diff --git a/.clang-format b/.clang-format index 7bfbefa3524..91003968851 100644 --- a/.clang-format +++ b/.clang-format @@ -18,7 +18,7 @@ AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: true BinPackArguments: false BinPackParameters: false -BraceWrapping: +BraceWrapping: AfterClass: true AfterControlStatement: true AfterEnum: false @@ -43,19 +43,27 @@ Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -IncludeCategories: - - Regex: '^<(BeastConfig)' +ForEachMacros: [ Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^<(test)/' Priority: 0 - - Regex: '^<(ripple)/' + - Regex: '^<(xrpld)/' + Priority: 1 + - Regex: '^<(xrpl)/' Priority: 2 - Regex: '^<(boost)/' Priority: 3 - - Regex: '.*' + - Regex: '^.*/' Priority: 4 + - Regex: '^.*\.h' + Priority: 5 + - Regex: '.*' + Priority: 6 IncludeIsMainRegex: '$' IndentCaseLabels: true IndentFunctionDeclarationAfterType: false +IndentRequiresClause: true IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: false @@ -71,6 +79,7 @@ PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left ReflowComments: true +RequiresClausePosition: OwnLine SortIncludes: true SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true @@ -84,4 +93,4 @@ SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp11 TabWidth: 8 -UseTab: Never \ No newline at end of file +UseTab: Never diff --git a/.codecov.yml b/.codecov.yml index b2bc67814e3..6df3786197f 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,5 +1,37 @@ - codecov: - ci: - - !appveyor - - travis + require_ci_to_pass: true + +comment: + behavior: default + layout: reach,diff,flags,tree,reach + show_carryforward_flags: false + +coverage: + range: "60..80" + precision: 1 + round: nearest + status: + project: + default: + target: 60% + threshold: 2% + patch: + default: + target: auto + threshold: 2% + changes: false + +github_checks: + annotations: true + +parsers: + cobertura: + partials_as_hits: true + handle_missing_conditions : true + +slack_app: false + +ignore: + - "src/test/" + - "include/xrpl/beast/test/" + - "include/xrpl/beast/unit_test/" diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000000..a72fc4afd83 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,13 @@ +# This feature requires Git >= 2.24 +# To use it by default in git blame: +# git config blame.ignoreRevsFile .git-blame-ignore-revs +50760c693510894ca368e90369b0cc2dabfd07f3 +e2384885f5f630c8f0ffe4bf21a169b433a16858 +241b9ddde9e11beb7480600fd5ed90e1ef109b21 +760f16f56835663d9286bd29294d074de26a7ba6 +0eebe6a5f4246fced516d52b83ec4e7f47373edd +2189cc950c0cebb89e4e2fa3b2d8817205bf7cef +b9d007813378ad0ff45660dc07285b823c7e9855 +fe9a5365b8a52d4acc42eb27369247e6f238a4f9 +9a93577314e6a8d4b4a8368cc9d2b15a5d8303e8 +552377c76f55b403a1c876df873a23d780fcc81c diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000000..e2df996005d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug Report +about: Create a report to help us improve rippled +title: "[Title with short description] (Version: [rippled version])" +labels: '' +assignees: '' + +--- + + +## Issue Description + + +## Steps to Reproduce + + +## Expected Result + + +## Actual Result + + +## Environment + + + + +## Supporting Files + + + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..9a1963b2904 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: XRP Ledger Documentation + url: https://xrpl.org/ + about: All things about XRPL + - name: Security bug bounty program + url: https://ripple.com/bug-bounty/ + about: Please report security-relevant bugs in our software here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000000..2e19746f520 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,21 @@ +--- +name: Feature Request +about: Suggest a new feature for the rippled project +title: "[Title with short description] (Version: [rippled version])" +labels: Feature Request +assignees: '' + +--- + + +## Summary + + +## Motivation + + +## Solution + + +## Paths Not Taken + diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml new file mode 100644 index 00000000000..6714369155f --- /dev/null +++ b/.github/actions/build/action.yml @@ -0,0 +1,34 @@ +name: build +inputs: + generator: + default: null + configuration: + required: true + cmake-args: + default: null + cmake-target: + default: all +# An implicit input is the environment variable `build_dir`. +runs: + using: composite + steps: + - name: configure + shell: bash + run: | + cd ${build_dir} + cmake \ + ${{ inputs.generator && format('-G "{0}"', inputs.generator) || '' }} \ + -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE=${{ inputs.configuration }} \ + -Dtests=TRUE \ + -Dxrpld=TRUE \ + ${{ inputs.cmake-args }} \ + .. + - name: build + shell: bash + run: | + cmake \ + --build ${build_dir} \ + --config ${{ inputs.configuration }} \ + --parallel ${NUM_PROCESSORS:-$(nproc)} \ + --target ${{ inputs.cmake-target }} diff --git a/.github/actions/dependencies/action.yml b/.github/actions/dependencies/action.yml new file mode 100644 index 00000000000..afce1557d3b --- /dev/null +++ b/.github/actions/dependencies/action.yml @@ -0,0 +1,57 @@ +name: dependencies +inputs: + configuration: + required: true +# An implicit input is the environment variable `build_dir`. +runs: + using: composite + steps: + - name: unlock Conan + shell: bash + run: conan remove --locks + - name: export custom recipes + shell: bash + run: | + conan config set general.revisions_enabled=1 + conan export external/snappy snappy/1.1.10@ + conan export external/rocksdb rocksdb/9.7.3@ + conan export external/soci soci/4.0.3@ + conan export external/nudb nudb/2.0.8@ + - name: add Ripple Conan remote + shell: bash + run: | + conan remote list + conan remote remove ripple || true + # Do not quote the URL. An empty string will be accepted (with + # a non-fatal warning), but a missing argument will not. + conan remote add ripple ${{ env.CONAN_URL }} --insert 0 + - name: try to authenticate to Ripple Conan remote + id: remote + shell: bash + run: | + # `conan user` implicitly uses the environment variables + # CONAN_LOGIN_USERNAME_ and CONAN_PASSWORD_. + # https://docs.conan.io/1/reference/commands/misc/user.html#using-environment-variables + # https://docs.conan.io/1/reference/env_vars.html#conan-login-username-conan-login-username-remote-name + # https://docs.conan.io/1/reference/env_vars.html#conan-password-conan-password-remote-name + echo outcome=$(conan user --remote ripple --password >&2 \ + && echo success || echo failure) | tee ${GITHUB_OUTPUT} + - name: list missing binaries + id: binaries + shell: bash + # Print the list of dependencies that would need to be built locally. + # A non-empty list means we have "failed" to cache binaries remotely. + run: | + echo missing=$(conan info . --build missing --settings build_type=${{ inputs.configuration }} --json 2>/dev/null | grep '^\[') | tee ${GITHUB_OUTPUT} + - name: install dependencies + shell: bash + run: | + mkdir ${build_dir} + cd ${build_dir} + conan install \ + --output-folder . \ + --build missing \ + --options tests=True \ + --options xrpld=True \ + --settings build_type=${{ inputs.configuration }} \ + .. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..3ab3a38807f --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,85 @@ + + +## High Level Overview of Change + + + +### Context of Change + + + +### Type of Change + + + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Refactor (non-breaking change that only restructures code) +- [ ] Performance (increase or change in throughput and/or latency) +- [ ] Tests (you added tests for code that already exists, or your new feature included in this PR) +- [ ] Documentation update +- [ ] Chore (no impact to binary, e.g. `.gitignore`, formatting, dropping support for older tooling) +- [ ] Release + +### API Impact + + + +- [ ] Public API: New feature (new methods and/or new fields) +- [ ] Public API: Breaking change (in general, breaking changes should only impact the next api_version) +- [ ] `libxrpl` change (any change that may affect `libxrpl` or dependents of `libxrpl`) +- [ ] Peer protocol change (must be backward compatible or bump the peer protocol version) + + + + + + diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 00000000000..1b86eed736d --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,59 @@ +name: clang-format + +on: [push, pull_request] + +jobs: + check: + runs-on: ubuntu-24.04 + env: + CLANG_VERSION: 18 + steps: + - uses: actions/checkout@v4 + - name: Install clang-format + run: | + codename=$( lsb_release --codename --short ) + sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null < and CONAN_PASSWORD_. + # https://docs.conan.io/1/reference/commands/misc/user.html#using-environment-variables + # https://docs.conan.io/1/reference/env_vars.html#conan-login-username-conan-login-username-remote-name + # https://docs.conan.io/1/reference/env_vars.html#conan-password-conan-password-remote-name + echo outcome=$(conan user --remote ripple --password >&2 \ + && echo success || echo failure) | tee ${GITHUB_OUTPUT} + - name: Upload new package + id: upload + if: (steps.remote.outputs.outcome == 'success') + shell: bash + run: | + echo "conan upload version ${{ steps.version.outputs.version }} on channel ${{ steps.channel.outputs.channel }}" + echo outcome=$(conan upload xrpl/${{ steps.version.outputs.version }}@${{ steps.channel.outputs.channel }} --remote ripple --confirm >&2 \ + && echo success || echo failure) | tee ${GITHUB_OUTPUT} + notify_clio: + name: Notify Clio + runs-on: ubuntu-latest + needs: publish + env: + GH_TOKEN: ${{ secrets.CLIO_NOTIFY_TOKEN }} + steps: + - name: Notify Clio about new version + if: (needs.publish.outputs.outcome == 'success') + shell: bash + run: | + gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \ + -F "client_payload[version]=${{ needs.publish.outputs.version }}@${{ needs.publish.outputs.channel }}" \ + -F "client_payload[pr]=${{ github.event.pull_request.number }}" diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml new file mode 100644 index 00000000000..566e3550e07 --- /dev/null +++ b/.github/workflows/macos.yml @@ -0,0 +1,94 @@ +name: macos +on: + pull_request: + push: + # If the branches list is ever changed, be sure to change it on all + # build/test jobs (nix, macos, windows, instrumentation) + branches: + # Always build the package branches + - develop + - release + - master + # Branches that opt-in to running + - 'ci/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + + test: + strategy: + matrix: + platform: + - macos + generator: + - Ninja + configuration: + - Release + runs-on: [self-hosted, macOS] + env: + # The `build` action requires these variables. + build_dir: .build + NUM_PROCESSORS: 12 + steps: + - name: checkout + uses: actions/checkout@v4 + - name: install Conan + run: | + brew install conan@1 + echo '/opt/homebrew/opt/conan@1/bin' >> $GITHUB_PATH + - name: install Ninja + if: matrix.generator == 'Ninja' + run: brew install ninja + - name: install python + run: | + if which python > /dev/null 2>&1; then + echo "Python executable exists" + else + brew install python@3.13 + ln -s /opt/homebrew/bin/python3 /opt/homebrew/bin/python + fi + - name: install cmake + run: | + if which cmake > /dev/null 2>&1; then + echo "cmake executable exists" + else + brew install cmake + fi + - name: install nproc + run: | + brew install coreutils + - name: check environment + run: | + env | sort + echo ${PATH} | tr ':' '\n' + python --version + conan --version + cmake --version + nproc --version + echo -n "nproc returns: " + nproc + - name: configure Conan + run : | + conan profile new default --detect || true + conan profile update settings.compiler.cppstd=20 default + - name: build dependencies + uses: ./.github/actions/dependencies + env: + CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod + CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }} + CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }} + with: + configuration: ${{ matrix.configuration }} + - name: build + uses: ./.github/actions/build + with: + generator: ${{ matrix.generator }} + configuration: ${{ matrix.configuration }} + cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}" + - name: test + run: | + n=$(nproc) + echo "Using $n test jobs" + ${build_dir}/rippled --unittest --unittest-jobs $n diff --git a/.github/workflows/missing-commits.yml b/.github/workflows/missing-commits.yml new file mode 100644 index 00000000000..8715671f33f --- /dev/null +++ b/.github/workflows/missing-commits.yml @@ -0,0 +1,60 @@ +name: missing-commits + +on: + push: + branches: + # Only check that the branches are up to date when updating the + # relevant branches. + - develop + - release + +jobs: + up_to_date: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Check for missing commits + id: commits + env: + SUGGESTION: | + + If you are reading this, then the commits indicated above are + missing from "develop" and/or "release". Do a reverse-merge + as soon as possible. See CONTRIBUTING.md for instructions. + run: | + set -o pipefail + # Branches ordered by how "canonical" they are. Every commit in + # one branch should be in all the branches behind it + order=( master release develop ) + branches=() + for branch in "${order[@]}" + do + # Check that the branches exist so that this job will work on + # forked repos, which don't necessarily have master and + # release branches. + if git ls-remote --exit-code --heads origin \ + refs/heads/${branch} > /dev/null + then + branches+=( origin/${branch} ) + fi + done + + prior=() + for branch in "${branches[@]}" + do + if [[ ${#prior[@]} -ne 0 ]] + then + echo "Checking ${prior[@]} for commits missing from ${branch}" + git log --oneline --no-merges "${prior[@]}" \ + ^$branch | tee -a "missing-commits.txt" + echo + fi + prior+=( "${branch}" ) + done + if [[ $( cat missing-commits.txt | wc -l ) -ne 0 ]] + then + echo "${SUGGESTION}" + exit 1 + fi diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 00000000000..d9a67a63e95 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,386 @@ +name: nix +on: + pull_request: + push: + # If the branches list is ever changed, be sure to change it on all + # build/test jobs (nix, macos, windows) + branches: + # Always build the package branches + - develop + - release + - master + # Branches that opt-in to running + - "ci/**" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# This workflow has multiple job matrixes. +# They can be considered phases because most of the matrices ("test", +# "coverage", "conan", ) depend on the first ("dependencies"). +# +# The first phase has a job in the matrix for each combination of +# variables that affects dependency ABI: +# platform, compiler, and configuration. +# It creates a GitHub artifact holding the Conan profile, +# and builds and caches binaries for all the dependencies. +# If an Artifactory remote is configured, they are cached there. +# If not, they are added to the GitHub artifact. +# GitHub's "cache" action has a size limit (10 GB) that is too small +# to hold the binaries if they are built locally. +# We must use the "{upload,download}-artifact" actions instead. +# +# The remaining phases have a job in the matrix for each test +# configuration. They install dependency binaries from the cache, +# whichever was used, and build and test rippled. +# +# "instrumentation" is independent, but is included here because it also +# builds on linux in the same "on:" conditions. + +jobs: + dependencies: + strategy: + fail-fast: false + matrix: + platform: + - linux + compiler: + - gcc + - clang + configuration: + - Debug + - Release + include: + - compiler: gcc + profile: + version: 11 + cc: /usr/bin/gcc + cxx: /usr/bin/g++ + - compiler: clang + profile: + version: 14 + cc: /usr/bin/clang-14 + cxx: /usr/bin/clang++-14 + runs-on: [self-hosted, heavy] + container: rippleci/rippled-build-ubuntu:aaf5e3e + env: + build_dir: .build + steps: + - name: upgrade conan + run: | + pip install --upgrade "conan<2" + - name: checkout + uses: actions/checkout@v4 + - name: check environment + run: | + echo ${PATH} | tr ':' '\n' + lsb_release -a || true + ${{ matrix.profile.cc }} --version + conan --version + cmake --version + env | sort + - name: configure Conan + run: | + conan profile new default --detect + conan profile update settings.compiler.cppstd=20 default + conan profile update settings.compiler=${{ matrix.compiler }} default + conan profile update settings.compiler.version=${{ matrix.profile.version }} default + conan profile update settings.compiler.libcxx=libstdc++11 default + conan profile update env.CC=${{ matrix.profile.cc }} default + conan profile update env.CXX=${{ matrix.profile.cxx }} default + conan profile update conf.tools.build:compiler_executables='{"c": "${{ matrix.profile.cc }}", "cpp": "${{ matrix.profile.cxx }}"}' default + - name: archive profile + # Create this archive before dependencies are added to the local cache. + run: tar -czf conan.tar -C ~/.conan . + - name: build dependencies + uses: ./.github/actions/dependencies + env: + CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod + CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }} + CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }} + with: + configuration: ${{ matrix.configuration }} + - name: upload archive + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} + path: conan.tar + if-no-files-found: error + + test: + strategy: + fail-fast: false + matrix: + platform: + - linux + compiler: + - gcc + - clang + configuration: + - Debug + - Release + cmake-args: + - + - "-Dunity=ON" + needs: dependencies + runs-on: [self-hosted, heavy] + container: rippleci/rippled-build-ubuntu:aaf5e3e + env: + build_dir: .build + steps: + - name: upgrade conan + run: | + pip install --upgrade "conan<2" + - name: download cache + uses: actions/download-artifact@v4 + with: + name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} + - name: extract cache + run: | + mkdir -p ~/.conan + tar -xzf conan.tar -C ~/.conan + - name: check environment + run: | + env | sort + echo ${PATH} | tr ':' '\n' + conan --version + cmake --version + - name: checkout + uses: actions/checkout@v4 + - name: dependencies + uses: ./.github/actions/dependencies + env: + CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod + with: + configuration: ${{ matrix.configuration }} + - name: build + uses: ./.github/actions/build + with: + generator: Ninja + configuration: ${{ matrix.configuration }} + cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}" + - name: test + run: | + ${build_dir}/rippled --unittest --unittest-jobs $(nproc) + + coverage: + strategy: + fail-fast: false + matrix: + platform: + - linux + compiler: + - gcc + configuration: + - Debug + needs: dependencies + runs-on: [self-hosted, heavy] + container: rippleci/rippled-build-ubuntu:aaf5e3e + env: + build_dir: .build + steps: + - name: upgrade conan + run: | + pip install --upgrade "conan<2" + - name: download cache + uses: actions/download-artifact@v4 + with: + name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} + - name: extract cache + run: | + mkdir -p ~/.conan + tar -xzf conan.tar -C ~/.conan + - name: install gcovr + run: pip install "gcovr>=7,<8" + - name: check environment + run: | + echo ${PATH} | tr ':' '\n' + conan --version + cmake --version + gcovr --version + env | sort + ls ~/.conan + - name: checkout + uses: actions/checkout@v4 + - name: dependencies + uses: ./.github/actions/dependencies + env: + CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod + with: + configuration: ${{ matrix.configuration }} + - name: build + uses: ./.github/actions/build + with: + generator: Ninja + configuration: ${{ matrix.configuration }} + cmake-args: >- + -Dassert=TRUE + -Dwerr=TRUE + -Dcoverage=ON + -Dcoverage_format=xml + -DCODE_COVERAGE_VERBOSE=ON + -DCMAKE_CXX_FLAGS="-O0" + -DCMAKE_C_FLAGS="-O0" + cmake-target: coverage + - name: move coverage report + shell: bash + run: | + mv "${build_dir}/coverage.xml" ./ + - name: archive coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage.xml + path: coverage.xml + retention-days: 30 + - name: upload coverage report + uses: wandalen/wretry.action@v1.4.10 + with: + action: codecov/codecov-action@v4.5.0 + with: | + files: coverage.xml + fail_ci_if_error: true + disable_search: true + verbose: true + plugin: noop + token: ${{ secrets.CODECOV_TOKEN }} + attempt_limit: 5 + attempt_delay: 210000 # in milliseconds + + conan: + needs: dependencies + runs-on: [self-hosted, heavy] + container: rippleci/rippled-build-ubuntu:aaf5e3e + env: + build_dir: .build + configuration: Release + steps: + - name: upgrade conan + run: | + pip install --upgrade "conan<2" + - name: download cache + uses: actions/download-artifact@v4 + with: + name: linux-gcc-${{ env.configuration }} + - name: extract cache + run: | + mkdir -p ~/.conan + tar -xzf conan.tar -C ~/.conan + - name: check environment + run: | + env | sort + echo ${PATH} | tr ':' '\n' + conan --version + cmake --version + - name: checkout + uses: actions/checkout@v4 + - name: dependencies + uses: ./.github/actions/dependencies + env: + CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod + with: + configuration: ${{ env.configuration }} + - name: export + run: | + version=$(conan inspect --raw version .) + reference="xrpl/${version}@local/test" + conan remove -f ${reference} || true + conan export . local/test + echo "reference=${reference}" >> "${GITHUB_ENV}" + - name: build + run: | + cd examples/example + mkdir ${build_dir} + cd ${build_dir} + conan install .. --output-folder . \ + --require-override ${reference} --build missing + cmake .. \ + -DCMAKE_TOOLCHAIN_FILE:FILEPATH=./build/${configuration}/generators/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE=${configuration} + cmake --build . + ./example | grep '^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+' + + # NOTE we are not using dependencies built above because it lags with + # compiler versions. Instrumentation requires clang version 16 or + # later + + instrumentation-build: + env: + CLANG_RELEASE: 16 + strategy: + fail-fast: false + runs-on: [self-hosted, heavy] + container: debian:bookworm + steps: + - name: install prerequisites + env: + DEBIAN_FRONTEND: noninteractive + run: | + apt-get update + apt-get install --yes --no-install-recommends \ + clang-${CLANG_RELEASE} clang++-${CLANG_RELEASE} \ + python3-pip python-is-python3 make cmake git wget + apt-get clean + update-alternatives --install \ + /usr/bin/clang clang /usr/bin/clang-${CLANG_RELEASE} 100 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-${CLANG_RELEASE} + update-alternatives --auto clang + pip install --no-cache --break-system-packages "conan<2" + + - name: checkout + uses: actions/checkout@v4 + + - name: prepare environment + run: | + mkdir ${GITHUB_WORKSPACE}/.build + echo "SOURCE_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV + echo "BUILD_DIR=$GITHUB_WORKSPACE/.build" >> $GITHUB_ENV + echo "CC=/usr/bin/clang" >> $GITHUB_ENV + echo "CXX=/usr/bin/clang++" >> $GITHUB_ENV + + - name: configure Conan + run: | + conan profile new --detect default + conan profile update settings.compiler=clang default + conan profile update settings.compiler.version=${CLANG_RELEASE} default + conan profile update settings.compiler.libcxx=libstdc++11 default + conan profile update settings.compiler.cppstd=20 default + conan profile update options.rocksdb=False default + conan profile update \ + 'conf.tools.build:compiler_executables={"c": "/usr/bin/clang", "cpp": "/usr/bin/clang++"}' default + conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default + conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default + conan export external/snappy snappy/1.1.10@ + conan export external/soci soci/4.0.3@ + + - name: build dependencies + run: | + cd ${BUILD_DIR} + conan install ${SOURCE_DIR} \ + --output-folder ${BUILD_DIR} \ + --install-folder ${BUILD_DIR} \ + --build missing \ + --settings build_type=Debug + + - name: build with instrumentation + run: | + cd ${BUILD_DIR} + cmake -S ${SOURCE_DIR} -B ${BUILD_DIR} \ + -Dvoidstar=ON \ + -Dtests=ON \ + -Dxrpld=ON \ + -DCMAKE_BUILD_TYPE=Debug \ + -DSECP256K1_BUILD_BENCHMARK=OFF \ + -DSECP256K1_BUILD_TESTS=OFF \ + -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \ + -DCMAKE_TOOLCHAIN_FILE=${BUILD_DIR}/build/generators/conan_toolchain.cmake + cmake --build . --parallel $(nproc) + + - name: verify instrumentation enabled + run: | + cd ${BUILD_DIR} + ./rippled --version | grep libvoidstar + + - name: run unit tests + run: | + cd ${BUILD_DIR} + ./rippled -u --unittest-jobs $(( $(nproc)/4 )) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 00000000000..7641db0d105 --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,97 @@ +name: windows + +on: + pull_request: + push: + # If the branches list is ever changed, be sure to change it on all + # build/test jobs (nix, macos, windows, instrumentation) + branches: + # Always build the package branches + - develop + - release + - master + # Branches that opt-in to running + - 'ci/**' + +# https://docs.github.com/en/actions/using-jobs/using-concurrency +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + + test: + strategy: + fail-fast: false + matrix: + version: + - generator: Visual Studio 17 2022 + runs-on: windows-2022 + configuration: + - type: Release + tests: true + - type: Debug + # Skip running unit tests on debug builds, because they + # take an unreasonable amount of time + tests: false + runtime: d + runs-on: ${{ matrix.version.runs-on }} + env: + build_dir: .build + steps: + - name: checkout + uses: actions/checkout@v4 + - name: choose Python + uses: actions/setup-python@v5 + with: + python-version: 3.9 + - name: learn Python cache directory + id: pip-cache + shell: bash + run: | + python -m pip install --upgrade pip + echo "dir=$(pip cache dir)" | tee ${GITHUB_OUTPUT} + - name: restore Python cache directory + uses: actions/cache@v4 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: ${{ runner.os }}-${{ hashFiles('.github/workflows/windows.yml') }} + - name: install Conan + run: pip install wheel 'conan<2' + - name: check environment + run: | + dir env: + $env:PATH -split ';' + python --version + conan --version + cmake --version + - name: configure Conan + shell: bash + run: | + conan profile new default --detect + conan profile update settings.compiler.cppstd=20 default + conan profile update \ + settings.compiler.runtime=MT${{ matrix.configuration.runtime }} \ + default + - name: build dependencies + uses: ./.github/actions/dependencies + env: + CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod + CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }} + CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }} + with: + configuration: ${{ matrix.configuration.type }} + - name: build + uses: ./.github/actions/build + with: + generator: '${{ matrix.version.generator }}' + configuration: ${{ matrix.configuration.type }} + # Hard code for now. Move to the matrix if varied options are needed + cmake-args: '-Dassert=TRUE -Dwerr=TRUE -Dreporting=OFF -Dunity=ON' + cmake-target: install + - name: test + shell: bash + if: ${{ matrix.configuration.tests }} + run: | + ${build_dir}/${{ matrix.configuration.type }}/rippled --unittest \ + --unittest-jobs $(nproc) diff --git a/.gitignore b/.gitignore index a21fee6417f..e5952e0de1b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,10 +21,12 @@ bin/project-cache.jam # Ignore object files. *.o -build .nih_c tags TAGS +GTAGS +GRTAGS +GPATH bin/rippled Debug/*.* Release/*.* @@ -34,6 +36,12 @@ Release/*.* *.gcda *.gcov +# Levelization checking +Builds/levelization/results/rawincludes.txt +Builds/levelization/results/paths.txt +Builds/levelization/results/includes/ +Builds/levelization/results/includedby/ + # Ignore tmp directory. tmp @@ -56,7 +64,7 @@ docs/html_doc # Xcode user-specific project settings # Xcode .DS_Store -*/build/* +/build/ *.pbxuser !default.pbxuser *.mode1v3 @@ -95,3 +103,12 @@ Builds/VisualStudio2015/*.sdf CMakeSettings.json compile_commands.json .clangd +packages +pkg_out +pkg +CMakeUserPresets.json +bld.rippled/ +.vscode + +# Suggested in-tree build directory +/.build/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 02475adf0ff..00000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,169 +0,0 @@ -# I don't know what the minimum size is, but we cannot build on t3.micro. - -# TODO: Factor common builds between different tests. - -# The parameters for our job matrix: -# -# 1. Generator (Make, Ninja, MSBuild) -# 2. Compiler (GCC, Clang, MSVC) -# 3. Build type (Debug, Release) -# 4. Definitions (-Dunity=OFF, -Dassert=ON, ...) - - -.job_linux_build_test: - only: - variables: - - $CI_PROJECT_URL =~ /^https?:\/\/gitlab.com\// - stage: build - tags: - - linux - - c5.2xlarge - image: thejohnfreeman/rippled-build-ubuntu:4b73694e07f0 - script: - - bin/ci/build.sh - - bin/ci/test.sh - cache: - # Use a different key for each unique combination of (generator, compiler, - # build type). Caches are stored as `.zip` files; they are not merged. - # Generate a new key whenever you want to bust the cache, e.g. when the - # dependency versions have been bumped. - # By default, jobs pull the cache. Only a few specially chosen jobs update - # the cache (with policy `pull-push`); one for each unique combination of - # (generator, compiler, build type). - policy: pull - paths: - - .nih_c/ - -'build+test Make GCC Debug': - extends: .job_linux_build_test - variables: - GENERATOR: Unix Makefiles - COMPILER: gcc - BUILD_TYPE: Debug - cache: - key: 62ada41c-fc9e-4949-9533-736d4d6512b6 - policy: pull-push - -'build+test Ninja GCC Debug': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: gcc - BUILD_TYPE: Debug - cache: - key: 1665d3eb-6233-4eef-9f57-172636899faa - policy: pull-push - -'build+test Ninja GCC Debug -Dstatic=OFF': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: gcc - BUILD_TYPE: Debug - CMAKE_ARGS: '-Dstatic=OFF' - cache: - key: 1665d3eb-6233-4eef-9f57-172636899faa - -'build+test Ninja GCC Debug -Dstatic=OFF -DBUILD_SHARED_LIBS=ON': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: gcc - BUILD_TYPE: Debug - CMAKE_ARGS: '-Dstatic=OFF -DBUILD_SHARED_LIBS=ON' - cache: - key: 1665d3eb-6233-4eef-9f57-172636899faa - -'build+test Ninja GCC Debug -Dunity=OFF': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: gcc - BUILD_TYPE: Debug - CMAKE_ARGS: '-Dunity=OFF' - cache: - key: 1665d3eb-6233-4eef-9f57-172636899faa - -'build+test Ninja GCC Release -Dassert=ON': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: gcc - BUILD_TYPE: Release - CMAKE_ARGS: '-Dassert=ON' - cache: - key: c45ec125-9625-4c19-acf7-4e889d5f90bd - policy: pull-push - -'build+test(manual) Ninja GCC Release -Dassert=ON': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: gcc - BUILD_TYPE: Release - CMAKE_ARGS: '-Dassert=ON' - MANUAL_TEST: 'true' - cache: - key: c45ec125-9625-4c19-acf7-4e889d5f90bd - -'build+test Make clang Debug': - extends: .job_linux_build_test - variables: - GENERATOR: Unix Makefiles - COMPILER: clang - BUILD_TYPE: Debug - cache: - key: bf578dc2-5277-4580-8de5-6b9523118b19 - policy: pull-push - -'build+test Ninja clang Debug': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: clang - BUILD_TYPE: Debug - cache: - key: 762514c5-3d4c-4c7c-8da2-2df9d8839cbe - policy: pull-push - -'build+test Ninja clang Debug -Dunity=OFF': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: clang - BUILD_TYPE: Debug - CMAKE_ARGS: '-Dunity=OFF' - cache: - key: 762514c5-3d4c-4c7c-8da2-2df9d8839cbe - -'build+test Ninja clang Debug -Dunity=OFF -Dsan=address': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: clang - BUILD_TYPE: Debug - CMAKE_ARGS: '-Dunity=OFF -Dsan=address' - CONCURRENT_TESTS: 1 - cache: - key: 762514c5-3d4c-4c7c-8da2-2df9d8839cbe - -'build+test Ninja clang Debug -Dunity=OFF -Dsan=undefined': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: clang - BUILD_TYPE: Debug - CMAKE_ARGS: '-Dunity=OFF -Dsan=undefined' - cache: - key: 762514c5-3d4c-4c7c-8da2-2df9d8839cbe - -'build+test Ninja clang Release -Dassert=ON': - extends: .job_linux_build_test - variables: - GENERATOR: Ninja - COMPILER: clang - BUILD_TYPE: Release - CMAKE_ARGS: '-Dassert=ON' - cache: - key: 7751be37-2358-4f08-b1d0-7e72e0ad266d - policy: pull-push diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000000..9f69d413797 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,6 @@ +# .pre-commit-config.yaml +repos: +- repo: https://github.com/pre-commit/mirrors-clang-format + rev: v18.1.3 + hooks: + - id: clang-format diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b45d7198005..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,326 +0,0 @@ -language: cpp -dist: xenial - -services: - - docker - -env: - global: - - DOCKER_IMAGE="mellery451/rippled-ci-builder:2019-08-26" - - CMAKE_EXTRA_ARGS="-Dwerr=ON -Dwextra=ON" - - NINJA_BUILD=true - # change this if we get more VM capacity - - MAX_TIME_MIN=80 - - CACHE_DIR=${TRAVIS_HOME}/_cache - - NIH_CACHE_ROOT=${CACHE_DIR}/nih_c - - PARALLEL_TESTS=true - # this is NOT used by linux container based builds (which already have boost installed) - - BOOST_URL='https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.bz2' - - VCPKG_DIR=${CACHE_DIR}/vcpkg - - USE_CCACHE=true - - CCACHE_BASEDIR=${TRAVIS_HOME}" - - CCACHE_NOHASHDIR=true - - CCACHE_DIR=${CACHE_DIR}/ccache - -before_install: - - if [ "$(uname)" = "Darwin" ] ; then export NUM_PROCESSORS=$(sysctl -n hw.physicalcpu); else export NUM_PROCESSORS=$(nproc); fi - - echo "NUM PROC is ${NUM_PROCESSORS}" - - if [ "$(uname)" = "Linux" ] ; then docker pull ${DOCKER_IMAGE}; fi - - if [ "${MATRIX_EVAL}" != "" ] ; then eval "${MATRIX_EVAL}"; fi - - if [ "${CMAKE_ADD}" != "" ] ; then export CMAKE_EXTRA_ARGS="${CMAKE_EXTRA_ARGS} ${CMAKE_ADD}"; fi - - bin/ci/ubuntu/travis-cache-start.sh - -matrix: - fast_finish: true - allow_failures: - # TODO these all need more investigation - # - # current tsan failure might be related to: - # https://github.com/google/sanitizers/issues/1104 - - name: tsan, clang-8 - # there are a number of UBs caught currently that need triage - - name: ubsan, clang-8 - - include: - # coverage builds - - compiler: gcc-8 - name: coverage, gcc-8 - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Debug - - CMAKE_ADD="-Dcoverage=ON" - - TARGET=coverage_report - - SKIP_TESTS=true - - compiler: clang-8 - name: coverage, clang-8 - env: - - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" - - BUILD_TYPE=Debug - - CMAKE_ADD="-Dcoverage=ON" - - TARGET=coverage_report - - SKIP_TESTS=true - # nounity - - compiler: gcc-8 - name: non-unity, gcc-8 - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Debug - - CMAKE_ADD="-Dunity=OFF" - - compiler: clang-8 - name: non-unity, clang-8 - env: - - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" - - BUILD_TYPE=Debug - - CMAKE_ADD="-Dunity=OFF" - # manual tests - - compiler: gcc-8 - name: manual tests, gcc-8, debug - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Debug - - MANUAL_TESTS=true - # manual tests - - compiler: gcc-8 - name: manual tests, gcc-8, release - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Release - - CMAKE_ADD="-Dassert=ON" - - MANUAL_TESTS=true - # release builds - - compiler: gcc-8 - name: gcc-8, release - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Release - - CMAKE_ADD="-Dassert=ON" - - compiler: clang-8 - name: clang-8, release - env: - - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" - - BUILD_TYPE=Release - - CMAKE_ADD="-Dassert=ON" - # debug builds - - compiler: gcc-8 - name: gcc-8, debug - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Debug - - compiler: clang-8 - name: clang-8, debug - env: - - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" - - BUILD_TYPE=Debug - # asan - - compiler: clang-8 - name: asan, clang-8 - env: - - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" - - BUILD_TYPE=Release - - CMAKE_ADD="-Dsan=address" - - ASAN_OPTIONS="print_stats=true:atexit=true" - #- LSAN_OPTIONS="verbosity=1:log_threads=1" - - PARALLEL_TESTS=false - # ubsan - - compiler: clang-8 - name: ubsan, clang-8 - env: - - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" - - BUILD_TYPE=Release - - CMAKE_ADD="-Dsan=undefined" - # once we can run clean under ubsan, add halt_on_error=1 to options below - - UBSAN_OPTIONS="print_stacktrace=1:report_error_type=1" - - PARALLEL_TESTS=false - # tsan - - compiler: clang-8 - name: tsan, clang-8 - env: - - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" - - BUILD_TYPE=Release - - CMAKE_ADD="-Dsan=thread" - - TSAN_OPTIONS="history_size=3 external_symbolizer_path=/usr/bin/llvm-symbolizer verbosity=1" - - PARALLEL_TESTS=false - # dynamic lib builds - - compiler: gcc-8 - name: non-static, gcc-8 - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Debug - - CMAKE_ADD="-Dstatic=OFF" - - compiler: gcc-8 - name: non-static + BUILD_SHARED_LIBS, gcc-8 - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Debug - - CMAKE_ADD="-Dstatic=OFF -DBUILD_SHARED_LIBS=ON" - # makefile - - compiler: gcc-8 - name: makefile generator, gcc-8 - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Debug - - NINJA_BUILD=false - # misc alternative compilers - - compiler: gcc-7 - name: gcc-7 - env: - - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - - BUILD_TYPE=Debug - - compiler: gcc-9 - name: gcc-9 - env: - - MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" - - BUILD_TYPE=Debug - - compiler: clang-5.0 - name: clang-5 - env: - - MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0" - - BUILD_TYPE=Debug - - compiler: clang-6.0 - name: clang-6 - env: - - MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0" - - BUILD_TYPE=Debug - - compiler: clang-7 - name: clang-7 - env: - - MATRIX_EVAL="CC=clang-7 && CXX=clang++-7" - - BUILD_TYPE=Debug - - compiler: clang-9 - name: clang-9 - env: - - MATRIX_EVAL="CC=clang-9 && CXX=clang++-9" - - BUILD_TYPE=Debug - # verify build with min version of cmake - - compiler: gcc-8 - name: min cmake version - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Debug - - CMAKE_EXE=/opt/local/cmake-3.9/bin/cmake - - SKIP_TESTS=true - # validator keys project as subproj of rippled - - compiler: gcc-8 - name: validator-keys - env: - - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - BUILD_TYPE=Debug - - CMAKE_ADD="-Dvalidator_keys=ON" - - TARGET=validator-keys - # macos - - &macos - os: osx - osx_image: xcode10.2 - name: xcode10, debug - env: - - BLD_CONFIG=Debug - - TEST_EXTRA_ARGS="" - - BOOST_ROOT=${CACHE_DIR}/boost_1_70_0 - - >- - CMAKE_ADD=" - -DBOOST_ROOT=${BOOST_ROOT}/_INSTALLED_ - -DBoost_ARCHITECTURE=-x64 - -DBoost_NO_SYSTEM_PATHS=ON - -DCMAKE_VERBOSE_MAKEFILE=ON" - addons: - homebrew: - packages: - - bash - - ninja - - cmake - - wget - - openssl@1.1 - update: true - install: - - export OPENSSL_ROOT=$(brew --prefix openssl@1.1) - - travis_wait ${MAX_TIME_MIN} Builds/containers/shared/install_boost.sh - - brew uninstall --ignore-dependencies boost - script: - - mkdir -p build.macos && cd build.macos - - cmake -G Ninja ${CMAKE_EXTRA_ARGS} -DCMAKE_BUILD_TYPE=${BLD_CONFIG} .. - - travis_wait ${MAX_TIME_MIN} cmake --build . --parallel --verbose - - ./rippled --unittest --quiet --unittest-log --unittest-jobs ${NUM_PROCESSORS} ${TEST_EXTRA_ARGS} - - <<: *macos - name: xcode10, release - before_script: - - export BLD_CONFIG=Release - - export CMAKE_EXTRA_ARGS="${CMAKE_EXTRA_ARGS} -Dassert=ON" - - <<: *macos - name: ipv6 (macos) - before_script: - - export TEST_EXTRA_ARGS="--unittest-ipv6" - - <<: *macos - osx_image: xcode9.4 - name: xcode9, debug - before_script: - # turn off warnings as err for this build - - export CMAKE_EXTRA_ARGS="${CMAKE_EXTRA_ARGS} -Dwerr=OFF" - - <<: *macos - osx_image: xcode11 - name: xcode11, debug - # windows - - &windows - # caching is unreliable on windows...disable for now - cache: false - os: windows - name: windows, debug - env: - # put NIH in a non-cached location until - # we come up with a way to stabilize that - # cache on windows (minimize incremental changes) - - NIH_CACHE_ROOT=${TRAVIS_BUILD_DIR}/nih_c - - VCPKG_DEFAULT_TRIPLET="x64-windows-static" - - BOOST_ROOT=${CACHE_DIR}/boost_1_70_0 - - MATRIX_EVAL="CC=cl.exe && CXX=cl.exe" - - >- - CMAKE_ADD=" - -DBOOST_ROOT=${BOOST_ROOT}/_INSTALLED_ - -DCMAKE_VERBOSE_MAKEFILE=ON - -DCMAKE_TOOLCHAIN_FILE=${VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake - -DVCPKG_TARGET_TRIPLET=x64-windows-static" - install: - - choco upgrade cmake.install - - choco install ninja visualstudio2017-workload-vctools -y - - travis_wait 30 bin/sh/install-vcpkg.sh - - travis_wait ${MAX_TIME_MIN} Builds/containers/shared/install_boost.sh - before_script: - - export BLD_CONFIG=Debug - script: - - . ./bin/sh/setup-msvc.sh - - mkdir -p build.ms && cd build.ms - - cmake -G Ninja ${CMAKE_EXTRA_ARGS} -DCMAKE_BUILD_TYPE=${BLD_CONFIG} .. - - travis_wait ${MAX_TIME_MIN} cmake --build . --parallel --verbose - - ./rippled.exe --unittest --quiet --unittest-log --unittest-jobs ${NUM_PROCESSORS} - - <<: *windows - name: windows, release - before_script: - - export BLD_CONFIG=Release - - <<: *windows - name: windows, visual studio, debug - script: - - mkdir -p build.ms && cd build.ms - - cmake -G "Visual Studio 15 2017 Win64" ${CMAKE_EXTRA_ARGS} .. - - export DESTDIR=${PWD}/_installed_ - - travis_wait ${MAX_TIME_MIN} cmake --build . --parallel --verbose --config ${BLD_CONFIG} --target install - - >- - "./_installed_/Program Files/rippled/bin/rippled.exe" --unittest --quiet --unittest-log --unittest-jobs ${NUM_PROCESSORS} - -cache: - timeout: 900 - directories: - - $CACHE_DIR -before_cache: - - if [ $(uname) = "Linux" ] ; then SUDO="sudo"; else SUDO=""; fi - - cd ${TRAVIS_HOME} - - if [ -f cache_ignore.tar ] ; then $SUDO tar xvf cache_ignore.tar; fi - - cd ${TRAVIS_BUILD_DIR} - -script: - - sudo chmod -R a+rw ${CACHE_DIR} - - ccache -s - - travis_wait ${MAX_TIME_MIN} bin/ci/ubuntu/build-in-docker.sh - - ccache -s - -notifications: - email: false - diff --git a/API-CHANGELOG.md b/API-CHANGELOG.md new file mode 100644 index 00000000000..0d5d8a8196b --- /dev/null +++ b/API-CHANGELOG.md @@ -0,0 +1,217 @@ +# API Changelog + +This changelog is intended to list all updates to the [public API methods](https://xrpl.org/public-api-methods.html). + +For info about how [API versioning](https://xrpl.org/request-formatting.html#api-versioning) works, including examples, please view the [XLS-22d spec](https://github.com/XRPLF/XRPL-Standards/discussions/54). For details about the implementation of API versioning, view the [implementation PR](https://github.com/XRPLF/rippled/pull/3155). API versioning ensures existing integrations and users continue to receive existing behavior, while those that request a higher API version will experience new behavior. + +The API version controls the API behavior you see. This includes what properties you see in responses, what parameters you're permitted to send in requests, and so on. You specify the API version in each of your requests. When a breaking change is introduced to the `rippled` API, a new version is released. To avoid breaking your code, you should set (or increase) your version when you're ready to upgrade. + +For a log of breaking changes, see the **API Version [number]** headings. In general, breaking changes are associated with a particular API Version number. For non-breaking changes, scroll to the **XRP Ledger version [x.y.z]** headings. Non-breaking changes are associated with a particular XRP Ledger (`rippled`) release. + +## API Version 2 + +API version 2 is available in `rippled` version 2.0.0 and later. To use this API, clients specify `"api_version" : 2` in each request. + +#### Removed methods + +In API version 2, the following deprecated methods are no longer available: (https://github.com/XRPLF/rippled/pull/4759) + +- `tx_history` - Instead, use other methods such as `account_tx` or `ledger` with the `transactions` field set to `true`. +- `ledger_header` - Instead, use the `ledger` method. + +#### Modifications to JSON transaction element in V2 + +In API version 2, JSON elements for transaction output have been changed and made consistent for all methods which output transactions. (https://github.com/XRPLF/rippled/pull/4775) +This helps to unify the JSON serialization format of transactions. (https://github.com/XRPLF/clio/issues/722, https://github.com/XRPLF/rippled/issues/4727) + +- JSON transaction element is named `tx_json` +- Binary transaction element is named `tx_blob` +- JSON transaction metadata element is named `meta` +- Binary transaction metadata element is named `meta_blob` + +Additionally, these elements are now consistently available next to `tx_json` (i.e. sibling elements), where possible: + +- `hash` - Transaction ID. This data was stored inside transaction output in API version 1, but in API version 2 is a sibling element. +- `ledger_index` - Ledger index (only set on validated ledgers) +- `ledger_hash` - Ledger hash (only set on closed or validated ledgers) +- `close_time_iso` - Ledger close time expressed in ISO 8601 time format (only set on validated ledgers) +- `validated` - Bool element set to `true` if the transaction is in a validated ledger, otherwise `false` + +This change affects the following methods: + +- `tx` - Transaction data moved into element `tx_json` (was inline inside `result`) or, if binary output was requested, moved from `tx` to `tx_blob`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements +- `account_tx` - Renamed transaction element from `tx` to `tx_json`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements +- `transaction_entry` - Renamed transaction metadata element from `metadata` to `meta`. Changed location of `hash` and added new elements +- `subscribe` - Renamed transaction element from `transaction` to `tx_json`. Changed location of `hash` and added new elements +- `sign`, `sign_for`, `submit` and `submit_multisigned` - Changed location of `hash` element. + +#### Modification to `Payment` transaction JSON schema + +When reading Payments, the `Amount` field should generally **not** be used. Instead, use [delivered_amount](https://xrpl.org/partial-payments.html#the-delivered_amount-field) to see the amount that the Payment delivered. To clarify its meaning, the `Amount` field is being renamed to `DeliverMax`. (https://github.com/XRPLF/rippled/pull/4733) + +- In `Payment` transaction type, JSON RPC field `Amount` is renamed to `DeliverMax`. To enable smooth client transition, `Amount` is still handled, as described below: (https://github.com/XRPLF/rippled/pull/4733) + - On JSON RPC input (e.g. `submit_multisigned` etc. methods), `Amount` is recognized as an alias to `DeliverMax` for both API version 1 and version 2 clients. + - On JSON RPC input, submitting both `Amount` and `DeliverMax` fields is allowed _only_ if they are identical; otherwise such input is rejected with `rpcINVALID_PARAMS` error. + - On JSON RPC output (e.g. `subscribe`, `account_tx` etc. methods), `DeliverMax` is present in both API version 1 and version 2. + - On JSON RPC output, `Amount` is only present in API version 1 and _not_ in version 2. + +#### Modifications to account_info response + +- `signer_lists` is returned in the root of the response. (In API version 1, it was nested under `account_data`.) (https://github.com/XRPLF/rippled/pull/3770) +- When using an invalid `signer_lists` value, the API now returns an "invalidParams" error. (https://github.com/XRPLF/rippled/pull/4585) + - (`signer_lists` must be a boolean. In API version 1, strings were accepted and may return a normal response - i.e. as if `signer_lists` were `true`.) + +#### Modifications to [account_tx](https://xrpl.org/account_tx.html#account_tx) response + +- Using `ledger_index_min`, `ledger_index_max`, and `ledger_index` returns `invalidParams` because if you use `ledger_index_min` or `ledger_index_max`, then it does not make sense to also specify `ledger_index`. In API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4571) + - The same applies for `ledger_index_min`, `ledger_index_max`, and `ledger_hash`. (https://github.com/XRPLF/rippled/issues/4545#issuecomment-1565065579) +- Using a `ledger_index_min` or `ledger_index_max` beyond the range of ledgers that the server has: + - returns `lgrIdxMalformed` in API version 2. Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/issues/4288) +- Attempting to use a non-boolean value (such as a string) for the `binary` or `forward` parameters returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4620) + +#### Modifications to [noripple_check](https://xrpl.org/noripple_check.html#noripple_check) response + +- Attempting to use a non-boolean value (such as a string) for the `transactions` parameter returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4620) + +## API Version 1 + +This version is supported by all `rippled` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified. + +The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conventions/request-formatting/#commandline-format) always uses the latest API version. The command line is intended for ad-hoc usage by humans, not programs or automated scripts. The command line is not meant for use in production code. + +### Inconsistency: server_info - network_id + +The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead. + +## XRP Ledger server version 2.4.0 + +As of 2025-01-28, version 2.4.0 is in development. You can use a pre-release version by building from source or [using the `nightly` package](https://xrpl.org/docs/infrastructure/installation/install-rippled-on-ubuntu). + +### Additions and bugfixes in 2.4.0 + +- `ledger_entry`: `state` is added an alias for `ripple_state`. +- `ledger_entry`: Enables case-insensitive filtering by canonical name in addition to case-sensitive filtering by RPC name. +- `validators`: Added new field `validator_list_threshold` in response. +- `simulate`: A new RPC that executes a [dry run of a transaction submission](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069d-simulate#2-rpc-simulate) +- Signing methods autofill fees better and properly handle transactions that don't have a base fee, and will also autofill the `NetworkID` field. + +## XRP Ledger server version 2.3.0 + +[Version 2.3.0](https://github.com/XRPLF/rippled/releases/tag/2.3.0) was released on Nov 25, 2024. + +### Breaking changes in 2.3.0 + +- `book_changes`: If the requested ledger version is not available on this node, a `ledgerNotFound` error is returned and the node does not attempt to acquire the ledger from the p2p network (as with other non-admin RPCs). + +Admins can still attempt to retrieve old ledgers with the `ledger_request` RPC. + +### Additions and bugfixes in 2.3.0 + +- `book_changes`: Returns a `validated` field in its response, which was missing in prior versions. + +## XRP Ledger server version 2.2.0 + +[Version 2.2.0](https://github.com/XRPLF/rippled/releases/tag/2.2.0) was released on Jun 5, 2024. The following additions are non-breaking (because they are purely additive): + +- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) + +## XRP Ledger server version 2.0.0 + +[Version 2.0.0](https://github.com/XRPLF/rippled/releases/tag/2.0.0) was released on Jan 9, 2024. The following additions are non-breaking (because they are purely additive): + +- `server_definitions`: A new RPC that generates a `definitions.json`-like output that can be used in XRPL libraries. +- In `Payment` transactions, `DeliverMax` has been added. This is a replacement for the `Amount` field, which should not be used. Typically, the `delivered_amount` (in transaction metadata) should be used. To ease the transition, `DeliverMax` is present regardless of API version, since adding a field is non-breaking. +- API version 2 has been moved from beta to supported, meaning that it is generally available (regardless of the `beta_rpc_api` setting). + +## XRP Ledger server version 2.2.0 + +The following is a non-breaking addition to the API. + +- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) + +## XRP Ledger server version 1.12.0 + +[Version 1.12.0](https://github.com/XRPLF/rippled/releases/tag/1.12.0) was released on Sep 6, 2023. The following additions are non-breaking (because they are purely additive). + +- `server_info`: Added `ports`, an array which advertises the RPC and WebSocket ports. This information is also included in the `/crawl` endpoint (which calls `server_info` internally). `grpc` and `peer` ports are also included. (https://github.com/XRPLF/rippled/pull/4427) + - `ports` contains objects, each containing a `port` for the listening port (a number string), and a `protocol` array listing the supported protocols on that port. + - This allows crawlers to build a more detailed topology without needing to port-scan nodes. + - (For peers and other non-admin clients, the info about admin ports is excluded.) +- Clawback: The following additions are gated by the Clawback amendment (`featureClawback`). (https://github.com/XRPLF/rippled/pull/4553) + - Adds an [AccountRoot flag](https://xrpl.org/accountroot.html#accountroot-flags) called `lsfAllowTrustLineClawback` (https://github.com/XRPLF/rippled/pull/4617) + - Adds the corresponding `asfAllowTrustLineClawback` [AccountSet Flag](https://xrpl.org/accountset.html#accountset-flags) as well. + - Clawback is disabled by default, so if an issuer desires the ability to claw back funds, they must use an `AccountSet` transaction to set the AllowTrustLineClawback flag. They must do this before creating any trust lines, offers, escrows, payment channels, or checks. + - Adds the [Clawback transaction type](https://github.com/XRPLF/XRPL-Standards/blob/master/XLS-39d-clawback/README.md#331-clawback-transaction), containing these fields: + - `Account`: The issuer of the asset being clawed back. Must also be the sender of the transaction. + - `Amount`: The amount being clawed back, with the `Amount.issuer` being the token holder's address. +- Adds [AMM](https://github.com/XRPLF/XRPL-Standards/discussions/78) ([#4294](https://github.com/XRPLF/rippled/pull/4294), [#4626](https://github.com/XRPLF/rippled/pull/4626)) feature: + - Adds `amm_info` API to retrieve AMM information for a given tokens pair. + - Adds `AMMCreate` transaction type to create `AMM` instance. + - Adds `AMMDeposit` transaction type to deposit funds into `AMM` instance. + - Adds `AMMWithdraw` transaction type to withdraw funds from `AMM` instance. + - Adds `AMMVote` transaction type to vote for the trading fee of `AMM` instance. + - Adds `AMMBid` transaction type to bid for the Auction Slot of `AMM` instance. + - Adds `AMMDelete` transaction type to delete `AMM` instance. + - Adds `sfAMMID` to `AccountRoot` to indicate that the account is `AMM`'s account. `AMMID` is used to fetch `ltAMM`. + - Adds `lsfAMMNode` `TrustLine` flag to indicate that one side of the `TrustLine` is `AMM` account. + - Adds `tfLPToken`, `tfSingleAsset`, `tfTwoAsset`, `tfOneAssetLPToken`, `tfLimitLPToken`, `tfTwoAssetIfEmpty`, + `tfWithdrawAll`, `tfOneAssetWithdrawAll` which allow a trader to specify different fields combination + for `AMMDeposit` and `AMMWithdraw` transactions. + - Adds new transaction result codes: + - tecUNFUNDED_AMM: insufficient balance to fund AMM. The account does not have funds for liquidity provision. + - tecAMM_BALANCE: AMM has invalid balance. Calculated balances greater than the current pool balances. + - tecAMM_FAILED: AMM transaction failed. Fails due to a processing failure. + - tecAMM_INVALID_TOKENS: AMM invalid LP tokens. Invalid input values, format, or calculated values. + - tecAMM_EMPTY: AMM is in empty state. Transaction requires AMM in non-empty state (LP tokens > 0). + - tecAMM_NOT_EMPTY: AMM is not in empty state. Transaction requires AMM in empty state (LP tokens == 0). + - tecAMM_ACCOUNT: AMM account. Clawback of AMM account. + - tecINCOMPLETE: Some work was completed, but more submissions required to finish. AMMDelete partially deletes the trustlines. + +## XRP Ledger server version 1.11.0 + +[Version 1.11.0](https://github.com/XRPLF/rippled/releases/tag/1.11.0) was released on Jun 20, 2023. + +### Breaking changes in 1.11 + +- Added the ability to mark amendments as obsolete. For the `feature` admin API, there is a new possible value for the `vetoed` field. (https://github.com/XRPLF/rippled/pull/4291) + - The value of `vetoed` can now be `true`, `false`, or `"Obsolete"`. +- Removed the acceptance of seeds or public keys in place of account addresses. (https://github.com/XRPLF/rippled/pull/4404) + - This simplifies the API and encourages better security practices (i.e. seeds should never be sent over the network). +- For the `ledger_data` method, when all entries are filtered out, the `state` field of the response is now an empty list (in other words, an empty array, `[]`). (Previously, it would return `null`.) While this is technically a breaking change, the new behavior is consistent with the documentation, so this is considered only a bug fix. (https://github.com/XRPLF/rippled/pull/4398) +- If and when the `fixNFTokenRemint` amendment activates, there will be a new AccountRoot field, `FirstNFTSequence`. This field is set to the current account sequence when the account issues their first NFT. If an account has not issued any NFTs, then the field is not set. ([#4406](https://github.com/XRPLF/rippled/pull/4406)) + - There is a new account deletion restriction: an account can only be deleted if `FirstNFTSequence` + `MintedNFTokens` + `256` is less than the current ledger sequence. + - This is potentially a breaking change if clients have logic for determining whether an account can be deleted. +- NetworkID + - For sidechains and networks with a network ID greater than 1024, there is a new [transaction common field](https://xrpl.org/transaction-common-fields.html), `NetworkID`. (https://github.com/XRPLF/rippled/pull/4370) + - This field helps to prevent replay attacks and is now required for chains whose network ID is 1025 or higher. + - The field must be omitted for Mainnet, so there is no change for Mainnet users. + - There are three new local error codes: + - `telNETWORK_ID_MAKES_TX_NON_CANONICAL`: a `NetworkID` is present but the chain's network ID is less than 1025. Remove the field from the transaction, and try again. + - `telREQUIRES_NETWORK_ID`: a `NetworkID` is required, but is not present. Add the field to the transaction, and try again. + - `telWRONG_NETWORK`: a `NetworkID` is specified, but it is for a different network. Submit the transaction to a different server which is connected to the correct network. + +### Additions and bug fixes in 1.11 + +- Added `nftoken_id`, `nftoken_ids` and `offer_id` meta fields into NFT `tx` and `account_tx` responses. (https://github.com/XRPLF/rippled/pull/4447) +- Added an `account_flags` object to the `account_info` method response. (https://github.com/XRPLF/rippled/pull/4459) +- Added `NFTokenPages` to the `account_objects` RPC. (https://github.com/XRPLF/rippled/pull/4352) +- Fixed: `marker` returned from the `account_lines` command would not work on subsequent commands. (https://github.com/XRPLF/rippled/pull/4361) + +## XRP Ledger server version 1.10.0 + +[Version 1.10.0](https://github.com/XRPLF/rippled/releases/tag/1.10.0) +was released on Mar 14, 2023. + +### Breaking changes in 1.10 + +- If the `XRPFees` feature is enabled, the `fee_ref` field will be + removed from the [ledger subscription stream](https://xrpl.org/subscribe.html#ledger-stream), because it will no longer + have any meaning. + +# Unit tests for API changes + +The following information is useful to developers contributing to this project: + +The purpose of unit tests is to catch bugs and prevent regressions. In general, it often makes sense to create a test function when there is a breaking change to the API. For APIs that have changed in a new API version, the tests should be modified so that both the prior version and the new version are properly tested. + +To take one example: for `account_info` version 1, WebSocket and JSON-RPC behavior should be tested. The latest API version, i.e. API version 2, should be tested over WebSocket, JSON-RPC, and command line. diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 00000000000..fd985dce817 --- /dev/null +++ b/BUILD.md @@ -0,0 +1,500 @@ +| :warning: **WARNING** :warning: +|---| +| These instructions assume you have a C++ development environment ready with Git, Python, Conan, CMake, and a C++ compiler. For help setting one up on Linux, macOS, or Windows, [see this guide](./docs/build/environment.md). | + +> These instructions also assume a basic familiarity with Conan and CMake. +> If you are unfamiliar with Conan, +> you can read our [crash course](./docs/build/conan.md) +> or the official [Getting Started][3] walkthrough. + +## Branches + +For a stable release, choose the `master` branch or one of the [tagged +releases](https://github.com/ripple/rippled/releases). + +``` +git checkout master +``` + +For the latest release candidate, choose the `release` branch. + +``` +git checkout release +``` + +For the latest set of untested features, or to contribute, choose the `develop` +branch. + +``` +git checkout develop +``` + +## Minimum Requirements + +See [System Requirements](https://xrpl.org/system-requirements.html). + +Building rippled generally requires git, Python, Conan, CMake, and a C++ compiler. Some guidance on setting up such a [C++ development environment can be found here](./docs/build/environment.md). + +- [Python 3.7](https://www.python.org/downloads/) +- [Conan 1.60](https://conan.io/downloads.html)[^1] +- [CMake 3.16](https://cmake.org/download/) + +[^1]: It is possible to build with Conan 2.x, +but the instructions are significantly different, +which is why we are not recommending it yet. +Notably, the `conan profile update` command is removed in 2.x. +Profiles must be edited by hand. + +`rippled` is written in the C++20 dialect and includes the `` header. +The [minimum compiler versions][2] required are: + +| Compiler | Version | +|-------------|---------| +| GCC | 11 | +| Clang | 13 | +| Apple Clang | 13.1.6 | +| MSVC | 19.23 | + +### Linux + +The Ubuntu operating system has received the highest level of +quality assurance, testing, and support. + +Here are [sample instructions for setting up a C++ development environment on Linux](./docs/build/environment.md#linux). + +### Mac + +Many rippled engineers use macOS for development. + +Here are [sample instructions for setting up a C++ development environment on macOS](./docs/build/environment.md#macos). + +### Windows + +Windows is not recommended for production use at this time. + +- Additionally, 32-bit Windows development is not supported. + +[Boost]: https://www.boost.org/ + +## Steps + +### Set Up Conan + +After you have a [C++ development environment](./docs/build/environment.md) ready with Git, Python, Conan, CMake, and a C++ compiler, you may need to set up your Conan profile. + +These instructions assume a basic familiarity with Conan and CMake. + +If you are unfamiliar with Conan, then please read [this crash course](./docs/build/conan.md) or the official [Getting Started][3] walkthrough. + +You'll need at least one Conan profile: + + ``` + conan profile new default --detect + ``` + +Update the compiler settings: + + ``` + conan profile update settings.compiler.cppstd=20 default + ``` + +Configure Conan (1.x only) to use recipe revisions: + + ``` + conan config set general.revisions_enabled=1 + ``` + +**Linux** developers will commonly have a default Conan [profile][] that compiles +with GCC and links with libstdc++. +If you are linking with libstdc++ (see profile setting `compiler.libcxx`), +then you will need to choose the `libstdc++11` ABI: + + ``` + conan profile update settings.compiler.libcxx=libstdc++11 default + ``` + + +Ensure inter-operability between `boost::string_view` and `std::string_view` types: + +``` +conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_BEAST_USE_STD_STRING_VIEW"]' default +conan profile update 'env.CXXFLAGS="-DBOOST_BEAST_USE_STD_STRING_VIEW"' default +``` + +If you have other flags in the `conf.tools.build` or `env.CXXFLAGS` sections, make sure to retain the existing flags and append the new ones. You can check them with: +``` +conan profile show default +``` + + +**Windows** developers may need to use the x64 native build tools. +An easy way to do that is to run the shortcut "x64 Native Tools Command +Prompt" for the version of Visual Studio that you have installed. + + Windows developers must also build `rippled` and its dependencies for the x64 + architecture: + + ``` + conan profile update settings.arch=x86_64 default + ``` + +### Multiple compilers + +When `/usr/bin/g++` exists on a platform, it is the default cpp compiler. This +default works for some users. + +However, if this compiler cannot build rippled or its dependencies, then you can +install another compiler and set Conan and CMake to use it. +Update the `conf.tools.build:compiler_executables` setting in order to set the correct variables (`CMAKE__COMPILER`) in the +generated CMake toolchain file. +For example, on Ubuntu 20, you may have gcc at `/usr/bin/gcc` and g++ at `/usr/bin/g++`; if that is the case, you can select those compilers with: +``` +conan profile update 'conf.tools.build:compiler_executables={"c": "/usr/bin/gcc", "cpp": "/usr/bin/g++"}' default +``` + +Replace `/usr/bin/gcc` and `/usr/bin/g++` with paths to the desired compilers. + +It should choose the compiler for dependencies as well, +but not all of them have a Conan recipe that respects this setting (yet). +For the rest, you can set these environment variables. +Replace `` with paths to the desired compilers: + +- `conan profile update env.CC= default` +- `conan profile update env.CXX= default` + +Export our [Conan recipe for Snappy](./external/snappy). +It does not explicitly link the C++ standard library, +which allows you to statically link it with GCC, if you want. + + ``` + # Conan 1.x + conan export external/snappy snappy/1.1.10@ + # Conan 2.x + conan export --version 1.1.10 external/snappy + ``` + +Export our [Conan recipe for RocksDB](./external/rocksdb). +It does not override paths to dependencies when building with Visual Studio. + + ``` + # Conan 1.x + conan export external/rocksdb rocksdb/9.7.3@ + # Conan 2.x + conan export --version 9.7.3 external/rocksdb + ``` + +Export our [Conan recipe for SOCI](./external/soci). +It patches their CMake to correctly import its dependencies. + + ``` + # Conan 1.x + conan export external/soci soci/4.0.3@ + # Conan 2.x + conan export --version 4.0.3 external/soci + ``` + +Export our [Conan recipe for NuDB](./external/nudb). +It fixes some source files to add missing `#include`s. + + + ``` + # Conan 1.x + conan export external/nudb nudb/2.0.8@ + # Conan 2.x + conan export --version 2.0.8 external/nudb + ``` + +### Build and Test + +1. Create a build directory and move into it. + + ``` + mkdir .build + cd .build + ``` + + You can use any directory name. Conan treats your working directory as an + install folder and generates files with implementation details. + You don't need to worry about these files, but make sure to change + your working directory to your build directory before calling Conan. + + **Note:** You can specify a directory for the installation files by adding + the `install-folder` or `-if` option to every `conan install` command + in the next step. + +2. Use conan to generate CMake files for every configuration you want to build: + + ``` + conan install .. --output-folder . --build missing --settings build_type=Release + conan install .. --output-folder . --build missing --settings build_type=Debug + ``` + + To build Debug, in the next step, be sure to set `-DCMAKE_BUILD_TYPE=Debug` + + For a single-configuration generator, e.g. `Unix Makefiles` or `Ninja`, + you only need to run this command once. + For a multi-configuration generator, e.g. `Visual Studio`, you may want to + run it more than once. + + Each of these commands should also have a different `build_type` setting. + A second command with the same `build_type` setting will overwrite the files + generated by the first. You can pass the build type on the command line with + `--settings build_type=$BUILD_TYPE` or in the profile itself, + under the section `[settings]` with the key `build_type`. + + If you are using a Microsoft Visual C++ compiler, + then you will need to ensure consistency between the `build_type` setting + and the `compiler.runtime` setting. + + When `build_type` is `Release`, `compiler.runtime` should be `MT`. + + When `build_type` is `Debug`, `compiler.runtime` should be `MTd`. + + ``` + conan install .. --output-folder . --build missing --settings build_type=Release --settings compiler.runtime=MT + conan install .. --output-folder . --build missing --settings build_type=Debug --settings compiler.runtime=MTd + ``` + +3. Configure CMake and pass the toolchain file generated by Conan, located at + `$OUTPUT_FOLDER/build/generators/conan_toolchain.cmake`. + + Single-config generators: + + Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type] + and make sure it matches the one of the `build_type` settings + you chose in the previous step. + + For example, to build Debug, in the next command, replace "Release" with "Debug" + + ``` + cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -Dxrpld=ON -Dtests=ON .. + ``` + + + Multi-config generators: + + ``` + cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -Dxrpld=ON -Dtests=ON .. + ``` + + **Note:** You can pass build options for `rippled` in this step. + +5. Build `rippled`. + + For a single-configuration generator, it will build whatever configuration + you passed for `CMAKE_BUILD_TYPE`. For a multi-configuration generator, + you must pass the option `--config` to select the build configuration. + + Single-config generators: + + ``` + cmake --build . + ``` + + Multi-config generators: + + ``` + cmake --build . --config Release + cmake --build . --config Debug + ``` + +6. Test rippled. + + Single-config generators: + + ``` + ./rippled --unittest + ``` + + Multi-config generators: + + ``` + ./Release/rippled --unittest + ./Debug/rippled --unittest + ``` + + The location of `rippled` in your build directory depends on your CMake + generator. Pass `--help` to see the rest of the command line options. + + +## Coverage report + +The coverage report is intended for developers using compilers GCC +or Clang (including Apple Clang). It is generated by the build target `coverage`, +which is only enabled when the `coverage` option is set, e.g. with +`--options coverage=True` in `conan` or `-Dcoverage=ON` variable in `cmake` + +Prerequisites for the coverage report: + +- [gcovr tool][gcovr] (can be installed e.g. with [pip][python-pip]) +- `gcov` for GCC (installed with the compiler by default) or +- `llvm-cov` for Clang (installed with the compiler by default) +- `Debug` build type + +A coverage report is created when the following steps are completed, in order: + +1. `rippled` binary built with instrumentation data, enabled by the `coverage` + option mentioned above +2. completed run of unit tests, which populates coverage capture data +3. completed run of the `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) + to assemble both instrumentation data and the coverage capture data into a coverage report + +The above steps are automated into a single target `coverage`. The instrumented +`rippled` binary can also be used for regular development or testing work, at +the cost of extra disk space utilization and a small performance hit +(to store coverage capture). In case of a spurious failure of unit tests, it is +possible to re-run the `coverage` target without rebuilding the `rippled` binary +(since it is simply a dependency of the coverage report target). It is also possible +to select only specific tests for the purpose of the coverage report, by setting +the `coverage_test` variable in `cmake` + +The default coverage report format is `html-details`, but the user +can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake` +by setting the `coverage_format` variable in `cmake`. It is also possible +to generate more than one format at a time by setting the `coverage_extra_args` +variable in `cmake`. The specific command line used to run the `gcovr` tool will be +displayed if the `CODE_COVERAGE_VERBOSE` variable is set. + +By default, the code coverage tool runs parallel unit tests with `--unittest-jobs` + set to the number of available CPU cores. This may cause spurious test +errors on Apple. Developers can override the number of unit test jobs with +the `coverage_test_parallelism` variable in `cmake`. + +Example use with some cmake variables set: + +``` +cd .build +conan install .. --output-folder . --build missing --settings build_type=Debug +cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -Dxrpld=ON -Dtests=ON -Dcoverage_test_parallelism=2 -Dcoverage_format=html-details -Dcoverage_extra_args="--json coverage.json" -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. +cmake --build . --target coverage +``` + +After the `coverage` target is completed, the generated coverage report will be +stored inside the build directory, as either of: + +- file named `coverage.`_extension_ , with a suitable extension for the report format, or +- directory named `coverage`, with the `index.html` and other files inside, for the `html-details` or `html-nested` report formats. + + +## Options + +| Option | Default Value | Description | +| --- | ---| ---| +| `assert` | OFF | Enable assertions. +| `coverage` | OFF | Prepare the coverage report. | +| `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. | +| `tests` | OFF | Build tests. | +| `unity` | ON | Configure a unity build. | +| `xrpld` | OFF | Build the xrpld (`rippled`) application, and not just the libxrpl library. | + +[Unity builds][5] may be faster for the first build +(at the cost of much more memory) since they concatenate sources into fewer +translation units. Non-unity builds may be faster for incremental builds, +and can be helpful for detecting `#include` omissions. + + +## Troubleshooting + + +### Conan + +After any updates or changes to dependencies, you may need to do the following: + +1. Remove your build directory. +2. Remove the Conan cache: + ``` + rm -rf ~/.conan/data + ``` +4. Re-run [conan install](#build-and-test). + + +### 'protobuf/port_def.inc' file not found + +If `cmake --build .` results in an error due to a missing a protobuf file, then you might have generated CMake files for a different `build_type` than the `CMAKE_BUILD_TYPE` you passed to conan. + +``` +/rippled/.build/pb-xrpl.libpb/xrpl/proto/ripple.pb.h:10:10: fatal error: 'google/protobuf/port_def.inc' file not found + 10 | #include + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1 error generated. +``` + +For example, if you want to build Debug: + +1. For conan install, pass `--settings build_type=Debug` +2. For cmake, pass `-DCMAKE_BUILD_TYPE=Debug` + + +### no std::result_of + +If your compiler version is recent enough to have removed `std::result_of` as +part of C++20, e.g. Apple Clang 15.0, then you might need to add a preprocessor +definition to your build. + +``` +conan profile update 'options.boost:extra_b2_flags="define=BOOST_ASIO_HAS_STD_INVOKE_RESULT"' default +conan profile update 'env.CFLAGS="-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"' default +conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"' default +conan profile update 'conf.tools.build:cflags+=["-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"]' default +conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"]' default +``` + + +### call to 'async_teardown' is ambiguous + +If you are compiling with an early version of Clang 16, then you might hit +a [regression][6] when compiling C++20 that manifests as an [error in a Boost +header][7]. You can workaround it by adding this preprocessor definition: + +``` +conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default +conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default +``` + + +### recompile with -fPIC + +If you get a linker error suggesting that you recompile Boost with +position-independent code, such as: + +``` +/usr/bin/ld.gold: error: /home/username/.conan/data/boost/1.77.0/_/_/package/.../lib/libboost_container.a(alloc_lib.o): + requires unsupported dynamic reloc 11; recompile with -fPIC +``` + +Conan most likely downloaded a bad binary distribution of the dependency. +This seems to be a [bug][1] in Conan just for Boost 1.77.0 compiled with GCC +for Linux. The solution is to build the dependency locally by passing +`--build boost` when calling `conan install`. + +``` +conan install --build boost ... +``` + + +## Add a Dependency + +If you want to experiment with a new package, follow these steps: + +1. Search for the package on [Conan Center](https://conan.io/center/). +2. Modify [`conanfile.py`](./conanfile.py): + - Add a version of the package to the `requires` property. + - Change any default options for the package by adding them to the + `default_options` property (with syntax `'$package:$option': $value`). +3. Modify [`CMakeLists.txt`](./CMakeLists.txt): + - Add a call to `find_package($package REQUIRED)`. + - Link a library from the package to the target `ripple_libs` + (search for the existing call to `target_link_libraries(ripple_libs INTERFACE ...)`). +4. Start coding! Don't forget to include whatever headers you need from the package. + + +[1]: https://github.com/conan-io/conan-center-index/issues/13168 +[2]: https://en.cppreference.com/w/cpp/compiler_support/20 +[3]: https://docs.conan.io/en/latest/getting_started.html +[5]: https://en.wikipedia.org/wiki/Unity_build +[6]: https://github.com/boostorg/beast/issues/2648 +[7]: https://github.com/boostorg/beast/issues/2661 +[gcovr]: https://gcovr.com/en/stable/getting-started.html +[python-pip]: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/ +[build_type]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html +[profile]: https://docs.conan.io/en/latest/reference/profiles.html diff --git a/Builds/CMake/CMakeFuncs.cmake b/Builds/CMake/CMakeFuncs.cmake deleted file mode 100644 index c4b3ce7a8cc..00000000000 --- a/Builds/CMake/CMakeFuncs.cmake +++ /dev/null @@ -1,298 +0,0 @@ - -## "target" parsing..DEPRECATED and will be removed in future -macro(parse_target) - if (target) - # Parse the target - set(remaining ${target}) - while (remaining) - # get the component up to the next dot or end - string(REGEX REPLACE "^\\.?([^\\.]+).*$" "\\1" cur_component ${remaining}) - string(REGEX REPLACE "^\\.?[^\\.]+(.*$)" "\\1" remaining ${remaining}) - - if (${cur_component} STREQUAL gcc) - if (DEFINED ENV{GNU_CC}) - set(CMAKE_C_COMPILER $ENV{GNU_CC}) - elseif ($ENV{CC} MATCHES .*gcc.*) - set(CMAKE_C_COMPILER $ENV{CC}) - else() - find_program(CMAKE_C_COMPILER gcc) - endif() - - if (DEFINED ENV{GNU_CXX}) - set(CMAKE_CXX_COMPILER $ENV{GNU_CXX}) - elseif ($ENV{CXX} MATCHES .*g\\+\\+.*) - set(CMAKE_CXX_COMPILER $ENV{CXX}) - else() - find_program(CMAKE_CXX_COMPILER g++) - endif() - endif() - - if (${cur_component} STREQUAL clang) - if (DEFINED ENV{CLANG_CC}) - set(CMAKE_C_COMPILER $ENV{CLANG_CC}) - elseif ($ENV{CC} MATCHES .*clang.*) - set(CMAKE_C_COMPILER $ENV{CC}) - else() - find_program(CMAKE_C_COMPILER clang) - endif() - - if (DEFINED ENV{CLANG_CXX}) - set(CMAKE_CXX_COMPILER $ENV{CLANG_CXX}) - elseif ($ENV{CXX} MATCHES .*clang.*) - set(CMAKE_CXX_COMPILER $ENV{CXX}) - else() - find_program(CMAKE_CXX_COMPILER clang++) - endif() - endif() - - if (${cur_component} STREQUAL msvc) - # TBD - endif() - - if (${cur_component} STREQUAL unity) - set(unity ON CACHE BOOL "" FORCE) - endif() - - if (${cur_component} STREQUAL nounity) - set(unity OFF CACHE BOOL "" FORCE) - endif() - - if (${cur_component} STREQUAL debug) - set(release false) - endif() - - if (${cur_component} STREQUAL release) - set(release true) - endif() - - if (${cur_component} STREQUAL coverage) - set(coverage ON CACHE BOOL "" FORCE) - set(debug true) - endif() - - if (${cur_component} STREQUAL profile) - set(profile ON CACHE BOOL "" FORCE) - endif() - endwhile() - endif() - - if(CMAKE_C_COMPILER MATCHES "-NOTFOUND$" OR - CMAKE_CXX_COMPILER MATCHES "-NOTFOUND$") - message(FATAL_ERROR "Can not find appropriate compiler for target ${target}") - endif() - - if (release) - set(CMAKE_BUILD_TYPE Release) - else() - set(CMAKE_BUILD_TYPE Debug) - endif() -endmacro() - -############################################################ - -macro(group_sources_in source_dir curdir) - file(GLOB children RELATIVE ${source_dir}/${curdir} - ${source_dir}/${curdir}/*) - foreach (child ${children}) - if (IS_DIRECTORY ${source_dir}/${curdir}/${child}) - group_sources_in(${source_dir} ${curdir}/${child}) - else() - string(REPLACE "/" "\\" groupname ${curdir}) - source_group(${groupname} FILES - ${source_dir}/${curdir}/${child}) - endif() - endforeach() -endmacro() - -macro(group_sources curdir) - group_sources_in(${PROJECT_SOURCE_DIR} ${curdir}) -endmacro() - -macro (exclude_from_default target_) - set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_ALL ON) - set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON) -endmacro () - -macro (exclude_if_included target_) - get_directory_property(has_parent PARENT_DIRECTORY) - if (has_parent) - exclude_from_default (${target_}) - endif () -endmacro () - -function (print_ep_logs _target) - ExternalProject_Get_Property (${_target} STAMP_DIR) - add_custom_command(TARGET ${_target} POST_BUILD - COMMENT "${_target} BUILD OUTPUT" - COMMAND ${CMAKE_COMMAND} - -DIN_FILE=${STAMP_DIR}/${_target}-build-out.log - -P ${CMAKE_SOURCE_DIR}/Builds/CMake/echo_file.cmake - COMMAND ${CMAKE_COMMAND} - -DIN_FILE=${STAMP_DIR}/${_target}-build-err.log - -P ${CMAKE_SOURCE_DIR}/Builds/CMake/echo_file.cmake) -endfunction () - -#[=========================================================[ - This is a function override for one function in the - standard ExternalProject module. We want to change - the generated build script slightly to include printing - the build logs in the case of failure. Those modifications - have been made here. This function override could break - in the future if the ExternalProject module changes internal - function names or changes the way it generates the build - scripts. - See: - https://gitlab.kitware.com/cmake/cmake/blob/df1ddeec128d68cc636f2dde6c2acd87af5658b6/Modules/ExternalProject.cmake#L1855-1952 -#]=========================================================] - -function(_ep_write_log_script name step cmd_var) - ExternalProject_Get_Property(${name} stamp_dir) - set(command "${${cmd_var}}") - - set(make "") - set(code_cygpath_make "") - if(command MATCHES "^\\$\\(MAKE\\)") - # GNU make recognizes the string "$(MAKE)" as recursive make, so - # ensure that it appears directly in the makefile. - string(REGEX REPLACE "^\\$\\(MAKE\\)" "\${make}" command "${command}") - set(make "-Dmake=$(MAKE)") - - if(WIN32 AND NOT CYGWIN) - set(code_cygpath_make " -if(\${make} MATCHES \"^/\") - execute_process( - COMMAND cygpath -w \${make} - OUTPUT_VARIABLE cygpath_make - ERROR_VARIABLE cygpath_make - RESULT_VARIABLE cygpath_error - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(NOT cygpath_error) - set(make \${cygpath_make}) - endif() -endif() -") - endif() - endif() - - set(config "") - if("${CMAKE_CFG_INTDIR}" MATCHES "^\\$") - string(REPLACE "${CMAKE_CFG_INTDIR}" "\${config}" command "${command}") - set(config "-Dconfig=${CMAKE_CFG_INTDIR}") - endif() - - # Wrap multiple 'COMMAND' lines up into a second-level wrapper - # script so all output can be sent to one log file. - if(command MATCHES "(^|;)COMMAND;") - set(code_execute_process " -${code_cygpath_make} -execute_process(COMMAND \${command} RESULT_VARIABLE result) -if(result) - set(msg \"Command failed (\${result}):\\n\") - foreach(arg IN LISTS command) - set(msg \"\${msg} '\${arg}'\") - endforeach() - message(FATAL_ERROR \"\${msg}\") -endif() -") - set(code "") - set(cmd "") - set(sep "") - foreach(arg IN LISTS command) - if("x${arg}" STREQUAL "xCOMMAND") - if(NOT "x${cmd}" STREQUAL "x") - string(APPEND code "set(command \"${cmd}\")${code_execute_process}") - endif() - set(cmd "") - set(sep "") - else() - string(APPEND cmd "${sep}${arg}") - set(sep ";") - endif() - endforeach() - string(APPEND code "set(command \"${cmd}\")${code_execute_process}") - file(GENERATE OUTPUT "${stamp_dir}/${name}-${step}-$-impl.cmake" CONTENT "${code}") - set(command ${CMAKE_COMMAND} "-Dmake=\${make}" "-Dconfig=\${config}" -P ${stamp_dir}/${name}-${step}-$-impl.cmake) - endif() - - # Wrap the command in a script to log output to files. - set(script ${stamp_dir}/${name}-${step}-$.cmake) - set(logbase ${stamp_dir}/${name}-${step}) - set(code " -${code_cygpath_make} -function (_echo_file _fil) - file (READ \${_fil} _cont) - execute_process (COMMAND \${CMAKE_COMMAND} -E echo \"\${_cont}\") -endfunction () -set(command \"${command}\") -execute_process( - COMMAND \${command} - RESULT_VARIABLE result - OUTPUT_FILE \"${logbase}-out.log\" - ERROR_FILE \"${logbase}-err.log\" - ) -if(result) - set(msg \"Command failed: \${result}\\n\") - foreach(arg IN LISTS command) - set(msg \"\${msg} '\${arg}'\") - endforeach() - execute_process (COMMAND \${CMAKE_COMMAND} -E echo \"Build output for ${logbase} : \") - _echo_file (\"${logbase}-out.log\") - _echo_file (\"${logbase}-err.log\") - set(msg \"\${msg}\\nSee above\\n\") - message(FATAL_ERROR \"\${msg}\") -else() - set(msg \"${name} ${step} command succeeded. See also ${logbase}-*.log\") - message(STATUS \"\${msg}\") -endif() -") - file(GENERATE OUTPUT "${script}" CONTENT "${code}") - set(command ${CMAKE_COMMAND} ${make} ${config} -P ${script}) - set(${cmd_var} "${command}" PARENT_SCOPE) -endfunction() - -find_package(Git) - -# function that calls git log to get current hash -function (git_hash hash_val) - # note: optional second extra string argument not in signature - if (NOT GIT_FOUND) - return () - endif () - set (_hash "") - set (_format "%H") - if (ARGC GREATER_EQUAL 2) - string (TOLOWER ${ARGV1} _short) - if (_short STREQUAL "short") - set (_format "%h") - endif () - endif () - execute_process (COMMAND ${GIT_EXECUTABLE} "log" "--pretty=${_format}" "-n1" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - RESULT_VARIABLE _git_exit_code - OUTPUT_VARIABLE _temp_hash - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET) - if (_git_exit_code EQUAL 0) - set (_hash ${_temp_hash}) - endif () - set (${hash_val} "${_hash}" PARENT_SCOPE) -endfunction () - -function (git_branch branch_val) - if (NOT GIT_FOUND) - return () - endif () - set (_branch "") - execute_process (COMMAND ${GIT_EXECUTABLE} "rev-parse" "--abbrev-ref" "HEAD" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - RESULT_VARIABLE _git_exit_code - OUTPUT_VARIABLE _temp_branch - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET) - if (_git_exit_code EQUAL 0) - set (_branch ${_temp_branch}) - endif () - set (${branch_val} "${_branch}" PARENT_SCOPE) -endfunction () - diff --git a/Builds/CMake/CMake_sqlite3.txt b/Builds/CMake/CMake_sqlite3.txt deleted file mode 100644 index d80557a9fc6..00000000000 --- a/Builds/CMake/CMake_sqlite3.txt +++ /dev/null @@ -1,60 +0,0 @@ - -#[=========================================================[ - SQLITE doesn't provide build files in the - standard source-only distribution. So we wrote - a simple cmake file and we copy it to the - external project folder so that we can use - this file to build the lib with ExternalProject -#]=========================================================] - -add_library (sqlite3 STATIC sqlite3.c) -#[=========================================================[ - When compiled with SQLITE_THREADSAFE=1, SQLite operates - in serialized mode. In this mode, SQLite can be safely - used by multiple threads with no restriction. - - NOTE: This implies a global mutex! - - When compiled with SQLITE_THREADSAFE=2, SQLite can be - used in a multithreaded program so long as no two - threads attempt to use the same database connection at - the same time. - - NOTE: This is the preferred threading model, but not - currently enabled because we need to investigate our - use-model and concurrency requirements. - - TODO: consider whether any other options should be - used: https://www.sqlite.org/compile.html -#]=========================================================] - -target_compile_definitions (sqlite3 - PRIVATE - SQLITE_THREADSAFE=1 - HAVE_USLEEP=1) -target_compile_options (sqlite3 - PRIVATE - $<$: - -wd4100 - -wd4127 - -wd4232 - -wd4244 - -wd4701 - -wd4706 - -wd4996 - > - $<$>:-Wno-array-bounds>) -install ( - TARGETS - sqlite3 - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include) -install ( - FILES - sqlite3.h - sqlite3ext.h - DESTINATION include) - - diff --git a/Builds/CMake/FindBoost.cmake b/Builds/CMake/FindBoost.cmake deleted file mode 100644 index b100f09ae81..00000000000 --- a/Builds/CMake/FindBoost.cmake +++ /dev/null @@ -1,2170 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -#[=======================================================================[.rst: -FindBoost ---------- - -Find Boost include dirs and libraries - -Use this module by invoking find_package with the form:: - - find_package(Boost - [version] [EXACT] # Minimum or EXACT version e.g. 1.67.0 - [REQUIRED] # Fail with error if Boost is not found - [COMPONENTS ...] # Boost libraries by their canonical name - # e.g. "date_time" for "libboost_date_time" - [OPTIONAL_COMPONENTS ...] - # Optional Boost libraries by their canonical name) - ) # e.g. "date_time" for "libboost_date_time" - -This module finds headers and requested component libraries OR a CMake -package configuration file provided by a "Boost CMake" build. For the -latter case skip to the "Boost CMake" section below. For the former -case results are reported in variables:: - - Boost_FOUND - True if headers and requested libraries were found - Boost_INCLUDE_DIRS - Boost include directories - Boost_LIBRARY_DIRS - Link directories for Boost libraries - Boost_LIBRARIES - Boost component libraries to be linked - Boost__FOUND - True if component was found ( is upper-case) - Boost__LIBRARY - Libraries to link for component (may include - target_link_libraries debug/optimized keywords) - Boost_VERSION_MACRO - BOOST_VERSION value from boost/version.hpp - Boost_VERSION_STRING - Boost version number in x.y.z format - Boost_VERSION - if CMP0093 NEW => same as Boost_VERSION_STRING - if CMP0093 OLD or unset => same as Boost_VERSION_MACRO - Boost_LIB_VERSION - Version string appended to library filenames - Boost_VERSION_MAJOR - Boost major version number (X in X.y.z) - alias: Boost_MAJOR_VERSION - Boost_VERSION_MINOR - Boost minor version number (Y in x.Y.z) - alias: Boost_MINOR_VERSION - Boost_VERSION_PATCH - Boost subminor version number (Z in x.y.Z) - alias: Boost_SUBMINOR_VERSION - Boost_VERSION_COUNT - Amount of version components (3) - Boost_LIB_DIAGNOSTIC_DEFINITIONS (Windows) - - Pass to add_definitions() to have diagnostic - information about Boost's automatic linking - displayed during compilation - -Note that Boost Python components require a Python version suffix -(Boost 1.67 and later), e.g. ``python36`` or ``python27`` for the -versions built against Python 3.6 and 2.7, respectively. This also -applies to additional components using Python including -``mpi_python`` and ``numpy``. Earlier Boost releases may use -distribution-specific suffixes such as ``2``, ``3`` or ``2.7``. -These may also be used as suffixes, but note that they are not -portable. - -This module reads hints about search locations from variables:: - - BOOST_ROOT - Preferred installation prefix - (or BOOSTROOT) - BOOST_INCLUDEDIR - Preferred include directory e.g. /include - BOOST_LIBRARYDIR - Preferred library directory e.g. /lib - Boost_NO_SYSTEM_PATHS - Set to ON to disable searching in locations not - specified by these hint variables. Default is OFF. - Boost_ADDITIONAL_VERSIONS - - List of Boost versions not known to this module - (Boost install locations may contain the version) - -and saves search results persistently in CMake cache entries:: - - Boost_INCLUDE_DIR - Directory containing Boost headers - Boost_LIBRARY_DIR_RELEASE - Directory containing release Boost libraries - Boost_LIBRARY_DIR_DEBUG - Directory containing debug Boost libraries - Boost__LIBRARY_DEBUG - Component library debug variant - Boost__LIBRARY_RELEASE - Component library release variant - -The following :prop_tgt:`IMPORTED` targets are also defined:: - - Boost::headers - Target for header-only dependencies - (Boost include directory) - alias: Boost::boost - Boost:: - Target for specific component dependency - (shared or static library); is lower- - case - Boost::diagnostic_definitions - interface target to enable diagnostic - information about Boost's automatic linking - during compilation (adds BOOST_LIB_DIAGNOSTIC) - Boost::disable_autolinking - interface target to disable automatic - linking with MSVC (adds BOOST_ALL_NO_LIB) - Boost::dynamic_linking - interface target to enable dynamic linking - linking with MSVC (adds BOOST_ALL_DYN_LINK) - -Implicit dependencies such as ``Boost::filesystem`` requiring -``Boost::system`` will be automatically detected and satisfied, even -if system is not specified when using :command:`find_package` and if -``Boost::system`` is not added to :command:`target_link_libraries`. If using -``Boost::thread``, then ``Threads::Threads`` will also be added automatically. - -It is important to note that the imported targets behave differently -than variables created by this module: multiple calls to -:command:`find_package(Boost)` in the same directory or sub-directories with -different options (e.g. static or shared) will not override the -values of the targets created by the first call. - -Users may set these hints or results as ``CACHE`` entries. Projects -should not read these entries directly but instead use the above -result variables. Note that some hint names start in upper-case -"BOOST". One may specify these as environment variables if they are -not specified as CMake variables or cache entries. - -This module first searches for the ``Boost`` header files using the above -hint variables (excluding ``BOOST_LIBRARYDIR``) and saves the result in -``Boost_INCLUDE_DIR``. Then it searches for requested component libraries -using the above hints (excluding ``BOOST_INCLUDEDIR`` and -``Boost_ADDITIONAL_VERSIONS``), "lib" directories near ``Boost_INCLUDE_DIR``, -and the library name configuration settings below. It saves the -library directories in ``Boost_LIBRARY_DIR_DEBUG`` and -``Boost_LIBRARY_DIR_RELEASE`` and individual library -locations in ``Boost__LIBRARY_DEBUG`` and ``Boost__LIBRARY_RELEASE``. -When one changes settings used by previous searches in the same build -tree (excluding environment variables) this module discards previous -search results affected by the changes and searches again. - -Boost libraries come in many variants encoded in their file name. -Users or projects may tell this module which variant to find by -setting variables:: - - Boost_USE_DEBUG_LIBS - Set to ON or OFF to specify whether to search - and use the debug libraries. Default is ON. - Boost_USE_RELEASE_LIBS - Set to ON or OFF to specify whether to search - and use the release libraries. Default is ON. - Boost_USE_MULTITHREADED - Set to OFF to use the non-multithreaded - libraries ('mt' tag). Default is ON. - Boost_USE_STATIC_LIBS - Set to ON to force the use of the static - libraries. Default is OFF. - Boost_USE_STATIC_RUNTIME - Set to ON or OFF to specify whether to use - libraries linked statically to the C++ runtime - ('s' tag). Default is platform dependent. - Boost_USE_DEBUG_RUNTIME - Set to ON or OFF to specify whether to use - libraries linked to the MS debug C++ runtime - ('g' tag). Default is ON. - Boost_USE_DEBUG_PYTHON - Set to ON to use libraries compiled with a - debug Python build ('y' tag). Default is OFF. - Boost_USE_STLPORT - Set to ON to use libraries compiled with - STLPort ('p' tag). Default is OFF. - Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS - - Set to ON to use libraries compiled with - STLPort deprecated "native iostreams" - ('n' tag). Default is OFF. - Boost_COMPILER - Set to the compiler-specific library suffix - (e.g. "-gcc43"). Default is auto-computed - for the C++ compiler in use. A list may be - used if multiple compatible suffixes should - be tested for, in decreasing order of - preference. - Boost_ARCHITECTURE - Set to the architecture-specific library suffix - (e.g. "-x64"). Default is auto-computed for the - C++ compiler in use. - Boost_THREADAPI - Suffix for "thread" component library name, - such as "pthread" or "win32". Names with - and without this suffix will both be tried. - Boost_NAMESPACE - Alternate namespace used to build boost with - e.g. if set to "myboost", will search for - myboost_thread instead of boost_thread. - -Other variables one may set to control this module are:: - - Boost_DEBUG - Set to ON to enable debug output from FindBoost. - Please enable this before filing any bug report. - Boost_REALPATH - Set to ON to resolve symlinks for discovered - libraries to assist with packaging. For example, - the "system" component library may be resolved to - "/usr/lib/libboost_system.so.1.67.0" instead of - "/usr/lib/libboost_system.so". This does not - affect linking and should not be enabled unless - the user needs this information. - Boost_LIBRARY_DIR - Default value for Boost_LIBRARY_DIR_RELEASE and - Boost_LIBRARY_DIR_DEBUG. - -On Visual Studio and Borland compilers Boost headers request automatic -linking to corresponding libraries. This requires matching libraries -to be linked explicitly or available in the link library search path. -In this case setting ``Boost_USE_STATIC_LIBS`` to ``OFF`` may not achieve -dynamic linking. Boost automatic linking typically requests static -libraries with a few exceptions (such as ``Boost.Python``). Use:: - - add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) - -to ask Boost to report information about automatic linking requests. - -Example to find Boost headers only:: - - find_package(Boost 1.36.0) - if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - add_executable(foo foo.cc) - endif() - -Example to find Boost libraries and use imported targets:: - - find_package(Boost 1.56 REQUIRED COMPONENTS - date_time filesystem iostreams) - add_executable(foo foo.cc) - target_link_libraries(foo Boost::date_time Boost::filesystem - Boost::iostreams) - -Example to find Boost Python 3.6 libraries and use imported targets:: - - find_package(Boost 1.67 REQUIRED COMPONENTS - python36 numpy36) - add_executable(foo foo.cc) - target_link_libraries(foo Boost::python36 Boost::numpy36) - -Example to find Boost headers and some *static* (release only) libraries:: - - set(Boost_USE_STATIC_LIBS ON) # only find static libs - set(Boost_USE_DEBUG_LIBS OFF) # ignore debug libs and - set(Boost_USE_RELEASE_LIBS ON) # only find release libs - set(Boost_USE_MULTITHREADED ON) - set(Boost_USE_STATIC_RUNTIME OFF) - find_package(Boost 1.66.0 COMPONENTS date_time filesystem system ...) - if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - add_executable(foo foo.cc) - target_link_libraries(foo ${Boost_LIBRARIES}) - endif() - -Boost CMake -^^^^^^^^^^^ - -If Boost was built using the boost-cmake project or from Boost 1.70.0 on -it provides a package configuration file for use with find_package's config mode. -This module looks for the package configuration file called -``BoostConfig.cmake`` or ``boost-config.cmake`` and stores the result in -``CACHE`` entry "Boost_DIR". If found, the package configuration file is loaded -and this module returns with no further action. See documentation of -the Boost CMake package configuration for details on what it provides. - -Set ``Boost_NO_BOOST_CMAKE`` to ``ON``, to disable the search for boost-cmake. -#]=======================================================================] - -# The FPHSA helper provides standard way of reporting final search results to -# the user including the version and component checks. -include(FindPackageHandleStandardArgs) - -# Save project's policies -cmake_policy(PUSH) -cmake_policy(SET CMP0057 NEW) # if IN_LIST - -#------------------------------------------------------------------------------- -# Before we go searching, check whether a boost cmake package is available, unless -# the user specifically asked NOT to search for one. -# -# If Boost_DIR is set, this behaves as any find_package call would. If not, -# it looks at BOOST_ROOT and BOOSTROOT to find Boost. -# -if (NOT Boost_NO_BOOST_CMAKE) - # If Boost_DIR is not set, look for BOOSTROOT and BOOST_ROOT as alternatives, - # since these are more conventional for Boost. - if ("$ENV{Boost_DIR}" STREQUAL "") - if (NOT "$ENV{BOOST_ROOT}" STREQUAL "") - set(ENV{Boost_DIR} $ENV{BOOST_ROOT}) - elseif (NOT "$ENV{BOOSTROOT}" STREQUAL "") - set(ENV{Boost_DIR} $ENV{BOOSTROOT}) - endif() - endif() - - # Do the same find_package call but look specifically for the CMake version. - # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no - # need to delegate them to this find_package call. - find_package(Boost QUIET NO_MODULE) - mark_as_advanced(Boost_DIR) - - # If we found a boost cmake package, then we're done. Print out what we found. - # Otherwise let the rest of the module try to find it. - if(Boost_FOUND) - # Neither the legacy boost-cmake nor the new builtin BoostConfig (as in 1.70) - # report the found components in the standard variables, so we need to convert - # them here - if(Boost_FIND_COMPONENTS) - foreach(_comp IN LISTS Boost_FIND_COMPONENTS) - string(TOUPPER ${_comp} _uppercomp) - if(DEFINED Boost${_comp}_FOUND) - set(Boost_${_comp}_FOUND ${Boost${_comp}_FOUND}) - elseif(DEFINED Boost_${_uppercomp}_FOUND) - set(Boost_${_comp}_FOUND ${Boost_${_uppercomp}_FOUND}) - endif() - endforeach() - endif() - - find_package_handle_standard_args(Boost HANDLE_COMPONENTS CONFIG_MODE) - - # Restore project's policies - cmake_policy(POP) - return() - endif() -endif() - - -#------------------------------------------------------------------------------- -# FindBoost functions & macros -# - -# -# Print debug text if Boost_DEBUG is set. -# Call example: -# _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "debug message") -# -function(_Boost_DEBUG_PRINT file line text) - if(Boost_DEBUG) - message(STATUS "[ ${file}:${line} ] ${text}") - endif() -endfunction() - -# -# _Boost_DEBUG_PRINT_VAR(file line variable_name [ENVIRONMENT] -# [SOURCE "short explanation of origin of var value"]) -# -# ENVIRONMENT - look up environment variable instead of CMake variable -# -# Print variable name and its value if Boost_DEBUG is set. -# Call example: -# _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" BOOST_ROOT) -# -function(_Boost_DEBUG_PRINT_VAR file line name) - if(Boost_DEBUG) - cmake_parse_arguments(_args "ENVIRONMENT" "SOURCE" "" ${ARGN}) - - unset(source) - if(_args_SOURCE) - set(source " (${_args_SOURCE})") - endif() - - if(_args_ENVIRONMENT) - if(DEFINED ENV{${name}}) - set(value "\"$ENV{${name}}\"") - else() - set(value "") - endif() - set(_name "ENV{${name}}") - else() - if(DEFINED "${name}") - set(value "\"${${name}}\"") - else() - set(value "") - endif() - set(_name "${name}") - endif() - - _Boost_DEBUG_PRINT("${file}" "${line}" "${_name} = ${value}${source}") - endif() -endfunction() - -############################################ -# -# Check the existence of the libraries. -# -############################################ -# This macro was taken directly from the FindQt4.cmake file that is included -# with the CMake distribution. This is NOT my work. All work was done by the -# original authors of the FindQt4.cmake file. Only minor modifications were -# made to remove references to Qt and make this file more generally applicable -# And ELSE/ENDIF pairs were removed for readability. -######################################################################### - -macro(_Boost_ADJUST_LIB_VARS basename) - if(Boost_INCLUDE_DIR ) - if(Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) - # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for - # single-config generators, set optimized and debug libraries - get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) - if(_isMultiConfig OR CMAKE_BUILD_TYPE) - set(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) - else() - # For single-config generators where CMAKE_BUILD_TYPE has no value, - # just use the release libraries - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) - endif() - # FIXME: This probably should be set for both cases - set(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) - endif() - - # if only the release version was found, set the debug variable also to the release version - if(Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) - set(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) - set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) - endif() - - # if only the debug version was found, set the release variable also to the debug version - if(Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) - set(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) - set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) - endif() - - # If the debug & release library ends up being the same, omit the keywords - if("${Boost_${basename}_LIBRARY_RELEASE}" STREQUAL "${Boost_${basename}_LIBRARY_DEBUG}") - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) - set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE} ) - endif() - - if(Boost_${basename}_LIBRARY AND Boost_${basename}_HEADER) - set(Boost_${basename}_FOUND ON) - if("x${basename}" STREQUAL "xTHREAD" AND NOT TARGET Threads::Threads) - string(APPEND Boost_ERROR_REASON_THREAD " (missing dependency: Threads)") - set(Boost_THREAD_FOUND OFF) - endif() - endif() - - endif() - # Make variables changeable to the advanced user - mark_as_advanced( - Boost_${basename}_LIBRARY_RELEASE - Boost_${basename}_LIBRARY_DEBUG - ) -endmacro() - -# Detect changes in used variables. -# Compares the current variable value with the last one. -# In short form: -# v != v_LAST -> CHANGED = 1 -# v is defined, v_LAST not -> CHANGED = 1 -# v is not defined, but v_LAST is -> CHANGED = 1 -# otherwise -> CHANGED = 0 -# CHANGED is returned in variable named ${changed_var} -macro(_Boost_CHANGE_DETECT changed_var) - set(${changed_var} 0) - foreach(v ${ARGN}) - if(DEFINED _Boost_COMPONENTS_SEARCHED) - if(${v}) - if(_${v}_LAST) - string(COMPARE NOTEQUAL "${${v}}" "${_${v}_LAST}" _${v}_CHANGED) - else() - set(_${v}_CHANGED 1) - endif() - elseif(_${v}_LAST) - set(_${v}_CHANGED 1) - endif() - if(_${v}_CHANGED) - set(${changed_var} 1) - endif() - else() - set(_${v}_CHANGED 0) - endif() - endforeach() -endmacro() - -# -# Find the given library (var). -# Use 'build_type' to support different lib paths for RELEASE or DEBUG builds -# -macro(_Boost_FIND_LIBRARY var build_type) - - find_library(${var} ${ARGN}) - - if(${var}) - # If this is the first library found then save Boost_LIBRARY_DIR_[RELEASE,DEBUG]. - if(NOT Boost_LIBRARY_DIR_${build_type}) - get_filename_component(_dir "${${var}}" PATH) - set(Boost_LIBRARY_DIR_${build_type} "${_dir}" CACHE PATH "Boost library directory ${build_type}" FORCE) - endif() - elseif(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) - # Try component-specific hints but do not save Boost_LIBRARY_DIR_[RELEASE,DEBUG]. - find_library(${var} HINTS ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT} ${ARGN}) - endif() - - # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is known then search only there. - if(Boost_LIBRARY_DIR_${build_type}) - set(_boost_LIBRARY_SEARCH_DIRS_${build_type} ${Boost_LIBRARY_DIR_${build_type}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "Boost_LIBRARY_DIR_${build_type}") - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "_boost_LIBRARY_SEARCH_DIRS_${build_type}") - endif() -endmacro() - -#------------------------------------------------------------------------------- - -# Convert CMAKE_CXX_COMPILER_VERSION to boost compiler suffix version. -function(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION _OUTPUT_VERSION_MAJOR _OUTPUT_VERSION_MINOR) - string(REGEX REPLACE "([0-9]+)\\.([0-9]+)(\\.[0-9]+)?" "\\1" - _boost_COMPILER_VERSION_MAJOR "${CMAKE_CXX_COMPILER_VERSION}") - string(REGEX REPLACE "([0-9]+)\\.([0-9]+)(\\.[0-9]+)?" "\\2" - _boost_COMPILER_VERSION_MINOR "${CMAKE_CXX_COMPILER_VERSION}") - - set(_boost_COMPILER_VERSION "${_boost_COMPILER_VERSION_MAJOR}${_boost_COMPILER_VERSION_MINOR}") - - set(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE) - set(${_OUTPUT_VERSION_MAJOR} ${_boost_COMPILER_VERSION_MAJOR} PARENT_SCOPE) - set(${_OUTPUT_VERSION_MINOR} ${_boost_COMPILER_VERSION_MINOR} PARENT_SCOPE) -endfunction() - -# -# Take a list of libraries with "thread" in it -# and prepend duplicates with "thread_${Boost_THREADAPI}" -# at the front of the list -# -function(_Boost_PREPEND_LIST_WITH_THREADAPI _output) - set(_orig_libnames ${ARGN}) - string(REPLACE "thread" "thread_${Boost_THREADAPI}" _threadapi_libnames "${_orig_libnames}") - set(${_output} ${_threadapi_libnames} ${_orig_libnames} PARENT_SCOPE) -endfunction() - -# -# If a library is found, replace its cache entry with its REALPATH -# -function(_Boost_SWAP_WITH_REALPATH _library _docstring) - if(${_library}) - get_filename_component(_boost_filepathreal ${${_library}} REALPATH) - unset(${_library} CACHE) - set(${_library} ${_boost_filepathreal} CACHE FILEPATH "${_docstring}") - endif() -endfunction() - -function(_Boost_CHECK_SPELLING _var) - if(${_var}) - string(TOUPPER ${_var} _var_UC) - message(FATAL_ERROR "ERROR: ${_var} is not the correct spelling. The proper spelling is ${_var_UC}.") - endif() -endfunction() - -# Guesses Boost's compiler prefix used in built library names -# Returns the guess by setting the variable pointed to by _ret -function(_Boost_GUESS_COMPILER_PREFIX _ret) - if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel") - if(WIN32) - set (_boost_COMPILER "-iw") - else() - set (_boost_COMPILER "-il") - endif() - elseif (GHSMULTI) - set(_boost_COMPILER "-ghs") - elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") - if(MSVC_TOOLSET_VERSION GREATER_EQUAL 150) - # Not yet known. - set(_boost_COMPILER "") - elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 140) - # MSVC toolset 14.x versions are forward compatible. - set(_boost_COMPILER "") - foreach(v 9 8 7 6 5 4 3 2 1 0) - if(MSVC_TOOLSET_VERSION GREATER_EQUAL 14${v}) - list(APPEND _boost_COMPILER "-vc14${v}") - endif() - endforeach() - elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 80) - set(_boost_COMPILER "-vc${MSVC_TOOLSET_VERSION}") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.10) - set(_boost_COMPILER "-vc71") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) # Good luck! - set(_boost_COMPILER "-vc7") # yes, this is correct - else() # VS 6.0 Good luck! - set(_boost_COMPILER "-vc6") # yes, this is correct - endif() - - if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang") - string(REPLACE "." ";" VERSION_LIST "${CMAKE_CXX_COMPILER_VERSION}") - list(GET VERSION_LIST 0 CLANG_VERSION_MAJOR) - set(_boost_COMPILER "-clangw${CLANG_VERSION_MAJOR};${_boost_COMPILER}") - endif() - elseif (BORLAND) - set(_boost_COMPILER "-bcb") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") - set(_boost_COMPILER "-sw") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "XL") - set(_boost_COMPILER "-xlc") - elseif (MINGW) - if(Boost_VERSION_STRING VERSION_LESS 1.34) - set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34 - else() - _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION _boost_COMPILER_VERSION_MAJOR _boost_COMPILER_VERSION_MINOR) - set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") - endif() - elseif (UNIX) - _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION _boost_COMPILER_VERSION_MAJOR _boost_COMPILER_VERSION_MINOR) - if(NOT Boost_VERSION_STRING VERSION_LESS 1.69.0) - # From GCC 5 and clang 4, versioning changes and minor becomes patch. - # For those compilers, patch is exclude from compiler tag in Boost 1.69+ library naming. - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND _boost_COMPILER_VERSION_MAJOR VERSION_GREATER 4) - set(_boost_COMPILER_VERSION "${_boost_COMPILER_VERSION_MAJOR}") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND _boost_COMPILER_VERSION_MAJOR VERSION_GREATER 3) - set(_boost_COMPILER_VERSION "${_boost_COMPILER_VERSION_MAJOR}") - endif() - endif() - - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if(Boost_VERSION_STRING VERSION_LESS 1.34) - set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34 - else() - # Determine which version of GCC we have. - if(APPLE) - if(Boost_VERSION_STRING VERSION_LESS 1.36.0) - # In Boost <= 1.35.0, there is no mangled compiler name for - # the macOS/Darwin version of GCC. - set(_boost_COMPILER "") - else() - # In Boost 1.36.0 and newer, the mangled compiler name used - # on macOS/Darwin is "xgcc". - set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") - endif() - else() - set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") - endif() - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - # TODO: Find out any Boost version constraints vs clang support. - set(_boost_COMPILER "-clang${_boost_COMPILER_VERSION}") - endif() - else() - set(_boost_COMPILER "") - endif() - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "_boost_COMPILER" SOURCE "guessed") - set(${_ret} ${_boost_COMPILER} PARENT_SCOPE) -endfunction() - -# -# Get component dependencies. Requires the dependencies to have been -# defined for the Boost release version. -# -# component - the component to check -# _ret - list of library dependencies -# -function(_Boost_COMPONENT_DEPENDENCIES component _ret) - # Note: to add a new Boost release, run - # - # % cmake -DBOOST_DIR=/path/to/boost/source -P Utilities/Scripts/BoostScanDeps.cmake - # - # The output may be added in a new block below. If it's the same as - # the previous release, simply update the version range of the block - # for the previous release. Also check if any new components have - # been added, and add any new components to - # _Boost_COMPONENT_HEADERS. - # - # This information was originally generated by running - # BoostScanDeps.cmake against every boost release to date supported - # by FindBoost: - # - # % for version in /path/to/boost/sources/* - # do - # cmake -DBOOST_DIR=$version -P Utilities/Scripts/BoostScanDeps.cmake - # done - # - # The output was then updated by search and replace with these regexes: - # - # - Strip message(STATUS) prefix dashes - # s;^-- ;; - # - Indent - # s;^set(; set(;; - # - Add conditionals - # s;Scanning /path/to/boost/sources/boost_\(.*\)_\(.*\)_\(.*); elseif(NOT Boost_VERSION_STRING VERSION_LESS \1\.\2\.\3 AND Boost_VERSION_STRING VERSION_LESS xxxx); - # - # This results in the logic seen below, but will require the xxxx - # replacing with the following Boost release version (or the next - # minor version to be released, e.g. 1.59 was the latest at the time - # of writing, making 1.60 the next. Identical consecutive releases - # were then merged together by updating the end range of the first - # block and removing the following redundant blocks. - # - # Running the script against all historical releases should be - # required only if the BoostScanDeps.cmake script logic is changed. - # The addition of a new release should only require it to be run - # against the new release. - - # Handle Python version suffixes - if(component MATCHES "^(python|mpi_python|numpy)([0-9][0-9]?|[0-9]\\.[0-9])\$") - set(component "${CMAKE_MATCH_1}") - set(component_python_version "${CMAKE_MATCH_2}") - endif() - - set(_Boost_IMPORTED_TARGETS TRUE) - if(Boost_VERSION_STRING AND Boost_VERSION_STRING VERSION_LESS 1.33.0) - message(WARNING "Imported targets and dependency information not available for Boost version ${Boost_VERSION_STRING} (all versions older than 1.33)") - set(_Boost_IMPORTED_TARGETS FALSE) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.33.0 AND Boost_VERSION_STRING VERSION_LESS 1.35.0) - set(_Boost_IOSTREAMS_DEPENDENCIES regex thread) - set(_Boost_REGEX_DEPENDENCIES thread) - set(_Boost_WAVE_DEPENDENCIES filesystem thread) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.35.0 AND Boost_VERSION_STRING VERSION_LESS 1.36.0) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_WAVE_DEPENDENCIES filesystem system thread) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.36.0 AND Boost_VERSION_STRING VERSION_LESS 1.38.0) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_WAVE_DEPENDENCIES filesystem system thread) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.38.0 AND Boost_VERSION_STRING VERSION_LESS 1.43.0) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES date_time) - set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.43.0 AND Boost_VERSION_STRING VERSION_LESS 1.44.0) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES date_time) - set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.44.0 AND Boost_VERSION_STRING VERSION_LESS 1.45.0) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random serialization) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES date_time) - set(_Boost_WAVE_DEPENDENCIES serialization filesystem system thread date_time) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.45.0 AND Boost_VERSION_STRING VERSION_LESS 1.47.0) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES date_time) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.47.0 AND Boost_VERSION_STRING VERSION_LESS 1.48.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES date_time) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.48.0 AND Boost_VERSION_STRING VERSION_LESS 1.50.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES date_time) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.50.0 AND Boost_VERSION_STRING VERSION_LESS 1.53.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.53.0 AND Boost_VERSION_STRING VERSION_LESS 1.54.0) - set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.54.0 AND Boost_VERSION_STRING VERSION_LESS 1.55.0) - set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.55.0 AND Boost_VERSION_STRING VERSION_LESS 1.56.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.56.0 AND Boost_VERSION_STRING VERSION_LESS 1.59.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_RANDOM_DEPENDENCIES system) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.59.0 AND Boost_VERSION_STRING VERSION_LESS 1.60.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_RANDOM_DEPENDENCIES system) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.60.0 AND Boost_VERSION_STRING VERSION_LESS 1.61.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_RANDOM_DEPENDENCIES system) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.61.0 AND Boost_VERSION_STRING VERSION_LESS 1.62.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_RANDOM_DEPENDENCIES system) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.62.0 AND Boost_VERSION_STRING VERSION_LESS 1.63.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_RANDOM_DEPENDENCIES system) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.63.0 AND Boost_VERSION_STRING VERSION_LESS 1.65.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_COROUTINE2_DEPENDENCIES context fiber thread chrono system date_time) - set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_RANDOM_DEPENDENCIES system) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.65.0 AND Boost_VERSION_STRING VERSION_LESS 1.67.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) - set(_Boost_RANDOM_DEPENDENCIES system) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.67.0 AND Boost_VERSION_STRING VERSION_LESS 1.68.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) - set(_Boost_RANDOM_DEPENDENCIES system) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.68.0 AND Boost_VERSION_STRING VERSION_LESS 1.69.0) - set(_Boost_CHRONO_DEPENDENCIES system) - set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) - set(_Boost_CONTRACT_DEPENDENCIES thread chrono system date_time) - set(_Boost_COROUTINE_DEPENDENCIES context system) - set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) - set(_Boost_FILESYSTEM_DEPENDENCIES system) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) - set(_Boost_RANDOM_DEPENDENCIES system) - set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - elseif(NOT Boost_VERSION_STRING VERSION_LESS 1.69.0 AND Boost_VERSION_STRING VERSION_LESS 1.70.0) - set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time) - set(_Boost_COROUTINE_DEPENDENCIES context) - set(_Boost_FIBER_DEPENDENCIES context) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) - set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - else() - if(NOT Boost_VERSION_STRING VERSION_LESS 1.70.0) - set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time) - set(_Boost_COROUTINE_DEPENDENCIES context) - set(_Boost_FIBER_DEPENDENCIES context) - set(_Boost_IOSTREAMS_DEPENDENCIES regex) - set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic) - set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) - set(_Boost_MPI_DEPENDENCIES serialization) - set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) - set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) - set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic) - set(_Boost_TIMER_DEPENDENCIES chrono system) - set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic) - set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - endif() - if(NOT Boost_VERSION_STRING VERSION_LESS 1.71.0) - message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets") - endif() - endif() - - string(TOUPPER ${component} uppercomponent) - set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) - set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE) - - string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_Boost_${uppercomponent}_DEPENDENCIES}") - if (NOT _boost_DEPS_STRING) - set(_boost_DEPS_STRING "(none)") - endif() - # message(STATUS "Dependencies for Boost::${component}: ${_boost_DEPS_STRING}") -endfunction() - -# -# Get component headers. This is the primary header (or headers) for -# a given component, and is used to check that the headers are present -# as well as the library itself as an extra sanity check of the build -# environment. -# -# component - the component to check -# _hdrs -# -function(_Boost_COMPONENT_HEADERS component _hdrs) - # Handle Python version suffixes - if(component MATCHES "^(python|mpi_python|numpy)([0-9][0-9]?|[0-9]\\.[0-9])\$") - set(component "${CMAKE_MATCH_1}") - set(component_python_version "${CMAKE_MATCH_2}") - endif() - - # Note: new boost components will require adding here. The header - # must be present in all versions of Boost providing a library. - set(_Boost_ATOMIC_HEADERS "boost/atomic.hpp") - set(_Boost_CHRONO_HEADERS "boost/chrono.hpp") - set(_Boost_CONTAINER_HEADERS "boost/container/container_fwd.hpp") - set(_Boost_CONTRACT_HEADERS "boost/contract.hpp") - if(Boost_VERSION_STRING VERSION_LESS 1.61.0) - set(_Boost_CONTEXT_HEADERS "boost/context/all.hpp") - else() - set(_Boost_CONTEXT_HEADERS "boost/context/detail/fcontext.hpp") - endif() - set(_Boost_COROUTINE_HEADERS "boost/coroutine/all.hpp") - set(_Boost_DATE_TIME_HEADERS "boost/date_time/date.hpp") - set(_Boost_EXCEPTION_HEADERS "boost/exception/exception.hpp") - set(_Boost_FIBER_HEADERS "boost/fiber/all.hpp") - set(_Boost_FILESYSTEM_HEADERS "boost/filesystem/path.hpp") - set(_Boost_GRAPH_HEADERS "boost/graph/adjacency_list.hpp") - set(_Boost_GRAPH_PARALLEL_HEADERS "boost/graph/adjacency_list.hpp") - set(_Boost_IOSTREAMS_HEADERS "boost/iostreams/stream.hpp") - set(_Boost_LOCALE_HEADERS "boost/locale.hpp") - set(_Boost_LOG_HEADERS "boost/log/core.hpp") - set(_Boost_LOG_SETUP_HEADERS "boost/log/detail/setup_config.hpp") - set(_Boost_MATH_HEADERS "boost/math_fwd.hpp") - set(_Boost_MATH_C99_HEADERS "boost/math/tr1.hpp") - set(_Boost_MATH_C99F_HEADERS "boost/math/tr1.hpp") - set(_Boost_MATH_C99L_HEADERS "boost/math/tr1.hpp") - set(_Boost_MATH_TR1_HEADERS "boost/math/tr1.hpp") - set(_Boost_MATH_TR1F_HEADERS "boost/math/tr1.hpp") - set(_Boost_MATH_TR1L_HEADERS "boost/math/tr1.hpp") - set(_Boost_MPI_HEADERS "boost/mpi.hpp") - set(_Boost_MPI_PYTHON_HEADERS "boost/mpi/python/config.hpp") - set(_Boost_NUMPY_HEADERS "boost/python/numpy.hpp") - set(_Boost_PRG_EXEC_MONITOR_HEADERS "boost/test/prg_exec_monitor.hpp") - set(_Boost_PROGRAM_OPTIONS_HEADERS "boost/program_options.hpp") - set(_Boost_PYTHON_HEADERS "boost/python.hpp") - set(_Boost_RANDOM_HEADERS "boost/random.hpp") - set(_Boost_REGEX_HEADERS "boost/regex.hpp") - set(_Boost_SERIALIZATION_HEADERS "boost/serialization/serialization.hpp") - set(_Boost_SIGNALS_HEADERS "boost/signals.hpp") - set(_Boost_STACKTRACE_ADDR2LINE_HEADERS "boost/stacktrace.hpp") - set(_Boost_STACKTRACE_BACKTRACE_HEADERS "boost/stacktrace.hpp") - set(_Boost_STACKTRACE_BASIC_HEADERS "boost/stacktrace.hpp") - set(_Boost_STACKTRACE_NOOP_HEADERS "boost/stacktrace.hpp") - set(_Boost_STACKTRACE_WINDBG_CACHED_HEADERS "boost/stacktrace.hpp") - set(_Boost_STACKTRACE_WINDBG_HEADERS "boost/stacktrace.hpp") - set(_Boost_SYSTEM_HEADERS "boost/system/config.hpp") - set(_Boost_TEST_EXEC_MONITOR_HEADERS "boost/test/test_exec_monitor.hpp") - set(_Boost_THREAD_HEADERS "boost/thread.hpp") - set(_Boost_TIMER_HEADERS "boost/timer.hpp") - set(_Boost_TYPE_ERASURE_HEADERS "boost/type_erasure/config.hpp") - set(_Boost_UNIT_TEST_FRAMEWORK_HEADERS "boost/test/framework.hpp") - set(_Boost_WAVE_HEADERS "boost/wave.hpp") - set(_Boost_WSERIALIZATION_HEADERS "boost/archive/text_wiarchive.hpp") - if(WIN32) - set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") - set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") - endif() - - string(TOUPPER ${component} uppercomponent) - set(${_hdrs} ${_Boost_${uppercomponent}_HEADERS} PARENT_SCOPE) - - string(REGEX REPLACE ";" " " _boost_HDRS_STRING "${_Boost_${uppercomponent}_HEADERS}") - if (NOT _boost_HDRS_STRING) - set(_boost_HDRS_STRING "(none)") - endif() - # message(STATUS "Headers for Boost::${component}: ${_boost_HDRS_STRING}") -endfunction() - -# -# Determine if any missing dependencies require adding to the component list. -# -# Sets _Boost_${COMPONENT}_DEPENDENCIES for each required component, -# plus _Boost_IMPORTED_TARGETS (TRUE if imported targets should be -# defined; FALSE if dependency information is unavailable). -# -# componentvar - the component list variable name -# extravar - the indirect dependency list variable name -# -# -function(_Boost_MISSING_DEPENDENCIES componentvar extravar) - # _boost_unprocessed_components - list of components requiring processing - # _boost_processed_components - components already processed (or currently being processed) - # _boost_new_components - new components discovered for future processing - # - list(APPEND _boost_unprocessed_components ${${componentvar}}) - - while(_boost_unprocessed_components) - list(APPEND _boost_processed_components ${_boost_unprocessed_components}) - foreach(component ${_boost_unprocessed_components}) - string(TOUPPER ${component} uppercomponent) - set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) - _Boost_COMPONENT_DEPENDENCIES("${component}" _Boost_${uppercomponent}_DEPENDENCIES) - set(_Boost_${uppercomponent}_DEPENDENCIES ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) - set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE) - foreach(componentdep ${_Boost_${uppercomponent}_DEPENDENCIES}) - if (NOT ("${componentdep}" IN_LIST _boost_processed_components OR "${componentdep}" IN_LIST _boost_new_components)) - list(APPEND _boost_new_components ${componentdep}) - endif() - endforeach() - endforeach() - set(_boost_unprocessed_components ${_boost_new_components}) - unset(_boost_new_components) - endwhile() - set(_boost_extra_components ${_boost_processed_components}) - if(_boost_extra_components AND ${componentvar}) - list(REMOVE_ITEM _boost_extra_components ${${componentvar}}) - endif() - set(${componentvar} ${_boost_processed_components} PARENT_SCOPE) - set(${extravar} ${_boost_extra_components} PARENT_SCOPE) -endfunction() - -# -# Some boost libraries may require particular set of compler features. -# The very first one was `boost::fiber` introduced in Boost 1.62. -# One can check required compiler features of it in -# - `${Boost_ROOT}/libs/fiber/build/Jamfile.v2`; -# - `${Boost_ROOT}/libs/context/build/Jamfile.v2`. -# -# TODO (Re)Check compiler features on (every?) release ??? -# One may use the following command to get the files to check: -# -# $ find . -name Jamfile.v2 | grep build | xargs grep -l cxx1 -# -function(_Boost_COMPILER_FEATURES component _ret) - # Boost >= 1.62 - if(NOT Boost_VERSION_STRING VERSION_LESS 1.62.0) - set(_Boost_FIBER_COMPILER_FEATURES - cxx_alias_templates - cxx_auto_type - cxx_constexpr - cxx_defaulted_functions - cxx_final - cxx_lambdas - cxx_noexcept - cxx_nullptr - cxx_rvalue_references - cxx_thread_local - cxx_variadic_templates - ) - # Compiler feature for `context` same as for `fiber`. - set(_Boost_CONTEXT_COMPILER_FEATURES ${_Boost_FIBER_COMPILER_FEATURES}) - endif() - - # Boost Contract library available in >= 1.67 - if(NOT Boost_VERSION_STRING VERSION_LESS 1.67.0) - # From `libs/contract/build/boost_contract_build.jam` - set(_Boost_CONTRACT_COMPILER_FEATURES - cxx_lambdas - cxx_variadic_templates - ) - endif() - - string(TOUPPER ${component} uppercomponent) - set(${_ret} ${_Boost_${uppercomponent}_COMPILER_FEATURES} PARENT_SCOPE) -endfunction() - -# -# Update library search directory hint variable with paths used by prebuilt boost binaries. -# -# Prebuilt windows binaries (https://sourceforge.net/projects/boost/files/boost-binaries/) -# have library directories named using MSVC compiler version and architecture. -# This function would append corresponding directories if MSVC is a current compiler, -# so having `BOOST_ROOT` would be enough to specify to find everything. -# -function(_Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS componentlibvar basedir) - if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_arch_suffix 64) - else() - set(_arch_suffix 32) - endif() - if(MSVC_TOOLSET_VERSION GREATER_EQUAL 150) - # Not yet known. - elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 140) - # MSVC toolset 14.x versions are forward compatible. - foreach(v 9 8 7 6 5 4 3 2 1 0) - if(MSVC_TOOLSET_VERSION GREATER_EQUAL 14${v}) - list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-14.${v}) - endif() - endforeach() - elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 80) - math(EXPR _toolset_major_version "${MSVC_TOOLSET_VERSION} / 10") - list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-${_toolset_major_version}.0) - endif() - set(${componentlibvar} ${${componentlibvar}} PARENT_SCOPE) - endif() -endfunction() - -# -# End functions/macros -# -#------------------------------------------------------------------------------- - -#------------------------------------------------------------------------------- -# main. -#------------------------------------------------------------------------------- - - -# If the user sets Boost_LIBRARY_DIR, use it as the default for both -# configurations. -if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR) - set(Boost_LIBRARY_DIR_RELEASE "${Boost_LIBRARY_DIR}") -endif() -if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR) - set(Boost_LIBRARY_DIR_DEBUG "${Boost_LIBRARY_DIR}") -endif() - -if(NOT DEFINED Boost_USE_DEBUG_LIBS) - set(Boost_USE_DEBUG_LIBS TRUE) -endif() -if(NOT DEFINED Boost_USE_RELEASE_LIBS) - set(Boost_USE_RELEASE_LIBS TRUE) -endif() -if(NOT DEFINED Boost_USE_MULTITHREADED) - set(Boost_USE_MULTITHREADED TRUE) -endif() -if(NOT DEFINED Boost_USE_DEBUG_RUNTIME) - set(Boost_USE_DEBUG_RUNTIME TRUE) -endif() - -# Check the version of Boost against the requested version. -if(Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) - message(SEND_ERROR "When requesting a specific version of Boost, you must provide at least the major and minor version numbers, e.g., 1.34") -endif() - -if(Boost_FIND_VERSION_EXACT) - # The version may appear in a directory with or without the patch - # level, even when the patch level is non-zero. - set(_boost_TEST_VERSIONS - "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.${Boost_FIND_VERSION_PATCH}" - "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") -else() - # The user has not requested an exact version. Among known - # versions, find those that are acceptable to the user request. - # - # Note: When adding a new Boost release, also update the dependency - # information in _Boost_COMPONENT_DEPENDENCIES and - # _Boost_COMPONENT_HEADERS. See the instructions at the top of - # _Boost_COMPONENT_DEPENDENCIES. - set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} - "1.70.0" "1.70" "1.69.0" "1.69" - "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65" - "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" - "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55" - "1.54.0" "1.54" "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51" - "1.50.0" "1.50" "1.49.0" "1.49" "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1" - "1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42" - "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37" - "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" - "1.34" "1.33.1" "1.33.0" "1.33") - - set(_boost_TEST_VERSIONS) - if(Boost_FIND_VERSION) - set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") - # Select acceptable versions. - foreach(version ${_Boost_KNOWN_VERSIONS}) - if(NOT "${version}" VERSION_LESS "${Boost_FIND_VERSION}") - # This version is high enough. - list(APPEND _boost_TEST_VERSIONS "${version}") - elseif("${version}.99" VERSION_EQUAL "${_Boost_FIND_VERSION_SHORT}.99") - # This version is a short-form for the requested version with - # the patch level dropped. - list(APPEND _boost_TEST_VERSIONS "${version}") - endif() - endforeach() - else() - # Any version is acceptable. - set(_boost_TEST_VERSIONS "${_Boost_KNOWN_VERSIONS}") - endif() -endif() - -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_TEST_VERSIONS") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_MULTITHREADED") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_STATIC_LIBS") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_STATIC_RUNTIME") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_ADDITIONAL_VERSIONS") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_NO_SYSTEM_PATHS") - -# Supply Boost_LIB_DIAGNOSTIC_DEFINITIONS as a convenience target. It -# will only contain any interface definitions on WIN32, but is created -# on all platforms to keep end user code free from platform dependent -# code. Also provide convenience targets to disable autolinking and -# enable dynamic linking. -if(NOT TARGET Boost::diagnostic_definitions) - add_library(Boost::diagnostic_definitions INTERFACE IMPORTED) - add_library(Boost::disable_autolinking INTERFACE IMPORTED) - add_library(Boost::dynamic_linking INTERFACE IMPORTED) - set_target_properties(Boost::dynamic_linking PROPERTIES - INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK") -endif() -if(WIN32) - # In windows, automatic linking is performed, so you do not have - # to specify the libraries. If you are linking to a dynamic - # runtime, then you can choose to link to either a static or a - # dynamic Boost library, the default is to do a static link. You - # can alter this for a specific library "whatever" by defining - # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be - # linked dynamically. Alternatively you can force all Boost - # libraries to dynamic link by defining BOOST_ALL_DYN_LINK. - - # This feature can be disabled for Boost library "whatever" by - # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining - # BOOST_ALL_NO_LIB. - - # If you want to observe which libraries are being linked against - # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking - # code to emit a #pragma message each time a library is selected - # for linking. - set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC") - set_target_properties(Boost::diagnostic_definitions PROPERTIES - INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC") - set_target_properties(Boost::disable_autolinking PROPERTIES - INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB") -endif() - -if (POLICY CMP0074) - cmake_policy(GET CMP0074 _Boost_CMP0074) - if(NOT "x${_Boost_CMP0074}x" STREQUAL "xNEWx") - _Boost_CHECK_SPELLING(Boost_ROOT) - endif() - unset(_Boost_CMP0074) -endif () -_Boost_CHECK_SPELLING(Boost_LIBRARYDIR) -_Boost_CHECK_SPELLING(Boost_INCLUDEDIR) - -# Collect environment variable inputs as hints. Do not consider changes. -foreach(v BOOSTROOT BOOST_ROOT BOOST_INCLUDEDIR BOOST_LIBRARYDIR) - set(_env $ENV{${v}}) - if(_env) - file(TO_CMAKE_PATH "${_env}" _ENV_${v}) - else() - set(_ENV_${v} "") - endif() -endforeach() -if(NOT _ENV_BOOST_ROOT AND _ENV_BOOSTROOT) - set(_ENV_BOOST_ROOT "${_ENV_BOOSTROOT}") -endif() - -# Collect inputs and cached results. Detect changes since the last run. -if(NOT BOOST_ROOT AND BOOSTROOT) - set(BOOST_ROOT "${BOOSTROOT}") -endif() -set(_Boost_VARS_DIR - BOOST_ROOT - Boost_NO_SYSTEM_PATHS - ) - -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_ROOT") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_ROOT" ENVIRONMENT) -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_INCLUDEDIR") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_INCLUDEDIR" ENVIRONMENT) -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_LIBRARYDIR") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_LIBRARYDIR" ENVIRONMENT) - -# ------------------------------------------------------------------------ -# Search for Boost include DIR -# ------------------------------------------------------------------------ - -set(_Boost_VARS_INC BOOST_INCLUDEDIR Boost_INCLUDE_DIR Boost_ADDITIONAL_VERSIONS) -_Boost_CHANGE_DETECT(_Boost_CHANGE_INCDIR ${_Boost_VARS_DIR} ${_Boost_VARS_INC}) -# Clear Boost_INCLUDE_DIR if it did not change but other input affecting the -# location did. We will find a new one based on the new inputs. -if(_Boost_CHANGE_INCDIR AND NOT _Boost_INCLUDE_DIR_CHANGED) - unset(Boost_INCLUDE_DIR CACHE) -endif() - -if(NOT Boost_INCLUDE_DIR) - set(_boost_INCLUDE_SEARCH_DIRS "") - if(BOOST_INCLUDEDIR) - list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_INCLUDEDIR}) - elseif(_ENV_BOOST_INCLUDEDIR) - list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_INCLUDEDIR}) - endif() - - if( BOOST_ROOT ) - list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_ROOT}/include ${BOOST_ROOT}) - elseif( _ENV_BOOST_ROOT ) - list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_ROOT}/include ${_ENV_BOOST_ROOT}) - endif() - - if( Boost_NO_SYSTEM_PATHS) - list(APPEND _boost_INCLUDE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) - else() - if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") - foreach(ver ${_boost_TEST_VERSIONS}) - string(REPLACE "." "_" ver "${ver}") - list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS "C:/local/boost_${ver}") - endforeach() - endif() - list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS - C:/boost/include - C:/boost - /sw/local/include - ) - endif() - - # Try to find Boost by stepping backwards through the Boost versions - # we know about. - # Build a list of path suffixes for each version. - set(_boost_PATH_SUFFIXES) - foreach(_boost_VER ${_boost_TEST_VERSIONS}) - # Add in a path suffix, based on the required version, ideally - # we could read this from version.hpp, but for that to work we'd - # need to know the include dir already - set(_boost_BOOSTIFIED_VERSION) - - # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0 - if(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") - set(_boost_BOOSTIFIED_VERSION - "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}_${CMAKE_MATCH_3}") - elseif(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)") - set(_boost_BOOSTIFIED_VERSION - "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}") - endif() - - list(APPEND _boost_PATH_SUFFIXES - "boost-${_boost_BOOSTIFIED_VERSION}" - "boost_${_boost_BOOSTIFIED_VERSION}" - "boost/boost-${_boost_BOOSTIFIED_VERSION}" - "boost/boost_${_boost_BOOSTIFIED_VERSION}" - ) - - endforeach() - - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_INCLUDE_SEARCH_DIRS") - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_PATH_SUFFIXES") - - # Look for a standard boost header file. - find_path(Boost_INCLUDE_DIR - NAMES boost/config.hpp - HINTS ${_boost_INCLUDE_SEARCH_DIRS} - PATH_SUFFIXES ${_boost_PATH_SUFFIXES} - ) -endif() - -# ------------------------------------------------------------------------ -# Extract version information from version.hpp -# ------------------------------------------------------------------------ - -if(Boost_INCLUDE_DIR) - _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp") - - # Extract Boost_VERSION_MACRO and Boost_LIB_VERSION from version.hpp - set(Boost_VERSION_MACRO 0) - set(Boost_LIB_VERSION "") - file(STRINGS "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS REGEX "#define BOOST_(LIB_)?VERSION ") - if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_VERSION ([0-9]+)") - set(Boost_VERSION_MACRO "${CMAKE_MATCH_1}") - endif() - if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_LIB_VERSION \"([0-9_]+)\"") - set(Boost_LIB_VERSION "${CMAKE_MATCH_1}") - endif() - unset(_boost_VERSION_HPP_CONTENTS) - - # Calculate version components - math(EXPR Boost_VERSION_MAJOR "${Boost_VERSION_MACRO} / 100000") - math(EXPR Boost_VERSION_MINOR "${Boost_VERSION_MACRO} / 100 % 1000") - math(EXPR Boost_VERSION_PATCH "${Boost_VERSION_MACRO} % 100") - set(Boost_VERSION_COUNT 3) - - # Define alias variables for backwards compat. - set(Boost_MAJOR_VERSION ${Boost_VERSION_MAJOR}) - set(Boost_MINOR_VERSION ${Boost_VERSION_MINOR}) - set(Boost_SUBMINOR_VERSION ${Boost_VERSION_PATCH}) - - # Define Boost version in x.y.z format - set(Boost_VERSION_STRING "${Boost_VERSION_MAJOR}.${Boost_VERSION_MINOR}.${Boost_VERSION_PATCH}") - - if (POLICY CMP0093) - # Define final Boost_VERSION - cmake_policy(GET CMP0093 _Boost_CMP0093 - PARENT_SCOPE # undocumented, do not use outside of CMake - ) - if("x${_Boost_CMP0093}x" STREQUAL "xNEWx") - set(Boost_VERSION ${Boost_VERSION_STRING}) - endif() - unset(_Boost_CMP0093) - else() - set(Boost_VERSION ${Boost_VERSION_MACRO}) - endif() - - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION") - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_STRING") - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MACRO") - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MAJOR") - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MINOR") - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_PATCH") - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_COUNT") -endif() - -# ------------------------------------------------------------------------ -# Prefix initialization -# ------------------------------------------------------------------------ - -set(Boost_LIB_PREFIX "") -if ( (GHSMULTI AND Boost_USE_STATIC_LIBS) OR - (WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN) ) - set(Boost_LIB_PREFIX "lib") -endif() - -if ( NOT Boost_NAMESPACE ) - set(Boost_NAMESPACE "boost") -endif() - -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_LIB_PREFIX") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_NAMESPACE") - -# ------------------------------------------------------------------------ -# Suffix initialization and compiler suffix detection. -# ------------------------------------------------------------------------ - -set(_Boost_VARS_NAME - Boost_NAMESPACE - Boost_COMPILER - Boost_THREADAPI - Boost_USE_DEBUG_PYTHON - Boost_USE_MULTITHREADED - Boost_USE_STATIC_LIBS - Boost_USE_STATIC_RUNTIME - Boost_USE_STLPORT - Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS - ) -_Boost_CHANGE_DETECT(_Boost_CHANGE_LIBNAME ${_Boost_VARS_NAME}) - -# Setting some more suffixes for the library -if (Boost_COMPILER) - set(_boost_COMPILER ${Boost_COMPILER}) - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "_boost_COMPILER" SOURCE "user-specified via Boost_COMPILER") -else() - # Attempt to guess the compiler suffix - # NOTE: this is not perfect yet, if you experience any issues - # please report them and use the Boost_COMPILER variable - # to work around the problems. - _Boost_GUESS_COMPILER_PREFIX(_boost_COMPILER) -endif() - -set (_boost_MULTITHREADED "-mt") -if( NOT Boost_USE_MULTITHREADED ) - set (_boost_MULTITHREADED "") -endif() -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_MULTITHREADED") - -#====================== -# Systematically build up the Boost ABI tag for the 'tagged' and 'versioned' layouts -# http://boost.org/doc/libs/1_66_0/more/getting_started/windows.html#library-naming -# http://boost.org/doc/libs/1_66_0/boost/config/auto_link.hpp -# http://boost.org/doc/libs/1_66_0/tools/build/src/tools/common.jam -# http://boost.org/doc/libs/1_66_0/boostcpp.jam -set( _boost_RELEASE_ABI_TAG "-") -set( _boost_DEBUG_ABI_TAG "-") -# Key Use this library when: -# s linking statically to the C++ standard library and -# compiler runtime support libraries. -if(Boost_USE_STATIC_RUNTIME) - set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}s") - set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}s") -endif() -# g using debug versions of the standard and runtime -# support libraries -if(WIN32 AND Boost_USE_DEBUG_RUNTIME) - if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" - OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang" - OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel") - string(APPEND _boost_DEBUG_ABI_TAG "g") - endif() -endif() -# y using special debug build of python -if(Boost_USE_DEBUG_PYTHON) - string(APPEND _boost_DEBUG_ABI_TAG "y") -endif() -# d using a debug version of your code -string(APPEND _boost_DEBUG_ABI_TAG "d") -# p using the STLport standard library rather than the -# default one supplied with your compiler -if(Boost_USE_STLPORT) - string(APPEND _boost_RELEASE_ABI_TAG "p") - string(APPEND _boost_DEBUG_ABI_TAG "p") -endif() -# n using the STLport deprecated "native iostreams" feature -# removed from the documentation in 1.43.0 but still present in -# boost/config/auto_link.hpp -if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS) - string(APPEND _boost_RELEASE_ABI_TAG "n") - string(APPEND _boost_DEBUG_ABI_TAG "n") -endif() - -# -x86 Architecture and address model tag -# First character is the architecture, then word-size, either 32 or 64 -# Only used in 'versioned' layout, added in Boost 1.66.0 -if(DEFINED Boost_ARCHITECTURE) - set(_boost_ARCHITECTURE_TAG "${Boost_ARCHITECTURE}") - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "_boost_ARCHITECTURE_TAG" SOURCE "user-specified via Boost_ARCHITECTURE") -else() - set(_boost_ARCHITECTURE_TAG "") - # {CMAKE_CXX_COMPILER_ARCHITECTURE_ID} is not currently set for all compilers - if(NOT "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "x" AND NOT Boost_VERSION_STRING VERSION_LESS 1.66.0) - string(APPEND _boost_ARCHITECTURE_TAG "-") - # This needs to be kept in-sync with the section of CMakePlatformId.h.in - # inside 'defined(_WIN32) && defined(_MSC_VER)' - if(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "IA64") - string(APPEND _boost_ARCHITECTURE_TAG "i") - elseif(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "X86" - OR CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "x64") - string(APPEND _boost_ARCHITECTURE_TAG "x") - elseif(CMAKE_CXX_COMPILER_ARCHITECTURE_ID MATCHES "^ARM") - string(APPEND _boost_ARCHITECTURE_TAG "a") - elseif(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "MIPS") - string(APPEND _boost_ARCHITECTURE_TAG "m") - endif() - - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - string(APPEND _boost_ARCHITECTURE_TAG "64") - else() - string(APPEND _boost_ARCHITECTURE_TAG "32") - endif() - endif() - _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "_boost_ARCHITECTURE_TAG" SOURCE "detected") -endif() - -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_RELEASE_ABI_TAG") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_DEBUG_ABI_TAG") - -# ------------------------------------------------------------------------ -# Begin finding boost libraries -# ------------------------------------------------------------------------ - -set(_Boost_VARS_LIB "") -foreach(c DEBUG RELEASE) - set(_Boost_VARS_LIB_${c} BOOST_LIBRARYDIR Boost_LIBRARY_DIR_${c}) - list(APPEND _Boost_VARS_LIB ${_Boost_VARS_LIB_${c}}) - _Boost_CHANGE_DETECT(_Boost_CHANGE_LIBDIR_${c} ${_Boost_VARS_DIR} ${_Boost_VARS_LIB_${c}} Boost_INCLUDE_DIR) - # Clear Boost_LIBRARY_DIR_${c} if it did not change but other input affecting the - # location did. We will find a new one based on the new inputs. - if(_Boost_CHANGE_LIBDIR_${c} AND NOT _Boost_LIBRARY_DIR_${c}_CHANGED) - unset(Boost_LIBRARY_DIR_${c} CACHE) - endif() - - # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is set, prefer its value. - if(Boost_LIBRARY_DIR_${c}) - set(_boost_LIBRARY_SEARCH_DIRS_${c} ${Boost_LIBRARY_DIR_${c}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) - else() - set(_boost_LIBRARY_SEARCH_DIRS_${c} "") - if(BOOST_LIBRARYDIR) - list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_LIBRARYDIR}) - elseif(_ENV_BOOST_LIBRARYDIR) - list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_LIBRARYDIR}) - endif() - - if(BOOST_ROOT) - list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_ROOT}/lib ${BOOST_ROOT}/stage/lib) - _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${BOOST_ROOT}") - elseif(_ENV_BOOST_ROOT) - list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_ROOT}/lib ${_ENV_BOOST_ROOT}/stage/lib) - _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${_ENV_BOOST_ROOT}") - endif() - - list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} - ${Boost_INCLUDE_DIR}/lib - ${Boost_INCLUDE_DIR}/../lib - ${Boost_INCLUDE_DIR}/stage/lib - ) - _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}/..") - _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}") - if( Boost_NO_SYSTEM_PATHS ) - list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) - else() - foreach(ver ${_boost_TEST_VERSIONS}) - string(REPLACE "." "_" ver "${ver}") - _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "C:/local/boost_${ver}") - endforeach() - _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "C:/boost") - list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} PATHS - C:/boost/lib - C:/boost - /sw/local/lib - ) - endif() - endif() -endforeach() - -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_LIBRARY_SEARCH_DIRS_RELEASE") -_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_LIBRARY_SEARCH_DIRS_DEBUG") - -# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES -if( Boost_USE_STATIC_LIBS ) - set( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - if(WIN32) - list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES .a) - endif() -endif() - -# We want to use the tag inline below without risking double dashes -if(_boost_RELEASE_ABI_TAG) - if(${_boost_RELEASE_ABI_TAG} STREQUAL "-") - set(_boost_RELEASE_ABI_TAG "") - endif() -endif() -if(_boost_DEBUG_ABI_TAG) - if(${_boost_DEBUG_ABI_TAG} STREQUAL "-") - set(_boost_DEBUG_ABI_TAG "") - endif() -endif() - -# The previous behavior of FindBoost when Boost_USE_STATIC_LIBS was enabled -# on WIN32 was to: -# 1. Search for static libs compiled against a SHARED C++ standard runtime library (use if found) -# 2. Search for static libs compiled against a STATIC C++ standard runtime library (use if found) -# We maintain this behavior since changing it could break people's builds. -# To disable the ambiguous behavior, the user need only -# set Boost_USE_STATIC_RUNTIME either ON or OFF. -set(_boost_STATIC_RUNTIME_WORKAROUND false) -if(WIN32 AND Boost_USE_STATIC_LIBS) - if(NOT DEFINED Boost_USE_STATIC_RUNTIME) - set(_boost_STATIC_RUNTIME_WORKAROUND TRUE) - endif() -endif() - -# On versions < 1.35, remove the System library from the considered list -# since it wasn't added until 1.35. -if(Boost_VERSION_STRING AND Boost_FIND_COMPONENTS) - if(Boost_VERSION_STRING VERSION_LESS 1.35.0) - list(REMOVE_ITEM Boost_FIND_COMPONENTS system) - endif() -endif() - -# Additional components may be required via component dependencies. -# Add any missing components to the list. -_Boost_MISSING_DEPENDENCIES(Boost_FIND_COMPONENTS _Boost_EXTRA_FIND_COMPONENTS) - -# If thread is required, get the thread libs as a dependency -if("thread" IN_LIST Boost_FIND_COMPONENTS) - if(Boost_FIND_QUIETLY) - set(_Boost_find_quiet QUIET) - else() - set(_Boost_find_quiet "") - endif() - find_package(Threads ${_Boost_find_quiet}) - unset(_Boost_find_quiet) -endif() - -# If the user changed any of our control inputs flush previous results. -if(_Boost_CHANGE_LIBDIR_DEBUG OR _Boost_CHANGE_LIBDIR_RELEASE OR _Boost_CHANGE_LIBNAME) - foreach(COMPONENT ${_Boost_COMPONENTS_SEARCHED}) - string(TOUPPER ${COMPONENT} UPPERCOMPONENT) - foreach(c DEBUG RELEASE) - set(_var Boost_${UPPERCOMPONENT}_LIBRARY_${c}) - unset(${_var} CACHE) - set(${_var} "${_var}-NOTFOUND") - endforeach() - endforeach() - set(_Boost_COMPONENTS_SEARCHED "") -endif() - -foreach(COMPONENT ${Boost_FIND_COMPONENTS}) - string(TOUPPER ${COMPONENT} UPPERCOMPONENT) - - set( _boost_docstring_release "Boost ${COMPONENT} library (release)") - set( _boost_docstring_debug "Boost ${COMPONENT} library (debug)") - - # Compute component-specific hints. - set(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT "") - if(${COMPONENT} STREQUAL "mpi" OR ${COMPONENT} STREQUAL "mpi_python" OR - ${COMPONENT} STREQUAL "graph_parallel") - foreach(lib ${MPI_CXX_LIBRARIES} ${MPI_C_LIBRARIES}) - if(IS_ABSOLUTE "${lib}") - get_filename_component(libdir "${lib}" PATH) - string(REPLACE "\\" "/" libdir "${libdir}") - list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT ${libdir}) - endif() - endforeach() - endif() - - # Handle Python version suffixes - unset(COMPONENT_PYTHON_VERSION_MAJOR) - unset(COMPONENT_PYTHON_VERSION_MINOR) - if(${COMPONENT} MATCHES "^(python|mpi_python|numpy)([0-9])\$") - set(COMPONENT_UNVERSIONED "${CMAKE_MATCH_1}") - set(COMPONENT_PYTHON_VERSION_MAJOR "${CMAKE_MATCH_2}") - elseif(${COMPONENT} MATCHES "^(python|mpi_python|numpy)([0-9])\\.?([0-9])\$") - set(COMPONENT_UNVERSIONED "${CMAKE_MATCH_1}") - set(COMPONENT_PYTHON_VERSION_MAJOR "${CMAKE_MATCH_2}") - set(COMPONENT_PYTHON_VERSION_MINOR "${CMAKE_MATCH_3}") - endif() - - unset(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME) - if (COMPONENT_PYTHON_VERSION_MINOR) - # Boost >= 1.67 - list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") - # Debian/Ubuntu (Some versions omit the 2 and/or 3 from the suffix) - list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") - list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") - # Gentoo - list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}.${COMPONENT_PYTHON_VERSION_MINOR}") - # RPMs - list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") - endif() - if (COMPONENT_PYTHON_VERSION_MAJOR AND NOT COMPONENT_PYTHON_VERSION_MINOR) - # Boost < 1.67 - list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}") - endif() - - # Consolidate and report component-specific hints. - if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME) - list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME) - _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "Component-specific library search names for ${COMPONENT_NAME}: ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME}") - endif() - if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) - list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) - _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "Component-specific library search paths for ${COMPONENT}: ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT}") - endif() - - # - # Find headers - # - _Boost_COMPONENT_HEADERS("${COMPONENT}" Boost_${UPPERCOMPONENT}_HEADER_NAME) - # Look for a standard boost header file. - if(Boost_${UPPERCOMPONENT}_HEADER_NAME) - if(EXISTS "${Boost_INCLUDE_DIR}/${Boost_${UPPERCOMPONENT}_HEADER_NAME}") - set(Boost_${UPPERCOMPONENT}_HEADER ON) - else() - set(Boost_${UPPERCOMPONENT}_HEADER OFF) - endif() - else() - set(Boost_${UPPERCOMPONENT}_HEADER ON) - message(WARNING "No header defined for ${COMPONENT}; skipping header check") - endif() - - # - # Find RELEASE libraries - # - unset(_boost_RELEASE_NAMES) - foreach(component IN LISTS _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME COMPONENT) - foreach(compiler IN LISTS _boost_COMPILER) - list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ) - endforeach() - list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component} ) - if(_boost_STATIC_RUNTIME_WORKAROUND) - set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}") - foreach(compiler IN LISTS _boost_COMPILER) - list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) - endforeach() - list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) - endif() - endforeach() - if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") - _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES}) - endif() - _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}") - - # if Boost_LIBRARY_DIR_RELEASE is not defined, - # but Boost_LIBRARY_DIR_DEBUG is, look there first for RELEASE libs - if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR_DEBUG) - list(INSERT _boost_LIBRARY_SEARCH_DIRS_RELEASE 0 ${Boost_LIBRARY_DIR_DEBUG}) - endif() - - # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. - string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_RELEASE}") - - if(Boost_USE_RELEASE_LIBS) - _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE RELEASE - NAMES ${_boost_RELEASE_NAMES} - HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} - NAMES_PER_DIR - DOC "${_boost_docstring_release}" - ) - endif() - - # - # Find DEBUG libraries - # - unset(_boost_DEBUG_NAMES) - foreach(component IN LISTS _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME COMPONENT) - foreach(compiler IN LISTS _boost_COMPILER) - list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ) - endforeach() - list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component} ) - if(_boost_STATIC_RUNTIME_WORKAROUND) - set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}") - foreach(compiler IN LISTS _boost_COMPILER) - list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) - endforeach() - list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG} - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) - endif() - endforeach() - if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") - _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES}) - endif() - _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" - "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}") - - # if Boost_LIBRARY_DIR_DEBUG is not defined, - # but Boost_LIBRARY_DIR_RELEASE is, look there first for DEBUG libs - if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR_RELEASE) - list(INSERT _boost_LIBRARY_SEARCH_DIRS_DEBUG 0 ${Boost_LIBRARY_DIR_RELEASE}) - endif() - - # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. - string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_DEBUG}") - - if(Boost_USE_DEBUG_LIBS) - _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG DEBUG - NAMES ${_boost_DEBUG_NAMES} - HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} - NAMES_PER_DIR - DOC "${_boost_docstring_debug}" - ) - endif () - - if(Boost_REALPATH) - _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "${_boost_docstring_release}") - _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "${_boost_docstring_debug}" ) - endif() - - _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT}) - - # Check if component requires some compiler features - _Boost_COMPILER_FEATURES(${COMPONENT} _Boost_${UPPERCOMPONENT}_COMPILER_FEATURES) - -endforeach() - -# Restore the original find library ordering -if( Boost_USE_STATIC_LIBS ) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) -endif() - -# ------------------------------------------------------------------------ -# End finding boost libraries -# ------------------------------------------------------------------------ - -set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR}) -set(Boost_LIBRARY_DIRS) -if(Boost_LIBRARY_DIR_RELEASE) - list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_RELEASE}) -endif() -if(Boost_LIBRARY_DIR_DEBUG) - list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_DEBUG}) -endif() -if(Boost_LIBRARY_DIRS) - list(REMOVE_DUPLICATES Boost_LIBRARY_DIRS) -endif() - -# ------------------------------------------------------------------------ -# Call FPHSA helper, see https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html -# ------------------------------------------------------------------------ - -# Define aliases as needed by the component handler in the FPHSA helper below -foreach(_comp IN LISTS Boost_FIND_COMPONENTS) - string(TOUPPER ${_comp} _uppercomp) - if(DEFINED Boost_${_uppercomp}_FOUND) - set(Boost_${_comp}_FOUND ${Boost_${_uppercomp}_FOUND}) - endif() -endforeach() - -find_package_handle_standard_args(Boost - REQUIRED_VARS Boost_INCLUDE_DIR - VERSION_VAR Boost_VERSION_STRING - HANDLE_COMPONENTS) - -if(Boost_FOUND) - if( NOT Boost_LIBRARY_DIRS ) - # Compatibility Code for backwards compatibility with CMake - # 2.4's FindBoost module. - - # Look for the boost library path. - # Note that the user may not have installed any libraries - # so it is quite possible the Boost_LIBRARY_DIRS may not exist. - set(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) - - if("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") - get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) - endif() - - if("${_boost_LIB_DIR}" MATCHES "/include$") - # Strip off the trailing "/include" in the path. - get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) - endif() - - if(EXISTS "${_boost_LIB_DIR}/lib") - string(APPEND _boost_LIB_DIR /lib) - elseif(EXISTS "${_boost_LIB_DIR}/stage/lib") - string(APPEND _boost_LIB_DIR "/stage/lib") - else() - set(_boost_LIB_DIR "") - endif() - - if(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") - set(Boost_LIBRARY_DIRS ${_boost_LIB_DIR}) - endif() - - endif() -else() - # Boost headers were not found so no components were found. - foreach(COMPONENT ${Boost_FIND_COMPONENTS}) - string(TOUPPER ${COMPONENT} UPPERCOMPONENT) - set(Boost_${UPPERCOMPONENT}_FOUND 0) - endforeach() -endif() - -# ------------------------------------------------------------------------ -# Add imported targets -# ------------------------------------------------------------------------ - -if(Boost_FOUND) - # The builtin CMake package in Boost 1.70+ introduces a new name - # for the header-only lib, let's provide the same UI in module mode - if(NOT TARGET Boost::headers) - add_library(Boost::headers INTERFACE IMPORTED) - if(Boost_INCLUDE_DIRS) - set_target_properties(Boost::headers PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}") - endif() - endif() - - # Define the old target name for header-only libraries for backwards - # compat. - if(NOT TARGET Boost::boost) - add_library(Boost::boost INTERFACE IMPORTED) - set_target_properties(Boost::boost - PROPERTIES INTERFACE_LINK_LIBRARIES Boost::headers) - endif() - - foreach(COMPONENT ${Boost_FIND_COMPONENTS}) - if(_Boost_IMPORTED_TARGETS AND NOT TARGET Boost::${COMPONENT}) - string(TOUPPER ${COMPONENT} UPPERCOMPONENT) - if(Boost_${UPPERCOMPONENT}_FOUND) - if(Boost_USE_STATIC_LIBS) - add_library(Boost::${COMPONENT} STATIC IMPORTED) - else() - # Even if Boost_USE_STATIC_LIBS is OFF, we might have static - # libraries as a result. - add_library(Boost::${COMPONENT} UNKNOWN IMPORTED) - endif() - if(Boost_INCLUDE_DIRS) - set_target_properties(Boost::${COMPONENT} PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}") - endif() - if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY}") - set_target_properties(Boost::${COMPONENT} PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" - IMPORTED_LOCATION "${Boost_${UPPERCOMPONENT}_LIBRARY}") - endif() - if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}") - set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY - IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(Boost::${COMPONENT} PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" - IMPORTED_LOCATION_RELEASE "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}") - endif() - if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}") - set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(Boost::${COMPONENT} PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" - IMPORTED_LOCATION_DEBUG "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}") - endif() - if(_Boost_${UPPERCOMPONENT}_DEPENDENCIES) - unset(_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES) - foreach(dep ${_Boost_${UPPERCOMPONENT}_DEPENDENCIES}) - list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Boost::${dep}) - endforeach() - if(COMPONENT STREQUAL "thread") - list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Threads::Threads) - endif() - set_target_properties(Boost::${COMPONENT} PROPERTIES - INTERFACE_LINK_LIBRARIES "${_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES}") - endif() - if(_Boost_${UPPERCOMPONENT}_COMPILER_FEATURES) - set_target_properties(Boost::${COMPONENT} PROPERTIES - INTERFACE_COMPILE_FEATURES "${_Boost_${UPPERCOMPONENT}_COMPILER_FEATURES}") - endif() - endif() - endif() - endforeach() -endif() - -# ------------------------------------------------------------------------ -# Finalize -# ------------------------------------------------------------------------ - -# Report Boost_LIBRARIES -set(Boost_LIBRARIES "") -foreach(_comp IN LISTS Boost_FIND_COMPONENTS) - string(TOUPPER ${_comp} _uppercomp) - if(Boost_${_uppercomp}_FOUND) - list(APPEND Boost_LIBRARIES ${Boost_${_uppercomp}_LIBRARY}) - if(_comp STREQUAL "thread") - list(APPEND Boost_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) - endif() - endif() -endforeach() - -# Configure display of cache entries in GUI. -foreach(v BOOSTROOT BOOST_ROOT ${_Boost_VARS_INC} ${_Boost_VARS_LIB}) - get_property(_type CACHE ${v} PROPERTY TYPE) - if(_type) - set_property(CACHE ${v} PROPERTY ADVANCED 1) - if("x${_type}" STREQUAL "xUNINITIALIZED") - if("x${v}" STREQUAL "xBoost_ADDITIONAL_VERSIONS") - set_property(CACHE ${v} PROPERTY TYPE STRING) - else() - set_property(CACHE ${v} PROPERTY TYPE PATH) - endif() - endif() - endif() -endforeach() - -# Record last used values of input variables so we can -# detect on the next run if the user changed them. -foreach(v - ${_Boost_VARS_INC} ${_Boost_VARS_LIB} - ${_Boost_VARS_DIR} ${_Boost_VARS_NAME} - ) - if(DEFINED ${v}) - set(_${v}_LAST "${${v}}" CACHE INTERNAL "Last used ${v} value.") - else() - unset(_${v}_LAST CACHE) - endif() -endforeach() - -# Maintain a persistent list of components requested anywhere since -# the last flush. -set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}") -list(APPEND _Boost_COMPONENTS_SEARCHED ${Boost_FIND_COMPONENTS}) -list(REMOVE_DUPLICATES _Boost_COMPONENTS_SEARCHED) -list(SORT _Boost_COMPONENTS_SEARCHED) -set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}" - CACHE INTERNAL "Components requested for this build tree.") - -# Restore project's policies -cmake_policy(POP) diff --git a/Builds/CMake/Findjemalloc.cmake b/Builds/CMake/Findjemalloc.cmake deleted file mode 100644 index 820ceeed4a1..00000000000 --- a/Builds/CMake/Findjemalloc.cmake +++ /dev/null @@ -1,47 +0,0 @@ -# - Try to find jemalloc -# Once done this will define -# JEMALLOC_FOUND - System has jemalloc -# JEMALLOC_INCLUDE_DIRS - The jemalloc include directories -# JEMALLOC_LIBRARIES - The libraries needed to use jemalloc - -if(NOT USE_BUNDLED_JEMALLOC) - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(PC_JEMALLOC QUIET jemalloc) - endif() -else() - set(PC_JEMALLOC_INCLUDEDIR) - set(PC_JEMALLOC_INCLUDE_DIRS) - set(PC_JEMALLOC_LIBDIR) - set(PC_JEMALLOC_LIBRARY_DIRS) - set(LIMIT_SEARCH NO_DEFAULT_PATH) -endif() - -set(JEMALLOC_DEFINITIONS ${PC_JEMALLOC_CFLAGS_OTHER}) - -find_path(JEMALLOC_INCLUDE_DIR jemalloc/jemalloc.h - PATHS ${PC_JEMALLOC_INCLUDEDIR} ${PC_JEMALLOC_INCLUDE_DIRS} - ${LIMIT_SEARCH}) - -# If we're asked to use static linkage, add libjemalloc.a as a preferred library name. -if(JEMALLOC_USE_STATIC) - list(APPEND JEMALLOC_NAMES - "${CMAKE_STATIC_LIBRARY_PREFIX}jemalloc${CMAKE_STATIC_LIBRARY_SUFFIX}") -endif() - -list(APPEND JEMALLOC_NAMES jemalloc) - -find_library(JEMALLOC_LIBRARY NAMES ${JEMALLOC_NAMES} - HINTS ${PC_JEMALLOC_LIBDIR} ${PC_JEMALLOC_LIBRARY_DIRS} - ${LIMIT_SEARCH}) - -set(JEMALLOC_LIBRARIES ${JEMALLOC_LIBRARY}) -set(JEMALLOC_INCLUDE_DIRS ${JEMALLOC_INCLUDE_DIR}) - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set JEMALLOC_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args(JeMalloc DEFAULT_MSG - JEMALLOC_LIBRARY JEMALLOC_INCLUDE_DIR) - -mark_as_advanced(JEMALLOC_INCLUDE_DIR JEMALLOC_LIBRARY) diff --git a/Builds/CMake/README.md b/Builds/CMake/README.md deleted file mode 100644 index 77d6813b653..00000000000 --- a/Builds/CMake/README.md +++ /dev/null @@ -1,18 +0,0 @@ - -These are modules and sources that support our CMake build. - -== FindBoost.cmake == - -In order to facilitate updating to latest releases of boost, we've made a local -copy of the FindBoost cmake module in our repo. The latest official version can -generally be obtained -[here](https://github.com/Kitware/CMake/blob/master/Modules/FindBoost.cmake). - -The latest version provided by Kitware can be tailored for use with the -version of CMake that it ships with (typically the next upcoming CMake -release). As such, the latest version from the repository might not work -perfectly with older versions of CMake - for instance, the latest version -might use features or properties only available in the version of CMake that -it ships with. Given this, it's best to test any updates to this module with a few -different versions of cmake. - diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake deleted file mode 100644 index bd98a5d4195..00000000000 --- a/Builds/CMake/RippledCore.cmake +++ /dev/null @@ -1,1022 +0,0 @@ -#[===================================================================[ - xrpl_core - core functionality, useable by some client software perhaps -#]===================================================================] - -file (GLOB_RECURSE rb_headers - src/ripple/beast/*.h - src/ripple/beast/*.hpp) - -add_library (xrpl_core - ${rb_headers}) ## headers added here for benefit of IDEs - -#[===============================[ - beast/legacy FILES: - TODO: review these sources for removal or replacement -#]===============================] -if (unity) - target_sources (xrpl_core PRIVATE - src/ripple/beast/core/core.unity.cpp - src/ripple/beast/unity/beast_hash_unity.cpp - src/ripple/beast/unity/beast_insight_unity.cpp - src/ripple/beast/unity/beast_net_unity.cpp - src/ripple/beast/unity/beast_utility_unity.cpp) -else () - target_sources (xrpl_core PRIVATE - src/ripple/beast/core/CurrentThreadName.cpp - src/ripple/beast/core/SemanticVersion.cpp - src/ripple/beast/hash/impl/xxhash.cpp - src/ripple/beast/insight/impl/Collector.cpp - src/ripple/beast/insight/impl/Groups.cpp - src/ripple/beast/insight/impl/Hook.cpp - src/ripple/beast/insight/impl/Metric.cpp - src/ripple/beast/insight/impl/NullCollector.cpp - src/ripple/beast/insight/impl/StatsDCollector.cpp - src/ripple/beast/net/impl/IPAddressConversion.cpp - src/ripple/beast/net/impl/IPAddressV4.cpp - src/ripple/beast/net/impl/IPAddressV6.cpp - src/ripple/beast/net/impl/IPEndpoint.cpp - src/ripple/beast/utility/src/beast_Journal.cpp - src/ripple/beast/utility/src/beast_PropertyStream.cpp) -endif () - -#[===============================[ - core sources -#]===============================] -if (unity) - target_sources (xrpl_core PRIVATE - src/ripple/unity/basics1.cpp - src/ripple/unity/json.cpp - src/ripple/unity/protocol.cpp - src/ripple/unity/crypto.cpp) -else () - target_sources (xrpl_core PRIVATE - #[===============================[ - nounity, main sources: - subdir: basics (partial) - #]===============================] - src/ripple/basics/impl/base64.cpp - src/ripple/basics/impl/contract.cpp - src/ripple/basics/impl/CountedObject.cpp - src/ripple/basics/impl/FileUtilities.cpp - src/ripple/basics/impl/Log.cpp - src/ripple/basics/impl/strHex.cpp - src/ripple/basics/impl/StringUtilities.cpp - #[===============================[ - nounity, main sources: - subdir: json - #]===============================] - src/ripple/json/impl/JsonPropertyStream.cpp - src/ripple/json/impl/Object.cpp - src/ripple/json/impl/Output.cpp - src/ripple/json/impl/Writer.cpp - src/ripple/json/impl/json_reader.cpp - src/ripple/json/impl/json_value.cpp - src/ripple/json/impl/json_valueiterator.cpp - src/ripple/json/impl/json_writer.cpp - src/ripple/json/impl/to_string.cpp - #[===============================[ - nounity, main sources: - subdir: protocol - #]===============================] - src/ripple/protocol/impl/AccountID.cpp - src/ripple/protocol/impl/Book.cpp - src/ripple/protocol/impl/BuildInfo.cpp - src/ripple/protocol/impl/ErrorCodes.cpp - src/ripple/protocol/impl/Feature.cpp - src/ripple/protocol/impl/HashPrefix.cpp - src/ripple/protocol/impl/IOUAmount.cpp - src/ripple/protocol/impl/Indexes.cpp - src/ripple/protocol/impl/InnerObjectFormats.cpp - src/ripple/protocol/impl/Issue.cpp - src/ripple/protocol/impl/Keylet.cpp - src/ripple/protocol/impl/LedgerFormats.cpp - src/ripple/protocol/impl/PublicKey.cpp - src/ripple/protocol/impl/Quality.cpp - src/ripple/protocol/impl/Rate2.cpp - src/ripple/protocol/impl/SField.cpp - src/ripple/protocol/impl/SOTemplate.cpp - src/ripple/protocol/impl/STAccount.cpp - src/ripple/protocol/impl/STAmount.cpp - src/ripple/protocol/impl/STArray.cpp - src/ripple/protocol/impl/STBase.cpp - src/ripple/protocol/impl/STBlob.cpp - src/ripple/protocol/impl/STInteger.cpp - src/ripple/protocol/impl/STLedgerEntry.cpp - src/ripple/protocol/impl/STObject.cpp - src/ripple/protocol/impl/STParsedJSON.cpp - src/ripple/protocol/impl/STPathSet.cpp - src/ripple/protocol/impl/STTx.cpp - src/ripple/protocol/impl/STValidation.cpp - src/ripple/protocol/impl/STVar.cpp - src/ripple/protocol/impl/STVector256.cpp - src/ripple/protocol/impl/SecretKey.cpp - src/ripple/protocol/impl/Seed.cpp - src/ripple/protocol/impl/Serializer.cpp - src/ripple/protocol/impl/Sign.cpp - src/ripple/protocol/impl/TER.cpp - src/ripple/protocol/impl/TxFormats.cpp - src/ripple/protocol/impl/UintTypes.cpp - src/ripple/protocol/impl/digest.cpp - src/ripple/protocol/impl/tokens.cpp - #[===============================[ - nounity, main sources: - subdir: crypto - #]===============================] - src/ripple/crypto/impl/GenerateDeterministicKey.cpp - src/ripple/crypto/impl/RFC1751.cpp - src/ripple/crypto/impl/csprng.cpp - src/ripple/crypto/impl/ec_key.cpp - src/ripple/crypto/impl/openssl.cpp) -endif () -add_library (Ripple::xrpl_core ALIAS xrpl_core) -target_include_directories (xrpl_core - PUBLIC - $ - $ - # this one is for beast/legacy files: - $ - $) -target_compile_options (xrpl_core - PUBLIC - $<$:-Wno-maybe-uninitialized>) -target_link_libraries (xrpl_core - PUBLIC - OpenSSL::Crypto - Ripple::boost - Ripple::syslibs - NIH::secp256k1 - NIH::ed25519-donna - date::date - Ripple::opts) -#[=================================[ - main/core headers installation -#]=================================] -install ( - FILES - src/ripple/basics/base64.h - src/ripple/basics/Blob.h - src/ripple/basics/Buffer.h - src/ripple/basics/CountedObject.h - src/ripple/basics/FileUtilities.h - src/ripple/basics/LocalValue.h - src/ripple/basics/Log.h - src/ripple/basics/safe_cast.h - src/ripple/basics/Slice.h - src/ripple/basics/StringUtilities.h - src/ripple/basics/ToString.h - src/ripple/basics/UnorderedContainers.h - src/ripple/basics/algorithm.h - src/ripple/basics/base_uint.h - src/ripple/basics/chrono.h - src/ripple/basics/contract.h - src/ripple/basics/hardened_hash.h - src/ripple/basics/strHex.h - DESTINATION include/ripple/basics) -install ( - FILES - src/ripple/crypto/GenerateDeterministicKey.h - src/ripple/crypto/RFC1751.h - src/ripple/crypto/csprng.h - DESTINATION include/ripple/crypto) -install ( - FILES - src/ripple/crypto/impl/ec_key.h - src/ripple/crypto/impl/openssl.h - DESTINATION include/ripple/crypto/impl) -install ( - FILES - src/ripple/json/JsonPropertyStream.h - src/ripple/json/Object.h - src/ripple/json/Output.h - src/ripple/json/Writer.h - src/ripple/json/json_forwards.h - src/ripple/json/json_reader.h - src/ripple/json/json_value.h - src/ripple/json/json_writer.h - src/ripple/json/to_string.h - DESTINATION include/ripple/json) -install ( - FILES - src/ripple/json/impl/json_assert.h - DESTINATION include/ripple/json/impl) -install ( - FILES - src/ripple/protocol/AccountID.h - src/ripple/protocol/AmountConversions.h - src/ripple/protocol/Book.h - src/ripple/protocol/BuildInfo.h - src/ripple/protocol/ErrorCodes.h - src/ripple/protocol/Feature.h - src/ripple/protocol/HashPrefix.h - src/ripple/protocol/IOUAmount.h - src/ripple/protocol/Indexes.h - src/ripple/protocol/InnerObjectFormats.h - src/ripple/protocol/Issue.h - src/ripple/protocol/KeyType.h - src/ripple/protocol/Keylet.h - src/ripple/protocol/KnownFormats.h - src/ripple/protocol/LedgerFormats.h - src/ripple/protocol/Protocol.h - src/ripple/protocol/PublicKey.h - src/ripple/protocol/Quality.h - src/ripple/protocol/Rate.h - src/ripple/protocol/SField.h - src/ripple/protocol/SOTemplate.h - src/ripple/protocol/STAccount.h - src/ripple/protocol/STAmount.h - src/ripple/protocol/STArray.h - src/ripple/protocol/STBase.h - src/ripple/protocol/STBitString.h - src/ripple/protocol/STBlob.h - src/ripple/protocol/STExchange.h - src/ripple/protocol/STInteger.h - src/ripple/protocol/STLedgerEntry.h - src/ripple/protocol/STObject.h - src/ripple/protocol/STParsedJSON.h - src/ripple/protocol/STPathSet.h - src/ripple/protocol/STTx.h - src/ripple/protocol/STValidation.h - src/ripple/protocol/STVector256.h - src/ripple/protocol/SecretKey.h - src/ripple/protocol/Seed.h - src/ripple/protocol/Serializer.h - src/ripple/protocol/Sign.h - src/ripple/protocol/SystemParameters.h - src/ripple/protocol/TER.h - src/ripple/protocol/TxFlags.h - src/ripple/protocol/TxFormats.h - src/ripple/protocol/UintTypes.h - src/ripple/protocol/XRPAmount.h - src/ripple/protocol/digest.h - src/ripple/protocol/jss.h - src/ripple/protocol/tokens.h - DESTINATION include/ripple/protocol) -install ( - FILES - src/ripple/protocol/impl/STVar.h - src/ripple/protocol/impl/secp256k1.h - DESTINATION include/ripple/protocol/impl) - -#[===================================[ - beast/legacy headers installation -#]===================================] -install ( - FILES - src/ripple/beast/clock/abstract_clock.h - src/ripple/beast/clock/basic_seconds_clock.h - src/ripple/beast/clock/manual_clock.h - DESTINATION include/ripple/beast/clock) -install ( - FILES - src/ripple/beast/core/LexicalCast.h - src/ripple/beast/core/List.h - src/ripple/beast/core/SemanticVersion.h - DESTINATION include/ripple/beast/core) -install ( - FILES - src/ripple/beast/crypto/detail/mac_facade.h - src/ripple/beast/crypto/detail/ripemd_context.h - src/ripple/beast/crypto/detail/sha2_context.h - src/ripple/beast/crypto/ripemd.h - src/ripple/beast/crypto/secure_erase.h - src/ripple/beast/crypto/sha2.h - DESTINATION include/ripple/beast/crypto) -install ( - FILES - src/ripple/beast/cxx17/type_traits.h - DESTINATION include/ripple/beast/cxx17) -install ( - FILES - src/ripple/beast/hash/endian.h - src/ripple/beast/hash/hash_append.h - src/ripple/beast/hash/meta.h - src/ripple/beast/hash/uhash.h - src/ripple/beast/hash/xxhasher.h - DESTINATION include/ripple/beast/hash) -install ( - FILES src/ripple/beast/hash/impl/xxhash.h - DESTINATION include/ripple/beast/hash/impl) -install ( - FILES - src/ripple/beast/rfc2616.h - src/ripple/beast/type_name.h - src/ripple/beast/unit_test.h - src/ripple/beast/xor_shift_engine.h - DESTINATION include/ripple/beast) -install ( - FILES - src/ripple/beast/utility/Journal.h - src/ripple/beast/utility/PropertyStream.h - src/ripple/beast/utility/Zero.h - src/ripple/beast/utility/rngfill.h - DESTINATION include/ripple/beast/utility) -# WARNING!! -- horrible levelization ahead -# (these files should be isolated or moved...but -# unfortunately unit_test.h above creates this dependency) -install ( - FILES - src/beast/extras/beast/unit_test/amount.hpp - src/beast/extras/beast/unit_test/dstream.hpp - src/beast/extras/beast/unit_test/global_suites.hpp - src/beast/extras/beast/unit_test/match.hpp - src/beast/extras/beast/unit_test/recorder.hpp - src/beast/extras/beast/unit_test/reporter.hpp - src/beast/extras/beast/unit_test/results.hpp - src/beast/extras/beast/unit_test/runner.hpp - src/beast/extras/beast/unit_test/suite.hpp - src/beast/extras/beast/unit_test/suite_info.hpp - src/beast/extras/beast/unit_test/suite_list.hpp - src/beast/extras/beast/unit_test/thread.hpp - DESTINATION include/beast/unit_test) -install ( - FILES - src/beast/extras/beast/unit_test/detail/const_container.hpp - DESTINATION include/beast/unit_test/detail) - -#[===================================================================[ - rippled executable -#]===================================================================] - -#[=========================================================[ - this one header is added as source just to keep older - versions of cmake happy. cmake 3.10+ allows - add_executable with no sources -#]=========================================================] -add_executable (rippled src/ripple/app/main/Application.h) -if (unity) - target_sources (rippled PRIVATE - #[===============================[ - unity, main sources - #]===============================] - src/ripple/unity/app_consensus.cpp - src/ripple/unity/app_ledger.cpp - src/ripple/unity/app_ledger_impl.cpp - src/ripple/unity/app_main1.cpp - src/ripple/unity/app_main2.cpp - src/ripple/unity/app_misc.cpp - src/ripple/unity/app_misc_impl.cpp - src/ripple/unity/app_paths.cpp - src/ripple/unity/app_tx.cpp - src/ripple/unity/conditions.cpp - src/ripple/unity/consensus.cpp - src/ripple/unity/core.cpp - src/ripple/unity/basics2.cpp - src/ripple/unity/ledger.cpp - src/ripple/unity/net.cpp - src/ripple/unity/nodestore.cpp - src/ripple/unity/overlay1.cpp - src/ripple/unity/overlay2.cpp - src/ripple/unity/peerfinder.cpp - src/ripple/unity/resource.cpp - src/ripple/unity/rpcx1.cpp - src/ripple/unity/rpcx2.cpp - src/ripple/unity/shamap.cpp - src/ripple/unity/server.cpp - src/ripple/unity/soci_ripple.cpp - #[===============================[ - unity, test sources - #]===============================] - src/test/unity/app_test_unity1.cpp - src/test/unity/app_test_unity2.cpp - src/test/unity/basics_test_unity.cpp - src/test/unity/beast_test_unity1.cpp - src/test/unity/beast_test_unity2.cpp - src/test/unity/conditions_test_unity.cpp - src/test/unity/consensus_test_unity.cpp - src/test/unity/core_test_unity.cpp - src/test/unity/crypto_test_unity.cpp - src/test/unity/json_test_unity.cpp - src/test/unity/ledger_test_unity.cpp - src/test/unity/net_test_unity.cpp - src/test/unity/nodestore_test_unity.cpp - src/test/unity/overlay_test_unity.cpp - src/test/unity/peerfinder_test_unity.cpp - src/test/unity/protocol_test_unity.cpp - src/test/unity/resource_test_unity.cpp - src/test/unity/rpc_test_unity.cpp - src/test/unity/server_test_unity.cpp - src/test/unity/server_status_test_unity.cpp - src/test/unity/shamap_test_unity.cpp - src/test/unity/jtx_unity1.cpp - src/test/unity/jtx_unity2.cpp - src/test/unity/csf_unity.cpp) -else () - target_sources (rippled PRIVATE - #[===============================[ - nounity, main sources: - subdir: app - #]===============================] - src/ripple/app/consensus/RCLConsensus.cpp - src/ripple/app/consensus/RCLCxPeerPos.cpp - src/ripple/app/consensus/RCLValidations.cpp - src/ripple/app/ledger/AcceptedLedger.cpp - src/ripple/app/ledger/AcceptedLedgerTx.cpp - src/ripple/app/ledger/AccountStateSF.cpp - src/ripple/app/ledger/BookListeners.cpp - src/ripple/app/ledger/ConsensusTransSetSF.cpp - src/ripple/app/ledger/Ledger.cpp - src/ripple/app/ledger/LedgerHistory.cpp - src/ripple/app/ledger/OrderBookDB.cpp - src/ripple/app/ledger/TransactionStateSF.cpp - src/ripple/app/ledger/impl/BuildLedger.cpp - src/ripple/app/ledger/impl/InboundLedger.cpp - src/ripple/app/ledger/impl/InboundLedgers.cpp - src/ripple/app/ledger/impl/InboundTransactions.cpp - src/ripple/app/ledger/impl/LedgerCleaner.cpp - src/ripple/app/ledger/impl/LedgerMaster.cpp - src/ripple/app/ledger/impl/LedgerReplay.cpp - src/ripple/app/ledger/impl/LedgerToJson.cpp - src/ripple/app/ledger/impl/LocalTxs.cpp - src/ripple/app/ledger/impl/OpenLedger.cpp - src/ripple/app/ledger/impl/TransactionAcquire.cpp - src/ripple/app/ledger/impl/TransactionMaster.cpp - src/ripple/app/main/Application.cpp - src/ripple/app/main/BasicApp.cpp - src/ripple/app/main/CollectorManager.cpp - src/ripple/app/main/LoadManager.cpp - src/ripple/app/main/Main.cpp - src/ripple/app/main/NodeIdentity.cpp - src/ripple/app/main/NodeStoreScheduler.cpp - src/ripple/app/misc/CanonicalTXSet.cpp - src/ripple/app/misc/FeeVoteImpl.cpp - src/ripple/app/misc/HashRouter.cpp - src/ripple/app/misc/NetworkOPs.cpp - src/ripple/app/misc/SHAMapStoreImp.cpp - src/ripple/app/misc/impl/AccountTxPaging.cpp - src/ripple/app/misc/impl/AmendmentTable.cpp - src/ripple/app/misc/impl/LoadFeeTrack.cpp - src/ripple/app/misc/impl/Manifest.cpp - src/ripple/app/misc/impl/Transaction.cpp - src/ripple/app/misc/impl/TxQ.cpp - src/ripple/app/misc/impl/ValidatorKeys.cpp - src/ripple/app/misc/impl/ValidatorList.cpp - src/ripple/app/misc/impl/ValidatorSite.cpp - src/ripple/app/paths/AccountCurrencies.cpp - src/ripple/app/paths/Credit.cpp - src/ripple/app/paths/Flow.cpp - src/ripple/app/paths/Node.cpp - src/ripple/app/paths/PathRequest.cpp - src/ripple/app/paths/PathRequests.cpp - src/ripple/app/paths/PathState.cpp - src/ripple/app/paths/Pathfinder.cpp - src/ripple/app/paths/RippleCalc.cpp - src/ripple/app/paths/RippleLineCache.cpp - src/ripple/app/paths/RippleState.cpp - src/ripple/app/paths/cursor/AdvanceNode.cpp - src/ripple/app/paths/cursor/DeliverNodeForward.cpp - src/ripple/app/paths/cursor/DeliverNodeReverse.cpp - src/ripple/app/paths/cursor/EffectiveRate.cpp - src/ripple/app/paths/cursor/ForwardLiquidity.cpp - src/ripple/app/paths/cursor/ForwardLiquidityForAccount.cpp - src/ripple/app/paths/cursor/Liquidity.cpp - src/ripple/app/paths/cursor/NextIncrement.cpp - src/ripple/app/paths/cursor/ReverseLiquidity.cpp - src/ripple/app/paths/cursor/ReverseLiquidityForAccount.cpp - src/ripple/app/paths/cursor/RippleLiquidity.cpp - src/ripple/app/paths/impl/BookStep.cpp - src/ripple/app/paths/impl/DirectStep.cpp - src/ripple/app/paths/impl/PaySteps.cpp - src/ripple/app/paths/impl/XRPEndpointStep.cpp - src/ripple/app/tx/impl/ApplyContext.cpp - src/ripple/app/tx/impl/BookTip.cpp - src/ripple/app/tx/impl/CancelCheck.cpp - src/ripple/app/tx/impl/CancelOffer.cpp - src/ripple/app/tx/impl/CancelTicket.cpp - src/ripple/app/tx/impl/CashCheck.cpp - src/ripple/app/tx/impl/Change.cpp - src/ripple/app/tx/impl/CreateCheck.cpp - src/ripple/app/tx/impl/CreateOffer.cpp - src/ripple/app/tx/impl/CreateTicket.cpp - src/ripple/app/tx/impl/DeleteAccount.cpp - src/ripple/app/tx/impl/DepositPreauth.cpp - src/ripple/app/tx/impl/Escrow.cpp - src/ripple/app/tx/impl/InvariantCheck.cpp - src/ripple/app/tx/impl/OfferStream.cpp - src/ripple/app/tx/impl/PayChan.cpp - src/ripple/app/tx/impl/Payment.cpp - src/ripple/app/tx/impl/SetAccount.cpp - src/ripple/app/tx/impl/SetRegularKey.cpp - src/ripple/app/tx/impl/SetSignerList.cpp - src/ripple/app/tx/impl/SetTrust.cpp - src/ripple/app/tx/impl/SignerEntries.cpp - src/ripple/app/tx/impl/Taker.cpp - src/ripple/app/tx/impl/Transactor.cpp - src/ripple/app/tx/impl/apply.cpp - src/ripple/app/tx/impl/applySteps.cpp - #[===============================[ - nounity, main sources: - subdir: basics (partial) - #]===============================] - src/ripple/basics/impl/Archive.cpp - src/ripple/basics/impl/BasicConfig.cpp - src/ripple/basics/impl/PerfLogImp.cpp - src/ripple/basics/impl/ResolverAsio.cpp - src/ripple/basics/impl/Sustain.cpp - src/ripple/basics/impl/UptimeClock.cpp - src/ripple/basics/impl/make_SSLContext.cpp - src/ripple/basics/impl/mulDiv.cpp - #[===============================[ - nounity, main sources: - subdir: conditions - #]===============================] - src/ripple/conditions/impl/Condition.cpp - src/ripple/conditions/impl/Fulfillment.cpp - src/ripple/conditions/impl/error.cpp - #[===============================[ - nounity, main sources: - subdir: core - #]===============================] - src/ripple/core/impl/Config.cpp - src/ripple/core/impl/DatabaseCon.cpp - src/ripple/core/impl/Job.cpp - src/ripple/core/impl/JobQueue.cpp - src/ripple/core/impl/LoadEvent.cpp - src/ripple/core/impl/LoadMonitor.cpp - src/ripple/core/impl/SNTPClock.cpp - src/ripple/core/impl/SociDB.cpp - src/ripple/core/impl/Stoppable.cpp - src/ripple/core/impl/TimeKeeper.cpp - src/ripple/core/impl/Workers.cpp - #[===============================[ - nounity, main sources: - subdir: consensus - #]===============================] - src/ripple/consensus/Consensus.cpp - #[===============================[ - nounity, main sources: - subdir: ledger - #]===============================] - src/ripple/ledger/impl/ApplyStateTable.cpp - src/ripple/ledger/impl/ApplyView.cpp - src/ripple/ledger/impl/ApplyViewBase.cpp - src/ripple/ledger/impl/ApplyViewImpl.cpp - src/ripple/ledger/impl/BookDirs.cpp - src/ripple/ledger/impl/CachedSLEs.cpp - src/ripple/ledger/impl/CachedView.cpp - src/ripple/ledger/impl/CashDiff.cpp - src/ripple/ledger/impl/Directory.cpp - src/ripple/ledger/impl/OpenView.cpp - src/ripple/ledger/impl/PaymentSandbox.cpp - src/ripple/ledger/impl/RawStateTable.cpp - src/ripple/ledger/impl/ReadView.cpp - src/ripple/ledger/impl/TxMeta.cpp - src/ripple/ledger/impl/View.cpp - #[===============================[ - nounity, main sources: - subdir: net - #]===============================] - src/ripple/net/impl/HTTPClient.cpp - src/ripple/net/impl/InfoSub.cpp - src/ripple/net/impl/RPCCall.cpp - src/ripple/net/impl/RPCErr.cpp - src/ripple/net/impl/RPCSub.cpp - src/ripple/net/impl/RegisterSSLCerts.cpp - src/ripple/net/impl/SSLHTTPDownloader.cpp - #[===============================[ - nounity, main sources: - subdir: nodestore - #]===============================] - src/ripple/nodestore/backend/MemoryFactory.cpp - src/ripple/nodestore/backend/NuDBFactory.cpp - src/ripple/nodestore/backend/NullFactory.cpp - src/ripple/nodestore/backend/RocksDBFactory.cpp - src/ripple/nodestore/impl/BatchWriter.cpp - src/ripple/nodestore/impl/Database.cpp - src/ripple/nodestore/impl/DatabaseNodeImp.cpp - src/ripple/nodestore/impl/DatabaseRotatingImp.cpp - src/ripple/nodestore/impl/DatabaseShardImp.cpp - src/ripple/nodestore/impl/DecodedBlob.cpp - src/ripple/nodestore/impl/DummyScheduler.cpp - src/ripple/nodestore/impl/EncodedBlob.cpp - src/ripple/nodestore/impl/ManagerImp.cpp - src/ripple/nodestore/impl/NodeObject.cpp - src/ripple/nodestore/impl/Shard.cpp - #[===============================[ - nounity, main sources: - subdir: overlay - #]===============================] - src/ripple/overlay/impl/Cluster.cpp - src/ripple/overlay/impl/ConnectAttempt.cpp - src/ripple/overlay/impl/Handshake.cpp - src/ripple/overlay/impl/Message.cpp - src/ripple/overlay/impl/OverlayImpl.cpp - src/ripple/overlay/impl/PeerImp.cpp - src/ripple/overlay/impl/PeerReservationTable.cpp - src/ripple/overlay/impl/PeerSet.cpp - src/ripple/overlay/impl/ProtocolVersion.cpp - src/ripple/overlay/impl/TrafficCount.cpp - #[===============================[ - nounity, main sources: - subdir: peerfinder - #]===============================] - src/ripple/peerfinder/impl/Bootcache.cpp - src/ripple/peerfinder/impl/Endpoint.cpp - src/ripple/peerfinder/impl/PeerfinderConfig.cpp - src/ripple/peerfinder/impl/PeerfinderManager.cpp - src/ripple/peerfinder/impl/SlotImp.cpp - src/ripple/peerfinder/impl/SourceStrings.cpp - #[===============================[ - nounity, main sources: - subdir: resource - #]===============================] - src/ripple/resource/impl/Charge.cpp - src/ripple/resource/impl/Consumer.cpp - src/ripple/resource/impl/Fees.cpp - src/ripple/resource/impl/ResourceManager.cpp - #[===============================[ - nounity, main sources: - subdir: rpc - #]===============================] - src/ripple/rpc/handlers/AccountChannels.cpp - src/ripple/rpc/handlers/AccountCurrenciesHandler.cpp - src/ripple/rpc/handlers/AccountInfo.cpp - src/ripple/rpc/handlers/AccountLines.cpp - src/ripple/rpc/handlers/AccountObjects.cpp - src/ripple/rpc/handlers/AccountOffers.cpp - src/ripple/rpc/handlers/AccountTx.cpp - src/ripple/rpc/handlers/AccountTxOld.cpp - src/ripple/rpc/handlers/AccountTxSwitch.cpp - src/ripple/rpc/handlers/BlackList.cpp - src/ripple/rpc/handlers/BookOffers.cpp - src/ripple/rpc/handlers/CanDelete.cpp - src/ripple/rpc/handlers/Connect.cpp - src/ripple/rpc/handlers/ConsensusInfo.cpp - src/ripple/rpc/handlers/CrawlShards.cpp - src/ripple/rpc/handlers/DepositAuthorized.cpp - src/ripple/rpc/handlers/DownloadShard.cpp - src/ripple/rpc/handlers/Feature1.cpp - src/ripple/rpc/handlers/Fee1.cpp - src/ripple/rpc/handlers/FetchInfo.cpp - src/ripple/rpc/handlers/GatewayBalances.cpp - src/ripple/rpc/handlers/GetCounts.cpp - src/ripple/rpc/handlers/LedgerAccept.cpp - src/ripple/rpc/handlers/LedgerCleanerHandler.cpp - src/ripple/rpc/handlers/LedgerClosed.cpp - src/ripple/rpc/handlers/LedgerCurrent.cpp - src/ripple/rpc/handlers/LedgerData.cpp - src/ripple/rpc/handlers/LedgerEntry.cpp - src/ripple/rpc/handlers/LedgerHandler.cpp - src/ripple/rpc/handlers/LedgerHeader.cpp - src/ripple/rpc/handlers/LedgerRequest.cpp - src/ripple/rpc/handlers/LogLevel.cpp - src/ripple/rpc/handlers/LogRotate.cpp - src/ripple/rpc/handlers/NoRippleCheck.cpp - src/ripple/rpc/handlers/OwnerInfo.cpp - src/ripple/rpc/handlers/PathFind.cpp - src/ripple/rpc/handlers/PayChanClaim.cpp - src/ripple/rpc/handlers/Peers.cpp - src/ripple/rpc/handlers/Ping.cpp - src/ripple/rpc/handlers/Print.cpp - src/ripple/rpc/handlers/Random.cpp - src/ripple/rpc/handlers/Reservations.cpp - src/ripple/rpc/handlers/RipplePathFind.cpp - src/ripple/rpc/handlers/ServerInfo.cpp - src/ripple/rpc/handlers/ServerState.cpp - src/ripple/rpc/handlers/SignFor.cpp - src/ripple/rpc/handlers/SignHandler.cpp - src/ripple/rpc/handlers/Stop.cpp - src/ripple/rpc/handlers/Submit.cpp - src/ripple/rpc/handlers/SubmitMultiSigned.cpp - src/ripple/rpc/handlers/Subscribe.cpp - src/ripple/rpc/handlers/TransactionEntry.cpp - src/ripple/rpc/handlers/Tx.cpp - src/ripple/rpc/handlers/TxHistory.cpp - src/ripple/rpc/handlers/UnlList.cpp - src/ripple/rpc/handlers/Unsubscribe.cpp - src/ripple/rpc/handlers/ValidationCreate.cpp - src/ripple/rpc/handlers/ValidatorListSites.cpp - src/ripple/rpc/handlers/Validators.cpp - src/ripple/rpc/handlers/WalletPropose.cpp - src/ripple/rpc/impl/DeliveredAmount.cpp - src/ripple/rpc/impl/Handler.cpp - src/ripple/rpc/impl/LegacyPathFind.cpp - src/ripple/rpc/impl/RPCHandler.cpp - src/ripple/rpc/impl/RPCHelpers.cpp - src/ripple/rpc/impl/Role.cpp - src/ripple/rpc/impl/ServerHandlerImp.cpp - src/ripple/rpc/impl/ShardArchiveHandler.cpp - src/ripple/rpc/impl/Status.cpp - src/ripple/rpc/impl/TransactionSign.cpp - #[===============================[ - nounity, main sources: - subdir: server - #]===============================] - src/ripple/server/impl/JSONRPCUtil.cpp - src/ripple/server/impl/Port.cpp - #[===============================[ - nounity, main sources: - subdir: shamap - #]===============================] - src/ripple/shamap/impl/SHAMap.cpp - src/ripple/shamap/impl/SHAMapDelta.cpp - src/ripple/shamap/impl/SHAMapItem.cpp - src/ripple/shamap/impl/SHAMapMissingNode.cpp - src/ripple/shamap/impl/SHAMapNodeID.cpp - src/ripple/shamap/impl/SHAMapSync.cpp - src/ripple/shamap/impl/SHAMapTreeNode.cpp - #[===============================[ - nounity, test sources: - subdir: app - #]===============================] - src/test/app/AccountDelete_test.cpp - src/test/app/AccountTxPaging_test.cpp - src/test/app/AmendmentTable_test.cpp - src/test/app/Check_test.cpp - src/test/app/CrossingLimits_test.cpp - src/test/app/DeliverMin_test.cpp - src/test/app/DepositAuth_test.cpp - src/test/app/Discrepancy_test.cpp - src/test/app/Escrow_test.cpp - src/test/app/Flow_test.cpp - src/test/app/Freeze_test.cpp - src/test/app/HashRouter_test.cpp - src/test/app/LedgerHistory_test.cpp - src/test/app/LedgerLoad_test.cpp - src/test/app/LedgerReplay_test.cpp - src/test/app/LoadFeeTrack_test.cpp - src/test/app/Manifest_test.cpp - src/test/app/MultiSign_test.cpp - src/test/app/OfferStream_test.cpp - src/test/app/Offer_test.cpp - src/test/app/OversizeMeta_test.cpp - src/test/app/Path_test.cpp - src/test/app/PayChan_test.cpp - src/test/app/PayStrand_test.cpp - src/test/app/PseudoTx_test.cpp - src/test/app/RCLCensorshipDetector_test.cpp - src/test/app/RCLValidations_test.cpp - src/test/app/Regression_test.cpp - src/test/app/SHAMapStore_test.cpp - src/test/app/SetAuth_test.cpp - src/test/app/SetRegularKey_test.cpp - src/test/app/SetTrust_test.cpp - src/test/app/Taker_test.cpp - src/test/app/Ticket_test.cpp - src/test/app/Transaction_ordering_test.cpp - src/test/app/TrustAndBalance_test.cpp - src/test/app/TxQ_test.cpp - src/test/app/ValidatorKeys_test.cpp - src/test/app/ValidatorList_test.cpp - src/test/app/ValidatorSite_test.cpp - #[===============================[ - nounity, test sources: - subdir: basics - #]===============================] - src/test/basics/Buffer_test.cpp - src/test/basics/DetectCrash_test.cpp - src/test/basics/FileUtilities_test.cpp - src/test/basics/KeyCache_test.cpp - src/test/basics/PerfLog_test.cpp - src/test/basics/RangeSet_test.cpp - src/test/basics/Slice_test.cpp - src/test/basics/StringUtilities_test.cpp - src/test/basics/TaggedCache_test.cpp - src/test/basics/base64_test.cpp - src/test/basics/base_uint_test.cpp - src/test/basics/contract_test.cpp - src/test/basics/hardened_hash_test.cpp - src/test/basics/mulDiv_test.cpp - src/test/basics/qalloc_test.cpp - src/test/basics/tagged_integer_test.cpp - #[===============================[ - nounity, test sources: - subdir: beast - #]===============================] - src/test/beast/IPEndpoint_test.cpp - src/test/beast/LexicalCast_test.cpp - src/test/beast/SemanticVersion_test.cpp - src/test/beast/aged_associative_container_test.cpp - src/test/beast/beast_CurrentThreadName_test.cpp - src/test/beast/beast_Journal_test.cpp - src/test/beast/beast_PropertyStream_test.cpp - src/test/beast/beast_Zero_test.cpp - src/test/beast/beast_abstract_clock_test.cpp - src/test/beast/beast_asio_error_test.cpp - src/test/beast/beast_basic_seconds_clock_test.cpp - src/test/beast/beast_io_latency_probe_test.cpp - src/test/beast/define_print.cpp - #[===============================[ - nounity, test sources: - subdir: conditions - #]===============================] - src/test/conditions/PreimageSha256_test.cpp - #[===============================[ - nounity, test sources: - subdir: consensus - #]===============================] - src/test/consensus/ByzantineFailureSim_test.cpp - src/test/consensus/Consensus_test.cpp - src/test/consensus/DistributedValidatorsSim_test.cpp - src/test/consensus/LedgerTiming_test.cpp - src/test/consensus/LedgerTrie_test.cpp - src/test/consensus/ScaleFreeSim_test.cpp - src/test/consensus/Validations_test.cpp - #[===============================[ - nounity, test sources: - subdir: core - #]===============================] - src/test/core/ClosureCounter_test.cpp - src/test/core/Config_test.cpp - src/test/core/Coroutine_test.cpp - src/test/core/CryptoPRNG_test.cpp - src/test/core/JobQueue_test.cpp - src/test/core/SociDB_test.cpp - src/test/core/Stoppable_test.cpp - src/test/core/Workers_test.cpp - #[===============================[ - nounity, test sources: - subdir: crypto - #]===============================] - src/test/crypto/Openssl_test.cpp - #[===============================[ - nounity, test sources: - subdir: csf - #]===============================] - src/test/csf/BasicNetwork_test.cpp - src/test/csf/Digraph_test.cpp - src/test/csf/Histogram_test.cpp - src/test/csf/Scheduler_test.cpp - src/test/csf/impl/Sim.cpp - src/test/csf/impl/ledgers.cpp - #[===============================[ - nounity, test sources: - subdir: json - #]===============================] - src/test/json/Object_test.cpp - src/test/json/Output_test.cpp - src/test/json/Writer_test.cpp - src/test/json/json_value_test.cpp - #[===============================[ - nounity, test sources: - subdir: jtx - #]===============================] - src/test/jtx/Env_test.cpp - src/test/jtx/WSClient_test.cpp - src/test/jtx/impl/Account.cpp - src/test/jtx/impl/Env.cpp - src/test/jtx/impl/JSONRPCClient.cpp - src/test/jtx/impl/ManualTimeKeeper.cpp - src/test/jtx/impl/WSClient.cpp - src/test/jtx/impl/acctdelete.cpp - src/test/jtx/impl/amount.cpp - src/test/jtx/impl/balance.cpp - src/test/jtx/impl/check.cpp - src/test/jtx/impl/delivermin.cpp - src/test/jtx/impl/deposit.cpp - src/test/jtx/impl/envconfig.cpp - src/test/jtx/impl/fee.cpp - src/test/jtx/impl/flags.cpp - src/test/jtx/impl/jtx_json.cpp - src/test/jtx/impl/memo.cpp - src/test/jtx/impl/multisign.cpp - src/test/jtx/impl/offer.cpp - src/test/jtx/impl/owners.cpp - src/test/jtx/impl/paths.cpp - src/test/jtx/impl/pay.cpp - src/test/jtx/impl/quality2.cpp - src/test/jtx/impl/rate.cpp - src/test/jtx/impl/regkey.cpp - src/test/jtx/impl/sendmax.cpp - src/test/jtx/impl/seq.cpp - src/test/jtx/impl/sig.cpp - src/test/jtx/impl/tag.cpp - src/test/jtx/impl/ticket.cpp - src/test/jtx/impl/trust.cpp - src/test/jtx/impl/txflags.cpp - src/test/jtx/impl/utility.cpp - #[===============================[ - nounity, test sources: - subdir: ledger - #]===============================] - src/test/ledger/BookDirs_test.cpp - src/test/ledger/CashDiff_test.cpp - src/test/ledger/Directory_test.cpp - src/test/ledger/Invariants_test.cpp - src/test/ledger/PaymentSandbox_test.cpp - src/test/ledger/PendingSaves_test.cpp - src/test/ledger/SkipList_test.cpp - src/test/ledger/View_test.cpp - #[===============================[ - nounity, test sources: - subdir: net - #]===============================] - src/test/net/SSLHTTPDownloader_test.cpp - #[===============================[ - nounity, test sources: - subdir: nodestore - #]===============================] - src/test/nodestore/Backend_test.cpp - src/test/nodestore/Basics_test.cpp - src/test/nodestore/Database_test.cpp - src/test/nodestore/Timing_test.cpp - src/test/nodestore/import_test.cpp - src/test/nodestore/varint_test.cpp - #[===============================[ - nounity, test sources: - subdir: overlay - #]===============================] - src/test/overlay/ProtocolVersion_test.cpp - src/test/overlay/cluster_test.cpp - src/test/overlay/short_read_test.cpp - #[===============================[ - nounity, test sources: - subdir: peerfinder - #]===============================] - src/test/peerfinder/Livecache_test.cpp - src/test/peerfinder/PeerFinder_test.cpp - #[===============================[ - nounity, test sources: - subdir: protocol - #]===============================] - src/test/protocol/IOUAmount_test.cpp - src/test/protocol/InnerObjectFormats_test.cpp - src/test/protocol/Issue_test.cpp - src/test/protocol/PublicKey_test.cpp - src/test/protocol/Quality_test.cpp - src/test/protocol/STAccount_test.cpp - src/test/protocol/STAmount_test.cpp - src/test/protocol/STObject_test.cpp - src/test/protocol/STTx_test.cpp - src/test/protocol/STValidation_test.cpp - src/test/protocol/SecretKey_test.cpp - src/test/protocol/Seed_test.cpp - src/test/protocol/TER_test.cpp - src/test/protocol/XRPAmount_test.cpp - src/test/protocol/digest_test.cpp - src/test/protocol/types_test.cpp - #[===============================[ - nounity, test sources: - subdir: resource - #]===============================] - src/test/resource/Logic_test.cpp - #[===============================[ - nounity, test sources: - subdir: rpc - #]===============================] - src/test/rpc/AccountCurrencies_test.cpp - src/test/rpc/AccountInfo_test.cpp - src/test/rpc/AccountLinesRPC_test.cpp - src/test/rpc/AccountObjects_test.cpp - src/test/rpc/AccountOffers_test.cpp - src/test/rpc/AccountSet_test.cpp - src/test/rpc/AccountTx_test.cpp - src/test/rpc/AmendmentBlocked_test.cpp - src/test/rpc/Book_test.cpp - src/test/rpc/DepositAuthorized_test.cpp - src/test/rpc/DeliveredAmount_test.cpp - src/test/rpc/Feature_test.cpp - src/test/rpc/GatewayBalances_test.cpp - src/test/rpc/GetCounts_test.cpp - src/test/rpc/JSONRPC_test.cpp - src/test/rpc/KeyGeneration_test.cpp - src/test/rpc/LedgerClosed_test.cpp - src/test/rpc/LedgerData_test.cpp - src/test/rpc/LedgerRPC_test.cpp - src/test/rpc/LedgerRequestRPC_test.cpp - src/test/rpc/NoRippleCheck_test.cpp - src/test/rpc/NoRipple_test.cpp - src/test/rpc/OwnerInfo_test.cpp - src/test/rpc/Peers_test.cpp - src/test/rpc/Roles_test.cpp - src/test/rpc/RPCCall_test.cpp - src/test/rpc/RPCOverload_test.cpp - src/test/rpc/RobustTransaction_test.cpp - src/test/rpc/ServerInfo_test.cpp - src/test/rpc/Status_test.cpp - src/test/rpc/Subscribe_test.cpp - src/test/rpc/Transaction_test.cpp - src/test/rpc/TransactionEntry_test.cpp - src/test/rpc/TransactionHistory_test.cpp - src/test/rpc/ValidatorRPC_test.cpp - src/test/rpc/Version_test.cpp - #[===============================[ - nounity, test sources: - subdir: server - #]===============================] - src/test/server/ServerStatus_test.cpp - src/test/server/Server_test.cpp - #[===============================[ - nounity, test sources: - subdir: shamap - #]===============================] - src/test/shamap/FetchPack_test.cpp - src/test/shamap/SHAMapSync_test.cpp - src/test/shamap/SHAMap_test.cpp - #[===============================[ - nounity, test sources: - subdir: unit_test - #]===============================] - src/test/unit_test/multi_runner.cpp) -endif () -target_link_libraries (rippled - Ripple::boost - Ripple::opts - Ripple::libs - Ripple::xrpl_core) -exclude_if_included (rippled) -# define a macro for tests that might need to -# be exluded or run differently in CI environment -if (is_ci) - target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI) -endif () diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake deleted file mode 100644 index b9d93f41af8..00000000000 --- a/Builds/CMake/RippledCov.cmake +++ /dev/null @@ -1,98 +0,0 @@ -#[===================================================================[ - coverage report target -#]===================================================================] - -if (coverage) - if (is_clang) - if (APPLE) - execute_process (COMMAND xcrun -f llvm-profdata - OUTPUT_VARIABLE LLVM_PROFDATA - OUTPUT_STRIP_TRAILING_WHITESPACE) - else () - find_program (LLVM_PROFDATA llvm-profdata) - endif () - if (NOT LLVM_PROFDATA) - message (WARNING "unable to find llvm-profdata - skipping coverage_report target") - endif () - - if (APPLE) - execute_process (COMMAND xcrun -f llvm-cov - OUTPUT_VARIABLE LLVM_COV - OUTPUT_STRIP_TRAILING_WHITESPACE) - else () - find_program (LLVM_COV llvm-cov) - endif () - if (NOT LLVM_COV) - message (WARNING "unable to find llvm-cov - skipping coverage_report target") - endif () - - set (extract_pattern "") - if (coverage_core_only) - set (extract_pattern "${CMAKE_SOURCE_DIR}/src/ripple/") - endif () - - if (LLVM_COV AND LLVM_PROFDATA) - add_custom_target (coverage_report - USES_TERMINAL - COMMAND ${CMAKE_COMMAND} -E echo "Generating coverage - results will be in ${CMAKE_BINARY_DIR}/coverage/index.html." - COMMAND ${CMAKE_COMMAND} -E echo "Running rippled tests." - COMMAND rippled --unittest$<$:=${coverage_test}> --quiet --unittest-log - COMMAND ${LLVM_PROFDATA} - merge -sparse default.profraw -o rip.profdata - COMMAND ${CMAKE_COMMAND} -E echo "Summary of coverage:" - COMMAND ${LLVM_COV} - report -instr-profile=rip.profdata - $ ${extract_pattern} - # generate html report - COMMAND ${LLVM_COV} - show -format=html -output-dir=${CMAKE_BINARY_DIR}/coverage - -instr-profile=rip.profdata - $ ${extract_pattern} - BYPRODUCTS coverage/index.html) - endif () - elseif (is_gcc) - find_program (LCOV lcov) - if (NOT LCOV) - message (WARNING "unable to find lcov - skipping coverage_report target") - endif () - - find_program (GENHTML genhtml) - if (NOT GENHTML) - message (WARNING "unable to find genhtml - skipping coverage_report target") - endif () - - set (extract_pattern "*") - if (coverage_core_only) - set (extract_pattern "*/src/ripple/*") - endif () - - if (LCOV AND GENHTML) - add_custom_target (coverage_report - USES_TERMINAL - COMMAND ${CMAKE_COMMAND} -E echo "Generating coverage- results will be in ${CMAKE_BINARY_DIR}/coverage/index.html." - # create baseline info file - COMMAND ${LCOV} - --no-external -d "${CMAKE_SOURCE_DIR}" -c -d . -i -o baseline.info - | grep -v "ignoring data for external file" - # run tests - COMMAND ${CMAKE_COMMAND} -E echo "Running rippled tests for coverage report." - COMMAND rippled --unittest$<$:=${coverage_test}> --quiet --unittest-log - # Create test coverage data file - COMMAND ${LCOV} - --no-external -d "${CMAKE_SOURCE_DIR}" -c -d . -o tests.info - | grep -v "ignoring data for external file" - # Combine baseline and test coverage data - COMMAND ${LCOV} - -a baseline.info -a tests.info -o lcov-all.info - # extract our files - COMMAND ${LCOV} - -e lcov-all.info "${extract_pattern}" -o lcov.info - COMMAND ${CMAKE_COMMAND} -E echo "Summary of coverage:" - COMMAND ${LCOV} --summary lcov.info - # generate HTML report - COMMAND ${GENHTML} - -o ${CMAKE_BINARY_DIR}/coverage lcov.info - BYPRODUCTS coverage/index.html) - endif () - endif () -endif () diff --git a/Builds/CMake/RippledDocs.cmake b/Builds/CMake/RippledDocs.cmake deleted file mode 100644 index be964a56049..00000000000 --- a/Builds/CMake/RippledDocs.cmake +++ /dev/null @@ -1,31 +0,0 @@ -#[===================================================================[ - docs target (optional) -#]===================================================================] - -find_package (Doxygen) -if (TARGET Doxygen::doxygen) - set (doc_srcs docs/source.dox) - file (GLOB_RECURSE other_docs docs/*.md) - list (APPEND doc_srcs "${other_docs}") - # read the source config and make a modified one - # that points the output files to our build directory - file (READ "${CMAKE_CURRENT_SOURCE_DIR}/docs/source.dox" dox_content) - string (REGEX REPLACE "[\t ]*OUTPUT_DIRECTORY[\t ]*=(.*)" - "OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}\n\\1" - new_config "${dox_content}") - file (WRITE "${CMAKE_BINARY_DIR}/source.dox" "${new_config}") - add_custom_target (docs - COMMAND "${DOXYGEN_EXECUTABLE}" "${CMAKE_BINARY_DIR}/source.dox" - BYPRODUCTS "${CMAKE_BINARY_DIR}/html_doc/index.html" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/docs" - SOURCES "${doc_srcs}") - if (is_multiconfig) - set_property ( - SOURCE ${doc_srcs} - APPEND - PROPERTY HEADER_FILE_ONLY - true) - endif () -else () - message (STATUS "doxygen executable not found -- skipping docs target") -endif () diff --git a/Builds/CMake/RippledInstall.cmake b/Builds/CMake/RippledInstall.cmake deleted file mode 100644 index 3cdeca9e6fb..00000000000 --- a/Builds/CMake/RippledInstall.cmake +++ /dev/null @@ -1,62 +0,0 @@ -#[===================================================================[ - install stuff -#]===================================================================] - -install ( - TARGETS - ed25519-donna - common - opts - ripple_syslibs - ripple_boost - xrpl_core - EXPORT RippleExports - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include) - -if(${INSTALL_SECP256K1}) -install ( - TARGETS - secp256k1 - EXPORT RippleExports - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include) -endif() - -install (EXPORT RippleExports - FILE RippleTargets.cmake - NAMESPACE Ripple:: - DESTINATION lib/cmake/ripple) -include (CMakePackageConfigHelpers) -write_basic_package_version_file ( - RippleConfigVersion.cmake - VERSION ${rippled_version} - COMPATIBILITY SameMajorVersion) - -if (is_root_project) - install (TARGETS rippled RUNTIME DESTINATION bin) - set_target_properties(rippled PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON) - install ( - FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Builds/CMake/RippleConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/RippleConfigVersion.cmake - DESTINATION lib/cmake/ripple) - # sample configs should not overwrite existing files - # install if-not-exists workaround as suggested by - # https://cmake.org/Bug/view.php?id=12646 - install(CODE " - macro (copy_if_not_exists SRC DEST NEWNAME) - if (NOT EXISTS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\") - file (INSTALL FILE_PERMISSIONS OWNER_READ OWNER_WRITE DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${DEST}\" FILES \"\${SRC}\" RENAME \"\${NEWNAME}\") - else () - message (\"-- Skipping : \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\") - endif () - endmacro() - copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/rippled-example.cfg\" etc rippled.cfg) - copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt) - ") -endif () diff --git a/Builds/CMake/RippledInterface.cmake b/Builds/CMake/RippledInterface.cmake deleted file mode 100644 index c28896087ee..00000000000 --- a/Builds/CMake/RippledInterface.cmake +++ /dev/null @@ -1,108 +0,0 @@ -#[===================================================================[ - rippled compile options/settings via an interface library -#]===================================================================] - -add_library (opts INTERFACE) -add_library (Ripple::opts ALIAS opts) -target_compile_definitions (opts - INTERFACE - BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS - $<$: - BOOST_ASIO_NO_DEPRECATED - BOOST_FILESYSTEM_NO_DEPRECATED - > - $<$>: - BOOST_COROUTINES_NO_DEPRECATION_WARNING - BOOST_BEAST_ALLOW_DEPRECATED - BOOST_FILESYSTEM_DEPRECATED - > - $<$: - USE_BEAST_HASHER - > - $<$:BEAST_NO_UNIT_TEST_INLINE=1> - $<$:BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES=1> - $<$:RIPPLE_SINGLE_IO_SERVICE_THREAD=1> - # doesn't currently compile ? : - $<$:RIPPLE_VERIFY_NODEOBJECT_KEYS=1>) -target_compile_options (opts - INTERFACE - $<$,$>:-Wsuggest-override> - $<$:-fno-omit-frame-pointer> - $<$,$>:-fprofile-arcs -ftest-coverage> - $<$,$>:-fprofile-instr-generate -fcoverage-mapping> - $<$:-pg> - $<$,$>:-p>) - -target_link_libraries (opts - INTERFACE - $<$,$>:-fprofile-arcs -ftest-coverage> - $<$,$>:-fprofile-instr-generate -fcoverage-mapping> - $<$:-pg> - $<$,$>:-p>) - -if (jemalloc) - if (static) - set(JEMALLOC_USE_STATIC ON CACHE BOOL "" FORCE) - endif () - find_package (jemalloc REQUIRED) - target_compile_definitions (opts INTERFACE PROFILE_JEMALLOC) - target_include_directories (opts SYSTEM INTERFACE ${JEMALLOC_INCLUDE_DIRS}) - target_link_libraries (opts INTERFACE ${JEMALLOC_LIBRARIES}) - get_filename_component (JEMALLOC_LIB_PATH ${JEMALLOC_LIBRARIES} DIRECTORY) - ## TODO see if we can use the BUILD_RPATH target property (is it transitive?) - set (CMAKE_BUILD_RPATH ${CMAKE_BUILD_RPATH} ${JEMALLOC_LIB_PATH}) -endif () - -if (san) - target_compile_options (opts - INTERFACE - # sanitizers recommend minimum of -O1 for reasonable performance - $<$:-O1> - ${SAN_FLAG} - -fno-omit-frame-pointer) - target_compile_definitions (opts - INTERFACE - $<$:SANITIZER=ASAN> - $<$:SANITIZER=TSAN> - $<$:SANITIZER=MSAN> - $<$:SANITIZER=UBSAN>) - target_link_libraries (opts INTERFACE ${SAN_FLAG} ${SAN_LIB}) -endif () - -#[===================================================================[ - rippled transitive library deps via an interface library -#]===================================================================] - -add_library (ripple_syslibs INTERFACE) -add_library (Ripple::syslibs ALIAS ripple_syslibs) -target_link_libraries (ripple_syslibs - INTERFACE - $<$: - legacy_stdio_definitions.lib - Shlwapi - kernel32 - user32 - gdi32 - winspool - comdlg32 - advapi32 - shell32 - ole32 - oleaut32 - uuid - odbc32 - odbccp32 - crypt32 - > - $<$>:dl> - $<$,$>>:rt>) - -if (NOT MSVC) - set (THREADS_PREFER_PTHREAD_FLAG ON) - find_package (Threads) - target_link_libraries (ripple_syslibs INTERFACE Threads::Threads) -endif () - -add_library (ripple_libs INTERFACE) -add_library (Ripple::libs ALIAS ripple_libs) -target_link_libraries (ripple_libs INTERFACE Ripple::syslibs) diff --git a/Builds/CMake/RippledMultiConfig.cmake b/Builds/CMake/RippledMultiConfig.cmake deleted file mode 100644 index 3bc500b53bc..00000000000 --- a/Builds/CMake/RippledMultiConfig.cmake +++ /dev/null @@ -1,39 +0,0 @@ -#[===================================================================[ - multiconfig misc -#]===================================================================] - -if (is_multiconfig) - # This code finds all source files in the src subdirectory for inclusion - # in the IDE file tree as non-compiled sources. Since this file list will - # have some overlap with files we have already added to our targets to - # be compiled, we explicitly remove any of these target source files from - # this list. - file (GLOB_RECURSE all_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - CONFIGURE_DEPENDS - src/*.* Builds/*.md docs/*.md src/*.md Builds/*.cmake) - file(GLOB md_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS - *.md) - LIST(APPEND all_sources ${md_files}) - foreach (_target secp256k1 ed25519-donna pbufs xrpl_core rippled) - get_target_property (_type ${_target} TYPE) - if(_type STREQUAL "INTERFACE_LIBRARY") - continue() - endif() - get_target_property (_src ${_target} SOURCES) - list (REMOVE_ITEM all_sources ${_src}) - endforeach () - target_sources (rippled PRIVATE ${all_sources}) - set_property ( - SOURCE ${all_sources} - APPEND - PROPERTY HEADER_FILE_ONLY true) - if (MSVC) - set_property( - DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - PROPERTY VS_STARTUP_PROJECT rippled) - endif () - - group_sources(src) - group_sources(docs) - group_sources(Builds) -endif () diff --git a/Builds/CMake/RippledNIH.cmake b/Builds/CMake/RippledNIH.cmake deleted file mode 100644 index e0c161aba78..00000000000 --- a/Builds/CMake/RippledNIH.cmake +++ /dev/null @@ -1,33 +0,0 @@ -#[===================================================================[ - NIH prefix path..this is where we will download - and build any ExternalProjects, and they will hopefully - survive across build directory deletion (manual cleans) -#]===================================================================] - -string (REGEX REPLACE "[ \\/%]+" "_" gen_for_path ${CMAKE_GENERATOR}) -string (TOLOWER ${gen_for_path} gen_for_path) -# HACK: trying to shorten paths for windows CI (which hits 260 MAXPATH easily) -# @see: https://issues.jenkins-ci.org/browse/JENKINS-38706?focusedCommentId=339847 -string (REPLACE "visual_studio" "vs" gen_for_path ${gen_for_path}) -if (NOT DEFINED NIH_CACHE_ROOT) - if (DEFINED ENV{NIH_CACHE_ROOT}) - set (NIH_CACHE_ROOT $ENV{NIH_CACHE_ROOT}) - else () - set (NIH_CACHE_ROOT "${CMAKE_SOURCE_DIR}/.nih_c") - endif () -endif () -set (nih_cache_path - "${NIH_CACHE_ROOT}/${gen_for_path}/${CMAKE_CXX_COMPILER_ID}_${CMAKE_CXX_COMPILER_VERSION}") -if (NOT is_multiconfig) - set (nih_cache_path "${nih_cache_path}/${CMAKE_BUILD_TYPE}") -endif () -file(TO_CMAKE_PATH "${nih_cache_path}" nih_cache_path) -message (STATUS "NIH-EP cache path: ${nih_cache_path}") -## two convenience variables: -set (ep_lib_prefix ${CMAKE_STATIC_LIBRARY_PREFIX}) -set (ep_lib_suffix ${CMAKE_STATIC_LIBRARY_SUFFIX}) - -# this is a setting for FetchContent and needs to be -# a cache variable -# https://cmake.org/cmake/help/latest/module/FetchContent.html#populating-the-content -set (FETCHCONTENT_BASE_DIR ${nih_cache_path} CACHE STRING "" FORCE) diff --git a/Builds/CMake/RippledRelease.cmake b/Builds/CMake/RippledRelease.cmake deleted file mode 100644 index a173695237d..00000000000 --- a/Builds/CMake/RippledRelease.cmake +++ /dev/null @@ -1,181 +0,0 @@ -#[===================================================================[ - package/container targets - (optional) -#]===================================================================] - -if (is_root_project) - if (NOT DOCKER) - find_program (DOCKER docker) - endif () - - if (DOCKER) - # if no container label is provided, use current git hash - git_hash (commit_hash) - if (NOT container_label) - set (container_label ${commit_hash}) - endif () - message (STATUS "using [${container_label}] as build container tag...") - - file (MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/packages) - file (MAKE_DIRECTORY ${NIH_CACHE_ROOT}/pkgbuild) - if (is_linux) - execute_process (COMMAND id -u - OUTPUT_VARIABLE DOCKER_USER_ID - OUTPUT_STRIP_TRAILING_WHITESPACE) - message (STATUS "docker local user id: ${DOCKER_USER_ID}") - execute_process (COMMAND id -g - OUTPUT_VARIABLE DOCKER_GROUP_ID - OUTPUT_STRIP_TRAILING_WHITESPACE) - message (STATUS "docker local group id: ${DOCKER_GROUP_ID}") - endif () - if (DOCKER_USER_ID AND DOCKER_GROUP_ID) - set(map_user TRUE) - endif () - #[===================================================================[ - rpm - #]===================================================================] - add_custom_target (rpm_container - docker build - --pull - --build-arg GIT_COMMIT=${commit_hash} - -t rippled-rpm-builder:${container_label} - $<$:--cache-from=${rpm_cache_from}> - -f centos-builder/Dockerfile . - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Builds/containers - VERBATIM - USES_TERMINAL - COMMAND_EXPAND_LISTS - SOURCES - Builds/containers/centos-builder/Dockerfile - Builds/containers/centos-builder/centos_setup.sh - Builds/containers/centos-builder/extras.sh - Builds/containers/shared/build_deps.sh - Builds/containers/shared/rippled.service - Builds/containers/shared/update_sources.sh - Builds/containers/shared/update-rippled.sh - Builds/containers/packaging/rpm/rippled.spec - Builds/containers/packaging/rpm/build_rpm.sh - ) - exclude_from_default (rpm_container) - add_custom_target (rpm - docker run - -e NIH_CACHE_ROOT=/opt/rippled_bld/pkg/.nih_c - -v ${NIH_CACHE_ROOT}/pkgbuild:/opt/rippled_bld/pkg/.nih_c - -v ${CMAKE_SOURCE_DIR}:/opt/rippled_bld/pkg/rippled - -v ${CMAKE_CURRENT_BINARY_DIR}/packages:/opt/rippled_bld/pkg/out - "$<$:--volume=/etc/passwd:/etc/passwd;--volume=/etc/group:/etc/group;--user=${DOCKER_USER_ID}:${DOCKER_GROUP_ID}>" - -t rippled-rpm-builder:${container_label} - VERBATIM - USES_TERMINAL - COMMAND_EXPAND_LISTS - SOURCES - Builds/containers/packaging/rpm/rippled.spec - ) - exclude_from_default (rpm) - if (NOT have_package_container) - add_dependencies(rpm rpm_container) - endif () - #[===================================================================[ - dpkg - #]===================================================================] - # currently use ubuntu 16.04 as a base b/c it has one of - # the lower versions of libc among ubuntu and debian releases. - # we could change this in the future and build with some other deb - # based system. - add_custom_target (dpkg_container - docker build - --pull - --build-arg DIST_TAG=16.04 - --build-arg GIT_COMMIT=${commit_hash} - -t rippled-dpkg-builder:${container_label} - $<$:--cache-from=${dpkg_cache_from}> - -f ubuntu-builder/Dockerfile . - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Builds/containers - VERBATIM - USES_TERMINAL - COMMAND_EXPAND_LISTS - SOURCES - Builds/containers/ubuntu-builder/Dockerfile - Builds/containers/ubuntu-builder/ubuntu_setup.sh - Builds/containers/shared/build_deps.sh - Builds/containers/shared/rippled.service - Builds/containers/shared/update_sources.sh - Builds/containers/shared/update-rippled.sh - Builds/containers/packaging/dpkg/build_dpkg.sh - Builds/containers/packaging/dpkg/debian/README.Debian - Builds/containers/packaging/dpkg/debian/conffiles - Builds/containers/packaging/dpkg/debian/control - Builds/containers/packaging/dpkg/debian/copyright - Builds/containers/packaging/dpkg/debian/dirs - Builds/containers/packaging/dpkg/debian/docs - Builds/containers/packaging/dpkg/debian/rippled-dev.install - Builds/containers/packaging/dpkg/debian/rippled.install - Builds/containers/packaging/dpkg/debian/rippled.links - Builds/containers/packaging/dpkg/debian/rippled.postinst - Builds/containers/packaging/dpkg/debian/rippled.postrm - Builds/containers/packaging/dpkg/debian/rippled.preinst - Builds/containers/packaging/dpkg/debian/rippled.prerm - Builds/containers/packaging/dpkg/debian/rules - ) - exclude_from_default (dpkg_container) - add_custom_target (dpkg - docker run - -e NIH_CACHE_ROOT=/opt/rippled_bld/pkg/.nih_c - -v ${NIH_CACHE_ROOT}/pkgbuild:/opt/rippled_bld/pkg/.nih_c - -v ${CMAKE_SOURCE_DIR}:/opt/rippled_bld/pkg/rippled - -v ${CMAKE_CURRENT_BINARY_DIR}/packages:/opt/rippled_bld/pkg/out - "$<$:--volume=/etc/passwd:/etc/passwd;--volume=/etc/group:/etc/group;--user=${DOCKER_USER_ID}:${DOCKER_GROUP_ID}>" - -t rippled-dpkg-builder:${container_label} - VERBATIM - USES_TERMINAL - COMMAND_EXPAND_LISTS - SOURCES - Builds/containers/packaging/dpkg/debian/control - ) - exclude_from_default (dpkg) - if (NOT have_package_container) - add_dependencies(dpkg dpkg_container) - endif () - #[===================================================================[ - ci container - #]===================================================================] - # now use the same ubuntu image for our travis-ci docker images, - # but we use a newer distro (18.04 vs 16.04). - # - # steps for publishing a new CI image when you make changes: - # - # mkdir bld.ci && cd bld.ci && cmake -Dpackages_only=ON -Dcontainer_label=CI_LATEST - # cmake --build . --target ci_container --verbose - # docker tag rippled-ci-builder:CI_LATEST /rippled-ci-builder:YYYY-MM-DD - # (change YYYY-MM-DD to match current date..or use a different - # tag/label scheme if you prefer) - # docker push /rippled-ci-builder:YYYY-MM-DD - # - # ...then change the DOCKER_IMAGE line in .travis.yml : - # - DOCKER_IMAGE="/rippled-ci-builder:YYYY-MM-DD" - add_custom_target (ci_container - docker build - --pull - --build-arg DIST_TAG=18.04 - --build-arg GIT_COMMIT=${commit_hash} - --build-arg CI_USE=true - -t rippled-ci-builder:${container_label} - $<$:--cache-from=${ci_cache_from}> - -f ubuntu-builder/Dockerfile . - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Builds/containers - VERBATIM - USES_TERMINAL - COMMAND_EXPAND_LISTS - SOURCES - Builds/containers/ubuntu-builder/Dockerfile - Builds/containers/ubuntu-builder/ubuntu_setup.sh - Builds/containers/shared/build_deps.sh - Builds/containers/shared/rippled.service - Builds/containers/shared/update_sources.sh - Builds/containers/shared/update-rippled.sh - ) - exclude_from_default (ci_container) - else () - message (STATUS "docker NOT found -- won't be able to build containers for packaging") - endif () -endif () - diff --git a/Builds/CMake/RippledSettings.cmake b/Builds/CMake/RippledSettings.cmake deleted file mode 100644 index edfdab9cf8d..00000000000 --- a/Builds/CMake/RippledSettings.cmake +++ /dev/null @@ -1,116 +0,0 @@ -#[===================================================================[ - declare user options/settings -#]===================================================================] - -option (assert "Enables asserts, even in release builds" OFF) -option (unity "Creates a build based on unity sources. This is the default" ON) -if (is_gcc OR is_clang) - option (coverage "Generates coverage info." OFF) - option (profile "Add profiling flags" OFF) - set (coverage_test "" CACHE STRING - "On gcc & clang, the specific unit test(s) to run for coverage. Default is all tests.") - if (coverage_test AND NOT coverage) - set (coverage ON CACHE BOOL "gcc/clang only" FORCE) - endif () - option (coverage_core_only - "Include only src/ripple files when generating coverage report. \ - Set to OFF to include all sources in coverage report." - ON) - option (wextra "compile with extra gcc/clang warnings enabled" ON) -else () - set (profile OFF CACHE BOOL "gcc/clang only" FORCE) - set (coverage OFF CACHE BOOL "gcc/clang only" FORCE) - set (wextra OFF CACHE BOOL "gcc/clang only" FORCE) -endif () -if (is_linux) - option (BUILD_SHARED_LIBS "build shared ripple libraries" OFF) - option (static "link protobuf, openssl, libc++, and boost statically" ON) - option (perf "Enables flags that assist with perf recording" OFF) - option (use_gold "enables detection of gold (binutils) linker" ON) -else () - # we are not ready to allow shared-libs on windows because it would require - # export declarations. On macos it's more feasible, but static openssl - # produces odd linker errors, thus we disable shared lib builds for now. - set (BUILD_SHARED_LIBS OFF CACHE BOOL "build shared ripple libraries - OFF for win/macos" FORCE) - set (static ON CACHE BOOL "static link, linux only. ON for WIN/macos" FORCE) - set (perf OFF CACHE BOOL "perf flags, linux only" FORCE) - set (use_gold OFF CACHE BOOL "gold linker, linux only" FORCE) -endif () -if (is_clang) - option (use_lld "enables detection of lld linker" ON) -else () - set (use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE) -endif () -option (jemalloc "Enables jemalloc for heap profiling" OFF) -option (werr "treat warnings as errors" OFF) -option (local_protobuf - "Force use of a local build of protobuf instead of system version." OFF) - -# this one is a string and therefore can't be an option -set (san "" CACHE STRING "On gcc & clang, add sanitizer instrumentation") -set_property (CACHE san PROPERTY STRINGS ";undefined;memory;address;thread") -if (san) - string (TOLOWER ${san} san) - set (SAN_FLAG "-fsanitize=${san}") - set (SAN_LIB "") - if (is_gcc) - if (san STREQUAL "address") - set (SAN_LIB "asan") - elseif (san STREQUAL "thread") - set (SAN_LIB "tsan") - elseif (san STREQUAL "memory") - set (SAN_LIB "msan") - elseif (san STREQUAL "undefined") - set (SAN_LIB "ubsan") - endif () - endif () - set (_saved_CRL ${CMAKE_REQUIRED_LIBRARIES}) - set (CMAKE_REQUIRED_LIBRARIES "${SAN_FLAG};${SAN_LIB}") - check_cxx_compiler_flag (${SAN_FLAG} COMPILER_SUPPORTS_SAN) - set (CMAKE_REQUIRED_LIBRARIES ${_saved_CRL}) - if (NOT COMPILER_SUPPORTS_SAN) - message (FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler") - endif () -endif () -set (container_label "" CACHE STRING "tag to use for package building containers") -option (packages_only - "ONLY generate package building targets. This is special use-case and almost \ - certainly not what you want. Use with caution as you won't be able to build \ - any compiled targets locally." OFF) -option (have_package_container - "Sometimes you already have the tagged container you want to use for package \ - building and you don't want docker to rebuild it. This flag will detach the \ - dependency of the package build from the container build. It's an advanced \ - use case and most likely you should not be touching this flag." OFF) - -# the remaining options are obscure and rarely used -option (beast_no_unit_test_inline - "Prevents unit test definitions from being inserted into global table" - OFF) -# NOTE - THIS OPTION CURRENTLY DOES NOT COMPILE : -# TODO: fix or remove -option (verify_nodeobject_keys - "This verifies that the hash of node objects matches the payload. \ - This check is expensive - use with caution." - OFF) -option (single_io_service_thread - "Restricts the number of threads calling io_service::run to one. \ - This can be useful when debugging." - OFF) -option (boost_show_deprecated - "Allow boost to fail on deprecated usage. Only useful if you're trying\ - to find deprecated calls." - OFF) -option (beast_hashers - "Use local implementations for sha/ripemd hashes (experimental, not recommended)" - OFF) - -if (WIN32) - option (beast_disable_autolink "Disables autolinking of system libraries on WIN32" OFF) -else () - set (beast_disable_autolink OFF CACHE BOOL "WIN32 only" FORCE) -endif () -if (coverage) - message (STATUS "coverage build requested - forcing Debug build") - set (CMAKE_BUILD_TYPE Debug CACHE STRING "build type" FORCE) -endif () diff --git a/Builds/CMake/RippledValidatorKeys.cmake b/Builds/CMake/RippledValidatorKeys.cmake deleted file mode 100644 index 2cf71f22365..00000000000 --- a/Builds/CMake/RippledValidatorKeys.cmake +++ /dev/null @@ -1,24 +0,0 @@ -option (validator_keys "Enables building of validator-keys-tool as a separate target (imported via FetchContent)" OFF) - -if (validator_keys AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.11) - git_branch (current_branch) - # default to tracking VK develop branch unless we are on master/release - if (NOT (current_branch STREQUAL "master" OR current_branch STREQUAL "release")) - set (current_branch "develop") - endif () - message (STATUS "tracking ValidatorKeys branch: ${current_branch}") - - FetchContent_Declare ( - validator_keys_src - GIT_REPOSITORY https://github.com/ripple/validator-keys-tool.git - GIT_TAG "${current_branch}" - ) - FetchContent_GetProperties (validator_keys_src) - if (NOT validator_keys_src_POPULATED) - message (STATUS "Pausing to download ValidatorKeys...") - FetchContent_Populate (validator_keys_src) - endif () - add_subdirectory (${validator_keys_src_SOURCE_DIR} ${CMAKE_BINARY_DIR}/validator-keys) -endif () - - diff --git a/Builds/CMake/RippledVersion.cmake b/Builds/CMake/RippledVersion.cmake deleted file mode 100644 index 936852af58b..00000000000 --- a/Builds/CMake/RippledVersion.cmake +++ /dev/null @@ -1,15 +0,0 @@ -#[===================================================================[ - read version from source -#]===================================================================] - -file (STRINGS src/ripple/protocol/impl/BuildInfo.cpp BUILD_INFO) -foreach (line_ ${BUILD_INFO}) - if (line_ MATCHES "versionString[ ]*=[ ]*\"(.+)\"") - set (rippled_version ${CMAKE_MATCH_1}) - endif () -endforeach () -if (rippled_version) - message (STATUS "rippled version: ${rippled_version}") -else () - message (FATAL_ERROR "unable to determine rippled version") -endif () diff --git a/Builds/CMake/deps/Boost.cmake b/Builds/CMake/deps/Boost.cmake deleted file mode 100644 index d8ab0366e6a..00000000000 --- a/Builds/CMake/deps/Boost.cmake +++ /dev/null @@ -1,92 +0,0 @@ -#[===================================================================[ - NIH dep: boost -#]===================================================================] - -if ((NOT DEFINED BOOST_ROOT) AND (DEFINED ENV{BOOST_ROOT})) - set (BOOST_ROOT $ENV{BOOST_ROOT}) -endif () -file (TO_CMAKE_PATH "${BOOST_ROOT}" BOOST_ROOT) -if (WIN32 OR CYGWIN) - # Workaround for MSVC having two boost versions - x86 and x64 on same PC in stage folders - if (DEFINED BOOST_ROOT) - if (IS_DIRECTORY ${BOOST_ROOT}/stage64/lib) - set (BOOST_LIBRARYDIR ${BOOST_ROOT}/stage64/lib) - else () - set (BOOST_LIBRARYDIR ${BOOST_ROOT}/stage/lib) - endif () - endif () -endif () -message (STATUS "BOOST_ROOT: ${BOOST_ROOT}") -message (STATUS "BOOST_LIBRARYDIR: ${BOOST_LIBRARYDIR}") - -# uncomment the following as needed to debug FindBoost issues: -#set (Boost_DEBUG ON) - -#[=========================================================[ - boost dynamic libraries don't trivially support @rpath - linking right now (cmake's default), so just force - static linking for macos, or if requested on linux by flag -#]=========================================================] -if (static) - set (Boost_USE_STATIC_LIBS ON) -endif () -set (Boost_USE_MULTITHREADED ON) -if (static AND NOT APPLE) - set (Boost_USE_STATIC_RUNTIME ON) -else () - set (Boost_USE_STATIC_RUNTIME OFF) -endif () -find_package (Boost 1.70 REQUIRED - COMPONENTS - chrono - context - coroutine - date_time - filesystem - program_options - regex - serialization - system - thread) - -add_library (ripple_boost INTERFACE) -add_library (Ripple::boost ALIAS ripple_boost) -if (is_xcode) - target_include_directories (ripple_boost BEFORE INTERFACE ${Boost_INCLUDE_DIRS}) - target_compile_options (ripple_boost INTERFACE --system-header-prefix="boost/") -else () - target_include_directories (ripple_boost SYSTEM BEFORE INTERFACE ${Boost_INCLUDE_DIRS}) -endif() - -target_link_libraries (ripple_boost - INTERFACE - Boost::boost - Boost::chrono - Boost::coroutine - Boost::date_time - Boost::filesystem - Boost::program_options - Boost::regex - Boost::serialization - Boost::system - Boost::thread) -if (san) - if (NOT Boost_INCLUDE_DIRS AND TARGET Boost::headers) - get_target_property (Boost_INCLUDE_DIRS Boost::headers INTERFACE_INCLUDE_DIRECTORIES) - endif () - message(STATUS "Adding [${Boost_INCLUDE_DIRS}] to sanitizer blacklist") - file (WRITE ${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt "src:${Boost_INCLUDE_DIRS}/*") - target_compile_options (opts - INTERFACE - # ignore boost headers for sanitizing - -fsanitize-blacklist=${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt) -endif () - -# workaround for xcode 10.2 and boost < 1.69 -# once we require Boost 1.69 or higher, this can be removed -# see: https://github.com/boostorg/asio/commit/43874d5 -if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND - CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.1.10010043 AND - Boost_VERSION LESS 106900) - target_compile_definitions (opts INTERFACE BOOST_ASIO_HAS_STD_STRING_VIEW) -endif () diff --git a/Builds/CMake/deps/Ed25519-donna.cmake b/Builds/CMake/deps/Ed25519-donna.cmake deleted file mode 100644 index 7f352423fdc..00000000000 --- a/Builds/CMake/deps/Ed25519-donna.cmake +++ /dev/null @@ -1,28 +0,0 @@ -#[===================================================================[ - NIH dep: ed25519-donna -#]===================================================================] - -add_library (ed25519-donna STATIC - src/ed25519-donna/ed25519.c) -target_include_directories (ed25519-donna - PUBLIC - $ - $ - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src/ed25519-donna) -#[=========================================================[ - NOTE for macos: - https://github.com/floodyberry/ed25519-donna/issues/29 - our source for ed25519-donna-portable.h has been - patched to workaround this. -#]=========================================================] -target_link_libraries (ed25519-donna PUBLIC OpenSSL::SSL) -add_library (NIH::ed25519-donna ALIAS ed25519-donna) -target_link_libraries (ripple_libs INTERFACE NIH::ed25519-donna) -#[===========================[ - headers installation -#]===========================] -install ( - FILES - src/ed25519-donna/ed25519.h - DESTINATION include/ed25519-donna) diff --git a/Builds/CMake/deps/Findlibarchive.cmake b/Builds/CMake/deps/Findlibarchive.cmake deleted file mode 100644 index ddf526f323a..00000000000 --- a/Builds/CMake/deps/Findlibarchive.cmake +++ /dev/null @@ -1,23 +0,0 @@ -find_package (PkgConfig REQUIRED) -pkg_search_module (libarchive_PC QUIET libarchive>=3.3.3) - -if(static) - set(LIBARCHIVE_LIB libarchive.a) -else() - set(LIBARCHIVE_LIB archive) -endif() - - -find_library (archive - NAMES ${LIBARCHIVE_LIB} - HINTS - ${libarchive_PC_LIBDIR} - ${libarchive_PC_LIBRARY_DIRS} - NO_DEFAULT_PATH) - -find_path (LIBARCHIVE_INCLUDE_DIR - NAMES archive.h - HINTS - ${libarchive_PC_INCLUDEDIR} - ${libarchive_PC_INCLUDEDIRS} - NO_DEFAULT_PATH) diff --git a/Builds/CMake/deps/Findlz4.cmake b/Builds/CMake/deps/Findlz4.cmake deleted file mode 100644 index c5ee2d9797b..00000000000 --- a/Builds/CMake/deps/Findlz4.cmake +++ /dev/null @@ -1,22 +0,0 @@ -find_package (PkgConfig REQUIRED) -pkg_search_module (lz4_PC QUIET liblz4>=1.8) - -if(static) - set(LZ4_LIB liblz4.a) -else() - set(LZ4_LIB lz4.so) -endif() - -find_library (lz4 - NAMES ${LZ4_LIB} - HINTS - ${lz4_PC_LIBDIR} - ${lz4_PC_LIBRARY_DIRS} - NO_DEFAULT_PATH) - -find_path (LZ4_INCLUDE_DIR - NAMES lz4.h - HINTS - ${lz4_PC_INCLUDEDIR} - ${lz4_PC_INCLUDEDIRS} - NO_DEFAULT_PATH) diff --git a/Builds/CMake/deps/Findsecp256k1.cmake b/Builds/CMake/deps/Findsecp256k1.cmake deleted file mode 100644 index f8caf0cd0ee..00000000000 --- a/Builds/CMake/deps/Findsecp256k1.cmake +++ /dev/null @@ -1,22 +0,0 @@ -find_package (PkgConfig REQUIRED) -pkg_search_module (secp256k1_PC QUIET libsecp256k1) - -if(static) - set(SECP256K1_LIB libsecp256k1.a) -else() - set(SECP256K1_LIB secp256k1) -endif() - -find_library(secp256k1 - NAMES ${SECP256K1_LIB} - HINTS - ${secp256k1_PC_LIBDIR} - ${secp256k1_PC_LIBRARY_PATHS} - NO_DEFAULT_PATH) - -find_path (SECP256K1_INCLUDE_DIR - NAMES secp256k1.h - HINTS - ${secp256k1_PC_INCLUDEDIR} - ${secp256k1_PC_INCLUDEDIRS} - NO_DEFAULT_PATH) diff --git a/Builds/CMake/deps/Findsnappy.cmake b/Builds/CMake/deps/Findsnappy.cmake deleted file mode 100644 index 1292b3e4acb..00000000000 --- a/Builds/CMake/deps/Findsnappy.cmake +++ /dev/null @@ -1,22 +0,0 @@ -find_package (PkgConfig REQUIRED) -pkg_search_module (snappy_PC QUIET snappy>=1.1.7) - -if(static) - set(SNAPPY_LIB libsnappy.a) -else() - set(SNAPPY_LIB libsnappy.so) -endif() - -find_library (snappy - NAMES ${SNAPPY_LIB} - HINTS - ${snappy_PC_LIBDIR} - ${snappy_PC_LIBRARY_DIRS} - NO_DEFAULT_PATH) - -find_path (SNAPPY_INCLUDE_DIR - NAMES snappy.h - HINTS - ${snappy_PC_INCLUDEDIR} - ${snappy_PC_INCLUDEDIRS} - NO_DEFAULT_PATH) diff --git a/Builds/CMake/deps/Findsoci.cmake b/Builds/CMake/deps/Findsoci.cmake deleted file mode 100644 index 5215a977eb5..00000000000 --- a/Builds/CMake/deps/Findsoci.cmake +++ /dev/null @@ -1,16 +0,0 @@ -find_package (PkgConfig REQUIRED) - -# no soci pkgconfig -#pkg_search_module (soci_PC QUIET libsoci_core>=3.2) - -if(static) - set(SOCI_LIB libsoci.a) -else() - set(SOCI_LIB libsoci_core.so) -endif() - -find_library (soci - NAMES ${SOCI_LIB}) - -find_path (SOCI_INCLUDE_DIR - NAMES soci/soci.h) diff --git a/Builds/CMake/deps/Findsqlite.cmake b/Builds/CMake/deps/Findsqlite.cmake deleted file mode 100644 index 377f4555b3d..00000000000 --- a/Builds/CMake/deps/Findsqlite.cmake +++ /dev/null @@ -1,22 +0,0 @@ -find_package (PkgConfig REQUIRED) -pkg_search_module (sqlite_PC QUIET sqlite3>=3.26.0) - -if(static) - set(SQLITE_LIB libsqlite3.a) -else() - set(SQLITE_LIB sqlite3.so) -endif() - -find_library (sqlite3 - NAMES ${SQLITE_LIB} - HINTS - ${sqlite_PC_LIBDIR} - ${sqlite_PC_LIBRARY_DIRS} - NO_DEFAULT_PATH) - -find_path (SQLITE_INCLUDE_DIR - NAMES sqlite3.h - HINTS - ${sqlite_PC_INCLUDEDIR} - ${sqlite_PC_INCLUDEDIRS} - NO_DEFAULT_PATH) diff --git a/Builds/CMake/deps/Libarchive.cmake b/Builds/CMake/deps/Libarchive.cmake deleted file mode 100644 index e95589fd3d6..00000000000 --- a/Builds/CMake/deps/Libarchive.cmake +++ /dev/null @@ -1,118 +0,0 @@ -#[===================================================================[ - NIH dep: libarchive -#]===================================================================] - -add_library (archive_lib STATIC IMPORTED GLOBAL) - -if (NOT WIN32) - find_package(libarchive REQUIRED) -endif() - -if(libarchive) - set_target_properties (archive_lib PROPERTIES - IMPORTED_LOCATION_DEBUG - ${archive} - IMPORTED_LOCATION_RELEASE - ${archive} - INTERFACE_INCLUDE_DIRECTORIES - ${LIBARCHIVE_INCLUDE_DIR}) - -else() - set (lib_post "") - if (MSVC) - set (lib_post "_static") - endif () - ExternalProject_Add (libarchive - PREFIX ${nih_cache_path} - GIT_REPOSITORY https://github.com/libarchive/libarchive.git - GIT_TAG v3.3.3 - CMAKE_ARGS - # passing the compiler seems to be needed for windows CI, sadly - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - $<$:-DCMAKE_VERBOSE_MAKEFILE=ON> - -DCMAKE_DEBUG_POSTFIX=_d - $<$>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}> - -DENABLE_LZ4=ON - -ULZ4_* - -DLZ4_INCLUDE_DIR=$,::> - # because we are building a static lib, this lz4 library doesn't - # actually matter since you can't generally link static libs to other static - # libs. The include files are needed, but the library itself is not (until - # we link our application, at which point we use the lz4 we built above). - # nonetheless, we need to provide a library to libarchive else it will - # NOT include lz4 support when configuring - -DLZ4_LIBRARY=$,$,$> - -DENABLE_WERROR=OFF - -DENABLE_TAR=OFF - -DENABLE_TAR_SHARED=OFF - -DENABLE_INSTALL=ON - -DENABLE_NETTLE=OFF - -DENABLE_OPENSSL=OFF - -DENABLE_LZO=OFF - -DENABLE_LZMA=OFF - -DENABLE_ZLIB=OFF - -DENABLE_BZip2=OFF - -DENABLE_LIBXML2=OFF - -DENABLE_EXPAT=OFF - -DENABLE_PCREPOSIX=OFF - -DENABLE_LibGCC=OFF - -DENABLE_CNG=OFF - -DENABLE_CPIO=OFF - -DENABLE_CPIO_SHARED=OFF - -DENABLE_CAT=OFF - -DENABLE_CAT_SHARED=OFF - -DENABLE_XATTR=OFF - -DENABLE_ACL=OFF - -DENABLE_ICONV=OFF - -DENABLE_TEST=OFF - -DENABLE_COVERAGE=OFF - $<$: - "-DCMAKE_C_FLAGS=-GR -Gd -fp:precise -FS -MP" - "-DCMAKE_C_FLAGS_DEBUG=-MTd" - "-DCMAKE_C_FLAGS_RELEASE=-MT" - > - LIST_SEPARATOR :: - LOG_BUILD ON - LOG_CONFIGURE ON - BUILD_COMMAND - ${CMAKE_COMMAND} - --build . - --config $ - --target archive_static - $<$:--parallel ${ep_procs}> - $<$: - COMMAND - ${CMAKE_COMMAND} -E copy - /libarchive/$/${ep_lib_prefix}archive${lib_post}$<$:_d>${ep_lib_suffix} - /libarchive - > - TEST_COMMAND "" - INSTALL_COMMAND "" - DEPENDS lz4_lib - BUILD_BYPRODUCTS - /libarchive/${ep_lib_prefix}archive${lib_post}${ep_lib_suffix} - /libarchive/${ep_lib_prefix}archive${lib_post}_d${ep_lib_suffix} - ) - ExternalProject_Get_Property (libarchive BINARY_DIR) - ExternalProject_Get_Property (libarchive SOURCE_DIR) - if (CMAKE_VERBOSE_MAKEFILE) - print_ep_logs (libarchive) - endif () - file (MAKE_DIRECTORY ${SOURCE_DIR}/libarchive) - set_target_properties (archive_lib PROPERTIES - IMPORTED_LOCATION_DEBUG - ${BINARY_DIR}/libarchive/${ep_lib_prefix}archive${lib_post}_d${ep_lib_suffix} - IMPORTED_LOCATION_RELEASE - ${BINARY_DIR}/libarchive/${ep_lib_prefix}archive${lib_post}${ep_lib_suffix} - INTERFACE_INCLUDE_DIRECTORIES - ${SOURCE_DIR}/libarchive - INTERFACE_COMPILE_DEFINITIONS - LIBARCHIVE_STATIC) -endif() - -add_dependencies (archive_lib libarchive) -target_link_libraries (archive_lib INTERFACE lz4_lib) -target_link_libraries (ripple_libs INTERFACE archive_lib) -exclude_if_included (libarchive) -exclude_if_included (archive_lib) diff --git a/Builds/CMake/deps/Lz4.cmake b/Builds/CMake/deps/Lz4.cmake deleted file mode 100644 index cc3101f1cfc..00000000000 --- a/Builds/CMake/deps/Lz4.cmake +++ /dev/null @@ -1,79 +0,0 @@ -#[===================================================================[ - NIH dep: lz4 -#]===================================================================] - -add_library (lz4_lib STATIC IMPORTED GLOBAL) - -if (NOT WIN32) - find_package(lz4) -endif() - -if(lz4) - set_target_properties (lz4_lib PROPERTIES - IMPORTED_LOCATION_DEBUG - ${lz4} - IMPORTED_LOCATION_RELEASE - ${lz4} - INTERFACE_INCLUDE_DIRECTORIES - ${LZ4_INCLUDE_DIR}) - -else() - ExternalProject_Add (lz4 - PREFIX ${nih_cache_path} - GIT_REPOSITORY https://github.com/lz4/lz4.git - GIT_TAG v1.8.2 - SOURCE_SUBDIR contrib/cmake_unofficial - CMAKE_ARGS - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - $<$:-DCMAKE_VERBOSE_MAKEFILE=ON> - -DCMAKE_DEBUG_POSTFIX=_d - $<$>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}> - -DBUILD_STATIC_LIBS=ON - -DBUILD_SHARED_LIBS=OFF - $<$: - "-DCMAKE_C_FLAGS=-GR -Gd -fp:precise -FS -MP" - "-DCMAKE_C_FLAGS_DEBUG=-MTd" - "-DCMAKE_C_FLAGS_RELEASE=-MT" - > - LOG_BUILD ON - LOG_CONFIGURE ON - BUILD_COMMAND - ${CMAKE_COMMAND} - --build . - --config $ - --target lz4_static - $<$:--parallel ${ep_procs}> - $<$: - COMMAND - ${CMAKE_COMMAND} -E copy - /$/${ep_lib_prefix}lz4$<$:_d>${ep_lib_suffix} - - > - TEST_COMMAND "" - INSTALL_COMMAND "" - BUILD_BYPRODUCTS - /${ep_lib_prefix}lz4${ep_lib_suffix} - /${ep_lib_prefix}lz4_d${ep_lib_suffix} - ) - ExternalProject_Get_Property (lz4 BINARY_DIR) - ExternalProject_Get_Property (lz4 SOURCE_DIR) - - file (MAKE_DIRECTORY ${SOURCE_DIR}/lz4) - set_target_properties (lz4_lib PROPERTIES - IMPORTED_LOCATION_DEBUG - ${BINARY_DIR}/${ep_lib_prefix}lz4_d${ep_lib_suffix} - IMPORTED_LOCATION_RELEASE - ${BINARY_DIR}/${ep_lib_prefix}lz4${ep_lib_suffix} - INTERFACE_INCLUDE_DIRECTORIES - ${SOURCE_DIR}/lib) - - if (CMAKE_VERBOSE_MAKEFILE) - print_ep_logs (lz4) - endif () -endif() - -add_dependencies (lz4_lib lz4) -target_link_libraries (ripple_libs INTERFACE lz4_lib) -exclude_if_included (lz4) -exclude_if_included (lz4_lib) diff --git a/Builds/CMake/deps/Nudb.cmake b/Builds/CMake/deps/Nudb.cmake deleted file mode 100644 index b8b9a73cd9f..00000000000 --- a/Builds/CMake/deps/Nudb.cmake +++ /dev/null @@ -1,47 +0,0 @@ -#[===================================================================[ - NIH dep: nudb - - NuDB is header-only, thus is an INTERFACE lib in CMake. - TODO: move the library definition into NuDB repo and add - proper targets and export/install -#]===================================================================] - -if (is_root_project) # NuDB not needed in the case of xrpl_core inclusion build - add_library (nudb INTERFACE) - if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.11) - FetchContent_Declare( - nudb_src - GIT_REPOSITORY https://github.com/CPPAlliance/NuDB.git - GIT_TAG 2.0.1 - ) - FetchContent_GetProperties(nudb_src) - if(NOT nudb_src_POPULATED) - message (STATUS "Pausing to download NuDB...") - FetchContent_Populate(nudb_src) - endif() - else () - ExternalProject_Add (nudb_src - PREFIX ${nih_cache_path} - GIT_REPOSITORY https://github.com/CPPAlliance/NuDB.git - GIT_TAG 2.0.1 - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - TEST_COMMAND "" - INSTALL_COMMAND "" - ) - ExternalProject_Get_Property (nudb_src SOURCE_DIR) - set (nudb_src_SOURCE_DIR "${SOURCE_DIR}") - file (MAKE_DIRECTORY ${nudb_src_SOURCE_DIR}/include) - add_dependencies (nudb nudb_src) - endif () - - file(TO_CMAKE_PATH "${nudb_src_SOURCE_DIR}" nudb_src_SOURCE_DIR) -# specify as system includes so as to avoid warnings - target_include_directories (nudb SYSTEM INTERFACE ${nudb_src_SOURCE_DIR}/include) - target_link_libraries (nudb - INTERFACE - Boost::thread - Boost::system) - add_library (NIH::nudb ALIAS nudb) - target_link_libraries (ripple_libs INTERFACE NIH::nudb) -endif () diff --git a/Builds/CMake/deps/OpenSSL.cmake b/Builds/CMake/deps/OpenSSL.cmake deleted file mode 100644 index f8761d26269..00000000000 --- a/Builds/CMake/deps/OpenSSL.cmake +++ /dev/null @@ -1,48 +0,0 @@ -#[===================================================================[ - NIH dep: openssl -#]===================================================================] - -#[===============================================[ - OPENSSL_ROOT_DIR is the only variable that - FindOpenSSL honors for locating, so convert any - OPENSSL_ROOT vars to this -#]===============================================] -if (NOT DEFINED OPENSSL_ROOT_DIR) - if (DEFINED ENV{OPENSSL_ROOT}) - set (OPENSSL_ROOT_DIR $ENV{OPENSSL_ROOT}) - elseif (HOMEBREW) - execute_process (COMMAND ${HOMEBREW} --prefix openssl - OUTPUT_VARIABLE OPENSSL_ROOT_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) - endif () - file (TO_CMAKE_PATH "${OPENSSL_ROOT_DIR}" OPENSSL_ROOT_DIR) -endif () - -if (static) - set (OPENSSL_USE_STATIC_LIBS ON) -endif () -set (OPENSSL_MSVC_STATIC_RT ON) -find_package (OpenSSL 1.0.2 REQUIRED) -target_link_libraries (ripple_libs - INTERFACE - OpenSSL::SSL - OpenSSL::Crypto) -# disable SSLv2...this can also be done when building/configuring OpenSSL -set_target_properties(OpenSSL::SSL PROPERTIES - INTERFACE_COMPILE_DEFINITIONS OPENSSL_NO_SSL2) -#[=========================================================[ - https://gitlab.kitware.com/cmake/cmake/issues/16885 - depending on how openssl is built, it might depend - on zlib. In fact, the openssl find package should - figure this out for us, but it does not currently... - so let's add zlib ourselves to the lib list - TODO: investigate linking to static zlib for static - build option -#]=========================================================] -find_package (ZLIB) -set (has_zlib FALSE) -if (TARGET ZLIB::ZLIB) - set_target_properties(OpenSSL::Crypto PROPERTIES - INTERFACE_LINK_LIBRARIES ZLIB::ZLIB) - set (has_zlib TRUE) -endif () diff --git a/Builds/CMake/deps/Protobuf.cmake b/Builds/CMake/deps/Protobuf.cmake deleted file mode 100644 index 4ca55d1fa7f..00000000000 --- a/Builds/CMake/deps/Protobuf.cmake +++ /dev/null @@ -1,124 +0,0 @@ -#[===================================================================[ - import protobuf (lib and compiler) and create a lib - from our proto message definitions. If the system protobuf - is not found, fallback on EP to download and build a version - from official source. -#]===================================================================] - -if (static) - set (Protobuf_USE_STATIC_LIBS ON) -endif () -find_package (Protobuf) -if (local_protobuf OR NOT TARGET protobuf::libprotobuf) - message (STATUS "using local protobuf build.") - if (WIN32) - # protobuf prepends lib even on windows - set (pbuf_lib_pre "lib") - else () - set (pbuf_lib_pre ${ep_lib_prefix}) - endif () - # for the external project build of protobuf, we currently ignore the - # static option and always build static libs here. This is consistent - # with our other EP builds. Dynamic libs in an EP would add complexity - # because we'd need to get them into the runtime path, and probably - # install them. - ExternalProject_Add (protobuf_src - PREFIX ${nih_cache_path} - GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git - GIT_TAG v3.6.1 - SOURCE_SUBDIR cmake - CMAKE_ARGS - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -Dprotobuf_BUILD_TESTS=OFF - -Dprotobuf_BUILD_EXAMPLES=OFF - -Dprotobuf_BUILD_PROTOC_BINARIES=ON - -Dprotobuf_MSVC_STATIC_RUNTIME=ON - -DBUILD_SHARED_LIBS=OFF - -Dprotobuf_BUILD_SHARED_LIBS=OFF - -DCMAKE_DEBUG_POSTFIX=_d - -Dprotobuf_DEBUG_POSTFIX=_d - -Dprotobuf_WITH_ZLIB=$,ON,OFF> - $<$:-DCMAKE_VERBOSE_MAKEFILE=ON> - $<$>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}> - $<$: - "-DCMAKE_CXX_FLAGS=-GR -Gd -fp:precise -FS -EHa -MP" - > - LOG_BUILD ON - LOG_CONFIGURE ON - BUILD_COMMAND - ${CMAKE_COMMAND} - --build . - --config $ - $<$:--parallel ${ep_procs}> - $<$: - COMMAND - ${CMAKE_COMMAND} -E copy - /$/${pbuf_lib_pre}protobuf$<$:_d>${ep_lib_suffix} - - COMMAND - ${CMAKE_COMMAND} -E copy - /$/protoc${CMAKE_EXECUTABLE_SUFFIX} - - > - TEST_COMMAND "" - INSTALL_COMMAND "" - BUILD_BYPRODUCTS - /${pbuf_lib_pre}protobuf${ep_lib_suffix} - /${pbuf_lib_pre}protobuf_d${ep_lib_suffix} - /protoc${CMAKE_EXECUTABLE_SUFFIX} - ) - ExternalProject_Get_Property (protobuf_src BINARY_DIR) - ExternalProject_Get_Property (protobuf_src SOURCE_DIR) - if (CMAKE_VERBOSE_MAKEFILE) - print_ep_logs (protobuf_src) - endif () - - if (NOT TARGET protobuf::libprotobuf) - add_library (protobuf::libprotobuf STATIC IMPORTED GLOBAL) - endif () - file (MAKE_DIRECTORY ${SOURCE_DIR}/src) - set_target_properties (protobuf::libprotobuf PROPERTIES - IMPORTED_LOCATION_DEBUG - ${BINARY_DIR}/${pbuf_lib_pre}protobuf_d${ep_lib_suffix} - IMPORTED_LOCATION_RELEASE - ${BINARY_DIR}/${pbuf_lib_pre}protobuf${ep_lib_suffix} - INTERFACE_INCLUDE_DIRECTORIES - ${SOURCE_DIR}/src) - add_dependencies (protobuf::libprotobuf protobuf_src) - exclude_if_included (protobuf_src) - exclude_if_included (protobuf::libprotobuf) - - if (NOT TARGET protobuf::protoc) - add_executable (protobuf::protoc IMPORTED) - exclude_if_included (protobuf::protoc) - endif () - set_target_properties (protobuf::protoc PROPERTIES - IMPORTED_LOCATION "${BINARY_DIR}/protoc${CMAKE_EXECUTABLE_SUFFIX}") - add_dependencies (protobuf::protoc protobuf_src) -endif () - -file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/proto_gen) -set (save_CBD ${CMAKE_CURRENT_BINARY_DIR}) -set (CMAKE_CURRENT_BINARY_DIR ${CMAKE_BINARY_DIR}/proto_gen) -protobuf_generate_cpp ( - PROTO_SRCS - PROTO_HDRS - src/ripple/proto/ripple.proto) -set (CMAKE_CURRENT_BINARY_DIR ${save_CBD}) - -add_library (pbufs STATIC ${PROTO_SRCS} ${PROTO_HDRS}) - -target_include_directories (pbufs PRIVATE src) -target_include_directories (pbufs - SYSTEM PUBLIC ${CMAKE_BINARY_DIR}/proto_gen) -target_link_libraries (pbufs protobuf::libprotobuf) -target_compile_options (pbufs - PUBLIC - $<$: - --system-header-prefix="google/protobuf" - -Wno-deprecated-dynamic-exception-spec - >) -add_library (Ripple::pbufs ALIAS pbufs) -target_link_libraries (ripple_libs INTERFACE Ripple::pbufs) -exclude_if_included (pbufs) diff --git a/Builds/CMake/deps/Rocksdb.cmake b/Builds/CMake/deps/Rocksdb.cmake deleted file mode 100644 index 5cfebd7d5d2..00000000000 --- a/Builds/CMake/deps/Rocksdb.cmake +++ /dev/null @@ -1,115 +0,0 @@ -#[===================================================================[ - NIH dep: rocksdb -#]===================================================================] - -ExternalProject_Add (rocksdb - PREFIX ${nih_cache_path} - GIT_REPOSITORY https://github.com/facebook/rocksdb.git - GIT_TAG v5.17.2 - PATCH_COMMAND - # only used by windows build - ${CMAKE_COMMAND} -E copy - ${CMAKE_SOURCE_DIR}/Builds/CMake/rocks_thirdparty.inc - /thirdparty.inc - COMMAND - # fixup their build version file to keep the values - # from changing always - ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_SOURCE_DIR}/Builds/CMake/rocksdb_build_version.cc.in - /util/build_version.cc.in - CMAKE_ARGS - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - $<$:-DCMAKE_VERBOSE_MAKEFILE=ON> - -DCMAKE_DEBUG_POSTFIX=_d - $<$>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}> - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DWITH_JEMALLOC=$,ON,OFF> - -DWITH_SNAPPY=ON - -DWITH_LZ4=ON - -DWITH_ZLIB=OFF - -DUSE_RTTI=ON - -DWITH_ZSTD=OFF - -DWITH_GFLAGS=OFF - -DWITH_BZ2=OFF - -ULZ4_* - -DLZ4_INCLUDE_DIR=$,::> - -DLZ4_LIBRARIES=$,$,$> - -DLZ4_FOUND=ON - -USNAPPY_* - -DSNAPPY_INCLUDE_DIR=$,::> - -DSNAPPY_LIBRARIES=$,$,$> - -DSNAPPY_FOUND=ON - -DWITH_MD_LIBRARY=OFF - -DWITH_RUNTIME_DEBUG=$,ON,OFF> - -DFAIL_ON_WARNINGS=OFF - -DWITH_ASAN=OFF - -DWITH_TSAN=OFF - -DWITH_UBSAN=OFF - -DWITH_NUMA=OFF - -DWITH_TBB=OFF - -DWITH_WINDOWS_UTF8_FILENAMES=OFF - -DWITH_XPRESS=OFF - -DPORTABLE=ON - -DFORCE_SSE42=OFF - -DDISABLE_STALL_NOTIF=OFF - -DOPTDBG=ON - -DROCKSDB_LITE=OFF - -DWITH_FALLOCATE=ON - -DWITH_LIBRADOS=OFF - -DWITH_JNI=OFF - -DROCKSDB_INSTALL_ON_WINDOWS=OFF - -DWITH_TESTS=OFF - -DWITH_TOOLS=OFF - $<$: - "-DCMAKE_CXX_FLAGS=-GR -Gd -fp:precise -FS -MP /DNDEBUG" - > - $<$>: - "-DCMAKE_CXX_FLAGS=-DNDEBUG" - > - LOG_BUILD ON - LOG_CONFIGURE ON - BUILD_COMMAND - ${CMAKE_COMMAND} - --build . - --config $ - $<$:--parallel ${ep_procs}> - $<$: - COMMAND - ${CMAKE_COMMAND} -E copy - /$/${ep_lib_prefix}rocksdb$<$:_d>${ep_lib_suffix} - - > - LIST_SEPARATOR :: - TEST_COMMAND "" - INSTALL_COMMAND "" - DEPENDS snappy_lib lz4_lib - BUILD_BYPRODUCTS - /${ep_lib_prefix}rocksdb${ep_lib_suffix} - /${ep_lib_prefix}rocksdb_d${ep_lib_suffix} -) -ExternalProject_Get_Property (rocksdb BINARY_DIR) -ExternalProject_Get_Property (rocksdb SOURCE_DIR) -if (CMAKE_VERBOSE_MAKEFILE) - print_ep_logs (rocksdb) -endif () -add_library (rocksdb_lib STATIC IMPORTED GLOBAL) -file (MAKE_DIRECTORY ${SOURCE_DIR}/include) -set_target_properties (rocksdb_lib PROPERTIES - IMPORTED_LOCATION_DEBUG - ${BINARY_DIR}/${ep_lib_prefix}rocksdb_d${ep_lib_suffix} - IMPORTED_LOCATION_RELEASE - ${BINARY_DIR}/${ep_lib_prefix}rocksdb${ep_lib_suffix} - INTERFACE_INCLUDE_DIRECTORIES - ${SOURCE_DIR}/include - INTERFACE_COMPILE_DEFINITIONS - RIPPLE_ROCKSDB_AVAILABLE=1) -add_dependencies (rocksdb_lib rocksdb) -target_link_libraries (rocksdb_lib INTERFACE snappy_lib lz4_lib) -if (MSVC) - target_link_libraries (rocksdb_lib INTERFACE rpcrt4) -endif () -target_link_libraries (ripple_libs INTERFACE rocksdb_lib) -exclude_if_included (rocksdb) -exclude_if_included (rocksdb_lib) diff --git a/Builds/CMake/deps/Secp256k1.cmake b/Builds/CMake/deps/Secp256k1.cmake deleted file mode 100644 index 944470024cf..00000000000 --- a/Builds/CMake/deps/Secp256k1.cmake +++ /dev/null @@ -1,59 +0,0 @@ -#[===================================================================[ - NIH dep: secp256k1 -#]===================================================================] - -add_library (secp256k1_lib STATIC IMPORTED GLOBAL) - -if (NOT WIN32) - find_package(secp256k1) -endif() - - -if(secp256k1) - set_target_properties (secp256k1_lib PROPERTIES - IMPORTED_LOCATION_DEBUG - ${secp256k1} - IMPORTED_LOCATION_RELEASE - ${secp256k1} - INTERFACE_INCLUDE_DIRECTORIES - ${SECP256K1_INCLUDE_DIR}) - - add_library (secp256k1 ALIAS secp256k1_lib) - add_library (NIH::secp256k1 ALIAS secp256k1_lib) - -else() - set(INSTALL_SECP256K1 true) - - add_library (secp256k1 STATIC - src/secp256k1/src/secp256k1.c) - target_compile_definitions (secp256k1 - PRIVATE - USE_NUM_NONE - USE_FIELD_10X26 - USE_FIELD_INV_BUILTIN - USE_SCALAR_8X32 - USE_SCALAR_INV_BUILTIN) - target_include_directories (secp256k1 - PUBLIC - $ - $ - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/secp256k1) - target_compile_options (secp256k1 - PRIVATE - $<$:-wd4319> - $<$>: - -Wno-deprecated-declarations - -Wno-unused-function - > - $<$:-Wno-nonnull-compare>) - target_link_libraries (ripple_libs INTERFACE NIH::secp256k1) -#[===========================[ - headers installation -#]===========================] - install ( - FILES - src/secp256k1/include/secp256k1.h - DESTINATION include/secp256k1/include) - - add_library (NIH::secp256k1 ALIAS secp256k1) -endif() diff --git a/Builds/CMake/deps/Snappy.cmake b/Builds/CMake/deps/Snappy.cmake deleted file mode 100644 index e31bd28f958..00000000000 --- a/Builds/CMake/deps/Snappy.cmake +++ /dev/null @@ -1,76 +0,0 @@ -#[===================================================================[ - NIH dep: snappy -#]===================================================================] - -add_library (snappy_lib STATIC IMPORTED GLOBAL) - -if (NOT WIN32) - find_package(snappy) -endif() - -if(snappy) - set_target_properties (snappy_lib PROPERTIES - IMPORTED_LOCATION_DEBUG - ${snappy} - IMPORTED_LOCATION_RELEASE - ${snappy} - INTERFACE_INCLUDE_DIRECTORIES - ${SNAPPY_INCLUDE_DIR}) - -else() - ExternalProject_Add (snappy - PREFIX ${nih_cache_path} - GIT_REPOSITORY https://github.com/google/snappy.git - GIT_TAG 1.1.7 - CMAKE_ARGS - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - $<$:-DCMAKE_VERBOSE_MAKEFILE=ON> - -DCMAKE_DEBUG_POSTFIX=_d - $<$>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}> - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DSNAPPY_BUILD_TESTS=OFF - $<$: - "-DCMAKE_CXX_FLAGS=-GR -Gd -fp:precise -FS -EHa -MP" - "-DCMAKE_CXX_FLAGS_DEBUG=-MTd" - "-DCMAKE_CXX_FLAGS_RELEASE=-MT" - > - LOG_BUILD ON - LOG_CONFIGURE ON - BUILD_COMMAND - ${CMAKE_COMMAND} - --build . - --config $ - $<$:--parallel ${ep_procs}> - $<$: - COMMAND - ${CMAKE_COMMAND} -E copy - /$/${ep_lib_prefix}snappy$<$:_d>${ep_lib_suffix} - - > - TEST_COMMAND "" - INSTALL_COMMAND "" - BUILD_BYPRODUCTS - /${ep_lib_prefix}snappy${ep_lib_suffix} - /${ep_lib_prefix}snappy_d${ep_lib_suffix} - ) - ExternalProject_Get_Property (snappy BINARY_DIR) - ExternalProject_Get_Property (snappy SOURCE_DIR) - if (CMAKE_VERBOSE_MAKEFILE) - print_ep_logs (snappy) - endif () - file (MAKE_DIRECTORY ${SOURCE_DIR}/snappy) - set_target_properties (snappy_lib PROPERTIES - IMPORTED_LOCATION_DEBUG - ${BINARY_DIR}/${ep_lib_prefix}snappy_d${ep_lib_suffix} - IMPORTED_LOCATION_RELEASE - ${BINARY_DIR}/${ep_lib_prefix}snappy${ep_lib_suffix} - INTERFACE_INCLUDE_DIRECTORIES - "${SOURCE_DIR};${BINARY_DIR}") -endif() - -add_dependencies (snappy_lib snappy) -target_link_libraries (ripple_libs INTERFACE snappy_lib) -exclude_if_included (snappy) -exclude_if_included (snappy_lib) diff --git a/Builds/CMake/deps/Soci.cmake b/Builds/CMake/deps/Soci.cmake deleted file mode 100644 index 58a7e1adf93..00000000000 --- a/Builds/CMake/deps/Soci.cmake +++ /dev/null @@ -1,146 +0,0 @@ -#[===================================================================[ - NIH dep: soci -#]===================================================================] - -foreach (_comp core empty sqlite3) - add_library ("soci_${_comp}" STATIC IMPORTED GLOBAL) -endforeach () - -if (NOT WIN32) - find_package(soci) -endif() - -if (soci) - foreach (_comp core empty sqlite3) - set_target_properties ("soci_${_comp}" PROPERTIES - IMPORTED_LOCATION_DEBUG - ${soci} - IMPORTED_LOCATION_RELEASE - ${soci} - INTERFACE_INCLUDE_DIRECTORIES - ${SOCI_INCLUDE_DIR}) - endforeach () - -else() - set (soci_lib_pre ${ep_lib_prefix}) - set (soci_lib_post "") - if (WIN32) - # for some reason soci on windows still prepends lib (non-standard) - set (soci_lib_pre lib) - # this version in the name might change if/when we change versions of soci - set (soci_lib_post "_4_0") - endif () - get_target_property (_boost_incs Boost::date_time INTERFACE_INCLUDE_DIRECTORIES) - ExternalProject_Add (soci - PREFIX ${nih_cache_path} - GIT_REPOSITORY https://github.com/SOCI/soci.git - GIT_TAG 04e1870294918d20761736743bb6136314c42dd5 - # We had an issue with soci integer range checking for boost::optional - # and needed to remove the exception that SOCI throws in this case. - # This is *probably* a bug in SOCI, but has never been investigated more - # nor reported to the maintainers. - # This cmake script comments out the lines in question. - # This patch process is likely fragile and should be reviewed carefully - # whenever we update the GIT_TAG above. - PATCH_COMMAND - ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/Builds/CMake/soci_patch.cmake - CMAKE_ARGS - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - $<$:-DCMAKE_VERBOSE_MAKEFILE=ON> - -DCMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}/sqlite3 - -DCMAKE_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/Builds/CMake - -DCMAKE_INCLUDE_PATH=$,::> - -DCMAKE_LIBRARY_PATH=${sqlite_BINARY_DIR} - -DCMAKE_DEBUG_POSTFIX=_d - $<$>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}> - -DSOCI_CXX_C11=ON - -DSOCI_STATIC=ON - -DSOCI_LIBDIR=lib - -DSOCI_SHARED=OFF - -DSOCI_TESTS=OFF - # hack to workaround the fact that soci doesn't currently use - # boost imported targets in its cmake. If they switch to - # proper imported targets, this next line can be removed - # (as well as the get_property above that sets _boost_incs) - -DBoost_INCLUDE_DIRS=$ - -DBOOST_ROOT=${BOOST_ROOT} - -DWITH_BOOST=ON - -DSOCI_DB2=OFF - -DSOCI_FIREBIRD=OFF - -DSOCI_MYSQL=OFF - -DSOCI_ODBC=OFF - -DSOCI_ORACLE=OFF - -DSOCI_POSTGRESQL=OFF - -DSOCI_SQLITE3=ON - -DSQLITE3_INCLUDE_DIR=$,::> - -DSQLITE3_LIBRARY=$,$,$> - $<$:-DCMAKE_FIND_FRAMEWORK=LAST> - $<$: - "-DCMAKE_CXX_FLAGS=-GR -Gd -fp:precise -FS -EHa -MP" - "-DCMAKE_CXX_FLAGS_DEBUG=-MTd" - "-DCMAKE_CXX_FLAGS_RELEASE=-MT" - > - $<$>: - "-DCMAKE_CXX_FLAGS=-Wno-deprecated-declarations" - > - # SEE: https://github.com/SOCI/soci/issues/640 - $<$,$>: - "-DCMAKE_CXX_FLAGS=-Wno-deprecated-declarations -Wno-error=format-overflow -Wno-format-overflow -Wno-error=format-truncation" - > - LIST_SEPARATOR :: - LOG_BUILD ON - LOG_CONFIGURE ON - BUILD_COMMAND - ${CMAKE_COMMAND} - --build . - --config $ - $<$:--parallel ${ep_procs}> - $<$: - COMMAND - ${CMAKE_COMMAND} -E copy - /lib/$/${soci_lib_pre}soci_core${soci_lib_post}$<$:_d>${ep_lib_suffix} - /lib/$/${soci_lib_pre}soci_empty${soci_lib_post}$<$:_d>${ep_lib_suffix} - /lib/$/${soci_lib_pre}soci_sqlite3${soci_lib_post}$<$:_d>${ep_lib_suffix} - /lib - > - TEST_COMMAND "" - INSTALL_COMMAND "" - DEPENDS sqlite - BUILD_BYPRODUCTS - /lib/${soci_lib_pre}soci_core${soci_lib_post}${ep_lib_suffix} - /lib/${soci_lib_pre}soci_core${soci_lib_post}_d${ep_lib_suffix} - /lib/${soci_lib_pre}soci_empty${soci_lib_post}${ep_lib_suffix} - /lib/${soci_lib_pre}soci_empty${soci_lib_post}_d${ep_lib_suffix} - /lib/${soci_lib_pre}soci_sqlite3${soci_lib_post}${ep_lib_suffix} - /lib/${soci_lib_pre}soci_sqlite3${soci_lib_post}_d${ep_lib_suffix} - ) - ExternalProject_Get_Property (soci BINARY_DIR) - ExternalProject_Get_Property (soci SOURCE_DIR) - if (CMAKE_VERBOSE_MAKEFILE) - print_ep_logs (soci) - endif () - file (MAKE_DIRECTORY ${SOURCE_DIR}/include) - file (MAKE_DIRECTORY ${BINARY_DIR}/include) - foreach (_comp core empty sqlite3) - set_target_properties ("soci_${_comp}" PROPERTIES - IMPORTED_LOCATION_DEBUG - ${BINARY_DIR}/lib/${soci_lib_pre}soci_${_comp}${soci_lib_post}_d${ep_lib_suffix} - IMPORTED_LOCATION_RELEASE - ${BINARY_DIR}/lib/${soci_lib_pre}soci_${_comp}${soci_lib_post}${ep_lib_suffix} - INTERFACE_INCLUDE_DIRECTORIES - "${SOURCE_DIR}/include;${BINARY_DIR}/include") - add_dependencies ("soci_${_comp}" soci) # something has to depend on the ExternalProject to trigger it - target_link_libraries (ripple_libs INTERFACE "soci_${_comp}") - if (NOT _comp STREQUAL "core") - target_link_libraries ("soci_${_comp}" INTERFACE soci_core) - endif () - endforeach () -endif() - -foreach (_comp core empty sqlite3) - exclude_if_included ("soci_${_comp}") -endforeach () - - -exclude_if_included (soci) diff --git a/Builds/CMake/deps/Sqlite.cmake b/Builds/CMake/deps/Sqlite.cmake deleted file mode 100644 index be2a7904e97..00000000000 --- a/Builds/CMake/deps/Sqlite.cmake +++ /dev/null @@ -1,87 +0,0 @@ -#[===================================================================[ - NIH dep: sqlite -#]===================================================================] - -add_library (sqlite STATIC IMPORTED GLOBAL) - -if (NOT WIN32) - find_package(sqlite) -endif() - - -if(sqlite3) - set_target_properties (sqlite PROPERTIES - IMPORTED_LOCATION_DEBUG - ${sqlite3} - IMPORTED_LOCATION_RELEASE - ${sqlite3} - INTERFACE_INCLUDE_DIRECTORIES - ${SQLITE_INCLUDE_DIR}) - -else() - ExternalProject_Add (sqlite3 - PREFIX ${nih_cache_path} - # sqlite doesn't use git, but it provides versioned tarballs - URL https://www.sqlite.org/2018/sqlite-amalgamation-3260000.zip - # ^^^ version is apparent in the URL: 3260000 => 3.26.0 - URL_HASH SHA256=de5dcab133aa339a4cf9e97c40aa6062570086d6085d8f9ad7bc6ddf8a52096e - # we wrote a very simple CMake file to build sqlite - # so that's what we copy here so that we can build with - # CMake. sqlite doesn't generally provided a build system - # for the single amalgamation source file. - PATCH_COMMAND - ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_SOURCE_DIR}/Builds/CMake/CMake_sqlite3.txt - /CMakeLists.txt - CMAKE_ARGS - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - $<$:-DCMAKE_VERBOSE_MAKEFILE=ON> - -DCMAKE_DEBUG_POSTFIX=_d - $<$>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}> - $<$: - "-DCMAKE_C_FLAGS=-GR -Gd -fp:precise -FS -MP" - "-DCMAKE_C_FLAGS_DEBUG=-MTd" - "-DCMAKE_C_FLAGS_RELEASE=-MT" - > - LOG_BUILD ON - LOG_CONFIGURE ON - BUILD_COMMAND - ${CMAKE_COMMAND} - --build . - --config $ - $<$:--parallel ${ep_procs}> - $<$: - COMMAND - ${CMAKE_COMMAND} -E copy - /$/${ep_lib_prefix}sqlite3$<$:_d>${ep_lib_suffix} - - > - TEST_COMMAND "" - INSTALL_COMMAND "" - BUILD_BYPRODUCTS - /${ep_lib_prefix}sqlite3${ep_lib_suffix} - /${ep_lib_prefix}sqlite3_d${ep_lib_suffix} - ) - ExternalProject_Get_Property (sqlite3 BINARY_DIR) - ExternalProject_Get_Property (sqlite3 SOURCE_DIR) - if (CMAKE_VERBOSE_MAKEFILE) - print_ep_logs (sqlite3) - endif () - - set_target_properties (sqlite PROPERTIES - IMPORTED_LOCATION_DEBUG - ${BINARY_DIR}/${ep_lib_prefix}sqlite3_d${ep_lib_suffix} - IMPORTED_LOCATION_RELEASE - ${BINARY_DIR}/${ep_lib_prefix}sqlite3${ep_lib_suffix} - INTERFACE_INCLUDE_DIRECTORIES - ${SOURCE_DIR}) - - add_dependencies (sqlite sqlite3) - exclude_if_included (sqlite3) -endif() - -target_link_libraries (sqlite INTERFACE $<$>:dl>) -target_link_libraries (ripple_libs INTERFACE sqlite) -exclude_if_included (sqlite) -set(sqlite_BINARY_DIR ${BINARY_DIR}) diff --git a/Builds/CMake/deps/date.cmake b/Builds/CMake/deps/date.cmake deleted file mode 100644 index 27a2242d945..00000000000 --- a/Builds/CMake/deps/date.cmake +++ /dev/null @@ -1,49 +0,0 @@ -#[===================================================================[ - NIH dep: date - - the main library is header-only, thus is an INTERFACE lib in CMake. - - NOTE: this has been accepted into c++20 so can likely be replaced - when we update to that standard -#]===================================================================] - -find_package (date QUIET) -if (NOT TARGET date::date) - if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.14) - FetchContent_Declare( - hh_date_src - GIT_REPOSITORY https://github.com/HowardHinnant/date.git - GIT_TAG 48f1455cd255df2fe73b5f293b47203ad0988199 - ) - FetchContent_MakeAvailable(hh_date_src) - else () - ExternalProject_Add (hh_date_src - PREFIX ${nih_cache_path} - GIT_REPOSITORY https://github.com/HowardHinnant/date.git - GIT_TAG 48f1455cd255df2fe73b5f293b47203ad0988199 - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - TEST_COMMAND "" - INSTALL_COMMAND "" - ) - ExternalProject_Get_Property (hh_date_src SOURCE_DIR) - set (hh_date_src_SOURCE_DIR "${SOURCE_DIR}") - file (MAKE_DIRECTORY ${hh_date_src_SOURCE_DIR}/include) - add_library (date_interface INTERFACE) - add_library (date::date ALIAS date_interface) - add_dependencies (date_interface hh_date_src) - file (TO_CMAKE_PATH "${hh_date_src_SOURCE_DIR}" hh_date_src_SOURCE_DIR) - target_include_directories (date_interface - SYSTEM INTERFACE - $ - $) - install ( - FILES - ${hh_date_src_SOURCE_DIR}/include/date/date.h - DESTINATION include/date) - install (TARGETS date_interface - EXPORT RippleExports - INCLUDES DESTINATION include) - endif () -endif () - diff --git a/Builds/CMake/echo_file.cmake b/Builds/CMake/echo_file.cmake deleted file mode 100644 index 8a593a7899d..00000000000 --- a/Builds/CMake/echo_file.cmake +++ /dev/null @@ -1,17 +0,0 @@ -#[=========================================================[ - This is a CMake script file that is used to write - the contents of a file to stdout (using the cmake - echo command). The input file is passed via the - IN_FILE variable. -#]=========================================================] - -if (EXISTS ${IN_FILE}) - file (READ ${IN_FILE} contents) - ## only print files that actually have some text in them - if (contents MATCHES "[a-z0-9A-Z]+") - execute_process( - COMMAND - ${CMAKE_COMMAND} -E echo "${contents}") - endif () -endif () - diff --git a/Builds/CMake/rocks_thirdparty.inc b/Builds/CMake/rocks_thirdparty.inc deleted file mode 100644 index 068f98f5506..00000000000 --- a/Builds/CMake/rocks_thirdparty.inc +++ /dev/null @@ -1,16 +0,0 @@ -set (THIRDPARTY_LIBS "") -if(WITH_SNAPPY) - find_package(snappy REQUIRED) - add_definitions(-DSNAPPY) - include_directories(${SNAPPY_INCLUDE_DIR}) - list(APPEND THIRDPARTY_LIBS ${SNAPPY_LIBRARIES}) -endif() - -if(WITH_LZ4) - find_package(lz4 REQUIRED) - add_definitions(-DLZ4) - include_directories(${LZ4_INCLUDE_DIR}) - list(APPEND THIRDPARTY_LIBS ${LZ4_LIBRARIES}) -endif() - - diff --git a/Builds/CMake/rocksdb_build_version.cc.in b/Builds/CMake/rocksdb_build_version.cc.in deleted file mode 100644 index c13c23a6522..00000000000 --- a/Builds/CMake/rocksdb_build_version.cc.in +++ /dev/null @@ -1,4 +0,0 @@ -#include "build_version.h" -const char* rocksdb_build_git_sha = "rocksdb_build_git_sha: N/A"; -const char* rocksdb_build_git_date = "rocksdb_build_git_date: N/A"; -const char* rocksdb_build_compile_date = "N/A"; diff --git a/Builds/CMake/soci_patch.cmake b/Builds/CMake/soci_patch.cmake deleted file mode 100644 index 7cfeaa2e4d1..00000000000 --- a/Builds/CMake/soci_patch.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# This patches unsigned-types.h in the soci official sources -# so as to remove type range check exceptions that cause -# us trouble when using boost::optional to select int values -file (STRINGS include/soci/unsigned-types.h sourcecode) -foreach (line_ ${sourcecode}) - if (line_ MATCHES "^[ \\t]+throw[ ]+soci_error[ ]*\\([ ]*\"Value outside of allowed.+$") - set (line_ "//${CMAKE_MATCH_0}") - endif () - file (APPEND include/soci/unsigned-types.h.patched "${line_}\n") -endforeach () -file (RENAME include/soci/unsigned-types.h include/soci/unsigned-types.h.orig) -file (RENAME include/soci/unsigned-types.h.patched include/soci/unsigned-types.h) - diff --git a/Builds/Test.py b/Builds/Test.py deleted file mode 100755 index f42538d8f42..00000000000 --- a/Builds/Test.py +++ /dev/null @@ -1,397 +0,0 @@ -#!/usr/bin/env python - -# This file is part of rippled: https://github.com/ripple/rippled -# Copyright (c) 2012 - 2017 Ripple Labs Inc. -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -""" -Invocation: - - ./Builds/Test.py - builds and tests all configurations - -The build must succeed without shell aliases for this to work. - -To pass flags to cmake, put them at the very end of the command line, after -the -- flag - like this: - - ./Builds/Test.py -- -j4 # Pass -j4 to cmake --build - - -Common problems: - -1) Boost not found. Solution: export BOOST_ROOT=[path to boost folder] - -2) OpenSSL not found. Solution: export OPENSSL_ROOT=[path to OpenSSL folder] - -3) cmake is not found. Solution: Be sure cmake directory is on your $PATH - -""" -from __future__ import absolute_import, division, print_function, unicode_literals - -import argparse -import itertools -import os -import platform -import re -import shutil -import sys -import subprocess - - -def powerset(iterable): - """powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)""" - s = list(iterable) - return itertools.chain.from_iterable(itertools.combinations(s, r) for r in range(len(s) + 1)) - -IS_WINDOWS = platform.system().lower() == 'windows' -IS_OS_X = platform.system().lower() == 'darwin' - -# CMake -if IS_WINDOWS: - CMAKE_UNITY_CONFIGS = ['Debug', 'Release'] - CMAKE_NONUNITY_CONFIGS = ['Debug', 'Release'] -else: - CMAKE_UNITY_CONFIGS = [] - CMAKE_NONUNITY_CONFIGS = [] -CMAKE_UNITY_COMBOS = { '' : [['rippled'], CMAKE_UNITY_CONFIGS], - '.nounity' : [['rippled'], CMAKE_NONUNITY_CONFIGS] } - -if IS_WINDOWS: - CMAKE_DIR_TARGETS = { ('msvc' + unity,) : targets for unity, targets in - CMAKE_UNITY_COMBOS.items() } -elif IS_OS_X: - CMAKE_DIR_TARGETS = { (build + unity,) : targets - for build in ['debug', 'release'] - for unity, targets in CMAKE_UNITY_COMBOS.items() } -else: - CMAKE_DIR_TARGETS = { (cc + "." + build + unity,) : targets - for cc in ['gcc', 'clang'] - for build in ['debug', 'release', 'coverage', 'profile'] - for unity, targets in CMAKE_UNITY_COMBOS.items() } - -# list of tuples of all possible options -if IS_WINDOWS or IS_OS_X: - CMAKE_ALL_GENERATE_OPTIONS = [tuple(x) for x in powerset(['-GNinja', '-Dassert=true'])] -else: - CMAKE_ALL_GENERATE_OPTIONS = list(set( - [tuple(x) for x in powerset(['-GNinja', '-Dstatic=true', '-Dassert=true', '-Dsan=address'])] + - [tuple(x) for x in powerset(['-GNinja', '-Dstatic=true', '-Dassert=true', '-Dsan=thread'])])) - -parser = argparse.ArgumentParser( - description='Test.py - run ripple tests' -) - -parser.add_argument( - '--all', '-a', - action='store_true', - help='Build all configurations.', -) - -parser.add_argument( - '--keep_going', '-k', - action='store_true', - help='Keep going after one configuration has failed.', -) - -parser.add_argument( - '--silent', '-s', - action='store_true', - help='Silence all messages except errors', -) - -parser.add_argument( - '--verbose', '-v', - action='store_true', - help=('Report more information about which commands are executed and the ' - 'results.'), -) - -parser.add_argument( - '--test', '-t', - default='', - help='Add a prefix for unit tests', -) - -parser.add_argument( - '--testjobs', - default='0', - type=int, - help='Run tests in parallel' -) - -parser.add_argument( - '--ipv6', - action='store_true', - help='Use IPv6 localhost when running unit tests.', -) - -parser.add_argument( - '--clean', '-c', - action='store_true', - help='delete all build artifacts after testing', -) - -parser.add_argument( - '--quiet', '-q', - action='store_true', - help='Reduce output where possible (unit tests)', -) - -parser.add_argument( - '--dir', '-d', - default=(), - nargs='*', - help='Specify one or more CMake dir names. ' - 'Will also be used as -Dtarget= running cmake.' -) - -parser.add_argument( - '--target', - default=(), - nargs='*', - help='Specify one or more CMake build targets. ' - 'Will be used as --target running cmake --build.' - ) - -parser.add_argument( - '--config', - default=(), - nargs='*', - help='Specify one or more CMake build configs. ' - 'Will be used as --config running cmake --build.' - ) - -parser.add_argument( - '--generator_option', - action='append', - help='Specify a CMake generator option. Repeat for multiple options. ' - 'Will be passed to the cmake generator. ' - 'Due to limits of the argument parser, arguments starting with \'-\' ' - 'must be attached to this option. e.g. --generator_option=-GNinja.') - -parser.add_argument( - '--build_option', - action='append', - help='Specify a build option. Repeat for multiple options. ' - 'Will be passed to the build tool via cmake --build. ' - 'Due to limits of the argument parser, arguments starting with \'-\' ' - 'must be attached to this option. e.g. --build_option=-j8.') - -parser.add_argument( - 'extra_args', - default=(), - nargs='*', - help='Extra arguments are passed through to the tools' -) - -ARGS = parser.parse_args() - -def decodeString(line): - # Python 2 vs. Python 3 - if isinstance(line, str): - return line - else: - return line.decode() - -def shell(cmd, args=(), silent=False, cust_env=None): - """"Execute a shell command and return the output.""" - silent = ARGS.silent or silent - verbose = not silent and ARGS.verbose - if verbose: - print('$' + cmd, *args) - - command = (cmd,) + args - - # shell is needed in Windows to find executable in the path - process = subprocess.Popen( - command, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - env=cust_env, - shell=IS_WINDOWS) - lines = [] - count = 0 - # readline returns '' at EOF - for line in iter(process.stdout.readline, ''): - if process.poll() is None: - decoded = decodeString(line) - lines.append(decoded) - if verbose: - print(decoded, end='') - elif not silent: - count += 1 - if count >= 80: - print() - count = 0 - else: - print('.', end='') - else: - break - - if not verbose and count: - print() - process.wait() - return process.returncode, lines - -def get_cmake_dir(cmake_dir): - return os.path.join('build' , 'cmake' , cmake_dir) - -def run_cmake(directory, cmake_dir, args): - print('Generating build in', directory, 'with', *args or ('default options',)) - old_dir = os.getcwd() - if not os.path.exists(directory): - os.makedirs(directory) - os.chdir(directory) - if IS_WINDOWS and not any(arg.startswith("-G") for arg in args) and not os.path.exists("CMakeCache.txt"): - if '--ninja' in args: - args += ( '-GNinja', ) - else: - args += ( '-GVisual Studio 14 2015 Win64', ) - # hack to extract cmake options/args from the legacy target format - if re.search('\.unity', cmake_dir): - args += ( '-Dunity=ON', ) - if re.search('\.nounity', cmake_dir): - args += ( '-Dunity=OFF', ) - if re.search('coverage', cmake_dir): - args += ( '-Dcoverage=ON', ) - if re.search('profile', cmake_dir): - args += ( '-Dprofile=ON', ) - if re.search('debug', cmake_dir): - args += ( '-DCMAKE_BUILD_TYPE=Debug', ) - if re.search('release', cmake_dir): - args += ( '-DCMAKE_BUILD_TYPE=Release', ) - if re.search('gcc', cmake_dir): - args += ( '-DCMAKE_C_COMPILER=gcc', '-DCMAKE_CXX_COMPILER=g++', ) - if re.search('clang', cmake_dir): - args += ( '-DCMAKE_C_COMPILER=clang', '-DCMAKE_CXX_COMPILER=clang++', ) - - args += ( os.path.join('..', '..', '..'), ) - resultcode, lines = shell('cmake', args) - - if resultcode: - print('Generating FAILED:') - if not ARGS.verbose: - print(*lines, sep='') - sys.exit(1) - - os.chdir(old_dir) - -def run_cmake_build(directory, target, config, args): - print('Building', target, config, 'in', directory, 'with', *args or ('default options',)) - build_args=('--build', directory) - if target: - build_args += ('--target', target) - if config: - build_args += ('--config', config) - if args: - build_args += ('--',) - build_args += tuple(args) - resultcode, lines = shell('cmake', build_args) - - if resultcode: - print('Build FAILED:') - if not ARGS.verbose: - print(*lines, sep='') - sys.exit(1) - -def run_cmake_tests(directory, target, config): - failed = [] - if IS_WINDOWS: - target += '.exe' - executable = os.path.join(directory, config if config else 'Debug', target) - if(not os.path.exists(executable)): - executable = os.path.join(directory, target) - print('Unit tests for', executable) - testflag = '--unittest' - quiet = '' - testjobs = '' - ipv6 = '' - if ARGS.test: - testflag += ('=' + ARGS.test) - if ARGS.quiet: - quiet = '-q' - if ARGS.ipv6: - ipv6 = '--unittest-ipv6' - if ARGS.testjobs: - testjobs = ('--unittest-jobs=' + str(ARGS.testjobs)) - resultcode, lines = shell(executable, (testflag, quiet, testjobs, ipv6)) - - if resultcode: - if not ARGS.verbose: - print('ERROR:', *lines, sep='') - failed.append([target, 'unittest']) - - return failed - -def main(): - all_failed = [] - if ARGS.all: - build_dir_targets = CMAKE_DIR_TARGETS - generator_options = CMAKE_ALL_GENERATE_OPTIONS - else: - build_dir_targets = { tuple(ARGS.dir) : [ARGS.target, ARGS.config] } - if ARGS.generator_option: - generator_options = [tuple(ARGS.generator_option)] - else: - generator_options = [tuple()] - - if not build_dir_targets: - # Let CMake choose the build tool. - build_dir_targets = { () : [] } - - if ARGS.build_option: - ARGS.build_option = ARGS.build_option + list(ARGS.extra_args) - else: - ARGS.build_option = list(ARGS.extra_args) - - for args in generator_options: - for build_dirs, (build_targets, build_configs) in build_dir_targets.items(): - if not build_dirs: - build_dirs = ('default',) - if not build_targets: - build_targets = ('rippled',) - if not build_configs: - build_configs = ('',) - for cmake_dir in build_dirs: - cmake_full_dir = get_cmake_dir(cmake_dir) - run_cmake(cmake_full_dir, cmake_dir, args) - - for target in build_targets: - for config in build_configs: - run_cmake_build(cmake_full_dir, target, config, ARGS.build_option) - failed = run_cmake_tests(cmake_full_dir, target, config) - - if failed: - print('FAILED:', *(':'.join(f) for f in failed)) - if not ARGS.keep_going: - sys.exit(1) - else: - all_failed.extend([decodeString(cmake_dir + - "." + target + "." + config), ':'.join(f)] - for f in failed) - else: - print('Success') - if ARGS.clean: - shutil.rmtree(cmake_full_dir) - - if all_failed: - if len(all_failed) > 1: - print() - print('FAILED:', *(':'.join(f) for f in all_failed)) - sys.exit(1) - -if __name__ == '__main__': - main() - sys.exit(0) diff --git a/Builds/VisualStudio2017/CMakeSettings-example.json b/Builds/VisualStudio2017/CMakeSettings-example.json deleted file mode 100644 index b2889ddf504..00000000000 --- a/Builds/VisualStudio2017/CMakeSettings-example.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file. - "configurations": [ - { - "name": "x64-Debug", - "generator": "Visual Studio 15 2017 Win64", - "configurationType": "Debug", - "inheritEnvironments": [ "msvc_x64_x64" ], - "buildRoot": "${thisFileDir}\\build\\${name}", - "cmakeCommandArgs": "", - "buildCommandArgs": "-v:minimal", - "ctestCommandArgs": "", - "variables": [ - { - "name": "BOOST_ROOT", - "value": "C:\\lib\\boost" - }, - { - "name": "OPENSSL_ROOT", - "value": "C:\\lib\\OpenSSL-Win64" - } - ] - }, - { - "name": "x64-Release", - "generator": "Visual Studio 15 2017 Win64", - "configurationType": "Release", - "inheritEnvironments": [ "msvc_x64_x64" ], - "buildRoot": "${thisFileDir}\\build\\${name}", - "cmakeCommandArgs": "", - "buildCommandArgs": "-v:minimal", - "ctestCommandArgs": "", - "variables": [ - { - "name": "BOOST_ROOT", - "value": "C:\\lib\\boost" - }, - { - "name": "OPENSSL_ROOT", - "value": "C:\\lib\\OpenSSL-Win64" - } - ] - } - ] -} diff --git a/Builds/VisualStudio2017/README.md b/Builds/VisualStudio2017/README.md deleted file mode 100644 index e52cf731588..00000000000 --- a/Builds/VisualStudio2017/README.md +++ /dev/null @@ -1,258 +0,0 @@ -# Visual Studio 2017 Build Instructions - -## Important - -We do not recommend Windows for rippled production use at this time. Currently, -the Ubuntu platform has received the highest level of quality assurance, -testing, and support. Additionally, 32-bit Windows versions are not supported. - -## Prerequisites - -To clone the source code repository, create branches for inspection or -modification, build rippled under Visual Studio, and run the unit tests you will -need these software components - -| Component | Minimum Recommended Version | -|-----------|-----------------------| -| [Visual Studio 2017](README.md#install-visual-studio-2017)| 15.5.4 | -| [Git for Windows](README.md#install-git-for-windows)| 2.16.1 | -| [OpenSSL Library](README.md#install-openssl) | 1.0.2n | -| [Boost library](README.md#build-boost) | 1.70.0 | -| [CMake for Windows](README.md#optional-install-cmake-for-windows)* | 3.12 | - -\* Only needed if not using the integrated CMake in VS 2017 and prefer generating dedicated project/solution files. - -## Install Software - -### Install Visual Studio 2017 - -If not already installed on your system, download your choice of installer from -the [Visual Studio 2017 -Download](https://www.visualstudio.com/downloads/download-visual-studio-vs) -page, run the installer, and follow the directions. **You may need to choose the -`Desktop development with C++` workload to install all necessary C++ features.** - -Any version of Visual Studio 2017 may be used to build rippled. The **Visual -Studio 2017 Community** edition is available free of charge (see [the product -page](https://www.visualstudio.com/products/visual-studio-community-vs) for -licensing details), while paid editions may be used for an initial free-trial -period. - -### Install Git for Windows - -Git is a distributed revision control system. The Windows version also provides -the bash shell and many Windows versions of Unix commands. While there are other -varieties of Git (such as TortoiseGit, which has a native Windows interface and -integrates with the Explorer shell), we recommend installing [Git for -Windows](https://git-scm.com/) since it provides a Unix-like command line -environment useful for running shell scripts. Use of the bash shell under -Windows is mandatory for running the unit tests. - -### Install OpenSSL - -[Download OpenSSL.](http://slproweb.com/products/Win32OpenSSL.html) There will -four `Win64` bit variants available, you want the non-light `v1.0` line. As of -this writing, you **should** select - -* Win64 OpenSSL v1.0.2n. - -and should **not** select - -* Win64 OpenSSL v1.0.2n light -* Win64 OpenSSL v1.1.0g -* Win64 OpenSSL v1.1.0g light - -Run the installer, and choose an appropriate location for your OpenSSL -installation. In this guide we use `C:\lib\OpenSSL-Win64` as the destination -location. - -You may be informed on running the installer that "Visual C++ 2008 -Redistributables" must first be installed first. If so, download it from the -[same page](http://slproweb.com/products/Win32OpenSSL.html), again making sure -to get the correct 32-/64-bit variant. - -* NOTE: Since rippled links statically to OpenSSL, it does not matter where the - OpenSSL .DLL files are placed, or what version they are. rippled does not use - or require any external .DLL files to run other than the standard operating - system ones. - -### Build Boost - -Boost 1.70 or later is required. - -After [downloading boost](http://www.boost.org/users/download/) and unpacking it -to `c:\lib`. As of this writing, the most recent version of boost is 1.70.0, -which will unpack into a directory named `boost_1_70_0`. We recommended either -renaming this directory to `boost`, or creating a junction link `mklink /J boost -boost_1_70_0`, so that you can more easily switch between versions. - -Next, open **Developer Command Prompt** and type the following commands - -```powershell -cd C:\lib\boost -bootstrap -``` - -The rippled application is linked statically to the standard runtimes and -external dependencies on Windows, to ensure that the behavior of the executable -is not affected by changes in outside files. Therefore, it is necessary to build -the required boost static libraries using this command: - -```powershell -bjam -j --toolset=msvc-14.1 address-model=64 architecture=x86 link=static threading=multi runtime-link=shared,static stage -``` - -where you should replace `` with the number of parallel -invocations to use build, e.g. `bjam -j4 ...` would use up to 4 concurrent build -shell commands for the build. - -Building the boost libraries may take considerable time. When the build process -is completed, take note of both the reported compiler include paths and linker -library paths as they will be required later. - -### (Optional) Install CMake for Windows - -[CMake](http://cmake.org) is a cross platform build system generator. Visual -Studio 2017 includes an integrated version of CMake that avoids having to -manually run CMake, but it is undergoing continuous improvement. Users that -prefer to use standard Visual Studio project and solution files need to install -a dedicated version of CMake to generate them. The latest version can be found -at the [CMake download site](https://cmake.org/download/). It is recommended you -select the install option to add CMake to your path. - -## Clone the rippled repository - -If you are familiar with cloning github repositories, just follow your normal -process and clone `git@github.com:ripple/rippled.git`. Otherwise follow this -section for instructions. - -1. If you don't have a github account, sign up for one at - [github.com](https://github.com/). -2. Make sure you have Github ssh keys. For help see - [generating-ssh-keys](https://help.github.com/articles/generating-ssh-keys). - -Open the "Git Bash" shell that was installed with "Git for Windows" in the step -above. Navigate to the directory where you want to clone rippled (git bash uses -`/c` for windows's `C:` and forward slash where windows uses backslash, so -`C:\Users\joe\projs` would be `/c/Users/joe/projs` in git bash). Now clone the -repository and optionally switch to the *master* branch. Type the following at -the bash prompt: - -```powershell -git clone git@github.com:ripple/rippled.git -cd rippled -``` -If you receive an error about not having the "correct access rights" make sure -you have Github ssh keys, as described above. - -For a stable release, choose the `master` branch or one of the tagged releases -listed on [rippled's GitHub page](https://github.com/ripple/rippled/releases). - -``` -git checkout master -``` - -To test the latest release candidate, choose the `release` branch. - -``` -git checkout release -``` - -If you are doing development work and want the latest set of untested features, -you can consider using the `develop` branch instead. - -``` -git checkout develop -``` - -# Build using Visual Studio integrated CMake - -In Visual Studio 2017, Microsoft added [integrated IDE support for -cmake](https://blogs.msdn.microsoft.com/vcblog/2016/10/05/cmake-support-in-visual-studio/). -To begin, simply: - -1. Launch Visual Studio and choose **File | Open | Folder**, navigating to the - cloned rippled folder. -2. Right-click on `CMakeLists.txt` in the **Solution Explorer - Folder View** to - generate a `CMakeSettings.json` file. A sample settings file is provided - [here](/Builds/VisualStudio2017/CMakeSettings-example.json). Customize the - settings for `BOOST_ROOT`, `OPENSSL_ROOT` to match the install paths if they - differ from those in the file. -4. Select either the `x64-Release` or `x64-Debug` configuration from the - **Project Setings** drop-down. This should invoke the built-in CMake project - generator. If not, you can right-click on the `CMakeLists.txt` file and - choose **Cache | Generate Cache**. -5. Select either the `rippled.exe` (unity) or `rippled_classic.exe` (non-unity) - option in the **Select Startup Item** drop-down. This will be the target - built when you press F7. Alternatively, you can choose a target to build from - the top-level **CMake | Build** menu. Note that at this time, there are other - targets listed that come from third party visual studio files embedded in the - rippled repo, e.g. `datagen.vcxproj`. Please ignore them. - -For details on configuring debugging sessions or further customization of CMake, -please refer to the [CMake tools for VS -documentation](https://docs.microsoft.com/en-us/cpp/ide/cmake-tools-for-visual-cpp). - -If using the provided `CMakeSettings.json` file, the executable will be in -``` -.\build\x64-Release\Release\rippled.exe -``` -or -``` -.\build\x64-Debug\Debug\rippled.exe -``` -These paths are relative to your cloned git repository. - -# Build using stand-alone CMake - -This requires having installed [CMake for -Windows](README.md#optional-install-cmake-for-windows). We do not recommend -mixing this method with the integrated CMake method for the same repository -clone. Assuming you included the cmake executable folder in your path, -execute the following commands within your `rippled` cloned repository: - -``` -mkdir build\cmake -cd build\cmake -cmake ..\.. -G"Visual Studio 15 2017 Win64" -DBOOST_ROOT="C:\lib\boost_1_70_0" -DOPENSSL_ROOT="C:\lib\OpenSSL-Win64" -``` -Now launch Visual Studio 2017 and select **File | Open | Project/Solution**. -Navigate to the `build\cmake` folder created above and select the `rippled.sln` -file. You can then choose whether to build the `Debug` or `Release` solution -configuration. - -The executable will be in -``` -.\build\cmake\Release\rippled.exe -``` -or -``` -.\build\cmake\Debug\rippled.exe -``` -These paths are relative to your cloned git repository. - -# Unity/No-Unity Builds - -The rippled build system defaults to using [unity source files](http://onqtam.com/programming/2018-07-07-unity-builds/) -to improve build times. In some cases it might be desirable to disable the unity build and compile -individual translation units. Here is how you can switch to a "no-unity" build configuration: - -## Visual Studio Integrated CMake - -Edit your `CmakeSettings.json` (described above) by adding `-Dunity=OFF` to the `cmakeCommandArgs` entry -for each build configuration. - -## Standalone CMake Builds - -When running cmake to generate the Visual Studio project files, add `-Dunity=OFF` to the -command line options passed to cmake. - -**Note:** you will need to re-run the cmake configuration step anytime you want to switch between unity/no-unity builds. - -# Unit Test (Recommended) - -`rippled` builds a set of unit tests into the server executable. To run these -unit tests after building, pass the `--unittest` option to the compiled -`rippled` executable. The executable will exit with summary info after running -the unit tests. - diff --git a/Builds/build_all.sh b/Builds/build_all.sh deleted file mode 100755 index 3a08e3b5a5d..00000000000 --- a/Builds/build_all.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -num_procs=$(lscpu -p | grep -v '^#' | sort -u -t, -k 2,4 | wc -l) # number of physical cores - -path=$(cd $(dirname $0) && pwd) -cd $(dirname $path) -${path}/Test.py -a -c --testjobs=${num_procs} -- -j${num_procs} diff --git a/Builds/containers/README.md b/Builds/containers/README.md deleted file mode 100644 index 9d96eb7719b..00000000000 --- a/Builds/containers/README.md +++ /dev/null @@ -1,31 +0,0 @@ - -# rippled Packaging and Containers - -This folder contains docker container definitions and configuration -files to support building rpm and deb packages of rippled. The container -definitions include some additional software/packages that are used -for general build/test CI workflows of rippled but are not explicitly -needed for the package building workflow. - -## CMake Targets - -If you have docker installed on your local system, then the main -CMake file will enable several targets related to building packages: -`rpm_container`, `rpm`, `dpkg_container`, and `dpkg`. The package targets -depend on the container targets and will trigger a build of those first. -The container builds can take several dozen minutes to complete (depending -on hardware specs), so quick build cycles are not possible currently. As -such, these targets are often best suited to CI/automated build systems. - -The package build can be invoked like any other cmake target from the -rippled root folder: -``` -mkdir -p build/pkg && cd build/pkg -cmake -Dpackages_only=ON ../.. -cmake --build . --target rpm -``` -Upon successful completion, the generated package files will be in -the `build/pkg/packages` directory. For deb packages, simply replace -`rpm` with `dpkg` in the build command above. - - diff --git a/Builds/containers/centos-builder/Dockerfile b/Builds/containers/centos-builder/Dockerfile deleted file mode 100644 index cc2d6bb5ff7..00000000000 --- a/Builds/containers/centos-builder/Dockerfile +++ /dev/null @@ -1,46 +0,0 @@ -FROM centos:7 -ARG GIT_COMMIT=unknown -ARG CI_USE=false - -LABEL git-commit=$GIT_COMMIT - -COPY centos-builder/centos_setup.sh /tmp/ -COPY shared/build_deps.sh /tmp/ -COPY shared/install_cmake.sh /tmp/ -COPY centos-builder/extras.sh /tmp/ -COPY shared/install_boost.sh /tmp/ -RUN chmod +x /tmp/centos_setup.sh && \ - chmod +x /tmp/build_deps.sh && \ - chmod +x /tmp/install_boost.sh && \ - chmod +x /tmp/install_cmake.sh && \ - chmod +x /tmp/extras.sh -RUN /tmp/centos_setup.sh - -RUN /tmp/install_cmake.sh 3.15.2 /opt/local/cmake-3.15 -RUN ln -s /opt/local/cmake-3.15 /opt/local/cmake -ENV PATH="/opt/local/cmake/bin:$PATH" -# also install min supported cmake for testing -RUN if [ "${CI_USE}" = true ] ; then /tmp/install_cmake.sh 3.9.0 /opt/local/cmake-3.9; fi - -RUN source scl_source enable devtoolset-7 python27 && \ - /tmp/build_deps.sh -ENV BOOST_ROOT="/opt/local/boost/_INSTALLED_" -ENV PLANTUML_JAR="/opt/plantuml/plantuml.jar" -ENV OPENSSL_ROOT="/opt/local/openssl" -ENV GDB_ROOT="/opt/local/gdb" -RUN source scl_source enable devtoolset-7 python27 && \ - /tmp/extras.sh - -# prep files for package building -RUN mkdir -m 777 -p /opt/rippled_bld/pkg -WORKDIR /opt/rippled_bld/pkg - -COPY packaging/rpm/rippled.spec ./ -COPY shared/update_sources.sh ./ -RUN mkdir -m 777 ./rpmbuild -RUN mkdir -m 777 ./rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} - -COPY packaging/rpm/build_rpm.sh ./ -CMD ./build_rpm.sh - - diff --git a/Builds/containers/centos-builder/centos_setup.sh b/Builds/containers/centos-builder/centos_setup.sh deleted file mode 100755 index 4a864d436fc..00000000000 --- a/Builds/containers/centos-builder/centos_setup.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -set -ex - -source /etc/os-release - -yum -y upgrade -yum -y update -yum -y install epel-release centos-release-scl -yum -y install \ - wget curl time gcc-c++ time yum-utils \ - libstdc++-static rpm-build gnupg which make cmake \ - devtoolset-7 devtoolset-7-gdb devtoolset-7-libasan-devel devtoolset-7-libtsan-devel devtoolset-7-libubsan-devel \ - devtoolset-8 devtoolset-8-gdb devtoolset-8-binutils devtoolset-8-libstdc++-devel \ - devtoolset-8-libasan-devel devtoolset-8-libtsan-devel devtoolset-8-libubsan-devel devtoolset-8-liblsan-devel \ - flex flex-devel bison bison-devel parallel \ - ncurses ncurses-devel ncurses-libs graphviz graphviz-devel \ - lzip p7zip bzip2 bzip2-devel lzma-sdk lzma-sdk-devel xz-devel \ - zlib zlib-devel zlib-static texinfo openssl openssl-static \ - jemalloc jemalloc-devel \ - libicu-devel htop \ - python27-python rh-python35-python \ - python-devel python27-python-devel rh-python35-python-devel \ - python27 rh-python35 \ - ninja-build git svn \ - protobuf protobuf-static protobuf-c-devel \ - protobuf-compiler protobuf-devel \ - swig perl-Digest-MD5 python2-pip - -if [ "${CI_USE}" = true ] ; then - # TODO need permanent link - yum -y install ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora-secondary/updates/26/i386/Packages/p/python2-six-1.10.0-9.fc26.noarch.rpm - - yum -y install \ - llvm-toolset-7 llvm-toolset-7-runtime llvm-toolset-7-build llvm-toolset-7-clang \ - llvm-toolset-7-clang-analyzer llvm-toolset-7-clang-devel llvm-toolset-7-clang-libs \ - llvm-toolset-7-clang-tools-extra llvm-toolset-7-compiler-rt llvm-toolset-7-lldb \ - llvm-toolset-7-lldb-devel llvm-toolset-7-python-lldb - -fi diff --git a/Builds/containers/centos-builder/extras.sh b/Builds/containers/centos-builder/extras.sh deleted file mode 100755 index b0f4b4c5ffa..00000000000 --- a/Builds/containers/centos-builder/extras.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash -set -ex - -if [ "${CI_USE}" = true ] ; then - cd /tmp - wget https://ftp.gnu.org/gnu/gdb/gdb-8.2.tar.xz - tar xf gdb-8.2.tar.xz - cd gdb-8.2 - ./configure CFLAGS="-w -O2" CXXFLAGS="-std=gnu++11 -g -O2 -w" --prefix=/opt/local/gdb-8.2 - make -j$(nproc) - make install - ln -s /opt/local/gdb-8.2 /opt/local/gdb - cd .. - rm -f gdb-8.2.tar.xz - rm -rf gdb-8.2 - - # clang from source - RELEASE=tags/RELEASE_701/final - INSTALL=/opt/llvm-7.0.1/ - mkdir -p /tmp/clang-src - cd /tmp/clang-src - TOPDIR=`pwd` - svn co -q http://llvm.org/svn/llvm-project/llvm/${RELEASE} llvm - cd ${TOPDIR}/llvm/tools - svn co -q http://llvm.org/svn/llvm-project/cfe/${RELEASE} clang - cd ${TOPDIR}/llvm/tools/clang/tools - svn co -q http://llvm.org/svn/llvm-project/clang-tools-extra/${RELEASE} extra - cd ${TOPDIR}/llvm/tools - svn co -q http://llvm.org/svn/llvm-project/lld/${RELEASE} lld - cd ${TOPDIR}/llvm/tools - svn co -q http://llvm.org/svn/llvm-project/polly/${RELEASE} polly - cd ${TOPDIR}/llvm/projects - svn co -q http://llvm.org/svn/llvm-project/compiler-rt/${RELEASE} compiler-rt - cd ${TOPDIR}/llvm/projects - svn co -q http://llvm.org/svn/llvm-project/openmp/${RELEASE} openmp - cd ${TOPDIR}/llvm/projects - svn co -q http://llvm.org/svn/llvm-project/libcxx/${RELEASE} libcxx - svn co -q http://llvm.org/svn/llvm-project/libcxxabi/${RELEASE} libcxxabi - cd ${TOPDIR}/llvm/projects - ## config/build - cd ${TOPDIR} - mkdir mybuilddir && cd mybuilddir - cmake ../llvm -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=${INSTALL} \ - -DLLVM_LIBDIR_SUFFIX=64 \ - -DLLVM_ENABLE_EH=ON \ - -DLLVM_ENABLE_RTTI=ON - cmake --build . --parallel --target install - cd /tmp - rm -rf clang-src -fi diff --git a/Builds/containers/gitlab-ci/build_container.sh b/Builds/containers/gitlab-ci/build_container.sh deleted file mode 100644 index c5914a0f787..00000000000 --- a/Builds/containers/gitlab-ci/build_container.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env sh -set -ex -pkgtype=$1 -if [ "${pkgtype}" = "rpm" ] ; then - container_name="${RPM_CONTAINER_NAME}" -elif [ "${pkgtype}" = "dpkg" ] ; then - container_name="${DPKG_CONTAINER_NAME}" -else - echo "invalid package type" - exit 1 -fi -if docker pull "${ARTIFACTORY_HUB}/${container_name}:${CI_COMMIT_SHA}"; then - echo "${pkgtype} container for ${CI_COMMIT_SHA} already exists" \ - "- skipping container build!" - exit 0 -else - echo "no existing ${pkgtype} container for this branch - searching history." - for CID_PREV in $(git log --pretty=%H -n30) ; do - if docker pull "${ARTIFACTORY_HUB}/${container_name}:${CID_PREV}"; then - echo "found container for previous commit ${CID_PREV}" \ - "- using as cache." - docker tag \ - "${ARTIFACTORY_HUB}/${container_name}:${CID_PREV}" \ - "${container_name}:${CID_PREV}" - CMAKE_EXTRA="-D${pkgtype}_cache_from=${container_name}:${CID_PREV}" - break - fi - done -fi -cmake --version -test -d build && rm -rf build -mkdir -p build/container && cd build/container -eval time \ - cmake -Dpackages_only=ON -DCMAKE_VERBOSE_MAKEFILE=ON ${CMAKE_EXTRA} \ - -G Ninja ../.. -time cmake --build . --target "${pkgtype}_container" -- -v -docker tag \ - "${container_name}:${CI_COMMIT_SHA}" \ - "${ARTIFACTORY_HUB}/${container_name}:${CI_COMMIT_SHA}" -time docker push "${ARTIFACTORY_HUB}/${container_name}:${CI_COMMIT_SHA}" - diff --git a/Builds/containers/gitlab-ci/build_package.sh b/Builds/containers/gitlab-ci/build_package.sh deleted file mode 100644 index 66e8fc8e9e7..00000000000 --- a/Builds/containers/gitlab-ci/build_package.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env sh -set -ex -pkgtype=$1 -if [ "${pkgtype}" = "rpm" ] ; then - container_name="${RPM_CONTAINER_NAME}" -elif [ "${pkgtype}" = "dpkg" ] ; then - container_name="${DPKG_CONTAINER_NAME}" -else - echo "invalid package type" - exit 1 -fi -time docker pull "${ARTIFACTORY_HUB}/${container_name}:${CI_COMMIT_SHA}" -docker tag \ - "${ARTIFACTORY_HUB}/${container_name}:${CI_COMMIT_SHA}" \ - "${container_name}:${CI_COMMIT_SHA}" -docker images -test -d build && rm -rf build -mkdir -p build/${pkgtype} && cd build/${pkgtype} -time cmake \ - -Dpackages_only=ON -Dhave_package_container=ON -DCMAKE_VERBOSE_MAKEFILE=ON \ - -G Ninja ../.. -time cmake --build . --target ${pkgtype} -- -v - diff --git a/Builds/containers/gitlab-ci/docker_alpine_setup.sh b/Builds/containers/gitlab-ci/docker_alpine_setup.sh deleted file mode 100644 index 43eeed8a914..00000000000 --- a/Builds/containers/gitlab-ci/docker_alpine_setup.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env sh -set -ex -# used as a before/setup script for docker steps in gitlab-ci -# expects to be run in standard alpine/dind image -echo $(nproc) -docker login -u rippled \ - -p ${ARTIFACTORY_DEPLOY_KEY_RIPPLED} ${ARTIFACTORY_HUB} -apk add \ - bash util-linux coreutils binutils grep \ - make ninja cmake build-base gcc g++ abuild git \ - python3 python3-dev -pip3 install awscli -# list curdir contents to build log: -ls -la - diff --git a/Builds/containers/gitlab-ci/get_component.sh b/Builds/containers/gitlab-ci/get_component.sh deleted file mode 100644 index 99963f40864..00000000000 --- a/Builds/containers/gitlab-ci/get_component.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env sh -case ${CI_COMMIT_REF_NAME} in - develop) - export COMPONENT="nightly" - ;; - release) - export COMPONENT="unstable" - ;; - master) - export COMPONENT="stable" - ;; - *) - export COMPONENT="_unknown_" - ;; -esac - diff --git a/Builds/containers/gitlab-ci/pkgbuild.yml b/Builds/containers/gitlab-ci/pkgbuild.yml deleted file mode 100644 index 8e33ec07505..00000000000 --- a/Builds/containers/gitlab-ci/pkgbuild.yml +++ /dev/null @@ -1,623 +0,0 @@ -######################################################################### -## ## -## gitlab CI defintition for rippled build containers and distro ## -## packages (rpm and dpkg). ## -## ## -######################################################################### - -# NOTE: these are sensible defaults for Ripple pipelines. These -# can be overridden by project or group variables as needed. -variables: - RPM_CONTAINER_NAME: "rippled-rpm-builder" - DPKG_CONTAINER_NAME: "rippled-dpkg-builder" - ARTIFACTORY_HOST: "artifactory.ops.ripple.com" - ARTIFACTORY_HUB: "${ARTIFACTORY_HOST}:6555" - GIT_SIGN_PUBKEYS_URL: "https://gitlab.ops.ripple.com/snippets/11/raw" - PUBLIC_REPO_ROOT: "https://repos.ripple.com/repos" - # also need to define this variable ONLY for the primary - # build/publish pipeline on the mainline repo: - # IS_PRIMARY_REPO = "true" - -stages: - - build_containers - - build_packages - - sign_packages - - smoketest - - verify_sig - - tag_images - - push_to_test - - verify_from_test - - wait_approval_prod - - push_to_prod - - verify_from_prod - - get_final_hashes - -.dind_template: &dind_param - before_script: - - . ./Builds/containers/gitlab-ci/docker_alpine_setup.sh - variables: - docker_driver: overlay2 - image: - name: docker:latest - services: - # workaround for TLS issues - consider going back - # back to unversioned `dind` when issues are resolved - - docker:18-dind - tags: - - docker-4xlarge - -.only_primary_template: &only_primary - only: - refs: - - /^(master|release|develop)$/ - variables: - - $IS_PRIMARY_REPO == "true" - -.smoketest_local_template: &run_local_smoketest - tags: - - xlarge - script: - - . ./Builds/containers/gitlab-ci/smoketest.sh local - -.smoketest_repo_template: &run_repo_smoketest - tags: - - xlarge - script: - - . ./Builds/containers/gitlab-ci/smoketest.sh repo - -######################################################################### -## ## -## stage: build_containers ## -## ## -## build containers from docker definitions. These containers are ## -## subsequently used to build the rpm and deb packages. ## -## ## -######################################################################### - -build_centos_container: - stage: build_containers - <<: *dind_param - cache: - key: containers - paths: - - .nih_c - script: - - . ./Builds/containers/gitlab-ci/build_container.sh rpm - -build_ubuntu_container: - stage: build_containers - <<: *dind_param - cache: - key: containers - paths: - - .nih_c - script: - - . ./Builds/containers/gitlab-ci/build_container.sh dpkg - -######################################################################### -## ## -## stage: build_packages ## -## ## -## build packages using containers from previous stage. ## -## ## -######################################################################### - -rpm_build: - stage: build_packages - dependencies: - - build_centos_container - <<: *dind_param - artifacts: - paths: - - build/rpm/packages/ - cache: - key: rpm - paths: - - .nih_c/pkgbuild - script: - - . ./Builds/containers/gitlab-ci/build_package.sh rpm - -dpkg_build: - stage: build_packages - dependencies: - - build_ubuntu_container - <<: *dind_param - artifacts: - paths: - - build/dpkg/packages/ - cache: - key: dpkg - paths: - - .nih_c/pkgbuild - script: - - . ./Builds/containers/gitlab-ci/build_package.sh dpkg - -######################################################################### -## ## -## stage: sign_packages ## -## ## -## build packages using containers from previous stage. ## -## ## -######################################################################### - -rpm_sign: - stage: sign_packages - dependencies: - - rpm_build - image: - name: centos:7 - # <<: *dind_param - before_script: - - | - # Make sure GnuPG is installed - yum -y install gnupg rpm-sign - # checking GPG signing support - if [ -n "$GPG_KEY_B64" ]; then - echo "$GPG_KEY_B64"| base64 -d | gpg --batch --no-tty --allow-secret-key-import --import - - unset GPG_KEY_B64 - export GPG_PASSPHRASE=$(echo $GPG_KEY_PASS_B64 | base64 -di) - unset GPG_KEY_PASS_B64 - export GPG_KEYID=$(gpg --with-colon --list-secret-keys | head -n1 | cut -d : -f 5) - else - echo -e "\033[0;31m****** GPG signing disabled ******\033[0m" - exit 1 - fi - artifacts: - paths: - - build/rpm/packages/ - script: - - ls -alh build/rpm/packages - - . ./Builds/containers/gitlab-ci/sign_package.sh rpm - -dpkg_sign: - stage: sign_packages - dependencies: - - dpkg_build - image: - name: ubuntu:18.04 - # <<: *dind_param - before_script: - - | - # make sure we have GnuPG - apt update - apt install -y gpg dpkg-sig - # checking GPG signing support - if [ -n "$GPG_KEY_B64" ]; then - echo "$GPG_KEY_B64"| base64 -d | gpg --batch --no-tty --allow-secret-key-import --import - - unset GPG_KEY_B64 - export GPG_PASSPHRASE=$(echo $GPG_KEY_PASS_B64 | base64 -di) - unset GPG_KEY_PASS_B64 - export GPG_KEYID=$(gpg --with-colon --list-secret-keys | head -n1 | cut -d : -f 5) - else - echo -e "\033[0;31m****** GPG signing disabled ******\033[0m" - exit 1 - fi - artifacts: - paths: - - build/dpkg/packages/ - script: - - ls -alh build/dpkg/packages - - . ./Builds/containers/gitlab-ci/sign_package.sh dpkg - -######################################################################### -## ## -## stage: smoketest ## -## ## -## install unsigned packages from previous step and run unit tests. ## -## ## -######################################################################### - -centos_7_smoketest: - stage: smoketest - dependencies: - - rpm_sign - image: - name: centos:7 - <<: *run_local_smoketest - -fedora_29_smoketest: - stage: smoketest - dependencies: - - rpm_sign - image: - name: fedora:29 - <<: *run_local_smoketest - -fedora_28_smoketest: - stage: smoketest - dependencies: - - rpm_sign - image: - name: fedora:28 - <<: *run_local_smoketest - -fedora_27_smoketest: - stage: smoketest - dependencies: - - rpm_sign - image: - name: fedora:27 - <<: *run_local_smoketest - -## this one is not LTS, but we -## get some extra coverage by including it -## consider dropping it when 20.04 is ready -ubuntu_19_smoketest: - stage: smoketest - dependencies: - - dpkg_sign - image: - name: ubuntu:19.04 - <<: *run_local_smoketest - -ubuntu_18_smoketest: - stage: smoketest - dependencies: - - dpkg_sign - image: - name: ubuntu:18.04 - <<: *run_local_smoketest - -ubuntu_16_smoketest: - stage: smoketest - dependencies: - - dpkg_sign - image: - name: ubuntu:16.04 - <<: *run_local_smoketest - -debian_9_smoketest: - stage: smoketest - dependencies: - - dpkg_sign - image: - name: debian:9 - <<: *run_local_smoketest - -######################################################################### -## ## -## stage: verify_sig ## -## ## -## use git/gpg to verify that HEAD is signed by an approved ## -## committer. The whitelist of pubkeys is manually mantained ## -## and fetched from GIT_SIGN_PUBKEYS_URL (currently a snippet ## -## link). ## -## ONLY RUNS FOR PRIMARY BRANCHES/REPO ## -## ## -######################################################################### - -verify_head_signed: - stage: verify_sig - image: - name: ubuntu:latest - <<: *only_primary - script: - - . ./Builds/containers/gitlab-ci/verify_head_commit.sh - -######################################################################### -## ## -## stage: tag_images ## -## ## -## apply rippled version tag to containers from previous stage. ## -## ONLY RUNS FOR PRIMARY BRANCHES/REPO ## -## ## -######################################################################### - -tag_bld_images: - stage: tag_images - variables: - docker_driver: overlay2 - image: - name: docker:latest - services: - # workaround for TLS issues - consider going back - # back to unversioned `dind` when issues are resolved - - docker:18-dind - tags: - - docker-large - dependencies: - - rpm_sign - - dpkg_sign - <<: *only_primary - script: - - . ./Builds/containers/gitlab-ci/tag_docker_image.sh - -######################################################################### -## ## -## stage: push_to_test ## -## ## -## push packages to artifactory repositories (test) ## -## ONLY RUNS FOR PRIMARY BRANCHES/REPO ## -## ## -######################################################################### - -push_test: - stage: push_to_test - variables: - DEB_REPO: "rippled-deb-test-mirror" - RPM_REPO: "rippled-rpm-test-mirror" - image: - name: alpine:latest - artifacts: - paths: - - files.info - dependencies: - - rpm_sign - - dpkg_sign - <<: *only_primary - script: - - . ./Builds/containers/gitlab-ci/push_to_artifactory.sh "PUT" "." - -######################################################################### -## ## -## stage: verify_from_test ## -## ## -## install/test packages from test repos. ## -## ONLY RUNS FOR PRIMARY BRANCHES/REPO ## -## ## -######################################################################### - -centos_7_verify_repo_test: - stage: verify_from_test - variables: - RPM_REPO: "rippled-rpm-test-mirror" - image: - name: centos:7 - dependencies: - - rpm_sign - <<: *only_primary - <<: *run_repo_smoketest - -fedora_29_verify_repo_test: - stage: verify_from_test - variables: - RPM_REPO: "rippled-rpm-test-mirror" - image: - name: fedora:29 - dependencies: - - rpm_sign - <<: *only_primary - <<: *run_repo_smoketest - -fedora_28_verify_repo_test: - stage: verify_from_test - variables: - RPM_REPO: "rippled-rpm-test-mirror" - image: - name: fedora:28 - dependencies: - - rpm_sign - <<: *only_primary - <<: *run_repo_smoketest - -fedora_27_verify_repo_test: - stage: verify_from_test - variables: - RPM_REPO: "rippled-rpm-test-mirror" - image: - name: fedora:27 - dependencies: - - rpm_sign - <<: *only_primary - <<: *run_repo_smoketest - -ubuntu_19_verify_repo_test: - stage: verify_from_test - variables: - DISTRO: "disco" - DEB_REPO: "rippled-deb-test-mirror" - image: - name: ubuntu:19.04 - dependencies: - - dpkg_sign - <<: *only_primary - <<: *run_repo_smoketest - -ubuntu_18_verify_repo_test: - stage: verify_from_test - variables: - DISTRO: "bionic" - DEB_REPO: "rippled-deb-test-mirror" - image: - name: ubuntu:18.04 - dependencies: - - dpkg_sign - <<: *only_primary - <<: *run_repo_smoketest - -ubuntu_16_verify_repo_test: - stage: verify_from_test - variables: - DISTRO: "xenial" - DEB_REPO: "rippled-deb-test-mirror" - image: - name: ubuntu:16.04 - dependencies: - - dpkg_sign - <<: *only_primary - <<: *run_repo_smoketest - -debian_9_verify_repo_test: - stage: verify_from_test - variables: - DISTRO: "stretch" - DEB_REPO: "rippled-deb-test-mirror" - image: - name: debian:9 - dependencies: - - dpkg_sign - <<: *only_primary - <<: *run_repo_smoketest - -######################################################################### -## ## -## stage: wait_approval_prod ## -## ## -## wait for manual approval before proceeding to next stage ## -## which pushes to prod repo. ## -## ONLY RUNS FOR PRIMARY BRANCHES/REPO ## -## ## -######################################################################### -wait_before_push_prod: - stage: wait_approval_prod - image: - name: alpine:latest - <<: *only_primary - script: - - echo "proceeding to next stage" - when: manual - allow_failure: false - -######################################################################### -## ## -## stage: push_to_prod ## -## ## -## push packages to artifactory repositories (prod) ## -## ONLY RUNS FOR PRIMARY BRANCHES/REPO ## -## ## -######################################################################### - -push_prod: - variables: - DEB_REPO: "rippled-deb" - RPM_REPO: "rippled-rpm" - image: - name: alpine:latest - stage: push_to_prod - artifacts: - paths: - - files.info - dependencies: - - rpm_sign - - dpkg_sign - <<: *only_primary - script: - - . ./Builds/containers/gitlab-ci/push_to_artifactory.sh "PUT" "." - -######################################################################### -## ## -## stage: verify_from_prod ## -## ## -## install/test packages from prod repos. ## -## ONLY RUNS FOR PRIMARY BRANCHES/REPO ## -## ## -######################################################################### - -centos_7_verify_repo_prod: - stage: verify_from_prod - variables: - RPM_REPO: "rippled-rpm" - image: - name: centos:7 - dependencies: - - rpm_sign - <<: *only_primary - <<: *run_repo_smoketest - -fedora_29_verify_repo_prod: - stage: verify_from_prod - variables: - RPM_REPO: "rippled-rpm" - image: - name: fedora:29 - dependencies: - - rpm_sign - <<: *only_primary - <<: *run_repo_smoketest - -fedora_28_verify_repo_prod: - stage: verify_from_prod - variables: - RPM_REPO: "rippled-rpm" - image: - name: fedora:28 - dependencies: - - rpm_sign - <<: *only_primary - <<: *run_repo_smoketest - -fedora_27_verify_repo_prod: - stage: verify_from_prod - variables: - RPM_REPO: "rippled-rpm" - image: - name: fedora:27 - dependencies: - - rpm_sign - <<: *only_primary - <<: *run_repo_smoketest - -ubuntu_19_verify_repo_prod: - stage: verify_from_prod - variables: - DISTRO: "disco" - DEB_REPO: "rippled-deb" - image: - name: ubuntu:19.04 - dependencies: - - dpkg_sign - <<: *only_primary - <<: *run_repo_smoketest - -ubuntu_18_verify_repo_prod: - stage: verify_from_prod - variables: - DISTRO: "bionic" - DEB_REPO: "rippled-deb" - image: - name: ubuntu:18.04 - dependencies: - - dpkg_sign - <<: *only_primary - <<: *run_repo_smoketest - -ubuntu_16_verify_repo_prod: - stage: verify_from_prod - variables: - DISTRO: "xenial" - DEB_REPO: "rippled-deb" - image: - name: ubuntu:16.04 - dependencies: - - dpkg_sign - <<: *only_primary - <<: *run_repo_smoketest - -debian_9_verify_repo_prod: - stage: verify_from_prod - variables: - DISTRO: "stretch" - DEB_REPO: "rippled-deb" - image: - name: debian:9 - dependencies: - - dpkg_sign - <<: *only_primary - <<: *run_repo_smoketest - -######################################################################### -## ## -## stage: get_final_hashes ## -## ## -## fetch final hashes from artifactory. ## -## ONLY RUNS FOR PRIMARY BRANCHES/REPO ## -## ## -######################################################################### - -get_prod_hashes: - variables: - DEB_REPO: "rippled-deb" - RPM_REPO: "rippled-rpm" - image: - name: alpine:latest - stage: get_final_hashes - artifacts: - paths: - - files.info - dependencies: - - rpm_sign - - dpkg_sign - <<: *only_primary - script: - - . ./Builds/containers/gitlab-ci/push_to_artifactory.sh "GET" ".checksums" - diff --git a/Builds/containers/gitlab-ci/push_to_artifactory.sh b/Builds/containers/gitlab-ci/push_to_artifactory.sh deleted file mode 100644 index a52227cbe59..00000000000 --- a/Builds/containers/gitlab-ci/push_to_artifactory.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env sh -set -ex -action=$1 -filter=$2 - -. ./Builds/containers/gitlab-ci/get_component.sh - -apk add curl jq coreutils util-linux -TOPDIR=$(pwd) - -# DPKG - -cd $TOPDIR -cd build/dpkg/packages -CURLARGS="-sk -X${action} -urippled:${ARTIFACTORY_DEPLOY_KEY_RIPPLED}" -RIPPLED_PKG=$(ls rippled_*.deb) -RIPPLED_DEV_PKG=$(ls rippled-dev_*.deb) -RIPPLED_DBG_PKG=$(ls rippled-dbgsym_*.deb) -# TODO - where to upload src tgz? -RIPPLED_SRC=$(ls rippled_*.orig.tar.gz) -DEB_MATRIX=";deb.component=${COMPONENT};deb.architecture=amd64" -for dist in stretch buster xenial bionic disco ; do - DEB_MATRIX="${DEB_MATRIX};deb.distribution=${dist}" -done -echo "{ \"debs\": {" > "${TOPDIR}/files.info" -for deb in ${RIPPLED_PKG} ${RIPPLED_DEV_PKG} ${RIPPLED_DBG_PKG} ; do - # first item doesn't get a comma separator - if [ $deb != $RIPPLED_PKG ] ; then - echo "," >> "${TOPDIR}/files.info" - fi - echo "\"${deb}\"": | tee -a "${TOPDIR}/files.info" - ca="${CURLARGS}" - if [ "${action}" = "PUT" ] ; then - url="https://${ARTIFACTORY_HOST}/artifactory/${DEB_REPO}/pool/${COMPONENT}/${deb}${DEB_MATRIX}" - ca="${ca} -T${deb}" - elif [ "${action}" = "GET" ] ; then - url="https://${ARTIFACTORY_HOST}/artifactory/api/storage/${DEB_REPO}/pool/${COMPONENT}/${deb}" - fi - echo "file info request url --> ${url}" - eval "curl ${ca} \"${url}\"" | jq -M "${filter}" | tee -a "${TOPDIR}/files.info" -done -echo "}," >> "${TOPDIR}/files.info" - -# RPM - -cd $TOPDIR -cd build/rpm/packages -RIPPLED_PKG=$(ls rippled-[0-9]*.x86_64.rpm) -RIPPLED_DEV_PKG=$(ls rippled-devel*.rpm) -RIPPLED_DBG_PKG=$(ls rippled-debuginfo*.rpm) -# TODO - where to upload src rpm ? -RIPPLED_SRC=$(ls rippled-[0-9]*.src.rpm) -echo "\"rpms\": {" >> "${TOPDIR}/files.info" -for rpm in ${RIPPLED_PKG} ${RIPPLED_DEV_PKG} ${RIPPLED_DBG_PKG} ; do - # first item doesn't get a comma separator - if [ $rpm != $RIPPLED_PKG ] ; then - echo "," >> "${TOPDIR}/files.info" - fi - echo "\"${rpm}\"": | tee -a "${TOPDIR}/files.info" - ca="${CURLARGS}" - if [ "${action}" = "PUT" ] ; then - url="https://${ARTIFACTORY_HOST}/artifactory/${RPM_REPO}/${COMPONENT}/" - ca="${ca} -T${rpm}" - elif [ "${action}" = "GET" ] ; then - url="https://${ARTIFACTORY_HOST}/artifactory/api/storage/${RPM_REPO}/${COMPONENT}/${rpm}" - fi - echo "file info request url --> ${url}" - eval "curl ${ca} \"${url}\"" | jq -M "${filter}" | tee -a "${TOPDIR}/files.info" -done -echo "}}" >> "${TOPDIR}/files.info" -jq '.' "${TOPDIR}/files.info" > "${TOPDIR}/files.info.tmp" -mv "${TOPDIR}/files.info.tmp" "${TOPDIR}/files.info" - -if [ ! -z "${SLACK_NOTIFY_URL}" ] && [ "${action}" = "GET" ] ; then - # extract files.info content to variable and sanitize so it can - # be interpolated into a slack text field below - finfo=$(cat ${TOPDIR}/files.info | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' | sed -E 's/"/\\"/g') - # try posting file info to slack. - # can add channel field to payload if the - # default channel is incorrect. Get rid of - # newlines in payload json since slack doesn't accept them - CONTENT=$(tr -d '[\n]' <> /etc/apt/sources.list - updateWithRetry - # uncomment this next line if you want to see the available package versions - # apt-cache policy rippled - apt-get -y install rippled=${dpkg_full_version} - elif [ "${install_from}" = "local" ] ; then - # cached pkg install - updateWithRetry - apt-get -y install libprotobuf-dev libssl-dev - rm -f build/dpkg/packages/rippled-dbgsym*.* - dpkg --no-debsig -i build/dpkg/packages/*.deb - else - echo "unrecognized pkg source!" - exit 1 - fi -else - yum -y update - if [ "${install_from}" = "repo" ] ; then - yum -y install yum-utils coreutils util-linux - REPOFILE="/etc/yum.repos.d/artifactory.repo" - echo "[Artifactory]" > ${REPOFILE} - echo "name=Artifactory" >> ${REPOFILE} - echo "baseurl=${REPO_ROOT}/${RPM_REPO}/${COMPONENT}/" >> ${REPOFILE} - echo "enabled=1" >> ${REPOFILE} - echo "gpgcheck=0" >> ${REPOFILE} - echo "gpgkey=${REPO_ROOT}/${RPM_REPO}/${COMPONENT}/repodata/repomd.xml.key" >> ${REPOFILE} - echo "repo_gpgcheck=1" >> ${REPOFILE} - yum -y update - # uncomment this next line if you want to see the available package versions - # yum --showduplicates list rippled - yum -y install ${rpm_version_release} - elif [ "${install_from}" = "local" ] ; then - # cached pkg install - yum install -y yum-utils openssl-static zlib-static - rm -f build/rpm/packages/rippled-debug*.rpm - rm -f build/rpm/packages/*.src.rpm - rpm -i build/rpm/packages/*.rpm - else - echo "unrecognized pkg source!" - exit 1 - fi -fi - -# verify installed version -INSTALLED=$(/opt/ripple/bin/rippled --version | awk '{print $NF}') -if [ "${rippled_version}" != "${INSTALLED}" ] ; then - echo "INSTALLED version ${INSTALLED} does not match ${rippled_version}" - exit 1 -fi -# run unit tests -/opt/ripple/bin/rippled --unittest --unittest-jobs $(nproc) -/opt/ripple/bin/validator-keys --unittest - - diff --git a/Builds/containers/gitlab-ci/tag_docker_image.sh b/Builds/containers/gitlab-ci/tag_docker_image.sh deleted file mode 100644 index 52a811a7381..00000000000 --- a/Builds/containers/gitlab-ci/tag_docker_image.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env sh -set -ex -docker login -u rippled \ - -p ${ARTIFACTORY_DEPLOY_KEY_RIPPLED} "${ARTIFACTORY_HUB}" -# this gives us rippled_version : -source build/rpm/packages/build_vars -docker pull "${ARTIFACTORY_HUB}/${RPM_CONTAINER_NAME}:${CI_COMMIT_SHA}" -docker pull "${ARTIFACTORY_HUB}/${DPKG_CONTAINER_NAME}:${CI_COMMIT_SHA}" -# tag/push two labels...one using the current rippled version and one just using "latest" -for label in ${rippled_version} latest ; do - docker tag \ - "${ARTIFACTORY_HUB}/${RPM_CONTAINER_NAME}:${CI_COMMIT_SHA}" \ - "${ARTIFACTORY_HUB}/${RPM_CONTAINER_NAME}:${label}_${CI_COMMIT_REF_SLUG}" - docker tag \ - "${ARTIFACTORY_HUB}/${DPKG_CONTAINER_NAME}:${CI_COMMIT_SHA}" \ - "${ARTIFACTORY_HUB}/${DPKG_CONTAINER_NAME}:${label}_${CI_COMMIT_REF_SLUG}" - docker push "${ARTIFACTORY_HUB}/${RPM_CONTAINER_NAME}" - docker push "${ARTIFACTORY_HUB}/${DPKG_CONTAINER_NAME}" -done - diff --git a/Builds/containers/gitlab-ci/verify_head_commit.sh b/Builds/containers/gitlab-ci/verify_head_commit.sh deleted file mode 100644 index b2b5ec1250e..00000000000 --- a/Builds/containers/gitlab-ci/verify_head_commit.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env sh -set -ex -apt -y update -apt -y install software-properties-common curl git gnupg -curl -sk -o rippled-pubkeys.txt "${GIT_SIGN_PUBKEYS_URL}" -gpg --import rippled-pubkeys.txt -if git verify-commit HEAD; then - echo "git commit signature check passed" -else - echo "git commit signature check failed" - git log -n 5 --color \ - --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an> [%G?]%Creset' \ - --abbrev-commit - exit 1 -fi - diff --git a/Builds/containers/packaging/dpkg/build_dpkg.sh b/Builds/containers/packaging/dpkg/build_dpkg.sh deleted file mode 100755 index 74e469e59c4..00000000000 --- a/Builds/containers/packaging/dpkg/build_dpkg.sh +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env bash -set -ex - -source update_sources.sh - -# Build the dpkg - -#dpkg uses - as separator, so we need to change our -bN versions to tilde -RIPPLED_DPKG_VERSION=$(echo "${RIPPLED_VERSION}" | sed 's!-!~!g') -# TODO - decide how to handle the trailing/release -# version here (hardcoded to 1). Does it ever need to change? -RIPPLED_DPKG_FULL_VERSION="${RIPPLED_DPKG_VERSION}-1" - -cd /opt/rippled_bld/pkg/rippled -if [[ -n $(git status --porcelain) ]]; then - git status - error "Unstaged changes in this repo - please commit first" -fi -git archive --format tar.gz --prefix rippled-${RIPPLED_DPKG_VERSION}/ -o ../rippled-${RIPPLED_DPKG_VERSION}.tar.gz HEAD -cd .. -# dpkg debmake would normally create this link, but we do it manually -ln -s ./rippled-${RIPPLED_DPKG_VERSION}.tar.gz rippled_${RIPPLED_DPKG_VERSION}.orig.tar.gz -tar xvf rippled-${RIPPLED_DPKG_VERSION}.tar.gz -cd rippled-${RIPPLED_DPKG_VERSION} -cp -pr ../debian . - -# dpkg requires a changelog. We don't currently maintain -# a useable one, so let's just fake it with our current version -# TODO : not sure if the "unstable" will need to change for -# release packages (?) -NOWSTR=$(TZ=UTC date -R) -cat << CHANGELOG > ./debian/changelog -rippled (${RIPPLED_DPKG_FULL_VERSION}) unstable; urgency=low - - * see RELEASENOTES - - -- Ripple Labs Inc. ${NOWSTR} -CHANGELOG - -# PATH must be preserved for our more modern cmake in /opt/local -# TODO : consider allowing lintian to run in future ? -export DH_BUILD_DDEBS=1 -export CC=gcc-8 -export CXX=g++-8 -debuild --no-lintian --preserve-envvar PATH --preserve-env -us -uc -rc=$?; if [[ $rc != 0 ]]; then - error "error building dpkg" -fi -cd .. -ls -latr - -# copy artifacts -cp rippled-dev_${RIPPLED_DPKG_FULL_VERSION}_amd64.deb ${PKG_OUTDIR} -cp rippled_${RIPPLED_DPKG_FULL_VERSION}_amd64.deb ${PKG_OUTDIR} -cp rippled_${RIPPLED_DPKG_FULL_VERSION}.dsc ${PKG_OUTDIR} -# dbgsym suffix is ddeb under newer debuild, but just deb under earlier -cp rippled-dbgsym_${RIPPLED_DPKG_FULL_VERSION}_amd64.* ${PKG_OUTDIR} -cp rippled_${RIPPLED_DPKG_FULL_VERSION}_amd64.changes ${PKG_OUTDIR} -cp rippled_${RIPPLED_DPKG_FULL_VERSION}_amd64.build ${PKG_OUTDIR} -cp rippled_${RIPPLED_DPKG_VERSION}.orig.tar.gz ${PKG_OUTDIR} -cp rippled_${RIPPLED_DPKG_FULL_VERSION}.debian.tar.xz ${PKG_OUTDIR} -# buildinfo is only generated by later version of debuild -if [ -e rippled_${RIPPLED_DPKG_FULL_VERSION}_amd64.buildinfo ] ; then - cp rippled_${RIPPLED_DPKG_FULL_VERSION}_amd64.buildinfo ${PKG_OUTDIR} -fi - -cat rippled_${RIPPLED_DPKG_FULL_VERSION}_amd64.changes -# extract the text in the .changes file that appears between -# Checksums-Sha256: ... -# and -# Files: ... -awk '/Checksums-Sha256:/{hit=1;next}/Files:/{hit=0}hit' \ - rippled_${RIPPLED_DPKG_VERSION}-1_amd64.changes | \ - sed -E 's!^[[:space:]]+!!' > shasums -DEB_SHA256=$(cat shasums | \ - grep "rippled_${RIPPLED_DPKG_VERSION}-1_amd64.deb" | cut -d " " -f 1) -DBG_SHA256=$(cat shasums | \ - grep "rippled-dbgsym_${RIPPLED_DPKG_VERSION}-1_amd64.*" | cut -d " " -f 1) -DEV_SHA256=$(cat shasums | \ - grep "rippled-dev_${RIPPLED_DPKG_VERSION}-1_amd64.deb" | cut -d " " -f 1) -SRC_SHA256=$(cat shasums | \ - grep "rippled_${RIPPLED_DPKG_VERSION}.orig.tar.gz" | cut -d " " -f 1) -echo "deb_sha256=${DEB_SHA256}" >> ${PKG_OUTDIR}/build_vars -echo "dbg_sha256=${DBG_SHA256}" >> ${PKG_OUTDIR}/build_vars -echo "dev_sha256=${DEV_SHA256}" >> ${PKG_OUTDIR}/build_vars -echo "src_sha256=${SRC_SHA256}" >> ${PKG_OUTDIR}/build_vars -echo "rippled_version=${RIPPLED_VERSION}" >> ${PKG_OUTDIR}/build_vars -echo "dpkg_version=${RIPPLED_DPKG_VERSION}" >> ${PKG_OUTDIR}/build_vars -echo "dpkg_full_version=${RIPPLED_DPKG_FULL_VERSION}" >> ${PKG_OUTDIR}/build_vars - diff --git a/Builds/containers/packaging/dpkg/debian/README.Debian b/Builds/containers/packaging/dpkg/debian/README.Debian deleted file mode 100644 index 25ba6b55f70..00000000000 --- a/Builds/containers/packaging/dpkg/debian/README.Debian +++ /dev/null @@ -1,3 +0,0 @@ -rippled daemon - - -- Mike Ellery Tue, 04 Dec 2018 18:19:03 +0000 diff --git a/Builds/containers/packaging/dpkg/debian/compat b/Builds/containers/packaging/dpkg/debian/compat deleted file mode 100644 index ec635144f60..00000000000 --- a/Builds/containers/packaging/dpkg/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/Builds/containers/packaging/dpkg/debian/conffiles b/Builds/containers/packaging/dpkg/debian/conffiles deleted file mode 100644 index ce164097ef0..00000000000 --- a/Builds/containers/packaging/dpkg/debian/conffiles +++ /dev/null @@ -1,3 +0,0 @@ -opt/ripple/etc/rippled.cfg -opt/ripple/etc/validators.txt -etc/logrotate.d/rippled diff --git a/Builds/containers/packaging/dpkg/debian/control b/Builds/containers/packaging/dpkg/debian/control deleted file mode 100644 index e09c0895ec8..00000000000 --- a/Builds/containers/packaging/dpkg/debian/control +++ /dev/null @@ -1,21 +0,0 @@ -Source: rippled -Section: misc -Priority: extra -Maintainer: Ripple Labs Inc. -Build-Depends: cmake, debhelper (>=9), libprotobuf-dev, libssl-dev, zlib1g-dev, dh-systemd, ninja-build -Standards-Version: 3.9.7 -Homepage: http://ripple.com/ - -Package: rippled -Architecture: any -Multi-Arch: foreign -Depends: ${misc:Depends}, ${shlibs:Depends} -Description: rippled daemon - -Package: rippled-dev -Section: devel -Recommends: rippled (= ${binary:Version}) -Architecture: any -Multi-Arch: same -Depends: ${misc:Depends}, ${shlibs:Depends}, libprotobuf-dev, libssl-dev -Description: development files for applications using xrpl core library (serialize + sign) diff --git a/Builds/containers/packaging/dpkg/debian/copyright b/Builds/containers/packaging/dpkg/debian/copyright deleted file mode 100644 index dce318fd765..00000000000 --- a/Builds/containers/packaging/dpkg/debian/copyright +++ /dev/null @@ -1,86 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: rippled -Source: https://github.com/ripple/rippled - -Files: * -Copyright: 2012-2019 Ripple Labs Inc. - -License: __UNKNOWN__ - -The accompanying files under various copyrights. - -Copyright (c) 2012, 2013, 2014 Ripple Labs Inc. - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -The accompanying files incorporate work covered by the following copyright -and previous license notice: - -Copyright (c) 2011 Arthur Britto, David Schwartz, Jed McCaleb, -Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant - -Some code from Raw Material Software, Ltd., provided under the terms of the - ISC License. See the corresponding source files for more details. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - -Some code from ASIO examples: -// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -Some code from Bitcoin: -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. - -Some code from Tom Wu: -This software is covered under the following copyright: - -/* - * Copyright (c) 2003-2005 Tom Wu - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * In addition, the following condition applies: - * - * All redistributions must retain an intact copy of this copyright notice - * and disclaimer. - */ - -Address all questions regarding this license to: - - Tom Wu - tjw@cs.Stanford.EDU diff --git a/Builds/containers/packaging/dpkg/debian/dirs b/Builds/containers/packaging/dpkg/debian/dirs deleted file mode 100644 index aed307ee178..00000000000 --- a/Builds/containers/packaging/dpkg/debian/dirs +++ /dev/null @@ -1,3 +0,0 @@ -/var/log/rippled/ -/var/lib/rippled/ -/etc/systemd/system/rippled.service.d/ diff --git a/Builds/containers/packaging/dpkg/debian/docs b/Builds/containers/packaging/dpkg/debian/docs deleted file mode 100644 index 4742cb8378f..00000000000 --- a/Builds/containers/packaging/dpkg/debian/docs +++ /dev/null @@ -1,3 +0,0 @@ -README.md -LICENSE -RELEASENOTES.md diff --git a/Builds/containers/packaging/dpkg/debian/rippled-dev.install b/Builds/containers/packaging/dpkg/debian/rippled-dev.install deleted file mode 100644 index a222857c0b7..00000000000 --- a/Builds/containers/packaging/dpkg/debian/rippled-dev.install +++ /dev/null @@ -1,3 +0,0 @@ -opt/ripple/include -opt/ripple/lib/*.a -opt/ripple/lib/cmake/ripple diff --git a/Builds/containers/packaging/dpkg/debian/rippled.install b/Builds/containers/packaging/dpkg/debian/rippled.install deleted file mode 100644 index eefdd152806..00000000000 --- a/Builds/containers/packaging/dpkg/debian/rippled.install +++ /dev/null @@ -1,7 +0,0 @@ -opt/ripple/bin/rippled -opt/ripple/bin/validator-keys -opt/ripple/bin/update-rippled.sh -opt/ripple/etc/rippled.cfg -opt/ripple/etc/validators.txt -opt/ripple/etc/update-rippled-cron -etc/logrotate.d/rippled diff --git a/Builds/containers/packaging/dpkg/debian/rippled.links b/Builds/containers/packaging/dpkg/debian/rippled.links deleted file mode 100644 index ff2abd82b31..00000000000 --- a/Builds/containers/packaging/dpkg/debian/rippled.links +++ /dev/null @@ -1,3 +0,0 @@ -opt/ripple/etc/rippled.cfg etc/opt/ripple/rippled.cfg -opt/ripple/etc/validators.txt etc/opt/ripple/validators.txt -opt/ripple/bin/rippled usr/local/bin/rippled diff --git a/Builds/containers/packaging/dpkg/debian/rippled.postinst b/Builds/containers/packaging/dpkg/debian/rippled.postinst deleted file mode 100644 index 9838fa593f7..00000000000 --- a/Builds/containers/packaging/dpkg/debian/rippled.postinst +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -set -e - -USER_NAME=rippled -GROUP_NAME=rippled -case "$1" in - configure) - id -u $USER_NAME >/dev/null 2>&1 || \ - adduser --system --quiet \ - --home /nonexistent --no-create-home \ - --disabled-password \ - --group "$GROUP_NAME" - chown -R $USER_NAME:$GROUP_NAME /var/log/rippled/ - chown -R $USER_NAME:$GROUP_NAME /var/lib/rippled/ - chown -R $USER_NAME:$GROUP_NAME /opt/ripple - chmod 755 /var/log/rippled/ - chmod 755 /var/lib/rippled/ - chmod 644 /opt/ripple/etc/update-rippled-cron - chmod 644 /etc/logrotate.d/rippled - chown -R root:$GROUP_NAME /opt/ripple/etc/update-rippled-cron - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - - -#DEBHELPER# - -exit 0 diff --git a/Builds/containers/packaging/dpkg/debian/rippled.postrm b/Builds/containers/packaging/dpkg/debian/rippled.postrm deleted file mode 100644 index 9086993a1f5..00000000000 --- a/Builds/containers/packaging/dpkg/debian/rippled.postrm +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -set -e - -case "$1" in - purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) - ;; - - *) - echo "postrm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - - -#DEBHELPER# - -exit 0 diff --git a/Builds/containers/packaging/dpkg/debian/rippled.preinst b/Builds/containers/packaging/dpkg/debian/rippled.preinst deleted file mode 100644 index 10575345a2b..00000000000 --- a/Builds/containers/packaging/dpkg/debian/rippled.preinst +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -set -e - -case "$1" in - install|upgrade) - ;; - - abort-upgrade) - ;; - - *) - echo "preinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - - -#DEBHELPER# - -exit 0 diff --git a/Builds/containers/packaging/dpkg/debian/rippled.prerm b/Builds/containers/packaging/dpkg/debian/rippled.prerm deleted file mode 100644 index adabdbfb72a..00000000000 --- a/Builds/containers/packaging/dpkg/debian/rippled.prerm +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -set -e - -case "$1" in - remove|upgrade|deconfigure) - ;; - - failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - - -#DEBHELPER# - -exit 0 diff --git a/Builds/containers/packaging/dpkg/debian/rules b/Builds/containers/packaging/dpkg/debian/rules deleted file mode 100755 index 1eccd9a44be..00000000000 --- a/Builds/containers/packaging/dpkg/debian/rules +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/make -f -export DH_VERBOSE = 1 -export DH_OPTIONS = -v -# debuild sets some warnings that don't work well -# for our curent build..so try to remove those flags here: -export CFLAGS:=$(subst -Wformat,,$(CFLAGS)) -export CFLAGS:=$(subst -Werror=format-security,,$(CFLAGS)) -export CXXFLAGS:=$(subst -Wformat,,$(CXXFLAGS)) -export CXXFLAGS:=$(subst -Werror=format-security,,$(CXXFLAGS)) - -%: - dh $@ --with systemd - -override_dh_auto_configure: - env - rm -rf bld - mkdir -p bld - cd bld && \ - cmake .. -G Ninja \ - -DCMAKE_INSTALL_PREFIX=/opt/ripple \ - -DCMAKE_BUILD_TYPE=Release \ - -Dstatic=true \ - -Dlocal_protobuf=ON \ - -Dvalidator_keys=ON \ - -DCMAKE_VERBOSE_MAKEFILE=ON - -override_dh_auto_build: - cd bld && \ - cmake --build . --target rippled --target validator-keys --parallel -- -v - -override_dh_auto_install: - cd bld && DESTDIR=../debian/tmp cmake --build . --target install -- -v - install -D bld/validator-keys/validator-keys debian/tmp/opt/ripple/bin/validator-keys - install -D Builds/containers/shared/update-rippled.sh debian/tmp/opt/ripple/bin/update-rippled.sh - install -D Builds/containers/shared/update-rippled-cron debian/tmp/opt/ripple/etc/update-rippled-cron - install -D Builds/containers/shared/rippled-logrotate debian/tmp/etc/logrotate.d/rippled - rm -rf bld - rm -rf bld_vl diff --git a/Builds/containers/packaging/dpkg/debian/source/format b/Builds/containers/packaging/dpkg/debian/source/format deleted file mode 100644 index 163aaf8d82b..00000000000 --- a/Builds/containers/packaging/dpkg/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/Builds/containers/packaging/dpkg/debian/source/local-options b/Builds/containers/packaging/dpkg/debian/source/local-options deleted file mode 100644 index 00131ee8c41..00000000000 --- a/Builds/containers/packaging/dpkg/debian/source/local-options +++ /dev/null @@ -1,2 +0,0 @@ -#abort-on-upstream-changes -#unapply-patches diff --git a/Builds/containers/packaging/rpm/50-rippled.preset b/Builds/containers/packaging/rpm/50-rippled.preset deleted file mode 100644 index 854e20a0872..00000000000 --- a/Builds/containers/packaging/rpm/50-rippled.preset +++ /dev/null @@ -1 +0,0 @@ -enable rippled.service \ No newline at end of file diff --git a/Builds/containers/packaging/rpm/build_rpm.sh b/Builds/containers/packaging/rpm/build_rpm.sh deleted file mode 100755 index df2455f6a1d..00000000000 --- a/Builds/containers/packaging/rpm/build_rpm.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env bash -set -ex - -source update_sources.sh - -# Build the rpm - -IFS='-' read -r RIPPLED_RPM_VERSION RELEASE <<< "$RIPPLED_VERSION" -export RIPPLED_RPM_VERSION - -RPM_RELEASE=${RPM_RELEASE-1} - -# post-release version -if [ "hf" = "$(echo "$RELEASE" | cut -c -2)" ]; then - RPM_RELEASE="${RPM_RELEASE}.${RELEASE}" -# pre-release version (-b or -rc) -elif [[ $RELEASE ]]; then - RPM_RELEASE="0.${RPM_RELEASE}.${RELEASE}" -fi - -export RPM_RELEASE - -if [[ $RPM_PATCH ]]; then - RPM_PATCH=".${RPM_PATCH}" - export RPM_PATCH -fi - -cd /opt/rippled_bld/pkg/rippled -if [[ -n $(git status --porcelain) ]]; then - git status - error "Unstaged changes in this repo - please commit first" -fi -git archive --format tar.gz --prefix rippled/ -o ../rpmbuild/SOURCES/rippled.tar.gz HEAD -# TODO include validator-keys sources -cd .. - -source /opt/rh/devtoolset-8/enable - -rpmbuild --define "_topdir ${PWD}/rpmbuild" -ba rippled.spec -rc=$?; if [[ $rc != 0 ]]; then - error "error building rpm" -fi - -# Make a tar of the rpm and source rpm -RPM_VERSION_RELEASE=$(rpm -qp --qf='%{NAME}-%{VERSION}-%{RELEASE}' ./rpmbuild/RPMS/x86_64/rippled-[0-9]*.rpm) -tar_file=$RPM_VERSION_RELEASE.tar.gz - -cp ./rpmbuild/RPMS/x86_64/* ${PKG_OUTDIR} -cp ./rpmbuild/SRPMS/* ${PKG_OUTDIR} - -RPM_MD5SUM=$(rpm -q --queryformat '%{SIGMD5}\n' -p ./rpmbuild/RPMS/x86_64/rippled-[0-9]*.rpm 2>/dev/null) -DBG_MD5SUM=$(rpm -q --queryformat '%{SIGMD5}\n' -p ./rpmbuild/RPMS/x86_64/rippled-debuginfo*.rpm 2>/dev/null) -DEV_MD5SUM=$(rpm -q --queryformat '%{SIGMD5}\n' -p ./rpmbuild/RPMS/x86_64/rippled-devel*.rpm 2>/dev/null) -SRC_MD5SUM=$(rpm -q --queryformat '%{SIGMD5}\n' -p ./rpmbuild/SRPMS/*.rpm 2>/dev/null) - -RPM_SHA256="$(sha256sum ./rpmbuild/RPMS/x86_64/rippled-[0-9]*.rpm | awk '{ print $1}')" -DBG_SHA256="$(sha256sum ./rpmbuild/RPMS/x86_64/rippled-debuginfo*.rpm | awk '{ print $1}')" -DEV_SHA256="$(sha256sum ./rpmbuild/RPMS/x86_64/rippled-devel*.rpm | awk '{ print $1}')" -SRC_SHA256="$(sha256sum ./rpmbuild/SRPMS/*.rpm | awk '{ print $1}')" - -echo "rpm_md5sum=$RPM_MD5SUM" > ${PKG_OUTDIR}/build_vars -echo "dbg_md5sum=$DBG_MD5SUM" >> ${PKG_OUTDIR}/build_vars -echo "dev_md5sum=$DEV_MD5SUM" >> ${PKG_OUTDIR}/build_vars -echo "src_md5sum=$SRC_MD5SUM" >> ${PKG_OUTDIR}/build_vars -echo "rpm_sha256=$RPM_SHA256" >> ${PKG_OUTDIR}/build_vars -echo "dbg_sha256=$DBG_SHA256" >> ${PKG_OUTDIR}/build_vars -echo "dev_sha256=$DEV_SHA256" >> ${PKG_OUTDIR}/build_vars -echo "src_sha256=$SRC_SHA256" >> ${PKG_OUTDIR}/build_vars -echo "rippled_version=$RIPPLED_VERSION" >> ${PKG_OUTDIR}/build_vars -echo "rpm_version=$RIPPLED_RPM_VERSION" >> ${PKG_OUTDIR}/build_vars -echo "rpm_file_name=$tar_file" >> ${PKG_OUTDIR}/build_vars -echo "rpm_version_release=$RPM_VERSION_RELEASE" >> ${PKG_OUTDIR}/build_vars - diff --git a/Builds/containers/packaging/rpm/rippled.spec b/Builds/containers/packaging/rpm/rippled.spec deleted file mode 100644 index fd9c04515ae..00000000000 --- a/Builds/containers/packaging/rpm/rippled.spec +++ /dev/null @@ -1,110 +0,0 @@ -%define rippled_version %(echo $RIPPLED_RPM_VERSION) -%define rpm_release %(echo $RPM_RELEASE) -%define rpm_patch %(echo $RPM_PATCH) -%define _prefix /opt/ripple -Name: rippled -# Dashes in Version extensions must be converted to underscores -Version: %{rippled_version} -Release: %{rpm_release}%{?dist}%{rpm_patch} -Summary: rippled daemon - -License: MIT -URL: http://ripple.com/ -Source0: rippled.tar.gz - -BuildRequires: protobuf-static openssl-static cmake zlib-static ninja-build - -%description -rippled - -%package devel -Summary: Files for development of applications using xrpl core library -Group: Development/Libraries -Requires: openssl-static, zlib-static - -%description devel -core library for development of standalone applications that sign transactions. - -%prep -%setup -c -n rippled - -%build -cd rippled -mkdir -p bld.release -cd bld.release -cmake .. -G Ninja -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_BUILD_TYPE=Release -Dstatic=true -DCMAKE_VERBOSE_MAKEFILE=ON -Dlocal_protobuf=ON -Dvalidator_keys=ON -cmake --build . --parallel --target rippled --target validator-keys -- -v - -%pre -test -e /etc/pki/tls || { mkdir -p /etc/pki; ln -s /usr/lib/ssl /etc/pki/tls; } - -%install -rm -rf $RPM_BUILD_ROOT -DESTDIR=$RPM_BUILD_ROOT cmake --build rippled/bld.release --target install -- -v -install -d ${RPM_BUILD_ROOT}/etc/opt/ripple -install -d ${RPM_BUILD_ROOT}/usr/local/bin -ln -s %{_prefix}/etc/rippled.cfg ${RPM_BUILD_ROOT}/etc/opt/ripple/rippled.cfg -ln -s %{_prefix}/etc/validators.txt ${RPM_BUILD_ROOT}/etc/opt/ripple/validators.txt -ln -s %{_prefix}/bin/rippled ${RPM_BUILD_ROOT}/usr/local/bin/rippled -install -D rippled/bld.release/validator-keys/validator-keys ${RPM_BUILD_ROOT}%{_bindir}/validator-keys -install -D ./rippled/Builds/containers/shared/rippled.service ${RPM_BUILD_ROOT}/usr/lib/systemd/system/rippled.service -install -D ./rippled/Builds/containers/packaging/rpm/50-rippled.preset ${RPM_BUILD_ROOT}/usr/lib/systemd/system-preset/50-rippled.preset -install -D ./rippled/Builds/containers/shared/update-rippled.sh ${RPM_BUILD_ROOT}%{_bindir}/update-rippled.sh -install -D ./rippled/Builds/containers/shared/update-rippled-cron ${RPM_BUILD_ROOT}%{_prefix}/etc/update-rippled-cron -install -D ./rippled/Builds/containers/shared/rippled-logrotate ${RPM_BUILD_ROOT}/etc/logrotate.d/rippled -install -d $RPM_BUILD_ROOT/var/log/rippled -install -d $RPM_BUILD_ROOT/var/lib/rippled - -%post -USER_NAME=rippled -GROUP_NAME=rippled - -getent passwd $USER_NAME &>/dev/null || useradd $USER_NAME -getent group $GROUP_NAME &>/dev/null || groupadd $GROUP_NAME - -chown -R $USER_NAME:$GROUP_NAME /var/log/rippled/ -chown -R $USER_NAME:$GROUP_NAME /var/lib/rippled/ -chown -R $USER_NAME:$GROUP_NAME %{_prefix}/ - -chmod 755 /var/log/rippled/ -chmod 755 /var/lib/rippled/ - -chmod 644 %{_prefix}/etc/update-rippled-cron -chmod 644 /etc/logrotate.d/rippled -chown -R root:$GROUP_NAME %{_prefix}/etc/update-rippled-cron - -%files -%doc rippled/README.md rippled/LICENSE -%{_bindir}/rippled -/usr/local/bin/rippled -%{_bindir}/update-rippled.sh -%{_prefix}/etc/update-rippled-cron -%{_bindir}/validator-keys -%config(noreplace) %{_prefix}/etc/rippled.cfg -%config(noreplace) /etc/opt/ripple/rippled.cfg -%config(noreplace) %{_prefix}/etc/validators.txt -%config(noreplace) /etc/opt/ripple/validators.txt -%config(noreplace) /etc/logrotate.d/rippled -%config(noreplace) /usr/lib/systemd/system/rippled.service -%config(noreplace) /usr/lib/systemd/system-preset/50-rippled.preset -%dir /var/log/rippled/ -%dir /var/lib/rippled/ - -%files devel -%{_prefix}/include -%{_prefix}/lib/*.a -%{_prefix}/lib/cmake/ripple - -%changelog -* Wed Aug 28 2019 Mike Ellery -- Switch to subproject build for validator-keys - -* Wed May 15 2019 Mike Ellery -- Make validator-keys use local rippled build for core lib - -* Wed Aug 01 2018 Mike Ellery -- add devel package for signing library - -* Thu Jun 02 2016 Brandon Wilson -- Install validators.txt - diff --git a/Builds/containers/shared/build_deps.sh b/Builds/containers/shared/build_deps.sh deleted file mode 100755 index 6287e3561d9..00000000000 --- a/Builds/containers/shared/build_deps.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env bash -set -ex - -function build_boost() -{ - local boost_ver=$1 - local do_link=$2 - local boost_path=$(echo "${boost_ver}" | sed -e 's!\.!_!g') - mkdir -p /opt/local - cd /opt/local - BOOST_ROOT=/opt/local/boost_${boost_path} - BOOST_URL="https://dl.bintray.com/boostorg/release/${boost_ver}/source/boost_${boost_path}.tar.bz2" - BOOST_BUILD_ALL=true - . /tmp/install_boost.sh - if [ "$do_link" = true ] ; then - ln -s ./boost_${boost_path} boost - fi -} - -build_boost "1.70.0" true - -# installed in opt, so won't be used -# unless specified by OPENSSL_ROOT_DIR -cd /tmp -OPENSSL_VER=1.1.1 -wget https://www.openssl.org/source/openssl-${OPENSSL_VER}.tar.gz -tar xf openssl-${OPENSSL_VER}.tar.gz -cd openssl-${OPENSSL_VER} -# NOTE: add -g to the end of the following line if we want debug symbols for openssl -SSLDIR=$(openssl version -d | cut -d: -f2 | tr -d [:space:]\") -./config -fPIC --prefix=/opt/local/openssl --openssldir=${SSLDIR} zlib shared -make -j$(nproc) -make install -cd .. -rm -f openssl-${OPENSSL_VER}.tar.gz -rm -rf openssl-${OPENSSL_VER} -LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:/opt/local/openssl/lib /opt/local/openssl/bin/openssl version -a - -if [ "${CI_USE}" = true ] ; then - cd /tmp - wget https://github.com/doxygen/doxygen/archive/Release_1_8_16.tar.gz - tar xf Release_1_8_16.tar.gz - cd doxygen-Release_1_8_16 - mkdir build - cd build - cmake -G "Unix Makefiles" .. - make -j$(nproc) - make install - cd ../.. - rm -f Release_1_8_16.tar.gz - rm -rf doxygen-Release_1_8_16 - - mkdir -p /opt/plantuml - wget -O /opt/plantuml/plantuml.jar https://downloads.sourceforge.net/project/plantuml/plantuml.jar - - cd /tmp - wget https://github.com/linux-test-project/lcov/releases/download/v1.14/lcov-1.14.tar.gz - tar xfz lcov-1.14.tar.gz - cd lcov-1.14 - make install PREFIX=/usr/local - cd .. - rm -r lcov-1.14 lcov-1.14.tar.gz - - cd /tmp - wget https://github.com/ccache/ccache/releases/download/v3.7.3/ccache-3.7.3.tar.gz - tar xf ccache-3.7.3.tar.gz - cd ccache-3.7.3 - ./configure --prefix=/usr/local - make - make install - cd .. - rm -f ccache-3.7.3.tar.gz - rm -rf ccache-3.7.3 - - pip install requests - pip install https://github.com/codecov/codecov-python/archive/master.zip -fi - diff --git a/Builds/containers/shared/install_boost.sh b/Builds/containers/shared/install_boost.sh deleted file mode 100755 index 81927fb076e..00000000000 --- a/Builds/containers/shared/install_boost.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env bash -# Assumptions: -# 1) BOOST_ROOT and BOOST_URL are already defined, -# and contain valid values. -# 2) The last namepart of BOOST_ROOT matches the -# folder name internal to boost's .tar.gz -# When testing you can force a boost build by clearing travis caches: -# https://travis-ci.org/ripple/rippled/caches -set -exu - -odir=$(pwd) - -if [[ -d "$BOOST_ROOT/lib" || -d "${BOOST_ROOT}/stage/lib" ]] ; then - echo "Using cached boost at $BOOST_ROOT" - exit -fi - -#fetch/unpack: -fn=$(basename -- "$BOOST_URL") -ext="${fn##*.}" -wget --quiet $BOOST_URL -O /tmp/boost.tar.${ext} -cd $(dirname $BOOST_ROOT) -rm -fr ${BOOST_ROOT} -tar xf /tmp/boost.tar.${ext} -cd $BOOST_ROOT - -BLDARGS=() -if [[ ${BOOST_BUILD_ALL:-false} == "true" ]]; then - # we never need boost-python...so even for ALL - # option we can skip it - BLDARGS+=(--without-python) -else - BLDARGS+=(--with-chrono) - BLDARGS+=(--with-context) - BLDARGS+=(--with-coroutine) - BLDARGS+=(--with-date_time) - BLDARGS+=(--with-filesystem) - BLDARGS+=(--with-program_options) - BLDARGS+=(--with-regex) - BLDARGS+=(--with-serialization) - BLDARGS+=(--with-system) - BLDARGS+=(--with-atomic) - BLDARGS+=(--with-thread) -fi -BLDARGS+=(-j$((2*${NUM_PROCESSORS:-2}))) -BLDARGS+=(--prefix=${BOOST_ROOT}/_INSTALLED_) -BLDARGS+=(-d0) # suppress messages/output - -if [[ -z ${COMSPEC:-} ]]; then - if [[ "$(uname)" == "Darwin" ]] ; then - BLDARGS+=(cxxflags="-std=c++14 -fvisibility=default") - else - BLDARGS+=(cxxflags="-std=c++14") - BLDARGS+=(runtime-link="static,shared") - fi - BLDARGS+=(--layout=tagged) - ./bootstrap.sh - ./b2 "${BLDARGS[@]}" stage - ./b2 "${BLDARGS[@]}" install -else - BLDARGS+=(runtime-link="static,shared") - BLDARGS+=(--layout=versioned) - BLDARGS+=(--toolset="msvc-14.1") - BLDARGS+=(address-model=64) - BLDARGS+=(architecture=x86) - BLDARGS+=(link=static) - BLDARGS+=(threading=multi) - cmd /E:ON /D /S /C"bootstrap.bat" - ./b2.exe "${BLDARGS[@]}" stage - ./b2.exe "${BLDARGS[@]}" install -fi - -if [[ ${CI:-false} == "true" ]]; then - # save some disk space...these are mostly - # obj files and don't need to be kept in CI contexts - rm -rf bin.v2 -fi - -cd $odir - diff --git a/Builds/containers/shared/install_cmake.sh b/Builds/containers/shared/install_cmake.sh deleted file mode 100755 index 2c9fa10d1c5..00000000000 --- a/Builds/containers/shared/install_cmake.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -set -e - -IFS=. read cm_maj cm_min cm_rel <<<"$1" -: ${cm_rel:-0} -CMAKE_ROOT=${2:-"${HOME}/cmake"} - -function cmake_version () -{ - if [[ -d ${CMAKE_ROOT} ]] ; then - local perms=$(test $(uname) = "Linux" && echo "/111" || echo "+111") - local installed=$(find ${CMAKE_ROOT} -perm ${perms} -type f -name cmake) - if [[ "${installed}" != "" ]] ; then - echo "$(${installed} --version | head -1)" - fi - fi -} - -installed=$(cmake_version) -if [[ "${installed}" != "" && ${installed} =~ ${cm_maj}.${cm_min}.${cm_rel} ]] ; then - echo "cmake already installed: ${installed}" - exit -fi - -pkgname="cmake-${cm_maj}.${cm_min}.${cm_rel}-$(uname)-x86_64.tar.gz" -tmppkg="/tmp/cmake.tar.gz" -wget --quiet https://cmake.org/files/v${cm_maj}.${cm_min}/${pkgname} -O ${tmppkg} -mkdir -p ${CMAKE_ROOT} -cd ${CMAKE_ROOT} -tar --strip-components 1 -xf ${tmppkg} -rm -f ${tmppkg} -echo "installed: $(cmake_version)" - - diff --git a/Builds/containers/shared/rippled-logrotate b/Builds/containers/shared/rippled-logrotate deleted file mode 100644 index 120aa91d3cc..00000000000 --- a/Builds/containers/shared/rippled-logrotate +++ /dev/null @@ -1,15 +0,0 @@ -/var/log/rippled/*.log { - daily - minsize 200M - rotate 7 - nocreate - missingok - notifempty - compress - compresscmd /usr/bin/nice - compressoptions -n19 ionice -c3 gzip - compressext .gz - postrotate - /opt/ripple/bin/rippled --conf /opt/ripple/etc/rippled.cfg logrotate - endscript -} diff --git a/Builds/containers/shared/rippled.service b/Builds/containers/shared/rippled.service deleted file mode 100644 index 4514edb0d1b..00000000000 --- a/Builds/containers/shared/rippled.service +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=Ripple Daemon - -[Service] -Type=simple -ExecStart=/opt/ripple/bin/rippled --net --silent --conf /etc/opt/ripple/rippled.cfg -# Default KillSignal can be used if/when rippled handles SIGTERM -KillSignal=SIGINT -Restart=no -User=rippled -Group=rippled -LimitNOFILE=65536 - -[Install] -WantedBy=multi-user.target diff --git a/Builds/containers/shared/update-rippled-cron b/Builds/containers/shared/update-rippled-cron deleted file mode 100644 index c7744219f9a..00000000000 --- a/Builds/containers/shared/update-rippled-cron +++ /dev/null @@ -1,10 +0,0 @@ -# For automatic updates, symlink this file to /etc/cron.d/ -# Do not remove the newline at the end of this cron script - -# bash required for use of RANDOM below. -SHELL=/bin/bash -PATH=/sbin;/bin;/usr/sbin;/usr/bin - -# invoke check/update script with random delay up to 59 mins -0 * * * * root sleep $((RANDOM*3540/32768)) && /opt/ripple/bin/update-rippled.sh - diff --git a/Builds/containers/shared/update-rippled.sh b/Builds/containers/shared/update-rippled.sh deleted file mode 100755 index 19409ece0cb..00000000000 --- a/Builds/containers/shared/update-rippled.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bash - -# auto-update script for rippled daemon - -# Check for sudo/root permissions -if [[ $(id -u) -ne 0 ]] ; then - echo "This update script must be run as root or sudo" - exit 1 -fi - -LOCKDIR=/tmp/rippleupdate.lock -UPDATELOG=/var/log/rippled/update.log - -function cleanup { - # If this directory isn't removed, future updates will fail. - rmdir $LOCKDIR -} - -# Use mkdir to check if process is already running. mkdir is atomic, as against file create. -if ! mkdir $LOCKDIR 2>/dev/null; then - echo $(date -u) "lockdir exists - won't proceed." >> $UPDATELOG - exit 1 -fi -trap cleanup EXIT - -source /etc/os-release -can_update=false - -if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]] ; then - # Silent update - apt-get update -qq - - # The next line is an "awk"ward way to check if the package needs to be updated. - RIPPLE=$(apt-get install -s --only-upgrade rippled | awk '/^Inst/ { print $2 }') - test "$RIPPLE" == "rippled" && can_update=true - - function apply_update { - apt-get install rippled -qq - } -elif [[ "$ID" == "fedora" || "$ID" == "centos" || "$ID" == "rhel" || "$ID" == "scientific" ]] ; then - RIPPLE_REPO=${RIPPLE_REPO-stable} - yum --disablerepo=* --enablerepo=ripple-$RIPPLE_REPO clean expire-cache - - yum check-update -q --enablerepo=ripple-$RIPPLE_REPO rippled || can_update=true - - function apply_update { - yum update -y --enablerepo=ripple-$RIPPLE_REPO rippled - } -else - echo "unrecognized distro!" - exit 1 -fi - -# Do the actual update and restart the service after reloading systemctl daemon. -if [ "$can_update" = true ] ; then - exec 3>&1 1>>${UPDATELOG} 2>&1 - set -e - apply_update - systemctl daemon-reload - systemctl restart rippled.service - echo $(date -u) "rippled daemon updated." -else - echo $(date -u) "no updates available" >> $UPDATELOG -fi - diff --git a/Builds/containers/shared/update_sources.sh b/Builds/containers/shared/update_sources.sh deleted file mode 100755 index 56ca958b287..00000000000 --- a/Builds/containers/shared/update_sources.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -function error { - echo $1 - exit 1 -} - -cd /opt/rippled_bld/pkg/rippled -export RIPPLED_VERSION=$(egrep -i -o "\b(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9a-z\-]+(\.[0-9a-z\-]+)*)?(\+[0-9a-z\-]+(\.[0-9a-z\-]+)*)?\b" src/ripple/protocol/impl/BuildInfo.cpp) - -: ${PKG_OUTDIR:=/opt/rippled_bld/pkg/out} -export PKG_OUTDIR -if [ ! -d ${PKG_OUTDIR} ]; then - error "${PKG_OUTDIR} is not mounted" -fi - -if [ -x ${OPENSSL_ROOT}/bin/openssl ]; then - LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${OPENSSL_ROOT}/lib ${OPENSSL_ROOT}/bin/openssl version -a -fi - diff --git a/Builds/containers/ubuntu-builder/Dockerfile b/Builds/containers/ubuntu-builder/Dockerfile deleted file mode 100644 index af80eae9686..00000000000 --- a/Builds/containers/ubuntu-builder/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -ARG DIST_TAG=16.04 -FROM ubuntu:$DIST_TAG -ARG GIT_COMMIT=unknown -ARG CI_USE=false -LABEL git-commit=$GIT_COMMIT - -# install/setup prerequisites: -COPY ubuntu-builder/ubuntu_setup.sh /tmp/ -COPY shared/build_deps.sh /tmp/ -COPY shared/install_cmake.sh /tmp/ -COPY shared/install_boost.sh /tmp/ -RUN chmod +x /tmp/ubuntu_setup.sh && \ - chmod +x /tmp/build_deps.sh && \ - chmod +x /tmp/install_boost.sh && \ - chmod +x /tmp/install_cmake.sh -RUN /tmp/ubuntu_setup.sh - -RUN /tmp/install_cmake.sh 3.15.2 /opt/local/cmake-3.15 -RUN ln -s /opt/local/cmake-3.15 /opt/local/cmake -ENV PATH="/opt/local/cmake/bin:$PATH" -# also install min supported cmake for testing -RUN if [ "${CI_USE}" = true ] ; then /tmp/install_cmake.sh 3.9.0 /opt/local/cmake-3.9; fi - -RUN /tmp/build_deps.sh -ENV PLANTUML_JAR="/opt/plantuml/plantuml.jar" -ENV BOOST_ROOT="/opt/local/boost/_INSTALLED_" -ENV OPENSSL_ROOT="/opt/local/openssl" - -# prep files for package building -RUN mkdir -m 777 -p /opt/rippled_bld/pkg -WORKDIR /opt/rippled_bld/pkg - -COPY packaging/dpkg/debian /opt/rippled_bld/pkg/debian/ -COPY shared/update_sources.sh ./ -COPY shared/rippled.service /opt/rippled_bld/pkg/debian/ - -COPY packaging/dpkg/build_dpkg.sh ./ -RUN update-alternatives --set gcc /usr/bin/gcc-8 - -CMD ./build_dpkg.sh - diff --git a/Builds/containers/ubuntu-builder/ubuntu_setup.sh b/Builds/containers/ubuntu-builder/ubuntu_setup.sh deleted file mode 100755 index caf491a9f2d..00000000000 --- a/Builds/containers/ubuntu-builder/ubuntu_setup.sh +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/env bash -set -ex - -source /etc/os-release - -if [[ ${VERSION_ID} =~ ^18\. || ${VERSION_ID} =~ ^16\. ]] ; then - echo "setup for ${PRETTY_NAME}" -else - echo "${VERSION} not supported" - exit 1 -fi - -export DEBIAN_FRONTEND="noninteractive" -echo "Acquire::Retries 3;" > /etc/apt/apt.conf.d/80-retries -echo "Acquire::http::Pipeline-Depth 0;" >> /etc/apt/apt.conf.d/80-retries -echo "Acquire::http::No-Cache true;" >> /etc/apt/apt.conf.d/80-retries -echo "Acquire::BrokenProxy true;" >> /etc/apt/apt.conf.d/80-retries -apt-get update -o Acquire::CompressionTypes::Order::=gz - -apt-get -y update -apt-get -y install apt-utils -apt-get -y install software-properties-common wget -apt-get -y upgrade -if [[ ${VERSION_ID} =~ ^18\. ]] ; then - apt-add-repository -y multiverse - apt-add-repository -y universe -fi -add-apt-repository -y ppa:ubuntu-toolchain-r/test -apt-get -y clean -apt-get -y update - -apt-get -y --fix-missing install \ - make cmake ninja-build \ - protobuf-compiler libprotobuf-dev openssl libssl-dev \ - liblzma-dev libbz2-dev zlib1g-dev \ - libjemalloc-dev \ - python-pip \ - gdb gdbserver \ - libstdc++6 \ - flex bison parallel \ - libicu-dev texinfo \ - java-common javacc \ - dpkg-dev debhelper devscripts fakeroot \ - debmake git-buildpackage dh-make gitpkg debsums gnupg \ - dh-buildinfo dh-make dh-systemd - -apt-get -y install gcc-7 g++-7 -update-alternatives --install \ - /usr/bin/gcc gcc /usr/bin/gcc-7 40 \ - --slave /usr/bin/g++ g++ /usr/bin/g++-7 \ - --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-7 \ - --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-7 \ - --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-7 \ - --slave /usr/bin/gcov gcov /usr/bin/gcov-7 \ - --slave /usr/bin/gcov-tool gcov-tool /usr/bin/gcov-dump-7 \ - --slave /usr/bin/gcov-dump gcov-dump /usr/bin/gcov-tool-7 - -apt-get -y install gcc-8 g++-8 -update-alternatives --install \ - /usr/bin/gcc gcc /usr/bin/gcc-8 20 \ - --slave /usr/bin/g++ g++ /usr/bin/g++-8 \ - --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-8 \ - --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-8 \ - --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-8 \ - --slave /usr/bin/gcov gcov /usr/bin/gcov-8 \ - --slave /usr/bin/gcov-tool gcov-tool /usr/bin/gcov-dump-8 \ - --slave /usr/bin/gcov-dump gcov-dump /usr/bin/gcov-tool-8 -update-alternatives --auto gcc - -update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-7 40 -update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-8 20 -update-alternatives --auto cpp - -if [ "${CI_USE}" = true ] ; then - apt-get -y install gcc-6 g++-6 - update-alternatives --install \ - /usr/bin/gcc gcc /usr/bin/gcc-6 10 \ - --slave /usr/bin/g++ g++ /usr/bin/g++-6 \ - --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-6 \ - --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-6 \ - --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-6 \ - --slave /usr/bin/gcov gcov /usr/bin/gcov-6 \ - --slave /usr/bin/gcov-tool gcov-tool /usr/bin/gcov-dump-6 \ - --slave /usr/bin/gcov-dump gcov-dump /usr/bin/gcov-tool-6 - - apt-get -y install gcc-9 g++-9 - update-alternatives --install \ - /usr/bin/gcc gcc /usr/bin/gcc-9 15 \ - --slave /usr/bin/g++ g++ /usr/bin/g++-9 \ - --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-9 \ - --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-9 \ - --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-9 \ - --slave /usr/bin/gcov gcov /usr/bin/gcov-9 \ - --slave /usr/bin/gcov-tool gcov-tool /usr/bin/gcov-dump-9 \ - --slave /usr/bin/gcov-dump gcov-dump /usr/bin/gcov-tool-9 -fi - -if [[ ${VERSION_ID} =~ ^18\. ]] ; then - apt-get -y install binutils -elif [[ ${VERSION_ID} =~ ^16\. ]] ; then - apt-get -y install python-software-properties binutils-gold -fi - -wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - -if [[ ${VERSION_ID} =~ ^18\. ]] ; then - cat << EOF > /etc/apt/sources.list.d/llvm.list -deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main -deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic main -deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main -deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main -deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main -deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main -deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main -deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main -EOF -elif [[ ${VERSION_ID} =~ ^16\. ]] ; then - cat << EOF > /etc/apt/sources.list.d/llvm.list -deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial main -deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial main -deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main -deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main -deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main -deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main -deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main -deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main -EOF -fi -apt-get -y update - -apt-get -y install \ - clang-7 libclang-common-7-dev libclang-7-dev libllvm7 llvm-7 \ - llvm-7-dev llvm-7-runtime clang-format-7 python-clang-7 \ - lld-7 libfuzzer-7-dev libc++-7-dev -update-alternatives --install \ - /usr/bin/clang clang /usr/bin/clang-7 40 \ - --slave /usr/bin/clang++ clang++ /usr/bin/clang++-7 \ - --slave /usr/bin/llvm-profdata llvm-profdata /usr/bin/llvm-profdata-7 \ - --slave /usr/bin/asan-symbolize asan-symbolize /usr/bin/asan_symbolize-7 \ - --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-7 \ - --slave /usr/bin/clang-format clang-format /usr/bin/clang-format-7 \ - --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-7 \ - --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-7 \ - --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-7 -apt-get -y install \ - clang-8 libclang-common-8-dev libclang-8-dev libllvm8 llvm-8 \ - llvm-8-dev llvm-8-runtime clang-format-8 python-clang-8 \ - lld-8 libfuzzer-8-dev libc++-8-dev -update-alternatives --install \ - /usr/bin/clang clang /usr/bin/clang-8 20 \ - --slave /usr/bin/clang++ clang++ /usr/bin/clang++-8 \ - --slave /usr/bin/llvm-profdata llvm-profdata /usr/bin/llvm-profdata-8 \ - --slave /usr/bin/asan-symbolize asan-symbolize /usr/bin/asan_symbolize-8 \ - --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-8 \ - --slave /usr/bin/clang-format clang-format /usr/bin/clang-format-8 \ - --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-8 \ - --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-8 \ - --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-8 -update-alternatives --auto clang - -if [ "${CI_USE}" = true ] ; then - apt-get -y install \ - clang-5.0 libclang-common-5.0-dev libclang-5.0-dev libllvm5.0 llvm-5.0 \ - llvm-5.0-dev llvm-5.0-runtime clang-format-5.0 python-clang-5.0 \ - lld-5.0 libfuzzer-5.0-dev - update-alternatives --install \ - /usr/bin/clang clang /usr/bin/clang-5.0 10 \ - --slave /usr/bin/clang++ clang++ /usr/bin/clang++-5.0 \ - --slave /usr/bin/llvm-profdata llvm-profdata /usr/bin/llvm-profdata-5.0 \ - --slave /usr/bin/asan-symbolize asan-symbolize /usr/bin/asan_symbolize-5.0 \ - --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-5.0 \ - --slave /usr/bin/clang-format clang-format /usr/bin/clang-format-5.0 \ - --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-5.0 \ - --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-5.0 \ - --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-5.0 - - apt-get -y install \ - clang-6.0 libclang-common-6.0-dev libclang-6.0-dev libllvm6.0 llvm-6.0 \ - llvm-6.0-dev llvm-6.0-runtime clang-format-6.0 python-clang-6.0 \ - lld-6.0 libfuzzer-6.0-dev - update-alternatives --install \ - /usr/bin/clang clang /usr/bin/clang-6.0 12 \ - --slave /usr/bin/clang++ clang++ /usr/bin/clang++-6.0 \ - --slave /usr/bin/llvm-profdata llvm-profdata /usr/bin/llvm-profdata-6.0 \ - --slave /usr/bin/asan-symbolize asan-symbolize /usr/bin/asan_symbolize-6.0 \ - --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-6.0 \ - --slave /usr/bin/clang-format clang-format /usr/bin/clang-format-6.0 \ - --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-6.0 \ - --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-6.0 \ - --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-6.0 - - apt-get -y install \ - clang-9 libclang-common-9-dev libclang-9-dev libllvm9 llvm-9 \ - llvm-9-dev llvm-9-runtime clang-format-9 python-clang-9 \ - lld-9 libfuzzer-9-dev libc++-9-dev - update-alternatives --install \ - /usr/bin/clang clang /usr/bin/clang-9 20 \ - --slave /usr/bin/clang++ clang++ /usr/bin/clang++-9 \ - --slave /usr/bin/llvm-profdata llvm-profdata /usr/bin/llvm-profdata-9 \ - --slave /usr/bin/asan-symbolize asan-symbolize /usr/bin/asan_symbolize-9 \ - --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-9 \ - --slave /usr/bin/clang-format clang-format /usr/bin/clang-format-9 \ - --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-9 \ - --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-9 \ - --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-9 - - # only install latest lldb - apt-get -y install lldb-9 python-lldb-9 liblldb-9-dev - update-alternatives --install \ - /usr/bin/lldb lldb /usr/bin/lldb-9 50 \ - --slave /usr/bin/lldb-server lldb-server /usr/bin/lldb-server-9 \ - --slave /usr/bin/lldb-argdumper lldb-argdumper /usr/bin/lldb-argdumper-9 \ - --slave /usr/bin/lldb-instr lldb-instr /usr/bin/lldb-instr-9 \ - --slave /usr/bin/lldb-mi lldb-mi /usr/bin/lldb-mi-9 - update-alternatives --auto clang -fi - -apt-get -y autoremove - diff --git a/Builds/levelization/README.md b/Builds/levelization/README.md new file mode 100644 index 00000000000..4ff3a54236a --- /dev/null +++ b/Builds/levelization/README.md @@ -0,0 +1,114 @@ +# Levelization + +Levelization is the term used to describe efforts to prevent rippled from +having or creating cyclic dependencies. + +rippled code is organized into directories under `src/rippled` (and +`src/test`) representing modules. The modules are intended to be +organized into "tiers" or "levels" such that a module from one level can +only include code from lower levels. Additionally, a module +in one level should never include code in an `impl` folder of any level +other than it's own. + +Unfortunately, over time, enforcement of levelization has been +inconsistent, so the current state of the code doesn't necessarily +reflect these rules. Whenever possible, developers should refactor any +levelization violations they find (by moving files or individual +classes). At the very least, don't make things worse. + +The table below summarizes the _desired_ division of modules, based on the +state of the rippled code when it was created. The levels are numbered from +the bottom up with the lower level, lower numbered, more independent +modules listed first, and the higher level, higher numbered modules with +more dependencies listed later. + +**tl;dr:** The modules listed first are more independent than the modules +listed later. + +| Level / Tier | Module(s) | +|--------------|-----------------------------------------------| +| 01 | ripple/beast ripple/unity +| 02 | ripple/basics +| 03 | ripple/json ripple/crypto +| 04 | ripple/protocol +| 05 | ripple/core ripple/conditions ripple/consensus ripple/resource ripple/server +| 06 | ripple/peerfinder ripple/ledger ripple/nodestore ripple/net +| 07 | ripple/shamap ripple/overlay +| 08 | ripple/app +| 09 | ripple/rpc +| 10 | ripple/perflog +| 11 | test/jtx test/beast test/csf +| 12 | test/unit_test +| 13 | test/crypto test/conditions test/json test/resource test/shamap test/peerfinder test/basics test/overlay +| 14 | test +| 15 | test/net test/protocol test/ledger test/consensus test/core test/server test/nodestore +| 16 | test/rpc test/app + +(Note that `test` levelization is *much* less important and *much* less +strictly enforced than `ripple` levelization, other than the requirement +that `test` code should *never* be included in `ripple` code.) + +## Validation + +The [levelization.sh](levelization.sh) script takes no parameters, +reads no environment variables, and can be run from any directory, +as long as it is in the expected location in the rippled repo. +It can be run at any time from within a checked out repo, and will +do an analysis of all the `#include`s in +the rippled source. The only caveat is that it runs much slower +under Windows than in Linux. It hasn't yet been tested under MacOS. +It generates many files of [results](results): + +* `rawincludes.txt`: The raw dump of the `#includes` +* `paths.txt`: A second dump grouping the source module + to the destination module, deduped, and with frequency counts. +* `includes/`: A directory where each file represents a module and + contains a list of modules and counts that the module _includes_. +* `includedby/`: Similar to `includes/`, but the other way around. Each + file represents a module and contains a list of modules and counts + that _include_ the module. +* [`loops.txt`](results/loops.txt): A list of direct loops detected + between modules as they actually exist, as opposed to how they are + desired as described above. In a perfect repo, this file will be + empty. + This file is committed to the repo, and is used by the [levelization + Github workflow](../../.github/workflows/levelization.yml) to validate + that nothing changed. +* [`ordering.txt`](results/ordering.txt): A list showing relationships + between modules where there are no loops as they actually exist, as + opposed to how they are desired as described above. + This file is committed to the repo, and is used by the [levelization + Github workflow](../../.github/workflows/levelization.yml) to validate + that nothing changed. +* [`levelization.yml`](../../.github/workflows/levelization.yml) + Github Actions workflow to test that levelization loops haven't + changed. Unfortunately, if changes are detected, it can't tell if + they are improvements or not, so if you have resolved any issues or + done anything else to improve levelization, run `levelization.sh`, + and commit the updated results. + +The `loops.txt` and `ordering.txt` files relate the modules +using comparison signs, which indicate the number of times each +module is included in the other. + +* `A > B` means that A should probably be at a higher level than B, + because B is included in A significantly more than A is included in B. + These results can be included in both `loops.txt` and `ordering.txt`. + Because `ordering.txt`only includes relationships where B is not + included in A at all, it will only include these types of results. +* `A ~= B` means that A and B are included in each other a different + number of times, but the values are so close that the script can't + definitively say that one should be above the other. These results + will only be included in `loops.txt`. +* `A == B` means that A and B include each other the same number of + times, so the script has no clue which should be higher. These results + will only be included in `loops.txt`. + +The committed files hide the detailed values intentionally, to +prevent false alarms and merging issues, and because it's easy to +get those details locally. + +1. Run `levelization.sh` +2. Grep the modules in `paths.txt`. + * For example, if a cycle is found `A ~= B`, simply `grep -w + A Builds/levelization/results/paths.txt | grep -w B` diff --git a/Builds/levelization/levelization.sh b/Builds/levelization/levelization.sh new file mode 100755 index 00000000000..c18ca703f78 --- /dev/null +++ b/Builds/levelization/levelization.sh @@ -0,0 +1,130 @@ +#!/bin/bash + +# Usage: levelization.sh +# This script takes no parameters, reads no environment variables, +# and can be run from any directory, as long as it is in the expected +# location in the repo. + +pushd $( dirname $0 ) + +if [ -v PS1 ] +then + # if the shell is interactive, clean up any flotsam before analyzing + git clean -ix +fi + +# Ensure all sorting is ASCII-order consistently across platforms. +export LANG=C + +rm -rfv results +mkdir results +includes="$( pwd )/results/rawincludes.txt" +pushd ../.. +echo Raw includes: +grep -r '^[ ]*#include.*/.*\.h' include src | \ + grep -v boost | tee ${includes} +popd +pushd results + +oldifs=${IFS} +IFS=: +mkdir includes +mkdir includedby +echo Build levelization paths +exec 3< ${includes} # open rawincludes.txt for input +while read -r -u 3 file include +do + level=$( echo ${file} | cut -d/ -f 2,3 ) + # If the "level" indicates a file, cut off the filename + if [[ "${level##*.}" != "${level}" ]] + then + # Use the "toplevel" label as a workaround for `sort` + # inconsistencies between different utility versions + level="$( dirname ${level} )/toplevel" + fi + level=$( echo ${level} | tr '/' '.' ) + + includelevel=$( echo ${include} | sed 's/.*["<]//; s/[">].*//' | \ + cut -d/ -f 1,2 ) + if [[ "${includelevel##*.}" != "${includelevel}" ]] + then + # Use the "toplevel" label as a workaround for `sort` + # inconsistencies between different utility versions + includelevel="$( dirname ${includelevel} )/toplevel" + fi + includelevel=$( echo ${includelevel} | tr '/' '.' ) + + if [[ "$level" != "$includelevel" ]] + then + echo $level $includelevel | tee -a paths.txt + fi +done +echo Sort and dedup paths +sort -ds paths.txt | uniq -c | tee sortedpaths.txt +mv sortedpaths.txt paths.txt +exec 3>&- #close fd 3 +IFS=${oldifs} +unset oldifs + +echo Split into flat-file database +exec 4&- #close fd 4 + +loops="$( pwd )/loops.txt" +ordering="$( pwd )/ordering.txt" +pushd includes +echo Search for loops +# Redirect stdout to a file +exec 4>&1 +exec 1>"${loops}" +for source in * +do + if [[ -f "$source" ]] + then + exec 5<"${source}" # open for input + while read -r -u 5 include includefreq + do + if [[ -f $include ]] + then + if grep -q -w $source $include + then + if grep -q -w "Loop: $include $source" "${loops}" + then + continue + fi + sourcefreq=$( grep -w $source $include | cut -d\ -f2 ) + echo "Loop: $source $include" + # If the counts are close, indicate that the two modules are + # on the same level, though they shouldn't be + if [[ $(( $includefreq - $sourcefreq )) -gt 3 ]] + then + echo -e " $source > $include\n" + elif [[ $(( $sourcefreq - $includefreq )) -gt 3 ]] + then + echo -e " $include > $source\n" + elif [[ $sourcefreq -eq $includefreq ]] + then + echo -e " $include == $source\n" + else + echo -e " $include ~= $source\n" + fi + else + echo "$source > $include" >> "${ordering}" + fi + fi + done + exec 5>&- #close fd 5 + fi +done +exec 1>&4 #close fd 1 +exec 4>&- #close fd 4 +cat "${ordering}" +cat "${loops}" +popd +popd +popd diff --git a/Builds/levelization/results/loops.txt b/Builds/levelization/results/loops.txt new file mode 100644 index 00000000000..df1d273f93b --- /dev/null +++ b/Builds/levelization/results/loops.txt @@ -0,0 +1,42 @@ +Loop: test.jtx test.toplevel + test.toplevel > test.jtx + +Loop: test.jtx test.unit_test + test.unit_test == test.jtx + +Loop: xrpld.app xrpld.core + xrpld.app > xrpld.core + +Loop: xrpld.app xrpld.ledger + xrpld.app > xrpld.ledger + +Loop: xrpld.app xrpld.net + xrpld.app > xrpld.net + +Loop: xrpld.app xrpld.overlay + xrpld.overlay > xrpld.app + +Loop: xrpld.app xrpld.peerfinder + xrpld.peerfinder ~= xrpld.app + +Loop: xrpld.app xrpld.rpc + xrpld.rpc > xrpld.app + +Loop: xrpld.app xrpld.shamap + xrpld.app > xrpld.shamap + +Loop: xrpld.core xrpld.net + xrpld.net > xrpld.core + +Loop: xrpld.core xrpld.perflog + xrpld.perflog == xrpld.core + +Loop: xrpld.net xrpld.rpc + xrpld.rpc ~= xrpld.net + +Loop: xrpld.overlay xrpld.rpc + xrpld.rpc ~= xrpld.overlay + +Loop: xrpld.perflog xrpld.rpc + xrpld.rpc ~= xrpld.perflog + diff --git a/Builds/levelization/results/ordering.txt b/Builds/levelization/results/ordering.txt new file mode 100644 index 00000000000..eca7fc6dc29 --- /dev/null +++ b/Builds/levelization/results/ordering.txt @@ -0,0 +1,196 @@ +libxrpl.basics > xrpl.basics +libxrpl.crypto > xrpl.basics +libxrpl.json > xrpl.basics +libxrpl.json > xrpl.json +libxrpl.protocol > xrpl.basics +libxrpl.protocol > xrpl.json +libxrpl.protocol > xrpl.protocol +libxrpl.resource > xrpl.basics +libxrpl.resource > xrpl.json +libxrpl.resource > xrpl.resource +libxrpl.server > xrpl.basics +libxrpl.server > xrpl.json +libxrpl.server > xrpl.protocol +libxrpl.server > xrpl.server +test.app > test.jtx +test.app > test.rpc +test.app > test.toplevel +test.app > test.unit_test +test.app > xrpl.basics +test.app > xrpld.app +test.app > xrpld.core +test.app > xrpld.ledger +test.app > xrpld.nodestore +test.app > xrpld.overlay +test.app > xrpld.rpc +test.app > xrpl.json +test.app > xrpl.protocol +test.app > xrpl.resource +test.basics > test.jtx +test.basics > test.unit_test +test.basics > xrpl.basics +test.basics > xrpld.perflog +test.basics > xrpld.rpc +test.basics > xrpl.json +test.basics > xrpl.protocol +test.beast > xrpl.basics +test.conditions > xrpl.basics +test.conditions > xrpld.conditions +test.consensus > test.csf +test.consensus > test.toplevel +test.consensus > test.unit_test +test.consensus > xrpl.basics +test.consensus > xrpld.app +test.consensus > xrpld.consensus +test.consensus > xrpld.ledger +test.consensus > xrpl.json +test.core > test.jtx +test.core > test.toplevel +test.core > test.unit_test +test.core > xrpl.basics +test.core > xrpld.core +test.core > xrpld.perflog +test.core > xrpl.json +test.core > xrpl.server +test.csf > xrpl.basics +test.csf > xrpld.consensus +test.csf > xrpl.json +test.csf > xrpl.protocol +test.json > test.jtx +test.json > xrpl.json +test.jtx > xrpl.basics +test.jtx > xrpld.app +test.jtx > xrpld.core +test.jtx > xrpld.ledger +test.jtx > xrpld.net +test.jtx > xrpld.rpc +test.jtx > xrpl.json +test.jtx > xrpl.protocol +test.jtx > xrpl.resource +test.jtx > xrpl.server +test.ledger > test.jtx +test.ledger > test.toplevel +test.ledger > xrpl.basics +test.ledger > xrpld.app +test.ledger > xrpld.core +test.ledger > xrpld.ledger +test.ledger > xrpl.protocol +test.nodestore > test.jtx +test.nodestore > test.toplevel +test.nodestore > test.unit_test +test.nodestore > xrpl.basics +test.nodestore > xrpld.core +test.nodestore > xrpld.nodestore +test.nodestore > xrpld.unity +test.overlay > test.jtx +test.overlay > test.toplevel +test.overlay > test.unit_test +test.overlay > xrpl.basics +test.overlay > xrpld.app +test.overlay > xrpld.overlay +test.overlay > xrpld.peerfinder +test.overlay > xrpld.shamap +test.overlay > xrpl.protocol +test.peerfinder > test.beast +test.peerfinder > test.unit_test +test.peerfinder > xrpl.basics +test.peerfinder > xrpld.core +test.peerfinder > xrpld.peerfinder +test.peerfinder > xrpl.protocol +test.protocol > test.toplevel +test.protocol > xrpl.basics +test.protocol > xrpl.json +test.protocol > xrpl.protocol +test.resource > test.unit_test +test.resource > xrpl.basics +test.resource > xrpl.resource +test.rpc > test.jtx +test.rpc > test.toplevel +test.rpc > xrpl.basics +test.rpc > xrpld.app +test.rpc > xrpld.core +test.rpc > xrpld.net +test.rpc > xrpld.overlay +test.rpc > xrpld.rpc +test.rpc > xrpl.json +test.rpc > xrpl.protocol +test.rpc > xrpl.resource +test.server > test.jtx +test.server > test.toplevel +test.server > test.unit_test +test.server > xrpl.basics +test.server > xrpld.app +test.server > xrpld.core +test.server > xrpld.rpc +test.server > xrpl.json +test.server > xrpl.server +test.shamap > test.unit_test +test.shamap > xrpl.basics +test.shamap > xrpld.nodestore +test.shamap > xrpld.shamap +test.shamap > xrpl.protocol +test.toplevel > test.csf +test.toplevel > xrpl.json +test.unit_test > xrpl.basics +xrpl.json > xrpl.basics +xrpl.protocol > xrpl.basics +xrpl.protocol > xrpl.json +xrpl.resource > xrpl.basics +xrpl.resource > xrpl.json +xrpl.resource > xrpl.protocol +xrpl.server > xrpl.basics +xrpl.server > xrpl.json +xrpl.server > xrpl.protocol +xrpld.app > test.unit_test +xrpld.app > xrpl.basics +xrpld.app > xrpld.conditions +xrpld.app > xrpld.consensus +xrpld.app > xrpld.nodestore +xrpld.app > xrpld.perflog +xrpld.app > xrpl.json +xrpld.app > xrpl.protocol +xrpld.app > xrpl.resource +xrpld.conditions > xrpl.basics +xrpld.conditions > xrpl.protocol +xrpld.consensus > xrpl.basics +xrpld.consensus > xrpl.json +xrpld.consensus > xrpl.protocol +xrpld.core > xrpl.basics +xrpld.core > xrpl.json +xrpld.core > xrpl.protocol +xrpld.ledger > xrpl.basics +xrpld.ledger > xrpl.json +xrpld.ledger > xrpl.protocol +xrpld.net > xrpl.basics +xrpld.net > xrpl.json +xrpld.net > xrpl.protocol +xrpld.net > xrpl.resource +xrpld.nodestore > xrpl.basics +xrpld.nodestore > xrpld.core +xrpld.nodestore > xrpld.unity +xrpld.nodestore > xrpl.json +xrpld.nodestore > xrpl.protocol +xrpld.overlay > xrpl.basics +xrpld.overlay > xrpld.core +xrpld.overlay > xrpld.peerfinder +xrpld.overlay > xrpld.perflog +xrpld.overlay > xrpl.json +xrpld.overlay > xrpl.protocol +xrpld.overlay > xrpl.resource +xrpld.overlay > xrpl.server +xrpld.peerfinder > xrpl.basics +xrpld.peerfinder > xrpld.core +xrpld.peerfinder > xrpl.protocol +xrpld.perflog > xrpl.basics +xrpld.perflog > xrpl.json +xrpld.rpc > xrpl.basics +xrpld.rpc > xrpld.core +xrpld.rpc > xrpld.ledger +xrpld.rpc > xrpld.nodestore +xrpld.rpc > xrpl.json +xrpld.rpc > xrpl.protocol +xrpld.rpc > xrpl.resource +xrpld.rpc > xrpl.server +xrpld.shamap > xrpl.basics +xrpld.shamap > xrpld.nodestore +xrpld.shamap > xrpl.protocol diff --git a/Builds/linux/README.md b/Builds/linux/README.md deleted file mode 100644 index bb91eba85cb..00000000000 --- a/Builds/linux/README.md +++ /dev/null @@ -1,238 +0,0 @@ -# Linux Build Instructions - -This document focuses on building rippled for development purposes under recent -Ubuntu linux distributions. To build rippled for Redhat, Fedora or Centos -builds, including docker based builds for those distributions, please consult -the [rippled-package-builder](https://github.com/ripple/rippled-package-builder) -repository. - -Note: Ubuntu 16.04 users may need to update their compiler (see the dependencies -section). For non Ubuntu distributions, the steps below should work be -installing the appropriate dependencies using that distribution's package -management tools. - -## Dependencies - -gcc-7 or later is required. - -Use `apt-get` to install the dependencies provided by the distribution - -``` -$ apt-get update -$ apt-get install -y gcc g++ wget git cmake protobuf-compiler libprotobuf-dev libssl-dev -``` - -Advanced users can choose to install newer versions of gcc, or the clang compiler. -At this time, rippled only supports protobuf version 2. Using version 3 of -protobuf will give errors. - -### Build Boost - -Boost 1.70 or later is required. We recommend downloading and compiling boost -with the following process: After changing to the directory where -you wish to download and compile boost, run - -``` -$ wget https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.gz -$ tar -xzf boost_1_70_0.tar.gz -$ cd boost_1_70_0 -$ ./bootstrap.sh -$ ./b2 headers -$ ./b2 -j -``` - -### (Optional) Dependencies for Building Source Documentation - -Source code documentation is not required for running/debugging rippled. That -said, the documentation contains some helpful information about specific -components of the application. For more information on how to install and run -the necessary components, see [this document](../../docs/README.md) - -## Build - -### Clone the rippled repository - -From a shell: - -``` -git clone git@github.com:ripple/rippled.git -cd rippled -``` - -For a stable release, choose the `master` branch or one of the tagged releases -listed on [GitHub](https://github.com/ripple/rippled/releases). - -``` -git checkout master -``` - -or to test the latest release candidate, choose the `release` branch. - -``` -git checkout release -``` - -If you are doing development work and want the latest set of untested -features, you can consider using the `develop` branch instead. - -``` -git checkout develop -``` - -### Configure Library Paths - -If you didn't persistently set the `BOOST_ROOT` environment variable to the -directory in which you compiled boost, then you should set it temporarily. - -For example, you built Boost in your home directory `~/boost_1_70_0`, you -would do for any shell in which you want to build: - -``` -export BOOST_ROOT=~/boost_1_70_0 -``` - -Alternatively, you can add `DBOOST_ROOT=~/boost_1_70_0` to the command line when -invoking `cmake`. - -### Generate Configuration - -All builds should be done in a separate directory from the source tree root -(a subdirectory is fine). For example, from the root of the ripple source tree: - -``` -mkdir my_build -cd my_build -``` - -followed by: - -``` -cmake -DCMAKE_BUILD_TYPE=Debug .. -``` - -If your operating system does not provide static libraries (Arch Linux, and -Manjaro Linux, for example), you must configure a non-static build by adding -`-Dstatic=OFF` to the above cmake line. - -`CMAKE_BUILD_TYPE` can be changed as desired for `Debug` vs. -`Release` builds (all four standard cmake build types are supported). - -To select a different compiler (most likely gcc will be found by default), pass -`-DCMAKE_C_COMPILER=` and -`-DCMAKE_CXX_COMPILER=` when configuring. If you prefer, -you can instead set `CC` and `CXX` environment variables which cmake will honor. - -#### Options During Configuration: - -The CMake file defines a number of configure-time options which can be -examined by running `cmake-gui` or `ccmake` to generated the build. In -particular, the `unity` option allows you to select between the unity and -non-unity builds. `unity` builds are faster to compile since they combine -multiple sources into a single compiliation unit - this is the default if you -don't specify. `nounity` builds can be helpful for detecting include omissions -or for finding other build-related issues, but aren't generally needed for -testing and running. - -* `-Dunity=ON` to enable/disable unity builds (defaults to ON) -* `-Dassert=ON` to enable asserts -* `-Djemalloc=ON` to enable jemalloc support for heap checking -* `-Dsan=thread` to enable the thread sanitizer with clang -* `-Dsan=address` to enable the address sanitizer with clang -* `-Dstatic=ON` to enable static linking library dependencies - -Several other infrequently used options are available - run `ccmake` or -`cmake-gui` for a list of all options. - -### Build - -Once you have generated the build system, you can run the build via cmake: - -``` -cmake --build . -- -j -``` - -the `-j` parameter in this example tells the build tool to compile several -files in parallel. This value should be chosen roughly based on the number of -cores you have available and/or want to use for building. - -When the build completes succesfully, you will have a `rippled` executable in -the current directory, which can be used to connect to the network (when -properly configured) or to run unit tests. - - -#### Optional Installation - -The rippled cmake build supports an installation target that will install -rippled as well as a support library that can be used to sign transactions. In -order to build and install the files, specify the `install` target when -building, e.g.: - -``` -cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/opt/local .. -cmake --build . --target install -- -j -``` - -We recommend specifying `CMAKE_INSTALL_PREFIX` when configuring in order to -explicitly control the install location for your files. Without this setting, -cmake will typically install in `/usr/local`. It is also possible to "rehome" -the installation by specifying the `DESTDIR` env variable during the install phase, -e.g.: - -``` -DESTDIR=~/mylibs cmake --build . --target install -- -j -``` - -in which case, the files would be installed in the `CMAKE_INSTALL_PREFIX` within -the specified `DESTDIR` path. - -#### Signing Library - -If you want to use the signing support library to create an application, there -are two simple mechanisms with cmake + git that facilitate this. - -With either option below, you will have access to a library from the -rippled project that you can link to in your own project's CMakeLists.txt, e.g.: - -``` -target_link_libraries (my-signing-app Ripple::xrpl_core) -``` - -##### Option 1: git submodules + add_subdirectory - -First, add the rippled repo as a submodule to your project repo: - -``` -git submodule add -b master https://github.com/ripple/rippled.git vendor/rippled -``` - -change the `vendor/rippled` path as desired for your repo layout. Furthermore, -change the branch name if you want to track a different rippled branch, such -as `develop`. - -Second, to bring this submodule into your project, just add the rippled subdirectory: - -``` -add_subdirectory (vendor/rippled) -``` - -##### Option 2: installed rippled + find_package - -First, follow the "Optional Installation" instructions above to -build and install the desired version of rippled. - -To make use of the installed files, add the following to your CMakeLists.txt file: - -``` -set (CMAKE_MODULE_PATH /opt/local/lib/cmake/ripple ${CMAKE_MODULE_PATH}) -find_package(Ripple REQUIRED) -``` - -change the `/opt/local` module path above to match your chosen installation prefix. - -## Unit Tests (Recommended) - -`rippled` builds a set of unit tests into the server executable. To run these unit -tests after building, pass the `--unittest` option to the compiled `rippled` -executable. The executable will exit with summary info after running the unit tests. - - diff --git a/Builds/macos/README.md b/Builds/macos/README.md deleted file mode 100644 index 5bc0b7c2c71..00000000000 --- a/Builds/macos/README.md +++ /dev/null @@ -1,231 +0,0 @@ -# macos Build Instructions - -## Important - -We don't recommend macos for rippled production use at this time. Currently, the -Ubuntu platform has received the highest level of quality assurance and -testing. That said, macos is suitable for many development/test tasks. - -## Prerequisites - -You'll need macos 10.8 or later. - -To clone the source code repository, create branches for inspection or -modification, build rippled using clang, and run the system tests you will need -these software components: - -* [XCode](https://developer.apple.com/xcode/) -* [Homebrew](http://brew.sh/) -* [Boost](http://boost.org/) -* other misc utilities and libraries installed via homebrew - -## Install Software - -### Install XCode - -If not already installed on your system, download and install XCode using the -appstore or by using [this link](https://developer.apple.com/xcode/). - -For more info, see "Step 1: Download and Install the Command Line Tools" -[here](http://www.moncefbelyamani.com/how-to-install-xcode-homebrew-git-rvm-ruby-on-mac) - -The command line tools can be installed through the terminal with the command: - -``` -xcode-select --install -``` - -### Install Homebrew - -> "[Homebrew](http://brew.sh/) installs the stuff you need that Apple didn’t." - -Open a terminal and type: - -``` -ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" -``` - -For more info, see "Step 2: Install Homebrew" -[here](http://www.moncefbelyamani.com/how-to-install-xcode-homebrew-git-rvm-ruby-on-mac#step-2) - -### Install Dependencies Using Homebrew - -`brew` will generally install the latest stable version of any package, which -should satisfy the the minimum version requirements for rippled. - -``` -brew update -brew install git cmake pkg-config protobuf openssl ninja -``` - -### Build Boost - -Boost 1.70 or later is required. - -We want to compile boost with clang/libc++ - -Download [a release](https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.bz2) - -Extract it to a folder, making note of where, open a terminal, then: - -``` -./bootstrap.sh -./b2 cxxflags="-std=c++14" visibility=global -``` - -Create an environment variable `BOOST_ROOT` in one of your `rc` files, pointing -to the root of the extracted directory. - -### Dependencies for Building Source Documentation - -Source code documentation is not required for running/debugging rippled. That -said, the documentation contains some helpful information about specific -components of the application. For more information on how to install and run -the necessary components, see [this document](../../docs/README.md) - -## Build - -### Clone the rippled repository - -From a shell: - -``` -git clone git@github.com:ripple/rippled.git -cd rippled -``` - -For a stable release, choose the `master` branch or one of the tagged releases -listed on [GitHub](https://github.com/ripple/rippled/releases GitHub). - -``` -git checkout master -``` - -or to test the latest release candidate, choose the `release` branch. - -``` -git checkout release -``` - -If you are doing development work and want the latest set of untested -features, you can consider using the `develop` branch instead. - -``` -git checkout develop -``` - -### Configure Library Paths - -If you didn't persistently set the `BOOST_ROOT` environment variable to the -root of the extracted directory above, then you should set it temporarily. - -For example, assuming your username were `Abigail` and you extracted Boost -1.70.0 in `/Users/Abigail/Downloads/boost_1_70_0`, you would do for any -shell in which you want to build: - -``` -export BOOST_ROOT=/Users/Abigail/Downloads/boost_1_70_0 -``` - -### Generate and Build - -For simple command line building we recommend using the *Unix Makefile* or -*Ninja* generator with cmake. All builds should be done in a separate directory -from the source tree root (a subdirectory is fine). For example, from the root -of the ripple source tree: - -``` -mkdir my_build -cd my_build -``` - -followed by: - -``` -cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug .. -``` - -or - -``` -cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug .. -``` - -`CMAKE_BUILD_TYPE` can be changed as desired for `Debug` vs. -`Release` builds (all four standard cmake build types are supported). - -Once you have generated the build system, you can run the build via cmake: - -``` -cmake --build . -- -j 4 -``` - -the `-j` parameter in this example tells the build tool to compile several -files in parallel. This value should be chosen roughly based on the number of -cores you have available and/or want to use for building. - -When the build completes succesfully, you will have a `rippled` executable in -the current directory, which can be used to connect to the network (when -properly configured) or to run unit tests. - -If you prefer to have an XCode project to use for building, ask CMake to -generate that instead: - -``` -cmake -GXcode .. -``` - -After generation succeeds, the xcode project file can be opened and used to -build/debug. However, just as with other generators, cmake knows how to build -using the xcode project as well: - -``` -cmake --build . -- -jobs 4 -``` - -This will invoke the `xcodebuild` utility to compile the project. See `xcodebuild ---help` for details about build options. - -#### Optional installation - -If you'd like to install the artifacts of the build, we have preliminary -support for standard CMake installation targets. We recommend explicitly -setting the installation location when configuring, e.g.: - -``` -cmake -DCMAKE_INSTALL_PREFIX=/opt/local .. -``` - -(change the destination as desired), and then build the `install` target: - -``` -cmake --build . --target install -- -jobs 4 -``` - -#### Options During Configuration: - -The CMake file defines a number of configure-time options which can be -examined by running `cmake-gui` or `ccmake` to generated the build. In -particular, the `unity` option allows you to select between the unity and -non-unity builds. `unity` builds are faster to compile since they combine -multiple sources into a single compiliation unit - this is the default if you -don't specify. `nounity` builds can be helpful for detecting include omissions -or for finding other build-related issues, but aren't generally needed for -testing and running. - -* `-Dunity=ON` to enable/disable unity builds (defaults to ON) -* `-Dassert=ON` to enable asserts -* `-Djemalloc=ON` to enable jemalloc support for heap checking -* `-Dsan=thread` to enable the thread sanitizer with clang -* `-Dsan=address` to enable the address sanitizer with clang - -Several other infrequently used options are available - run `ccmake` or -`cmake-gui` for a list of all options. - -## Unit Tests (Recommended) - -`rippled` builds a set of unit tests into the server executable. To run these unit -tests after building, pass the `--unittest` option to the compiled `rippled` -executable. The executable will exit with summary info after running the unit tests. - - diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e4204e2cb3..03dba51d0c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,33 +1,58 @@ -cmake_minimum_required (VERSION 3.9.0) -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Builds/CMake") -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Builds/CMake/deps") +cmake_minimum_required(VERSION 3.16) + +if(POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +endif() +if(POLICY CMP0077) + cmake_policy(SET CMP0077 NEW) +endif() + +# Fix "unrecognized escape" issues when passing CMAKE_MODULE_PATH on Windows. +file(TO_CMAKE_PATH "${CMAKE_MODULE_PATH}" CMAKE_MODULE_PATH) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +project(xrpl) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# make GIT_COMMIT_HASH define available to all sources +find_package(Git) +if(Git_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse HEAD + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gch) + if(gch) + set(GIT_COMMIT_HASH "${gch}") + message(STATUS gch: ${GIT_COMMIT_HASH}) + add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}") + endif() + + execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse --abbrev-ref HEAD + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gb) + if(gb) + set(GIT_BRANCH "${gb}") + message(STATUS gb: ${GIT_BRANCH}) + add_definitions(-DGIT_BRANCH="${GIT_BRANCH}") + endif() +endif() #git + +if(thread_safety_analysis) + add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DRIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS) + add_compile_options("-stdlib=libc++") + add_link_options("-stdlib=libc++") +endif() include (CheckCXXCompilerFlag) -if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.11) - include (FetchContent) -endif () -if (MSVC AND CMAKE_VERSION VERSION_LESS 3.12) - message (FATAL_ERROR "MSVC requires cmake 3.12 or greater for proper boost support") -endif () +include (FetchContent) include (ExternalProject) include (CMakeFuncs) # must come *after* ExternalProject b/c it overrides one function in EP -include (ProcessorCount) if (target) - message (WARNING - "The target option is deprecated and will be removed in a future release") - parse_target() -endif () -project (rippled) - -if (POLICY CMP0074) - cmake_policy(SET CMP0074 NEW) + message (FATAL_ERROR "The target option has been removed - use native cmake options to control build") endif () include(RippledSanity) include(RippledVersion) include(RippledSettings) -include(RippledNIH) -include(RippledRelease) # this check has to remain in the top-level cmake # because of the early return statement if (packages_only) @@ -39,27 +64,71 @@ endif () include(RippledCompiler) include(RippledInterface) +option(only_docs "Include only the docs target?" FALSE) +include(RippledDocs) +if(only_docs) + return() +endif() + ### include(deps/Boost) -include(deps/OpenSSL) -include(deps/Secp256k1) -include(deps/Ed25519-donna) -include(deps/Lz4) -include(deps/Libarchive) -include(deps/Sqlite) -include(deps/Soci) -include(deps/Snappy) -include(deps/Rocksdb) -include(deps/Nudb) -include(deps/date) -include(deps/Protobuf) +find_package(OpenSSL 1.1.1 REQUIRED) +set_target_properties(OpenSSL::SSL PROPERTIES + INTERFACE_COMPILE_DEFINITIONS OPENSSL_NO_SSL2 +) +set(SECP256K1_INSTALL TRUE) +add_subdirectory(external/secp256k1) +add_library(secp256k1::secp256k1 ALIAS secp256k1) +add_subdirectory(external/ed25519-donna) +add_subdirectory(external/antithesis-sdk) +find_package(gRPC REQUIRED) +find_package(lz4 REQUIRED) +# Target names with :: are not allowed in a generator expression. +# We need to pull the include directories and imported location properties +# from separate targets. +find_package(LibArchive REQUIRED) +find_package(SOCI REQUIRED) +find_package(SQLite3 REQUIRED) -### +option(rocksdb "Enable RocksDB" ON) +if(rocksdb) + find_package(RocksDB REQUIRED) + set_target_properties(RocksDB::rocksdb PROPERTIES + INTERFACE_COMPILE_DEFINITIONS RIPPLE_ROCKSDB_AVAILABLE=1 + ) + target_link_libraries(ripple_libs INTERFACE RocksDB::rocksdb) +endif() +find_package(nudb REQUIRED) +find_package(date REQUIRED) +find_package(xxHash REQUIRED) + +target_link_libraries(ripple_libs INTERFACE + ed25519::ed25519 + lz4::lz4 + OpenSSL::Crypto + OpenSSL::SSL + secp256k1::secp256k1 + soci::soci + SQLite::SQLite3 +) + +# Work around changes to Conan recipe for now. +if(TARGET nudb::core) + set(nudb nudb::core) +elseif(TARGET NuDB::nudb) + set(nudb NuDB::nudb) +else() + message(FATAL_ERROR "unknown nudb target") +endif() +target_link_libraries(ripple_libs INTERFACE ${nudb}) + +if(coverage) + include(RippledCov) +endif() + +set(PROJECT_EXPORT_SET RippleExports) include(RippledCore) include(RippledInstall) -include(RippledCov) -include(RippledMultiConfig) -include(RippledDocs) include(RippledValidatorKeys) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..cb3eb6f0481 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,1021 @@ +The XRP Ledger has many and diverse stakeholders, and everyone deserves +a chance to contribute meaningful changes to the code that runs the +XRPL. + +# Contributing + +We assume you are familiar with the general practice of [making +contributions on GitHub][contrib]. This file includes only special +instructions specific to this project. + + +## Before you start + +The following branches exist in the main project repository: + +- `develop`: The latest set of unreleased features, and the most common + starting point for contributions. +- `release`: The latest beta release or release candidate. +- `master`: The latest stable release. +- `gh-pages`: The documentation for this project, built by Doxygen. + +The tip of each branch must be signed. In order for GitHub to sign a +squashed commit that it builds from your pull request, GitHub must know +your verifying key. Please set up [signature verification][signing]. + +In general, external contributions should be developed in your personal +[fork][forking]. Contributions from developers with write permissions +should be done in [the main repository][rippled] in a branch with +a permitted prefix. Permitted prefixes are: +* XLS-[a-zA-Z0-9]+/.+ + * e.g. XLS-0033d/mpt-clarify-STEitherAmount +* [GitHub username]/.+ + * e.g. JoelKatz/fix-rpc-webhook-queue +* [Organization name]/.+ + * e.g. ripple/antithesis + +Regardless of where the branch is created, please open a *draft* pull +request as soon as possible after pushing the branch to Github, to +increase visibility, and ease feedback during the development process. + + +## Major contributions + +If your contribution is a major feature or breaking change, then you +must first write an XRP Ledger Standard (XLS) describing it. Go to +[XRPL-Standards](https://github.com/XRPLF/XRPL-Standards/discussions), +choose the next available standard number, and open a discussion with an +appropriate title to propose your draft standard. + +When you submit a pull request, please link the corresponding XLS in the +description. An XLS still in draft status is considered a +work-in-progress and open for discussion. Please allow time for +questions, suggestions, and changes to the XLS draft. It is the +responsibility of the XLS author to update the draft to match the final +implementation when its corresponding pull request is merged, unless the +author delegates that responsibility to others. + + +## Before making a pull request +(Or marking a draft pull request as ready.) + +Changes that alter transaction processing must be guarded by an +[Amendment](https://xrpl.org/amendments.html). +All other changes that maintain the existing behavior do not need an +Amendment. + +Ensure that your code compiles according to the build instructions in +[`BUILD.md`](./BUILD.md). + +Please write tests for your code. +If your test can be run offline, in under 60 seconds, then it can be an +automatic test run by `rippled --unittest`. +Otherwise, it must be a manual test. + +If you create new source files, they must be organized as follows: +* If the files are in any of the `libxrpl` modules, the headers (`.h`) must go + under `include/xrpl`, and source (`.cpp`) files must go under + `src/libxrpl`. +* All other non-test files must go under `src/xrpld`. +* All test source files must go under `src/test`. + +The source must be formatted according to the style guide below. + +Header includes must be [levelized](./Builds/levelization). + +Changes should be usually squashed down into a single commit. +Some larger or more complicated change sets make more sense, +and are easier to review if organized into multiple logical commits. +Either way, all commits should fit the following criteria: +* Changes should be presented in a single commit or a logical + sequence of commits. + Specifically, chronological commits that simply + reflect the history of how the author implemented + the change, "warts and all", are not useful to + reviewers. +* Every commit should have a [good message](#good-commit-messages). + to explain a specific aspects of the change. +* Every commit should be signed. +* Every commit should be well-formed (builds successfully, + unit tests passing), as this helps to resolve merge + conflicts, and makes it easier to use `git bisect` + to find bugs. + +### Good commit messages + +Refer to +["How to Write a Git Commit Message"](https://cbea.ms/git-commit/) +for general rules on writing a good commit message. + +tl;dr +> 1. Separate subject from body with a blank line. +> 2. Limit the subject line to 50 characters. +> * [...]shoot for 50 characters, but consider 72 the hard limit. +> 3. Capitalize the subject line. +> 4. Do not end the subject line with a period. +> 5. Use the imperative mood in the subject line. +> * A properly formed Git commit subject line should always be able +> to complete the following sentence: "If applied, this commit will +> _your subject line here_". +> 6. Wrap the body at 72 characters. +> 7. Use the body to explain what and why vs. how. + +In addition to those guidelines, please add one of the following +prefixes to the subject line if appropriate. +* `fix:` - The primary purpose is to fix an existing bug. +* `perf:` - The primary purpose is performance improvements. +* `refactor:` - The changes refactor code without affecting + functionality. +* `test:` - The changes _only_ affect unit tests. +* `docs:` - The changes _only_ affect documentation. This can + include code comments in addition to `.md` files like this one. +* `build:` - The changes _only_ affect the build process, + including CMake and/or Conan settings. +* `chore:` - Other tasks that don't affect the binary, but don't fit + any of the other cases. e.g. formatting, git settings, updating + Github Actions jobs. + +Whenever possible, when updating commits after the PR is open, please +add the PR number to the end of the subject line. e.g. `test: Add +unit tests for Feature X (#1234)`. + +## Pull requests + +In general, pull requests use `develop` as the base branch. +The exceptions are +* Fixes and improvements to a release candidate use `release` as the + base. +* Hotfixes use `master` as the base. + +If your changes are not quite ready, but you want to make it easily available +for preliminary examination or review, you can create a "Draft" pull request. +While a pull request is marked as a "Draft", you can rebase or reorganize the +commits in the pull request as desired. + +Github pull requests are created as "Ready" by default, or you can mark +a "Draft" pull request as "Ready". +Once a pull request is marked as "Ready", +any changes must be added as new commits. Do not +force-push to a branch in a pull request under review. +(This includes rebasing your branch onto the updated base branch. +Use a merge operation, instead or hit the "Update branch" button +at the bottom of the Github PR page.) +This preserves the ability for reviewers to filter changes since their last +review. + +A pull request must obtain **approvals from at least two reviewers** +before it can be considered for merge by a Maintainer. +Maintainers retain discretion to require more approvals if they feel the +credibility of the existing approvals is insufficient. + +Pull requests must be merged by [squash-and-merge][squash] +to preserve a linear history for the `develop` branch. + +### "Ready to merge" + +A pull request should only have the "Ready to merge" label added when it +meets a few criteria: + +1. It must have two approving reviews [as described + above](#pull-requests). (Exception: PRs that are deemed "trivial" + only need one approval.) +2. All CI checks must be complete and passed. (One-off failures may + be acceptable if they are related to a known issue.) +3. The PR must have a [good commit message](#good-commit-messages). + * If the PR started with a good commit message, and it doesn't + need to be updated, the author can indicate that in a comment. + * Any contributor, preferably the author, can leave a comment + suggesting a commit message. + * If the author squashes and rebases the code in preparation for + merge, they should also ensure the commit message(s) are updated + as well. +4. The PR branch must be up to date with the base branch (usually + `develop`). This is usually accomplished by merging the base branch + into the feature branch, but if the other criteria are met, the + changes can be squashed and rebased on top of the base branch. +5. Finally, and most importantly, the author of the PR must + positively indicate that the PR is ready to merge. That can be + accomplished by adding the "Ready to merge" label if their role + allows, or by leaving a comment to the effect that the PR is ready to + merge. + +Once the "Ready to merge" label is added, a maintainer may merge the PR +at any time, so don't use it lightly. + +# Style guide + +This is a non-exhaustive list of recommended style guidelines. These are +not always strictly enforced and serve as a way to keep the codebase +coherent rather than a set of _thou shalt not_ commandments. + + +## Formatting + +All code must conform to `clang-format` version 18, +according to the settings in [`.clang-format`](./.clang-format), +unless the result would be unreasonably difficult to read or maintain. +To demarcate lines that should be left as-is, surround them with comments like +this: + +``` +// clang-format off +... +// clang-format on +``` + +You can format individual files in place by running `clang-format -i ...` +from any directory within this project. + +There is a Continuous Integration job that runs clang-format on pull requests. If the code doesn't comply, a patch file that corrects auto-fixable formatting issues is generated. + +To download the patch file: + +1. Next to `clang-format / check (pull_request) Failing after #s` -> click **Details** to open the details page. +2. Left menu -> click **Summary** +3. Scroll down to near the bottom-right under `Artifacts` -> click **clang-format.patch** +4. Download the zip file and extract it to your local git repository. Run `git apply [patch-file-name]`. +5. Commit and push. + +You can install a pre-commit hook to automatically run `clang-format` before every commit: +``` +pip3 install pre-commit +pre-commit install +``` + +## Contracts and instrumentation + +We are using [Antithesis](https://antithesis.com/) for continuous fuzzing, +and keep a copy of [Antithesis C++ SDK](https://github.com/antithesishq/antithesis-sdk-cpp/) +in `external/antithesis-sdk`. One of the aims of fuzzing is to identify bugs +by finding external conditions which cause contracts violations inside `rippled`. +The contracts are expressed as `XRPL_ASSERT` or `UNREACHABLE` (defined in +`include/xrpl/beast/utility/instrumentation.h`), which are effectively (outside +of Antithesis) wrappers for `assert(...)` with added name. The purpose of name +is to provide contracts with stable identity which does not rely on line numbers. + +When `rippled` is built with the Antithesis instrumentation enabled +(using `voidstar` CMake option) and ran on the Antithesis platform, the +contracts become +[test properties](https://antithesis.com/docs/using_antithesis/properties.html); +otherwise they are just like a regular `assert`. +To learn more about Antithesis, see +[How Antithesis Works](https://antithesis.com/docs/introduction/how_antithesis_works.html) +and [C++ SDK](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html#) + +We continue to use the old style `assert` or `assert(false)` in certain +locations, where the reporting of contract violations on the Antithesis +platform is either not possible or not useful. + +For this reason: +* The locations where `assert` or `assert(false)` contracts should continue to be used: + * `constexpr` functions + * unit tests i.e. files under `src/test` + * unit tests-related modules (files under `beast/test` and `beast/unit_test`) +* Outside of the listed locations, do not use `assert`; use `XRPL_ASSERT` instead, + giving it unique name, with the short description of the contract. +* Outside of the listed locations, do not use `assert(false)`; use + `UNREACHABLE` instead, giving it unique name, with the description of the + condition being violated +* The contract name should start with a full name (including scope) of the + function, optionally a named lambda, followed by a colon ` : ` and a brief + (typically at most five words) description. `UNREACHABLE` contracts + can use slightly longer descriptions. If there are multiple overloads of the + function, use common sense to balance both brevity and unambiguity of the + function name. NOTE: the purpose of name is to provide stable means of + unique identification of every contract; for this reason try to avoid elements + which can change in some obvious refactors or when reinforcing the condition. +* Contract description typically (except for `UNREACHABLE`) should describe the + _expected_ condition, as in "I assert that _expected_ is true". +* Contract description for `UNREACHABLE` should describe the _unexpected_ + situation which caused the line to have been reached. +* Example good name for an + `UNREACHABLE` macro `"Json::operator==(Value, Value) : invalid type"`; example + good name for an `XRPL_ASSERT` macro `"Json::Value::asCString : valid type"`. +* Example **bad** name + `"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"` + (missing namespace, unnecessary full function signature, description too verbose). + Good name: `"ripple::RFC1751::insert : minimum length"`. +* In **few** well-justified cases a non-standard name can be used, in which case a + comment should be placed to explain the rationale (example in `contract.cpp`) +* Do **not** rename a contract without a good reason (e.g. the name no longer + reflects the location or the condition being checked) +* Do not use `std::unreachable` +* Do not put contracts where they can be violated by an external condition + (e.g. timing, data payload before mandatory validation etc.) as this creates + bogus bug reports (and causes crashes of Debug builds) + +## Unit Tests +To execute all unit tests: + +```rippled --unittest --unittest-jobs=``` + +(Note: Using multiple cores on a Mac M1 can cause spurious test failures. The +cause is still under investigation. If you observe this problem, try specifying fewer jobs.) + +To run a specific set of test suites: + +``` +rippled --unittest TestSuiteName +``` +Note: In this example, all tests with prefix `TestSuiteName` will be run, so if +`TestSuiteName1` and `TestSuiteName2` both exist, then both tests will run. +Alternatively, if the unit test name finds an exact match, it will stop +doing partial matches, i.e. if a unit test with a title of `TestSuiteName` +exists, then no other unit test will be executed, apart from `TestSuiteName`. + +## Avoid + +1. Proliferation of nearly identical code. +2. Proliferation of new files and classes. +3. Complex inheritance and complex OOP patterns. +4. Unmanaged memory allocation and raw pointers. +5. Macros and non-trivial templates (unless they add significant value). +6. Lambda patterns (unless these add significant value). +7. CPU or architecture-specific code unless there is a good reason to + include it, and where it is used, guard it with macros and provide + explanatory comments. +8. Importing new libraries unless there is a very good reason to do so. + + +## Seek to + +9. Extend functionality of existing code rather than creating new code. +10. Prefer readability over terseness where important logic is + concerned. +11. Inline functions that are not used or are not likely to be used + elsewhere in the codebase. +12. Use clear and self-explanatory names for functions, variables, + structs and classes. +13. Use TitleCase for classes, structs and filenames, camelCase for + function and variable names, lower case for namespaces and folders. +14. Provide as many comments as you feel that a competent programmer + would need to understand what your code does. + + +# Maintainers + +Maintainers are ecosystem participants with elevated access to the repository. +They are able to push new code, make decisions on when a release should be +made, etc. + + +## Adding and removing + +New maintainers can be proposed by two existing maintainers, subject to a vote +by a quorum of the existing maintainers. +A minimum of 50% support and a 50% participation is required. +In the event of a tie vote, the addition of the new maintainer will be +rejected. + +Existing maintainers can resign, or be subject to a vote for removal at the +behest of two existing maintainers. +A minimum of 60% agreement and 50% participation are required. +The XRP Ledger Foundation will have the ability, for cause, to remove an +existing maintainer without a vote. + + +## Current Maintainers + +Maintainers are users with maintain or admin access to the repo. + +* [bthomee](https://github.com/bthomee) (Ripple) +* [intelliot](https://github.com/intelliot) (Ripple) +* [JoelKatz](https://github.com/JoelKatz) (Ripple) +* [nixer89](https://github.com/nixer89) (XRP Ledger Foundation) +* [RichardAH](https://github.com/RichardAH) (XRP Ledger Foundation) +* [Silkjaer](https://github.com/Silkjaer) (XRP Ledger Foundation) +* [WietseWind](https://github.com/WietseWind) (XRPL Labs + XRP Ledger Foundation) +* [ximinez](https://github.com/ximinez) (Ripple) + + +## Current Code Reviewers + +Code Reviewers are developers who have the ability to review, approve, and +in some cases merge source code changes. + +* [HowardHinnant](https://github.com/HowardHinnant) (Ripple) +* [scottschurr](https://github.com/scottschurr) (Ripple) +* [seelabs](https://github.com/seelabs) (Ripple) +* [Ed Hennis](https://github.com/ximinez) (Ripple) +* [mvadari](https://github.com/mvadari) (Ripple) +* [thejohnfreeman](https://github.com/thejohnfreeman) (Ripple) +* [Bronek](https://github.com/Bronek) (Ripple) +* [manojsdoshi](https://github.com/manojsdoshi) (Ripple) +* [godexsoft](https://github.com/godexsoft) (Ripple) +* [mDuo13](https://github.com/mDuo13) (Ripple) +* [ckniffen](https://github.com/ckniffen) (Ripple) +* [arihantkothari](https://github.com/arihantkothari) (Ripple) +* [pwang200](https://github.com/pwang200) (Ripple) +* [sophiax851](https://github.com/sophiax851) (Ripple) +* [shawnxie999](https://github.com/shawnxie999) (Ripple) +* [gregtatcam](https://github.com/gregtatcam) (Ripple) +* [mtrippled](https://github.com/mtrippled) (Ripple) +* [ckeshava](https://github.com/ckeshava) (Ripple) +* [nbougalis](https://github.com/nbougalis) None +* [RichardAH](https://github.com/RichardAH) (XRPL Labs + XRP Ledger Foundation) +* [dangell7](https://github.com/dangell7) (XRPL Labs) + +Developers not on this list are able and encouraged to submit feedback +on pending code changes (open pull requests). + +## Instructions for maintainers + +These instructions assume you have your git upstream remotes configured +to avoid accidental pushes to the main repo, and a remote group +specifying both of them. e.g. +``` +$ git remote -v | grep upstream +upstream https://github.com/XRPLF/rippled.git (fetch) +upstream https://github.com/XRPLF/rippled.git (push) +upstream-push git@github.com:XRPLF/rippled.git (fetch) +upstream-push git@github.com:XRPLF/rippled.git (push) + +$ git config remotes.upstreams +upstream upstream-push +``` + +You can use the [setup-upstreams] script to set this up. + +It also assumes you have a default gpg signing key set up in git. e.g. +``` +$ git config user.signingkey +968479A1AFF927E37D1A566BB5690EEEBB952194 +# (This is github's key. Use your own.) +``` + +### When and how to merge pull requests + +The maintainer should double-check that the PR has met all the +necessary criteria, and can request additional information from the +owner, or additional reviews, and can always feel free to remove the +"Ready to merge" label if appropriate. The maintainer has final say on +whether a PR gets merged, and are encouraged to communicate and issues +or concerns to other maintainers. + +#### Most pull requests: "Squash and merge" + +Most pull requests don't need special handling, and can simply be +merged using the "Squash and merge" button on the Github UI. Update +the suggested commit message, or modify it as needed. + +#### Slightly more complicated pull requests + +Some pull requests need to be pushed to `develop` as more than one +commit. A PR author may *request* to merge as separate commits. They +must *justify* why separate commits are needed, and *specify* how they +would like the commits to be merged. If you disagree with the author, +discuss it with them directly. + +If the process is reasonable, follow it. The simplest option is to do a +fast forward only merge (`--ff-only`) on the command line and push to +`develop`. + +Some examples of when separate commits are worthwhile are: +1. PRs where source files are reorganized in multiple steps. +2. PRs where the commits are mostly independent and *could* be separate + PRs, but are pulled together into one PR under a commit theme or + issue. +3. PRs that are complicated enough that `git bisect` would not be much + help if it determined this PR introduced a problem. + +Either way, check that: +* The commits are based on the current tip of `develop`. +* The commits are clean: No merge commits (except when reverse + merging), no "[FOLD]" or "fixup!" messages. +* All commits are signed. If the commits are not signed by the author, use + `git commit --amend -S` to sign them yourself. +* At least one (but preferably all) of the commits has the PR number + in the commit message. + +The "Create a merge commit" and "Rebase and merge" options should be +disabled in the Github UI, but if you ever find them available **Do not +use them!** + +### Releases + +All releases, including release candidates and betas, are handled +differently from typical PRs. Most importantly, never use +the Github UI to merge a release. + +Rippled uses a linear workflow model that can be summarized as: + +1. In between releases, developers work against the `develop` branch. +2. Periodically, a maintainer will build and tag a beta version from + `develop`, which is pushed to `release`. + * Betas are usually released every two to three weeks, though that + schedule can vary depending on progress, availability, and other + factors. +3. When the changes in `develop` are considered stable and mature enough + to be ready to release, a release candidate (RC) is built and tagged + from `develop`, and merged to `release`. + * Further development for that release (primarily fixes) then + continues against `release`, while other development continues on + `develop`. Effectively, `release` is forked from `develop`. Changes + to `release` must be reverse merged to `develop`. +4. When the candidate has passed testing and is ready for release, the + final release is merged to `master`. +5. If any issues are found post-release, a hotfix / point release may be + created, which is merged to `master`, and then reverse merged to + `develop`. + +#### Betas, and the first release candidate + +##### Preparing the `develop` branch + +1. Optimally, the `develop` branch will be ready to go, with all + relevant PRs already merged. +2. If there are any PRs pending, merge them **BEFORE** preparing the beta. + 1. If only one or two PRs need to be merged, merge those PRs [as + normal](#when-and-how-to-merge-pull-requests), updating the second + one, and waiting for CI to finish in between. + 2. If there are several pending PRs, do not use the Github UI, + because the delays waiting for CI in between each merge will be + unnecessarily onerous. (Incidentally, this process can also be + used to merge if the Github UI has issues.) Merge each PR branch + directly to a `release-next` on your local machine and create a single + PR, then push your branch to `develop`. + 1. Squash the changes from each PR, one commit each (unless more + are needed), being sure to sign each commit and update the + commit message to include the PR number. You may be able to use + a fast-forward merge for the first PR. + 2. Push your branch. + 3. Continue to [Making the release](#making-the-release) to update + the version number, etc. + + The workflow may look something like: +``` +git fetch --multiple upstreams user1 user2 user3 [...] +git checkout -B release-next --no-track upstream/develop + +# Only do an ff-only merge if prbranch1 is either already +# squashed, or needs to be merged with separate commits, +# and has no merge commits. +# Use -S on the ff-only merge if prbranch1 isn't signed. +git merge [-S] --ff-only user1/prbranch1 + +git merge --squash user2/prbranch2 +git commit -S # Use the commit message provided on the PR + +git merge --squash user3/prbranch3 +git commit -S # Use the commit message provided on the PR + +[...] + +# Make sure the commits look right +git log --show-signature "upstream/develop..HEAD" + +git push --set-upstream origin + +# Continue to "Making the release" to update the version number, so +# everything can be done in one PR. +``` + +You can also use the [squash-branches] script. + +You may also need to manually close the open PRs after the changes are +merged to `develop`. Be sure to include the commit ID. + +##### Making the release + +This includes, betas, and the first release candidate (RC). + +1. If you didn't create one [preparing the `develop` + branch](#preparing-the-develop-branch), Ensure there is no old + `release-next` branch hanging around. Then make a `release-next` + branch that only changes the version number. e.g. +``` +git fetch upstreams + +git checkout --no-track -B release-next upstream/develop + +v="A.B.C-bD" +build=$( find -name BuildInfo.cpp ) +sed 's/\(^.*versionString =\).*$/\1 "'${v}'"/' ${build} > version.cpp && mv -vi version.cpp ${build} + +git diff + +git add ${build} + +git commit -S -m "Set version to ${v}" + +# You could use your "origin" repo, but some CI tests work better on upstream. +git push upstream-push +git fetch upstreams +git branch --set-upstream-to=upstream/release-next +``` + You can also use the [update-version] script. +2. Create a Pull Request for `release-next` with **`develop`** as + the base branch. + 1. Use the title "[TRIVIAL] Set version to X.X.X-bX". + 2. Instead of the default description template, use the following: +``` +## High Level Overview of Change + +This PR only changes the version number. It will be merged as +soon as Github CI actions successfully complete. +``` +3. Wait for CI to successfully complete, and get someone to approve + the PR. (It is safe to ignore known CI issues.) +4. Push the updated `develop` branch using your `release-next` + branch. **Do not use the Github UI. It's important to preserve + commit IDs.** +``` +git push upstream-push release-next:develop +``` +5. In the unlikely event that the push fails because someone has merged + something else in the meantime, rebase your branch onto the updated + `develop` branch, push again, and go back to step 3. +6. Ensure that your PR against `develop` is closed. Github should do it + automatically. +7. Once this is done, forward progress on `develop` can continue + (other PRs may be merged). +8. Now create a Pull Request for `release-next` with **`release`** as + the base branch. Instead of the default template, reuse and update + the message from the previous release. Include the following verbiage + somewhere in the description: +``` +The base branch is `release`. [All releases (including +betas)](https://github.com/XRPLF/rippled/blob/develop/CONTRIBUTING.md#before-you-start) +go in `release`. This PR branch will be pushed directly to `release` (not +squashed or rebased, and not using the GitHub UI). +``` +7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur + offline, but at least one approval will be needed on the PR. + * If issues are discovered during testing, simply abandon the + release. It's easy to start a new release, it should be easy to + abandon one. **DO NOT REUSE THE VERSION NUMBER.** e.g. If you + abandon 2.4.0-b1, the next attempt will be 2.4.0-b2. +8. Once everything is ready to go, push to `release`. +``` +git fetch upstreams + +# Just to be safe, do a dry run first: +git push --dry-run upstream-push release-next:release + +# If everything looks right, push the branch +git push upstream-push release-next:release + +# Check that all of the branches are updated +git fetch upstreams +git log -1 --oneline +# The output should look like: +# 0123456789 (HEAD -> upstream/release-next, upstream/release, +# upstream/develop) Set version to 2.4.0-b1 +# Note that upstream/develop may not be on this commit, but +# upstream/release must be. +# Other branches, including some from upstream-push, may also be +# present. +``` +9. Tag the release, too. +``` +git tag +git push upstream-push +``` +10. Delete the `release-next` branch on the repo. Use the Github UI or: +``` +git push --delete upstream-push release-next +``` +11. Finally [create a new release on + Github](https://github.com/XRPLF/rippled/releases). + +#### Release candidates after the first + +Once the first release candidate is [merged into +release](#making-the-release), then `release` and `develop` *are allowed +to diverge*. + +If a bug or issue is discovered in a version that has a release +candidate being tested, any fix and new version will need to be applied +against `release`, then reverse-merged to `develop`. This helps keep git +history as linear as possible. + +A `release-next` branch will be created from `release`, and any further +work for that release must be based on `release-next`. Specifically, +PRs must use `release-next` as the base, and those PRs will be merged +directly to `release-next` when approved. Changes should be restricted +to bug fixes, but other changes may be necessary from time to time. + +1. Open any PRs for the pending release using `release-next` as the base, + so they can be merged directly in to it. Unlike `develop`, though, + `release-next` can be thrown away and recreated if necessary. +2. Once a new release candidate is ready, create a version commit as in + step 1 [above](#making-the-release) on `release-next`. You can use + the [update-version] script for this, too. +3. Jump to step 8 ("Now create a Pull Request for `release-next` with + **`release`** as the base") from the process + [above](#making-the-release) to merge `release-next` into `release`. + +##### Follow up: reverse merge + +Once the RC is merged and tagged, it needs to be reverse merged into +`develop` as soon as possible. + +1. Create a branch, based on `upstream/develop`. + The branch name is not important, but could include "mergeNNNrcN". + E.g. For release A.B.C-rcD, use `mergeABCrcD`. +``` +git fetch upstreams + +git checkout --no-track -b mergeABCrcD upstream/develop +``` +2. Merge `release` into your branch. +``` +# I like the "--edit --log --verbose" parameters, but they are +# not required. +git merge upstream/release +``` +3. `BuildInfo.cpp` will have a conflict with the version number. + Resolve it with the version from `develop` - the higher version. +4. Push your branch to your repo (or `upstream` if you have permission), + and open a normal PR against `develop`. The "High level overview" can + simply indicate that this is a merge of the RC. The "Context" should + summarize the changes from the RC. Include the following text + prominently: +``` +This PR must be merged manually using a push. Do not use the Github UI. +``` +5. Depending on the complexity of the changes, and/or merge conflicts, + the PR may need a thorough review, or just a sign-off that the + merge was done correctly. +6. If `develop` is updated before this PR is merged, do not merge + `develop` back into your branch. Instead rebase preserving merges, + or do the merge again. (See also the `rerere` git config setting.) +``` +git rebase --rebase-merges upstream/develop +# OR +git reset --hard upstream/develop +git merge upstream/release +``` +7. When the PR is ready, push it to `develop`. +``` +git fetch upstreams + +# Make sure the commits look right +git log --show-signature "upstream/develop^..HEAD" + +git push upstream-push mergeABCrcD:develop + +git fetch upstreams +``` +Development on `develop` can proceed as normal. + + +#### Final releases + +A final release is any release that is not a beta or RC, such as 2.2.0. + +Only code that has already been tested and vetted across all three +platforms should be included in a final release. Most of the time, that +means that the commit immediately preceding the commit setting the +version number will be an RC. Occasionally, there may be last-minute bug +fixes included as well. If so, those bug fixes must have been tested +internally as if they were RCs (at minimum, ensuring unit tests pass, +and the app starts, syncs, and stops cleanly across all three +platforms.) + +*If in doubt, make an RC first.* + +The process for building a final release is very similar to [the process +for building a beta](#making-the-release), except the code will be +moving from `release` to `master` instead of from `develop` to +`release`, and both branches will be pushed at the same time. + +1. Ensure there is no old `master-next` branch hanging around. + Then make a `master-next` branch that only changes the version + number. As above, or using the + [update-version] script. +2. Create a Pull Request for `master-next` with **`master`** as + the base branch. Instead of the default template, reuse and update + the message from the previous final release. Include the following verbiage + somewhere in the description: +``` +The base branch is `master`. This PR branch will be pushed directly to +`release` and `master` (not squashed or rebased, and not using the +GitHub UI). +``` +7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur + offline, but at least one approval will be needed on the PR. + * If issues are discovered during testing, close the PR, delete + `master-next`, and move development back to `release`, [issuing + more RCs as necessary](#release-candidates-after-the-first) +8. Once everything is ready to go, push to `release` and `master`. +``` +git fetch upstreams + +# Just to be safe, do dry runs first: +git push --dry-run upstream-push master-next:release +git push --dry-run upstream-push master-next:master + +# If everything looks right, push the branch +git push upstream-push master-next:release +git push upstream-push master-next:master + +# Check that all of the branches are updated +git fetch upstreams +git log -1 --oneline +# The output should look like: +# 0123456789 (HEAD -> upstream/master-next, upstream/master, +# upstream/release) Set version to A.B.0 +# Note that both upstream/release and upstream/master must be on this +# commit. +# Other branches, including some from upstream-push, may also be +# present. +``` +9. Tag the release, too. +``` +git tag +git push upstream-push +``` +10. Delete the `master-next` branch on the repo. Use the Github UI or: +``` +git push --delete upstream-push master-next +``` +11. [Create a new release on + Github](https://github.com/XRPLF/rippled/releases). Be sure that + "Set as the latest release" is checked. +12. Finally [reverse merge the release into `develop`](#follow-up-reverse-merge). + +#### Special cases: point releases, hotfixes, etc. + +On occassion, a bug or issue is discovered in a version that already +had a final release. Most of the time, development will have started +on the next version, and will usually have changes in `develop` +and often in `release`. + +Because git history is kept as linear as possible, any fix and new +version will need to be applied against `master`. + +The process for building a hotfix release is very similar to [the +process for building release candidates after the +first](#release-candidates-after-the-first) and [for building a final +release](#final-releases), except the changes will be done against +`master` instead of `release`. + +If there is only a single issue for the hotfix, the work can be done in +any branch. When it's ready to merge, jump to step 3 using your branch +instead of `master-next`. + +1. Create a `master-next` branch from `master`. +``` +git checkout --no-track -b master-next upstream/master +git push upstream-push +git fetch upstreams +``` +2. Open any PRs for the pending hotfix using `master-next` as the base, + so they can be merged directly in to it. Unlike `develop`, though, + `master-next` can be thrown away and recreated if necessary. +3. Once the hotfix is ready, create a version commit using the same + steps as above, or use the + [update-version] script. +4. Create a Pull Request for `master-next` with **`master`** as + the base branch. Instead of the default template, reuse and update + the message from the previous final release. Include the following verbiage + somewhere in the description: +``` +The base branch is `master`. This PR branch will be pushed directly to +`master` (not squashed or rebased, and not using the GitHub UI). +``` +7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur + offline, but at least one approval will be needed on the PR. + * If issues are discovered during testing, update `master-next` as + needed, but ensure that the changes are properly squashed, and the + version setting commit remains last +8. Once everything is ready to go, push to `master` **only**. +``` +git fetch upstreams + +# Just to be safe, do a dry run first: +git push --dry-run upstream-push master-next:master + +# If everything looks right, push the branch +git push upstream-push master-next:master + +# Check that all of the branches are updated +git fetch upstreams +git log -1 --oneline +# The output should look like: +# 0123456789 (HEAD -> upstream/master-next, upstream/master) Set version +# to 2.4.1 +# Note that upstream/master must be on this commit. upstream/release and +# upstream/develop should not. +# Other branches, including some from upstream-push, may also be +# present. +``` +9. Tag the release, too. +``` +git tag +git push upstream-push +``` +9. Delete the `master-next` branch on the repo. +``` +git push --delete upstream-push master-next +``` +10. [Create a new release on + Github](https://github.com/XRPLF/rippled/releases). Be sure that + "Set as the latest release" is checked. + +Once the hotfix is released, it needs to be reverse merged into +`develop` as soon as possible. It may also need to be merged into +`release` if a release candidate is under development. + +1. Create a branch in your own repo, based on `upstream/develop`. + The branch name is not important, but could include "mergeNNN". + E.g. For release 2.2.3, use `merge223`. +``` +git fetch upstreams + +git checkout --no-track -b merge223 upstream/develop +``` +2. Merge master into your branch. +``` +# I like the "--edit --log --verbose" parameters, but they are +# not required. +git merge upstream/master +``` +3. `BuildInfo.cpp` will have a conflict with the version number. + Resolve it with the version from `develop` - the higher version. +4. Push your branch to your repo, and open a normal PR against + `develop`. The "High level overview" can simply indicate that this + is a merge of the hotfix version. The "Context" should summarize + the changes from the hotfix. Include the following text + prominently: +``` +This PR must be merged manually using a --ff-only merge. Do not use the Github UI. +``` +5. Depending on the complexity of the hotfix, and/or merge conflicts, + the PR may need a thorough review, or just a sign-off that the + merge was done correctly. +6. If `develop` is updated before this PR is merged, do not merge + `develop` back into your branch. Instead rebase preserving merges, + or do the merge again. (See also the `rerere` git config setting.) +``` +git rebase --rebase-merges upstream/develop +# OR +git reset --hard upstream/develop +git merge upstream/master +``` +7. When the PR is ready, push it to `develop`. +``` +git fetch upstreams + +# Make sure the commits look right +git log --show-signature "upstream/develop..HEAD" + +git push upstream-push HEAD:develop +``` +Development on `develop` can proceed as normal. It is recommended to +create a beta (or RC) immediately to ensure that everything worked as +expected. + +##### An even rarer scenario: A hotfix on an old release + +Historically, once a final release is tagged and packages are released, +versions older than the latest final release are no longer supported. +However, there is a possibility that a very high severity bug may occur +in a non-amendment blocked version that is still being run by +a significant fraction of users, which would necessitate a hotfix / point +release to that version as well as any later versions. + +This scenario would follow the same basic procedure as above, +except that *none* of `develop`, `release`, or `master` +would be touched during the release process. + +In this example, consider if version 2.1.1 needed to be patched. + +1. Create two branches in the main (`upstream`) repo. +``` +git fetch upstreams + +# Create a base branch off the tag +git checkout --no-track -b master-2.1.2 2.1.1 +git push upstream-push + +# Create a working branch +git checkout --no-track -b master212-next master-2.1.2 +git push upstream-push + +git fetch upstreams +``` +2. Work continues as above, except using `master-2.1.2`as + the base branch for any merging, packaging, etc. +3. After the release is tagged and packages are built, you could + potentially delete both branches, e.g. `master-2.1.2` and + `master212-next`. However, it may be useful to keep `master-2.1.2` + around indefinitely for reference. +4. Assuming that a hotfix is also released for the latest + version in parallel with this one, or if the issue is + already fixed in the latest version, do no do any + reverse merges. However, if it is not, it probably makes + sense to reverse merge `master-2.1.2` into `master`, + release a hotfix for _that_ version, then reverse merge + from `master` to `develop`. (Please don't do this unless absolutely + necessary.) + +[contrib]: https://docs.github.com/en/get-started/quickstart/contributing-to-projects +[squash]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-commits +[forking]: https://github.com/XRPLF/rippled/fork +[rippled]: https://github.com/XRPLF/rippled +[signing]: https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification +[setup-upstreams]: ./bin/git/setup-upstreams.sh +[squash-branches]: ./bin/git/squash-branches.sh +[update-version]: ./bin/git/update-version.sh diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 90e6e374f2c..00000000000 --- a/LICENSE +++ /dev/null @@ -1,77 +0,0 @@ -The accompanying files under various copyrights. - -Copyright (c) 2012, 2013, 2014 Ripple Labs Inc. - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -The accompanying files incorporate work covered by the following copyright -and previous license notice: - -Copyright (c) 2011 Arthur Britto, David Schwartz, Jed McCaleb, -Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant - -Some code from Raw Material Software, Ltd., provided under the terms of the - ISC License. See the corresponding source files for more details. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - -Some code from ASIO examples: -// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -Some code from Bitcoin: -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. - -Some code from Tom Wu: -This software is covered under the following copyright: - -/* - * Copyright (c) 2003-2005 Tom Wu - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * In addition, the following condition applies: - * - * All redistributions must retain an intact copy of this copyright notice - * and disclaimer. - */ - -Address all questions regarding this license to: - - Tom Wu - tjw@cs.Stanford.EDU diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000000..9282ed78baf --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,17 @@ +ISC License + +Copyright (c) 2011, Arthur Britto, David Schwartz, Jed McCaleb, Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant. +Copyright (c) 2012-2020, the XRP Ledger developers. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + diff --git a/README.md b/README.md index 0b5a0a23f36..cc002a2dd82 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,19 @@ # The XRP Ledger -The XRP Ledger is a decentralized cryptographic ledger powered by a network of peer-to-peer servers. The XRP Ledger uses a novel Byzantine Fault Tolerant consensus algorithm to settle and record transactions in a secure distributed database without a central operator. +The [XRP Ledger](https://xrpl.org/) is a decentralized cryptographic ledger powered by a network of peer-to-peer nodes. The XRP Ledger uses a novel Byzantine Fault Tolerant consensus algorithm to settle and record transactions in a secure distributed database without a central operator. ## XRP -XRP is a public, counterparty-free asset native to the XRP Ledger, and is designed to bridge the many different currencies in use worldwide. XRP is traded on the open-market and is available for anyone to access. The XRP Ledger was created in 2012 with a finite supply of 100 billion units of XRP. Its creators gifted 80 billion XRP to a company, now called [Ripple](https://ripple.com/), to develop the XRP Ledger and its ecosystem. Ripple uses XRP to help build the Internet of Value, ushering in a world in which money moves as fast and efficiently as information does today. +[XRP](https://xrpl.org/xrp.html) is a public, counterparty-free asset native to the XRP Ledger, and is designed to bridge the many different currencies in use worldwide. XRP is traded on the open-market and is available for anyone to access. The XRP Ledger was created in 2012 with a finite supply of 100 billion units of XRP. ## rippled -The server software that powers the XRP Ledger is called `rippled` and is available in this repository under the permissive [ISC open-source license](LICENSE). The `rippled` server is written primarily in C++ and runs on a variety of platforms. +The server software that powers the XRP Ledger is called `rippled` and is available in this repository under the permissive [ISC open-source license](LICENSE.md). The `rippled` server software is written primarily in C++ and runs on a variety of platforms. The `rippled` server software can run in several modes depending on its [configuration](https://xrpl.org/rippled-server-modes.html). + +If you are interested in running an **API Server** (including a **Full History Server**), take a look at [Clio](https://github.com/XRPLF/clio). (rippled Reporting Mode has been replaced by Clio.) ### Build from Source -* [Linux](Builds/linux/README.md) -* [Mac](Builds/macos/README.md) -* [Windows](Builds/VisualStudio2017/README.md) +* [Read the build instructions in `BUILD.md`](BUILD.md) +* If you encounter any issues, please [open an issue](https://github.com/XRPLF/rippled/issues) ## Key Features of the XRP Ledger @@ -24,18 +25,22 @@ The server software that powers the XRP Ledger is called `rippled` and is availa - **[Modern Features for Smart Contracts][]:** Features like Escrow, Checks, and Payment Channels support cutting-edge financial applications including the [Interledger Protocol](https://interledger.org/). This toolbox of advanced features comes with safety features like a process for amending the network and separate checks against invariant constraints. - **[On-Ledger Decentralized Exchange][]:** In addition to all the features that make XRP useful on its own, the XRP Ledger also has a fully-functional accounting system for tracking and trading obligations denominated in any way users want, and an exchange built into the protocol. The XRP Ledger can settle long, cross-currency payment paths and exchanges of multiple currencies in atomic transactions, bridging gaps of trust with XRP. -[Censorship-Resistant Transaction Processing]: https://developers.ripple.com/xrp-ledger-overview.html#censorship-resistant-transaction-processing -[Fast, Efficient Consensus Algorithm]: https://developers.ripple.com/xrp-ledger-overview.html#fast-efficient-consensus-algorithm -[Finite XRP Supply]: https://developers.ripple.com/xrp-ledger-overview.html#finite-xrp-supply -[Responsible Software Governance]: https://developers.ripple.com/xrp-ledger-overview.html#responsible-software-governance -[Secure, Adaptable Cryptography]: https://developers.ripple.com/xrp-ledger-overview.html#secure-adaptable-cryptography -[Modern Features for Smart Contracts]: https://developers.ripple.com/xrp-ledger-overview.html#modern-features-for-smart-contracts -[On-Ledger Decentralized Exchange]: https://developers.ripple.com/xrp-ledger-overview.html#on-ledger-decentralized-exchange +[Censorship-Resistant Transaction Processing]: https://xrpl.org/xrp-ledger-overview.html#censorship-resistant-transaction-processing +[Fast, Efficient Consensus Algorithm]: https://xrpl.org/xrp-ledger-overview.html#fast-efficient-consensus-algorithm +[Finite XRP Supply]: https://xrpl.org/xrp-ledger-overview.html#finite-xrp-supply +[Responsible Software Governance]: https://xrpl.org/xrp-ledger-overview.html#responsible-software-governance +[Secure, Adaptable Cryptography]: https://xrpl.org/xrp-ledger-overview.html#secure-adaptable-cryptography +[Modern Features for Smart Contracts]: https://xrpl.org/xrp-ledger-overview.html#modern-features-for-smart-contracts +[On-Ledger Decentralized Exchange]: https://xrpl.org/xrp-ledger-overview.html#on-ledger-decentralized-exchange ## Source Code -[![travis-ci.com: Build Status](https://travis-ci.com/ripple/rippled.svg?branch=develop)](https://travis-ci.com/ripple/rippled) -[![codecov.io: Code Coverage](https://codecov.io/gh/ripple/rippled/branch/develop/graph/badge.svg)](https://codecov.io/gh/ripple/rippled) + +Here are some good places to start learning the source code: + +- Read the markdown files in the source tree: `src/ripple/**/*.md`. +- Read [the levelization document](./Builds/levelization) to get an idea of the internal dependency graph. +- In the big picture, the `main` function constructs an `ApplicationImp` object, which implements the `Application` virtual interface. Almost every component in the application takes an `Application&` parameter in its constructor, typically named `app` and stored as a member variable `app_`. This allows most components to depend on any other component. ### Repository Contents @@ -51,11 +56,14 @@ Some of the directories under `src` are external repositories included using git-subtree. See those directories' README files for more details. -## See Also +## Additional Documentation + +* [XRP Ledger Dev Portal](https://xrpl.org/) +* [Setup and Installation](https://xrpl.org/install-rippled.html) +* [Source Documentation (Doxygen)](https://xrplf.github.io/rippled/) -* [XRP Ledger Dev Portal](https://developers.ripple.com/) -* [XRP News](https://ripple.com/category/xrp/) -* [Setup and Installation](https://developers.ripple.com/install-rippled.html) +## See Also -To learn about how Ripple is transforming global payments, visit -. +* [Clio API Server for the XRP Ledger](https://github.com/XRPLF/clio) +* [Mailing List for Release Announcements](https://groups.google.com/g/ripple-server) +* [Learn more about the XRP Ledger (YouTube)](https://www.youtube.com/playlist?list=PLJQ55Tj1hIVZtJ_JdTvSum2qMTsedWkNi) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a526702f250..6bc7beccc7b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,19 +1,1899 @@ # Release Notes -![Ripple](docs/images/ripple.png) +![XRP](docs/images/xrp-text-mark-black-small@2x.png) + +This document contains the release notes for `rippled`, the reference server implementation of the XRP Ledger protocol. To learn more about how to build, run or update a `rippled` server, visit https://xrpl.org/install-rippled.html + +Have new ideas? Need help with setting up your node? [Please open an issue here](https://github.com/xrplf/rippled/issues/new/choose). +## Full Changelog + +### Amendments + +The following amendments are open for voting with this release: + +- **DynamicNFT (XLS-46)** - Adds the ability to mint mutable `NFToken` objects whose URI can be changed. ([#5048](https://github.com/XRPLF/rippled/pull/5048)) +- **PermissionedDomains (XLS-80)** - Adds Permissioned Domains, which act as part of broader systems on the XRP Ledger to restrict access to satisfy compliance rules. ([#5161](https://github.com/XRPLF/rippled/pull/5161)) +- **DeepFreeze (XLS-77)** - Adds the ability to deep freeze trust lines, enabling token issuers to block the transfer of assets for holders who have been deep frozen. ([#5187](https://github.com/XRPLF/rippled/pull/5187)) +- **fixFrozenLPTokenTransfer** - Prohibits the transfer of LP tokens when the associated liquidity pool contains at least one frozen asset. ([#5227](https://github.com/XRPLF/rippled/pull/5227)) +- **fixInvalidTxFlags** - Adds transaction flag checking for `CredentialCreate`, `CredentialAccept`, and `CredentialDelete` transactions. ([#5250](https://github.com/XRPLF/rippled/pull/5250)) + + +### New Features + +- Added a new `simulate` API method to execute dry runs of transactions and see the simulated metadata. ([#5069](https://github.com/XRPLF/rippled/pull/5069), [#5265](https://github.com/XRPLF/rippled/pull/5265)) +- Added the ability to specify MPTs when defining assets in transactions. ([#5200](https://github.com/XRPLF/rippled/pull/5200)) +- Added a `state` alias for `ripple_state` in the `ledger_entry` API method. Also refactored `LedgerEntry.cpp` to make it easier to read. ([#5199](https://github.com/XRPLF/rippled/pull/5199)) +- Improved UNL security by enabling validators to set a minimum number of UNL publishers to agree on validators. ([#5112](https://github.com/XRPLF/rippled/pull/5112)) +- Updated the XRPL Foundation UNL keys. ([#5289](https://github.com/XRPLF/rippled/pull/5289)) +- Added a new XRPL Foundation subdomain to enable a staged migration without modifying the key for the current UNL list. ([#5326](https://github.com/XRPLF/rippled/pull/5326)) +- Added support to filter ledger entry types by their canonical names in the `ledger`, `ledger_data`, and `account_objects` API methods. ([#5271](https://github.com/XRPLF/rippled/pull/5271)) +- Added detailed logging for each validation and proposal received from the network. ([#5291](https://github.com/XRPLF/rippled/pull/5291)) +- Improved git commit hash lookups when checking the version of a `rippled` debug build. Also added git commit hash info when using the `server_info` API method on an admin connection. ([#5225](https://github.com/XRPLF/rippled/pull/5225)) + + +### Bug fixes + +- Fixed an issue with overlapping data types in the `Expected` class. ([#5218](https://github.com/XRPLF/rippled/pull/5218)) +- Fixed an issue that prevented `rippled` from building on Windows with VS2022. ([#5197](https://github.com/XRPLF/rippled/pull/5197)) +- Fixed `server_definitions` prefixes. ([#5231](https://github.com/XRPLF/rippled/pull/5231)) +- Added missing dependency installations for generic MasOS runners. ([#5233](https://github.com/XRPLF/rippled/pull/5233)) +- Updated deprecated Github actions. ([#5241](https://github.com/XRPLF/rippled/pull/5241)) +- Fixed a failing assert scenario when submitting the `connect` admin RPC. ([#5235](https://github.com/XRPLF/rippled/pull/5235)) +- Fixed the levelization script to ignore single-line comments during dependency analysis. ([#5194](https://github.com/XRPLF/rippled/pull/5194)) +- Fixed the assert name used in `PermissionedDomainDelete`. ([#5245](https://github.com/XRPLF/rippled/pull/5245)) +- Fixed macOS unit tests. ([#5196](https://github.com/XRPLF/rippled/pull/5196)) +- Fixed an issue with validators not accurately reflecting amendment votes. Also added debug logging of amendment votes. ([#5173](https://github.com/XRPLF/rippled/pull/5173), [#5312](https://github.com/XRPLF/rippled/pull/5312)) +- Fixed a potential issue with double-charging fees. ([#5269](https://github.com/XRPLF/rippled/pull/5269)) +- Removed the `new parent hash` assert and replaced it with a log message. ([#5313](https://github.com/XRPLF/rippled/pull/5313)) +- Fixed an issue that prevented previously-failed inbound ledgers to not be acquired if a new trusted proposal arrived. ([#5318](https://github.com/XRPLF/rippled/pull/5318)) -This document contains the release notes for `rippled`, the reference server implementation of the Ripple protocol. To learn more about how to build and run a `rippled` server, visit https://ripple.com/build/rippled-setup/ -> **Do you work at a digital asset exchange or wallet provider?** -> -> Please [contact us](mailto:support@ripple.com). We can help guide your integration. +### Other Improvements -## Updating `rippled` +- Added unit tests for `AccountID` handling. ([#5174](https://github.com/XRPLF/rippled/pull/5174)) +- Added enforced levelization in `libxrpl` with CMake. ([#5199](https://github.com/XRPLF/rippled/pull/5111)) +- Updated `libxrpl` and all submodules to use the same compiler options. ([#5228](https://github.com/XRPLF/rippled/pull/5228)) +- Added Antithesis instrumentation. ([#5042](https://github.com/XRPLF/rippled/pull/5042), [#5213](https://github.com/XRPLF/rippled/pull/5213)) +- Added `rpcName` to the `LEDGER_ENTRY` macro to help prevent future bugs. ([#5202](https://github.com/XRPLF/rippled/pull/5202)) +- Updated the contribution guidelines to introduce a new workflow that avoids code freezes. Also added scripts that can be used by maintainers in branch management, and a CI job to check that code is consistent across the three main branches: `master`, `release`, and `develop`. ([#5215](https://github.com/XRPLF/rippled/pull/5215)) +- Added unit tests to check for caching issues fixed in `rippled 2.3.0`. ([#5242](https://github.com/XRPLF/rippled/pull/5242)) +- Cleaned up the API changelog. ([#5207](https://github.com/XRPLF/rippled/pull/5207)) +- Improved logs readability. ([#5251](https://github.com/XRPLF/rippled/pull/5251)) +- Updated Visual Studio CI to VS 2022, and added VS Debug builds. ([#5240](https://github.com/XRPLF/rippled/pull/5240)) +- Updated the `secp256k1` library to version 0.6.0. ([#5254](https://github.com/XRPLF/rippled/pull/5254)) +- Changed the `[port_peer]` parameter in `rippled` example config back to `51235`; also added the recommendation to use the default port of `2459` for new deployments. ([#5290](https://github.com/XRPLF/rippled/pull/5290), [#5299](https://github.com/XRPLF/rippled/pull/5299)) +- Improved CI management. ([#5268](https://github.com/XRPLF/rippled/pull/5268)) +- Updated the git commit message rules for contributors. ([#5283](https://github.com/XRPLF/rippled/pull/5283)) +- Fixed unnecessary `setCurrentThreadName` calls. ([#5280](https://github.com/XRPLF/rippled/pull/5280)) +- Added a check to prevent permissioned domains from being created in the event the Permissioned Domains amendement is enabled before the Credentials amendement. ([#5275](https://github.com/XRPLF/rippled/pull/5275)) +- Updated Conan dependencies. ([#5256](https://github.com/XRPLF/rippled/pull/5256)) +- Fixed minor typos in code comments. ([#5279](https://github.com/XRPLF/rippled/pull/5279)) +- Fixed incorrect build instructions. ([#5274](https://github.com/XRPLF/rippled/pull/5274)) +- Refactored `rotateWithLock()` to not hold a lock during callbacks. ([#5276](https://github.com/XRPLF/rippled/pull/5276)) +- Cleaned up debug logging by combining multiple data points into a single message. ([#5302](https://github.com/XRPLF/rippled/pull/5302)) +- Updated build flags to fix performance regressions. ([#5325](https://github.com/XRPLF/rippled/pull/5325)) -If you are using Red Hat Enterprise Linux 7 or CentOS 7, you can [update using `yum`](https://ripple.com/build/rippled-setup/#updating-rippled). For other platforms, please [compile from source](https://wiki.ripple.com/Rippled_build_instructions). + +## Credits + +The following people contributed directly to this release: + +- Aanchal Malhotra +- Bart Thomee <11445373+bthomee@users.noreply.github.com> +- Bronek Kozicki +- code0xff +- Darius Tumas +- David Fuelling +- Donovan Hide +- Ed Hennis +- Elliot Lee +- Javier Romero +- Kenny Lei +- Mark Travis <7728157+mtrippled@users.noreply.github.com> +- Mayukha Vadari +- Michael Legleux +- Oleksandr <115580134+oleks-rip@users.noreply.github.com> +- Qi Zhao +- Ramkumar Srirengaram Gunasegharan +- Shae Wang +- Shawn Xie +- Sophia Xie +- Vijay Khanna Raviraj +- Vladislav Vysokikh +- Xun Zhao + +## Bug Bounties and Responsible Disclosures + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + +# Version 2.3.1 + +Version 2.3.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. +This is a hotfix release that includes the following updates: +- Fix an erroneous high fee penalty that peers could incur for sending older transactions. +- Update to the fees charged for imposing a load on the server. +- Prevent the relaying of internal pseudo-transactions. + - Before: Pseudo-transactions received from a peer will fail the signature check, even if they were requested (using TMGetObjectByHash) because they have no signature. This causes the peer to be charged for an invalid signature. + - After: Pseudo-transactions, are put into the global cache (TransactionMaster) only. If the transaction is not part of a TMTransactions batch, the peer is charged an unwanted data fee. These fees will not be a problem in the normal course of operations but should dissuade peers from behaving badly by sending a bunch of junk. +- Improved logging now specifies the reason for the fee charged to the peer. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Action Required + +If you run an XRP Ledger validator, upgrade to version 2.3.1 as soon as possible to ensure stable and uninterrupted network behavior. + +## Changelog + +### Amendments and New Features + +- None + +### Bug Fixes and Performance Improvements + +- Change the charged fee for sending older transactions from feeInvalidSignature to feeUnwantedData. [#5243](https://github.com/XRPLF/rippled/pull/5243) + +### Docs and Build System + +- None + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +Ed Hennis +JoelKatz +Sophia Xie <106177003+sophiax851@users.noreply.github.com> +Valentin Balaschenko <13349202+vlntb@users.noreply.github.com> + + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + +# Version 2.3.0 + +Version 2.3.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes 8 new amendments, including Multi-Purpose Tokens, Credentials, Clawback support for AMMs, and the ability to make offers as part of minting NFTs. Additionally, this release includes important fixes for stability, so server operators are encouraged to upgrade as soon as possible. + + +## Action Required + +If you run an XRP Ledger server, upgrade to version 2.3.0 as soon as possible to ensure service continuity. + +Additionally, new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +## Full Changelog + +### Amendments + +The following amendments are open for voting with this release: + +- **XLS-70 Credentials** - Users can issue Credentials on the ledger and use Credentials to pre-approve incoming payments when using Deposit Authorization instead of individually approving payers. ([#5103](https://github.com/XRPLF/rippled/pull/5103)) + - related fix: #5189 (https://github.com/XRPLF/rippled/pull/5189) +- **XLS-33 Multi-Purpose Tokens** - A new type of fungible token optimized for institutional DeFi including stablecoins. ([#5143](https://github.com/XRPLF/rippled/pull/5143)) +- **XLS-37 AMM Clawback** - Allows clawback-enabled tokens to be used in AMMs, with appropriate guardrails. ([#5142](https://github.com/XRPLF/rippled/pull/5142)) +- **XLS-52 NFTokenMintOffer** - Allows creating an NFT sell offer as part of minting a new NFT. ([#4845](https://github.com/XRPLF/rippled/pull/4845)) +- **fixAMMv1_2** - Fixes two bugs in Automated Market Maker (AMM) transaction processing. ([#5176](https://github.com/XRPLF/rippled/pull/5176)) +- **fixNFTokenPageLinks** - Fixes a bug that can cause NFT directories to have missing links, and introduces a transaction to repair corrupted ledger state. ([#4945](https://github.com/XRPLF/rippled/pull/4945)) +- **fixEnforceNFTokenTrustline** - Fixes two bugs in the interaction between NFT offers and trust lines. ([#4946](https://github.com/XRPLF/rippled/pull/4946)) +- **fixInnerObjTemplate2** - Standardizes the way inner objects are enforced across all transaction and ledger data. ([#5047](https://github.com/XRPLF/rippled/pull/5047)) + +The following amendment is partially implemented but not open for voting: + +- **InvariantsV1_1** - Adds new invariants to ensure transactions process as intended, starting with an invariant to ensure that ledger entries owned by an account are deleted when the account is deleted. ([#4663](https://github.com/XRPLF/rippled/pull/4663)) + +### New Features + +- Allow configuration of SQLite database page size. ([#5135](https://github.com/XRPLF/rippled/pull/5135), [#5140](https://github.com/XRPLF/rippled/pull/5140)) +- In the `libxrpl` C++ library, provide a list of known amendments. ([#5026](https://github.com/XRPLF/rippled/pull/5026)) + +### Deprecations + +- History Shards are removed. ([#5066](https://github.com/XRPLF/rippled/pull/5066)) +- Reporting mode is removed. ([#5092](https://github.com/XRPLF/rippled/pull/5092)) + +For users wanting to store more ledger history, it is recommended to run a Clio server instead. + +### Bug fixes + +- Fix a crash in debug builds when amm_info request contains an invalid AMM account ID. ([#5188](https://github.com/XRPLF/rippled/pull/5188)) +- Fix a crash caused by a race condition in peer-to-peer code. ([#5071](https://github.com/XRPLF/rippled/pull/5071)) +- Fix a crash in certain situations +- Fix several bugs in the book_changes API method. ([#5096](https://github.com/XRPLF/rippled/pull/5096)) +- Fix bug triggered by providing an invalid marker to the account_nfts API method. ([#5045](https://github.com/XRPLF/rippled/pull/5045)) +- Accept lower-case hexadecimal in compact transaction identifier (CTID) parameters in API methods. ([#5049](https://github.com/XRPLF/rippled/pull/5049)) +- Disallow filtering by types that an account can't own in the account_objects API method. ([#5056](https://github.com/XRPLF/rippled/pull/5056)) +- Fix error code returned by the feature API method when providing an invalid parameter. ([#5063](https://github.com/XRPLF/rippled/pull/5063)) +- (API v3) Fix error code returned by amm_info when providing invalid parameters. ([#4924](https://github.com/XRPLF/rippled/pull/4924)) + +### Other Improvements + +- Adds a new default hub, hubs.xrpkuwait.com, to the config file and bootstrapping code. ([#5169](https://github.com/XRPLF/rippled/pull/5169)) +- Improve error message when commandline interface fails with `rpcInternal` because there was no response from the server. ([#4959](https://github.com/XRPLF/rippled/pull/4959)) +- Add tools for debugging specific transactions via replay. ([#5027](https://github.com/XRPLF/rippled/pull/5027), [#5087](https://github.com/XRPLF/rippled/pull/5087)) +- Major reorganization of source code files. ([#4997](https://github.com/XRPLF/rippled/pull/4997)) +- Add new unit tests. ([#4886](https://github.com/XRPLF/rippled/pull/4886)) +- Various improvements to build tools and contributor documentation. ([#5001](https://github.com/XRPLF/rippled/pull/5001), [#5028](https://github.com/XRPLF/rippled/pull/5028), [#5052](https://github.com/XRPLF/rippled/pull/5052), [#5091](https://github.com/XRPLF/rippled/pull/5091), [#5084](https://github.com/XRPLF/rippled/pull/5084), [#5120](https://github.com/XRPLF/rippled/pull/5120), [#5010](https://github.com/XRPLF/rippled/pull/5010). [#5055](https://github.com/XRPLF/rippled/pull/5055), [#5067](https://github.com/XRPLF/rippled/pull/5067), [#5061](https://github.com/XRPLF/rippled/pull/5061), [#5072](https://github.com/XRPLF/rippled/pull/5072), [#5044](https://github.com/XRPLF/rippled/pull/5044) ) +- Various code cleanup and refactoring. ([#4509](https://github.com/XRPLF/rippled/pull/4509), [#4521](https://github.com/XRPLF/rippled/pull/4521), [#4856](https://github.com/XRPLF/rippled/pull/4856), [#5190](https://github.com/XRPLF/rippled/pull/5190), [#5081](https://github.com/XRPLF/rippled/pull/5081), [#5053](https://github.com/XRPLF/rippled/pull/5053), [#5058](https://github.com/XRPLF/rippled/pull/5058), [#5122](https://github.com/XRPLF/rippled/pull/5122), [#5059](https://github.com/XRPLF/rippled/pull/5059), [#5041](https://github.com/XRPLF/rippled/pull/5041)) + + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + +# Version 2.2.3 + +Version 2.2.3 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes a problem that can cause full-history servers to run out of space in their SQLite databases, depending on configuration. There are no new amendments in this release. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Background + +The `rippled` server uses a SQLite database for tracking transactions, in addition to the main data store (usually NuDB) for ledger data. In servers keeping a large amount of history, this database can run out of space based on the configured number and size of database pages, even if the machine has disk space available. Based on the size of full history on Mainnet, servers with the default SQLite page size of 4096 may now run out of space if they store full history. In this case, your server may shut down with an error such as the following: + +```text +Free SQLite space for transaction db is less than 512MB. To fix this, rippled + must be executed with the vacuum parameter before restarting. + Note that this activity can take multiple days, depending on database size. +``` + +The exact timing of when a server runs out of space can vary based on a few factors. Server operators who encountered a similar problem in 2018 and followed steps to [increase the SQLite transaction database page size issue](../../../docs/infrastructure/troubleshooting/fix-sqlite-tx-db-page-size-issue) may not encounter this problem at all. The `--vacuum` commandline option to `rippled` from that time may work to free up space in the database, but requires extended downtime. + +Version 2.2.3 of `rippled` reconfigures the maximum number of SQLite pages so that the issue does not occur. + +Clio servers providing full history are not affected by this issue. + + +## Action Required + +If you run an [XRP Ledger full history server](https://xrpl.org/docs/infrastructure/configuration/data-retention/configure-full-history), upgrading to version 2.2.3 may prevent the server from crashing when `transaction.db` exceeds approximately 8.7 terabytes. + +Additionally, five amendments introduced in version 2.2.0 are open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. If you operate an XRP Ledger server older than version 2.2.0, upgrade by Sep 23, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +## Changelog + +### Bug Fixes + +- Update SQLite3 max_page_count to match current defaults ([#5114](https://github.com/XRPLF/rippled/pull/5114)) + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +J. Scott Branson + + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + +# Version 2.2.2 + +Version 2.2.2 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes an ongoing issue with Mainnet where validators can stall during consensus processing due to lock contention, preventing ledgers from being validated for up to two minutes. There are no new amendments in this release. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Action Required + +If you run an XRP Ledger validator, upgrade to version 2.2.2 as soon as possible to ensure stable and uninterrupted network behavior. + +Additionally, five amendments introduced in version 2.2.0 are open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. If you operate an XRP Ledger server older than version 2.2.0, upgrade by September 17, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. Version 2.2.2 is recommended because of known bugs affecting stability of versions 2.2.0 and 2.2.1. + +If you operate a Clio server, Clio needs to be updated to 2.1.2 before updating to rippled 2.2.0. Clio will be blocked if it is not updated. + +## Changelog + +### Amendments and New Features + +- None + +### Bug Fixes and Performance Improvements + +- Allow only 1 job queue slot for acquiring inbound ledger [#5115](https://github.com/XRPLF/rippled/pull/5115) ([7741483](https://github.com/XRPLF/rippled/commit/774148389467781aca7c01bac90af2fba870570c)) + +- Allow only 1 job queue slot for each validation ledger check [#5115](https://github.com/XRPLF/rippled/pull/5115) ([fbbea9e](https://github.com/XRPLF/rippled/commit/fbbea9e6e25795a8a6bd1bf64b780771933a9579)) + +### Other improvements + + - Track latencies of certain code blocks, and log if they take too long [#5115](https://github.com/XRPLF/rippled/pull/5115) ([00ed7c9](https://github.com/XRPLF/rippled/commit/00ed7c942436f02644a13169002b5123f4e2a116)) + +### Docs and Build System + +- None + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +Mark Travis +Valentin Balaschenko <13349202+vlntb@users.noreply.github.com> + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + +# Version 2.2.1 + +Version 2.2.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes a critical bug introduced in 2.2.0 handling some types of RPC requests. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Action Required + +If you run an XRP Ledger validator, upgrade to version 2.2.1 as soon as possible to ensure stable and uninterrupted network behavior. + +Additionally, five amendments introduced in version 2.2.0 are open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. If you operate an XRP Ledger server older than version 2.2.0, upgrade by August 14, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. Version 2.2.1 is recommended because of known bugs affecting stability of versions 2.2.0. + +If you operate a Clio server, Clio needs to be updated to 2.2.2 before updating to rippled 2.2.1. Clio will be blocked if it is not updated. + +## Changelog + +### Amendments and New Features + +- None + +### Bug Fixes and Performance Improvements + +- Improve error handling in some RPC commands. [#5078](https://github.com/XRPLF/rippled/pull/5078) + +- Use error codes throughout fast Base58 implementation. [#5078](https://github.com/XRPLF/rippled/pull/5078) + +### Docs and Build System + +- None + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +John Freeman +Mayukha Vadari + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + +# Version 2.2.0 + +Version 2.2.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release adds performance optimizations, several bug fixes, and introduces the `featurePriceOracle`, `fixEmptyDID`, `fixXChainRewardRounding`, `fixPreviousTxnID`, and `fixAMMv1_1` amendments. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Action Required + +Five new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, upgrade to version 2.2.0 by June 17, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +If you operate a Clio server, Clio needs to be updated to 2.1.2 before updating to rippled 2.2.0. Clio will be blocked if it is not updated. + +## Changelog + +### Amendments and New Features +(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) + +- **featurePriceOracle** amendment: Implements a price oracle as defined in the [XLS-47](https://github.com/XRPLF/XRPL-Standards/blob/master/XLS-47d-PriceOracles/README.md) spec. A Price Oracle is used to bring real-world data, such as market prices, onto the blockchain, enabling dApps to access and utilize information that resides outside the blockchain. [#4789](https://github.com/XRPLF/rippled/pull/4789) + +- **fixEmptyDID** amendment: Modifies the behavior of the DID amendment: adds an additional check to ensure that DIDs are non-empty when created, and returns a `tecEMPTY_DID` error if the DID would be empty. [#4950](https://github.com/XRPLF/rippled/pull/4950) + +- **fixXChainRewardRounding** amendment: Modifies the behavior of the XChainBridge amendment: fixes rounding so reward shares are always rounded down, even when the `fixUniversalNumber` amendment is active. [#4933](https://github.com/XRPLF/rippled/pull/4933) + +- **fixPreviousTxnID** amendment: Adds `PreviousTxnID` and `PreviousTxnLgrSequence` as fields to all ledger entries that did not already have them included (`DirectoryNode`, `Amendments`, `FeeSettings`, `NegativeUNL`, and `AMM`). Existing ledger entries will gain the fields whenever transactions modify those entries. [#4751](https://github.com/XRPLF/rippled/pull/4751). + +- **fixAMMv1_1** amendment: Fixes AMM offer rounding and low quality order book offers from blocking the AMM. [#4983](https://github.com/XRPLF/rippled/pull/4983) + +- Add a non-admin version of `feature` API method. [#4781](https://github.com/XRPLF/rippled/pull/4781) + +### Bug Fixes and Performance Improvements +(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) + +- Optimize the base58 encoder and decoder. The algorithm is now about 10 times faster for encoding and 15 times faster for decoding. [#4327](https://github.com/XRPLF/rippled/pull/4327) + +- Optimize the `account_tx` SQL query. [#4955](https://github.com/XRPLF/rippled/pull/4955) + +- Don't reach consensus as quickly if no other proposals are seen. [#4763](https://github.com/XRPLF/rippled/pull/4763) + +- Fix a potential deadlock in the database module. [#4989](https://github.com/XRPLF/rippled/pull/4989) + +- Enforce no duplicate slots from incoming connections. [#4944](https://github.com/XRPLF/rippled/pull/4944) + +- Fix an order book update variable swap. [#4890](https://github.com/XRPLF/rippled/pull/4890) + +### Docs and Build System + +- Add unit test to raise the test coverage of the AMM. [#4971](https://github.com/XRPLF/rippled/pull/4971) + +- Improve test coverage reporting. [#4977](https://github.com/XRPLF/rippled/pull/4977) + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +Alex Kremer +Alloy Networks <45832257+alloynetworks@users.noreply.github.com> +Bronek Kozicki +Chenna Keshava +Denis Angell +Ed Hennis +Gregory Tsipenyuk +Howard Hinnant +John Freeman +Mark Travis +Mayukha Vadari +Michael Legleux +Nik Bougalis +Olek <115580134+oleks-rip@users.noreply.github.com> +Scott Determan +Snoppy + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + +## Version 2.1.1 + +The `rippled` 2.1.1 release fixes a critical bug in the integration of AMMs with the payment engine. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + + +## Action Required + +One new amendment is now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, upgrade to version 2.1.1 by April 8, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +## Changelog + +### Amendments + +- **fixAMMOverflowOffer**: Fix improper handling of large synthetic AMM offers in the payment engine. Due to the importance of this fix, the default vote in the source code has been set to YES. For information on how to configure your validator's amendment voting, see [Configure Amendment Voting](https://xrpl.org/docs/infrastructure/configuration/configure-amendment-voting). + +# Introducing XRP Ledger version 2.1.0 + +Version 2.1.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release adds a bug fix, build improvements, and introduces the `fixNFTokenReserve` and `fixInnerObjTemplate` amendments. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + + +## Action Required + +Two new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, upgrade to version 2.1.0 by March 5, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +## Changelog + +### Amendments +(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) + +- **fixNFTokenReserve**: Adds a check to the `NFTokenAcceptOffer` transactor to see if the `OwnerCount` changed. If it did, it checks that the reserve requirement is met. [#4767](https://github.com/XRPLF/rippled/pull/4767) + +- **fixInnerObjTemplate**: Adds an `STObject` constructor overload that includes an additional boolean argument to set the inner object template; currently, the inner object template isn't set upon object creation. In some circumstances, this causes a `tefEXCEPTION` error when trying to access the AMM `sfTradingFee` and `sfDiscountedFee` fields in the inner objects of `sfVoteEntry` and `sfAuctionSlot`. [#4906](https://github.com/XRPLF/rippled/pull/4906) + + +### Bug Fixes and Performance Improvements +(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) + +- Fixed a bug that prevented the gRPC port info from being specified in the `rippled` config file. [#4728](https://github.com/XRPLF/rippled/pull/4728) + + +### Docs and Build System + +- Added unit tests to check that payees and payers aren't the same account. [#4860](https://github.com/XRPLF/rippled/pull/4860) + +- Removed a workaround that bypassed Windows CI unit test failures. [#4871](https://github.com/XRPLF/rippled/pull/4871) + +- Updated library names to be platform-agnostic in Conan recipes. [#4831](https://github.com/XRPLF/rippled/pull/4831) + +- Added headers required in the Conan package to build xbridge witness servers. [#4885](https://github.com/XRPLF/rippled/pull/4885) + +- Improved object lifetime management when creating a temporary `Rules` object, fixing a crash in Windows unit tests. [#4917](https://github.com/XRPLF/rippled/pull/4917) + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +- Bronek Kozicki +- CJ Cobb +- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> +- Ed Hennis +- Elliot Lee +- Gregory Tsipenyuk +- John Freeman +- Michael Legleux +- Ryan Molley +- Shawn Xie <35279399+shawnxie999@users.noreply.github.com> + + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + +# Introducing XRP Ledger version 2.0.1 + +Version 2.0.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes minor fixes, unit test improvements, and doc updates. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + + +## Action Required + +If you operate an XRP Ledger server, upgrade to version 2.0.1 to take advantage of the changes included in this update. Nodes on version 1.12 should upgrade as soon as possible. + + +## Changelog + + +### Changes +(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) + +- Updated the `send_queue_limit` to 500 in the default `rippled` config to handle increased transaction loads. [#4867](https://github.com/XRPLF/rippled/pull/4867) + + +### Bug Fixes and Performance Improvements +(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) + +- Fixed an assertion that occurred when `rippled` was under heavy websocket client load. [#4848](https://github.com/XRPLF/rippled/pull/4848) + +- Improved lifetime management of serialized type ledger entries to improve memory usage. [#4822](https://github.com/XRPLF/rippled/pull/4822) + +- Fixed a clang warning about deprecated sprintf usage. [#4747](https://github.com/XRPLF/rippled/pull/4747) + + +### Docs and Build System + +- Added `DeliverMax` to more JSONRPC tests. [#4826](https://github.com/XRPLF/rippled/pull/4826) + +- Updated the pull request template to include a `Type of Change` checkbox and additional contextual questions. [#4875](https://github.com/XRPLF/rippled/pull/4875) + +- Updated help messages for unit tests pattern matching. [#4846](https://github.com/XRPLF/rippled/pull/4846) + +- Improved the time it take to generate coverage reports. [#4849](https://github.com/XRPLF/rippled/pull/4849) + +- Fixed broken links in the Conan build docs. [#4699](https://github.com/XRPLF/rippled/pull/4699) + +- Spurious codecov uploads are now retried if there's an error uploading them the first time. [#4896](https://github.com/XRPLF/rippled/pull/4896) + + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +- Bronek Kozicki +- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> +- Ed Hennis +- Elliot Lee +- Lathan Britz +- Mark Travis +- nixer89 + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + +# Introducing XRP Ledger version 2.0.0 + +Version 2.0.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release adds new features and bug fixes, and introduces these amendments: + +- `DID` +- `XChainBridge` +- `fixDisallowIncomingV1` +- `fixFillOrKill` + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + + +## Action Required + +Four new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, upgrade to version 2.0.0 by January 22, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + + +## Changelog + + +### Amendments, New Features, and Changes +(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) + +- **XChainBridge**: Introduces cross-chain bridges, enabling interoperability between the XRP Ledger and sidechains. [#4292](https://github.com/XRPLF/rippled/pull/4292) + +- **DID**: Introduces decentralized identifiers. [#4636](https://github.com/XRPLF/rippled/pull/4636) + +- **fixDisallowIncomingV1**: Fixes an issue that occurs when users try to authorize a trustline while the `lsfDisallowIncomingTrustline` flag is enabled on their account. [#4721](https://github.com/XRPLF/rippled/pull/4721) + +- **fixFillOrKill**: Fixes an issue introduced in the `flowCross` amendment. The `tfFillOrKill` and `tfSell` flags are now properly handled to allow offers to cross in certain scenarios. [#4694](https://github.com/XRPLF/rippled/pull/4694) + +- **API v2 released with these changes:** + + - Accepts currency codes in ASCII, using the full alphabet. [#4566](https://github.com/XRPLF/rippled/pull/4566) + - Added test to verify the `check` field is a string. [#4630](https://github.com/XRPLF/rippled/pull/4630) + - Added errors for malformed `account_tx` and `noripple_check` fields. [#4620](https://github.com/XRPLF/rippled/pull/4620) + - Added errors for malformed `gateway_balances` and `channel_authorize` requests. [#4618](https://github.com/XRPLF/rippled/pull/4618) + - Added a `DeliverMax` alias to `Amount` and removed `Amount`. [#4733](https://github.com/XRPLF/rippled/pull/4733) + - Removed `tx_history` and `ledger_header` methods. Also updated `RPC::Handler` to allow for version-specific methods. [#4759](https://github.com/XRPLF/rippled/pull/4759) + - Standardized the JSON serialization format of transactions. [#4727](https://github.com/XRPLF/rippled/issues/4727) + - Bumped API support to v2, but kept the command-line interface for `rippled` and unit tests at v1. [#4803](https://github.com/XRPLF/rippled/pull/4803) + - Standardized `ledger_index` to return as a number. [#4820](https://github.com/XRPLF/rippled/pull/4820) + +- Added a `server_definitions` command that returns an SDK-compatible `definitions.json` file, generated from the `rippled` instance currently running. [#4703](https://github.com/XRPLF/rippled/pull/4703) + +- Improved unit test command line input and run times. [#4634](https://github.com/XRPLF/rippled/pull/4634) + +- Added the link compression setting to the the `rippled-example.cfg` file. [#4753](https://github.com/XRPLF/rippled/pull/4753) + +- Changed the reserved hook error code name from `tecHOOK_ERROR` to `tecHOOK_REJECTED`. [#4559](https://github.com/XRPLF/rippled/pull/4559) + + +### Bug Fixes and Performance Improvements +(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) + +- Simplified `TxFormats` common fields logic. [#4637](https://github.com/XRPLF/rippled/pull/4637) + +- Improved transaction throughput by asynchronously writing batches to *NuDB*. [#4503](https://github.com/XRPLF/rippled/pull/4503) + +- Removed 2 unused functions. [#4708](https://github.com/XRPLF/rippled/pull/4708) + +- Removed an unused variable that caused clang 14 build errors. [#4672](https://github.com/XRPLF/rippled/pull/4672) + +- Fixed comment about return value of `LedgerHistory::fixIndex`. [#4574](https://github.com/XRPLF/rippled/pull/4574) + +- Updated `secp256k1` to 0.3.2. [#4653](https://github.com/XRPLF/rippled/pull/4653) + +- Removed built-in SNTP clock issues. [#4628](https://github.com/XRPLF/rippled/pull/4628) + +- Fixed amendment flapping. This issue usually occurred when an amendment was on the verge of gaining majority, but a validator not in favor of the amendment went offline. [#4410](https://github.com/XRPLF/rippled/pull/4410) + +- Fixed asan stack-use-after-scope issue. [#4676](https://github.com/XRPLF/rippled/pull/4676) + +- Transactions and pseudo-transactions share the same `commonFields` again. [#4715](https://github.com/XRPLF/rippled/pull/4715) + +- Reduced boilerplate in `applySteps.cpp`. When a new transactor is added, only one function needs to be modified now. [#4710](https://github.com/XRPLF/rippled/pull/4710) + +- Removed an incorrect assert. [#4743](https://github.com/XRPLF/rippled/pull/4743) + +- Replaced some asserts in `PeerFinder::Logic` with `LogicError` to better indicate the nature of server crashes. [#4562](https://github.com/XRPLF/rippled/pull/4562) + +- Fixed an issue with enabling new amendments on a network with an ID greater than 1024. [#4737](https://github.com/XRPLF/rippled/pull/4737) + + +### Docs and Build System + +- Updated `rippled-example.cfg` docs to clarify usage of *ssl_cert* vs *ssl_chain*. [#4667](https://github.com/XRPLF/rippled/pull/4667) + +- Updated `BUILD.md`: + - Made the `environment.md` link easier to find. Also made it easier to find platform-specific info. [#4507](https://github.com/XRPLF/rippled/pull/4507) + - Fixed typo. [#4718](https://github.com/XRPLF/rippled/pull/4718) + - Updated the minimum compiler requirements. [#4700](https://github.com/XRPLF/rippled/pull/4700) + - Added note about enabling `XRPFees`. [#4741](https://github.com/XRPLF/rippled/pull/4741) + +- Updated `API-CHANGELOG.md`: + - Explained API v2 is releasing with `rippled` 2.0.0. [#4633](https://github.com/XRPLF/rippled/pull/4633) + - Clarified the location of the `signer_lists` field in the `account_info` response for API v2. [#4724](https://github.com/XRPLF/rippled/pull/4724) + - Added documentation for the new `DeliverMax` field. [#4784](https://github.com/XRPLF/rippled/pull/4784) + - Removed references to API v2 being "in progress" and "in beta". [#4828](https://github.com/XRPLF/rippled/pull/4828) + - Clarified that all breaking API changes will now occur in API v3 or later. [#4773](https://github.com/XRPLF/rippled/pull/4773) + +- Fixed a mistake in the overlay README. [#4635](https://github.com/XRPLF/rippled/pull/4635) + +- Fixed an early return from `RippledRelease.cmake` that prevented targets from being created during packaging. [#4707](https://github.com/XRPLF/rippled/pull/4707) + +- Fixed a build error with Intel Macs. [#4632](https://github.com/XRPLF/rippled/pull/4632) + +- Added `.build` to `.gitignore`. [#4722](https://github.com/XRPLF/rippled/pull/4722) + +- Fixed a `uint is not universally defined` Windows build error. [#4731](https://github.com/XRPLF/rippled/pull/4731) + +- Reenabled Windows CI build with Artifactory support. [#4596](https://github.com/XRPLF/rippled/pull/4596) + +- Fixed output of remote step in Nix workflow. [#4746](https://github.com/XRPLF/rippled/pull/4746) + +- Fixed a broken link in `conan.md`. [#4740](https://github.com/XRPLF/rippled/pull/4740) + +- Added a `python` call to fix the `pip` upgrade command in Windows CI. [#4768](https://github.com/XRPLF/rippled/pull/4768) + +- Added an API Impact section to `pull_request_template.md`. [#4757](https://github.com/XRPLF/rippled/pull/4757) + +- Set permissions for the Doxygen workflow. [#4756](https://github.com/XRPLF/rippled/pull/4756) + +- Switched to Unity builds to speed up Windows CI. [#4780](https://github.com/XRPLF/rippled/pull/4780) + +- Clarified what makes consensus healthy in `FeeEscalation.md`. [#4729](https://github.com/XRPLF/rippled/pull/4729) + +- Removed a dependency on the header for unit tests. [#4788](https://github.com/XRPLF/rippled/pull/4788) + +- Fixed a clang `unused-but-set-variable` warning. [#4677](https://github.com/XRPLF/rippled/pull/4677) + +- Removed an unused Dockerfile. [#4791](https://github.com/XRPLF/rippled/pull/4791) + +- Fixed unit tests to work with API v2. [#4785](https://github.com/XRPLF/rippled/pull/4785) + +- Added support for the mold linker on Linux. [#4807](https://github.com/XRPLF/rippled/pull/4807) + +- Updated Linux distribtuions `rippled` smoke tests run on. [#4813](https://github.com/XRPLF/rippled/pull/4813) + +- Added codename `bookworm` to the distribution matrix during Artifactory uploads, enabling Debian 12 clients to install `rippled` packages. [#4836](https://github.com/XRPLF/rippled/pull/4836) + +- Added a workaround for compilation errors with GCC 13 and other compilers relying on libstdc++ version 13. [#4817](https://github.com/XRPLF/rippled/pull/4817) + +- Fixed a minor typo in the code comments of `AMMCreate.h`. [4821](https://github.com/XRPLF/rippled/pull/4821) + + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +- Bronek Kozicki +- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> +- Denis Angell +- Ed Hennis +- Elliot Lee +- Florent <36513774+florent-uzio@users.noreply.github.com> +- ForwardSlashBack <142098649+ForwardSlashBack@users.noreply.github.com> +- Gregory Tsipenyuk +- Howard Hinnant +- Hussein Badakhchani +- Jackson Mills +- John Freeman +- Manoj Doshi +- Mark Pevec +- Mark Travis +- Mayukha Vadari +- Michael Legleux +- Nik Bougalis +- Peter Chen <34582813+PeterChen13579@users.noreply.github.com> +- Rome Reginelli +- Scott Determan +- Scott Schurr +- Sophia Xie <106177003+sophiax851@users.noreply.github.com> +- Stefan van Kessel +- pwang200 <354723+pwang200@users.noreply.github.com> +- shichengsg002 <147461171+shichengsg002@users.noreply.github.com> +- sokkaofthewatertribe <140777955+sokkaofthewatertribe@users.noreply.github.com> + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the rippled code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + +# Introducing XRP Ledger version 1.12.0 + +Version 1.12.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release adds new features and bug fixes, and introduces these amendments: + +- `AMM` +- `Clawback` +- `fixReducedOffersV1` + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Action Required + +Three new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, upgrade to version 1.12.0 by September 20, 2023 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + + +## Install / Upgrade + +On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). + +The XRPL Foundation publishes portable binaries, which are drop-in replacements for the `rippled` daemon. [See information and downloads for the portable binaries](https://github.com/XRPLF/rippled-portable-builds#portable-builds-of-the-rippled-server). This will work on most distributions, including Ubuntu 16.04, 18.04, 20.04, and 22.04; CentOS; and others. Please test and open issues on GitHub if there are problems. + + +## Changelog + +### Amendments, New Features, and Changes +(These are changes which may impact or be useful to end users. For example, you may be able to update your code/workflow to take advantage of these changes.) + +- **`AMM`**: Introduces an automated market maker (AMM) protocol to the XRP Ledger's decentralized exchange, enabling you to trade assets without a counterparty. For more information about AMMs, see: [Automated Market Maker](https://opensource.ripple.com/docs/xls-30d-amm/amm-uc/). [#4294](https://github.com/XRPLF/rippled/pull/4294) + +- **`Clawback`**: Adds a setting, *Allow Clawback*, which lets an issuer recover, or _claw back_, tokens that they previously issued. Issuers cannot enable this setting if they have issued tokens already. For additional documentation on this feature, see: [#4553](https://github.com/XRPLF/rippled/pull/4553). + +- **`fixReducedOffersV1`**: Reduces the occurrence of order books that are blocked by reduced offers. [#4512](https://github.com/XRPLF/rippled/pull/4512) + +- Added WebSocket and RPC port info to `server_info` responses. [#4427](https://github.com/XRPLF/rippled/pull/4427) + +- Removed the deprecated `accepted`, `seqNum`, `hash`, and `totalCoins` fields from the `ledger` method. [#4244](https://github.com/XRPLF/rippled/pull/4244) + + +### Bug Fixes and Performance Improvements +(These are behind-the-scenes improvements, such as internal changes to the code, which are not expected to impact end users.) + +- Added a pre-commit hook that runs the clang-format linter locally before committing changes. To install this feature, see: [CONTRIBUTING](https://github.com/XRPLF/xrpl-dev-portal/blob/master/CONTRIBUTING.md). [#4599](https://github.com/XRPLF/rippled/pull/4599) + +- In order to make it more straightforward to catch and handle overflows: changed the output type of the `mulDiv()` function from `std::pair` to `std::optional`. [#4243](https://github.com/XRPLF/rippled/pull/4243) + +- Updated `Handler::Condition` enum values to make the code less brittle. [#4239](https://github.com/XRPLF/rippled/pull/4239) + +- Renamed `ServerHandlerImp` to `ServerHandler`. [#4516](https://github.com/XRPLF/rippled/pull/4516), [#4592](https://github.com/XRPLF/rippled/pull/4592) + +- Replaced hand-rolled code with `std::from_chars` for better maintainability. [#4473](https://github.com/XRPLF/rippled/pull/4473) + +- Removed an unused `TypedField` move constructor. [#4567](https://github.com/XRPLF/rippled/pull/4567) + + +### Docs and Build System + +- Updated checkout versions to resolve warnings during GitHub jobs. [#4598](https://github.com/XRPLF/rippled/pull/4598) + +- Fixed an issue with the Debian package build. [#4591](https://github.com/XRPLF/rippled/pull/4591) + +- Updated build instructions with additional steps to take after updating dependencies. [#4623](https://github.com/XRPLF/rippled/pull/4623) + +- Updated contributing doc to clarify that beta releases should also be pushed to the `release` branch. [#4589](https://github.com/XRPLF/rippled/pull/4589) + +- Enabled the `BETA_RPC_API` flag in the default unit tests config, making the API v2 (beta) available to unit tests. [#4573](https://github.com/XRPLF/rippled/pull/4573) + +- Conan dependency management. + - Fixed package definitions for Conan. [#4485](https://github.com/XRPLF/rippled/pull/4485) + - Updated build dependencies to the most recent versions in Conan Center. [#4595](https://github.com/XRPLF/rippled/pull/4595) + - Updated Conan recipe for NuDB. [#4615](https://github.com/XRPLF/rippled/pull/4615) + +- Added binary hardening and linker flags to enhance security during the build process. [#4603](https://github.com/XRPLF/rippled/pull/4603) + +- Added an Artifactory to the `nix` workflow to improve build times. [#4556](https://github.com/XRPLF/rippled/pull/4556) + +- Added quality-of-life improvements to workflows, using new [concurrency control](https://docs.github.com/en/actions/using-jobs/using-concurrency) features. [#4597](https://github.com/XRPLF/rippled/pull/4597) + + +[Full Commit Log](https://github.com/XRPLF/rippled/compare/1.11.0...1.12.0) + + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +- Alphonse N. Mousse <39067955+a-noni-mousse@users.noreply.github.com> +- Arihant Kothari +- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> +- Denis Angell +- Ed Hennis +- Elliot Lee +- Gregory Tsipenyuk +- Howard Hinnant +- Ikko Eltociear Ashimine +- John Freeman +- Manoj Doshi +- Mark Travis +- Mayukha Vadari +- Michael Legleux +- Peter Chen <34582813+PeterChen13579@users.noreply.github.com> +- RichardAH +- Rome Reginelli +- Scott Schurr +- Shawn Xie <35279399+shawnxie999@users.noreply.github.com> +- drlongle + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the rippled code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + +# Introducing XRP Ledger version 1.11.0 + +Version 1.11.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. + +This release reduces memory usage, introduces the `fixNFTokenRemint` amendment, and adds new features and bug fixes. For example, the new NetworkID field in transactions helps to prevent replay attacks with side-chains. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Action Required + +The `fixNFTokenRemint` amendment is now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, upgrade to version 1.11.0 by July 5 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + + +## Install / Upgrade + +On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). + + +## What's Changed + +### New Features and Improvements + +* Allow port numbers be be specified using a either a colon or a space by @RichardAH in https://github.com/XRPLF/rippled/pull/4328 +* Eliminate memory allocation from critical path: by @nbougalis in https://github.com/XRPLF/rippled/pull/4353 +* Make it easy for projects to depend on libxrpl by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4449 +* Add the ability to mark amendments as obsolete by @ximinez in https://github.com/XRPLF/rippled/pull/4291 +* Always create the FeeSettings object in genesis ledger by @ximinez in https://github.com/XRPLF/rippled/pull/4319 +* Log exception messages in several locations by @drlongle in https://github.com/XRPLF/rippled/pull/4400 +* Parse flags in account_info method by @drlongle in https://github.com/XRPLF/rippled/pull/4459 +* Add NFTokenPages to account_objects RPC by @RichardAH in https://github.com/XRPLF/rippled/pull/4352 +* add jss fields used by clio `nft_info` by @ledhed2222 in https://github.com/XRPLF/rippled/pull/4320 +* Introduce a slab-based memory allocator and optimize SHAMapItem by @nbougalis in https://github.com/XRPLF/rippled/pull/4218 +* Add NetworkID field to transactions to help prevent replay attacks on and from side-chains by @RichardAH in https://github.com/XRPLF/rippled/pull/4370 +* If present, set quorum based on command line. by @mtrippled in https://github.com/XRPLF/rippled/pull/4489 +* API does not accept seed or public key for account by @drlongle in https://github.com/XRPLF/rippled/pull/4404 +* Add `nftoken_id`, `nftoken_ids` and `offer_id` meta fields into NFT `Tx` responses by @shawnxie999 in https://github.com/XRPLF/rippled/pull/4447 + +### Bug Fixes + +* fix(gateway_balances): handle overflow exception by @RichardAH in https://github.com/XRPLF/rippled/pull/4355 +* fix(ValidatorSite): handle rare null pointer dereference in timeout by @ximinez in https://github.com/XRPLF/rippled/pull/4420 +* RPC commands understand markers derived from all ledger object types by @ximinez in https://github.com/XRPLF/rippled/pull/4361 +* `fixNFTokenRemint`: prevent NFT re-mint: by @shawnxie999 in https://github.com/XRPLF/rippled/pull/4406 +* Fix a case where ripple::Expected returned a json array, not a value by @scottschurr in https://github.com/XRPLF/rippled/pull/4401 +* fix: Ledger data returns an empty list (instead of null) when all entries are filtered out by @drlongle in https://github.com/XRPLF/rippled/pull/4398 +* Fix unit test ripple.app.LedgerData by @drlongle in https://github.com/XRPLF/rippled/pull/4484 +* Fix the fix for std::result_of by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4496 +* Fix errors for Clang 16 by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4501 +* Ensure that switchover vars are initialized before use: by @seelabs in https://github.com/XRPLF/rippled/pull/4527 +* Move faulty assert by @ximinez in https://github.com/XRPLF/rippled/pull/4533 +* Fix unaligned load and stores: (#4528) by @seelabs in https://github.com/XRPLF/rippled/pull/4531 +* fix node size estimation by @dangell7 in https://github.com/XRPLF/rippled/pull/4536 +* fix: remove redundant moves by @ckeshava in https://github.com/XRPLF/rippled/pull/4565 + +### Code Cleanup and Testing + +* Replace compare() with the three-way comparison operator in base_uint, Issue and Book by @drlongle in https://github.com/XRPLF/rippled/pull/4411 +* Rectify the import paths of boost::function_output_iterator by @ckeshava in https://github.com/XRPLF/rippled/pull/4293 +* Expand Linux test matrix by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4454 +* Add patched recipe for SOCI by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4510 +* Switch to self-hosted runners for macOS by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4511 +* [TRIVIAL] Add missing includes by @seelabs in https://github.com/XRPLF/rippled/pull/4555 + +### Docs + +* Refactor build instructions by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4381 +* Add install instructions for package managers by @thejohnfreeman in https://github.com/XRPLF/rippled/pull/4472 +* Fix typo by @solmsted in https://github.com/XRPLF/rippled/pull/4508 +* Update environment.md by @sappenin in https://github.com/XRPLF/rippled/pull/4498 +* Update BUILD.md by @oeggert in https://github.com/XRPLF/rippled/pull/4514 +* Trivial: add comments for NFToken-related invariants by @scottschurr in https://github.com/XRPLF/rippled/pull/4558 + +## New Contributors +* @drlongle made their first contribution in https://github.com/XRPLF/rippled/pull/4411 +* @ckeshava made their first contribution in https://github.com/XRPLF/rippled/pull/4293 +* @solmsted made their first contribution in https://github.com/XRPLF/rippled/pull/4508 +* @sappenin made their first contribution in https://github.com/XRPLF/rippled/pull/4498 +* @oeggert made their first contribution in https://github.com/XRPLF/rippled/pull/4514 + +**Full Changelog**: https://github.com/XRPLF/rippled/compare/1.10.1...1.11.0 + + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + +### Credits + +The following people contributed directly to this release: +- Alloy Networks <45832257+alloynetworks@users.noreply.github.com> +- Brandon Wilson +- Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> +- David Fuelling +- Denis Angell +- Ed Hennis +- Elliot Lee +- John Freeman +- Mark Travis +- Nik Bougalis +- RichardAH +- Scott Determan +- Scott Schurr +- Shawn Xie <35279399+shawnxie999@users.noreply.github.com> +- drlongle +- ledhed2222 +- oeggert <117319296+oeggert@users.noreply.github.com> +- solmsted + + +Bug Bounties and Responsible Disclosures: +We welcome reviews of the rippled code and urge researchers to +responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + bugs@xrpl.org + + +# Introducing XRP Ledger version 1.10.1 + +Version 1.10.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release restores packages for Ubuntu 18.04. + +Compared to version 1.10.0, the only C++ code change fixes an edge case in Reporting Mode. + +If you are already running version 1.10.0, then upgrading to version 1.10.1 is generally not required. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Install / Upgrade + +On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). + +## Changelog + +- [`da18c86cbf`](https://github.com/ripple/rippled/commit/da18c86cbfea1d8fe6940035f9103e15890d47ce) Build packages with Ubuntu 18.04 +- [`f7b3ddd87b`](https://github.com/ripple/rippled/commit/f7b3ddd87b8ef093a06ab1420bea57ed1e77643a) Reporting Mode: Do not attempt to acquire missing data from peer network (#4458) + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + +### Credits + +The following people contributed directly to this release: + +- John Freeman +- Mark Travis +- Michael Legleux + +Bug Bounties and Responsible Disclosures: +We welcome reviews of the rippled code and urge researchers to +responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + bugs@xrpl.org + + +# Introducing XRP Ledger version 1.10.0 + +Version 1.10.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release introduces six new amendments, detailed below, and cleans up code to improve performance. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Action Required + +Six new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, upgrade to version 1.10.0 by March 21 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + + +## Install / Upgrade + +On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). + + +## New Amendments + +- **`featureImmediateOfferKilled`**: Changes the response code of an `OfferCreate` transaction with the `tfImmediateOrCancel` flag to return `tecKILLED` when no funds are moved. The previous return code of `tecSUCCESS` was unintuitive. [#4157](https://github.com/XRPLF/rippled/pull/4157) + +- **`featureDisallowIncoming`**: Enables an account to block incoming checks, payment channels, NFToken offers, and trust lines. [#4336](https://github.com/XRPLF/rippled/pull/4336) + +- **`featureXRPFees`**: Simplifies transaction cost calculations to use XRP directly, rather than calculating indirectly in "fee units" and translating the results to XRP. Updates all instances of "fee units" in the protocol and ledger data to be drops of XRP instead. [#4247](https://github.com/XRPLF/rippled/pull/4247) + +- **`fixUniversalNumber`**: Simplifies and unifies the code for decimal floating point math. In some cases, this provides slightly better accuracy than the previous code, resulting in calculations whose least significant digits are different than when calculated with the previous code. The different results may cause other edge case differences where precise calculations are used, such as ranking of offers or processing of payments that use several different paths. [#4192](https://github.com/XRPLF/rippled/pull/4192) + +- **`fixNonFungibleTokensV1_2`**: This amendment is a combination of NFToken fixes. [#4417](https://github.com/XRPLF/rippled/pull/4417) + - Fixes unburnable NFTokens when it has over 500 offers. [#4346](https://github.com/XRPLF/rippled/pull/4346) + - Fixes 3 NFToken offer acceptance issues. [#4380](https://github.com/XRPLF/rippled/pull/4380) + - Prevents brokered sales of NFTokens to owners. [#4403](https://github.com/XRPLF/rippled/pull/4403) + - Only allows the destination to settle NFToken offers through brokerage. [#4399](https://github.com/XRPLF/rippled/pull/4399) + +- **`fixTrustLinesToSelf`**: Trust lines must be between two different accounts, but two exceptions exist because of a bug that briefly existed. This amendment removes those trust lines. [69bb2be](https://github.com/XRPLF/rippled/pull/4270/commits/69bb2be446e3cc24c694c0835b48bd2ecd3d119e) + + +## Changelog + + +### New Features and Improvements + +- **Improve Handshake in the peer protocol**: Switched to using a cryptographically secure PRNG for the Instance Cookie. `rippled` now uses hex encoding for the `Closed-Ledger` and `Previous-Ledger` fields in the Handshake. Also added `--newnodeid` and `--nodeid` command line options. [5a15229](https://github.com/XRPLF/rippled/pull/4270/commits/5a15229eeb13b69c8adf1f653b88a8f8b9480546) + +- **RPC tooBusy response now has 503 HTTP status code**: Added ripplerpc 3.0, enabling RPC tooBusy responses to return relevant HTTP status codes. This is a non-breaking change that only applies to JSON-RPC when you include `"ripplerpc": "3.0"` in the request. [#4143](https://github.com/XRPLF/rippled/pull/4143) + +- **Use the Conan package manager**: Added a `conanfile.py` and Conan recipe for Snappy. Removed the RocksDB recipe from the repo; you can now get it from Conan Center. [#4367](https://github.com/XRPLF/rippled/pull/4367), [c2b03fe](https://github.com/XRPLF/rippled/commit/c2b03fecca19a304b37467b01fa78593d3dce3fb) + +- **Update Build Instructions**: Updated the build instructions to build with the Conan package manager and restructured info for easier comprehension. [#4376](https://github.com/XRPLF/rippled/pull/4376), [#4383](https://github.com/XRPLF/rippled/pull/4383) + +- **Revise CONTRIBUTING**: Updated code contribution guidelines. `rippled` is an open source project and contributions are very welcome. [#4382](https://github.com/XRPLF/rippled/pull/4382) + +- **Update documented pathfinding configuration defaults**: `417cfc2` changed the default Path Finding configuration values, but missed updating the values documented in rippled-example.cfg. Updated those defaults and added recommended values for nodes that want to support advanced pathfinding. [#4409](https://github.com/XRPLF/rippled/pull/4409) + +- **Remove gRPC code previously used for the Xpring SDK**: Removed gRPC code used for the Xpring SDK. The gRPC API is also enabled locally by default in `rippled-example.cfg`. This API is used for [Reporting Mode](https://xrpl.org/build-run-rippled-in-reporting-mode.html) and [Clio](https://github.com/XRPLF/clio). [28f4cc7](https://github.com/XRPLF/rippled/pull/4321/commits/28f4cc7817c2e477f0d7e9ade8f07a45ff2b81f1) + +- **Switch from C++17 to C++20**: Updated `rippled` to use C++20. [92d35e5](https://github.com/XRPLF/rippled/pull/4270/commits/92d35e54c7de6bbe44ff6c7c52cc0765b3f78258) + +- **Support for Boost 1.80.0:**: [04ef885](https://github.com/XRPLF/rippled/pull/4321/commits/04ef8851081f6ee9176783ad3725960b8a931ebb) + +- **Reduce default reserves to 10/2**: Updated the hard-coded default reserves to match the current settings on Mainnet. [#4329](https://github.com/XRPLF/rippled/pull/4329) + +- **Improve self-signed certificate generation**: Improved speed and security of TLS certificate generation on fresh startup. [0ecfc7c](https://github.com/XRPLF/rippled/pull/4270/commits/0ecfc7cb1a958b731e5f184876ea89ae2d4214ee) + + +### Bug Fixes + +- **Update command-line usage help message**: Added `manifest` and `validator_info` to the `rippled` CLI usage statement. [b88ed5a](https://github.com/XRPLF/rippled/pull/4270/commits/b88ed5a8ec2a0735031ca23dc6569d54787dc2f2) + +- **Work around gdb bug by changing a template parameter**: Added a workaround for a bug in gdb, where unsigned template parameters caused issues with RTTI. [#4332](https://github.com/XRPLF/rippled/pull/4332) + +- **Fix clang 15 warnings**: [#4325](https://github.com/XRPLF/rippled/pull/4325) + +- **Catch transaction deserialization error in doLedgerGrpc**: Fixed an issue in the gRPC API, so `Clio` can extract ledger headers and state objects from specific transactions that can't be deserialized by `rippled` code. [#4323](https://github.com/XRPLF/rippled/pull/4323) + +- **Update dependency: gRPC**: New Conan recipes broke the old version of gRPC, so the dependency was updated. [#4407](https://github.com/XRPLF/rippled/pull/4407) + +- **Fix Doxygen workflow**: Added options to build documentation that don't depend on the library dependencies of `rippled`. [#4372](https://github.com/XRPLF/rippled/pull/4372) + +- **Don't try to read SLE with key 0 from the ledger**: Fixed the `preclaim` function to check for 0 in `NFTokenSellOffer` and `NFTokenBuyOffer` before calling `Ledger::read`. This issue only affected debug builds. [#4351](https://github.com/XRPLF/rippled/pull/4351) + +- **Update broken link to hosted Doxygen content**: [5e1cb09](https://github.com/XRPLF/rippled/pull/4270/commits/5e1cb09b8892e650f6c34a66521b6b1673bd6b65) + + +### Code Cleanup + +- **Prevent unnecessary `shared_ptr` copies by accepting a value in `SHAMapInnerNode::setChild`**: [#4266](https://github.com/XRPLF/rippled/pull/4266) + +- **Release TaggedCache object memory outside the lock**: [3726f8b](https://github.com/XRPLF/rippled/pull/4321/commits/3726f8bf31b3eab8bab39dce139656fd705ae9a0) + +- **Rename SHAMapStoreImp::stopping() to healthWait()**: [7e9e910](https://github.com/XRPLF/rippled/pull/4321/commits/7e9e9104eabbf0391a0837de5630af17a788e233) + +- **Improve wrapper around OpenSSL RAND**: [7b3507b](https://github.com/XRPLF/rippled/pull/4270/commits/7b3507bb873495a974db33c57a888221ddabcacc) + +- **Improve AccountID string conversion caching**: Improved memory cache usage. [e2eed96](https://github.com/XRPLF/rippled/pull/4270/commits/e2eed966b0ecb6445027e6a023b48d702c5f4832) + +- **Build the command map at compile time**: [9aaa0df](https://github.com/XRPLF/rippled/pull/4270/commits/9aaa0dff5fd422e5f6880df8e20a1fd5ad3b4424) + +- **Avoid unnecessary copying and dynamic memory allocations**: [d318ab6](https://github.com/XRPLF/rippled/pull/4270/commits/d318ab612adc86f1fd8527a50af232f377ca89ef) + +- **Use constexpr to check memo validity**: [e67f905](https://github.com/XRPLF/rippled/pull/4270/commits/e67f90588a9050162881389d7e7d1d0fb31066b0) + +- **Remove charUnHex**: [83ac141](https://github.com/XRPLF/rippled/pull/4270/commits/83ac141f656b1a95b5661853951ebd95b3ffba99) + +- **Remove deprecated AccountTxOld.cpp**: [ce64f7a](https://github.com/XRPLF/rippled/pull/4270/commits/ce64f7a90f99c6b5e68d3c3d913443023de061a6) + +- **Remove const_cast usage**: [23ce431](https://github.com/XRPLF/rippled/pull/4321/commits/23ce4318768b718c82e01004d23f1abc9a9549ff) + +- **Remove inaccessible code paths and outdated data format wchar_t**: [95fabd5](https://github.com/XRPLF/rippled/pull/4321/commits/95fabd5762a4917753c06268192e4d4e4baef8e4) + +- **Improve move semantics in Expected**: [#4326](https://github.com/XRPLF/rippled/pull/4326) + + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + +### Credits + +The following people contributed directly to this release: + +- Alexander Kremer +- Alloy Networks <45832257+alloynetworks@users.noreply.github.com> +- CJ Cobb <46455409+cjcobb23@users.noreply.github.com> +- Chenna Keshava B S +- Crypto Brad Garlinghouse +- Denis Angell +- Ed Hennis +- Elliot Lee +- Gregory Popovitch +- Howard Hinnant +- J. Scott Branson <18340247+crypticrabbit@users.noreply.github.com> +- John Freeman +- ledhed2222 +- Levin Winter <33220502+levinwinter@users.noreply.github.com> +- manojsdoshi +- Nik Bougalis +- RichardAH +- Scott Determan +- Scott Schurr +- Shawn Xie <35279399+shawnxie999@users.noreply.github.com> + +Security Bug Bounty Acknowledgements: +- Aaron Hook +- Levin Winter + +Bug Bounties and Responsible Disclosures: +We welcome reviews of the rippled code and urge researchers to +responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + bugs@xrpl.org + + +# Introducing XRP Ledger version 1.9.4 + +Version 1.9.4 of `rippled`, the reference implementation of the XRP Ledger protocol is now available. This release introduces an amendment that removes the ability for an NFT issuer to indicate that trust lines should be automatically created for royalty payments from secondary sales of NFTs, in response to a bug report that indicated how this functionality could be abused to mount a denial of service attack against the issuer. + +## Action Required + +This release introduces a new amendment to the XRP Ledger protocol, **`fixRemoveNFTokenAutoTrustLine`** to mitigate a potential denial-of-service attack against NFT issuers that minted NFTs and allowed secondary trading of those NFTs to create trust lines for any asset. + +This amendment is open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, then you should upgrade to version 1.9.4 within two weeks, to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +For more information about NFTs on the XRP Ledger, see [NFT Conceptual Overview](https://xrpl.org/nft-conceptual-overview.html). + + +## Install / Upgrade + +On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). + +## Changelog + +## Contributions + +The primary change in this release is the following bug fix: + +- **Introduce fixRemoveNFTokenAutoTrustLine amendment**: Introduces the `fixRemoveNFTokenAutoTrustLine` amendment, which disables the `tfTrustLine` flag, which a malicious attacker could exploit to mount denial-of-service attacks against NFT issuers that specified the flag on their NFTs. ([#4301](https://github.com/XRPLF/rippled/4301)) + + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers and help us build the Internet of Value. + +### Credits + +The following people contributed directly to this release: + +- Scott Schurr +- Howard Hinnant +- Scott Determan +- Ikko Ashimine + + +# Introducing XRP Ledger version 1.9.3 + +Version 1.9.3 of `rippled`, the reference server implementation of the XRP Ledger protocol is now available. This release corrects minor technical flaws with the code that loads configured amendment votes after a startup and the copy constructor of `PublicKey`. + +## Install / Upgrade + +On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). + +## Changelog + +## Contributions + +This release contains the following bug fixes: + +- **Change by-value to by-reference to persist vote**: A minor technical flaw, caused by use of a copy instead of a reference, resulted in operator-configured "yes" votes to not be properly loaded after a restart. ([#4256](https://github.com/XRPLF/rippled/pull/4256)) +- **Properly handle self-assignment of PublicKey**: The `PublicKey` copy assignment operator mishandled the case where a `PublicKey` would be assigned to itself, and could result in undefined behavior. + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome contributions, big and small, and invite everyone to join the community of XRP Ledger developers and help us build the Internet of Value. + +### Credits + +The following people contributed directly to this release: + +- Howard Hinnant +- Crypto Brad Garlinghouse +- Wo Jake <87929946+wojake@users.noreply.github.com> + + +# Introducing XRP Ledger version 1.9.2 + +Version 1.9.2 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes several fixes and improvements, including a second new fix amendment to correct a bug in Non-Fungible Tokens (NFTs) code, a new API method for order book changes, less noisy logging, and other small fixes. + + + + +## Action Required + +This release introduces a two new amendments to the XRP Ledger protocol. The first, **fixNFTokenNegOffer**, fixes a bug in code associated with the **NonFungibleTokensV1** amendment, originally introduced in [version 1.9.0](https://xrpl.org/blog/2022/rippled-1.9.0.html). The second, **NonFungibleTokensV1_1**, is a "roll-up" amendment that enables the **NonFungibleTokensV1** feature plus the two fix amendments associated with it, **fixNFTokenDirV1** and **fixNFTokenNegOffer**. + +If you want to enable NFT code on the XRP Ledger Mainnet, you can vote in favor of only the **NonFungibleTokensV1_1** amendment to support enabling the feature and fixes together, without risk that the unfixed NFT code may become enabled first. + +These amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, then you should upgrade to version 1.9.2 within two weeks, to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +For more information about NFTs on the XRP Ledger, see [NFT Conceptual Overview](https://xrpl.org/nft-conceptual-overview.html). + +## Install / Upgrade + +On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). + +## Changelog + +This release contains the following features and improvements. + +- **Introduce fixNFTokenNegOffer amendment.** This amendment fixes a bug in the Non-Fungible Tokens (NFTs) functionality provided by the NonFungibleTokensV1 amendment (not currently enabled on Mainnet). The bug allowed users to place offers to buy tokens for negative amounts of money when using Brokered Mode. Anyone who accepted such an offer would transfer the token _and_ pay money. This amendment explicitly disallows offers to buy or sell NFTs for negative amounts of money, and returns an appropriate error code. This also corrects the error code returned when placing offers to buy or sell NFTs for negative amounts in Direct Mode. ([8266d9d](https://github.com/XRPLF/rippled/commit/8266d9d598d19f05e1155956b30ca443c27e119e)) +- **Introduce `NonFungibleTokensV1_1` amendment.** This amendment encompasses three NFT-related amendments: the original NonFungibleTokensV1 amendment (from version 1.9.0), the fixNFTokenDirV1 amendment (from version 1.9.1), and the new fixNFTokenNegOffer amendment from this release. This amendment contains no changes other than enabling those three amendments together; this allows validators to vote in favor of _only_ enabling the feature and fixes at the same time. ([59326bb](https://github.com/XRPLF/rippled/commit/59326bbbc552287e44b3a0d7b8afbb1ddddb3e3b)) +- **Handle invalid port numbers.** If the user specifies a URL with an invalid port number, the server would silently attempt to use port 0 instead. Now it raises an error instead. This affects admin API methods and config file parameters for downloading history shards and specifying validator list sites. ([#4213](https://github.com/XRPLF/rippled/pull/4213)) +- **Reduce log noisiness.** Decreased the severity of benign log messages in several places: "addPathsForType" messages during regular operation, expected errors during unit tests, and missing optional documentation components when compiling from source. ([#4178](https://github.com/XRPLF/rippled/pull/4178), [#4166](https://github.com/XRPLF/rippled/pull/4166), [#4180](https://github.com/XRPLF/rippled/pull/4180)) +- **Fix race condition in history shard implementation and support clang's ThreadSafetyAnalysis tool.** Added build settings so that developers can use this feature of the clang compiler to analyze the code for correctness, and fix an error found by this tool, which was the source of rare crashes in unit tests. ([#4188](https://github.com/XRPLF/rippled/pull/4188)) +- **Prevent crash when rotating a database with missing data.** When rotating databases, a missing entry could cause the server to crash. While there should never be a missing database entry, this change keeps the server running by aborting database rotation. ([#4182](https://github.com/XRPLF/rippled/pull/4182)) +- **Fix bitwise comparison in OfferCreate.** Fixed an expression that incorrectly used a bitwise comparison for two boolean values rather than a true boolean comparison. The outcome of the two comparisons is equivalent, so this is not a transaction processing change, but the bitwise comparison relied on compilers to implicitly fix the expression. ([#4183](https://github.com/XRPLF/rippled/pull/4183)) +- **Disable cluster timer when not in a cluster.** Disabled a timer that was unused on servers not running in clustered mode. The functionality of clustered servers is unchanged. ([#4173](https://github.com/XRPLF/rippled/pull/4173)) +- **Limit how often to process peer discovery messages.** In the peer-to-peer network, servers periodically share IP addresses of their peers with each other to facilitate peer discovery. It is not necessary to process these types of messages too often; previously, the code tracked whether it needed to process new messages of this type but always processed them anyway. With this change, the server no longer processes peer discovery messages if it has done so recently. ([#4202](https://github.com/XRPLF/rippled/pull/4202)) +- **Improve STVector256 deserialization.** Optimized the processing of this data type in protocol messages. This data type is used in several types of ledger entry that are important for bookkeeping, including directory pages that track other ledger types, amendments tracking, and the ledger hashes history. ([#4204](https://github.com/XRPLF/rippled/pull/4204)) +- **Fix and refactor spinlock code.** The spinlock code, which protects the `SHAMapInnerNode` child lists, had a mistake that allowed the same child to be repeatedly locked under some circumstances. Fixed this bug and improved the spinlock code to make it easier to use correctly and easier to verify that the code works correctly. ([#4201](https://github.com/XRPLF/rippled/pull/4201)) +- **Improve comments and contributor documentation.** Various minor documentation changes including some to reflect the fact that the source code repository is now owned by the XRP Ledger Foundation. ([#4214](https://github.com/XRPLF/rippled/pull/4214), [#4179](https://github.com/XRPLF/rippled/pull/4179), [#4222](https://github.com/XRPLF/rippled/pull/4222)) +- **Introduces a new API book_changes to provide information in a format that is useful for building charts that highlight DEX activity at a per-ledger level.** ([#4212](https://github.com/XRPLF/rippled/pull/4212)) + +## Contributions + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome contributions, big and small, and invite everyone to join the community of XRP Ledger developers and help us build the Internet of Value. + +### Credits + +The following people contributed directly to this release: + +- Chenna Keshava B S +- Ed Hennis +- Ikko Ashimine +- Nik Bougalis +- Richard Holland +- Scott Schurr +- Scott Determan + +For a real-time view of all lifetime contributors, including links to the commits made by each, please visit the "Contributors" section of the GitHub repository: . + +# Introducing XRP Ledger version 1.9.1 + +Version 1.9.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes several important fixes, including a fix for a syncing issue from 1.9.0, a new fix amendment to correct a bug in the new Non-Fungible Tokens (NFTs) code, and a new amendment to allow multi-signing by up to 32 signers. + + + + +## Action Required + +This release introduces two new amendments to the XRP Ledger protocol. These amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. + +If you operate an XRP Ledger server, then you should upgrade to version 1.9.1 within two weeks, to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +The **fixNFTokenDirV1** amendment fixes a bug in code associated with the **NonFungibleTokensV1** amendment, so the fixNFTokenDirV1 amendment should be enabled first. All validator operators are encouraged to [configure amendment voting](https://xrpl.org/configure-amendment-voting.html) to oppose the NonFungibleTokensV1 amendment until _after_ the fixNFTokenDirV1 amendment has become enabled. For more information about NFTs on the XRP Ledger, see [NFT Conceptual Overview](https://xrpl.org/nft-conceptual-overview.html). + +The **ExpandedSignerList** amendment extends the ledger's built-in multi-signing functionality so that each list can contain up to 32 entries instead of the current limit of 8. Additionally, this amendment allows each signer to have an arbitrary 256-bit data field associated with it. This data can be used to identify the signer or provide other metadata that is useful for organizations, smart contracts, or other purposes. + +## Install / Upgrade + +On supported platforms, see the [instructions on installing or updating `rippled`](https://xrpl.org/install-rippled.html). + +## Changelog + +This release contains the following features and improvements. + +## New Features and Amendments + +- **Introduce fixNFTokenDirV1 Amendment** - This amendment fixes an off-by-one error that occurred in some corner cases when determining which `NFTokenPage` an `NFToken` object belongs on. It also adjusts the constraints of `NFTokenPage` invariant checks, so that certain error cases fail with a suitable error code such as `tecNO_SUITABLE_TOKEN_PAGE` instead of failing with a `tecINVARIANT_FAILED` error code. ([#4155](https://github.com/ripple/rippled/pull/4155)) + +- **Introduce ExpandedSignerList Amendment** - This amendment expands the maximum signer list size to 32 entries and allows each signer to have an optional 256-bit `WalletLocator` field containing arbitrary data. ([#4097](https://github.com/ripple/rippled/pull/4097)) + +- **Pause online deletion rather than canceling it if the server fails health check** - The server stops performing online deletion of old ledger history if the server fails its internal health check during this time. Online deletion can now resume after the server recovers, rather than having to start over. ([#4139](https://github.com/ripple/rippled/pull/4139)) + + +## Bug Fixes and Performance Improvements + +- **Fix performance issues introduced in 1.9.0** - Readjusts some parameters of the ledger acquisition engine to revert some changes introduced in 1.9.0 that had adverse effects on some systems, including causing some systems to fail to sync to the network. ([#4152](https://github.com/ripple/rippled/pull/4152)) + +- **Improve Memory Efficiency of Path Finding** - Finding paths for cross-currency payments is a resource-intensive operation. While that remains true, this fix improves memory usage of pathfinding by discarding trust line results that cannot be used before those results are fully loaded or cached. ([#4111](https://github.com/ripple/rippled/pull/4111)) + +- **Fix incorrect CMake behavior on Windows when platform is unspecified or x64** - Fixes handling of platform selection when using the cmake-gui tool to build on Windows. The generator expects `Win64` but the GUI only provides `x64` as an option, which raises an error. This fix only raises an error if the platform is `Win32` instead, allowing the generation of solution files to succeed. ([#4150](https://github.com/ripple/rippled/pull/4150)) + +- **Fix test failures with newer MSVC compilers on Windows** - Fixes some cases where the API handler code used string pointer comparisons, which may not work correctly with some versions of the MSVC compiler. ([#4149](https://github.com/ripple/rippled/pull/4149)) + +- **Update minimum Boost version to 1.71.0** - This release is compatible with Boost library versions 1.71.0 through 1.77.0. The build configuration and documentation have been updated to reflect this. ([#4134](https://github.com/ripple/rippled/pull/4134)) + +- **Fix unit test failures for DatabaseDownloader** - Increases a timeout in the `DatabaseDownloader` code and adjusts unit tests so that the code does not return spurious failures, and more data is logged if it does fail. ([#4021](https://github.com/ripple/rippled/pull/4021)) + +- **Refactor relational database interface** - Improves code comments, naming, and organization of the module that interfaces with relational databases (such as the SQLite database used for tracking transaction history). ([#3965](https://github.com/ripple/rippled/pull/3965)) + + +## Contributions + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome contributions, big and small, and invite everyone to join the community of XRP Ledger developers and help us build the Internet of Value. + + +### Credits + +The following people contributed directly to this release: + +- Devon White +- Ed Hennis +- Gregory Popovitch +- Mark Travis +- Manoj Doshi +- Nik Bougalis +- Richard Holland +- Scott Schurr + +For a real-time view of all lifetime contributors, including links to the commits made by each, please visit the "Contributors" section of the GitHub repository: . + +We welcome external contributions and are excited to see the broader XRP Ledger community continue to grow and thrive. + + +# Change log + +- API version 2 will now return `signer_lists` in the root of the `account_info` response, no longer nested under `account_data`. # Releases +## Version 1.9.0 +This is the 1.9.0 release of `rippled`, the reference implementation of the XRP Ledger protocol. This release brings several features and improvements. + +### New and Improved Features +- **Introduce NFT support (XLS020):** This release introduces support for non-fungible tokens, currently available to the developer community for broader review and testing. Developers can create applications that allow users to mint, transfer, and ultimately burn (if desired) NFTs on the XRP Ledger. You can try out the new NFT transactions using the [nft-devnet](https://xrpl.org/xrp-testnet-faucet.html). Note that some fields and error codes from earlier releases of the supporting code have been refactored for this release, shown in the Code Refactoring section, below. [70779f](https://github.com/ripple/rippled/commit/70779f6850b5f33cdbb9cf4129bc1c259af0013e) + +- **Simplify the Job Queue:** This is a refactor aimed at cleaning up and simplifying the existing job queue. Currently, all jobs are canceled at the same time and in the same way, so this commit removes the unnecessary per-job cancellation token. [#3656](https://github.com/ripple/rippled/pull/3656) + +- **Optimize trust line caching:** The existing trust line caching code was suboptimal in that it stored redundant information, pinned SLEs into memory, and required multiple memory allocations per cached object. This commit eliminates redundant data, reduces the size of cached objects and unpinning SLEs from memory, and uses value types to avoid the need for `std::shared_ptr`. As a result of these changes, the effective size of a cached object includes the overhead of the memory allocator, and the `std::shared_ptr` should be reduced by at least 64 bytes. This is significant, as there can easily be tens of millions of these objects. [4d5459](https://github.com/ripple/rippled/commit/4d5459d041da8f5a349c5f458d664e5865e1f1b5) + +- **Incremental improvements to pathfinding memory usage:** This commit aborts background pathfinding when closed or disconnected, exits the pathfinding job thread if there are no requests left, does not create the path find a job if there are no requests, and refactors to remove the circular dependency between InfoSub and PathRequest. [#4111](https://github.com/ripple/rippled/pull/4111) + +- **Improve deterministic transaction sorting in TxQ:** This commit ensures that transactions with the same fee level are sorted by TxID XORed with the parent ledger hash, the TxQ is re-sorted after every ledger, and attempts to future-proof the TxQ tie-breaking test. [#4077](https://github.com/ripple/rippled/pull/4077) + +- **Improve stop signaling for Application:** [34ca45](https://github.com/ripple/rippled/commit/34ca45713244d0defc39549dd43821784b2a5c1d) + +- **Eliminate SHAMapInnerNode lock contention:** The `SHAMapInnerNode` class had a global mutex to protect the array of node children. Profiling suggested that around 4% of all attempts to lock the global would block. This commit removes that global mutex, and replaces it with a new per-node 16-way spinlock (implemented so as not to affect the size of an inner node object), effectively eliminating the lock contention. [1b9387](https://github.com/ripple/rippled/commit/1b9387eddc1f52165d3243d2ace9be0c62495eea) + +- **Improve ledger-fetching logic:** When fetching ledgers, the existing code would isolate the peer that sent the most useful responses, and issue follow-up queries only to that peer. This commit increases the query aggressiveness, and changes the mechanism used to select which peers to issue follow-up queries to so as to more evenly spread the load among those peers that provided useful responses. [48803a](https://github.com/ripple/rippled/commit/48803a48afc3bede55d71618c2ee38fd9dbfd3b0) + +- **Simplify and improve order book tracking:** The order book tracking code would use `std::shared_ptr` to track the lifetime of objects. This commit changes the logic to eliminate the overhead of `std::shared_ptr` by using value types, resulting in significant memory savings. [b9903b](https://github.com/ripple/rippled/commit/b9903bbcc483a384decf8d2665f559d123baaba2) + +- **Negative cache support for node store:** This commit allows the cache to service requests for nodes that were previously looked up but not found, reducing the need to perform I/O in several common scenarios. [3eb8aa](https://github.com/ripple/rippled/commit/3eb8aa8b80bd818f04c99cee2cfc243192709667) + +- **Improve asynchronous database handlers:** This commit optimizes the way asynchronous node store operations are processed, both by reducing the number of times locks are held and by minimizing the number of memory allocations and data copying. [6faaa9](https://github.com/ripple/rippled/commit/6faaa91850d6b2eb9fbf16c1256bf7ef11ac4646) + +- **Cleanup AcceptedLedger and AcceptedLedgerTx:** This commit modernizes the `AcceptedLedger` and `AcceptedLedgerTx` classes, reduces their memory footprint, and reduces unnecessary dynamic memory allocations. [8f5868](https://github.com/ripple/rippled/commit/8f586870917818133924bf2e11acab5321c2b588) + +### Code Refactoring + +This release includes name changes in the NFToken API for SFields, RPC return labels, and error codes for clarity and consistency. To refactor your code, migrate the names of these items to the new names as listed below. + +#### `SField` name changes: +* `TokenTaxon -> NFTokenTaxon` +* `MintedTokens -> MintedNFTokens` +* `BurnedTokens -> BurnedNFTokens` +* `TokenID -> NFTokenID` +* `TokenOffers -> NFTokenOffers` +* `BrokerFee -> NFTokenBrokerFee` +* `Minter -> NFTokenMinter` +* `NonFungibleToken -> NFToken` +* `NonFungibleTokens -> NFTokens` +* `BuyOffer -> NFTokenBuyOffer` +* `SellOffer -> NFTokenSellOffer` +* `OfferNode -> NFTokenOfferNode` + +#### RPC return labels +* `tokenid -> nft_id` +* `index -> nft_offer_index` + +#### Error codes +* `temBAD_TRANSFER_FEE -> temBAD_NFTOKEN_TRANSFER_FEE` +* `tefTOKEN_IS_NOT_TRANSFERABLE -> tefNFTOKEN_IS_NOT_TRANSFERABLE` +* `tecNO_SUITABLE_PAGE -> tecNO_SUITABLE_NFTOKEN_PAGE` +* `tecBUY_SELL_MISMATCH -> tecNFTOKEN_BUY_SELL_MISMATCH` +* `tecOFFER_TYPE_MISMATCH -> tecNFTOKEN_OFFER_TYPE_MISMATCH` +* `tecCANT_ACCEPT_OWN_OFFER -> tecCANT_ACCEPT_OWN_NFTOKEN_OFFER` + + +### Bug Fixes +- **Fix deletion of orphan node store directories:** Orphaned node store directories should only be deleted if the proper node store directories are confirmed to exist. [06e87e](https://github.com/ripple/rippled/commit/06e87e0f6add5b880d647e14ab3d950decfcf416) + +## Version 1.8.5 +This is the 1.8.5 release of `rippled`, the reference implementation of the XRP Ledger protocol. This release includes fixes and updates for stability and security, and improvements to build scripts. There are no user-facing API or protocol changes in this release. + +### Bug Fixes + +This release contains the following bug fixes and under-the-hood improvements: + +- **Correct TaggedPointer move constructor:** Fixes a bug in unused code for the TaggedPointer class. The old code would fail if a caller explicitly tried to remove a child that is not actually part of the node. (227a12d) + +- **Ensure protocol buffer prerequisites are present:** The build scripts and packages now properly handle Protobuf packages and various packages. Prior to this change, building on Ubuntu 21.10 Impish Indri would fail unless the `libprotoc-dev` package was installed. (e06465f) + +- **Improve handling of endpoints during peer discovery.** This hardens and improves handling of incoming messages on the peer protocol. (289bc0a) + +- **Run tests on updated linux distros:** Test builds now run on Rocky Linux 8, Fedora 34 and 35, Ubuntu 18, 20, and 22, and Debian 9, 10, and 11. (a9ee802) + +- **Avoid dereferencing empty optional in ReportingETL:** Fixes a bug in Reporting Mode that could dereference an empty optional value when throwing an error. (cdc215d) + +- **Correctly add GIT_COMMIT_HASH into version string:** When building the server from a non-tagged release, the build files now add the commit ID in a way that follows the semantic-versioning standard, and correctly handle the case where the commit hash ID cannot be retrieved. (d23d37f) + +- **Update RocksDB to version 6.27.3:** Updates the version of RocksDB included in the server from 6.7.3 (which was released on 2020-03-18) to 6.27.3 (released 2021-12-10). + + + +## Version 1.8.4 +This is the 1.8.4 release of `rippled`, the reference implementation of the XRP Ledger protocol. + +This release corrects a technical flaw introduced with 1.8.3 that may result in failures if the newly-introduced 'fast loading' is enabled. The release also adjusts default parameters used to configure the pathfinding engine to reduce resource usage. + +### Bug Fixes +- **Adjust mutex scope in `walkMapParallel`**: This commit corrects a technical flaw introduced with commit [7c12f0135897361398917ad2c8cda888249d42ae] that would result in undefined behavior if the server operator configured their server to use the 'fast loading' mechanism introduced with 1.8.3. + +- **Adjust pathfinding configuration defaults**: This commit adjusts the default configuration of the pathfinding engine, to account for the size of the XRP Ledger mainnet. Unless explicitly overriden, the changes mean that pathfinding operations will return fewer, shallower paths than previous releases. + + +## Version 1.8.3 +This is the 1.8.3 release of `rippled`, the reference implementation of the XRP Ledger protocol. + +This release implements changes that improve the syncing performance of peers on the network, adds countermeasures to several routines involving LZ4 to defend against CVE-2021-3520, corrects a minor technical flaw that would result in the server not using a cache for nodestore operations, and adjusts tunable values to optimize disk I/O. + +### Summary of Issues +Recently, servers in the XRP Ledger network have been taking an increasingly long time to sync back to the network after restartiningg. This is one of several releases which will be made to improve on this issue. + + +### Bug Fixes + +- **Parallel ledger loader & I/O performance improvements**: This commit makes several changes that, together, should decrease the time needed for a server to sync to the network. To make full use of this change, `rippled` needs to be using storage with high IOPS and operators need to explicitly enable this behavior by adding the following to their config file, under the `[node_db]` stanza: + + [node_db] + ... + fast_load=1 + +Note that when 'fast loading' is enabled the server will not open RPC and WebSocket interfaces until after the initial load is completed. Because of this, it may appear unresponsive or down. + +- **Detect CVE-2021-3520 when decompressing using LZ4**: This commit adds code to detect LZ4 payloads that may result in out-of-bounds memory accesses. + +- **Provide sensible default values for nodestore cache:**: The nodestore includes a built-in cache to reduce the disk I/O load but, by default, this cache was not initialized unless it was explicitly configured by the server operator. This commit introduces sensible defaults based on the server's configured node size. + +- **Adjust the number of concurrent ledger data jobs**: Processing a large amount of data at once can effectively bottleneck a server's I/O subsystem. This commits helps optimize I/O performance by controlling how many jobs can concurrently process ledger data. + +- **Two small SHAMapSync improvements**: This commit makes minor changes to optimize the way memory is used and control the amount of background I/O performed when attempting to fetch missing `SHAMap` nodes. + +## Version 1.8.2 +Ripple has released version 1.8.2 of rippled, the reference server implementation of the XRP Ledger protocol. This release addresses the full transaction queues and elevated transaction fees issue observed on the XRP ledger, and also provides some optimizations and small fixes to improve the server's performance overall. + +### Summary of Issues +Recently, servers in the XRP Ledger network have had full transaction queues and transactions paying low fees have mostly not been able to be confirmed through the queue. After investigation, it was discovered that a large influx of transactions to the network caused it to raise the transaction costs to be proposed in the next ledger block, and defer transactions paying lower costs to later ledgers. The first part worked as designed, but deferred transactions were not being confirmed as the ledger had capacity to process them. + +The root cause was that there were very many low-cost transactions that different servers in the network received in a different order due to incidental differences in timing or network topology, which caused validators to propose different sets of low-cost transactions from the queue. Since none of these transactions had support from a majority of validators, they were removed from the proposed transaction set. Normally, any transactions removed from a proposed transaction set are supposed to be retried in the next ledger, but servers attempted to put these deferred transactions into their transaction queues first, which had filled up. As a result, the deferred transactions were discarded, and the network was only able to confirm transactions that paid high costs. + +### Bug Fixes + +- **Address elevated transaction fees**: This change addresses the full queue problems in two ways. First, it puts deferred transactions directly into the open ledger, rather than transaction queue. This reverts a subset of the changes from [ximinez@62127d7](https://github.com/ximinez/rippled/commit/62127d725d801641bfaa61dee7d88c95e48820c5). A transaction that is in the open ledger but doesn't get validated should stay in the open ledger so that it can be proposed again right away. Second, it changes the order in which transactions are pulled from the transaction queue to increase the overlap in servers' initial transaction consensus proposals. Like the old rules, transactions paying higher fee levels are selected first. Unlike the old rules, transactions paying the same fee level are ordered by transaction ID / hash ascending. (Previously, transactions paying the same fee level were unsorted, resulting in each server having a different order.) + +- **Add ignore_default option to account_lines API**: This flag, if present, suppresses the output of incoming trust lines in the default state. This is primarily motivated by observing that users often have many unwanted incoming trust lines in a default state, which are not useful in the vast majority of cases. Being able to suppress those when doing `account_lines` saves bandwidth and resources. ([#3980](https://github.com/ripple/rippled/pull/3980)) + +- **Make I/O and prefetch worker threads configurable**: This commit adds the ability to specify **io_workers** and **prefetch_workers** in the config file which can be used to specify the number of threads for processing raw inbound and outbound IO and configure the number of threads for performing node store prefetching. ([#3994](https://github.com/ripple/rippled/pull/3994)) + +- **Enforce account RPC limits by objects traversed**: This changes the way the account_objects API method counts and limits the number of objects it returns. Instead of limiting results by the number of objects found, it counts by the number of objects traversed. Additionally, the default and maximum limits for non-admin connections have been decreased. This reduces the amount of work that one API call can do so that public API servers can share load more effectively. ([#4032](https://github.com/ripple/rippled/pull/4032)) + +- **Fix a crash on shutdown**: The NuDB backend class could throw an error in its destructor, resulting in a crash while the server was shutting down gracefully. This crash was harmless but resulted in false alarms and noise when tracking down other possible crashes. ([#4017](https://github.com/ripple/rippled/pull/4017)) + +- **Improve reporting of job queue in admin server_info**: The server_info command, when run with admin permissions, provides information about jobs in the server's job queue. This commit provides more descriptive names and more granular categories for many jobs that were previously all identified as "clientCommand". ([#4031](https://github.com/ripple/rippled/pull/4031)) + +- **Improve full & compressed inner node deserialization**: Remove a redundant copy operation from low-level SHAMap deserialization. ([#4004](https://github.com/ripple/rippled/pull/4004)) + +- **Reporting mode: only forward to P2P nodes that are synced**: Previously, reporting mode servers forwarded to any of their configured P2P nodes at random. This commit improves the selection so that it only chooses from P2P nodes that are fully synced with the network. ([#4028](https://github.com/ripple/rippled/pull/4028)) + +- **Improve handling of HTTP X-Forwarded-For and Forwarded headers**: Fixes the way the server handles IPv6 addresses in these HTTP headers. ([#4009](https://github.com/ripple/rippled/pull/4009), [#4030](https://github.com/ripple/rippled/pull/4030)) + +- **Other minor improvements to logging and Reporting Mode.** + + +## Version 1.8.0 +Ripple has released version 1.8.0 of rippled, the reference server implementation of the XRP Ledger protocol. This release brings several features and improvements. + +### New and Improved Features + +- **Improve History Sharding**: Shards of ledger history are now assembled in a deterministic way so that any server can make a binary-identical shard for a given range of ledgers. This makes it possible to retrieve a shard from multiple sources in parallel, then verify its integrity by comparing checksums with peers' checksums for the same shard. Additionally, there's a new admin RPC command to import ledger history from the shard store, and the crawl_shards command has been expanded with more info. ([#2688](https://github.com/ripple/rippled/issues/2688), [#3726](https://github.com/ripple/rippled/pull/3726), [#3875](https://github.com/ripple/rippled/pull/3875)) +- **New CheckCashMakesTrustLine Amendment**: If enabled, this amendment will change the CheckCash transaction type so that cashing a check for an issued token automatically creates a trust line to hold the token, similar to how purchasing a token in the decentralized exchange creates a trust line to hold the token. This change provides a way for issuers to send tokens to a user before that user has set up a trust line, but without forcing anyone to hold tokens they don't want. ([#3823](https://github.com/ripple/rippled/pull/3823)) +- **Automatically determine the node size**: The server now selects an appropriate `[node_size]` configuration value by default if it is not explicitly specified. This parameter tunes various settings to the specs of the hardware that the server is running on, especially the amount of RAM and the number of CPU threads available in the system. Previously the server always chose the smallest value by default. +- **Improve transaction relaying logic**: Previously, the server relayed every transaction to all its peers (except the one that it received the transaction from). To reduce redundant messages, the server now relays transactions to a subset of peers using a randomized algorithm. Peers can determine whether there are transactions they have not seen and can request them from a peer that has them. It is expected that this feature will further reduce the bandwidth needed to operate a server. +- **Improve the Byzantine validator detector**: This expands the detection capabilities of the Byzantine validation detector. Previously, the server only monitored validators on its own UNL. Now, the server monitors for Byzantine behavior in all validations it sees. +- **Experimental tx stream with history for sidechains**: Adds an experimental subscription stream for sidechain federators to track messages on the main chain in canonical order. This stream is expected to change or be replaced in future versions as work on sidechains matures. +- **Support Debian 11 Bullseye**: This is the first release that is compatible with Debian Linux version 11.x, "Bullseye." The .deb packages now use absolute paths only, for compatibility with Bullseye's stricter package requirements. ([#3909](https://github.com/ripple/rippled/pull/3909)) +- **Improve Cache Performance**: The server uses a new storage structure for several in-memory caches for greatly improved overall performance. The process of purging old data from these caches, called "sweeping", was time-consuming and blocked other important activities necessary for maintaining ledger state and participating in consensus. The new structure divides the caches into smaller partitions that can be swept in parallel. +- **Amendment default votes:** Introduces variable default votes per amendment. Previously the server always voted "yes" on any new amendment unless an admin explicitly configured a voting preference for that amendment. Now the server's default vote can be "yes" or "no" in the source code. This should allow a safer, more gradual roll-out of new amendments, as new releases can be configured to understand a new amendment but not vote for it by default. ([#3877](https://github.com/ripple/rippled/pull/3877)) +- **More fields in the `validations` stream:** The `validations` subscription stream in the API now reports additional fields that were added to validation messages by the HardenedValidations amendment. These fields make it easier to detect misconfigurations such as multiple servers sharing a validation key pair. ([#3865](https://github.com/ripple/rippled/pull/3865)) +- **Reporting mode supports `validations` and `manifests` streams:** In the API it is now possible to connect to these streams when connected to a servers running in reporting. Previously, attempting to subscribe to these streams on a reporting server failed with the error `reportingUnsupported`. ([#3905](https://github.com/ripple/rippled/pull/3905)) + +### Bug Fixes + +- **Clarify the safety of NetClock::time_point arithmetic**: * NetClock::rep is uint32_t and can be error-prone when used with subtraction. * Fixes [#3656](https://github.com/ripple/rippled/pull/3656) +- **Fix out-of-bounds reserve, and some minor optimizations** +- **Fix nested locks in ValidatorSite** +- **Fix clang warnings about copies vs references** +- **Fix reporting mode build issue** +- **Fix potential deadlock in Validator sites** +- **Use libsecp256k1 instead of OpenSSL for key derivation**: The deterministic key derivation code was still using calls to OpenSSL. This replaces the OpenSSL-based routines with new libsecp256k1-based implementations +- **Improve NodeStore to ShardStore imports**: This runs the import process in a background thread while preventing online_delete from removing ledgers pending import +- **Simplify SHAMapItem construction**: The existing class offered several constructors which were mostly unnecessary. This eliminates all existing constructors and introduces a single new one, taking a `Slice`. The internal buffer is switched from `std::vector` to `Buffer` to save a minimum of 8 bytes (plus the buffer slack that is inherent in `std::vector`) per SHAMapItem instance. +- **Redesign stoppable objects**: Stoppable is no longer an abstract base class, but a pattern, modeled after the well-understood `std::thread`. The immediate benefits are less code, less synchronization, less runtime work, and (subjectively) more readable code. The end goal is to adhere to RAII in our object design, and this is one necessary step on that path. + +## Version 1.7.3 + +This is the 1.7.3 release of `rippled`, the reference implementation of the XRP Ledger protocol. This release addresses an OOB memory read identified by Guido Vranken, as well as an unrelated issue identified by the Ripple C++ team that could result in incorrect use of SLEs. Additionally, this version also introduces the `NegativeUNL` amendment, which corresponds to the feature which was introduced with the 1.6.0 release. + +## Action Required + +If you operate an XRP Ledger server, then you should upgrade to version 1.7.3 at your earliest convenience to mitigate the issues addressed in this hotfix. If a sufficient majority of servers on the network upgrade, the `NegativeUNL` amendment may gain a majority, at which point a two week activation countdown will begin. If the `NegativeUNL` amendment activates, servers running versions of `rippled` prior to 1.7.3 will become [amendment blocked](https://xrpl.org/amendments.html#amendment-blocked). + +### Bug Fixes + +- **Improve SLE usage in check cashing**: Fixes a situation which could result in the incorrect use of SLEs. +- **Address OOB in base58 decoder**: Corrects a technical flaw that could allow an out-of-bounds memory read in the Base58 decoder. +- **Add `NegativeUNL` as a supported amendment**: Introduces an amendment for the Negative UNL feature introduced in `rippled` 1.6.0. + +## Version 1.7.2 + +This the 1.7.2 release of rippled, the reference server implementation of the XRP Ledger protocol. This release protects against the security issue [CVE-2021-3499](https://www.openssl.org/news/secadv/20210325.txt) affecting OpenSSL, adds an amendment to fix an issue with small offers not being properly removed from order books in some cases, and includes various other minor fixes. +Version 1.7.2 supersedes version 1.7.1 and adds fixes for more issues that were discovered during the release cycle. + +## Action Required + +This release introduces a new amendment to the XRP Ledger protocol: `fixRmSmallIncreasedQOffers`. This amendments is now open for voting according to the XRP Ledger's amendment process, which enables protocol changes following two weeks of >80% support from trusted validators. +If you operate an XRP Ledger server, then you should upgrade to version 1.7.2 within two weeks, to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. +If you operate an XRP Ledger validator, please learn more about this amendment so you can make informed decisions about how your validator votes. If you take no action, your validator begins voting in favor of any new amendments as soon as it has been upgraded. + +### Bug Fixes + +- **fixRmSmallIncreasedQOffers Amendment:** This amendment fixes an issue where certain small offers can be left at the tip of an order book without being consumed or removed when appropriate and causes some payments and Offers to fail when they should have succeeded [(#3827)](https://github.com/ripple/rippled/pull/3827). +- **Adjust OpenSSL defaults and mitigate CVE-2021-3499:** Prior to this fix, servers compiled against a vulnerable version of OpenSSL could have a crash triggered by a malicious network connection. This fix disables renegotiation support in OpenSSL so that the rippled server is not vulnerable to this bug regardless of the OpenSSL version used to compile the server. This also removes support for deprecated TLS versions 1.0 and 1.1 and ciphers that are not part of TLS 1.2 [(#79e69da)](https://github.com/ripple/rippled/pull/3843/commits/79e69da3647019840dca49622621c3d88bc3883f). +- **Support HTTP health check in reporting mode:** Enables the Health Check special method when running the server in the new Reporting Mode introduced in 1.7.0 [(9c8cadd)](https://github.com/ripple/rippled/pull/3843/commits/9c8caddc5a197bdd642556f8beb14f06d53cdfd3). +- **Maintain compatibility for forwarded RPC responses:** Fixes a case in API responses from servers in Reporting Mode, where requests that were forwarded to a P2P-mode server would have the result field nested inside another result field [(8579eb0)](https://github.com/ripple/rippled/pull/3843/commits/8579eb0c191005022dcb20641444ab471e277f67). +- **Add load_factor in reporting mode:** Adds a load_factor value to the server info method response when running the server in Reporting Mode so that the response is compatible with the format returned by servers in P2P mode (the default) [(430802c)](https://github.com/ripple/rippled/pull/3843/commits/430802c1cf6d4179f2249a30bfab9eff8e1fa748). +- **Properly encode metadata from tx RPC command:** Fixes a problem where transaction metadata in the tx API method response would be in JSON format even when binary was requested [(7311629)](https://github.com/ripple/rippled/pull/3843/commits/73116297aa94c4acbfc74c2593d1aa2323b4cc52). +- **Updates to Windows builds:** When building on Windows, use vcpkg 2021 by default and add compatibility with MSVC 2019 [(36fe196)](https://github.com/ripple/rippled/pull/3843/commits/36fe1966c3cd37f668693b5d9910fab59c3f8b1f), [(30fd458)](https://github.com/ripple/rippled/pull/3843/commits/30fd45890b1d3d5f372a2091d1397b1e8e29d2ca). + +## Version 1.7.0 + +Ripple has released version 1.7.0 of `rippled`, the reference server implementation of the XRP Ledger protocol. +This release [significantly improves memory usage](https://blog.ripplex.io/how-ripples-c-team-cut-rippleds-memory-footprint-down-to-size/), introduces a protocol amendment to allow out-of-order transaction execution with Tickets, and brings several other features and improvements. + +## Upgrading (SPECIAL ACTION REQUIRED) +If you use the precompiled binaries of rippled that Ripple publishes for supported platforms, please note that Ripple has renewed the GPG key used to sign these packages. +If you are upgrading from a previous install, you must download and trust the renewed key. Automatic upgrades will not work until you have re-trusted the key. +### Red Hat Enterprise Linux / CentOS + +Perform a [manual upgrade](https://xrpl.org/update-rippled-manually-on-centos-rhel.html). When prompted, confirm that the key's fingerprint matches the following example, then press `y` to accept the updated key: + +``` +$ sudo yum install rippled +Loaded plugins: fastestmirror +Loading mirror speeds from cached hostfile +* base: mirror.web-ster.com +* epel: mirrors.syringanetworks.net +* extras: ftp.osuosl.org +* updates: mirrors.vcea.wsu.edu +ripple-nightly/signature | 650 B 00:00:00 +Retrieving key from https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key +Importing GPG key 0xCCAFD9A2: +Userid : "TechOps Team at Ripple " +Fingerprint: c001 0ec2 05b3 5a33 10dc 90de 395f 97ff ccaf d9a2 +From : https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key +Is this ok [y/N]: y +``` + +### Ubuntu / Debian + +Download and trust the updated public key, then perform a [manual upgrade](https://xrpl.org/update-rippled-manually-on-ubuntu.html) as follows: + +``` +wget -q -O - "https://repos.ripple.com/repos/api/gpg/key/public" | \ + sudo apt-key add - +sudo apt -y update +sudo apt -y install rippled +``` + +### New and Improved Features + +- **Rework deferred node logic and async fetch behavior:** This change significantly improves ledger sync and fetch times while reducing memory consumption. (https://blog.ripplex.io/how-ripples-c-team-cut-rippleds-memory-footprint-down-to-size/) +- **New Ticket feature:** Tickets are a mechanism to prepare and send certain transactions outside of the normal sequence order. This version reworks and completes the implementation for Tickets after more than 6 years of development. This feature is now open for voting as the newly-introduced `TicketBatch` amendment, which replaces the previously-proposed `Tickets` amendment. The specification for this change can be found at: [xrp-community/standards-drafts#16](https://github.com/xrp-community/standards-drafts/issues/16) +- **Add Reporting Mode:** The server can be compiled to operate in a new mode that serves API requests for validated ledger data without connecting directly to the peer-to-peer network. (The server needs a gRPC connection to another server that is on the peer-to-peer network.) Reporting Mode servers can share access to ledger data via Apache Cassandra and PostgreSQL to more efficiently serve API requests while peer-to-peer servers specialize in broadcasting and processing transactions. +- **Optimize relaying of validation and proposal messages:** Servers typically receive multiple copies of any given message from directly connected peers; in particular, consensus proposal and validation messages are often relayed with extremely high redundancy. For servers with several peers, this can cause redundant work. This commit introduces experimental code that attempts to optimize the relaying of proposals and validations by allowing servers to instruct their peers to "squelch" delivery of selected proposals and validations. This change is considered experimental at this time and is disabled by default because the functioning of the consensus network depends on messages propagating with high reliability through the constantly-changing peer-to-peer network. Server operators who wish to test the optimized code can enable it in their server config file. +- **Report server domain to other servers:** Server operators now have the option to configure a domain name to be associated with their servers. The value is communicated to other servers and is also reported via the `server_info` API. The value is meant for third-party applications and tools to group servers together. For example, a tool that visualizes the network's topology can show how many servers are operated by different stakeholders. An operator can claim any domain, so tools should use the [xrp-ledger.toml file](https://xrpl.org/xrp-ledger-toml.html) to confirm that the domain also claims ownership of the servers. +- **Improve handling of peers that aren't synced:** When evaluating the fitness and usefulness of an outbound peer, the code would incorrectly calculate the amount of time that the peer spent in a non-useful state. This release fixes the calculation and makes the timeout values configurable by server operators. Two new options are introduced in the 'overlay' stanza of the config file. +- **Persist API-configured voting settings:** Previously, the amendments that a server would vote in support of or against could be configured both via the configuration file and via the ["feature" API method](https://xrpl.org/feature.html). Changes made in the configuration file were only loaded at server startup; changes made via the command line take effect immediately but were not persisted across restarts. Starting with this release, changes made via the API are saved to the wallet.db database file so that they persist even if the server is restarted. +Amendment voting in the config file is deprecated. The first time the server starts with v1.7.0 or higher, it reads any amendment voting settings in the config file and saves the settings to the database; on later restarts the server prints a warning message and ignores the [amendments] and [veto_amendments] stanzas of the config file. +Going forward, use the [feature method](https://xrpl.org/feature.html) to view and configure amendment votes. If you want to use the config file to configure amendment votes, add a line to the [rpc_startup] stanza such as the following: +[rpc_startup] +{ "command": "feature", "feature": "FlowSortStrands", "vetoed": true } +- **Support UNLs with future effective dates:** Updates the format for the recommended validator list file format, allowing publishers to pre-publish the next recommended UNL while the current one is still valid. The server is still backwards compatible with the previous format, but the new format removes some uncertainty during the transition from one list to the next. Also, starting with this release, the server locks down and reports an error if it has no valid validator list. You can clear the error by loading a validator list from a file or by configuring a different UNL and restarting; the error also goes away on its own if the server is able to obtain a trusted validator list from the network (for example, after an network outage resolves itself). +- **Improve manifest relaying:** Servers now propagate change messages for validators' ephemeral public keys ("manifests") on a best-effort basis, to make manifests more available throughout the peer-to-peer network. Previously, the server would only relay manifests from validators it trusts locally, which made it difficult to detect and track validators that are not broadly trusted. +- **Implement ledger forward replay feature:** The server can now sync up to the network by "playing forward" transactions from a previously saved ledger until it catches up to the network. Compared with the default behavior of fetching the latest state and working backwards, forward replay can save time and bandwidth by reconstructing previous ledgers' state data rather than downloading the pre-calculated results from the network. As an added bonus, forward replay confirms that the rest of the network followed the same transaction processing rules as the local server when processing the intervening ledgers. This feature is considered experimental this time and can be enabled with an option in the config file. +- **Make the transaction job queue limit adjustable:** The server uses a job queue to manage tasks, with limits on how many jobs of a particular type can be queued. The previously hard-coded limit associated with transactions is now configurable. Server operators can increase the number of transactions their server is able to queue, which may be useful if your server has a large memory capacity or you expect an influx of transactions. (https://github.com/ripple/rippled/issues/3556) +- **Add public_key to the Validator List method response:** The [Validator List method](https://xrpl.org/validator-list.html) can be used to request a recommended validator list from a rippled instance. The response now includes the public key of the requested list. (https://github.com/ripple/rippled/issues/3392) +- **Server operators can now configure maximum inbound and outbound peers separately:** The new `peers_in_max` and `peers_out_max` config options allow server operators to independently control the maximum number of inbound and outbound peers the server allows. [70c4ecc] +- **Improvements to shard downloading:** Previously the download_shard command could only load shards over HTTPS. Compressed shards can now also be downloaded over plain HTTP. The server fully checks the data for integrity and consistency, so the encryption is not strictly necessary. When initiating multiple shard downloads, the server now returns an error if there is not enough space to store all the shards currently being downloaded. +- **The manifest command is now public:** The manifest API method returns public information about a given validator. The required permissions have been changed so it is now part of the public API. + +### Bug Fixes + +- **Implement sticky DNS resolution for validator list retrieval:** When attempting to load a validator list from a configured site, attempt to reuse the last IP that was successfully used if that IP is still present in the DNS response. (https://github.com/ripple/rippled/issues/3494). +- **Improve handling of RPC ledger_index argument:** You can now provide the `ledger_index` as a numeric string. This allows you to copy and use the numeric string `ledger_index` value returned by certain RPC commands. Previously you could only send native JSON numbers or shortcut strings such as "validated" in the `ledger_index` field. (https://github.com/ripple/rippled/issues/3533) +- **Fix improper promotion of bool on return** [6968da1] +- **Fix ledger sequence on copynode** [ef53197] +- **Fix parsing of node public keys in `manifest` CLI:** The previous code attempts to validate the provided node public key using a function that assumes that the encoded public key is for an account. This causes the parsing to fail. This commit fixes #3317 (https://github.com/ripple/rippled/issues/3317) by letting the caller specify the type of the public key being checked. +- **Fix idle peer timer:** Fixes a bug where a function to remove idle peers was called every second instead of every 4 seconds. #3754 (https://github.com/ripple/rippled/issues/3754) +- **Add database counters:** Fix bug where DatabaseRotateImp::getBackend and ::sync utilized the writable backend without a lock. ::getBackend was replaced with ::getCounters. +- **Improve online_delete configuration and DB tuning** [6e9051e] +- **Improve handling of burst writes in NuDB database** ( https://github.com/ripple/rippled/pull/3662 ) +- **Fix excessive logging after disabling history shards.** Previously if you configured the server with a shard store, then disabled it, the server output excessive warning messages about the shard limit being exceeded. +- **Fixed some issues with negotiating link compression.** ( https://github.com/ripple/rippled/pull/3705 ) +- **Fixed a potential thread deadlock with history sharding.** ( https://github.com/ripple/rippled/pull/3683 ) +- **Various fixes to typos and comments, refactoring, and build system improvements** + +## Version 1.6.0 + +This release introduces several new features including changes to the XRP Ledger's consensus mechanism to make it even more robust in +adverse conditions, as well as numerous bug fixes and optimizations. + +### New and Improved Features + +- Initial implementation of Negative UNL functionality: This change can improve the liveness of the network during periods of network instability, by allowing servers to track which validators are temporarily offline and to adjust quorum calculations to match. This change requires an amendment, but the amendment is not in the **1.6.0** release. Ripple expects to run extensive public testing for Negative UNL functionality on the Devnet in the coming weeks. If public testing satisfies all requirements across security, reliability, stability, and performance, then the amendment could be included in a version 2.0 release. [[#3380](https://github.com/ripple/rippled/pull/3380)] +- Validation Hardening: This change allows servers to detect accidental misconfiguration of validators, as well as potentially Byzantine behavior by malicious validators. Servers can now log a message to notify operators if they detect a single validator issuing validations for multiple, incompatible ledger versions, or validations from multiple servers sharing a key. As part of this update, validators report the version of `rippled` they are using, as well as the hash of the last ledger they consider to be fully validated, in validation messages. [[#3291](https://github.com/ripple/rippled/pull/3291)] ![Amendment: Required](https://img.shields.io/badge/Amendment-Required-red) +- Software Upgrade Monitoring & Notification: After the `HardenedValidations` amendment is enabled and the validators begin reporting the versions of `rippled` they are running, a server can check how many of the validators on its UNL run a newer version of the software than itself. If more than 60% of a server's validators are running a newer version, the server writes a message to notify the operator to consider upgrading their software. [[#3447](https://github.com/ripple/rippled/pull/3447)] +- Link Compression: Beginning with **1.6.0**, server operators can enable support for compressing peer-to-peer messages. This can save bandwidth at a cost of higher CPU usage. This support is disabled by default and should prove useful for servers with a large number of peers. [[#3287](https://github.com/ripple/rippled/pull/3287)] +- Unconditionalize Amendments that were enabled in 2017: This change removes legacy code which the network has not used since 2017. This change limits the ability to [replay](https://github.com/xrp-community/standards-drafts/issues/14) ledgers that rely on the pre-2017 behavior. [[#3292](https://github.com/ripple/rippled/pull/3292)] +- New Health Check Method: Perform a simple HTTP request to get a summary of the health of the server: Healthy, Warning, or Critical. [[#3365](https://github.com/ripple/rippled/pull/3365)] +- Start work on API version 2. Version 2 of the API will be part of a future release. The first breaking change will be to consolidate several closely related error messages that can occur when the server is not synced into a single "notSynced" error message. [[#3269](https://github.com/ripple/rippled/pull/3269)] +- Improved shard concurrency: Improvements to the shard engine have helped reduce the lock scope on all public functions, increasing the concurrency of the code. [[#3251](https://github.com/ripple/rippled/pull/3251)] +- Default Port: In the config file, the `[ips_fixed]` and `[ips]` stanzas now use the [IANA-assigned port](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=2459) for the XRP Ledger protocol (2459) when no port is specified. The `connect` API method also uses the same port by default. [[#2861](https://github.com/ripple/rippled/pull/2861)]. +- Improve proposal and validation relaying. The peer-to-peer protocol always relays trusted proposals and validations (as part of the [consensus process](https://xrpl.org/consensus.html)), but only relays _untrusted_ proposals and validations in certain circumstances. This update adds configuration options so server operators can fine-tune how their server handles untrusted proposals and validations, and changes the default behavior to prioritize untrusted validations higher than untrusted proposals. [[#3391](https://github.com/ripple/rippled/pull/3391)] +- Various Build and CI Improvements including updates to RocksDB 6.7.3 [[#3356](https://github.com/ripple/rippled/pull/3356)], NuDB 2.0.3 [[#3437](https://github.com/ripple/rippled/pull/3437)], adjusting CMake settings so that rippled can be built as a submodule [[#3449](https://github.com/ripple/rippled/pull/3449)], and adding Travis CI settings for Ubuntu Bionic Beaver [[#3319](https://github.com/ripple/rippled/pull/3319)]. +- Better documentation in the config file for online deletion and database tuning. [[#3429](https://github.com/ripple/rippled/pull/3429)] + + +### Bug Fixes + +- Fix the 14 day timer to enable amendment to start at the correct quorum size [[#3396](https://github.com/ripple/rippled/pull/3396)] +- Improve online delete backend lock which addresses a possibility in the online delete process where one or more backend shared pointer references may become invalid during rotation. [[#3342](https://github.com/ripple/rippled/pull/3342)] +- Address an issue that can occur during the loading of validator tokens, where a deliberately malformed token could cause the server to crash during startup. [[#3326](https://github.com/ripple/rippled/pull/3326)] +- Add delivered amount to GetAccountTransactionHistory. The delivered_amount field was not being populated when calling GetAccountTransactionHistory. In contrast, the delivered_amount field was being populated when calling GetTransaction. This change populates delivered_amount in the response to GetAccountTransactionHistory, and adds a unit test to make sure the results delivered by GetTransaction and GetAccountTransactionHistory match each other. [[#3370](https://github.com/ripple/rippled/pull/3370)] +- Fix build issues for GCC 10 [[#3393](https://github.com/ripple/rippled/pull/3393)] +- Fix historical ledger acquisition - this fixes an issue where historical ledgers were acquired only since the last online deletion interval instead of the configured value to allow deletion.[[#3369](https://github.com/ripple/rippled/pull/3369)] +- Fix build issue with Docker [#3416](https://github.com/ripple/rippled/pull/3416)] +- Add Shard family. The App Family utilizes a single shared Tree Node and Full Below cache for all history shards. This can create a problem when acquiring a shard that shares an account state node that was recently cached from another shard operation. The new Shard Family class solves this issue by managing separate Tree Node and Full Below caches for each shard. [#3448](https://github.com/ripple/rippled/pull/3448)] +- Amendment table clean up which fixes a calculation issue with majority. [#3428](https://github.com/ripple/rippled/pull/3428)] +- Add the `ledger_cleaner` command to rippled command line help [[#3305](https://github.com/ripple/rippled/pull/3305)] +- Various typo and comments fixes. + + +## Version 1.5.0 + +The `rippled` 1.5.0 release introduces several improvements and new features, including support for gRPC API, API versioning, UNL propagation via the peer network, new RPC methods `validator_info` and `manifest`, augmented `submit` method, improved `tx` method response, improved command line parsing, improved handshake protocol, improved package building and various other minor bug fixes and improvements. + +This release also introduces two new amendments: `fixQualityUpperBound` and `RequireFullyCanonicalSig`. + +Several improvements to the sharding system are currently being evaluated for inclusion into the upcoming 1.6 release of `rippled`. These changes are incompatible with shards generated by previous versions of the code. +Additionally, an issue with the existing sharding engine can result in a server running versions 1.4 or 1.5 of the software to experience a deadlock and automatically restart when running with the sharding feature enabled. +At this time, the developers recommend running with sharding disabled, pending the improvements scheduled to be introduced with 1.6. For more information on how to disable sharding, please visit https://xrpl.org/configure-history-sharding.html + + +**New and Updated Features** +- The `RequireFullyCanonicalSig` amendment which changes the signature requirements for the XRP Ledger protocol so that non-fully-canonical signatures are no longer valid. This protects against transaction malleability on all transactions, instead of just transactions with the tfFullyCanonicalSig flag enabled. Without this amendment, a transaction is malleable if it uses a secp256k1 signature and does not have tfFullyCanonicalSig enabled. Most signing utilities enable tfFullyCanonicalSig by default, but there are exceptions. With this amendment, no single-signed transactions are malleable. (Multi-signed transactions may still be malleable if signers provide more signatures than are necessary.) All transactions must use the fully canonical form of the signature, regardless of the tfFullyCanonicalSig flag. Signing utilities that do not create fully canonical signatures are not supported. All of Ripple's signing utilities have been providing fully-canonical signatures exclusively since at least 2014. For more information. [`ec137044a`](https://github.com/ripple/rippled/commit/ec137044a014530263cd3309d81643a5a3c1fdab) +- Native [gRPC API](https://grpc.io/) support. Currently, this API provides a subset of the full `rippled` [API](https://xrpl.org/rippled-api.html). You can enable the gRPC API on your server with a new configuration stanza. [`7d867b806`](https://github.com/ripple/rippled/commit/7d867b806d70fc41fb45e3e61b719397033b272c) +- API Versioning which allows for future breaking change of RPC methods to co-exist with existing versions. [`2aa11fa41`](https://github.com/ripple/rippled/commit/2aa11fa41d4a7849ae6a5d7a11df6f367191e3ef) +- Nodes now receive and broadcast UNLs over the peer network under various conditions. [`2c71802e3`](https://github.com/ripple/rippled/commit/2c71802e389a59118024ea0152123144c084b31c) +- Augmented `submit` method to include additional details on the status of the command. [`79e9085dd`](https://github.com/ripple/rippled/commit/79e9085dd1eb72864afe841225b78ec96e72b5ca) +- Improved `tx` method response with additional details on ledgers searched. [`47501b7f9`](https://github.com/ripple/rippled/commit/47501b7f99d4103d9ad405e399169fc251161548) +- New `validator_info` method which returns information pertaining to the current validator's keys, manifest sequence, and domain. [`3578acaf0`](https://github.com/ripple/rippled/commit/3578acaf0b5f2d27ddc33f5b4cc81d21be1903ae) +- New `manifest` method which looks up manifest information for the specified key (either master or ephemeral). [`3578acaf0`](https://github.com/ripple/rippled/commit/3578acaf0b5f2d27ddc33f5b4cc81d21be1903ae) +- Introduce handshake protocol for compression negotiation (compression is not implemented at this point) and other minor improvements. [`f6916bfd4`](https://github.com/ripple/rippled/commit/f6916bfd429ce654e017ae9686cb023d9e05408b) +- Remove various old conditionals introduced by amendments. [`(51ed7db00`](https://github.com/ripple/rippled/commit/51ed7db0027ba822739bd9de6f2613f97c1b227b), [`6e4945c56)`](https://github.com/ripple/rippled/commit/6e4945c56b1a1c063b32921d7750607587ec3063) +- Add `getRippledInfo` info gathering script to `rippled` Linux packages. [`acf4b7889`](https://github.com/ripple/rippled/commit/acf4b78892074303cb1fa22b778da5e7e7eddeda) + +**Bug Fixes and Improvements** +- The `fixQualityUpperBound` amendment which fixes a bug in unused code for estimating the ratio of input to output of individual steps in cross-currency payments. [`9d3626fec`](https://github.com/ripple/rippled/commit/9d3626fec5b610100f401dc0d25b9ec8e4a9a362) +- `tx` method now properly fetches all historical tx if they are incorporated into a validated ledger under rules that applied at the time. [`11cf27e00`](https://github.com/ripple/rippled/commit/11cf27e00698dbfc099b23463927d1dac829ed19) +- Fix to how `fail_hard` flag is handled with the `submit` method - transactions that are submitted with the `fail_hard` flag that result in any TER code besides tesSUCCESS is neither queued nor held. [`cd9732b47`](https://github.com/ripple/rippled/commit/cd9732b47a9d4e95bcb74e048d2c76fa118b80fb) +- Remove unused `Beast` code. [`172ead822`](https://github.com/ripple/rippled/commit/172ead822159a3c1f9b73217da4316df48851ab6) +- Lag ratchet code fix to use proper ephemeral public keys instead of the long-term master public keys.[`6529d3e6f`](https://github.com/ripple/rippled/commit/6529d3e6f7333fc5226e5aa9ae65f834cb93dfe5) + + ## Version 1.4.0 The `rippled` 1.4.0 release introduces several improvements and new features, including support for deleting accounts, improved peer slot management, improved CI integration and package building and support for [C++17](https://en.wikipedia.org/wiki/C%2B%2B17) and [Boost 1.71](https://www.boost.org/users/history/version_1_71_0.html). Finally, this release removes the code for the `SHAMapV2` amendment which failed to gain majority support and has been obsoleted by other improvements. @@ -55,7 +1935,7 @@ The `rippled` 1.3.0 release introduces several new features and overall improvem **Bug Fixes** - Improve ledger trie ancestry tracking to reduce unnecessary error messages. -- More efficient detection of dry paths in the payment engine. Although not a transaction-breaking change, this should reduces spurious error messages in the log files. +- More efficient detection of dry paths in the payment engine. Although not a transaction-breaking change, this should reduce spurious error messages in the log files. ## Version 1.2.4 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..4e845735d4c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,149 @@ +### Operating an XRP Ledger server securely + +For more details on operating an XRP Ledger server securely, please visit https://xrpl.org/manage-the-rippled-server.html. + + +# Security Policy + +## Supported Versions + +Software constantly evolves. In order to focus resources, we only generally only accept vulnerability reports that affect recent and current versions of the software. We always accept reports for issues present in the **master**, **release** or **develop** branches, and with proposed, [open pull requests](https://github.com/ripple/rippled/pulls). + +## Identifying and Reporting Vulnerabilities + +We take security seriously and we do our best to ensure that all our releases are bug free. But we aren't perfect and sometimes things will slip through. + +### Responsible Investigation + +We urge you to examine our code carefully and responsibly, and to disclose any issues that you identify in a responsible fashion. + +Responsible investigation includes, but isn't limited to, the following: + +- Not performing tests on the main network. If testing is necessary, use the [Testnet or Devnet](https://xrpl.org/xrp-testnet-faucet.html). +- Not targeting physical security measures, or attempting to use social engineering, spam, distributed denial of service (DDOS) attacks, etc. +- Investigating bugs in a way that makes a reasonable, good faith effort not to be disruptive or harmful to the XRP Ledger and the broader ecosystem. + +### Responsible Disclosure + +If you discover a vulnerability or potential threat, or if you _think_ +you have, please reach out by dropping an email using the contact +information below. + +Your report should include the following: + +- Your contact information (typically, an email address); +- The description of the vulnerability; +- The attack scenario (if any); +- The steps to reproduce the vulnerability; +- Any other relevant details or artifacts, including code, scripts or patches. + +In your email, please describe the issue or potential threat. If possible, include a "repro" (code that can reproduce the issue) or describe the best way to reproduce and replicate the issue. Please make your report as detailed and comprehensive as possible. + +For more information on responsible disclosure, please read this [Wikipedia article](https://en.wikipedia.org/wiki/Responsible_disclosure). + +## Report Handling Process + +Please report the bug directly to us and limit further disclosure. If you want to prove that you knew the bug as of a given time, consider using a cryptographic precommitment: hash the content of your report and publish the hash on a medium of your choice (e.g. on Twitter or as a memo in a transaction) as "proof" that you had written the text at a given point in time. + +Once we receive a report, we: + +1. Assign two people to independently evaluate the report; +2. Consider their recommendations; +3. If action is necessary, formulate a plan to address the issue; +4. Communicate privately with the reporter to explain our plan. +5. Prepare, test and release a version which fixes the issue; and +6. Announce the vulnerability publicly. + +We will triage and respond to your disclosure within 24 hours. Beyond that, we will work to analyze the issue in more detail, formulate, develop and test a fix. + +While we commit to responding with 24 hours of your initial report with our triage assessment, we cannot guarantee a response time for the remaining steps. We will communicate with you throughout this process, letting you know where we are and keeping you updated on the timeframe. + +## Bug Bounty Program + +[Ripple](https://ripple.com) is generously sponsoring a bug bounty program for vulnerabilities in [`rippled`](https://github.com/XRPLF/rippled) (and other related projects, like [`xrpl.js`](https://github.com/XRPLF/xrpl.js), [`xrpl-py`](https://github.com/XRPLF/xrpl-py), [`xrpl4j`](https://github.com/XRPLF/xrpl4j)). + +This program allows us to recognize and reward individuals or groups that identify and report bugs. In summary, in order to qualify for a bounty, the bug must be: + +1. **In scope**. Only bugs in software under the scope of the program qualify. Currently, that means `rippled`, `xrpl.js`, `xrpl-py`, `xrpl4j`. +2. **Relevant**. A security issue, posing a danger to user funds, privacy, or the operation of the XRP Ledger. +3. **Original and previously unknown**. Bugs that are already known and discussed in public do not qualify. Previously reported bugs, even if publicly unknown, are not eligible. +4. **Specific**. We welcome general security advice or recommendations, but we cannot pay bounties for that. +5. **Fixable**. There has to be something we can do to permanently fix the problem. Note that bugs in other people’s software may still qualify in some cases. For example, if you find a bug in a library that we use which can compromise the security of software that is in scope and we can get it fixed, you may qualify for a bounty. +6. **Unused**. If you use the exploit to attack the XRP Ledger, you do not qualify for a bounty. If you report a vulnerability used in an ongoing or past attack and there is specific, concrete evidence that suggests you are the attacker we reserve the right not to pay a bounty. + +The amount paid varies dramatically. Vulnerabilities that are harmless on their own, but could form part of a critical exploit will usually receive a bounty. Full-blown exploits can receive much higher bounties. Please don’t hold back partial vulnerabilities while trying to construct a full-blown exploit. We will pay a bounty to anyone who reports a complete chain of vulnerabilities even if they have reported each component of the exploit separately and those vulnerabilities have been fixed in the meantime. However, to qualify for a the full bounty, you must to have been the first to report each of the partial exploits. + +### Contacting Us + +To report a qualifying bug, please send a detailed report to: + +|Email Address|bugs@ripple.com | +|:-----------:|:----------------------------------------------------| +|Short Key ID | `0xC57929BE` | +|Long Key ID | `0xCD49A0AFC57929BE` | +|Fingerprint | `24E6 3B02 37E0 FA9C 5E96 8974 CD49 A0AF C579 29BE` | + +The full PGP key for this address, which is also available on several key servers (e.g. on [keys.gnupg.net](https://keys.gnupg.net)), is: +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- +mQINBFUwGHYBEAC0wpGpBPkd8W1UdQjg9+cEFzeIEJRaoZoeuJD8mofwI5Ejnjdt +kCpUYEDal0ygkKobu8SzOoATcDl18iCrScX39VpTm96vISFZMhmOryYCIp4QLJNN +4HKc2ZdBj6W4igNi6vj5Qo6JMyGpLY2mz4CZskbt0TNuUxWrGood+UrCzpY8x7/N +a93fcvNw+prgCr0rCH3hAPmAFfsOBbtGzNnmq7xf3jg5r4Z4sDiNIF1X1y53DAfV +rWDx49IKsuCEJfPMp1MnBSvDvLaQ2hKXs+cOpx1BCZgHn3skouEUxxgqbtTzBLt1 +xXpmuijsaltWngPnGO7mOAzbpZSdBm82/Emrk9bPMuD0QaLQjWr7HkTSUs6ZsKt4 +7CLPdWqxyY/QVw9UaxeHEtWGQGMIQGgVJGh1fjtUr5O1sC9z9jXcQ0HuIHnRCTls +GP7hklJmfH5V4SyAJQ06/hLuEhUJ7dn+BlqCsT0tLmYTgZYNzNcLHcqBFMEZHvHw +9GENMx/tDXgajKql4bJnzuTK0iGU/YepanANLd1JHECJ4jzTtmKOus9SOGlB2/l1 +0t0ADDYAS3eqOdOcUvo9ElSLCI5vSVHhShSte/n2FMWU+kMUboTUisEG8CgQnrng +g2CvvQvqDkeOtZeqMcC7HdiZS0q3LJUWtwA/ViwxrVlBDCxiTUXCotyBWwARAQAB +tDBSaXBwbGUgTGFicyBCdWcgQm91bnR5IFByb2dyYW0gPGJ1Z3NAcmlwcGxlLmNv +bT6JAjcEEwEKACEFAlUwGHYCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ +zUmgr8V5Kb6R0g//SwY/mVJY59k87iL26/KayauSoOcz7xjcST26l4ZHVVX85gOY +HYZl8k0+m8X3zxeYm9a3QAoAml8sfoaFRFQP8ynnefRrLUPaZ2MjbJ0SACMwZNef +T6o7Mi8LBAaiNZdYVyIfX1oM6YXtqYkuJdav6ZCyvVYqc9OvMJPY2ZzJYuI/ZtvQ +/lTndxCeg9ALNX/iezOLGdfMpf4HuIFVwcPPlwGi+HDlB9/bggDEHC8z434SXVFc +aQatXAPcDkjMUweU7y0CZtYEj00HITd4pSX6MqGiHrxlDZTqinCOPs1Ieqp7qufs +MzlM6irLGucxj1+wa16ieyYvEtGaPIsksUKkywx0O7cf8N2qKg+eIkUk6O0Uc6eO +CszizmiXIXy4O6OiLlVHGKkXHMSW9Nwe9GE95O8G9WR8OZCEuDv+mHPAutO+IjdP +PDAAUvy+3XnkceO+HGWRpVvJZfFP2YH4A33InFL5yqlJmSoR/yVingGLxk55bZDM ++HYGR3VeMb8Xj1rf/02qERsZyccMCFdAvKDbTwmvglyHdVLu5sPmktxbBYiemfyJ +qxMxmYXCc9S0hWrWZW7edktBa9NpE58z1mx+hRIrDNbS2sDHrib9PULYCySyVYcF +P+PWEe1CAS5jqkR2ker5td2/pHNnJIycynBEs7l6zbc9fu+nktFJz0q2B+GJAhwE +EAEKAAYFAlUwGaQACgkQ+tiY1qQ2QkjMFw//f2hNY3BPNe+1qbhzumMDCnbTnGif +kLuAGl9OKt81VHG1f6RnaGiLpR696+6Ja45KzH15cQ5JJl5Bgs1YkR/noTGX8IAD +c70eNwiFu8JXTaaeeJrsmFkF9Tueufb364risYkvPP8tNUD3InBFEZT3WN7JKwix +coD4/BwekUwOZVDd/uCFEyhlhZsROxdKNisNo3VtAq2s+3tIBAmTrriFUl0K+ZC5 +zgavcpnPN57zMtW9aK+VO3wXqAKYLYmtgxkVzSLUZt2M7JuwOaAdyuYWAneKZPCu +1AXkmyo+d84sd5mZaKOr5xArAFiNMWPUcZL4rkS1Fq4dKtGAqzzR7a7hWtA5o27T +6vynuxZ1n0PPh0er2O/zF4znIjm5RhTlfjp/VmhZdQfpulFEQ/dMxxGkQ9z5IYbX +mTlSDbCSb+FMsanRBJ7Drp5EmBIudVGY6SHI5Re1RQiEh7GoDfUMUwZO+TVDII5R +Ra7WyuimYleJgDo/+7HyfuIyGDaUCVj6pwVtYtYIdOI3tTw1R1Mr0V8yaNVnJghL +CHcEJQL+YHSmiMM3ySil3O6tm1By6lFz8bVe/rgG/5uklQrnjMR37jYboi1orCC4 +yeIoQeV0ItlxeTyBwYIV/o1DBNxDevTZvJabC93WiGLw2XFjpZ0q/9+zI2rJUZJh +qxmKP+D4e27lCI65Ag0EVTAYdgEQAMvttYNqeRNBRpSX8fk45WVIV8Fb21fWdwk6 +2SkZnJURbiC0LxQnOi7wrtii7DeFZtwM2kFHihS1VHekBnIKKZQSgGoKuFAQMGyu +a426H4ZsSmA9Ufd7kRbvdtEcp7/RTAanhrSL4lkBhaKJrXlxBJ27o3nd7/rh7r3a +OszbPY6DJ5bWClX3KooPTDl/RF2lHn+fweFk58UvuunHIyo4BWJUdilSXIjLun+P +Qaik4ZAsZVwNhdNz05d+vtai4AwbYoO7adboMLRkYaXSQwGytkm+fM6r7OpXHYuS +cR4zB/OK5hxCVEpWfiwN71N2NMvnEMaWd/9uhqxJzyvYgkVUXV9274TUe16pzXnW +ZLfmitjwc91e7mJBBfKNenDdhaLEIlDRwKTLj7k58f9srpMnyZFacntu5pUMNblB +cjXwWxz5ZaQikLnKYhIvrIEwtWPyjqOzNXNvYfZamve/LJ8HmWGCKao3QHoAIDvB +9XBxrDyTJDpxbog6Qu4SY8AdgVlan6c/PsLDc7EUegeYiNTzsOK+eq3G5/E92eIu +TsUXlciypFcRm1q8vLRr+HYYe2mJDo4GetB1zLkAFBcYJm/x9iJQbu0hn5NxJvZO +R0Y5nOJQdyi+muJzKYwhkuzaOlswzqVXkq/7+QCjg7QsycdcwDjiQh3OrsgXHrwl +M7gyafL9ABEBAAGJAh8EGAEKAAkFAlUwGHYCGwwACgkQzUmgr8V5Kb50BxAAhj9T +TwmNrgRldTHszj+Qc+v8RWqV6j+R+zc0cn5XlUa6XFaXI1OFFg71H4dhCPEiYeN0 +IrnocyMNvCol+eKIlPKbPTmoixjQ4udPTR1DC1Bx1MyW5FqOrsgBl5t0e1VwEViM +NspSStxu5Hsr6oWz2GD48lXZWJOgoL1RLs+uxjcyjySD/em2fOKASwchYmI+ezRv +plfhAFIMKTSCN2pgVTEOaaz13M0U+MoprThqF1LWzkGkkC7n/1V1f5tn83BWiagG +2N2Q4tHLfyouzMUKnX28kQ9sXfxwmYb2sA9FNIgxy+TdKU2ofLxivoWT8zS189z/ +Yj9fErmiMjns2FzEDX+bipAw55X4D/RsaFgC+2x2PDbxeQh6JalRA2Wjq32Ouubx +u+I4QhEDJIcVwt9x6LPDuos1F+M5QW0AiUhKrZJ17UrxOtaquh/nPUL9T3l2qPUn +1ChrZEEEhHO6vA8+jn0+cV9n5xEz30Str9iHnDQ5QyR5LyV4UBPgTdWyQzNVKA69 +KsSr9lbHEtQFRzGuBKwt6UlSFv9vPWWJkJit5XDKAlcKuGXj0J8OlltToocGElkF ++gEBZfoOWi/IBjRLrFW2cT3p36DTR5O1Ud/1DLnWRqgWNBLrbs2/KMKE6EnHttyD +7Tz8SQkuxltX/yBXMV3Ddy0t6nWV2SZEfuxJAQI= +=spg4 +-----END PGP PUBLIC KEY BLOCK----- +``` diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index a5baa7da8aa..00000000000 --- a/appveyor.yml +++ /dev/null @@ -1,107 +0,0 @@ -# Set environment variables. -environment: - - # We bundle up only the parts of boost and openssl we need so - # that it's a small download. We also use appveyor's free cache, avoiding fees - # downloading from S3 each time. - # TODO: script to create this package. - RIPPLED_DEPS_PATH: rippled_deps17.05 - RIPPLED_DEPS_BASE_URL: https://ripple.github.io/Downloads/appveyor - RIPPLED_OPENSSL: rippled_deps.openssl.1.0.2j.zip - RIPPLED_BOOST: rippled_deps.boost.1.70.zip - RIPPLED_BOOST_STAGE: rippled_deps.boost.stage.1.70.zip - - # CMake honors these environment variables, setting the include/lib paths. - BOOST_ROOT: C:/%RIPPLED_DEPS_PATH%/boost - OPENSSL_ROOT: C:/%RIPPLED_DEPS_PATH%/openssl - NIH_CACHE_ROOT: C:/%RIPPLED_DEPS_PATH%/ - - # We've had trouble with AppVeyor apparently not having a stack as large - # as the *nix CI platforms. AppVeyor support suggested that we try - # GCE VMs. The following line is supposed to enable that VM type. - appveyor_build_worker_cloud: gce - - matrix: - - build: cmake - target: msvc.debug - buildconfig: Debug - -os: Visual Studio 2017 - -# At the end of each successful build we cache this directory. -# https://www.appveyor.com/docs/build-cache/ -# Resulting archive should not exceed 100 MB. -cache: - - 'C:\%RIPPLED_DEPS_PATH%' - -# This means we'll download a zip of the branch we want, rather than the full -# history. -shallow_clone: true - -install: - # Download dependencies if appveyor didn't restore them from the cache. - # Use 7zip to unzip. - - ps: | - if (-not(Test-Path "C:/$env:RIPPLED_DEPS_PATH")) { - $files = @( - "$env:RIPPLED_BOOST", - "$env:RIPPLED_BOOST_STAGE", - "$env:RIPPLED_OPENSSL" - ) - For ($i=0; $i -lt $files.Length; $i++) { - $file = $files[$i] - $url = "$env:RIPPLED_DEPS_BASE_URL/$file" - echo "Download $file from $url" - Start-FileDownload "$url" - 7z x "$file" -o"C:\$env:RIPPLED_DEPS_PATH" -y > $null - if ($LastExitCode -ne 0) { throw "7z failed" } - } - } - else - { - "Dependencies are in cache" - ls "C:/$env:RIPPLED_DEPS_PATH" - } - - # Newer DEPS include a versions file. - # Dump it so we can verify correct behavior. - - ps: | - cat "C:/$env:RIPPLED_DEPS_PATH/version*.txt" - -# TODO: This is giving me grief -# artifacts: -# # Save rippled.exe in the cloud after each build. -# - path: "build\\rippled.exe" - -build_script: - # We set the environment variables needed to put compilers on the PATH. - - '"%VS140COMNTOOLS%../../VC/vcvarsall.bat" x86_amd64' - # Show which version of the compiler we are using. - - cl - - ps: | - # Build with cmake - cmake --version - $cmake_target="$($env:target).ci" - "$cmake_target" - New-Item -ItemType Directory -Force -Path "build/$cmake_target" - Push-Location "build/$cmake_target" - cmake -G"Visual Studio 15 2017 Win64" ../.. - if ($LastExitCode -ne 0) { throw "CMake failed" } - cmake --build . --config $env:buildconfig --parallel 3 - if ($LastExitCode -ne 0) { throw "CMake build failed" } - Pop-Location - -after_build: - - ps: | - $exe="build/$cmake_target/$env:buildconfig/rippled" - "Exe is at $exe" - -test_script: - - ps: | - & { - # Run the rippled unit tests - & $exe --unittest --unittest-log --unittest-jobs 2 - # https://connect.microsoft.com/PowerShell/feedback/details/751703/option-to-stop-script-if-command-line-exe-fails - if ($LastExitCode -ne 0) { throw "Unit tests failed" } - } - diff --git a/bin/ci/README.md b/bin/ci/README.md deleted file mode 100644 index 36d4fc1d310..00000000000 --- a/bin/ci/README.md +++ /dev/null @@ -1,24 +0,0 @@ -In this directory are two scripts, `build.sh` and `test.sh` used for building -and testing rippled. - -(For now, they assume Bash and Linux. Once I get Windows containers for -testing, I'll try them there, but if Bash is not available, then they will -soon be joined by PowerShell scripts `build.ps` and `test.ps`.) - -We don't want these scripts to require arcane invocations that can only be -pieced together from within a CI configuration. We want something that humans -can easily invoke, read, and understand, for when we eventually have to test -and debug them interactively. That means: - -(1) They should work with no arguments. -(2) They should document their arguments. -(3) They should expand short arguments into long arguments. - -While we want to provide options for common use cases, we don't need to offer -the kitchen sink. We can rightfully expect users with esoteric, complicated -needs to write their own scripts. - -To make argument-handling easy for us, the implementers, we can just take all -arguments from environment variables. They have the nice advantage that every -command-line uses named arguments. For the benefit of us and our users, we -document those variables at the top of each script. diff --git a/bin/ci/build.sh b/bin/ci/build.sh deleted file mode 100755 index fa7a0c96829..00000000000 --- a/bin/ci/build.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -set -o xtrace -set -o errexit - -# The build system. Either 'Unix Makefiles' or 'Ninja'. -GENERATOR=${GENERATOR:-Unix Makefiles} -# The compiler. Either 'gcc' or 'clang'. -COMPILER=${COMPILER:-gcc} -# The build type. Either 'Debug' or 'Release'. -BUILD_TYPE=${BUILD_TYPE:-Debug} -# Additional arguments to CMake. -# We use the `-` substitution here instead of `:-` so that callers can erase -# the default by setting `$CMAKE_ARGS` to the empty string. -CMAKE_ARGS=${CMAKE_ARGS-'-Dwerr=ON'} - -# https://gitlab.kitware.com/cmake/cmake/issues/18865 -CMAKE_ARGS="-DBoost_NO_BOOST_CMAKE=ON ${CMAKE_ARGS}" - -if [[ ${COMPILER} == 'gcc' ]]; then - export CC='gcc' - export CXX='g++' -elif [[ ${COMPILER} == 'clang' ]]; then - export CC='clang' - export CXX='clang++' -fi - -mkdir build -cd build -cmake -G "${GENERATOR}" -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${CMAKE_ARGS} .. -cmake --build . -- -j $(nproc) diff --git a/bin/ci/test.sh b/bin/ci/test.sh deleted file mode 100755 index 6162f37aa0e..00000000000 --- a/bin/ci/test.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash - -set -o xtrace -set -o errexit - -# Set to 'true' to run the known "manual" tests in rippled. -MANUAL_TESTS=${MANUAL_TESTS:-false} -# The maximum number of concurrent tests. -CONCURRENT_TESTS=${CONCURRENT_TESTS:-$(nproc)} -# The path to rippled. -RIPPLED=${RIPPLED:-build/rippled} -# Additional arguments to rippled. -RIPPLED_ARGS=${RIPPLED_ARGS:-} - -function join_by { local IFS="$1"; shift; echo "$*"; } - -declare -a manual_tests=( - 'beast.chrono.abstract_clock' - 'beast.unit_test.print' - 'ripple.NodeStore.Timing' - 'ripple.app.Flow_manual' - 'ripple.app.NoRippleCheckLimits' - 'ripple.app.PayStrandAllPairs' - 'ripple.consensus.ByzantineFailureSim' - 'ripple.consensus.DistributedValidators' - 'ripple.consensus.ScaleFreeSim' - 'ripple.ripple_data.digest' - 'ripple.tx.CrossingLimits' - 'ripple.tx.FindOversizeCross' - 'ripple.tx.Offer_manual' - 'ripple.tx.OversizeMeta' - 'ripple.tx.PlumpBook' -) - -if [[ ${MANUAL_TESTS} == 'true' ]]; then - RIPPLED_ARGS+=" --unittest=$(join_by , "${manual_tests[@]}")" -else - RIPPLED_ARGS+=" --unittest --quiet --unittest-log" -fi -RIPPLED_ARGS+=" --unittest-jobs ${CONCURRENT_TESTS}" - -${RIPPLED} ${RIPPLED_ARGS} diff --git a/bin/ci/ubuntu/build-and-test.sh b/bin/ci/ubuntu/build-and-test.sh deleted file mode 100755 index 41f433ef1ae..00000000000 --- a/bin/ci/ubuntu/build-and-test.sh +++ /dev/null @@ -1,250 +0,0 @@ -#!/usr/bin/env bash -set -ex - -function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; } - -__dirname=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -echo "using CC: ${CC}" -"${CC}" --version -export CC - -COMPNAME=$(basename $CC) -echo "using CXX: ${CXX:-notset}" -if [[ $CXX ]]; then - "${CXX}" --version - export CXX -fi -: ${BUILD_TYPE:=Debug} -echo "BUILD TYPE: ${BUILD_TYPE}" - -: ${TARGET:=install} -echo "BUILD TARGET: ${TARGET}" - -JOBS=${NUM_PROCESSORS:-2} -if [[ ${TRAVIS:-false} != "true" ]]; then - JOBS=$((JOBS+1)) -fi - -if [[ ! -z "${CMAKE_EXE:-}" ]] ; then - export PATH="$(dirname ${CMAKE_EXE}):$PATH" -fi - -if [ -x /usr/bin/time ] ; then - : ${TIME:="Duration: %E"} - export TIME - time=/usr/bin/time -else - time= -fi - -echo "Building rippled" -: ${CMAKE_EXTRA_ARGS:=""} -if [[ ${NINJA_BUILD:-} == true ]]; then - CMAKE_EXTRA_ARGS+=" -G Ninja" -fi - -coverage=false -if [[ "${TARGET}" == "coverage_report" ]] ; then - echo "coverage option detected." - coverage=true -fi - -cmake --version -CMAKE_VER=$(cmake --version | cut -d " " -f 3 | head -1) - -# -# allow explicit setting of the name of the build -# dir, otherwise default to the compiler.build_type -# -: "${BUILD_DIR:=${COMPNAME}.${BUILD_TYPE}}" -BUILDARGS="--target ${TARGET}" -BUILDTOOLARGS="" -if version_ge $CMAKE_VER "3.12.0" ; then - BUILDARGS+=" --parallel" -fi - -if [[ ${NINJA_BUILD:-} == false ]]; then - if version_ge $CMAKE_VER "3.12.0" ; then - BUILDARGS+=" ${JOBS}" - else - BUILDTOOLARGS+=" -j ${JOBS}" - fi -fi - -if [[ ${VERBOSE_BUILD:-} == true ]]; then - CMAKE_EXTRA_ARGS+=" -DCMAKE_VERBOSE_MAKEFILE=ON" - if version_ge $CMAKE_VER "3.14.0" ; then - BUILDARGS+=" --verbose" - else - if [[ ${NINJA_BUILD:-} == false ]]; then - BUILDTOOLARGS+=" verbose=1" - else - BUILDTOOLARGS+=" -v" - fi - fi -fi - -if [[ ${USE_CCACHE:-} == true ]]; then - echo "using ccache with basedir [${CCACHE_BASEDIR:-}]" - CMAKE_EXTRA_ARGS+=" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" -fi -if [ -d "build/${BUILD_DIR}" ]; then - rm -rf "build/${BUILD_DIR}" -fi - -mkdir -p "build/${BUILD_DIR}" -pushd "build/${BUILD_DIR}" - -# generate -${time} cmake ../.. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${CMAKE_EXTRA_ARGS} -# build -export DESTDIR=$(pwd)/_INSTALLED_ - -${time} eval cmake --build . ${BUILDARGS} -- ${BUILDTOOLARGS} - -if [[ ${TARGET} == "docs" ]]; then - ## mimic the standard test output for docs build - ## to make controlling processes like jenkins happy - if [ -f html_doc/index.html ]; then - echo "1 case, 1 test total, 0 failures" - else - echo "1 case, 1 test total, 1 failures" - fi - exit -fi -popd - -if [[ "${TARGET}" == "validator-keys" ]] ; then - export APP_PATH="$PWD/build/${BUILD_DIR}/validator-keys/validator-keys" -else - export APP_PATH="$PWD/build/${BUILD_DIR}/rippled" -fi -echo "using APP_PATH: ${APP_PATH}" - -# See what we've actually built -ldd ${APP_PATH} - -: ${APP_ARGS:=} - -if [[ "${TARGET}" == "validator-keys" ]] ; then - APP_ARGS="--unittest" -else - function join_by { local IFS="$1"; shift; echo "$*"; } - - # This is a list of manual tests - # in rippled that we want to run - # ORDER matters here...sorted in approximately - # descending execution time (longest running tests at top) - declare -a manual_tests=( - 'ripple.ripple_data.digest' - 'ripple.tx.Offer_manual' - 'ripple.app.PayStrandAllPairs' - 'ripple.tx.CrossingLimits' - 'ripple.tx.PlumpBook' - 'ripple.app.Flow_manual' - 'ripple.tx.OversizeMeta' - 'ripple.consensus.DistributedValidators' - 'ripple.app.NoRippleCheckLimits' - 'ripple.NodeStore.Timing' - 'ripple.consensus.ByzantineFailureSim' - 'beast.chrono.abstract_clock' - 'beast.unit_test.print' - ) - if [[ ${TRAVIS:-false} != "true" ]]; then - # these two tests cause travis CI to run out of memory. - # TODO: investigate possible workarounds. - manual_tests=( - 'ripple.consensus.ScaleFreeSim' - 'ripple.tx.FindOversizeCross' - "${manual_tests[@]}" - ) - fi - - if [[ ${MANUAL_TESTS:-} == true ]]; then - APP_ARGS+=" --unittest=$(join_by , "${manual_tests[@]}")" - else - APP_ARGS+=" --unittest --quiet --unittest-log" - fi - if [[ ${coverage} == false && ${PARALLEL_TESTS:-} == true ]]; then - APP_ARGS+=" --unittest-jobs ${JOBS}" - fi - - if [[ ${IPV6_TESTS:-} == true ]]; then - APP_ARGS+=" --unittest-ipv6" - fi -fi - -if [[ ${coverage} == true && $CC =~ ^gcc ]]; then - # Push the results (lcov.info) to codecov - codecov -X gcov # don't even try and look for .gcov files ;) - find . -name "*.gcda" | xargs rm -f -fi - -if [[ ${SKIP_TESTS:-} == true ]]; then - echo "skipping tests." - exit -fi - -ulimit -a -corepat=$(cat /proc/sys/kernel/core_pattern) -if [[ ${corepat} =~ ^[:space:]*\| ]] ; then - echo "WARNING: core pattern is piping - can't search for core files" - look_core=false -else - look_core=true - coredir=$(dirname ${corepat}) -fi -if [[ ${look_core} == true ]]; then - before=$(ls -A1 ${coredir}) -fi - -set +e -echo "Running tests for ${APP_PATH}" -if [[ ${MANUAL_TESTS:-} == true && ${PARALLEL_TESTS:-} != true ]]; then - for t in "${manual_tests[@]}" ; do - ${APP_PATH} --unittest=${t} - TEST_STAT=$? - if [[ $TEST_STAT -ne 0 ]] ; then - break - fi - done -else - ${APP_PATH} ${APP_ARGS} - TEST_STAT=$? -fi -set -e - -if [[ ${look_core} == true ]]; then - after=$(ls -A1 ${coredir}) - oIFS="${IFS}" - IFS=$'\n\r' - found_core=false - for l in $(diff -w --suppress-common-lines <(echo "$before") <(echo "$after")) ; do - if [[ "$l" =~ ^[[:space:]]*\>[[:space:]]*(.+)$ ]] ; then - corefile="${BASH_REMATCH[1]}" - echo "FOUND core dump file at '${coredir}/${corefile}'" - gdb_output=$(/bin/mktemp /tmp/gdb_output_XXXXXXXXXX.txt) - found_core=true - gdb \ - -ex "set height 0" \ - -ex "set logging file ${gdb_output}" \ - -ex "set logging on" \ - -ex "print 'ripple::BuildInfo::versionString'" \ - -ex "thread apply all backtrace full" \ - -ex "info inferiors" \ - -ex quit \ - "$APP_PATH" \ - "${coredir}/${corefile}" &> /dev/null - - echo -e "CORE INFO: \n\n $(cat ${gdb_output}) \n\n)" - fi - done - IFS="${oIFS}" -fi - -if [[ ${found_core} == true ]]; then - exit -1 -else - exit $TEST_STAT -fi - diff --git a/bin/ci/ubuntu/build-in-docker.sh b/bin/ci/ubuntu/build-in-docker.sh deleted file mode 100755 index feeabb1189a..00000000000 --- a/bin/ci/ubuntu/build-in-docker.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -# run our build script in a docker container -# using travis-ci hosts -set -eux - -function join_by { local IFS="$1"; shift; echo "$*"; } - -set +x -echo "VERBOSE_BUILD=true" > /tmp/co.env -matchers=( - 'TRAVIS.*' 'CI' 'CC' 'CXX' - 'BUILD_TYPE' 'TARGET' 'MAX_TIME' - 'CODECOV.+' 'CMAKE.*' '.+_TESTS' - '.+_OPTIONS' 'NINJA.*' 'NUM_.+' - 'NIH_.+' 'BOOST.*' '.*CCACHE.*') - -matchstring=$(join_by '|' "${matchers[@]}") -echo "MATCHSTRING IS:: $matchstring" -env | grep -E "^(${matchstring})=" >> /tmp/co.env -set -x -# need to eliminate TRAVIS_CMD...don't want to pass it to the container -cat /tmp/co.env | grep -v TRAVIS_CMD > /tmp/co.env.2 -mv /tmp/co.env.2 /tmp/co.env -cat /tmp/co.env -mkdir -p -m 0777 ${TRAVIS_BUILD_DIR}/cores -echo "${TRAVIS_BUILD_DIR}/cores/%e.%p" | sudo tee /proc/sys/kernel/core_pattern -docker run \ - -t --env-file /tmp/co.env \ - -v ${TRAVIS_HOME}:${TRAVIS_HOME} \ - -w ${TRAVIS_BUILD_DIR} \ - --cap-add SYS_PTRACE \ - --ulimit "core=-1" \ - $DOCKER_IMAGE \ - /bin/bash -c 'if [[ $CC =~ ([[:alpha:]]+)-([[:digit:].]+) ]] ; then sudo update-alternatives --set ${BASH_REMATCH[1]} /usr/bin/$CC; fi; bin/ci/ubuntu/build-and-test.sh' - - diff --git a/bin/ci/ubuntu/travis-cache-start.sh b/bin/ci/ubuntu/travis-cache-start.sh deleted file mode 100755 index b7cfb744c2b..00000000000 --- a/bin/ci/ubuntu/travis-cache-start.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -# some cached files create churn, so save them here for -# later restoration before packing the cache -set -eux -pushd ${TRAVIS_HOME} -if [ -f cache_ignore.tar ] ; then - rm -f cache_ignore.tar -fi - -if [ -d _cache/nih_c ] ; then - find _cache/nih_c -name "build.ninja" | tar rf cache_ignore.tar --files-from - - find _cache/nih_c -name ".ninja_deps" | tar rf cache_ignore.tar --files-from - - find _cache/nih_c -name ".ninja_log" | tar rf cache_ignore.tar --files-from - - find _cache/nih_c -name "*.log" | tar rf cache_ignore.tar --files-from - - find _cache/nih_c -name "*.tlog" | tar rf cache_ignore.tar --files-from - - # show .a files in the cache, for sanity checking - find _cache/nih_c -name "*.a" -ls -fi - -if [ -d _cache/ccache ] ; then - find _cache/ccache -name "stats" | tar rf cache_ignore.tar --files-from - -fi - -if [ -f cache_ignore.tar ] ; then - tar -tf cache_ignore.tar -fi -popd - - diff --git a/bin/getInfoRippled.sh b/bin/getInfoRippled.sh deleted file mode 100755 index 240eed642e3..00000000000 --- a/bin/getInfoRippled.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash - -rippled_exe=/opt/ripple/bin/rippled -conf_file=/etc/opt/ripple/rippled.cfg - -while getopts ":e:c:" opt; do - case $opt in - e) - rippled_exe=${OPTARG} - ;; - c) - conf_file=${OPTARG} - ;; - \?) - echo "Invalid option: -$OPTARG" - esac -done - -tmp_loc=$(mktemp -d --tmpdir ripple_info.XXXX) -cd /tmp -chmod 751 ripple_info.* -cd ~ -echo ${tmp_loc} - -cleaned_conf=${tmp_loc}/cleaned_rippled_cfg.txt - -if [[ -f ${conf_file} ]] -then - db=$(sed -r -e 's/\/secretsecretsecretsecretmaybe/g' ${conf_file} |\ - awk -v OUT_FILE=${cleaned_conf} ' - BEGIN {skip=0; db_path="";print > OUT_FILE} - /^\[validation_seed\]/ {skip=1; next} - /^\[node_seed\]/ {skip=1; next} - /^\[validation_manifest\]/ {skip=1; next} - /^\[validator_token\]/ {skip=1; next} - /^\[.*\]/ {skip=0} - skip==1 {next} - save==1 {save=0;db_path=$0} - /^\[database_path\]/ {save=1} - {print >> OUT_FILE} - END {print db_path} - ') -fi - -echo "database_path: ${db}" -df ${db} > ${tmp_loc}/db_path_df.txt -echo - -# Send output from this script to a log file -## this captures any messages -## or errors from the script itself - -log_file=${tmp_loc}/get_info.log -exec 3>&1 1>>${log_file} 2>&1 - -## Send all stdout files to /tmp - -if [[ -x ${rippled_exe} ]] -then - pgrep rippled && \ - ${rippled_exe} --conf ${conf_file} \ - -- server_info > ${tmp_loc}/server_info.txt -fi - -df -h > ${tmp_loc}/free_disk_space.txt -cat /proc/meminfo > ${tmp_loc}/amount_mem.txt -cat /proc/swaps > ${tmp_loc}/swap_space.txt -ulimit -a > ${tmp_loc}/reported_current_limits.txt - -for dev_path in $(df | awk '$1 ~ /^\/dev\// {print $1}'); do - # strip numbers from end and remove '/dev/' - dev=$(basename ${dev_path%%[0-9]}) - if [[ "$(cat /sys/block/${dev}/queue/rotational)" = 0 ]] - then - echo "${dev} : SSD" >> ${tmp_loc}/is_ssd.txt - else - echo "${dev} : NO SSD" >> ${tmp_loc}/is_ssd.txt - fi -done - -pushd ${tmp_loc} -tar -czvf info-package.tar.gz *.txt *.log -popd - -echo "Use the following command on your local machine to download from your rippled instance: scp @:${tmp_loc}/info-package.tar.gz "| tee /dev/fd/3 - diff --git a/bin/getRippledInfo b/bin/getRippledInfo new file mode 100755 index 00000000000..abfa449bac4 --- /dev/null +++ b/bin/getRippledInfo @@ -0,0 +1,150 @@ +#!/usr/bin/env bash + +# This script generates information about your rippled installation +# and system. It can be used to help debug issues that you may face +# in your installation. While this script endeavors to not display any +# sensitive information, it is recommended that you read the output +# before sharing with any third parties. + + +rippled_exe=/opt/ripple/bin/rippled +conf_file=/etc/opt/ripple/rippled.cfg + +while getopts ":e:c:" opt; do + case $opt in + e) + rippled_exe=${OPTARG} + ;; + c) + conf_file=${OPTARG} + ;; + \?) + echo "Invalid option: -$OPTARG" + exit -1 + esac +done + +tmp_loc=$(mktemp -d --tmpdir ripple_info.XXXXX) +chmod 751 ${tmp_loc} +awk_prog=${tmp_loc}/cfg.awk +summary_out=${tmp_loc}/rippled_info.md +printf "# rippled report info\n\n> generated at %s\n" "$(date -R)" > ${summary_out} + +function log_section { + printf "\n## %s\n" "$*" >> ${summary_out} + + while read -r l; do + echo " $l" >> ${summary_out} + done > ${awk_prog} + BEGIN {FS="[[:space:]]*=[[:space:]]*"; skip=0; db_path=""; print > OUT_FILE; split(exl,exa,"|")} + /^#/ {next} + save==2 && /^[[:space:]]*$/ {next} + /^\[.+\]$/ { + section=tolower(gensub(/^\[[[:space:]]*([a-zA-Z_]+)[[:space:]]*\]$/, "\\1", "g")) + skip = 0 + for (i in exa) { + if (section == exa[i]) + skip = 1 + } + if (section == "database_path") + save = 1 + } + skip==1 {next} + save==2 {save=0; db_path=$0} + save==1 {save=2} + $1 ~ /password/ {$0=$1"="} + {print >> OUT_FILE} + END {print db_path} +EOP + + db=$(\ + sed -r -e 's/\//g;s/^[[:space:]]*//;s/[[:space:]]*$//' ${conf_file} |\ + awk -v OUT_FILE=${cleaned_conf} -v exl="$(join_by '|' "${exclude[@]}")" -f ${awk_prog}) + rm ${awk_prog} + cat ${cleaned_conf} | log_section "cleaned config file" + rm ${cleaned_conf} + echo "${db}" | log_section "database path" + df ${db} | log_section "df: database" +fi + +# Send output from this script to a log file +## this captures any messages +## or errors from the script itself + +log_file=${tmp_loc}/get_info.log +exec 3>&1 1>>${log_file} 2>&1 + +## Send all stdout files to /tmp + +if [[ -x ${rippled_exe} ]] ; then + pgrep rippled && \ + ${rippled_exe} --conf ${conf_file} \ + -- server_info | log_section "server info" +fi + +cat /proc/meminfo | log_section "meminfo" +cat /proc/swaps | log_section "swap space" +ulimit -a | log_section "ulimit" + +if command -v lshw >/dev/null 2>&1 ; then + lshw 2>/dev/null | log_section "hardware info" +else + lscpu > ${tmp_loc}/hw_info.txt + hwinfo >> ${tmp_loc}/hw_info.txt + lspci >> ${tmp_loc}/hw_info.txt + lsblk >> ${tmp_loc}/hw_info.txt + cat ${tmp_loc}/hw_info.txt | log_section "hardware info" + rm ${tmp_loc}/hw_info.txt +fi + +if command -v iostat >/dev/null 2>&1 ; then + iostat -t -d -x 2 6 | log_section "iostat" +fi + +df -h | log_section "free disk space" +drives=($(df | awk '$1 ~ /^\/dev\// {print $1}' | xargs -n 1 basename)) +block_devs=($(ls /sys/block/)) +for d in "${drives[@]}"; do + for dev in "${block_devs[@]}"; do + #echo "D: [$d], DEV: [$dev]" + if [[ $d =~ $dev ]]; then + # this file (if exists) has 0 for SSD and 1 for HDD + if [[ "$(cat /sys/block/${dev}/queue/rotational 2>/dev/null)" == 0 ]] ; then + echo "${d} : SSD" >> ${tmp_loc}/is_ssd.txt + else + echo "${d} : NO SSD" >> ${tmp_loc}/is_ssd.txt + fi + fi + done +done + +if [[ -f ${tmp_loc}/is_ssd.txt ]] ; then + cat ${tmp_loc}/is_ssd.txt | log_section "SSD" + rm ${tmp_loc}/is_ssd.txt +fi + +cat ${log_file} | log_section "script log" + +cat << MSG | tee /dev/fd/3 +#################################################### + rippled info has been gathered. Please copy the + contents of ${summary_out} + to a github gist at https://gist.github.com/ + + PLEASE REVIEW THIS FILE FOR ANY SENSITIVE DATA + BEFORE POSTING! We have tried our best to omit + any sensitive information from this file, but you + should verify before posting. +#################################################### +MSG + diff --git a/bin/git/setup-upstreams.sh b/bin/git/setup-upstreams.sh new file mode 100755 index 00000000000..cdf3f37f37e --- /dev/null +++ b/bin/git/setup-upstreams.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +if [[ $# -ne 1 || "$1" == "--help" || "$1" == "-h" ]] +then + name=$( basename $0 ) + cat <<- USAGE + Usage: $name + + Where is the Github username of the upstream repo. e.g. XRPLF +USAGE + exit 0 +fi + +# Create upstream remotes based on origin +shift +user="$1" +# Get the origin URL. Expect it be an SSH-style URL +origin=$( git remote get-url origin ) +if [[ "${origin}" == "" ]] +then + echo Invalid origin remote >&2 + exit 1 +fi +# echo "Origin: ${origin}" +# Parse the origin +ifs_orig="${IFS}" +IFS=':' read remote originpath <<< "${origin}" +# echo "Remote: ${remote}, Originpath: ${originpath}" +IFS='@' read sshuser server <<< "${remote}" +# echo "SSHUser: ${sshuser}, Server: ${server}" +IFS='/' read originuser repo <<< "${originpath}" +# echo "Originuser: ${originuser}, Repo: ${repo}" +if [[ "${sshuser}" == "" || "${server}" == "" || "${originuser}" == "" + || "${repo}" == "" ]] +then + echo "Can't parse origin URL: ${origin}" >&2 + exit 1 +fi +upstream="https://${server}/${user}/${repo}" +upstreampush="${remote}:${user}/${repo}" +upstreamgroup="upstream upstream-push" +current=$( git remote get-url upstream 2>/dev/null ) +currentpush=$( git remote get-url upstream-push 2>/dev/null ) +currentgroup=$( git config remotes.upstreams ) +if [[ "${current}" == "${upstream}" ]] +then + echo "Upstream already set up correctly. Skip" +elif [[ -n "${current}" && "${current}" != "${upstream}" && + "${current}" != "${upstreampush}" ]] +then + echo "Upstream already set up as: ${current}. Skip" +else + if [[ "${current}" == "${upstreampush}" ]] + then + echo "Upstream set to dangerous push URL. Update." + _run git remote rename upstream upstream-push || \ + _run git remote remove upstream + currentpush=$( git remote get-url upstream-push 2>/dev/null ) + fi + _run git remote add upstream "${upstream}" +fi + +if [[ "${currentpush}" == "${upstreampush}" ]] +then + echo "upstream-push already set up correctly. Skip" +elif [[ -n "${currentpush}" && "${currentpush}" != "${upstreampush}" ]] +then + echo "upstream-push already set up as: ${currentpush}. Skip" +else + _run git remote add upstream-push "${upstreampush}" +fi + +if [[ "${currentgroup}" == "${upstreamgroup}" ]] +then + echo "Upstreams group already set up correctly. Skip" +elif [[ -n "${currentgroup}" && "${currentgroup}" != "${upstreamgroup}" ]] +then + echo "Upstreams group already set up as: ${currentgroup}. Skip" +else + _run git config --add remotes.upstreams "${upstreamgroup}" +fi + +_run git fetch --jobs=$(nproc) upstreams + +exit 0 + diff --git a/bin/git/squash-branches.sh b/bin/git/squash-branches.sh new file mode 100755 index 00000000000..66f1a2d715c --- /dev/null +++ b/bin/git/squash-branches.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +if [[ $# -lt 3 || "$1" == "--help" || "$1" = "-h" ]] +then + name=$( basename $0 ) + cat <<- USAGE + Usage: $name workbranch base/branch user/branch [user/branch [...]] + + * workbranch will be created locally from base/branch + * base/branch and user/branch may be specified as user:branch to allow + easy copying from Github PRs + * Remotes for each user must already be set up +USAGE +exit 0 +fi + +work="$1" +shift + +branches=( $( echo "${@}" | sed "s/:/\//" ) ) +base="${branches[0]}" +unset branches[0] + +set -e + +users=() +for b in "${branches[@]}" +do + users+=( $( echo $b | cut -d/ -f1 ) ) +done + +users=( $( printf '%s\n' "${users[@]}" | sort -u ) ) + +git fetch --multiple upstreams "${users[@]}" +git checkout -B "$work" --no-track "$base" + +for b in "${branches[@]}" +do + git merge --squash "${b}" + git commit -S # Use the commit message provided on the PR +done + +# Make sure the commits look right +git log --show-signature "$base..HEAD" + +parts=( $( echo $base | sed "s/\// /" ) ) +repo="${parts[0]}" +b="${parts[1]}" +push=$repo +if [[ "$push" == "upstream" ]] +then + push="upstream-push" +fi +if [[ "$repo" == "upstream" ]] +then + repo="upstreams" +fi +cat << PUSH + +------------------------------------------------------------------- +This script will not push. Verify everything is correct, then push +to your repo, and create a PR if necessary. Once the PR is approved, +run: + +git push $push HEAD:$b +git fetch $repo +------------------------------------------------------------------- +PUSH + diff --git a/bin/git/update-version.sh b/bin/git/update-version.sh new file mode 100755 index 00000000000..c901a29e6a7 --- /dev/null +++ b/bin/git/update-version.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +if [[ $# -ne 3 || "$1" == "--help" || "$1" = "-h" ]] +then + name=$( basename $0 ) + cat <<- USAGE + Usage: $name workbranch base/branch version + + * workbranch will be created locally from base/branch. If it exists, + it will be reused, so make sure you don't overwrite any work. + * base/branch may be specified as user:branch to allow easy copying + from Github PRs. +USAGE +exit 0 +fi + +work="$1" +shift + +base=$( echo "$1" | sed "s/:/\//" ) +shift + +version=$1 +shift + +set -e + +git fetch upstreams + +git checkout -B "${work}" --no-track "${base}" + +push=$( git rev-parse --abbrev-ref --symbolic-full-name '@{push}' \ + 2>/dev/null ) || true +if [[ "${push}" != "" ]] +then + echo "Warning: ${push} may already exist." +fi + +build=$( find -name BuildInfo.cpp ) +sed 's/\(^.*versionString =\).*$/\1 "'${version}'"/' ${build} > version.cpp && \ +diff "${build}" version.cpp && exit 1 || \ +mv -vi version.cpp ${build} + +git diff + +git add ${build} + +git commit -S -m "Set version to ${version}" + +git log --oneline --first-parent ${base}^.. + +cat << PUSH + +------------------------------------------------------------------- +This script will not push. Verify everything is correct, then push +to your repo, and create a PR as described in CONTRIBUTING.md. +------------------------------------------------------------------- +PUSH diff --git a/bin/physical.sh b/bin/physical.sh new file mode 100755 index 00000000000..c2c5aad68db --- /dev/null +++ b/bin/physical.sh @@ -0,0 +1,218 @@ +#!/bin/bash + +set -o errexit + +marker_base=985c80fbc6131f3a8cedd0da7e8af98dfceb13c7 +marker_commit=${1:-${marker_base}} + +if [ $(git merge-base ${marker_commit} ${marker_base}) != ${marker_base} ]; then + echo "first marker commit not an ancestor: ${marker_commit}" + exit 1 +fi + +if [ $(git merge-base ${marker_commit} HEAD) != $(git rev-parse --verify ${marker_commit}) ]; then + echo "given marker commit not an ancestor: ${marker_commit}" + exit 1 +fi + +if [ -e Builds/CMake ]; then + echo move CMake + git mv Builds/CMake cmake + git add --update . + git commit -m 'Move CMake directory' --author 'Pretty Printer ' +fi + +if [ -e src/ripple ]; then + + echo move protocol buffers + mkdir -p include/xrpl + if [ -e src/ripple/proto ]; then + git mv src/ripple/proto include/xrpl + fi + + extract_list() { + git show ${marker_commit}:Builds/CMake/RippledCore.cmake | \ + awk "/END ${1}/ { p = 0 } p && /src\/ripple/; /BEGIN ${1}/ { p = 1 }" | \ + sed -e 's#src/ripple/##' -e 's#[^a-z]\+$##' + } + + move_files() { + oldroot="$1"; shift + newroot="$1"; shift + detail="$1"; shift + files=("$@") + for file in ${files[@]}; do + if [ ! -e ${oldroot}/${file} ]; then + continue + fi + dir=$(dirname ${file}) + if [ $(basename ${dir}) == 'details' ]; then + dir=$(dirname ${dir}) + fi + if [ $(basename ${dir}) == 'impl' ]; then + dir="$(dirname ${dir})/${detail}" + fi + mkdir -p ${newroot}/${dir} + git mv ${oldroot}/${file} ${newroot}/${dir} + done + } + + echo move libxrpl headers + files=$(extract_list 'LIBXRPL HEADERS') + files+=( + basics/SlabAllocator.h + + beast/asio/io_latency_probe.h + beast/container/aged_container.h + beast/container/aged_container_utility.h + beast/container/aged_map.h + beast/container/aged_multimap.h + beast/container/aged_multiset.h + beast/container/aged_set.h + beast/container/aged_unordered_map.h + beast/container/aged_unordered_multimap.h + beast/container/aged_unordered_multiset.h + beast/container/aged_unordered_set.h + beast/container/detail/aged_associative_container.h + beast/container/detail/aged_container_iterator.h + beast/container/detail/aged_ordered_container.h + beast/container/detail/aged_unordered_container.h + beast/container/detail/empty_base_optimization.h + beast/core/LockFreeStack.h + beast/insight/Collector.h + beast/insight/Counter.h + beast/insight/CounterImpl.h + beast/insight/Event.h + beast/insight/EventImpl.h + beast/insight/Gauge.h + beast/insight/GaugeImpl.h + beast/insight/Group.h + beast/insight/Groups.h + beast/insight/Hook.h + beast/insight/HookImpl.h + beast/insight/Insight.h + beast/insight/Meter.h + beast/insight/MeterImpl.h + beast/insight/NullCollector.h + beast/insight/StatsDCollector.h + beast/test/fail_counter.h + beast/test/fail_stream.h + beast/test/pipe_stream.h + beast/test/sig_wait.h + beast/test/string_iostream.h + beast/test/string_istream.h + beast/test/string_ostream.h + beast/test/test_allocator.h + beast/test/yield_to.h + beast/utility/hash_pair.h + beast/utility/maybe_const.h + beast/utility/temp_dir.h + + # included by only json/impl/json_assert.h + json/json_errors.h + + protocol/PayChan.h + protocol/RippleLedgerHash.h + protocol/messages.h + protocol/st.h + ) + files+=( + basics/README.md + crypto/README.md + json/README.md + protocol/README.md + resource/README.md + ) + move_files src/ripple include/xrpl detail ${files[@]} + + echo move libxrpl sources + files=$(extract_list 'LIBXRPL SOURCES') + move_files src/ripple src/libxrpl "" ${files[@]} + + echo check leftovers + dirs=$(cd include/xrpl; ls -d */) + dirs=$(cd src/ripple; ls -d ${dirs} 2>/dev/null || true) + files="$(cd src/ripple; find ${dirs} -type f)" + if [ -n "${files}" ]; then + echo "leftover files:" + echo ${files} + exit + fi + + echo remove empty directories + empty_dirs="$(cd src/ripple; find ${dirs} -depth -type d)" + for dir in ${empty_dirs[@]}; do + if [ -e ${dir} ]; then + rmdir ${dir} + fi + done + + echo move xrpld sources + files=$( + extract_list 'XRPLD SOURCES' + cd src/ripple + find * -regex '.*\.\(h\|ipp\|md\|pu\|uml\|png\)' + ) + move_files src/ripple src/xrpld detail ${files[@]} + + files="$(cd src/ripple; find . -type f)" + if [ -n "${files}" ]; then + echo "leftover files:" + echo ${files} + exit + fi + +fi + +rm -rf src/ripple + +echo rename .hpp to .h +find include src -name '*.hpp' -exec bash -c 'f="{}"; git mv "${f}" "${f%hpp}h"' \; + +echo move PerfLog.h +if [ -e include/xrpl/basics/PerfLog.h ]; then + git mv include/xrpl/basics/PerfLog.h src/xrpld/perflog +fi + +# Make sure all protobuf includes have the correct prefix. +protobuf_replace='s:^#include\s*["<].*org/xrpl\([^">]\+\)[">]:#include :' +# Make sure first-party includes use angle brackets and .h extension. +ripple_replace='s:include\s*["<]ripple/\(.*\)\.h\(pp\)\?[">]:include :' +beast_replace='s:include\s*:#include :" \ + -e "s:^#include ' +find include src -type f \( -name '*.cpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-10 -i {} + +git add --update . +git commit -m 'Rewrite includes' --author 'Pretty Printer ' +./Builds/levelization/levelization.sh +git add --update . +git commit -m 'Recompute loops' --author 'Pretty Printer ' diff --git a/bin/sh/install-vcpkg.sh b/bin/sh/install-vcpkg.sh index 984fad7fc42..8cf8f2d0881 100755 --- a/bin/sh/install-vcpkg.sh +++ b/bin/sh/install-vcpkg.sh @@ -1,33 +1,51 @@ #!/usr/bin/env bash set -exu +: ${TRAVIS_BUILD_DIR:=""} +: ${VCPKG_DIR:=".vcpkg"} +export VCPKG_ROOT=${VCPKG_DIR} +: ${VCPKG_DEFAULT_TRIPLET:="x64-windows-static"} + +export VCPKG_DEFAULT_TRIPLET + +EXE="vcpkg" if [[ -z ${COMSPEC:-} ]]; then - EXE="vcpkg" -else - EXE="vcpkg.exe" + EXE="${EXE}.exe" fi -if [[ -d "${VCPKG_DIR}" && -x "${VCPKG_DIR}/${EXE}" ]] ; then +if [[ -d "${VCPKG_DIR}" && -x "${VCPKG_DIR}/${EXE}" && -d "${VCPKG_DIR}/installed" ]] ; then echo "Using cached vcpkg at ${VCPKG_DIR}" ${VCPKG_DIR}/${EXE} list - exit -fi - -if [[ -d "${VCPKG_DIR}" ]] ; then - rm -rf "${VCPKG_DIR}" +else + if [[ -d "${VCPKG_DIR}" ]] ; then + rm -rf "${VCPKG_DIR}" + fi + git clone --branch 2021.04.30 https://github.com/Microsoft/vcpkg.git ${VCPKG_DIR} + pushd ${VCPKG_DIR} + BSARGS=() + if [[ "$(uname)" == "Darwin" ]] ; then + BSARGS+=(--allowAppleClang) + fi + if [[ -z ${COMSPEC:-} ]]; then + chmod +x ./bootstrap-vcpkg.sh + time ./bootstrap-vcpkg.sh "${BSARGS[@]}" + else + time ./bootstrap-vcpkg.bat + fi + popd fi -git clone --branch 2019.06 https://github.com/Microsoft/vcpkg.git ${VCPKG_DIR} -pushd ${VCPKG_DIR} -if [[ -z ${COMSPEC:-} ]]; then - chmod +x ./bootstrap-vcpkg.sh - ./bootstrap-vcpkg.sh +# TODO: bring boost in this way as well ? +# NOTE: can pin specific ports to a commit/version like this: +# git checkout ports/boost +if [ $# -eq 0 ]; then + echo "No extra packages specified..." + PKGS=() else - ./bootstrap-vcpkg.bat + PKGS=( "$@" ) fi -popd -# TODO -- can pin specific ports to a commit/version like this: -#git checkout ports/boost +for LIB in "${PKGS[@]}"; do + time ${VCPKG_DIR}/${EXE} --clean-after-build install ${LIB} +done -${VCPKG_DIR}/${EXE} install openssl diff --git a/bin/sh/setup-msvc.sh b/bin/sh/setup-msvc.sh index 100cf363d95..8d61c9757fa 100755 --- a/bin/sh/setup-msvc.sh +++ b/bin/sh/setup-msvc.sh @@ -22,6 +22,8 @@ while read line ; do fi fi done <= 7 + +import argparse +import asyncio +import configparser +import contextlib +import json +import logging +import os +from pathlib import Path +import platform +import subprocess +import time +import urllib.error +import urllib.request + +# Enable asynchronous subprocesses on Windows. The default changed in 3.8. +# https://docs.python.org/3.7/library/asyncio-platforms.html#subprocess-support-on-windows +if (platform.system() == 'Windows' and sys.version_info.major == 3 + and sys.version_info.minor < 8): + asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) + +DEFAULT_EXE = 'rippled' +DEFAULT_CONFIGURATION_FILE = 'rippled.cfg' +# Number of seconds to wait before forcefully terminating. +PATIENCE = 120 +# Number of contiguous seconds in a sync state to be considered synced. +DEFAULT_SYNC_DURATION = 60 +# Number of seconds between polls of state. +DEFAULT_POLL_INTERVAL = 5 +SYNC_STATES = ('full', 'validating', 'proposing') + + +def read_config(config_file): + # strict = False: Allow duplicate keys, e.g. [rpc_startup]. + # allow_no_value = True: Allow keys with no values. Generally, these + # instances use the "key" as the value, and the section name is the key, + # e.g. [debug_logfile]. + # delimiters = ('='): Allow ':' as a character in Windows paths. Some of + # our "keys" are actually values, and we don't want to split them on ':'. + config = configparser.ConfigParser( + strict=False, + allow_no_value=True, + delimiters=('='), + ) + config.read(config_file) + return config + + +def to_list(value, separator=','): + """Parse a list from a delimited string value.""" + return [s.strip() for s in value.split(separator) if s] + + +def find_log_file(config_file): + """Try to figure out what log file the user has chosen. Raises all kinds + of exceptions if there is any possibility of ambiguity.""" + config = read_config(config_file) + values = list(config['debug_logfile'].keys()) + if len(values) < 1: + raise ValueError( + f'no [debug_logfile] in configuration file: {config_file}') + if len(values) > 1: + raise ValueError( + f'too many [debug_logfile] in configuration file: {config_file}') + return values[0] + + +def find_http_port(config_file): + config = read_config(config_file) + names = list(config['server'].keys()) + for name in names: + server = config[name] + if 'http' in to_list(server.get('protocol', '')): + return int(server['port']) + raise ValueError(f'no server in [server] for "http" protocol') + + +@contextlib.asynccontextmanager +async def rippled(exe=DEFAULT_EXE, config_file=DEFAULT_CONFIGURATION_FILE): + """A context manager for a rippled process.""" + # Start the server. + process = await asyncio.create_subprocess_exec( + str(exe), + '--conf', + str(config_file), + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + logging.info(f'rippled started with pid {process.pid}') + try: + yield process + finally: + # Ask it to stop. + logging.info(f'asking rippled (pid: {process.pid}) to stop') + start = time.time() + process.terminate() + + # Wait nicely. + try: + await asyncio.wait_for(process.wait(), PATIENCE) + except asyncio.TimeoutError: + # Ask the operating system to kill it. + logging.warning(f'killing rippled ({process.pid})') + try: + process.kill() + except ProcessLookupError: + pass + + code = await process.wait() + end = time.time() + logging.info( + f'rippled stopped after {end - start:.1f} seconds with code {code}' + ) + + +async def sync( + port, + *, + duration=DEFAULT_SYNC_DURATION, + interval=DEFAULT_POLL_INTERVAL, +): + """Poll rippled on an interval until it has been synced for a duration.""" + start = time.perf_counter() + while (time.perf_counter() - start) < duration: + await asyncio.sleep(interval) + + request = urllib.request.Request( + f'http://127.0.0.1:{port}', + data=json.dumps({ + 'method': 'server_state' + }).encode(), + headers={'Content-Type': 'application/json'}, + ) + with urllib.request.urlopen(request) as response: + try: + body = json.loads(response.read()) + except urllib.error.HTTPError as cause: + logging.warning(f'server_state returned not JSON: {cause}') + start = time.perf_counter() + continue + + try: + state = body['result']['state']['server_state'] + except KeyError as cause: + logging.warning(f'server_state response missing key: {cause.key}') + start = time.perf_counter() + continue + logging.info(f'server_state: {state}') + if state not in SYNC_STATES: + # Require a contiguous sync state. + start = time.perf_counter() + + +async def loop(test, + *, + exe=DEFAULT_EXE, + config_file=DEFAULT_CONFIGURATION_FILE): + """ + Start-test-stop rippled in an infinite loop. + + Moves log to a different file after each iteration. + """ + log_file = find_log_file(config_file) + id = 0 + while True: + logging.info(f'iteration: {id}') + async with rippled(exe, config_file) as process: + start = time.perf_counter() + exited = asyncio.create_task(process.wait()) + tested = asyncio.create_task(test()) + # Try to sync as long as the process is running. + done, pending = await asyncio.wait( + {exited, tested}, + return_when=asyncio.FIRST_COMPLETED, + ) + if done == {exited}: + code = exited.result() + logging.warning( + f'server halted for unknown reason with code {code}') + else: + assert done == {tested} + assert tested.exception() is None + end = time.perf_counter() + logging.info(f'synced after {end - start:.0f} seconds') + os.replace(log_file, f'debug.{id}.log') + id += 1 + + +logging.basicConfig( + format='%(asctime)s %(levelname)-8s %(message)s', + level=logging.INFO, + datefmt='%Y-%m-%d %H:%M:%S', +) + +parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) +parser.add_argument( + 'rippled', + type=Path, + nargs='?', + default=DEFAULT_EXE, + help='Path to rippled.', +) +parser.add_argument( + '--conf', + type=Path, + default=DEFAULT_CONFIGURATION_FILE, + help='Path to configuration file.', +) +parser.add_argument( + '--duration', + type=int, + default=DEFAULT_SYNC_DURATION, + help='Number of contiguous seconds required in a synchronized state.', +) +parser.add_argument( + '--interval', + type=int, + default=DEFAULT_POLL_INTERVAL, + help='Number of seconds to wait between polls of state.', +) +args = parser.parse_args() + +port = find_http_port(args.conf) + + +def test(): + return sync(port, duration=args.duration, interval=args.interval) + + +try: + asyncio.run(loop(test, exe=args.rippled, config_file=args.conf)) +except KeyboardInterrupt: + # Squelch the message. This is a normal mode of exit. + pass diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg index c43f0e2d1f6..8fb7d008758 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/rippled-example.cfg @@ -13,15 +13,17 @@ # # 4. HTTPS Client # -# 5. Database +# 5. # -# 6. Diagnostics +# 6. Database # -# 7. Voting +# 7. Diagnostics # -# 8. Misc Settings +# 8. Voting # -# 9. Example Settings +# 9. Misc Settings +# +# 10. Example Settings # #------------------------------------------------------------------------------- # @@ -36,7 +38,7 @@ # For more information on where the rippled server instance searches for the # file, visit: # -# https://developers.ripple.com/commandline-usage.html#generic-options +# https://xrpl.org/commandline-usage.html#generic-options # # This file should be named rippled.cfg. This file is UTF-8 with DOS, UNIX, # or Mac style end of lines. Blank lines and lines beginning with '#' are @@ -198,9 +200,19 @@ # # admin = [ IP, IP, IP, ... ] # -# A comma-separated list of IP addresses. -# -# When set, grants administrative command access to the specified IP +# A comma-separated list of IP addresses or subnets. Subnets +# should be represented in "slash" notation, such as: +# 10.0.0.0/8 +# 172.16.0.0/12 +# 192.168.0.0/16 +# Those examples are ipv4, but ipv6 is also supported. +# When configuring subnets, the address must match the +# underlying network address. Otherwise, the desired IP range is +# ambiguous. For example, 10.1.2.3/24 has a network address of +# 10.1.2.0. Therefore, that subnet should be configured as +# 10.1.2.0/24. +# +# When set, grants administrative command access to the specified # addresses. These commands may be issued over http, https, ws, or wss # if configured on the port. If not provided, the default is to not allow # administrative commands. @@ -231,9 +243,10 @@ # # secure_gateway = [ IP, IP, IP, ... ] # -# A comma-separated list of IP addresses. +# A comma-separated list of IP addresses or subnets. See the +# details for the "admin" option above. # -# When set, allows the specified IP addresses to pass HTTP headers +# When set, allows the specified addresses to pass HTTP headers # containing username and remote IP address for each session. If a # non-empty username is passed in this way, then resource controls # such as often resulting in "tooBusy" errors will be lifted. However, @@ -248,9 +261,9 @@ # proxies. Since rippled trusts these hosts, they must be # responsible for properly authenticating the remote user. # -# The same IP address cannot be used in both "admin" and "secure_gateway" -# lists for the same port. In this case, rippled will abort with an error -# message to the console shortly after startup +# If some IP addresses are included for both "admin" and +# "secure_gateway" connections, then they will be treated as +# "admin" addresses. # # ssl_key = # ssl_cert = @@ -270,12 +283,14 @@ # ssl_cert # # Specifies the path to the SSL certificate file in PEM format. -# This is not needed if the chain includes it. +# This is not needed if the chain includes it. Use ssl_chain if +# your certificate includes one or more intermediates. # # ssl_chain # # If you need a certificate chain, specify the path to the # certificate chain here. The chain may include the end certificate. +# This must be used if the certificate includes intermediates. # # ssl_ciphers = # @@ -351,6 +366,14 @@ # connection is no longer available. # # +# [server_domain] +# +# domain name +# +# The domain under which a TOML file applicable to this server can be +# found. A server may lie about its domain so the TOML should contain +# a reference to this server by pubkey in the [nodes] array. +# # #------------------------------------------------------------------------------- # @@ -366,26 +389,44 @@ # # # +# [compression] +# +# true or false +# +# true - enables compression +# false - disables compression [default]. +# +# The rippled server can save bandwidth by compressing its peer-to-peer communications, +# at a cost of greater CPU usage. If you enable link compression, +# the server automatically compresses communications with peer servers +# that also have link compression enabled. +# https://xrpl.org/enable-link-compression.html +# +# +# # [ips] # # List of hostnames or ips where the Ripple protocol is served. A default # starter list is included in the code and used if no other hostnames are # available. # -# One address or domain name per line is allowed. A port may must be -# specified after adding a space to the address. The ordering of entries -# does not generally matter. +# One address or domain name per line is allowed. A port may be specified +# after adding a space to the address. If a port is not specified, the default +# port of 2459 will be used. Many servers still use the legacy port of 51235. +# To connect to such servers, you must specify the port number. The ordering +# of entries does not generally matter. # # The default list of entries is: # - r.ripple.com 51235 -# - zaphod.alloy.ee 51235 # - sahyadri.isrdc.in 51235 +# - hubs.xrpkuwait.com 51235 +# - hub.xrpl-commons.org 51235 # # Examples: # # [ips] # 192.168.0.1 -# 192.168.0.1 2459 +# 192.168.0.1 2459 # r.ripple.com 51235 # # @@ -440,17 +481,11 @@ # # # -# [sntp_servers] -# -# IP address or domain of NTP servers to use for time synchronization. +# [max_transactions] # -# These NTP servers are suitable for rippled servers located in the United -# States: -# time.windows.com -# time.apple.com -# time.nist.gov -# pool.ntp.org +# Configure the maximum number of transactions to have in the job queue # +# Must be a number between 100 and 1000, defaults to 250 # # # [overlay] @@ -474,6 +509,23 @@ # single host from consuming all inbound slots. If the value is not # present the server will autoconfigure an appropriate limit. # +# max_unknown_time = +# +# The maximum amount of time, in seconds, that an outbound connection +# is allowed to stay in the "unknown" tracking state. This option can +# take any value between 300 and 1800 seconds, inclusive. If the option +# is not present the server will autoconfigure an appropriate limit. +# +# The current default (which is subject to change) is 600 seconds. +# +# max_diverged_time = +# +# The maximum amount of time, in seconds, that an outbound connection +# is allowed to stay in the "diverged" tracking state. The option can +# take any value between 60 and 900 seconds, inclusive. If the option +# is not present the server will autoconfigure an appropriate limit. +# +# The current default (which is subject to change) is 300 seconds. # # # [transaction_queue] EXPERIMENTAL @@ -506,14 +558,6 @@ # than the original transaction's fee, or meet the current open # ledger fee to be considered. Default: 25. # -# multi_txn_percent = -# -# If a client submits multiple transactions (different sequence -# numbers), later transactions must pay a fee at least -# percent higher than the transaction with the previous sequence -# number. -# Default: -90. -# # minimum_escalation_multiplier = # # At ledger close time, the median fee level of the transactions @@ -583,22 +627,43 @@ # #------------------------------------------------------------------------------- # -# 3. Ripple Protocol +# 3. Protocol # #------------------- # # These settings affect the behavior of the server instance with respect -# to Ripple payment protocol level activities such as validating and -# closing ledgers or adjusting fees in response to server overloads. +# to protocol level activities such as validating and closing ledgers +# adjusting fees in response to server overloads. # # # -# [node_size] # -# Tunes the servers based on the expected load and available memory. Legal -# sizes are "tiny", "small", "medium", "large", and "huge". We recommend -# you start at the default and raise the setting if you have extra memory. -# The default is "tiny". +# [relay_proposals] +# +# Controls the relay and processing behavior for proposals received by this +# server that are issued by validators that are not on the server's UNL. +# +# Legal values are: +# "all" - Relay and process all incoming proposals +# "trusted" - Relay only trusted proposals, but locally process all +# "drop_untrusted" - Relay only trusted proposals, do not process untrusted +# +# The default is "trusted". +# +# +# [relay_validations] +# +# Controls the relay and processing behavior for validations received by this +# server that are issued by validators that are not on the server's UNL. +# +# Legal values are: +# "all" - Relay and process all incoming validations +# "trusted" - Relay only trusted validations, but locally process all +# "drop_untrusted" - Relay only trusted validations, do not process untrusted +# +# The default is "all". +# +# # # # @@ -700,7 +765,9 @@ # When searching for paths, the default search aggressiveness. This can take # exponentially more resources as the size is increased. # -# The default is: 7 +# The recommended value to support advanced pathfinding is: 7 +# +# The default is: 2 # # [path_search_fast] # [path_search_max] @@ -709,12 +776,19 @@ # If you do not need pathfinding, you can set path_search_max to zero to # disable it and avoid some expensive bookkeeping. # -# The default for 'path_search_fast' is 2. The default for 'path_search_max' is 10. +# To support advanced pathfinding the recommended value for +# 'path_search_fast' is 2, and for 'path_search_max' is 10. +# +# The default for 'path_search_fast' is 2. The default for 'path_search_max' is 3. # # [path_search_old] # # For clients that use the legacy path finding interfaces, the search -# aggressiveness to use. The default is 7. +# aggressiveness to use. +# +# The recommended value to support advanced pathfinding is: 7. +# +# The default is: 2 # # # @@ -728,9 +802,17 @@ # [workers] # # Configures the number of threads for processing work submitted by peers -# and clients. If not specified, then the value is automatically determined -# by factors including the number of system processors and whether this -# node is a validator. +# and clients. If not specified, then the value is automatically set to the +# number of processor threads plus 2 for networked nodes. Nodes running in +# stand alone mode default to 1 worker. +# +# [io_workers] +# +# Configures the number of threads for processing raw inbound and outbound IO. +# +# [prefetch_workers] +# +# Configures the number of threads for performing nodestore prefetching. # # # @@ -746,11 +828,23 @@ # # main -> 0 # testnet -> 1 +# devnet -> 2 # # If this value is not specified the server is not explicitly configured # to track a particular network. # # +# [ledger_replay] +# +# 0 or 1. +# +# 0: Disable the ledger replay feature [default] +# 1: Enable the ledger replay feature. With this feature enabled, when +# acquiring a ledger from the network, a rippled node only downloads +# the ledger header and the transactions instead of the whole ledger. +# And the ledger is built by applying the transactions to the parent +# ledger. +# #------------------------------------------------------------------------------- # # 4. HTTPS Client @@ -791,11 +885,9 @@ # certificates that the server will accept for verifying HTTP servers. # Used only for outbound HTTPS client connections. # -# -# #------------------------------------------------------------------------------- # -# 5. Database +# 6. Database # #------------ # @@ -844,25 +936,84 @@ # keeping full history is not advised, and using online delete is # recommended. # -# Required keys: -# path Location to store the database (all types) +# Required keys for NuDB and RocksDB: # -# Optional keys: +# path Location to store the database +# +# Optional keys +# +# cache_size Size of cache for database records. Default is 16384. +# Setting this value to 0 will use the default value. +# +# cache_age Length of time in minutes to keep database records +# cached. Default is 5 minutes. Setting this value to +# 0 will use the default value. +# +# Note: if neither cache_size nor cache_age is +# specified, the cache for database records will not +# be created. If only one of cache_size or cache_age +# is specified, the cache will be created using the +# default value for the unspecified parameter. +# +# Note: the cache will not be created if online_delete +# is specified. # -# These keys are possible for any type of backend: +# fast_load Boolean. If set, load the last persisted ledger +# from disk upon process start before syncing to +# the network. This is likely to improve performance +# if sufficient IOPS capacity is available. +# Default 0. +# +# Optional keys for NuDB or RocksDB: +# +# earliest_seq The default is 32570 to match the XRP ledger +# network's earliest allowed sequence. Alternate +# networks may set this value. Minimum value of 1. # # online_delete Minimum value of 256. Enable automatic purging # of older ledger information. Maintain at least this # number of ledger records online. Must be greater # than or equal to ledger_history. # -# advisory_delete 0 for disabled, 1 for enabled. If set, then -# require administrative RPC call "can_delete" -# to enable online deletion of ledger records. +# These keys modify the behavior of online_delete, and thus are only +# relevant if online_delete is defined and non-zero: # -# earliest_seq The default is 32570 to match the XRP ledger -# network's earliest allowed sequence. Alternate -# networks may set this value. Minimum value of 1. +# advisory_delete 0 for disabled, 1 for enabled. If set, the +# administrative RPC call "can_delete" is required +# to enable online deletion of ledger records. +# Online deletion does not run automatically if +# non-zero and the last deletion was on a ledger +# greater than the current "can_delete" setting. +# Default is 0. +# +# delete_batch When automatically purging, SQLite database +# records are deleted in batches. This value +# controls the maximum size of each batch. Larger +# batches keep the databases locked for more time, +# which may cause other functions to fall behind, +# and thus cause the node to lose sync. +# Default is 100. +# +# back_off_milliseconds +# Number of milliseconds to wait between +# online_delete batches to allow other functions +# to catch up. +# Default is 100. +# +# age_threshold_seconds +# The online delete process will only run if the +# latest validated ledger is younger than this +# number of seconds. +# Default is 60. +# +# recovery_wait_seconds +# The online delete process checks periodically +# that rippled is still in sync with the network, +# and that the validated ledger is less than +# 'age_threshold_seconds' old. If not, then continue +# sleeping for this number of seconds and +# checking until healthy. +# Default is 5. # # Notes: # The 'node_db' entry configures the primary, persistent storage. @@ -874,34 +1025,108 @@ # [import_db] Settings for performing a one-time import (optional) # [database_path] Path to the book-keeping databases. # -# [shard_db] Settings for the Shard Database (optional) +# The server creates and maintains 4 to 5 bookkeeping SQLite databases in +# the 'database_path' location. If you omit this configuration setting, +# the server creates a directory called "db" located in the same place as +# your rippled.cfg file. +# Partial pathnames are relative to the location of the rippled executable. +# +# [sqlite] Tuning settings for the SQLite databases (optional) # # Format (without spaces): # One or more lines of case-insensitive key / value pairs: # '=' # ... # -# Example: -# path=db/shards/nudb -# -# Required keys: -# path Location to store the database -# -# max_size_gb Maximum disk space the database will utilize (in gigabytes) +# Example 1: +# safety_level=low # +# Example 2: +# journal_mode=off +# synchronous=off # -# There are 4 bookkeeping SQLite database that the server creates and -# maintains. If you omit this configuration setting, it will default to -# creating a directory called "db" located in the same place as your -# rippled.cfg file. Partial pathnames will be considered relative to -# the location of the rippled executable. +# WARNING: These settings can have significant effects on data integrity, +# particularly in systemic failure scenarios. It is strongly recommended +# that they be left at their defaults unless the server is having +# performance issues during normal operation or during automatic purging +# (online_delete) operations. A warning will be logged on startup if +# 'ledger_history' is configured to store more than 10,000,000 ledgers and +# any of these settings are less safe than the default. This is due to the +# inordinate amount of time and bandwidth it will take to safely rebuild a +# corrupted database of that size from other peers. # +# Optional keys: # +# safety_level Valid values: high, low +# The default is "high", which tunes the SQLite +# databases in the most reliable mode, and is +# equivalent to: +# journal_mode=wal +# synchronous=normal +# temp_store=file +# "low" is equivalent to: +# journal_mode=memory +# synchronous=off +# temp_store=memory +# These "low" settings trade speed and reduced I/O +# for a higher risk of data loss. See the +# individual settings below for more information. +# This setting may not be combined with any of the +# other tuning settings: "journal_mode", +# "synchronous", or "temp_store". +# +# journal_mode Valid values: delete, truncate, persist, memory, wal, off +# The default is "wal", which uses a write-ahead +# log to implement database transactions. +# Alternately, "memory" saves disk I/O, but if +# rippled crashes during a transaction, the +# database is likely to be corrupted. +# See https://www.sqlite.org/pragma.html#pragma_journal_mode +# for more details about the available options. +# This setting may not be combined with the +# "safety_level" setting. +# +# synchronous Valid values: off, normal, full, extra +# The default is "normal", which works well with +# the "wal" journal mode. Alternatively, "off" +# allows rippled to continue as soon as data is +# passed to the OS, which can significantly +# increase speed, but risks data corruption if +# the host computer crashes before writing that +# data to disk. +# See https://www.sqlite.org/pragma.html#pragma_synchronous +# for more details about the available options. +# This setting may not be combined with the +# "safety_level" setting. +# +# temp_store Valid values: default, file, memory +# The default is "file", which will use files +# for temporary database tables and indices. +# Alternatively, "memory" may save I/O, but +# rippled does not currently use many, if any, +# of these temporary objects. +# See https://www.sqlite.org/pragma.html#pragma_temp_store +# for more details about the available options. +# This setting may not be combined with the +# "safety_level" setting. +# +# page_size Valid values: integer (MUST be power of 2 between 512 and 65536) +# The default is 4096 bytes. This setting determines +# the size of a page in the transaction.db file. +# See https://www.sqlite.org/pragma.html#pragma_page_size +# for more details about the available options. +# +# journal_size_limit Valid values: integer +# The default is 1582080. This setting limits +# the size of the journal for transaction.db file. When the limit is +# reached, older entries will be deleted. +# See https://www.sqlite.org/pragma.html#pragma_journal_size_limit +# for more details about the available options. # # #------------------------------------------------------------------------------- # -# 6. Diagnostics +# 7. Diagnostics # #--------------- # @@ -975,7 +1200,7 @@ # #------------------------------------------------------------------------------- # -# 7. Voting +# 8. Voting # #---------- # @@ -1010,7 +1235,7 @@ # default. Don't change this without understanding the consequences. # # Example: -# account_reserve = 20000000 # 20 XRP +# account_reserve = 10000000 # 10 XRP # # owner_reserve = # @@ -1022,14 +1247,34 @@ # default. Don't change this without understanding the consequences. # # Example: -# owner_reserve = 5000000 # 5 XRP +# owner_reserve = 2000000 # 2 XRP # #------------------------------------------------------------------------------- # -# 8. Misc Settings +# 9. Misc Settings # #----------------- # +# [node_size] +# +# Tunes the servers based on the expected load and available memory. Legal +# sizes are "tiny", "small", "medium", "large", and "huge". We recommend +# you start at the default and raise the setting if you have extra memory. +# +# The code attempts to automatically determine the appropriate size for +# this parameter based on the amount of RAM and the number of execution +# cores available to the server. The current decision matrix is: +# +# | | Cores | +# |---------|------------------------| +# | RAM | 1 | 2 or 3 | ≥ 4 | +# |---------|------|--------|--------| +# | < ~8GB | tiny | tiny | tiny | +# | < ~12GB | tiny | small | small | +# | < ~16GB | tiny | small | medium | +# | < ~24GB | tiny | small | large | +# | < ~32GB | tiny | small | huge | +# # [signing_support] # # Specifies whether the server will accept "sign" and "sign_for" commands @@ -1052,7 +1297,7 @@ # [crawl] # # List of options to control what data is reported through the /crawl endpoint -# See https://developers.ripple.com/peer-protocol.html#peer-crawler +# See https://xrpl.org/peer-crawler.html # # # @@ -1093,9 +1338,28 @@ # counts = 0 # unl = 1 # +# [vl] +# +# Options to control what data is reported through the /vl endpoint +# See [...] +# +# enable = +# +# Enable or disable access to /vl requests. Default is '1' which +# enables access. +# +# [beta_rpc_api] +# +# 0 or 1. +# +# 0: Disable the beta API version for JSON-RPC and WebSocket [default] +# 1: Enable the beta API version for testing. The beta API version +# contains breaking changes that require a new API version number. +# They are not ready for public consumption. +# #------------------------------------------------------------------------------- # -# 9. Example Settings +# 10. Example Settings # #-------------------- # @@ -1123,6 +1387,12 @@ # Admin level API commands over Secure Websockets, when originating # from the same machine (via the loopback adapter at 127.0.0.1). # +# "grpc" +# +# ETL commands for Clio. We recommend setting secure_gateway +# in this section to a comma-separated list of the addresses +# of your Clio servers, in order to bypass rippled's rate limiting. +# # This port is commented out but can be enabled by removing # the '#' from each corresponding line including the entry under [server] # @@ -1156,6 +1426,9 @@ admin = 127.0.0.1 protocol = http [port_peer] +# Many servers still use the legacy port of 51235, so for backward-compatibility +# we maintain that port number here. However, for new servers we recommend +# changing this to the default port of 2459. port = 51235 ip = 0.0.0.0 # alternatively, to accept connections on IPv4 + IPv6, use: @@ -1167,56 +1440,51 @@ port = 6006 ip = 127.0.0.1 admin = 127.0.0.1 protocol = ws +send_queue_limit = 500 + +[port_grpc] +port = 50051 +ip = 127.0.0.1 +secure_gateway = 127.0.0.1 #[port_ws_public] #port = 6005 #ip = 127.0.0.1 #protocol = wss +#send_queue_limit = 500 #------------------------------------------------------------------------------- -[node_size] -medium - # This is primary persistent datastore for rippled. This includes transaction # metadata, account states, and ledger headers. Helpful information can be -# found here: https://ripple.com/wiki/NodeBackEnd -# delete old ledgers while maintaining at least 2000. Do not require an -# external administrative command to initiate deletion. +# found at https://xrpl.org/capacity-planning.html#node-db-type +# type=NuDB is recommended for non-validators with fast SSDs. Validators or +# slow / spinning disks should use RocksDB. Caution: Spinning disks are +# not recommended. They do not perform well enough to consistently remain +# synced to the network. +# online_delete=512 is recommended to delete old ledgers while maintaining at +# least 512. +# advisory_delete=0 allows the online delete process to run automatically +# when the node has approximately two times the "online_delete" value of +# ledgers. No external administrative command is required to initiate +# deletion. [node_db] -type=RocksDB -path=/var/lib/rippled/db/rocksdb -open_files=2000 -filter_bits=12 -cache_mb=256 -file_size_mb=8 -file_size_mult=2 -online_delete=2000 +type=NuDB +path=/var/lib/rippled/db/nudb +online_delete=512 advisory_delete=0 -# This is the persistent datastore for shards. It is important for the health -# of the ripple network that rippled operators shard as much as practical. -# NuDB requires SSD storage. Helpful information can be found here -# https://ripple.com/build/history-sharding -#[shard_db] -#path=/var/lib/rippled/db/shards/nudb -#max_size_gb=500 - [database_path] /var/lib/rippled/db + # This needs to be an absolute directory reference, not a relative one. # Modify this value as required. [debug_logfile] /var/log/rippled/debug.log -[sntp_servers] -time.windows.com -time.apple.com -time.nist.gov -pool.ntp.org - -# To use the XRP test network (see https://ripple.com/build/xrp-test-net/), +# To use the XRP test network +# (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), # use the following [ips] section: # [ips] # r.altnet.rippletest.net 51235 diff --git a/cfg/validators-example.txt b/cfg/validators-example.txt index 86a1de99cc4..df9757caba5 100644 --- a/cfg/validators-example.txt +++ b/cfg/validators-example.txt @@ -1,12 +1,11 @@ # # Default validators.txt # -# A list of domains to bootstrap a nodes UNLs or for clients to indirectly -# locate IPs to contact the Ripple network. +# This file is located in the same folder as your rippled.cfg file +# and defines which validators your server trusts not to collude. # -# This file is UTF-8 with Dos, UNIX, or Mac style end of lines. +# This file is UTF-8 with DOS, UNIX, or Mac style line endings. # Blank lines and lines starting with a '#' are ignored. -# All other lines should be hankos or domain names. # # # @@ -25,11 +24,9 @@ # # List of URIs serving lists of recommended validators. # -# The latest list of recommended validator sites can be -# obtained from https://ripple.com/ripple.txt -# # Examples: # https://vl.ripple.com +# https://vl.xrplf.org # http://127.0.0.1:8000 # file:///etc/opt/ripple/vl.txt # @@ -41,13 +38,9 @@ # publisher key. # Validator list keys should be hex-encoded. # -# The latest list of recommended validator keys can be -# obtained from https://ripple.com/ripple.txt -# # Examples: -# ed499d732bded01504a7407c224412ef550cc1ade638a4de4eb88af7c36cb8b282 -# 0202d3f36a801349f3be534e3f64cfa77dede6e1b6310a0b48f40f20f955cec945 -# 02dd8b7075f64d77d9d2bdb88da364f29fcd975f9ea6f21894abcc7564efda8054 +# ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734 +# ED307A760EE34F2D0CAA103377B1969117C38B8AA0AA1E2A24DAC1F32FC97087ED # # The default validator list publishers that the rippled instance @@ -61,11 +54,15 @@ [validator_list_sites] https://vl.ripple.com +https://unl.xrplf.org [validator_list_keys] +#vl.ripple.com ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734 +#unl.xrplf.org +ED42AEC58B701EEBB77356FFFEC26F83C1F0407263530F068C7C73D392C7E06FD1 -# To use the XRP test network (see https://ripple.com/build/xrp-test-net/), +# To use the test network (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), # use the following configuration instead: # # [validator_list_sites] @@ -73,3 +70,21 @@ ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734 # # [validator_list_keys] # ED264807102805220DA0F312E71FC2C69E1552C9C5790F6C25E3729DEB573D5860 + + +# [validator_list_threshold] +# +# Minimum number of validator lists on which a validator must be listed in +# order to be used. +# +# This can be set explicitly to any positive integer number not greater than +# the size of [validator_list_keys]. If it is not set, or set to 0, the +# value will be calculated at startup from the size of [validator_list_keys], +# where the calculation is: +# +# threshold = size(validator_list_keys) < 3 +# ? 1 +# : floor(size(validator_list_keys) / 2) + 1 + +[validator_list_threshold] +0 diff --git a/cmake/CMakeFuncs.cmake b/cmake/CMakeFuncs.cmake new file mode 100644 index 00000000000..a4c66a120dd --- /dev/null +++ b/cmake/CMakeFuncs.cmake @@ -0,0 +1,48 @@ +macro(group_sources_in source_dir curdir) + file(GLOB children RELATIVE ${source_dir}/${curdir} + ${source_dir}/${curdir}/*) + foreach (child ${children}) + if (IS_DIRECTORY ${source_dir}/${curdir}/${child}) + group_sources_in(${source_dir} ${curdir}/${child}) + else() + string(REPLACE "/" "\\" groupname ${curdir}) + source_group(${groupname} FILES + ${source_dir}/${curdir}/${child}) + endif() + endforeach() +endmacro() + +macro(group_sources curdir) + group_sources_in(${PROJECT_SOURCE_DIR} ${curdir}) +endmacro() + +macro (exclude_from_default target_) + set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_ALL ON) + set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON) +endmacro () + +macro (exclude_if_included target_) + get_directory_property(has_parent PARENT_DIRECTORY) + if (has_parent) + exclude_from_default (${target_}) + endif () +endmacro () + +find_package(Git) + +function (git_branch branch_val) + if (NOT GIT_FOUND) + return () + endif () + set (_branch "") + execute_process (COMMAND ${GIT_EXECUTABLE} "rev-parse" "--abbrev-ref" "HEAD" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE _git_exit_code + OUTPUT_VARIABLE _temp_branch + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + if (_git_exit_code EQUAL 0) + set (_branch ${_temp_branch}) + endif () + set (${branch_val} "${_branch}" PARENT_SCOPE) +endfunction () diff --git a/cmake/CodeCoverage.cmake b/cmake/CodeCoverage.cmake new file mode 100644 index 00000000000..323303c92dc --- /dev/null +++ b/cmake/CodeCoverage.cmake @@ -0,0 +1,453 @@ +# Copyright (c) 2012 - 2017, Lars Bilke +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# CHANGES: +# +# 2012-01-31, Lars Bilke +# - Enable Code Coverage +# +# 2013-09-17, Joakim Söderberg +# - Added support for Clang. +# - Some additional usage instructions. +# +# 2016-02-03, Lars Bilke +# - Refactored functions to use named parameters +# +# 2017-06-02, Lars Bilke +# - Merged with modified version from github.com/ufz/ogs +# +# 2019-05-06, Anatolii Kurotych +# - Remove unnecessary --coverage flag +# +# 2019-12-13, FeRD (Frank Dana) +# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor +# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments. +# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY +# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list +# - Set lcov basedir with -b argument +# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be +# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().) +# - Delete output dir, .info file on 'make clean' +# - Remove Python detection, since version mismatches will break gcovr +# - Minor cleanup (lowercase function names, update examples...) +# +# 2019-12-19, FeRD (Frank Dana) +# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets +# +# 2020-01-19, Bob Apthorpe +# - Added gfortran support +# +# 2020-02-17, FeRD (Frank Dana) +# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters +# in EXCLUDEs, and remove manual escaping from gcovr targets +# +# 2021-01-19, Robin Mueller +# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run +# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional +# flags to the gcovr command +# +# 2020-05-04, Mihchael Davis +# - Add -fprofile-abs-path to make gcno files contain absolute paths +# - Fix BASE_DIRECTORY not working when defined +# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines +# +# 2021-05-10, Martin Stump +# - Check if the generator is multi-config before warning about non-Debug builds +# +# 2022-02-22, Marko Wehle +# - Change gcovr output from -o for --xml and --html output respectively. +# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt". +# +# 2022-09-28, Sebastian Mueller +# - fix append_coverage_compiler_flags_to_target to correctly add flags +# - replace "-fprofile-arcs -ftest-coverage" with "--coverage" (equivalent) +# +# 2024-01-04, Bronek Kozicki +# - remove setup_target_for_coverage_lcov (slow) and setup_target_for_coverage_fastcov (no support for Clang) +# - fix Clang support by adding find_program( ... llvm-cov ) +# - add Apple Clang support by adding execute_process( COMMAND xcrun -f llvm-cov ... ) +# - add CODE_COVERAGE_GCOV_TOOL to explicitly select gcov tool and disable find_program +# - replace both functions setup_target_for_coverage_gcovr_* with a single setup_target_for_coverage_gcovr +# - add support for all gcovr output formats +# +# 2024-04-03, Bronek Kozicki +# - add support for output formats: jacoco, clover, lcov +# +# USAGE: +# +# 1. Copy this file into your cmake modules path. +# +# 2. Add the following line to your CMakeLists.txt (best inside an if-condition +# using a CMake option() to enable it just optionally): +# include(CodeCoverage) +# +# 3. Append necessary compiler flags for all supported source files: +# append_coverage_compiler_flags() +# Or for specific target: +# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME) +# +# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og +# +# 4. If you need to exclude additional directories from the report, specify them +# using full paths in the COVERAGE_EXCLUDES variable before calling +# setup_target_for_coverage_*(). +# Example: +# set(COVERAGE_EXCLUDES +# '${PROJECT_SOURCE_DIR}/src/dir1/*' +# '/path/to/my/src/dir2/*') +# Or, use the EXCLUDE argument to setup_target_for_coverage_*(). +# Example: +# setup_target_for_coverage_gcovr( +# NAME coverage +# EXECUTABLE testrunner +# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*") +# +# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set +# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR) +# Example: +# set(COVERAGE_EXCLUDES "dir1/*") +# setup_target_for_coverage_gcovr( +# NAME coverage +# EXECUTABLE testrunner +# FORMAT html-details +# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" +# EXCLUDE "dir2/*") +# +# 4.b If you need to pass specific options to gcovr, specify them in +# GCOVR_ADDITIONAL_ARGS variable. +# Example: +# set (GCOVR_ADDITIONAL_ARGS --exclude-throw-branches --exclude-noncode-lines -s) +# setup_target_for_coverage_gcovr( +# NAME coverage +# EXECUTABLE testrunner +# EXCLUDE "src/dir1" "src/dir2") +# +# 5. Use the functions described below to create a custom make target which +# runs your test executable and produces a code coverage report. +# +# 6. Build a Debug build: +# cmake -DCMAKE_BUILD_TYPE=Debug .. +# make +# make my_coverage_target + +include(CMakeParseArguments) + +option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) + +# Check prereqs +find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) + +if(DEFINED CODE_COVERAGE_GCOV_TOOL) + set(GCOV_TOOL "${CODE_COVERAGE_GCOV_TOOL}") +elseif(DEFINED ENV{CODE_COVERAGE_GCOV_TOOL}) + set(GCOV_TOOL "$ENV{CODE_COVERAGE_GCOV_TOOL}") +elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if(APPLE) + execute_process( COMMAND xcrun -f llvm-cov + OUTPUT_VARIABLE LLVMCOV_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + else() + find_program( LLVMCOV_PATH llvm-cov ) + endif() + if(LLVMCOV_PATH) + set(GCOV_TOOL "${LLVMCOV_PATH} gcov") + endif() +elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + find_program( GCOV_PATH gcov ) + set(GCOV_TOOL "${GCOV_PATH}") +endif() + +# Check supported compiler (Clang, GNU and Flang) +get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(LANG ${LANGUAGES}) + if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3) + message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") + endif() + elseif(NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU" + AND NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(LLVM)?[Ff]lang") + message(FATAL_ERROR "Compiler is not GNU or Flang! Aborting...") + endif() +endforeach() + +set(COVERAGE_COMPILER_FLAGS "-g --coverage" + CACHE INTERNAL "") +if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path) + if(HAVE_cxx_fprofile_abs_path) + set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") + endif() + include(CheckCCompilerFlag) + check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path) + if(HAVE_c_fprofile_abs_path) + set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") + endif() +endif() + +set(CMAKE_Fortran_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the Fortran compiler during coverage builds." + FORCE ) +set(CMAKE_CXX_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C++ compiler during coverage builds." + FORCE ) +set(CMAKE_C_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C compiler during coverage builds." + FORCE ) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used for linking binaries during coverage builds." + FORCE ) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used by the shared libraries linker during coverage builds." + FORCE ) +mark_as_advanced( + CMAKE_Fortran_FLAGS_COVERAGE + CMAKE_CXX_FLAGS_COVERAGE + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) + +get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)) + message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") +endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + link_libraries(gcov) +endif() + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_gcovr( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# FORMAT "cobertura" # Output format, one of: +# # xml cobertura sonarqube jacoco clover +# # json-summary json-details coveralls csv +# # txt html-single html-nested html-details +# # lcov (xml is an alias to cobertura; +# # if no format is set, defaults to xml) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# ) +# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the +# GCVOR command. +function(setup_target_for_coverage_gcovr) + set(options NONE) + set(oneValueArgs BASE_DIRECTORY NAME FORMAT) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT GCOV_TOOL) + message(FATAL_ERROR "Could not find gcov or llvm-cov tool! Aborting...") + endif() + + if(NOT GCOVR_PATH) + message(FATAL_ERROR "Could not find gcovr tool! Aborting...") + endif() + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + if(NOT DEFINED Coverage_FORMAT) + set(Coverage_FORMAT xml) + endif() + + if("--output" IN_LIST GCOVR_ADDITIONAL_ARGS) + message(FATAL_ERROR "Unsupported --output option detected in GCOVR_ADDITIONAL_ARGS! Aborting...") + else() + if((Coverage_FORMAT STREQUAL "html-details") + OR (Coverage_FORMAT STREQUAL "html-nested")) + set(GCOVR_OUTPUT_FILE ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html) + set(GCOVR_CREATE_FOLDER ${PROJECT_BINARY_DIR}/${Coverage_NAME}) + elseif(Coverage_FORMAT STREQUAL "html-single") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.html) + elseif((Coverage_FORMAT STREQUAL "json-summary") + OR (Coverage_FORMAT STREQUAL "json-details") + OR (Coverage_FORMAT STREQUAL "coveralls")) + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.json) + elseif(Coverage_FORMAT STREQUAL "txt") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.txt) + elseif(Coverage_FORMAT STREQUAL "csv") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.csv) + elseif(Coverage_FORMAT STREQUAL "lcov") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.lcov) + else() + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml) + endif() + endif() + + if((Coverage_FORMAT STREQUAL "cobertura") + OR (Coverage_FORMAT STREQUAL "xml")) + list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura-pretty ) + set(Coverage_FORMAT cobertura) # overwrite xml + elseif(Coverage_FORMAT STREQUAL "sonarqube") + list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "jacoco") + list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco-pretty ) + elseif(Coverage_FORMAT STREQUAL "clover") + list(APPEND GCOVR_ADDITIONAL_ARGS --clover "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --clover-pretty ) + elseif(Coverage_FORMAT STREQUAL "lcov") + list(APPEND GCOVR_ADDITIONAL_ARGS --lcov "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "json-summary") + list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty) + elseif(Coverage_FORMAT STREQUAL "json-details") + list(APPEND GCOVR_ADDITIONAL_ARGS --json "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --json-pretty) + elseif(Coverage_FORMAT STREQUAL "coveralls") + list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls-pretty) + elseif(Coverage_FORMAT STREQUAL "csv") + list(APPEND GCOVR_ADDITIONAL_ARGS --csv "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "txt") + list(APPEND GCOVR_ADDITIONAL_ARGS --txt "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "html-single") + list(APPEND GCOVR_ADDITIONAL_ARGS --html "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --html-self-contained) + elseif(Coverage_FORMAT STREQUAL "html-nested") + list(APPEND GCOVR_ADDITIONAL_ARGS --html-nested "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "html-details") + list(APPEND GCOVR_ADDITIONAL_ARGS --html-details "${GCOVR_OUTPUT_FILE}" ) + else() + message(FATAL_ERROR "Unsupported output style ${Coverage_FORMAT}! Aborting...") + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES GCOVR_EXCLUDES) + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDE_ARGS "") + foreach(EXCLUDE ${GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDE_ARGS "-e") + list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") + endforeach() + + # Set up commands which will be run to generate coverage data + # Run tests + set(GCOVR_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + + # Create folder + if(DEFINED GCOVR_CREATE_FOLDER) + set(GCOVR_FOLDER_CMD + ${CMAKE_COMMAND} -E make_directory ${GCOVR_CREATE_FOLDER}) + else() + set(GCOVR_FOLDER_CMD echo) # dummy + endif() + + # Running gcovr + set(GCOVR_CMD + ${GCOVR_PATH} + --gcov-executable ${GCOV_TOOL} + --gcov-ignore-parse-errors=negative_hits.warn_once_per_file + -r ${BASEDIR} + ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} + --object-directory=${PROJECT_BINARY_DIR} + ) + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + + message(STATUS "Command to run tests: ") + string(REPLACE ";" " " GCOVR_EXEC_TESTS_CMD_SPACED "${GCOVR_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_EXEC_TESTS_CMD_SPACED}") + + if(NOT GCOVR_FOLDER_CMD STREQUAL "echo") + message(STATUS "Command to create a folder: ") + string(REPLACE ";" " " GCOVR_FOLDER_CMD_SPACED "${GCOVR_FOLDER_CMD}") + message(STATUS "${GCOVR_FOLDER_CMD_SPACED}") + endif() + + message(STATUS "Command to generate gcovr coverage data: ") + string(REPLACE ";" " " GCOVR_CMD_SPACED "${GCOVR_CMD}") + message(STATUS "${GCOVR_CMD_SPACED}") + endif() + + add_custom_target(${Coverage_NAME} + COMMAND ${GCOVR_EXEC_TESTS_CMD} + COMMAND ${GCOVR_FOLDER_CMD} + COMMAND ${GCOVR_CMD} + + BYPRODUCTS ${GCOVR_OUTPUT_FILE} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Running gcovr to produce code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Code coverage report saved in ${GCOVR_OUTPUT_FILE} formatted as ${Coverage_FORMAT}" + ) +endfunction() # setup_target_for_coverage_gcovr + +function(append_coverage_compiler_flags) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") +endfunction() # append_coverage_compiler_flags + +# Setup coverage for specific library +function(append_coverage_compiler_flags_to_target name) + separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}") + target_compile_options(${name} PRIVATE ${_flag_list}) + if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + target_link_libraries(${name} PRIVATE gcov) + endif() +endfunction() diff --git a/Builds/CMake/RippleConfig.cmake b/cmake/RippleConfig.cmake similarity index 94% rename from Builds/CMake/RippleConfig.cmake rename to cmake/RippleConfig.cmake index 1091e741e74..445010e915d 100644 --- a/Builds/CMake/RippleConfig.cmake +++ b/cmake/RippleConfig.cmake @@ -15,13 +15,13 @@ endif () find_dependency (Boost 1.70 COMPONENTS chrono + container context coroutine date_time filesystem program_options regex - serialization system thread) #[=========================================================[ @@ -45,8 +45,9 @@ if (static OR APPLE OR MSVC) set (OPENSSL_USE_STATIC_LIBS ON) endif () set (OPENSSL_MSVC_STATIC_RT ON) -find_dependency (OpenSSL 1.0.2 REQUIRED) +find_dependency (OpenSSL 1.1.1 REQUIRED) find_dependency (ZLIB) +find_dependency (date) if (TARGET ZLIB::ZLIB) set_target_properties(OpenSSL::Crypto PROPERTIES INTERFACE_LINK_LIBRARIES ZLIB::ZLIB) diff --git a/Builds/CMake/RippledCompiler.cmake b/cmake/RippledCompiler.cmake similarity index 84% rename from Builds/CMake/RippledCompiler.cmake rename to cmake/RippledCompiler.cmake index 66be2f86299..7485605d950 100644 --- a/Builds/CMake/RippledCompiler.cmake +++ b/cmake/RippledCompiler.cmake @@ -13,7 +13,6 @@ link_libraries (Ripple::common) set_target_properties (common PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_CXX_EXTENSIONS OFF) -target_compile_features (common INTERFACE cxx_std_17) target_compile_definitions (common INTERFACE $<$:DEBUG _DEBUG> @@ -38,6 +37,11 @@ if (MSVC) # /ZI (Edit & Continue debugging information) is incompatible with Gy- string (REPLACE "/ZI" "/Zi" ${var_} "${${var_}}") + + # omit debug info completely under CI (not needed) + if (is_ci) + string (REPLACE "/Zi" " " ${var_} "${${var_}}") + endif () endforeach () target_compile_options (common @@ -103,6 +107,7 @@ else () -Wno-char-subscripts -Wno-format -Wno-unused-local-typedefs + -fstack-protector $<$: -Wno-unused-but-set-variable -Wno-deprecated @@ -115,14 +120,38 @@ else () target_link_libraries (common INTERFACE -rdynamic + $<$:-Wl,-z,relro,-z,now,--build-id> # link to static libc/c++ iff: # * static option set and # * NOT APPLE (AppleClang does not support static libc/c++) and # * NOT san (sanitizers typically don't work with static libc/c++) - $<$,$>,$>>:-static-libstdc++>) + $<$,$>,$>>: + -static-libstdc++ + -static-libgcc + >) +endif () + +# Antithesis instrumentation will only be built and deployed using machines running Linux. +if (voidstar) + if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(FATAL_ERROR "Antithesis instrumentation requires Debug build type, aborting...") + elseif (NOT is_linux) + message(FATAL_ERROR "Antithesis instrumentation requires Linux, aborting...") + elseif (NOT (is_clang AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)) + message(FATAL_ERROR "Antithesis instrumentation requires Clang version 16 or later, aborting...") + endif () endif () -if (use_gold AND is_gcc) +if (use_mold) + # use mold linker if available + execute_process ( + COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=mold -Wl,--version + ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) + if ("${LD_VERSION}" MATCHES "mold") + target_link_libraries (common INTERFACE -fuse-ld=mold) + endif () + unset (LD_VERSION) +elseif (use_gold AND is_gcc) # use gold linker if available execute_process ( COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=gold -Wl,--version @@ -154,9 +183,7 @@ if (use_gold AND is_gcc) $<$>:-Wl,--disable-new-dtags>) endif () unset (LD_VERSION) -endif () - -if (use_lld) +elseif (use_lld) # use lld linker if available execute_process ( COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=lld -Wl,--version @@ -167,6 +194,7 @@ if (use_lld) unset (LD_VERSION) endif() + if (assert) foreach (var_ CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) STRING (REGEX REPLACE "[-/]DNDEBUG" "" ${var_} "${${var_}}") diff --git a/cmake/RippledCore.cmake b/cmake/RippledCore.cmake new file mode 100644 index 00000000000..fc0576872a5 --- /dev/null +++ b/cmake/RippledCore.cmake @@ -0,0 +1,191 @@ +#[===================================================================[ + Exported targets. +#]===================================================================] + +include(target_protobuf_sources) + +# Protocol buffers cannot participate in a unity build, +# because all the generated sources +# define a bunch of `static const` variables with the same names, +# so we just build them as a separate library. +add_library(xrpl.libpb) +set_target_properties(xrpl.libpb PROPERTIES UNITY_BUILD OFF) +target_protobuf_sources(xrpl.libpb xrpl/proto + LANGUAGE cpp + IMPORT_DIRS include/xrpl/proto + PROTOS include/xrpl/proto/ripple.proto +) + +file(GLOB_RECURSE protos "include/xrpl/proto/org/*.proto") +target_protobuf_sources(xrpl.libpb xrpl/proto + LANGUAGE cpp + IMPORT_DIRS include/xrpl/proto + PROTOS "${protos}" +) +target_protobuf_sources(xrpl.libpb xrpl/proto + LANGUAGE grpc + IMPORT_DIRS include/xrpl/proto + PROTOS "${protos}" + PLUGIN protoc-gen-grpc=$ + GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc +) + +target_compile_options(xrpl.libpb + PUBLIC + $<$:-wd4996> + $<$: + --system-header-prefix="google/protobuf" + -Wno-deprecated-dynamic-exception-spec + > + PRIVATE + $<$:-wd4065> + $<$>:-Wno-deprecated-declarations> +) + +target_link_libraries(xrpl.libpb + PUBLIC + protobuf::libprotobuf + gRPC::grpc++ +) + +# TODO: Clean up the number of library targets later. +add_library(xrpl.imports.main INTERFACE) + +target_link_libraries(xrpl.imports.main + INTERFACE + LibArchive::LibArchive + OpenSSL::Crypto + Ripple::boost + Ripple::opts + Ripple::syslibs + absl::random_random + date::date + ed25519::ed25519 + secp256k1::secp256k1 + xrpl.libpb + xxHash::xxhash + $<$:antithesis-sdk-cpp> +) + +include(add_module) +include(target_link_modules) + +# Level 01 +add_module(xrpl beast) +target_link_libraries(xrpl.libxrpl.beast PUBLIC + xrpl.imports.main + xrpl.libpb +) + +# Level 02 +add_module(xrpl basics) +target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast) + +# Level 03 +add_module(xrpl json) +target_link_libraries(xrpl.libxrpl.json PUBLIC xrpl.libxrpl.basics) + +add_module(xrpl crypto) +target_link_libraries(xrpl.libxrpl.crypto PUBLIC xrpl.libxrpl.basics) + +# Level 04 +add_module(xrpl protocol) +target_link_libraries(xrpl.libxrpl.protocol PUBLIC + xrpl.libxrpl.crypto + xrpl.libxrpl.json +) + +# Level 05 +add_module(xrpl resource) +target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol) + +add_module(xrpl server) +target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol) + + +add_library(xrpl.libxrpl) +set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl) + +add_library(xrpl::libxrpl ALIAS xrpl.libxrpl) + +file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/libxrpl/*.cpp" +) +target_sources(xrpl.libxrpl PRIVATE ${sources}) + +target_link_modules(xrpl PUBLIC + basics + beast + crypto + json + protocol + resource + server +) + +# All headers in libxrpl are in modules. +# Uncomment this stanza if you have not yet moved new headers into a module. +# target_include_directories(xrpl.libxrpl +# PRIVATE +# $ +# PUBLIC +# $ +# $) + +if(xrpld) + add_executable(rippled) + if(tests) + target_compile_definitions(rippled PUBLIC ENABLE_TESTS) + endif() + target_include_directories(rippled + PRIVATE + $ + ) + + file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld/*.cpp" + ) + target_sources(rippled PRIVATE ${sources}) + + if(tests) + file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/test/*.cpp" + ) + target_sources(rippled PRIVATE ${sources}) + endif() + + target_link_libraries(rippled + Ripple::boost + Ripple::opts + Ripple::libs + xrpl.libxrpl + ) + exclude_if_included(rippled) + # define a macro for tests that might need to + # be exluded or run differently in CI environment + if(is_ci) + target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI) + endif () + + if(voidstar) + target_compile_options(rippled + PRIVATE + -fsanitize-coverage=trace-pc-guard + ) + # rippled requires access to antithesis-sdk-cpp implementation file + # antithesis_instrumentation.h, which is not exported as INTERFACE + target_include_directories(rippled + PRIVATE + ${CMAKE_SOURCE_DIR}/external/antithesis-sdk + ) + endif() + + # any files that don't play well with unity should be added here + if(tests) + set_source_files_properties( + # these two seem to produce conflicts in beast teardown template methods + src/test/rpc/ValidatorRPC_test.cpp + src/test/ledger/Invariants_test.cpp + PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) + endif() +endif() diff --git a/cmake/RippledCov.cmake b/cmake/RippledCov.cmake new file mode 100644 index 00000000000..3c48bb1c145 --- /dev/null +++ b/cmake/RippledCov.cmake @@ -0,0 +1,38 @@ +#[===================================================================[ + coverage report target +#]===================================================================] + +if(NOT coverage) + message(FATAL_ERROR "Code coverage not enabled! Aborting ...") +endif() + +if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + message(WARNING "Code coverage on Windows is not supported, ignoring 'coverage' flag") + return() +endif() + +include(CodeCoverage) + +# The instructions for these commands come from the `CodeCoverage` module, +# which was copied from https://github.com/bilke/cmake-modules, commit fb7d2a3, +# then locally changed (see CHANGES: section in `CodeCoverage.cmake`) + +set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) +if(NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") + separate_arguments(GCOVR_ADDITIONAL_ARGS) +endif() + +list(APPEND GCOVR_ADDITIONAL_ARGS + --exclude-throw-branches + --exclude-noncode-lines + --exclude-unreachable-branches -s + -j ${coverage_test_parallelism}) + +setup_target_for_coverage_gcovr( + NAME coverage + FORMAT ${coverage_format} + EXECUTABLE rippled + EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log + EXCLUDE "src/test" "include/xrpl/beast/test" "include/xrpl/beast/unit_test" "${CMAKE_BINARY_DIR}/pb-xrpl.libpb" + DEPENDENCIES rippled +) diff --git a/cmake/RippledDocs.cmake b/cmake/RippledDocs.cmake new file mode 100644 index 00000000000..d93bc119c0d --- /dev/null +++ b/cmake/RippledDocs.cmake @@ -0,0 +1,85 @@ +#[===================================================================[ + docs target (optional) +#]===================================================================] + +option(with_docs "Include the docs target?" FALSE) + +if(NOT (with_docs OR only_docs)) + return() +endif() + +find_package(Doxygen) +if(NOT TARGET Doxygen::doxygen) + message(STATUS "doxygen executable not found -- skipping docs target") + return() +endif() + +set(doxygen_output_directory "${CMAKE_BINARY_DIR}/docs") +set(doxygen_include_path "${CMAKE_CURRENT_SOURCE_DIR}/src") +set(doxygen_index_file "${doxygen_output_directory}/html/index.html") +set(doxyfile "${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile") + +file(GLOB_RECURSE doxygen_input + docs/*.md + include/*.h + include/*.cpp + include/*.md + src/*.h + src/*.cpp + src/*.md + Builds/*.md + *.md) +list(APPEND doxygen_input + external/README.md + ) +set(dependencies "${doxygen_input}" "${doxyfile}") + +function(verbose_find_path variable name) + # find_path sets a CACHE variable, so don't try using a "local" variable. + find_path(${variable} "${name}" ${ARGN}) + if(NOT ${variable}) + message(NOTICE "could not find ${name}") + else() + message(STATUS "found ${name}: ${${variable}}/${name}") + endif() +endfunction() + +verbose_find_path(doxygen_plantuml_jar_path plantuml.jar PATH_SUFFIXES share/plantuml) +verbose_find_path(doxygen_dot_path dot) + +# https://en.cppreference.com/w/Cppreference:Archives +# https://stackoverflow.com/questions/60822559/how-to-move-a-file-download-from-configure-step-to-build-step +set(download_script "${CMAKE_BINARY_DIR}/docs/download-cppreference.cmake") +file(WRITE + "${download_script}" + "file(DOWNLOAD \ + http://upload.cppreference.com/mwiki/images/b/b2/html_book_20190607.zip \ + ${CMAKE_BINARY_DIR}/docs/cppreference.zip \ + EXPECTED_HASH MD5=82b3a612d7d35a83e3cb1195a63689ab \ + )\n \ + execute_process( \ + COMMAND \"${CMAKE_COMMAND}\" -E tar -xf cppreference.zip \ + )\n" +) +set(tagfile "${CMAKE_BINARY_DIR}/docs/cppreference-doxygen-web.tag.xml") +add_custom_command( + OUTPUT "${tagfile}" + COMMAND "${CMAKE_COMMAND}" -P "${download_script}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/docs" +) +set(doxygen_tagfiles "${tagfile}=http://en.cppreference.com/w/") + +add_custom_command( + OUTPUT "${doxygen_index_file}" + COMMAND "${CMAKE_COMMAND}" -E env + "DOXYGEN_OUTPUT_DIRECTORY=${doxygen_output_directory}" + "DOXYGEN_INCLUDE_PATH=${doxygen_include_path}" + "DOXYGEN_TAGFILES=${doxygen_tagfiles}" + "DOXYGEN_PLANTUML_JAR_PATH=${doxygen_plantuml_jar_path}" + "DOXYGEN_DOT_PATH=${doxygen_dot_path}" + "${DOXYGEN_EXECUTABLE}" "${doxyfile}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + DEPENDS "${dependencies}" "${tagfile}") +add_custom_target(docs + DEPENDS "${doxygen_index_file}" + SOURCES "${dependencies}") diff --git a/cmake/RippledInstall.cmake b/cmake/RippledInstall.cmake new file mode 100644 index 00000000000..9ce288d7854 --- /dev/null +++ b/cmake/RippledInstall.cmake @@ -0,0 +1,81 @@ +#[===================================================================[ + install stuff +#]===================================================================] + +include(create_symbolic_link) + +install ( + TARGETS + common + opts + ripple_syslibs + ripple_boost + xrpl.imports.main + xrpl.libpb + xrpl.libxrpl.basics + xrpl.libxrpl.beast + xrpl.libxrpl.crypto + xrpl.libxrpl.json + xrpl.libxrpl.protocol + xrpl.libxrpl.resource + xrpl.libxrpl.server + xrpl.libxrpl + antithesis-sdk-cpp + EXPORT RippleExports + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin + INCLUDES DESTINATION include) + +install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) + +install(CODE " + set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\") + include(create_symbolic_link) + create_symbolic_link(xrpl \ + \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple) +") + +install (EXPORT RippleExports + FILE RippleTargets.cmake + NAMESPACE Ripple:: + DESTINATION lib/cmake/ripple) +include (CMakePackageConfigHelpers) +write_basic_package_version_file ( + RippleConfigVersion.cmake + VERSION ${rippled_version} + COMPATIBILITY SameMajorVersion) + +if (is_root_project AND TARGET rippled) + install (TARGETS rippled RUNTIME DESTINATION bin) + set_target_properties(rippled PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON) + # sample configs should not overwrite existing files + # install if-not-exists workaround as suggested by + # https://cmake.org/Bug/view.php?id=12646 + install(CODE " + macro (copy_if_not_exists SRC DEST NEWNAME) + if (NOT EXISTS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\") + file (INSTALL FILE_PERMISSIONS OWNER_READ OWNER_WRITE DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${DEST}\" FILES \"\${SRC}\" RENAME \"\${NEWNAME}\") + else () + message (\"-- Skipping : \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\") + endif () + endmacro() + copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/rippled-example.cfg\" etc rippled.cfg) + copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt) + ") + install(CODE " + set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\") + include(create_symbolic_link) + create_symbolic_link(rippled${suffix} \ + \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix}) + ") +endif () + +install ( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RippleConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/RippleConfigVersion.cmake + DESTINATION lib/cmake/ripple) diff --git a/cmake/RippledInterface.cmake b/cmake/RippledInterface.cmake new file mode 100644 index 00000000000..85e27172712 --- /dev/null +++ b/cmake/RippledInterface.cmake @@ -0,0 +1,101 @@ +#[===================================================================[ + rippled compile options/settings via an interface library +#]===================================================================] + +add_library (opts INTERFACE) +add_library (Ripple::opts ALIAS opts) +target_compile_definitions (opts + INTERFACE + BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS + BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT + BOOST_CONTAINER_FWD_BAD_DEQUE + HAS_UNCAUGHT_EXCEPTIONS=1 + $<$: + BOOST_ASIO_NO_DEPRECATED + BOOST_FILESYSTEM_NO_DEPRECATED + > + $<$>: + BOOST_COROUTINES_NO_DEPRECATION_WARNING + BOOST_BEAST_ALLOW_DEPRECATED + BOOST_FILESYSTEM_DEPRECATED + > + $<$:BEAST_NO_UNIT_TEST_INLINE=1> + $<$:BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES=1> + $<$:RIPPLE_SINGLE_IO_SERVICE_THREAD=1> + $<$:ENABLE_VOIDSTAR>) +target_compile_options (opts + INTERFACE + $<$,$>:-Wsuggest-override> + $<$:-Wno-maybe-uninitialized> + $<$:-fno-omit-frame-pointer> + $<$,$>:-g --coverage -fprofile-abs-path> + $<$,$>:-g --coverage> + $<$:-pg> + $<$,$>:-p>) + +target_link_libraries (opts + INTERFACE + $<$,$>:-g --coverage -fprofile-abs-path> + $<$,$>:-g --coverage> + $<$:-pg> + $<$,$>:-p>) + +if(jemalloc) + find_package(jemalloc REQUIRED) + target_compile_definitions(opts INTERFACE PROFILE_JEMALLOC) + target_link_libraries(opts INTERFACE jemalloc::jemalloc) +endif () + +if (san) + target_compile_options (opts + INTERFACE + # sanitizers recommend minimum of -O1 for reasonable performance + $<$:-O1> + ${SAN_FLAG} + -fno-omit-frame-pointer) + target_compile_definitions (opts + INTERFACE + $<$:SANITIZER=ASAN> + $<$:SANITIZER=TSAN> + $<$:SANITIZER=MSAN> + $<$:SANITIZER=UBSAN>) + target_link_libraries (opts INTERFACE ${SAN_FLAG} ${SAN_LIB}) +endif () + +#[===================================================================[ + rippled transitive library deps via an interface library +#]===================================================================] + +add_library (ripple_syslibs INTERFACE) +add_library (Ripple::syslibs ALIAS ripple_syslibs) +target_link_libraries (ripple_syslibs + INTERFACE + $<$: + legacy_stdio_definitions.lib + Shlwapi + kernel32 + user32 + gdi32 + winspool + comdlg32 + advapi32 + shell32 + ole32 + oleaut32 + uuid + odbc32 + odbccp32 + crypt32 + > + $<$>:dl> + $<$,$>>:rt>) + +if (NOT MSVC) + set (THREADS_PREFER_PTHREAD_FLAG ON) + find_package (Threads) + target_link_libraries (ripple_syslibs INTERFACE Threads::Threads) +endif () + +add_library (ripple_libs INTERFACE) +add_library (Ripple::libs ALIAS ripple_libs) +target_link_libraries (ripple_libs INTERFACE Ripple::syslibs) diff --git a/Builds/CMake/RippledSanity.cmake b/cmake/RippledSanity.cmake similarity index 75% rename from Builds/CMake/RippledSanity.cmake rename to cmake/RippledSanity.cmake index aec1f18e3d3..3dd5fb782fd 100644 --- a/Builds/CMake/RippledSanity.cmake +++ b/cmake/RippledSanity.cmake @@ -2,6 +2,8 @@ convenience variables and sanity checks #]===================================================================] +include(ProcessorCount) + if (NOT ep_procs) ProcessorCount(ep_procs) if (ep_procs GREATER 1) @@ -10,12 +12,7 @@ if (NOT ep_procs) message (STATUS "Using ${ep_procs} cores for ExternalProject builds.") endif () endif () -get_property (is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if (is_multiconfig STREQUAL "NOTFOUND") - if (${CMAKE_GENERATOR} STREQUAL "Xcode" OR ${CMAKE_GENERATOR} MATCHES "^Visual Studio") - set (is_multiconfig TRUE) - endif () -endif () +get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) set (CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) if (NOT is_multiconfig) @@ -39,19 +36,16 @@ endif () if ("${CMAKE_CXX_COMPILER_ID}" MATCHES ".*Clang") # both Clang and AppleClang set (is_clang TRUE) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND - CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) - message (FATAL_ERROR "This project requires clang 5 or later") + CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) + message (FATAL_ERROR "This project requires clang 8 or later") endif () # TODO min AppleClang version check ? elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set (is_gcc TRUE) - if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0) - message (FATAL_ERROR "This project requires GCC 7 or later") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) + message (FATAL_ERROR "This project requires GCC 8 or later") endif () endif () -if (CMAKE_GENERATOR STREQUAL "Xcode") - set (is_xcode TRUE) -endif () if (CMAKE_SYSTEM_NAME STREQUAL "Linux") set (is_linux TRUE) @@ -72,10 +66,8 @@ if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") "directory from ${CMAKE_CURRENT_SOURCE_DIR} and try building in a separate directory.") endif () -if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio" AND - NOT ("${CMAKE_GENERATOR}" MATCHES .*Win64.*)) - message (FATAL_ERROR - "Visual Studio 32-bit build is not supported. Use -G\"${CMAKE_GENERATOR} Win64\"") +if (MSVC AND CMAKE_GENERATOR_PLATFORM STREQUAL "Win32") + message (FATAL_ERROR "Visual Studio 32-bit build is not supported.") endif () if (NOT CMAKE_SIZEOF_VOID_P EQUAL 8) diff --git a/cmake/RippledSettings.cmake b/cmake/RippledSettings.cmake new file mode 100644 index 00000000000..58877e1885b --- /dev/null +++ b/cmake/RippledSettings.cmake @@ -0,0 +1,134 @@ +#[===================================================================[ + declare user options/settings +#]===================================================================] + +include(ProcessorCount) + +ProcessorCount(PROCESSOR_COUNT) + +option(assert "Enables asserts, even in release builds" OFF) + +option(xrpld "Build xrpld" ON) + +option(tests "Build tests" ON) + +option(unity "Creates a build using UNITY support in cmake. This is the default" ON) +if(unity) + if(NOT is_ci) + set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") + endif() + set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build") +endif() +if(is_clang AND is_linux) + option(voidstar "Enable Antithesis instrumentation." OFF) +endif() +if(is_gcc OR is_clang) + option(coverage "Generates coverage info." OFF) + option(profile "Add profiling flags" OFF) + set(coverage_test_parallelism "${PROCESSOR_COUNT}" CACHE STRING + "Unit tests parallelism for the purpose of coverage report.") + set(coverage_format "html-details" CACHE STRING + "Output format of the coverage report.") + set(coverage_extra_args "" CACHE STRING + "Additional arguments to pass to gcovr.") + set(coverage_test "" CACHE STRING + "On gcc & clang, the specific unit test(s) to run for coverage. Default is all tests.") + if(coverage_test AND NOT coverage) + set(coverage ON CACHE BOOL "gcc/clang only" FORCE) + endif() + option(wextra "compile with extra gcc/clang warnings enabled" ON) +else() + set(profile OFF CACHE BOOL "gcc/clang only" FORCE) + set(coverage OFF CACHE BOOL "gcc/clang only" FORCE) + set(wextra OFF CACHE BOOL "gcc/clang only" FORCE) +endif() +if(is_linux) + option(BUILD_SHARED_LIBS "build shared ripple libraries" OFF) + option(static "link protobuf, openssl, libc++, and boost statically" ON) + option(perf "Enables flags that assist with perf recording" OFF) + option(use_gold "enables detection of gold (binutils) linker" ON) + option(use_mold "enables detection of mold (binutils) linker" ON) +else() + # we are not ready to allow shared-libs on windows because it would require + # export declarations. On macos it's more feasible, but static openssl + # produces odd linker errors, thus we disable shared lib builds for now. + set(BUILD_SHARED_LIBS OFF CACHE BOOL "build shared ripple libraries - OFF for win/macos" FORCE) + set(static ON CACHE BOOL "static link, linux only. ON for WIN/macos" FORCE) + set(perf OFF CACHE BOOL "perf flags, linux only" FORCE) + set(use_gold OFF CACHE BOOL "gold linker, linux only" FORCE) + set(use_mold OFF CACHE BOOL "mold linker, linux only" FORCE) +endif() +if(is_clang) + option(use_lld "enables detection of lld linker" ON) +else() + set(use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE) +endif() +option(jemalloc "Enables jemalloc for heap profiling" OFF) +option(werr "treat warnings as errors" OFF) +option(local_protobuf + "Force a local build of protobuf instead of looking for an installed version." OFF) +option(local_grpc + "Force a local build of gRPC instead of looking for an installed version." OFF) + +# this one is a string and therefore can't be an option +set(san "" CACHE STRING "On gcc & clang, add sanitizer instrumentation") +set_property(CACHE san PROPERTY STRINGS ";undefined;memory;address;thread") +if(san) + string(TOLOWER ${san} san) + set(SAN_FLAG "-fsanitize=${san}") + set(SAN_LIB "") + if(is_gcc) + if(san STREQUAL "address") + set(SAN_LIB "asan") + elseif(san STREQUAL "thread") + set(SAN_LIB "tsan") + elseif(san STREQUAL "memory") + set(SAN_LIB "msan") + elseif(san STREQUAL "undefined") + set(SAN_LIB "ubsan") + endif() + endif() + set(_saved_CRL ${CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_LIBRARIES "${SAN_FLAG};${SAN_LIB}") + check_cxx_compiler_flag(${SAN_FLAG} COMPILER_SUPPORTS_SAN) + set(CMAKE_REQUIRED_LIBRARIES ${_saved_CRL}) + if(NOT COMPILER_SUPPORTS_SAN) + message(FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler") + endif() +endif() +set(container_label "" CACHE STRING "tag to use for package building containers") +option(packages_only + "ONLY generate package building targets. This is special use-case and almost \ + certainly not what you want. Use with caution as you won't be able to build \ + any compiled targets locally." OFF) +option(have_package_container + "Sometimes you already have the tagged container you want to use for package \ + building and you don't want docker to rebuild it. This flag will detach the \ + dependency of the package build from the container build. It's an advanced \ + use case and most likely you should not be touching this flag." OFF) + +# the remaining options are obscure and rarely used +option(beast_no_unit_test_inline + "Prevents unit test definitions from being inserted into global table" + OFF) +option(single_io_service_thread + "Restricts the number of threads calling io_service::run to one. \ + This can be useful when debugging." + OFF) +option(boost_show_deprecated + "Allow boost to fail on deprecated usage. Only useful if you're trying\ + to find deprecated calls." + OFF) +option(beast_hashers + "Use local implementations for sha/ripemd hashes (experimental, not recommended)" + OFF) + +if(WIN32) + option(beast_disable_autolink "Disables autolinking of system libraries on WIN32" OFF) +else() + set(beast_disable_autolink OFF CACHE BOOL "WIN32 only" FORCE) +endif() +if(coverage) + message(STATUS "coverage build requested - forcing Debug build") + set(CMAKE_BUILD_TYPE Debug CACHE STRING "build type" FORCE) +endif() diff --git a/cmake/RippledValidatorKeys.cmake b/cmake/RippledValidatorKeys.cmake new file mode 100644 index 00000000000..b6760ca496b --- /dev/null +++ b/cmake/RippledValidatorKeys.cmake @@ -0,0 +1,22 @@ +option (validator_keys "Enables building of validator-keys-tool as a separate target (imported via FetchContent)" OFF) + +if (validator_keys) + git_branch (current_branch) + # default to tracking VK master branch unless we are on release + if (NOT (current_branch STREQUAL "release")) + set (current_branch "master") + endif () + message (STATUS "tracking ValidatorKeys branch: ${current_branch}") + + FetchContent_Declare ( + validator_keys_src + GIT_REPOSITORY https://github.com/ripple/validator-keys-tool.git + GIT_TAG "${current_branch}" + ) + FetchContent_GetProperties (validator_keys_src) + if (NOT validator_keys_src_POPULATED) + message (STATUS "Pausing to download ValidatorKeys...") + FetchContent_Populate (validator_keys_src) + endif () + add_subdirectory (${validator_keys_src_SOURCE_DIR} ${CMAKE_BINARY_DIR}/validator-keys) +endif () diff --git a/cmake/RippledVersion.cmake b/cmake/RippledVersion.cmake new file mode 100644 index 00000000000..fda3cb6ff7b --- /dev/null +++ b/cmake/RippledVersion.cmake @@ -0,0 +1,15 @@ +#[===================================================================[ + read version from source +#]===================================================================] + +file(STRINGS src/libxrpl/protocol/BuildInfo.cpp BUILD_INFO) +foreach(line_ ${BUILD_INFO}) + if(line_ MATCHES "versionString[ ]*=[ ]*\"(.+)\"") + set(rippled_version ${CMAKE_MATCH_1}) + endif() +endforeach() +if(rippled_version) + message(STATUS "rippled version: ${rippled_version}") +else() + message(FATAL_ERROR "unable to determine rippled version") +endif() diff --git a/cmake/add_module.cmake b/cmake/add_module.cmake new file mode 100644 index 00000000000..bcfce1bf600 --- /dev/null +++ b/cmake/add_module.cmake @@ -0,0 +1,37 @@ +include(isolate_headers) + +# Create an OBJECT library target named +# +# ${PROJECT_NAME}.lib${parent}.${name} +# +# with sources in src/lib${parent}/${name} +# and headers in include/${parent}/${name} +# that cannot include headers from other directories in include/ +# unless they come through linked libraries. +# +# add_module(parent a) +# add_module(parent b) +# target_link_libraries(project.libparent.b PUBLIC project.libparent.a) +function(add_module parent name) + set(target ${PROJECT_NAME}.lib${parent}.${name}) + add_library(${target} OBJECT) + file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}/*.cpp" + ) + target_sources(${target} PRIVATE ${sources}) + target_include_directories(${target} PUBLIC + "$" + ) + isolate_headers( + ${target} + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/include/${parent}/${name}" + PUBLIC + ) + isolate_headers( + ${target} + "${CMAKE_CURRENT_SOURCE_DIR}/src" + "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}" + PRIVATE + ) +endfunction() diff --git a/cmake/create_symbolic_link.cmake b/cmake/create_symbolic_link.cmake new file mode 100644 index 00000000000..60fcf2e0b57 --- /dev/null +++ b/cmake/create_symbolic_link.cmake @@ -0,0 +1,20 @@ +# file(CREATE_SYMLINK) only works on Windows with administrator privileges. +# https://stackoverflow.com/a/61244115/618906 +function(create_symbolic_link target link) + if(WIN32) + if(NOT IS_SYMLINK "${link}") + if(NOT IS_ABSOLUTE "${target}") + # Relative links work do not work on Windows. + set(target "${link}/../${target}") + endif() + file(TO_NATIVE_PATH "${target}" target) + file(TO_NATIVE_PATH "${link}" link) + execute_process(COMMAND cmd.exe /c mklink /J "${link}" "${target}") + endif() + else() + file(CREATE_LINK "${target}" "${link}" SYMBOLIC) + endif() + if(NOT IS_SYMLINK "${link}") + message(ERROR "failed to create symlink: <${link}>") + endif() +endfunction() diff --git a/cmake/deps/Boost.cmake b/cmake/deps/Boost.cmake new file mode 100644 index 00000000000..041c2380e12 --- /dev/null +++ b/cmake/deps/Boost.cmake @@ -0,0 +1,53 @@ +find_package(Boost 1.82 REQUIRED + COMPONENTS + chrono + container + context + coroutine + date_time + filesystem + json + program_options + regex + system + thread +) + +add_library(ripple_boost INTERFACE) +add_library(Ripple::boost ALIAS ripple_boost) +if(XCODE) + target_include_directories(ripple_boost BEFORE INTERFACE ${Boost_INCLUDE_DIRS}) + target_compile_options(ripple_boost INTERFACE --system-header-prefix="boost/") +else() + target_include_directories(ripple_boost SYSTEM BEFORE INTERFACE ${Boost_INCLUDE_DIRS}) +endif() + +target_link_libraries(ripple_boost + INTERFACE + Boost::boost + Boost::chrono + Boost::container + Boost::coroutine + Boost::date_time + Boost::filesystem + Boost::json + Boost::program_options + Boost::regex + Boost::system + Boost::thread) +if(Boost_COMPILER) + target_link_libraries(ripple_boost INTERFACE Boost::disable_autolinking) +endif() +if(san AND is_clang) + # TODO: gcc does not support -fsanitize-blacklist...can we do something else + # for gcc ? + if(NOT Boost_INCLUDE_DIRS AND TARGET Boost::headers) + get_target_property(Boost_INCLUDE_DIRS Boost::headers INTERFACE_INCLUDE_DIRECTORIES) + endif() + message(STATUS "Adding [${Boost_INCLUDE_DIRS}] to sanitizer blacklist") + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt "src:${Boost_INCLUDE_DIRS}/*") + target_compile_options(opts + INTERFACE + # ignore boost headers for sanitizing + -fsanitize-blacklist=${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt) +endif() diff --git a/cmake/isolate_headers.cmake b/cmake/isolate_headers.cmake new file mode 100644 index 00000000000..0a5a43a6a28 --- /dev/null +++ b/cmake/isolate_headers.cmake @@ -0,0 +1,48 @@ +include(create_symbolic_link) + +# Consider include directory B nested under prefix A: +# +# /path/to/A/then/to/B/... +# +# Call C the relative path from A to B. +# C is what we want to write in `#include` directives: +# +# #include +# +# Examples, all from the `jobqueue` module: +# +# - Library public headers: +# B = /include/xrpl/jobqueue +# A = /include/ +# C = xrpl/jobqueue +# +# - Library private headers: +# B = /src/libxrpl/jobqueue +# A = /src/ +# C = libxrpl/jobqueue +# +# - Test private headers: +# B = /tests/jobqueue +# A = / +# C = tests/jobqueue +# +# To isolate headers from each other, +# we want to create a symlink Y that points to B, +# within a subdirectory X of the `CMAKE_BINARY_DIR`, +# that has the same relative path C between X and Y, +# and then add X as an include directory of the target, +# sometimes `PUBLIC` and sometimes `PRIVATE`. +# The Cs are all guaranteed to be unique. +# We can guarantee a unique X per target by using +# `${CMAKE_CURRENT_BINARY_DIR}/include/${target}`. +# +# isolate_headers(target A B scope) +function(isolate_headers target A B scope) + file(RELATIVE_PATH C "${A}" "${B}") + set(X "${CMAKE_CURRENT_BINARY_DIR}/modules/${target}") + set(Y "${X}/${C}") + cmake_path(GET Y PARENT_PATH parent) + file(MAKE_DIRECTORY "${parent}") + create_symbolic_link("${B}" "${Y}") + target_include_directories(${target} ${scope} "$") +endfunction() diff --git a/cmake/target_link_modules.cmake b/cmake/target_link_modules.cmake new file mode 100644 index 00000000000..acbf67903a1 --- /dev/null +++ b/cmake/target_link_modules.cmake @@ -0,0 +1,24 @@ +# Link a library to its modules (see: `add_module`) +# and remove the module sources from the library's sources. +# +# add_module(parent a) +# add_module(parent b) +# target_link_libraries(project.libparent.b PUBLIC project.libparent.a) +# add_library(project.libparent) +# target_link_modules(parent PUBLIC a b) +function(target_link_modules parent scope) + set(library ${PROJECT_NAME}.lib${parent}) + foreach(name ${ARGN}) + set(module ${library}.${name}) + get_target_property(sources ${library} SOURCES) + list(LENGTH sources before) + get_target_property(dupes ${module} SOURCES) + list(LENGTH dupes expected) + list(REMOVE_ITEM sources ${dupes}) + list(LENGTH sources after) + math(EXPR actual "${before} - ${after}") + message(STATUS "${module} with ${expected} sources took ${actual} sources from ${library}") + set_target_properties(${library} PROPERTIES SOURCES "${sources}") + target_link_libraries(${library} ${scope} ${module}) + endforeach() +endfunction() diff --git a/cmake/target_protobuf_sources.cmake b/cmake/target_protobuf_sources.cmake new file mode 100644 index 00000000000..da2ef6dc9a2 --- /dev/null +++ b/cmake/target_protobuf_sources.cmake @@ -0,0 +1,62 @@ +find_package(Protobuf REQUIRED) + +# .proto files import each other like this: +# +# import "path/to/file.proto"; +# +# For the protobuf compiler to find these imports, +# the parent directory of "path" must be in the import path. +# +# When generating C++, +# it turns into an include statement like this: +# +# #include "path/to/file.pb.h" +# +# and the header is generated at a path relative to the output directory +# that matches the given .proto path relative to the source directory +# minus the first matching prefix on the import path. +# +# In other words, a file `include/package/path/to/file.proto` +# with import path [`include/package`, `include`] +# will generate files `output/path/to/file.pb.{h,cc}` +# with includes like `#include "path/to/file.pb.h". +# +# During build, the generated files can find each other if the output +# directory is an include directory, but we want to install that directory +# under our package's include directory (`include/package`), not as a sibling. +# After install, they can find each other if that subdirectory is an include +# directory. + +# Add protocol buffer sources to an existing library target. +# target: +# The name of the library target. +# prefix: +# The install prefix for headers relative to `CMAKE_INSTALL_INCLUDEDIR`. +# This prefix should appear at the start of all your consumer includes. +# ARGN: +# A list of .proto files. +function(target_protobuf_sources target prefix) + set(dir "${CMAKE_CURRENT_BINARY_DIR}/pb-${target}") + file(MAKE_DIRECTORY "${dir}/${prefix}") + + protobuf_generate( + TARGET ${target} + PROTOC_OUT_DIR "${dir}/${prefix}" + "${ARGN}" + ) + target_include_directories(${target} SYSTEM PUBLIC + # Allows #include used by consumer files. + $ + # Allows #include "path/to/file.proto" used by generated files. + $ + # Allows #include used by consumer files. + $ + # Allows #include "path/to/file.proto" used by generated files. + $ + ) + install( + DIRECTORY ${dir}/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h" + ) +endfunction() diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 00000000000..a42c116ca2c --- /dev/null +++ b/conanfile.py @@ -0,0 +1,178 @@ +from conan import ConanFile +from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout +import re + +class Xrpl(ConanFile): + name = 'xrpl' + + license = 'ISC' + author = 'John Freeman ' + url = 'https://github.com/xrplf/rippled' + description = 'The XRP Ledger' + settings = 'os', 'compiler', 'build_type', 'arch' + options = { + 'assertions': [True, False], + 'coverage': [True, False], + 'fPIC': [True, False], + 'jemalloc': [True, False], + 'rocksdb': [True, False], + 'shared': [True, False], + 'static': [True, False], + 'tests': [True, False], + 'unity': [True, False], + 'xrpld': [True, False], + } + + requires = [ + 'date/3.0.3', + 'grpc/1.50.1', + 'libarchive/3.7.6', + 'nudb/2.0.8', + 'openssl/1.1.1v', + 'soci/4.0.3', + 'xxhash/0.8.2', + 'zlib/1.3.1', + ] + + tool_requires = [ + 'protobuf/3.21.9', + ] + + default_options = { + 'assertions': False, + 'coverage': False, + 'fPIC': True, + 'jemalloc': False, + 'rocksdb': True, + 'shared': False, + 'static': True, + 'tests': False, + 'unity': False, + 'xrpld': False, + + 'date/*:header_only': True, + 'grpc/*:shared': False, + 'grpc/*:secure': True, + 'libarchive/*:shared': False, + 'libarchive/*:with_acl': False, + 'libarchive/*:with_bzip2': False, + 'libarchive/*:with_cng': False, + 'libarchive/*:with_expat': False, + 'libarchive/*:with_iconv': False, + 'libarchive/*:with_libxml2': False, + 'libarchive/*:with_lz4': True, + 'libarchive/*:with_lzma': False, + 'libarchive/*:with_lzo': False, + 'libarchive/*:with_nettle': False, + 'libarchive/*:with_openssl': False, + 'libarchive/*:with_pcreposix': False, + 'libarchive/*:with_xattr': False, + 'libarchive/*:with_zlib': False, + 'lz4/*:shared': False, + 'openssl/*:shared': False, + 'protobuf/*:shared': False, + 'protobuf/*:with_zlib': True, + 'rocksdb/*:enable_sse': False, + 'rocksdb/*:lite': False, + 'rocksdb/*:shared': False, + 'rocksdb/*:use_rtti': True, + 'rocksdb/*:with_jemalloc': False, + 'rocksdb/*:with_lz4': True, + 'rocksdb/*:with_snappy': True, + 'snappy/*:shared': False, + 'soci/*:shared': False, + 'soci/*:with_sqlite3': True, + 'soci/*:with_boost': True, + 'xxhash/*:shared': False, + } + + def set_version(self): + path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp' + regex = r'versionString\s?=\s?\"(.*)\"' + with open(path, 'r') as file: + matches = (re.search(regex, line) for line in file) + match = next(m for m in matches if m) + self.version = match.group(1) + + def configure(self): + if self.settings.compiler == 'apple-clang': + self.options['boost'].visibility = 'global' + + def requirements(self): + self.requires('boost/1.83.0', force=True) + self.requires('lz4/1.10.0', force=True) + self.requires('protobuf/3.21.9', force=True) + self.requires('sqlite3/3.47.0', force=True) + if self.options.jemalloc: + self.requires('jemalloc/5.3.0') + if self.options.rocksdb: + self.requires('rocksdb/9.7.3') + + exports_sources = ( + 'CMakeLists.txt', + 'bin/getRippledInfo', + 'cfg/*', + 'cmake/*', + 'external/*', + 'include/*', + 'src/*', + ) + + def layout(self): + cmake_layout(self) + # Fix this setting to follow the default introduced in Conan 1.48 + # to align with our build instructions. + self.folders.generators = 'build/generators' + + generators = 'CMakeDeps' + def generate(self): + tc = CMakeToolchain(self) + tc.variables['tests'] = self.options.tests + tc.variables['assert'] = self.options.assertions + tc.variables['coverage'] = self.options.coverage + tc.variables['jemalloc'] = self.options.jemalloc + tc.variables['rocksdb'] = self.options.rocksdb + tc.variables['BUILD_SHARED_LIBS'] = self.options.shared + tc.variables['static'] = self.options.static + tc.variables['unity'] = self.options.unity + tc.variables['xrpld'] = self.options.xrpld + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.verbose = True + cmake.configure() + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.verbose = True + cmake.install() + + def package_info(self): + libxrpl = self.cpp_info.components['libxrpl'] + libxrpl.libs = [ + 'xrpl', + 'xrpl.libpb', + 'ed25519', + 'secp256k1', + ] + # TODO: Fix the protobufs to include each other relative to + # `include/`, not `include/ripple/proto/`. + libxrpl.includedirs = ['include', 'include/ripple/proto'] + libxrpl.requires = [ + 'boost::boost', + 'date::date', + 'grpc::grpc++', + 'libarchive::libarchive', + 'lz4::lz4', + 'nudb::nudb', + 'openssl::crypto', + 'protobuf::libprotobuf', + 'soci::soci', + 'sqlite3::sqlite', + 'xxhash::xxhash', + 'zlib::zlib', + ] + if self.options.rocksdb: + libxrpl.requires.append('rocksdb::librocksdb') diff --git a/docs/0001-negative-unl/README.md b/docs/0001-negative-unl/README.md new file mode 100644 index 00000000000..606b30aab15 --- /dev/null +++ b/docs/0001-negative-unl/README.md @@ -0,0 +1,597 @@ +# Negative UNL Engineering Spec + +## The Problem Statement + +The moment-to-moment health of the XRP Ledger network depends on the health and +connectivity of a small number of computers (nodes). The most important nodes +are validators, specifically ones listed on the unique node list +([UNL](#Question-What-are-UNLs)). Ripple publishes a recommended UNL that most +network nodes use to determine which peers in the network are trusted. Although +most validators use the same list, they are not required to. The XRP Ledger +network progresses to the next ledger when enough validators reach agreement +(above the minimum quorum of 80%) about what transactions to include in the next +ledger. + +As an example, if there are 10 validators on the UNL, at least 8 validators have +to agree with the latest ledger for it to become validated. But what if enough +of those validators are offline to drop the network below the 80% quorum? The +XRP Ledger network favors safety/correctness over advancing the ledger. Which +means if enough validators are offline, the network will not be able to validate +ledgers. + +Unfortunately validators can go offline at any time for many different reasons. +Power outages, network connectivity issues, and hardware failures are just a few +scenarios where a validator would appear "offline". Given that most of these +events are temporary, it would make sense to temporarily remove that validator +from the UNL. But the UNL is updated infrequently and not every node uses the +same UNL. So instead of removing the unreliable validator from the Ripple +recommended UNL, we can create a second negative UNL which is stored directly on +the ledger (so the entire network has the same view). This will help the network +see which validators are **currently** unreliable, and adjust their quorum +calculation accordingly. + +*Improving the liveness of the network is the main motivation for the negative UNL.* + +### Targeted Faults + +In order to determine which validators are unreliable, we need clearly define +what kind of faults to measure and analyze. We want to deal with the faults we +frequently observe in the production network. Hence we will only monitor for +validators that do not reliably respond to network messages or send out +validations disagreeing with the locally generated validations. We will not +target other byzantine faults. + +To track whether or not a validator is responding to the network, we could +monitor them with a “heartbeat” protocol. Instead of creating a new heartbeat +protocol, we can leverage some existing protocol messages to mimic the +heartbeat. We picked validation messages because validators should send one and +only one validation message per ledger. In addition, we only count the +validation messages that agree with the local node's validations. + +With the negative UNL, the network could keep making forward progress safely +even if the number of remaining validators gets to 60%. Say we have a network +with 10 validators on the UNL and everything is operating correctly. The quorum +required for this network would be 8 (80% of 10). When validators fail, the +quorum required would be as low as 6 (60% of 10), which is the absolute +***minimum quorum***. We need the absolute minimum quorum to be strictly greater +than 50% of the original UNL so that there cannot be two partitions of +well-behaved nodes headed in different directions. We arbitrarily choose 60% as +the minimum quorum to give a margin of safety. + +Consider these events in the absence of negative UNL: +1. 1:00pm - validator1 fails, votes vs. quorum: 9 >= 8, we have quorum +1. 3:00pm - validator2 fails, votes vs. quorum: 8 >= 8, we have quorum +1. 5:00pm - validator3 fails, votes vs. quorum: 7 < 8, we don’t have quorum + * **network cannot validate new ledgers with 3 failed validators** + +We're below 80% agreement, so new ledgers cannot be validated. This is how the +XRP Ledger operates today, but if the negative UNL was enabled, the events would +happen as follows. (Please note that the events below are from a simplified +version of our protocol.) + +1. 1:00pm - validator1 fails, votes vs. quorum: 9 >= 8, we have quorum +1. 1:40pm - network adds validator1 to negative UNL, quorum changes to ceil(9 * 0.8), or 8 +1. 3:00pm - validator2 fails, votes vs. quorum: 8 >= 8, we have quorum +1. 3:40pm - network adds validator2 to negative UNL, quorum changes to ceil(8 * 0.8), or 7 +1. 5:00pm - validator3 fails, votes vs. quorum: 7 >= 7, we have quorum +1. 5:40pm - network adds validator3 to negative UNL, quorum changes to ceil(7 * 0.8), or 6 +1. 7:00pm - validator4 fails, votes vs. quorum: 6 >= 6, we have quorum + * **network can still validate new ledgers with 4 failed validators** + +## External Interactions + +### Message Format Changes +This proposal will: +1. add a new pseudo-transaction type +1. add the negative UNL to the ledger data structure. + +Any tools or systems that rely on the format of this data will have to be +updated. + +### Amendment +This feature **will** need an amendment to activate. + +## Design + +This section discusses the following topics about the Negative UNL design: + +* [Negative UNL protocol overview](#Negative-UNL-Protocol-Overview) +* [Validator reliability measurement](#Validator-Reliability-Measurement) +* [Format Changes](#Format-Changes) +* [Negative UNL maintenance](#Negative-UNL-Maintenance) +* [Quorum size calculation](#Quorum-Size-Calculation) +* [Filter validation messages](#Filter-Validation-Messages) +* [High level sequence diagram of code + changes](#High-Level-Sequence-Diagram-of-Code-Changes) + +### Negative UNL Protocol Overview + +Every ledger stores a list of zero or more unreliable validators. Updates to the +list must be approved by the validators using the consensus mechanism that +validators use to agree on the set of transactions. The list is used only when +checking if a ledger is fully validated. If a validator V is in the list, nodes +with V in their UNL adjust the quorum and V’s validation message is not counted +when verifying if a ledger is fully validated. V’s flow of messages and network +interactions, however, will remain the same. + +We define the ***effective UNL** = original UNL - negative UNL*, and the +***effective quorum*** as the quorum of the *effective UNL*. And we set +*effective quorum = Ceiling(80% * effective UNL)*. + +### Validator Reliability Measurement + +A node only measures the reliability of validators on its own UNL, and only +proposes based on local observations. There are many metrics that a node can +measure about its validators, but we have chosen ledger validation messages. +This is because every validator shall send one and only one signed validation +message per ledger. This keeps the measurement simple and removes +timing/clock-sync issues. A node will measure the percentage of agreeing +validation messages (*PAV*) received from each validator on the node's UNL. Note +that the node will only count the validation messages that agree with its own +validations. + +We define the **PAV** as the **P**ercentage of **A**greed **V**alidation +messages received for the last N ledgers, where N = 256 by default. + +When the PAV drops below the ***low-water mark***, the validator is considered +unreliable, and is a candidate to be disabled by being added to the negative +UNL. A validator must have a PAV higher than the ***high-water mark*** to be +re-enabled. The validator is re-enabled by removing it from the negative UNL. In +the implementation, we plan to set the low-water mark as 50% and the high-water +mark as 80%. + +### Format Changes + +The negative UNL component in a ledger contains three fields. +* ***NegativeUNL***: The current negative UNL, a list of unreliable validators. +* ***ToDisable***: The validator to be added to the negative UNL on the next + flag ledger. +* ***ToReEnable***: The validator to be removed from the negative UNL on the + next flag ledger. + +All three fields are optional. When the *ToReEnable* field exists, the +*NegativeUNL* field cannot be empty. + +A new pseudo-transaction, ***UNLModify***, is added. It has three fields +* ***Disabling***: A flag indicating whether the modification is to disable or + to re-enable a validator. +* ***Seq***: The ledger sequence number. +* ***Validator***: The validator to be disabled or re-enabled. + +There would be at most one *disable* `UNLModify` and one *re-enable* `UNLModify` +transaction per flag ledger. The full machinery is described further on. + +### Negative UNL Maintenance + +The negative UNL can only be modified on the flag ledgers. If a validator's +reliability status changes, it takes two flag ledgers to modify the negative +UNL. Let's see an example of the algorithm: + +* Ledger seq = 100: A validator V goes offline. +* Ledger seq = 256: This is a flag ledger, and V's reliability measurement *PAV* + is lower than the low-water mark. Other validators add `UNLModify` + pseudo-transactions `{true, 256, V}` to the transaction set which goes through + the consensus. Then the pseudo-transaction is applied to the negative UNL + ledger component by setting `ToDisable = V`. +* Ledger seq = 257 ~ 511: The negative UNL ledger component is copied from the + parent ledger. +* Ledger seq=512: This is a flag ledger, and the negative UNL is updated + `NegativeUNL = NegativeUNL + ToDisable`. + +The negative UNL may have up to `MaxNegativeListed = floor(original UNL * 25%)` +validators. The 25% is because of 75% * 80% = 60%, where 75% = 100% - 25%, 80% +is the quorum of the effective UNL, and 60% is the absolute minimum quorum of +the original UNL. Adding more than 25% validators to the negative UNL does not +improve the liveness of the network, because adding more validators to the +negative UNL cannot lower the effective quorum. + +The following is the detailed algorithm: + +* **If** the ledger seq = x is a flag ledger + + 1. Compute `NegativeUNL = NegativeUNL + ToDisable - ToReEnable` if they + exist in the parent ledger + + 1. Try to find a candidate to disable if `sizeof NegativeUNL < MaxNegativeListed` + + 1. Find a validator V that has a *PAV* lower than the low-water + mark, but is not in `NegativeUNL`. + + 1. If two or more are found, their public keys are XORed with the hash + of the parent ledger and the one with the lowest XOR result is chosen. + + 1. If V is found, create a `UNLModify` pseudo-transaction + `TxDisableValidator = {true, x, V}` + + 1. Try to find a candidate to re-enable if `sizeof NegativeUNL > 0`: + + 1. Find a validator U that is in `NegativeUNL` and has a *PAV* higher + than the high-water mark. + + 1. If U is not found, try to find one in `NegativeUNL` but not in the + local *UNL*. + + 1. If two or more are found, their public keys are XORed with the hash + of the parent ledger and the one with the lowest XOR result is chosen. + + 1. If U is found, create a `UNLModify` pseudo-transaction + `TxReEnableValidator = {false, x, U}` + + 1. If any `UNLModify` pseudo-transactions are created, add them to the + transaction set. The transaction set goes through the consensus algorithm. + + 1. If have enough support, the `UNLModify` pseudo-transactions remain in the + transaction set agreed by the validators. Then the pseudo-transactions are + applied to the ledger: + + 1. If have `TxDisableValidator`, set `ToDisable=TxDisableValidator.V`. + Else clear `ToDisable`. + + 1. If have `TxReEnableValidator`, set + `ToReEnable=TxReEnableValidator.U`. Else clear `ToReEnable`. + +* **Else** (not a flag ledger) + + 1. Copy the negative UNL ledger component from the parent ledger + +The negative UNL is stored on each ledger because we don't know when a validator +may reconnect to the network. If the negative UNL was stored only on every flag +ledger, then a new validator would have to wait until it acquires the latest +flag ledger to know the negative UNL. So any new ledgers created that are not +flag ledgers copy the negative UNL from the parent ledger. + +Note that when we have a validator to disable and a validator to re-enable at +the same flag ledger, we create two separate `UNLModify` pseudo-transactions. We +want either one or the other or both to make it into the ledger on their own +merits. + +Readers may have noticed that we defined several rules of creating the +`UNLModify` pseudo-transactions but did not describe how to enforce the rules. +The rules are actually enforced by the existing consensus algorithm. Unless +enough validators propose the same pseudo-transaction it will not be included in +the transaction set of the ledger. + +### Quorum Size Calculation + +The effective quorum is 80% of the effective UNL. Note that because at most 25% +of the original UNL can be on the negative UNL, the quorum should not be lower +than the absolute minimum quorum (i.e. 60%) of the original UNL. However, +considering that different nodes may have different UNLs, to be safe we compute +`quorum = Ceiling(max(60% * original UNL, 80% * effective UNL))`. + +### Filter Validation Messages + +If a validator V is in the negative UNL, it still participates in consensus +sessions in the same way, i.e. V still follows the protocol and publishes +proposal and validation messages. The messages from V are still stored the same +way by everyone, used to calculate the new PAV for V, and could be used in +future consensus sessions if needed. However V's ledger validation message is +not counted when checking if the ledger is fully validated. + +### High Level Sequence Diagram of Code Changes + +The diagram below is the sequence of one round of consensus. Classes and +components with non-trivial changes are colored green. + +* The `ValidatorList` class is modified to compute the quorum of the effective + UNL. + +* The `Validations` class provides an interface for querying the validation + messages from trusted validators. + +* The `ConsensusAdaptor` component: + + * The `RCLConsensus::Adaptor` class is modified for creating `UNLModify` + Pseudo-Transactions. + + * The `Change` class is modified for applying `UNLModify` + Pseudo-Transactions. + + * The `Ledger` class is modified for creating and adjusting the negative UNL + ledger component. + + * The `LedgerMaster` class is modified for filtering out validation messages + from negative UNL validators when verifying if a ledger is fully + validated. + +![Sequence diagram](./negativeUNL_highLevel_sequence.png?raw=true "Negative UNL + Changes") + + +## Roads Not Taken + +### Use a Mechanism Like Fee Voting to Process UNLModify Pseudo-Transactions + +The previous version of the negative UNL specification used the same mechanism +as the [fee voting](https://xrpl.org/fee-voting.html#voting-process.) for +creating the negative UNL, and used the negative UNL as soon as the ledger was +fully validated. However the timing of fully validation can differ among nodes, +so different negative UNLs could be used, resulting in different effective UNLs +and different quorums for the same ledger. As a result, the network's safety is +impacted. + +This updated version does not impact safety though operates a bit more slowly. +The negative UNL modifications in the *UNLModify* pseudo-transaction approved by +the consensus will take effect at the next flag ledger. The extra time of the +256 ledgers should be enough for nodes to be in sync of the negative UNL +modifications. + +### Use an Expiration Approach to Re-enable Validators + +After a validator disabled by the negative UNL becomes reliable, other +validators explicitly vote for re-enabling it. An alternative approach to +re-enable a validator is the expiration approach, which was considered in the +previous version of the specification. In the expiration approach, every entry +in the negative UNL has a fixed expiration time. One flag ledger interval was +chosen as the expiration interval. Once expired, the other validators must +continue voting to keep the unreliable validator on the negative UNL. The +advantage of this approach is its simplicity. But it has a requirement. The +negative UNL protocol must be able to vote multiple unreliable validators to be +disabled at the same flag ledger. In this version of the specification, however, +only one unreliable validator can be disabled at a flag ledger. So the +expiration approach cannot be simply applied. + +### Validator Reliability Measurement and Flag Ledger Frequency + +If the ledger time is about 4.5 seconds and the low-water mark is 50%, then in +the worst case, it takes 48 minutes *((0.5 * 256 + 256 + 256) * 4.5 / 60 = 48)* +to put an offline validator on the negative UNL. We considered lowering the flag +ledger frequency so that the negative UNL can be more responsive. We also +considered decoupling the reliability measurement and flag ledger frequency to +be more flexible. In practice, however, their benefits are not clear. + + +## New Attack Vectors + +A group of malicious validators may try to frame a reliable validator and put it +on the negative UNL. But they cannot succeed. Because: + +1. A reliable validator sends a signed validation message every ledger. A +sufficient peer-to-peer network will propagate the validation messages to other +validators. The validators will decide if another validator is reliable or not +only by its local observation of the validation messages received. So an honest +validator’s vote on another validator’s reliability is accurate. + +1. Given the votes are accurate, and one vote per validator, an honest validator +will not create a UNLModify transaction of a reliable validator. + +1. A validator can be added to a negative UNL only through a UNLModify +transaction. + +Assuming the group of malicious validators is less than the quorum, they cannot +frame a reliable validator. + +## Summary + +The bullet points below briefly summarize the current proposal: + +* The motivation of the negative UNL is to improve the liveness of the network. + +* The targeted faults are the ones frequently observed in the production + network. + +* Validators propose negative UNL candidates based on their local measurements. + +* The absolute minimum quorum is 60% of the original UNL. + +* The format of the ledger is changed, and a new *UNLModify* pseudo-transaction + is added. Any tools or systems that rely on the format of these data will have + to be updated. + +* The negative UNL can only be modified on the flag ledgers. + +* At most one validator can be added to the negative UNL at a flag ledger. + +* At most one validator can be removed from the negative UNL at a flag ledger. + +* If a validator's reliability status changes, it takes two flag ledgers to + modify the negative UNL. + +* The quorum is the larger of 80% of the effective UNL and 60% of the original + UNL. + +* If a validator is on the negative UNL, its validation messages are ignored + when the local node verifies if a ledger is fully validated. + +## FAQ + +### Question: What are UNLs? + +Quote from the [Technical FAQ](https://xrpl.org/technical-faq.html): "They are +the lists of transaction validators a given participant believes will not +conspire to defraud them." + +### Question: How does the negative UNL proposal affect network liveness? + +The network can make forward progress when more than a quorum of the trusted +validators agree with the progress. The lower the quorum size is, the easier for +the network to progress. If the quorum is too low, however, the network is not +safe because nodes may have different results. So the quorum size used in the +consensus protocol is a balance between the safety and the liveness of the +network. The negative UNL reduces the size of the effective UNL, resulting in a +lower quorum size while keeping the network safe. + +

Question: How does a validator get into the negative UNL? How is a +validator removed from the negative UNL?

+ +A validator’s reliability is measured by other validators. If a validator +becomes unreliable, at a flag ledger, other validators propose *UNLModify* +pseudo-transactions which vote the validator to add to the negative UNL during +the consensus session. If agreed, the validator is added to the negative UNL at +the next flag ledger. The mechanism of removing a validator from the negative +UNL is the same. + +### Question: Given a negative UNL, what happens if the UNL changes? + +Answer: Let’s consider the cases: + +1. A validator is added to the UNL, and it is already in the negative UNL. This +case could happen when not all the nodes have the same UNL. Note that the +negative UNL on the ledger lists unreliable nodes that are not necessarily the +validators for everyone. + + In this case, the liveness is affected negatively. Because the minimum + quorum could be larger but the usable validators are not increased. + +1. A validator is removed from the UNL, and it is in the negative UNL. + + In this case, the liveness is affected positively. Because the quorum could + be smaller but the usable validators are not reduced. + +1. A validator is added to the UNL, and it is not in the negative UNL. +1. A validator is removed from the UNL, and it is not in the negative UNL. + + Case 3 and 4 are not affected by the negative UNL protocol. + +### Question: Can we simply lower the quorum to 60% without the negative UNL? + +Answer: No, because the negative UNL approach is safer. + +First let’s compare the two approaches intuitively, (1) the *negative UNL* +approach, and (2) *lower quorum*: simply lowering the quorum from 80% to 60% +without the negative UNL. The negative UNL approach uses consensus to come up +with a list of unreliable validators, which are then removed from the effective +UNL temporarily. With this approach, the list of unreliable validators is agreed +to by a quorum of validators and will be used by every node in the network to +adjust its UNL. The quorum is always 80% of the effective UNL. The lower quorum +approach is a tradeoff between safety and liveness and against our principle of +preferring safety over liveness. Note that different validators don't have to +agree on which validation sources they are ignoring. + +Next we compare the two approaches quantitatively with examples, and apply +Theorem 8 of [Analysis of the XRP Ledger Consensus +Protocol](https://arxiv.org/abs/1802.07242) paper: + +*XRP LCP guarantees fork safety if **Oi,j > nj / 2 + +ni − qi + ti,j** for every pair of nodes +Pi, Pj,* + +where *Oi,j* is the overlapping requirement, nj and +ni are UNL sizes, qi is the quorum size of Pi, +*ti,j = min(ti, tj, Oi,j)*, and +ti and tj are the number of faults can be tolerated by +Pi and Pj. + +We denote *UNLi* as *Pi's UNL*, and *|UNLi|* as +the size of *Pi's UNL*. + +Assuming *|UNLi| = |UNLj|*, let's consider the following +three cases: + +1. With 80% quorum and 20% faults, *Oi,j > 100% / 2 + 100% - 80% + +20% = 90%*. I.e. fork safety requires > 90% UNL overlaps. This is one of the +results in the analysis paper. + +1. If the quorum is 60%, the relationship between the overlapping requirement +and the faults that can be tolerated is *Oi,j > 90% + +ti,j*. Under the same overlapping condition (i.e. 90%), to guarantee +the fork safety, the network cannot tolerate any faults. So under the same +overlapping condition, if the quorum is simply lowered, the network can tolerate +fewer faults. + +1. With the negative UNL approach, we want to argue that the inequation +*Oi,j > nj / 2 + ni − qi + +ti,j* is always true to guarantee fork safety, while the negative UNL +protocol runs, i.e. the effective quorum is lowered without weakening the +network's fault tolerance. To make the discussion easier, we rewrite the +inequation as *Oi,j > nj / 2 + (ni − +qi) + min(ti, tj)*, where Oi,j is +dropped from the definition of ti,j because *Oi,j > +min(ti, tj)* always holds under the parameters we will +use. Assuming a validator V is added to the negative UNL, now let's consider the +4 cases: + + 1. V is not on UNLi nor UNLj + + The inequation holds because none of the variables change. + + 1. V is on UNLi but not on UNLj + + The value of *(ni − qi)* is smaller. The value of + *min(ti, tj)* could be smaller too. Other + variables do not change. Overall, the left side of the inequation does + not change, but the right side is smaller. So the inequation holds. + + 1. V is not on UNLi but on UNLj + + The value of *nj / 2* is smaller. The value of + *min(ti, tj)* could be smaller too. Other + variables do not change. Overall, the left side of the inequation does + not change, but the right side is smaller. So the inequation holds. + + 1. V is on both UNLi and UNLj + + The value of *Oi,j* is reduced by 1. The values of + *nj / 2*, *(ni − qi)*, and + *min(ti, tj)* are reduced by 0.5, 0.2, and 1 + respectively. The right side is reduced by 1.7. Overall, the left side + of the inequation is reduced by 1, and the right side is reduced by 1.7. + So the inequation holds. + + The inequation holds for all the cases. So with the negative UNL approach, + the network's fork safety is preserved, while the quorum is lowered that + increases the network's liveness. + +

Question: We have observed that occasionally a validator wanders off on its +own chain. How is this case handled by the negative UNL algorithm?

+ +Answer: The case that a validator wanders off on its own chain can be measured +with the validations agreement. Because the validations by this validator must +be different from other validators' validations of the same sequence numbers. +When there are enough disagreed validations, other validators will vote this +validator onto the negative UNL. + +In general by measuring the agreement of validations, we also measured the +"sanity". If two validators have too many disagreements, one of them could be +insane. When enough validators think a validator is insane, that validator is +put on the negative UNL. + +

Question: Why would there be at most one disable UNLModify and one +re-enable UNLModify transaction per flag ledger?

+ +Answer: It is a design choice so that the effective UNL does not change too +quickly. A typical targeted scenario is several validators go offline slowly +during a long weekend. The current design can handle this kind of cases well +without changing the effective UNL too quickly. + +## Appendix + +### Confidence Test + +We will use two test networks, a single machine test network with multiple IP +addresses and the QE test network with multiple machines. The single machine +network will be used to test all the test cases and to debug. The QE network +will be used after that. We want to see the test cases still pass with real +network delay. A test case specifies: + +1. a UNL with different number of validators for different test cases, +1. a network with zero or more non-validator nodes, +1. a sequence of validator reliability change events (by killing/restarting + nodes, or by running modified rippled that does not send all validation + messages), +1. the correct outcomes. + +For all the test cases, the correct outcomes are verified by examining logs. We +will grep the log to see if the correct negative UNLs are generated, and whether +or not the network is making progress when it should be. The ripdtop tool will +be helpful for monitoring validators' states and ledger progress. Some of the +timing parameters of rippled will be changed to have faster ledger time. Most if +not all test cases do not need client transactions. + +For example, the test cases for the prototype: +1. A 10-validator UNL. +1. The network does not have other nodes. +1. The validators will be started from the genesis. Once they start to produce + ledgers, we kill five validators, one every flag ledger interval. Then we + will restart them one by one. +1. A sequence of events (or the lack of events) such as a killed validator is + added to the negative UNL. + +#### Roads Not Taken: Test with Extended CSF + +We considered testing with the current unit test framework, specifically the +[Consensus Simulation +Framework](https://github.com/ripple/rippled/blob/develop/src/test/csf/README.md) +(CSF). However, the CSF currently can only test the generic consensus algorithm +as in the paper: [Analysis of the XRP Ledger Consensus +Protocol](https://arxiv.org/abs/1802.07242). \ No newline at end of file diff --git a/docs/0001-negative-unl/negativeUNLSqDiagram.puml b/docs/0001-negative-unl/negativeUNLSqDiagram.puml new file mode 100644 index 00000000000..8cb491af6ab --- /dev/null +++ b/docs/0001-negative-unl/negativeUNLSqDiagram.puml @@ -0,0 +1,79 @@ +@startuml negativeUNL_highLevel_sequence + +skinparam sequenceArrowThickness 2 +skinparam roundcorner 20 +skinparam maxmessagesize 160 + +actor "Rippled Start" as RS +participant "Timer" as T +participant "NetworkOPs" as NOP +participant "ValidatorList" as VL #lightgreen +participant "Consensus" as GC +participant "ConsensusAdaptor" as CA #lightgreen +participant "Validations" as RM #lightgreen + +RS -> NOP: begin consensus +activate NOP +NOP -[#green]> VL: update negative UNL +hnote over VL#lightgreen: store a copy of\nnegative UNL +VL -> NOP +NOP -> VL: update trusted validators +activate VL +VL -> VL: re-calculate quorum +hnote over VL#lightgreen: ignore negative listed validators\nwhen calculate quorum +VL -> NOP +deactivate VL +NOP -> GC: start round +activate GC +GC -> GC: phase = OPEN +GC -> NOP +deactivate GC +deactivate NOP + +loop at regular frequency +T -> GC: timerEntry +activate GC +end + +alt phase == OPEN + alt should close ledger + GC -> GC: phase = ESTABLISH + GC -> CA: onClose + activate CA + alt sqn%256==0 + CA -[#green]> RM: getValidations + CA -[#green]> CA: create UNLModify Tx + hnote over CA#lightgreen: use validatations of the last 256 ledgers\nto figure out UNLModify Tx candidates.\nIf any, create UNLModify Tx, and add to TxSet. + end + CA -> GC + GC -> CA: propose + deactivate CA + end +else phase == ESTABLISH + hnote over GC: receive peer postions + GC -> GC : update our position + GC -> CA : propose \n(if position changed) + GC -> GC : check if have consensus + alt consensus reached + GC -> GC: phase = ACCEPT + GC -> CA : onAccept + activate CA + CA -> CA : build LCL + hnote over CA #lightgreen: copy negative UNL from parent ledger + alt sqn%256==0 + CA -[#green]> CA: Adjust negative UNL + CA -[#green]> CA: apply UNLModify Tx + end + CA -> CA : validate and send validation message + activate NOP + CA -> NOP : end consensus and\nbegin next consensus round + deactivate NOP + deactivate CA + hnote over RM: receive validations + end +else phase == ACCEPTED + hnote over GC: timerEntry hash nothing to do at this phase +end +deactivate GC + +@enduml \ No newline at end of file diff --git a/docs/0001-negative-unl/negativeUNL_highLevel_sequence.png b/docs/0001-negative-unl/negativeUNL_highLevel_sequence.png new file mode 100644 index 00000000000..b962693b49c Binary files /dev/null and b/docs/0001-negative-unl/negativeUNL_highLevel_sequence.png differ diff --git a/docs/0010-ledger-replay/README.md b/docs/0010-ledger-replay/README.md new file mode 100644 index 00000000000..170fd15c43e --- /dev/null +++ b/docs/0010-ledger-replay/README.md @@ -0,0 +1,88 @@ +# Ledger Replay + +`LedgerReplayer` is a new `Stoppable` for replaying ledgers. +Patterned after two other `Stoppable`s under `JobQueue`---`InboundLedgers` +and `InboundTransactions`---it acts like a factory for creating +state-machine workers, and a network message demultiplexer for those workers. +Think of these workers like asynchronous functions. +Like functions, they each take a set of parameters. +The `Stoppable` memoizes these functions. It maintains a table for each +worker type, mapping sets of arguments to the worker currently working +on that argument set. +Whenever the `Stoppable` is asked to construct a worker, it first searches its +table to see if there is an existing worker with the same or overlapping +argument set. +If one exists, then it is used. If not, then a new one is created, +initialized, and added to the table. + +For `LedgerReplayer`, there are three worker types: `LedgerReplayTask`, +`SkipListAcquire`, and `LedgerDeltaAcquire`. +Each is derived from `TimeoutCounter` to give it a timeout. +For `LedgerReplayTask`, the parameter set +is {reason, finish ledger ID, number of ledgers}. For `SkipListAcquire` and +`LedgerDeltaAcquire`, there is just one parameter: a ledger ID. + +Each `Stoppable` has an entry point. For `LedgerReplayer`, it is `replay`. +`replay` creates two workers: a `LedgerReplayTask` and a `SkipListAcquire`. +`LedgerDeltaAcquire`s are created in the callback for when the skip list +returns. + +For `SkipListAcquire` and `LedgerDeltaAcquire`, initialization fires off the +underlying asynchronous network request and starts the timeout. The argument +set identifying the worker is included in the network request, and copied to +the network response. `SkipListAcquire` sends a request for a proof path for +the skip list of the desired ledger. `LedgerDeltaAcquire` sends a request for +the transaction set of the desired ledger. + +`LedgerReplayer` is also a network message demultiplexer. +When a response arrives for a request that was sent by a `SkipListAcquire` or +`LedgerDeltaAcquire` worker, the `Peer` object knows to send it to the +`LedgerReplayer`, which looks up the worker waiting for that response based on +the identifying argument set included in the response. + +`LedgerReplayTask` may ask `InboundLedgers` to send requests to acquire +the start ledger, but there is no way to attach a callback or be notified when +the `InboundLedger` worker completes. All the responses for its messages will +be directed to `InboundLedgers`, not `LedgerReplayer`. Instead, +`LedgerReplayTask` checks whether the start ledger has arrived every time its +timeout expires. + +Like a promise, each worker keeps track of whether it is pending (`!isDone()`) +or whether it has resolved successfully (`complete_ == true`) or unsuccessfully +(`failed_ == true`). It will never exist in both resolved states at once, nor +will it return to a pending state after reaching a resolved state. + +Like promises, some workers can accept continuations to be called when they +reach a resolved state, or immediately if they are already resolved. +`SkipListAcquire` and `LedgerDeltaAcquire` both accept continuations of a type +specific to their payload, both via a method named `addDataCallback()`. Continuations +cannot be removed explicitly, but they are held by `std::weak_ptr` so they can +be removed implicitly. + +`LedgerReplayTask` is simultaneously: + +1. an asynchronous function, +1. a continuation to one `SkipListAcquire` asynchronous function, +1. a continuation to zero or more `LedgerDeltaAcquire` asynchronous functions, and +1. a continuation to its own timeout. + +Each of these roles corresponds to different entry points: + +1. `init()` +1. the callback added to `SkipListAcquire`, which calls `updateSkipList(...)` or `cancel()` +1. the callback added to `LedgerDeltaAcquire`, which calls `deltaReady(...)` or `cancel()` +1. `onTimer()` + +Each of these entry points does something unique to that entry point. They +either (a) transition `LedgerReplayTask` to a terminal failed resolved state +(`cancel()` and `onTimer()`) or (b) try to make progress toward the successful +resolved state. `init()` and `updateSkipList(...)` call `trigger()` while +`deltaReady(...)` calls `tryAdvance()`. There's a similarity between this +pattern and the way coroutines are implemented, where every yield saves the spot +in the code where it left off and every resume jumps back to that spot. + +### Sequence Diagram +![Sequence diagram](./ledger_replay_sequence.png?raw=true "A successful ledger replay") + +### Class Diagram +![Class diagram](./ledger_replay_classes.png?raw=true "Ledger replay classes") diff --git a/docs/0010-ledger-replay/ledger_replay_classes.png b/docs/0010-ledger-replay/ledger_replay_classes.png new file mode 100644 index 00000000000..f4cbab62907 Binary files /dev/null and b/docs/0010-ledger-replay/ledger_replay_classes.png differ diff --git a/docs/0010-ledger-replay/ledger_replay_classes.puml b/docs/0010-ledger-replay/ledger_replay_classes.puml new file mode 100644 index 00000000000..4c90ef2511c --- /dev/null +++ b/docs/0010-ledger-replay/ledger_replay_classes.puml @@ -0,0 +1,98 @@ +@startuml + +class TimeoutCounter { + #app_ : Application& +} + +TimeoutCounter o-- "1" Application +': app_ + +Stoppable <.. Application + +class Application { + -m_ledgerReplayer : uptr + -m_inboundLedgers : uptr +} + +Application *-- "1" LedgerReplayer +': m_ledgerReplayer +Application *-- "1" InboundLedgers +': m_inboundLedgers + +Stoppable <.. InboundLedgers +Application "1" --o InboundLedgers +': app_ + +class InboundLedgers { + -app_ : Application& +} + +Stoppable <.. LedgerReplayer +InboundLedgers "1" --o LedgerReplayer +': inboundLedgers_ +Application "1" --o LedgerReplayer +': app_ + +class LedgerReplayer { + +createDeltas(LedgerReplayTask) + -app_ : Application& + -inboundLedgers_ : InboundLedgers& + -tasks_ : vector> + -deltas_ : hash_map> + -skipLists_ : hash_map> +} + +LedgerReplayer *-- LedgerReplayTask +': tasks_ +LedgerReplayer o-- LedgerDeltaAcquire +': deltas_ +LedgerReplayer o-- SkipListAcquire +': skipLists_ + +TimeoutCounter <.. LedgerReplayTask +InboundLedgers "1" --o LedgerReplayTask +': inboundLedgers_ +LedgerReplayer "1" --o LedgerReplayTask +': replayer_ + +class LedgerReplayTask { + -inboundLedgers_ : InboundLedgers& + -replayer_ : LedgerReplayer& + -skipListAcquirer_ : sptr + -deltas_ : vector> + +addDelta(sptr) +} + +LedgerReplayTask *-- "1" SkipListAcquire +': skipListAcquirer_ +LedgerReplayTask *-- LedgerDeltaAcquire +': deltas_ + +TimeoutCounter <.. SkipListAcquire +InboundLedgers "1" --o SkipListAcquire +': inboundLedgers_ +LedgerReplayer "1" --o SkipListAcquire +': replayer_ +LedgerReplayTask --o SkipListAcquire : implicit via callback + +class SkipListAcquire { + +addDataCallback(callback) + -inboundLedgers_ : InboundLedgers& + -replayer_ : LedgerReplayer& + -dataReadyCallbacks_ : vector +} + +TimeoutCounter <.. LedgerDeltaAcquire +InboundLedgers "1" --o LedgerDeltaAcquire +': inboundLedgers_ +LedgerReplayer "1" --o LedgerDeltaAcquire +': replayer_ +LedgerReplayTask --o LedgerDeltaAcquire : implicit via callback + +class LedgerDeltaAcquire { + +addDataCallback(callback) + -inboundLedgers_ : InboundLedgers& + -replayer_ : LedgerReplayer& + -dataReadyCallbacks_ : vector +} +@enduml \ No newline at end of file diff --git a/docs/0010-ledger-replay/ledger_replay_sequence.png b/docs/0010-ledger-replay/ledger_replay_sequence.png new file mode 100644 index 00000000000..37bcbd5069a Binary files /dev/null and b/docs/0010-ledger-replay/ledger_replay_sequence.png differ diff --git a/docs/0010-ledger-replay/ledger_replay_sequence.puml b/docs/0010-ledger-replay/ledger_replay_sequence.puml new file mode 100644 index 00000000000..481819b5e87 --- /dev/null +++ b/docs/0010-ledger-replay/ledger_replay_sequence.puml @@ -0,0 +1,85 @@ +@startuml + +autoactivate on + +' participant app as "Application" +participant peer as "Peer" +participant lr as "LedgerReplayer" +participant lrt as "LedgerReplayTask" +participant sla as "SkipListAcquire" +participant lda as "LedgerDeltaAcquire" + +[-> lr : replay(finishId, numLedgers) + lr -> sla : make_shared(finishHash) + return skipList + lr -> lrt : make_shared(skipList) + return task + lr -> sla : init(numPeers=1) + sla -> sla : trigger(numPeers=1) + sla -> peer : sendRequest(ProofPathRequest) + return + return + return + lr -> lrt : init() + lrt -> sla : addDataCallback(callback) + return + return +deactivate lr + +[-> peer : onMessage(ProofPathResponse) + peer -> lr : gotSkipList(ledgerHeader, item) + lr -> sla : processData(ledgerSeq, item) + sla -> sla : onSkipListAcquired(skipList, ledgerSeq) + sla -> sla : notify() + note over sla: call the callbacks added by\naddDataCallback(callback). + sla -> lrt : callback(ledgerId) + lrt -> lrt : updateSkipList(ledgerId, ledgerSeq, skipList) + lrt -> lr : createDeltas(this) + loop + lr -> lda : make_shared(ledgerId, ledgerSeq) + return delta + lr -> lrt : addDelta(delta) + lrt -> lda : addDataCallback(callback) + return + return + lr -> lda : init(numPeers=1) + lda -> lda : trigger(numPeers=1) + lda -> peer : sendRequest(ReplayDeltaRequest) + return + return + return + end + return + return + return + return + return + return +deactivate peer + +[-> peer : onMessage(ReplayDeltaResponse) + peer -> lr : gotReplayDelta(ledgerHeader) + lr -> lda : processData(ledgerHeader, txns) + lda -> lda : notify() + note over lda: call the callbacks added by\naddDataCallback(callback). + lda -> lrt : callback(ledgerId) + lrt -> lrt : deltaReady(ledgerId) + lrt -> lrt : tryAdvance() + loop as long as child can be built + lrt -> lda : tryBuild(parent) + lda -> lda : onLedgerBuilt() + note over lda + Schedule a job to store the built ledger. + end note + return + return child + end + return + return + return + return + return +deactivate peer + + +@enduml \ No newline at end of file diff --git a/docs/Docker.md b/docs/Docker.md index d0103fbd9ae..9f67c87ee51 100644 --- a/docs/Docker.md +++ b/docs/Docker.md @@ -1,16 +1,5 @@ -# Rippled Docker Image +# `rippled` Docker Image -Rippled has a continuous deployment pipeline that turns every git commit into a -docker image for quick testing and deployment. - -To run the tip of the latest release via docker: - -```$ docker run -P -v /srv/rippled/ ripple/rippled:latest``` - -To run the tip of active development: - -```$ docker run -P -v /srv/rippled/ ripple/rippled:develop``` - -Where ```/srv/rippled``` points to a directory containing a rippled.cfg and -database files. By default, port 5005/tcp maps to the RPC port and 51235/udp to -the peer port. +- Some info relating to Docker containers can be found here: [../Builds/containers](../Builds/containers) +- Images for building and testing rippled can be found here: [thejohnfreeman/rippled-docker](https://github.com/thejohnfreeman/rippled-docker/) + - These images do not have rippled. They have all the tools necessary to build rippled. diff --git a/docs/Dockerfile b/docs/Dockerfile deleted file mode 100644 index dd33d95e647..00000000000 --- a/docs/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt -y update -RUN apt -y upgrade -RUN apt -y install build-essential g++ git libbz2-dev wget python-dev -RUN apt -y install cmake flex bison graphviz graphviz-dev libicu-dev -RUN apt -y install jarwrapper java-common - -RUN cd /tmp -ENV CM_INSTALLER=cmake-3.10.0-rc3-Linux-x86_64.sh -ENV CM_VER_DIR=/opt/local/cmake-3.10.0 -RUN cd /tmp && wget https://cmake.org/files/v3.10/$CM_INSTALLER && chmod a+x $CM_INSTALLER -RUN mkdir -p $CM_VER_DIR -RUN ln -s $CM_VER_DIR /opt/local/cmake -RUN /tmp/$CM_INSTALLER --prefix=$CM_VER_DIR --exclude-subdir -RUN rm -f /tmp/$CM_INSTALLER - -RUN cd /tmp && wget https://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.14.src.tar.gz -RUN cd /tmp && tar xvf doxygen-1.8.14.src.tar.gz -RUN mkdir -p /tmp/doxygen-1.8.14/build -RUN cd /tmp/doxygen-1.8.14/build && /opt/local/cmake/bin/cmake -G "Unix Makefiles" .. -RUN cd /tmp/doxygen-1.8.14/build && make -j2 -RUN cd /tmp/doxygen-1.8.14/build && make install -RUN rm -f /tmp/doxygen-1.8.14.src.tar.gz -RUN rm -rf /tmp/doxygen-1.8.14 - -RUN mkdir -p /opt/plantuml -RUN wget -O /opt/plantuml/plantuml.jar http://sourceforge.net/projects/plantuml/files/plantuml.jar/download -ENV PLANTUML_JAR=/opt/plantuml/plantuml.jar - -CMD cd /opt/rippled/docs && doxygen source.dox diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100644 index 00000000000..750ae0fb649 --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,343 @@ +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "rippled" +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +PROJECT_LOGO = +OUTPUT_DIRECTORY = $(DOXYGEN_OUTPUT_DIRECTORY) +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = YES +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = src/ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = YES +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = NO +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = NO +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = YES +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = NO +GENERATE_TESTLIST = NO +GENERATE_BUGLIST = NO +GENERATE_DEPRECATEDLIST= NO +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = NO +SHOW_FILES = NO +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = \ + . \ + + +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.h *.cpp *.md +RECURSIVE = YES +EXCLUDE = \ + .github \ + external/ed25519-donna \ + external/secp256k1 \ + +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = \ + docs/images/ \ + docs/images/consensus/ \ + src/test/csf/ \ + +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = ./README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +CLANG_ASSISTED_PARSING = NO +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = $(DOXYGEN_INCLUDE_PATH) +INCLUDE_FILE_PATTERNS = +PREDEFINED = DOXYGEN \ + GENERATING_DOCS \ + _MSC_VER \ + NUDB_POSIX_FILE=1 + +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = $(DOXYGEN_TAGFILES) +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +# DOT_NUM_THREADS = 0 means 1 for every processor. +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = $(DOXYGEN_DOT_PATH) +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = $(DOXYGEN_PLANTUML_JAR_PATH) +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/docs/README.md b/docs/README.md index 04e25775273..55b9e30e04d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,76 +1,63 @@ # Building documentation -## Specifying Files - -To specify the source files for which to build documentation, modify `INPUT` -and its related fields in `docs/source.dox`. Note that the `INPUT` paths are -relative to the `docs/` directory. - -## Install Dependencies - -### Windows +## Dependencies Install these dependencies: -1. Install [Doxygen](http://www.stack.nl/~dimitri/doxygen/download.html) +- [Doxygen](http://www.doxygen.nl): All major platforms have [official binary + distributions](http://www.doxygen.nl/download.html#srcbin), or you can + build from [source](http://www.doxygen.nl/download.html#srcbin). -### MacOS + - MacOS: We recommend installing via Homebrew: `brew install doxygen`. + The executable will be installed in `/usr/local/bin` which is already + in the default `PATH`. -1. Install doxygen: - * Use homebrew to install: `brew install doxygen`. The executable will be - installed in `/usr/local/bin` which is already in your path. - * Alternatively, install from here: [doxygen](http://www.stack.nl/~dimitri/doxygen/download.html). - You'll then need to make doxygen available to your command line. You can - do this by adding a symbolic link from `/usr/local/bin` to the doxygen - executable. For example, `$ ln -s /Applications/Doxygen.app/Contents/Resources/doxygen /usr/local/bin/doxygen` + If you use the official binary distribution, then you'll need to make + Doxygen available to your command line. You can do this by adding + a symbolic link from `/usr/local/bin` to the `doxygen` executable. For + example, -### Linux + ``` + $ ln -s /Applications/Doxygen.app/Contents/Resources/doxygen /usr/local/bin/doxygen + ``` -1. Install doxygen using your package manager OR from source using the links above. +- [PlantUML](http://plantuml.com): -### [Optional] Install Plantuml (all platforms) + 1. Install a functioning Java runtime, if you don't already have one. + 2. Download [`plantuml.jar`](http://sourceforge.net/projects/plantuml/files/plantuml.jar/download). -Doxygen supports the optional use of [plantuml](http://plantuml.com) to -generate diagrams from `@startuml` sections. We don't currently rely on this -functionality for docs, so it's largely optional. Requirements: +- [Graphviz](https://www.graphviz.org): -1. Download/install a functioning java runtime, if you don't already have one. -2. Download [plantuml](http://plantuml.com) from - [here](http://sourceforge.net/projects/plantuml/files/plantuml.jar/download). - Set a system environment variable named `PLANTUML_JAR` with a value of the fullpath - to the file system location of the `plantuml.jar` file you downloaded. + - Linux: Install from your package manager. + - Windows: Use an [official installer](https://graphviz.gitlab.io/_pages/Download/Download_windows.html). + - MacOS: Install via Homebrew: `brew install graphviz`. -## Do it - -### all platforms - -From the rippled root folder: -``` -cd docs -mkdir -p html_doc -doxygen source.dox -``` -The output will be in `docs/html_doc`. ## Docker -(applicable to all platforms) - -Instead of installing the doxygen tools locally, you can use the provided `Dockerfile` to create -an ubuntu based image for running the tools: +Instead of installing the above dependencies locally, you can use the official +build environment Docker image, which has all of them installed already. 1. Install [Docker](https://docs.docker.com/engine/installation/) -2. Build Docker image. From the rippled root folder: +2. Pull the image: + ``` + sudo docker pull rippleci/rippled-ci-builder:2944b78d22db + ``` +3. Run the image from the project folder: + ``` + sudo docker run -v $PWD:/opt/rippled --rm rippleci/rippled-ci-builder:2944b78d22db + ``` -``` -sudo docker build -t rippled-docs docs/ -``` -Then to run the image, from the rippled root folder: +## Build + +There is a `docs` target in the CMake configuration. ``` -sudo docker run -v $PWD:/opt/rippled --rm rippled-docs +mkdir build +cd build +cmake .. +cmake --build . --target docs ``` -The output will be in `docs/html_doc`. - +The output will be in `build/docs/html`. diff --git a/docs/build/conan.md b/docs/build/conan.md new file mode 100644 index 00000000000..5f1ff7ae983 --- /dev/null +++ b/docs/build/conan.md @@ -0,0 +1,124 @@ +## A crash course in CMake and Conan + +To better understand how to use Conan, +we should first understand _why_ we use Conan, +and to understand that, +we need to understand how we use CMake. + + +### CMake + +Technically, you don't need CMake to build this project. +You could manually compile every translation unit into an object file, +using the right compiler options, +and then manually link all those objects together, +using the right linker options. +However, that is very tedious and error-prone, +which is why we lean on tools like CMake. + +We have written CMake configuration files +([`CMakeLists.txt`](./CMakeLists.txt) and friends) +for this project so that CMake can be used to correctly compile and link +all of the translation units in it. +Or rather, CMake will generate files for a separate build system +(e.g. Make, Ninja, Visual Studio, Xcode, etc.) +that compile and link all of the translation units. +Even then, CMake has parameters, some of which are platform-specific. +In CMake's parlance, parameters are specially-named **variables** like +[`CMAKE_BUILD_TYPE`][build_type] or +[`CMAKE_MSVC_RUNTIME_LIBRARY`][runtime]. +Parameters include: + +- what build system to generate files for +- where to find the compiler and linker +- where to find dependencies, e.g. libraries and headers +- how to link dependencies, e.g. any special compiler or linker flags that + need to be used with them, including preprocessor definitions +- how to compile translation units, e.g. with optimizations, debug symbols, + position-independent code, etc. +- on Windows, which runtime library to link with + +For some of these parameters, like the build system and compiler, +CMake goes through a complicated search process to choose default values. +For others, like the dependencies, +_we_ had written in the CMake configuration files of this project +our own complicated process to choose defaults. +For most developers, things "just worked"... until they didn't, and then +you were left trying to debug one of these complicated processes, instead of +choosing and manually passing the parameter values yourself. + +You can pass every parameter to CMake on the command line, +but writing out these parameters every time we want to configure CMake is +a pain. +Most humans prefer to put them into a configuration file, once, that +CMake can read every time it is configured. +For CMake, that file is a [toolchain file][toolchain]. + + +### Conan + +These next few paragraphs on Conan are going to read much like the ones above +for CMake. + +Technically, you don't need Conan to build this project. +You could manually download, configure, build, and install all of the +dependencies yourself, and then pass all of the parameters necessary for +CMake to link to those dependencies. +To guarantee ABI compatibility, you must be sure to use the same set of +compiler and linker options for all dependencies _and_ this project. +However, that is very tedious and error-prone, which is why we lean on tools +like Conan. + +We have written a Conan configuration file ([`conanfile.py`](../../conanfile.py)) +so that Conan can be used to correctly download, configure, build, and install +all of the dependencies for this project, +using a single set of compiler and linker options for all of them. +It generates files that contain almost all of the parameters that CMake +expects. +Those files include: + +- A single toolchain file. +- For every dependency, a CMake [package configuration file][pcf], + [package version file][pvf], and for every build type, a package + targets file. + Together, these files implement version checking and define `IMPORTED` + targets for the dependencies. + +The toolchain file itself amends the search path +([`CMAKE_PREFIX_PATH`][prefix_path]) so that [`find_package()`][find_package] +will [discover][search] the generated package configuration files. + +**Nearly all we must do to properly configure CMake is pass the toolchain +file.** +What CMake parameters are left out? +You'll still need to pick a build system generator, +and if you choose a single-configuration generator, +you'll need to pass the `CMAKE_BUILD_TYPE`, +which should match the `build_type` setting you gave to Conan. + +Even then, Conan has parameters, some of which are platform-specific. +In Conan's parlance, parameters are either settings or options. +**Settings** are shared by all packages, e.g. the build type. +**Options** are specific to a given package, e.g. whether to build and link +OpenSSL as a shared library. + +For settings, Conan goes through a complicated search process to choose +defaults. +For options, each package recipe defines its own defaults. + +You can pass every parameter to Conan on the command line, +but it is more convenient to put them in a configuration file, once, that +Conan can read every time it is configured. +For Conan, that file is a [profile][]. +**All we must do to properly configure Conan is edit and pass the profile.** +By default, Conan will use the profile named "default". + +[build_type]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html +[find_package]: https://cmake.org/cmake/help/latest/command/find_package.html +[pcf]: https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#package-configuration-file +[prefix_path]: https://cmake.org/cmake/help/latest/variable/CMAKE_PREFIX_PATH.html +[profile]: https://docs.conan.io/en/latest/reference/profiles.html +[pvf]: https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#package-version-file +[runtime]: https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html +[search]: https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure +[toolchain]: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html diff --git a/docs/build/depend.md b/docs/build/depend.md new file mode 100644 index 00000000000..42fd41a26e8 --- /dev/null +++ b/docs/build/depend.md @@ -0,0 +1,98 @@ +We recommend two different methods to depend on libxrpl in your own [CMake][] +project. +Both methods add a CMake library target named `xrpl::libxrpl`. + + +## Conan requirement + +The first method adds libxrpl as a [Conan][] requirement. +With this method, there is no need for a Git [submodule][]. +It is good for when you just need a dependency on libxrpl as-is. + +``` +# This conanfile.txt is just an example. +[requires] +xrpl/1.10.0 + +[generators] +CMakeDeps +CMakeToolchain +``` + +``` +# If you want to depend on a version of libxrpl that is not in ConanCenter, +# then you can export the recipe from the rippled project. +conan export +``` + +```cmake +# Find and link the library in your CMake project. +find_package(xrpl) +target_link_libraries( PUBLIC xrpl::libxrpl) +``` + +``` +# Download, build, and connect dependencies with Conan. +mkdir .build +cd .build +mkdir -p build/generators +conan install \ + --install-folder build/generators \ + --build missing \ + --settings build_type=Release \ + .. +cmake \ + -DCMAKE_TOOLCHAIN_FILE=build/generators/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. +cmake --build . --parallel +``` + + +## CMake subdirectory + +The second method adds the [rippled][] project as a CMake +[subdirectory][add_subdirectory]. +This method works well when you keep the rippled project as a Git +[submodule][]. +It's good for when you want to make changes to libxrpl as part of your own +project. +Be careful, though. +Your project will inherit all of the same CMake options, +so watch out for name collisions. +We still recommend using [Conan][] to download, build, and connect dependencies. + +``` +# Add the project as a Git submodule. +mkdir submodules +git submodule add https://github.com/XRPLF/rippled.git submodules/rippled +``` + +```cmake +# Add and link the library in your CMake project. +add_subdirectory(submodules/rippled) +target_link_libraries( PUBLIC xrpl::libxrpl) +``` + +``` +# Download, build, and connect dependencies with Conan. +mkdir .build +cd .build +conan install \ + --output-folder . \ + --build missing \ + --settings build_type=Release \ + ../submodules/rippled +cmake \ + -DCMAKE_TOOLCHAIN_FILE=build/generators/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. +cmake --build . --parallel +``` + + +[add_subdirectory]: https://cmake.org/cmake/help/latest/command/add_subdirectory.html +[submodule]: https://git-scm.com/book/en/v2/Git-Tools-Submodules +[rippled]: https://github.com/ripple/rippled +[Conan]: https://docs.conan.io/ +[CMake]: https://cmake.org/cmake/help/latest/ diff --git a/docs/build/environment.md b/docs/build/environment.md new file mode 100644 index 00000000000..7fe89ffb49f --- /dev/null +++ b/docs/build/environment.md @@ -0,0 +1,84 @@ +Our [build instructions][BUILD.md] assume you have a C++ development +environment complete with Git, Python, Conan, CMake, and a C++ compiler. +This document exists to help readers set one up on any of the Big Three +platforms: Linux, macOS, or Windows. + +[BUILD.md]: ../../BUILD.md + + +## Linux + +Package ecosystems vary across Linux distributions, +so there is no one set of instructions that will work for every Linux user. +These instructions are written for Ubuntu 22.04. +They are largely copied from the [script][1] used to configure our Docker +container for continuous integration. +That script handles many more responsibilities. +These instructions are just the bare minimum to build one configuration of +rippled. +You can check that codebase for other Linux distributions and versions. +If you cannot find yours there, +then we hope that these instructions can at least guide you in the right +direction. + +``` +apt update +apt install --yes curl git libssl-dev python3.10-dev python3-pip make g++-11 libprotobuf-dev protobuf-compiler + +curl --location --remote-name \ + "https://github.com/Kitware/CMake/releases/download/v3.25.1/cmake-3.25.1.tar.gz" +tar -xzf cmake-3.25.1.tar.gz +rm cmake-3.25.1.tar.gz +cd cmake-3.25.1 +./bootstrap --parallel=$(nproc) +make --jobs $(nproc) +make install +cd .. + +pip3 install 'conan<2' +``` + +[1]: https://github.com/thejohnfreeman/rippled-docker/blob/master/ubuntu-22.04/install.sh + + +## macOS + +Open a Terminal and enter the below command to bring up a dialog to install +the command line developer tools. +Once it is finished, this command should return a version greater than the +minimum required (see [BUILD.md][]). + +``` +clang --version +``` + +The command line developer tools should include Git too: + +``` +git --version +``` + +Install [Homebrew][], +use it to install [pyenv][], +use it to install Python, +and use it to install Conan: + +[Homebrew]: https://brew.sh/ +[pyenv]: https://github.com/pyenv/pyenv + +``` +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +brew update +brew install xz +brew install pyenv +pyenv install 3.10-dev +pyenv global 3.10-dev +eval "$(pyenv init -)" +pip install 'conan<2' +``` + +Install CMake with Homebrew too: + +``` +brew install cmake +``` diff --git a/docs/build/install.md b/docs/build/install.md new file mode 100644 index 00000000000..af0d6f335c0 --- /dev/null +++ b/docs/build/install.md @@ -0,0 +1,159 @@ +This document contains instructions for installing rippled. +The APT package manager is common on Debian-based Linux distributions like +Ubuntu, +while the YUM package manager is common on Red Hat-based Linux distributions +like CentOS. +Installing from source is an option for all platforms, +and the only supported option for installing custom builds. + + +## From source + +From a source build, you can install rippled and libxrpl using CMake's +`--install` mode: + +``` +cmake --install . --prefix /opt/local +``` + +The default [prefix][1] is typically `/usr/local` on Linux and macOS and +`C:/Program Files/rippled` on Windows. + +[1]: https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html + + +## With the APT package manager + +1. Update repositories: + + sudo apt update -y + +2. Install utilities: + + sudo apt install -y apt-transport-https ca-certificates wget gnupg + +3. Add Ripple's package-signing GPG key to your list of trusted keys: + + sudo mkdir /usr/local/share/keyrings/ + wget -q -O - "https://repos.ripple.com/repos/api/gpg/key/public" | gpg --dearmor > ripple-key.gpg + sudo mv ripple-key.gpg /usr/local/share/keyrings + + +4. Check the fingerprint of the newly-added key: + + gpg /usr/local/share/keyrings/ripple-key.gpg + + The output should include an entry for Ripple such as the following: + + gpg: WARNING: no command supplied. Trying to guess what you mean ... + pub rsa3072 2019-02-14 [SC] [expires: 2026-02-17] + C0010EC205B35A3310DC90DE395F97FFCCAFD9A2 + uid TechOps Team at Ripple + sub rsa3072 2019-02-14 [E] [expires: 2026-02-17] + + + In particular, make sure that the fingerprint matches. (In the above example, the fingerprint is on the third line, starting with `C001`.) + +4. Add the appropriate Ripple repository for your operating system version: + + echo "deb [signed-by=/usr/local/share/keyrings/ripple-key.gpg] https://repos.ripple.com/repos/rippled-deb focal stable" | \ + sudo tee -a /etc/apt/sources.list.d/ripple.list + + The above example is appropriate for **Ubuntu 20.04 Focal Fossa**. For other operating systems, replace the word `focal` with one of the following: + + - `jammy` for **Ubuntu 22.04 Jammy Jellyfish** + - `bionic` for **Ubuntu 18.04 Bionic Beaver** + - `bullseye` for **Debian 11 Bullseye** + - `buster` for **Debian 10 Buster** + + If you want access to development or pre-release versions of `rippled`, use one of the following instead of `stable`: + + - `unstable` - Pre-release builds ([`release` branch](https://github.com/ripple/rippled/tree/release)) + - `nightly` - Experimental/development builds ([`develop` branch](https://github.com/ripple/rippled/tree/develop)) + + **Warning:** Unstable and nightly builds may be broken at any time. Do not use these builds for production servers. + +5. Fetch the Ripple repository. + + sudo apt -y update + +6. Install the `rippled` software package: + + sudo apt -y install rippled + +7. Check the status of the `rippled` service: + + systemctl status rippled.service + + The `rippled` service should start automatically. If not, you can start it manually: + + sudo systemctl start rippled.service + +8. Optional: allow `rippled` to bind to privileged ports. + + This allows you to serve incoming API requests on port 80 or 443. (If you want to do so, you must also update the config file's port settings.) + + sudo setcap 'cap_net_bind_service=+ep' /opt/ripple/bin/rippled + + +## With the YUM package manager + +1. Install the Ripple RPM repository: + + Choose the appropriate RPM repository for the stability of releases you want: + + - `stable` for the latest production release (`master` branch) + - `unstable` for pre-release builds (`release` branch) + - `nightly` for experimental/development builds (`develop` branch) + + *Stable* + + cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo + [ripple-stable] + name=XRP Ledger Packages + enabled=1 + gpgcheck=0 + repo_gpgcheck=1 + baseurl=https://repos.ripple.com/repos/rippled-rpm/stable/ + gpgkey=https://repos.ripple.com/repos/rippled-rpm/stable/repodata/repomd.xml.key + REPOFILE + + *Unstable* + + cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo + [ripple-unstable] + name=XRP Ledger Packages + enabled=1 + gpgcheck=0 + repo_gpgcheck=1 + baseurl=https://repos.ripple.com/repos/rippled-rpm/unstable/ + gpgkey=https://repos.ripple.com/repos/rippled-rpm/unstable/repodata/repomd.xml.key + REPOFILE + + *Nightly* + + cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo + [ripple-nightly] + name=XRP Ledger Packages + enabled=1 + gpgcheck=0 + repo_gpgcheck=1 + baseurl=https://repos.ripple.com/repos/rippled-rpm/nightly/ + gpgkey=https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key + REPOFILE + +2. Fetch the latest repo updates: + + sudo yum -y update + +3. Install the new `rippled` package: + + sudo yum install -y rippled + +4. Configure the `rippled` service to start on boot: + + sudo systemctl enable rippled.service + +5. Start the `rippled` service: + + sudo systemctl start rippled.service diff --git a/docs/consensus.md b/docs/consensus.md index 1423786b0db..4ee5aa70dca 100644 --- a/docs/consensus.md +++ b/docs/consensus.md @@ -4,7 +4,7 @@ Consensus is the task of reaching agreement within a distributed system in the presence of faulty or even malicious participants. This document outlines the -[Ripple Consensus Algorithm](https://ripple.com/files/ripple/consensus/whitepaper.pdf) +[XRP Ledger Consensus Algorithm](https://arxiv.org/abs/1802.07242) as implemented in [rippled](https://github.com/ripple/rippled), but focuses on its utility as a generic consensus algorithm independent of the detailed mechanics of the Ripple Consensus Ledger. Most notably, the algorithm @@ -469,7 +469,7 @@ struct Ledger // Whether the ledger's close time was a non-trivial consensus result bool closeAgree() const; - // The close time resolution used in determing the close time + // The close time resolution used in determining the close time NetClock::duration closeTimeResolution() const; // The (effective) close time, based on the closeTimeResolution @@ -558,7 +558,7 @@ struct ConsensusResult ConsensusTimer roundTime; // Indicates state in which consensus ended. Once in the accept phase - // will be either Yes or MovedOn + // will be either Yes or MovedOn or Expired ConsensusState state = ConsensusState::No; }; diff --git a/docs/images/xrp-text-mark-black-small@2x.png b/docs/images/xrp-text-mark-black-small@2x.png new file mode 100644 index 00000000000..f16a20a15ba Binary files /dev/null and b/docs/images/xrp-text-mark-black-small@2x.png differ diff --git a/docs/source.dox b/docs/source.dox deleted file mode 100644 index fb2fa12ff6e..00000000000 --- a/docs/source.dox +++ /dev/null @@ -1,400 +0,0 @@ -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- -DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = "rippled" -PROJECT_NUMBER = -PROJECT_BRIEF = C++ Library -PROJECT_LOGO = -PROJECT_LOGO = images/LogoForDocumentation.png -OUTPUT_DIRECTORY = -CREATE_SUBDIRS = NO -ALLOW_UNICODE_NAMES = NO -OUTPUT_LANGUAGE = English -BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = YES -ABBREVIATE_BRIEF = -ALWAYS_DETAILED_SEC = NO -INLINE_INHERITED_MEMB = YES -FULL_PATH_NAMES = NO -STRIP_FROM_PATH = ../src/ -STRIP_FROM_INC_PATH = -SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = YES -QT_AUTOBRIEF = NO -MULTILINE_CPP_IS_BRIEF = NO -INHERIT_DOCS = YES -SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 4 -ALIASES = -TCL_SUBST = -OPTIMIZE_OUTPUT_FOR_C = NO -OPTIMIZE_OUTPUT_JAVA = NO -OPTIMIZE_FOR_FORTRAN = NO -OPTIMIZE_OUTPUT_VHDL = NO -EXTENSION_MAPPING = -MARKDOWN_SUPPORT = YES -AUTOLINK_SUPPORT = YES -BUILTIN_STL_SUPPORT = NO -CPP_CLI_SUPPORT = NO -SIP_SUPPORT = NO -IDL_PROPERTY_SUPPORT = YES -DISTRIBUTE_GROUP_DOC = NO -GROUP_NESTED_COMPOUNDS = NO -SUBGROUPING = YES -INLINE_GROUPED_CLASSES = NO -INLINE_SIMPLE_STRUCTS = NO -TYPEDEF_HIDES_STRUCT = NO -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- -EXTRACT_ALL = YES -EXTRACT_PRIVATE = YES -EXTRACT_PACKAGE = NO -EXTRACT_STATIC = YES -EXTRACT_LOCAL_CLASSES = YES -EXTRACT_LOCAL_METHODS = YES -EXTRACT_ANON_NSPACES = NO -HIDE_UNDOC_MEMBERS = NO -HIDE_UNDOC_CLASSES = NO -HIDE_FRIEND_COMPOUNDS = NO -HIDE_IN_BODY_DOCS = NO -INTERNAL_DOCS = NO -CASE_SENSE_NAMES = YES -HIDE_SCOPE_NAMES = NO -HIDE_COMPOUND_REFERENCE= NO -SHOW_INCLUDE_FILES = NO -SHOW_GROUPED_MEMB_INC = NO -FORCE_LOCAL_INCLUDES = NO -INLINE_INFO = NO -SORT_MEMBER_DOCS = NO -SORT_BRIEF_DOCS = NO -SORT_MEMBERS_CTORS_1ST = YES -SORT_GROUP_NAMES = NO -SORT_BY_SCOPE_NAME = NO -STRICT_PROTO_MATCHING = NO -GENERATE_TODOLIST = NO -GENERATE_TESTLIST = NO -GENERATE_BUGLIST = NO -GENERATE_DEPRECATEDLIST= NO -ENABLED_SECTIONS = -MAX_INITIALIZER_LINES = 30 -SHOW_USED_FILES = NO -SHOW_FILES = NO -SHOW_NAMESPACES = NO -FILE_VERSION_FILTER = -LAYOUT_FILE = -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- -QUIET = NO -WARNINGS = YES -WARN_IF_UNDOCUMENTED = YES -WARN_IF_DOC_ERROR = YES -WARN_NO_PARAMDOC = NO -WARN_AS_ERROR = NO -WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- -INPUT = \ -\ - ../src/ripple/app/misc/TxQ.h \ - ../src/ripple/app/tx/apply.h \ - ../src/ripple/app/tx/applySteps.h \ - ../src/ripple/protocol/STObject.h \ - ../src/ripple/protocol/JsonFields.h \ - ../src/test/jtx/AbstractClient.h \ - ../src/test/jtx/JSONRPCClient.h \ - ../src/test/jtx/WSClient.h \ - ../src/ripple/consensus/Consensus.h \ - ../src/ripple/consensus/ConsensusProposal.h \ - ../src/ripple/consensus/ConsensusTypes.h \ - ../src/ripple/consensus/DisputedTx.h \ - ../src/ripple/consensus/LedgerTiming.h \ - ../src/ripple/consensus/LedgerTrie.h \ - ../src/ripple/consensus/Validations.h \ - ../src/ripple/consensus/ConsensusParms.h \ - ../src/ripple/app/consensus/RCLCxTx.h \ - ../src/ripple/app/consensus/RCLCxLedger.h \ - ../src/ripple/app/consensus/RCLConsensus.h \ - ../src/ripple/app/consensus/RCLCxPeerPos.h \ - ../src/ripple/app/tx/apply.h \ - ../src/ripple/app/tx/applySteps.h \ - ../src/ripple/app/tx/impl/InvariantCheck.h \ - ../src/ripple/app/consensus/RCLValidations.h \ - ../src/README.md \ - ../src/ripple/README.md \ - ../README.md \ - ../RELEASENOTES.md \ - ../docs/CodingStyle.md \ - ../docs/CheatSheet.md \ - ../docs/README.md \ - ../docs/sample_chart.doc \ - ../docs/HeapProfiling.md \ - ../docs/Docker.md \ - ../docs/consensus.md \ - ../Builds/macos/README.md \ - ../Builds/linux/README.md \ - ../Builds/VisualStudio2017/README.md \ - ../src/ripple/consensus/README.md \ - ../src/ripple/app/consensus/README.md \ - ../src/test/csf/README.md \ - ../src/ripple/basics/README.md \ - ../src/ripple/crypto/README.md \ - ../src/ripple/peerfinder/README.md \ - ../src/ripple/app/misc/README.md \ - ../src/ripple/app/misc/FeeEscalation.md \ - ../src/ripple/app/ledger/README.md \ - ../src/ripple/app/paths/README.md \ - ../src/ripple/app/tx/README.md \ - ../src/ripple/proto/README.md \ - ../src/ripple/shamap/README.md \ - ../src/ripple/protocol/README.md \ - ../src/ripple/json/README.md \ - ../src/ripple/json/TODO.md \ - ../src/ripple/resource/README.md \ - ../src/ripple/rpc/README.md \ - ../src/ripple/overlay/README.md \ - ../src/ripple/nodestore/README.md \ - ../src/ripple/nodestore/Benchmarks.md \ - - -INPUT_ENCODING = UTF-8 -FILE_PATTERNS = -RECURSIVE = NO -EXCLUDE = -EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = -EXCLUDE_SYMBOLS = -EXAMPLE_PATH = -EXAMPLE_PATTERNS = -EXAMPLE_RECURSIVE = NO -IMAGE_PATH = \ - ./images/ \ - ./images/consensus/ \ - ../src/test/csf/ \ - -INPUT_FILTER = -FILTER_PATTERNS = -FILTER_SOURCE_FILES = NO -FILTER_SOURCE_PATTERNS = -USE_MDFILE_AS_MAINPAGE = ../src/README.md - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- -SOURCE_BROWSER = NO -INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = YES -REFERENCED_BY_RELATION = NO -REFERENCES_RELATION = NO -REFERENCES_LINK_SOURCE = YES -SOURCE_TOOLTIPS = YES -USE_HTAGS = NO -VERBATIM_HEADERS = YES -CLANG_ASSISTED_PARSING = NO -CLANG_OPTIONS = - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- -ALPHABETICAL_INDEX = YES -COLS_IN_ALPHA_INDEX = 5 -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- -GENERATE_HTML = YES -HTML_OUTPUT = html_doc -HTML_FILE_EXTENSION = .html -HTML_HEADER = -HTML_FOOTER = -HTML_STYLESHEET = -HTML_EXTRA_STYLESHEET = -HTML_EXTRA_FILES = -HTML_COLORSTYLE_HUE = 220 -HTML_COLORSTYLE_SAT = 100 -HTML_COLORSTYLE_GAMMA = 80 -HTML_TIMESTAMP = NO -HTML_DYNAMIC_SECTIONS = NO -HTML_INDEX_NUM_ENTRIES = 100 -GENERATE_DOCSET = NO -DOCSET_FEEDNAME = "Doxygen generated docs" -DOCSET_BUNDLE_ID = org.doxygen.Project -DOCSET_PUBLISHER_ID = org.doxygen.Publisher -DOCSET_PUBLISHER_NAME = Publisher -GENERATE_HTMLHELP = NO -CHM_FILE = -HHC_LOCATION = -GENERATE_CHI = NO -CHM_INDEX_ENCODING = -BINARY_TOC = NO -TOC_EXPAND = NO -GENERATE_QHP = NO -QCH_FILE = -QHP_NAMESPACE = org.doxygen.Project -QHP_VIRTUAL_FOLDER = doc -QHP_CUST_FILTER_NAME = -QHP_CUST_FILTER_ATTRS = -QHP_SECT_FILTER_ATTRS = -QHG_LOCATION = -GENERATE_ECLIPSEHELP = NO -ECLIPSE_DOC_ID = org.doxygen.Project -DISABLE_INDEX = NO -GENERATE_TREEVIEW = NO -ENUM_VALUES_PER_LINE = 4 -TREEVIEW_WIDTH = 250 -EXT_LINKS_IN_WINDOW = NO -FORMULA_FONTSIZE = 10 -FORMULA_TRANSPARENT = YES -USE_MATHJAX = NO -MATHJAX_FORMAT = HTML-CSS -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest -MATHJAX_EXTENSIONS = -MATHJAX_CODEFILE = -SEARCHENGINE = YES -SERVER_BASED_SEARCH = NO -EXTERNAL_SEARCH = NO -SEARCHENGINE_URL = -SEARCHDATA_FILE = searchdata.xml -EXTERNAL_SEARCH_ID = -EXTRA_SEARCH_MAPPINGS = - -#--------------------------------------------------------------------------- -# Configuration options related to the LaTeX output -#--------------------------------------------------------------------------- -GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = a4 -EXTRA_PACKAGES = -LATEX_HEADER = -LATEX_FOOTER = -LATEX_EXTRA_STYLESHEET = -LATEX_EXTRA_FILES = -PDF_HYPERLINKS = YES -USE_PDFLATEX = YES -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -LATEX_SOURCE_CODE = NO -LATEX_BIB_STYLE = plain -LATEX_TIMESTAMP = NO - -#--------------------------------------------------------------------------- -# Configuration options related to the RTF output -#--------------------------------------------------------------------------- -GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = -RTF_SOURCE_CODE = NO - -#--------------------------------------------------------------------------- -# Configuration options related to the man page output -#--------------------------------------------------------------------------- -GENERATE_MAN = NO -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_SUBDIR = -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# Configuration options related to the XML output -#--------------------------------------------------------------------------- -GENERATE_XML = NO -XML_OUTPUT = temp -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# Configuration options related to the DOCBOOK output -#--------------------------------------------------------------------------- -GENERATE_DOCBOOK = NO -DOCBOOK_OUTPUT = docbook -DOCBOOK_PROGRAMLISTING = NO - -#--------------------------------------------------------------------------- -# Configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- -GENERATE_AUTOGEN_DEF = NO -GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- -ENABLE_PREPROCESSING = YES -MACRO_EXPANSION = YES -EXPAND_ONLY_PREDEF = YES -SEARCH_INCLUDES = YES -INCLUDE_PATH = ../ -INCLUDE_FILE_PATTERNS = -PREDEFINED = DOXYGEN \ - GENERATING_DOCS \ - _MSC_VER \ - NUDB_POSIX_FILE=1 - -EXPAND_AS_DEFINED = -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration options related to external references -#--------------------------------------------------------------------------- -TAGFILES = -GENERATE_TAGFILE = -ALLEXTERNALS = NO -EXTERNAL_GROUPS = YES -EXTERNAL_PAGES = YES -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- -CLASS_DIAGRAMS = NO -MSCGEN_PATH = -DIA_PATH = -HIDE_UNDOC_RELATIONS = YES -HAVE_DOT = NO -DOT_NUM_THREADS = 0 -DOT_FONTNAME = Helvetica -DOT_FONTSIZE = 10 -DOT_FONTPATH = -CLASS_GRAPH = YES -COLLABORATION_GRAPH = YES -GROUP_GRAPHS = YES -UML_LOOK = NO -UML_LIMIT_NUM_FIELDS = 10 -TEMPLATE_RELATIONS = NO -INCLUDE_GRAPH = YES -INCLUDED_BY_GRAPH = YES -CALL_GRAPH = NO -CALLER_GRAPH = NO -GRAPHICAL_HIERARCHY = YES -DIRECTORY_GRAPH = YES -DOT_IMAGE_FORMAT = png -INTERACTIVE_SVG = NO -DOT_PATH = -DOTFILE_DIRS = -MSCFILE_DIRS = -DIAFILE_DIRS = -PLANTUML_JAR_PATH = $(PLANTUML_JAR) -PLANTUML_INCLUDE_PATH = -DOT_GRAPH_MAX_NODES = 50 -MAX_DOT_GRAPH_DEPTH = 0 -DOT_TRANSPARENT = NO -DOT_MULTI_TARGETS = NO -GENERATE_LEGEND = YES -DOT_CLEANUP = YES diff --git a/examples/example/CMakeLists.txt b/examples/example/CMakeLists.txt new file mode 100644 index 00000000000..83aa24880d1 --- /dev/null +++ b/examples/example/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.21) + +set(name example) +set(version 0.1.0) + +project( + ${name} + VERSION ${version} + LANGUAGES CXX +) + +find_package(xrpl REQUIRED) + +add_executable(example) +target_sources(example PRIVATE src/example.cpp) +target_link_libraries(example PRIVATE xrpl::libxrpl) diff --git a/examples/example/conanfile.py b/examples/example/conanfile.py new file mode 100644 index 00000000000..be3750bf9e9 --- /dev/null +++ b/examples/example/conanfile.py @@ -0,0 +1,59 @@ +from conan import ConanFile, conan_version +from conan.tools.cmake import CMake, cmake_layout + +class Example(ConanFile): + + def set_name(self): + if self.name is None: + self.name = 'example' + + def set_version(self): + if self.version is None: + self.version = '0.1.0' + + license = 'ISC' + author = 'John Freeman ' + + settings = 'os', 'compiler', 'build_type', 'arch' + options = {'shared': [True, False], 'fPIC': [True, False]} + default_options = { + 'shared': False, + 'fPIC': True, + 'xrpl:xrpld': False, + } + + requires = ['xrpl/2.2.0-rc1@jfreeman/nodestore'] + generators = ['CMakeDeps', 'CMakeToolchain'] + + exports_sources = [ + 'CMakeLists.txt', + 'cmake/*', + 'external/*', + 'include/*', + 'src/*', + ] + + # For out-of-source build. + # https://docs.conan.io/en/latest/reference/build_helpers/cmake.html#configure + no_copy_source = True + + def layout(self): + cmake_layout(self) + + def config_options(self): + if self.settings.os == 'Windows': + del self.options.fPIC + + def build(self): + cmake = CMake(self) + cmake.configure(variables={'BUILD_TESTING': 'NO'}) + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + + def package_info(self): + path = f'{self.package_folder}/share/{self.name}/cpp_info.py' + with open(path, 'r') as file: + exec(file.read(), {}, {'self': self.cpp_info}) diff --git a/examples/example/src/example.cpp b/examples/example/src/example.cpp new file mode 100644 index 00000000000..8c3acdee075 --- /dev/null +++ b/examples/example/src/example.cpp @@ -0,0 +1,8 @@ +#include + +#include + +int main(int argc, char const** argv) { + std::printf("%s\n", ripple::BuildInfo::getVersionString().c_str()); + return 0; +} diff --git a/external/README.md b/external/README.md new file mode 100644 index 00000000000..c810539fd7d --- /dev/null +++ b/external/README.md @@ -0,0 +1,14 @@ +# External Conan recipes + +The subdirectories in this directory contain either copies or Conan recipes +of external libraries used by rippled. +The Conan recipes include patches we have not yet pushed upstream. + +| Folder | Upstream | Description | +|:----------------|:---------------------------------------------|:------------| +| `antithesis-sdk`| [Project](https://github.com/antithesishq/antithesis-sdk-cpp/) | [Antithesis](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html) SDK for C++ | +| `ed25519-donna` | [Project](https://github.com/floodyberry/ed25519-donna) | [Ed25519](http://ed25519.cr.yp.to/) digital signatures | +| `rocksdb` | [Recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/rocksdb) | Fast key/value database. (Supports rotational disks better than NuDB.) | +| `secp256k1` | [Project](https://github.com/bitcoin-core/secp256k1) | ECDSA digital signatures using the **secp256k1** curve | +| `snappy` | [Recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/snappy) | "Snappy" lossless compression algorithm. | +| `soci` | [Recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/soci) | Abstraction layer for database access. | diff --git a/external/antithesis-sdk/.clang-format b/external/antithesis-sdk/.clang-format new file mode 100644 index 00000000000..e871ed18b43 --- /dev/null +++ b/external/antithesis-sdk/.clang-format @@ -0,0 +1,3 @@ +--- +DisableFormat: true +SortIncludes: false diff --git a/external/antithesis-sdk/CMakeLists.txt b/external/antithesis-sdk/CMakeLists.txt new file mode 100644 index 00000000000..d2c1f536afd --- /dev/null +++ b/external/antithesis-sdk/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.25) + +# Note, version set explicitly by rippled project +project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX) + +add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h) + +# Note, both sections below created by rippled project +target_include_directories(antithesis-sdk-cpp INTERFACE + $ + $ +) + +install( + FILES antithesis_sdk.h + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) diff --git a/external/antithesis-sdk/LICENSE b/external/antithesis-sdk/LICENSE new file mode 100644 index 00000000000..90f1712ed1a --- /dev/null +++ b/external/antithesis-sdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Antithesis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/external/antithesis-sdk/README.md b/external/antithesis-sdk/README.md new file mode 100644 index 00000000000..eb0237868de --- /dev/null +++ b/external/antithesis-sdk/README.md @@ -0,0 +1,8 @@ +# Antithesis C++ SDK + +This library provides methods for C++ programs to configure the [Antithesis](https://antithesis.com) platform. It contains three kinds of functionality: +* Assertion macros that allow you to define test properties about your software or workload. +* Randomness functions for requesting both structured and unstructured randomness from the Antithesis platform. +* Lifecycle functions that inform the Antithesis environment that particular test phases or milestones have been reached. + +For general usage guidance see the [Antithesis C++ SDK Documentation](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/) diff --git a/external/antithesis-sdk/antithesis_instrumentation.h b/external/antithesis-sdk/antithesis_instrumentation.h new file mode 100644 index 00000000000..a88895d72a0 --- /dev/null +++ b/external/antithesis-sdk/antithesis_instrumentation.h @@ -0,0 +1,113 @@ +#pragma once + +/* +This header file enables code coverage instrumentation. It is distributed with the Antithesis C++ SDK. + +This header file can be used in both C and C++ programs. (The rest of the SDK works only for C++ programs.) + +You should include it in a single .cpp or .c file. + +The instructions (such as required compiler flags) and usage guidance are found at https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/. +*/ + +#include +#include +#include +#include +#include +#ifndef __cplusplus +#include +#include +#endif + +// If the libvoidstar(determ) library is present, +// pass thru trace_pc_guard related callbacks to it +typedef void (*trace_pc_guard_init_fn)(uint32_t *start, uint32_t *stop); +typedef void (*trace_pc_guard_fn)(uint32_t *guard, uint64_t edge); + +static trace_pc_guard_init_fn trace_pc_guard_init = NULL; +static trace_pc_guard_fn trace_pc_guard = NULL; +static bool did_check_libvoidstar = false; +static bool has_libvoidstar = false; + +static __attribute__((no_sanitize("coverage"))) void debug_message_out(const char *msg) { + (void)printf("%s\n", msg); + return; +} + +extern +#ifdef __cplusplus + "C" +#endif +__attribute__((no_sanitize("coverage"))) void antithesis_load_libvoidstar() { +#ifdef __cplusplus + constexpr +#endif + const char* LIB_PATH = "/usr/lib/libvoidstar.so"; + + if (did_check_libvoidstar) { + return; + } + debug_message_out("TRYING TO LOAD libvoidstar"); + did_check_libvoidstar = true; + void* shared_lib = dlopen(LIB_PATH, RTLD_NOW); + if (!shared_lib) { + debug_message_out("Can not load the Antithesis native library"); + return; + } + + void* trace_pc_guard_init_sym = dlsym(shared_lib, "__sanitizer_cov_trace_pc_guard_init"); + if (!trace_pc_guard_init_sym) { + debug_message_out("Can not forward calls to libvoidstar for __sanitizer_cov_trace_pc_guard_init"); + return; + } + + void* trace_pc_guard_sym = dlsym(shared_lib, "__sanitizer_cov_trace_pc_guard_internal"); + if (!trace_pc_guard_sym) { + debug_message_out("Can not forward calls to libvoidstar for __sanitizer_cov_trace_pc_guard"); + return; + } + + trace_pc_guard_init = (trace_pc_guard_init_fn)(trace_pc_guard_init_sym); + trace_pc_guard = (trace_pc_guard_fn)(trace_pc_guard_sym); + has_libvoidstar = true; + debug_message_out("LOADED libvoidstar"); +} + +// The following symbols are indeed reserved identifiers, since we're implementing functions defined +// in the compiler runtime. Not clear how to get Clang on board with that besides narrowly suppressing +// the warning in this case. The sample code on the CoverageSanitizer documentation page fails this +// warning! +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-identifier" +extern +#ifdef __cplusplus + "C" +#endif +void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { + debug_message_out("SDK forwarding to libvoidstar for __sanitizer_cov_trace_pc_guard_init()"); + if (!did_check_libvoidstar) { + antithesis_load_libvoidstar(); + } + if (has_libvoidstar) { + trace_pc_guard_init(start, stop); + } + return; +} + +extern +#ifdef __cplusplus + "C" +#endif +void __sanitizer_cov_trace_pc_guard( uint32_t *guard ) { + if (has_libvoidstar) { + uint64_t edge = (uint64_t)(__builtin_return_address(0)); + trace_pc_guard(guard, edge); + } else { + if (guard) { + *guard = 0; + } + } + return; +} +#pragma clang diagnostic pop diff --git a/external/antithesis-sdk/antithesis_sdk.h b/external/antithesis-sdk/antithesis_sdk.h new file mode 100644 index 00000000000..14eb292c2d5 --- /dev/null +++ b/external/antithesis-sdk/antithesis_sdk.h @@ -0,0 +1,1105 @@ +#pragma once + +// This header file contains the Antithesis C++ SDK, which enables C++ applications to integrate with the [Antithesis platform]. +// +// Documentation for the SDK is found at https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/. + +#ifndef NO_ANTITHESIS_SDK + +#if __cplusplus < 202000L + #error "The Antithesis C++ API requires C++20 or higher" + #define NO_ANTITHESIS_SDK +#endif + +#if !defined(__clang__) + #error "The Antithesis C++ API requires a clang compiler" + #define NO_ANTITHESIS_SDK +#endif + +#if __clang_major__ < 16 + #error "The Antithesis C++ API requires clang version 16 or higher" + #define NO_ANTITHESIS_SDK +#endif + +#else + +#if __cplusplus < 201700L + #error "The Antithesis C++ API (with NO_ANTITHESIS_SDK) requires C++17 or higher" +#endif + +#endif + +/***************************************************************************** + * COMMON + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +namespace antithesis { + inline const char* SDK_VERSION = "0.4.4"; + inline const char* PROTOCOL_VERSION = "1.1.0"; + + struct JSON; struct JSONArray; + typedef std::variant JSONValue; + + struct JSONArray : std::vector { + using std::vector::vector; + + template::value, bool>::type = true> + JSONArray(std::vector vals) : std::vector(vals.begin(), vals.end()) {} + }; + + struct JSON : std::map { + JSON() : std::map() {} + JSON( std::initializer_list> args) : std::map(args) {} + + JSON( std::initializer_list> args, std::vector> more_args ) : std::map(args) { + for (auto& pair : more_args) { + (*this)[pair.first] = pair.second; + } + } + }; +} + + +/***************************************************************************** + * INTERNAL HELPERS: LOCAL RANDOM + * Used in both the NO_ANTITHESIS_SDK version and when running locally + *****************************************************************************/ + +#include + +namespace antithesis::internal::random { + struct LocalRandom { + std::random_device device; + std::mt19937_64 gen; + std::uniform_int_distribution distribution; + + LocalRandom() : device(), gen(device()), distribution() {} + + uint64_t random() { +#ifdef ANTITHESIS_RANDOM_OVERRIDE + return ANTITHESIS_RANDOM_OVERRIDE(); +#else + return distribution(gen); +#endif + } + }; +} + +/***************************************************************************** + * INTERNAL HELPERS: JSON + *****************************************************************************/ + +#ifndef NO_ANTITHESIS_SDK + +#include +#include + +namespace antithesis::internal::json { + template + inline constexpr bool always_false_v = false; + + static std::ostream& operator<<(std::ostream& out, const JSON& details); + + static void escaped(std::ostream& out, const char c) { + const char HEX[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + switch (c) { + case '\t': out << "\\t"; break; + case '\b': out << "\\b"; break; + case '\n': out << "\\n"; break; + case '\f': out << "\\f"; break; + case '\r': out << "\\r"; break; + case '\"': out << "\\\""; break; + case '\\': out << "\\\\"; break; + default: + if ('\u0000' <= c && c <= '\u001F') { + out << "\\u00" << HEX[(c >> 4) & 0x0F] << HEX[c & 0x0F]; + } else { + out << c; + } + } + } + + static std::ostream& operator<<(std::ostream& out, const JSONValue& json) { + std::visit([&](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + out << '"'; + for (auto c : arg) { + escaped(out, c); + } + out << '"'; + } else if constexpr (std::is_same_v) { + out << (arg ? "true" : "false"); + } else if constexpr (std::is_same_v) { + out << '"'; + escaped(out, arg); + out << '"'; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << '"'; + for (auto str = arg; *str != '\0'; str++) { + escaped(out, *str); + } + out << '"'; + } else if constexpr (std::is_same_v) { + out << "null"; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << '['; + bool first = true; + for (auto &item : arg) { + if (!first) { + out << ','; + } + first = false; + out << item; + } + out << ']'; + } else { + static_assert(always_false_v, "non-exhaustive JSONValue visitor!"); + } + }, json); + + return out; + } + + static std::ostream& operator<<(std::ostream& out, const JSON& details) { + out << '{'; + + bool first = true; + for (auto [key, value] : details) { + if (!first) { + out << ','; + } + out << '"'; + for (auto c : key) { + escaped(out, c); + } + out << '"' << ':' << value; + first = false; + } + + out << '}'; + return out; + } +} + +#endif + +/***************************************************************************** + * INTERNAL HELPERS: HANDLERS + * Implementations for running locally and running in Antithesis + *****************************************************************************/ + +#ifndef NO_ANTITHESIS_SDK + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace antithesis::internal::handlers { + constexpr const char* const ERROR_LOG_LINE_PREFIX = "[* antithesis-sdk-cpp *]"; + constexpr const char* LIB_PATH = "/usr/lib/libvoidstar.so"; + constexpr const char* LOCAL_OUTPUT_ENVIRONMENT_VARIABLE = "ANTITHESIS_SDK_LOCAL_OUTPUT"; + + using namespace antithesis::internal::json; + + struct LibHandler { + virtual ~LibHandler() = default; + virtual void output(const char* message) const = 0; + virtual uint64_t random() = 0; + + void output(const JSON& json) const { + std::ostringstream out; + out << json; + output(out.str().c_str()); + } + }; + + struct AntithesisHandler : LibHandler { + void output(const char* message) const override { + if (message != nullptr) { + fuzz_json_data(message, strlen(message)); + fuzz_flush(); + } + } + + uint64_t random() override { + return fuzz_get_random(); + } + + static std::unique_ptr create() { + void* shared_lib = dlopen(LIB_PATH, RTLD_NOW); + if (!shared_lib) { + error("Can not load the Antithesis native library"); + return nullptr; + } + + void* fuzz_json_data = dlsym(shared_lib, "fuzz_json_data"); + if (!fuzz_json_data) { + error("Can not access symbol fuzz_json_data"); + return nullptr; + } + + void* fuzz_flush = dlsym(shared_lib, "fuzz_flush"); + if (!fuzz_flush) { + error("Can not access symbol fuzz_flush"); + return nullptr; + } + + void* fuzz_get_random = dlsym(shared_lib, "fuzz_get_random"); + if (!fuzz_get_random) { + error("Can not access symbol fuzz_get_random"); + return nullptr; + } + + return std::unique_ptr(new AntithesisHandler( + reinterpret_cast(fuzz_json_data), + reinterpret_cast(fuzz_flush), + reinterpret_cast(fuzz_get_random))); + } + + private: + typedef void (*fuzz_json_data_t)( const char* message, size_t length ); + typedef void (*fuzz_flush_t)(); + typedef uint64_t (*fuzz_get_random_t)(); + + + fuzz_json_data_t fuzz_json_data; + fuzz_flush_t fuzz_flush; + fuzz_get_random_t fuzz_get_random; + + AntithesisHandler(fuzz_json_data_t fuzz_json_data, fuzz_flush_t fuzz_flush, fuzz_get_random_t fuzz_get_random) : + fuzz_json_data(fuzz_json_data), fuzz_flush(fuzz_flush), fuzz_get_random(fuzz_get_random) {} + + static void error(const char* message) { + fprintf(stderr, "%s %s: %s\n", ERROR_LOG_LINE_PREFIX, message, dlerror()); + } + }; + + struct LocalHandler : LibHandler{ + ~LocalHandler() override { + if (file != nullptr) { + fclose(file); + } + } + + void output(const char* message) const override { + if (file != nullptr && message != nullptr) { + fprintf(file, "%s\n", message); + } + } + + uint64_t random() override { + return random_gen.random(); + } + + static std::unique_ptr create() { + return std::unique_ptr(new LocalHandler(create_internal())); + } + private: + FILE* file; + antithesis::internal::random::LocalRandom random_gen; + + LocalHandler(FILE* file): file(file), random_gen() { + } + + // If `localOutputEnvVar` is set to a non-empty path, attempt to open that path and truncate the file + // to serve as the log file of the local handler. + // Otherwise, we don't have a log file, and logging is a no-op in the local handler. + static FILE* create_internal() { + const char* path = std::getenv(LOCAL_OUTPUT_ENVIRONMENT_VARIABLE); + if (!path || !path[0]) { + return nullptr; + } + + // Open the file for writing (create if needed and possible) and truncate it + FILE* file = fopen(path, "w"); + if (file == nullptr) { + fprintf(stderr, "%s Failed to open path %s: %s\n", ERROR_LOG_LINE_PREFIX, path, strerror(errno)); + return nullptr; + } + int ret = fchmod(fileno(file), 0644); + if (ret != 0) { + fprintf(stderr, "%s Failed to set permissions for path %s: %s\n", ERROR_LOG_LINE_PREFIX, path, strerror(errno)); + fclose(file); + return nullptr; + } + + return file; + } + }; + + static std::unique_ptr init() { + struct stat stat_buf; + if (stat(LIB_PATH, &stat_buf) == 0) { + std::unique_ptr tmp = AntithesisHandler::create(); + if (!tmp) { + fprintf(stderr, "%s Failed to create handler for Antithesis library\n", ERROR_LOG_LINE_PREFIX); + exit(-1); + } + return tmp; + } else { + return LocalHandler::create(); + } + } + + inline LibHandler& get_lib_handler() { + static LibHandler* lib_handler = nullptr; + if (lib_handler == nullptr) { + lib_handler = init().release(); // Leak on exit, rather than exit-time-destructor + + JSON language_block{ + {"name", "C++"}, + {"version", __VERSION__} + }; + + JSON version_message{ + {"antithesis_sdk", JSON{ + {"language", language_block}, + {"sdk_version", SDK_VERSION}, + {"protocol_version", PROTOCOL_VERSION} + } + }}; + lib_handler->output(version_message); + } + + return *lib_handler; + } +} + +#endif + +/***************************************************************************** + * INTERNAL HELPERS: Various classes related to assertions + *****************************************************************************/ + +#ifndef NO_ANTITHESIS_SDK + +namespace antithesis::internal::assertions { + using namespace antithesis::internal::handlers; + + struct AssertionState { + uint8_t false_not_seen : 1; + uint8_t true_not_seen : 1; + uint8_t rest : 6; + + AssertionState() : false_not_seen(true), true_not_seen(true), rest(0) {} + }; + + enum AssertionType { + ALWAYS_ASSERTION, + ALWAYS_OR_UNREACHABLE_ASSERTION, + SOMETIMES_ASSERTION, + REACHABLE_ASSERTION, + UNREACHABLE_ASSERTION, + }; + + inline constexpr bool get_must_hit(AssertionType type) { + switch (type) { + case ALWAYS_ASSERTION: + case SOMETIMES_ASSERTION: + case REACHABLE_ASSERTION: + return true; + case ALWAYS_OR_UNREACHABLE_ASSERTION: + case UNREACHABLE_ASSERTION: + return false; + } + } + + inline constexpr const char* get_assert_type_string(AssertionType type) { + switch (type) { + case ALWAYS_ASSERTION: + case ALWAYS_OR_UNREACHABLE_ASSERTION: + return "always"; + case SOMETIMES_ASSERTION: + return "sometimes"; + case REACHABLE_ASSERTION: + case UNREACHABLE_ASSERTION: + return "reachability"; + } + } + + inline constexpr const char* get_display_type_string(AssertionType type) { + switch (type) { + case ALWAYS_ASSERTION: return "Always"; + case ALWAYS_OR_UNREACHABLE_ASSERTION: return "AlwaysOrUnreachable"; + case SOMETIMES_ASSERTION: return "Sometimes"; + case REACHABLE_ASSERTION: return "Reachable"; + case UNREACHABLE_ASSERTION: return "Unreachable"; + } + } + + struct LocationInfo { + const char* class_name; + const char* function_name; + const char* file_name; + const int line; + const int column; + + JSON to_json() const { + return JSON{ + {"class", class_name}, + {"function", function_name}, + {"file", file_name}, + {"begin_line", line}, + {"begin_column", column}, + }; + } + }; + + inline std::string make_key([[maybe_unused]] const char* message, const LocationInfo& location_info) { + return message; + } + + inline void assert_impl(bool cond, const char* message, const JSON& details, const LocationInfo& location_info, + bool hit, bool must_hit, const char* assert_type, const char* display_type, const char* id) { + JSON assertion{ + {"antithesis_assert", JSON{ + {"hit", hit}, + {"must_hit", must_hit}, + {"assert_type", assert_type}, + {"display_type", display_type}, + {"message", message}, + {"condition", cond}, + {"id", id}, + {"location", location_info.to_json()}, + {"details", details}, + }} + }; + antithesis::internal::handlers::get_lib_handler().output(assertion); + } + + inline void assert_raw(bool cond, const char* message, const JSON& details, + const char* class_name, const char* function_name, const char* file_name, const int line, const int column, + bool hit, bool must_hit, const char* assert_type, const char* display_type, const char* id) { + LocationInfo location_info{ class_name, function_name, file_name, line, column }; + assert_impl(cond, message, details, location_info, hit, must_hit, assert_type, display_type, id); + } + + typedef std::set CatalogEntryTracker; + + inline CatalogEntryTracker& get_catalog_entry_tracker() { + static CatalogEntryTracker catalog_entry_tracker; + return catalog_entry_tracker; + } + + struct Assertion { + AssertionState state; + AssertionType type; + const char* message; + LocationInfo location; + + Assertion(const char* message, AssertionType type, LocationInfo&& location) : + state(), type(type), message(message), location(std::move(location)) { + this->add_to_catalog(); + } + + void add_to_catalog() const { + std::string id = make_key(message, location); + CatalogEntryTracker& tracker = get_catalog_entry_tracker(); + if (!tracker.contains(id)) { + tracker.insert(id); + const bool condition = (type == REACHABLE_ASSERTION ? true : false); + const bool hit = false; + const char* assert_type = get_assert_type_string(type); + const bool must_hit = get_must_hit(type); + const char* display_type = get_display_type_string(type); + assert_impl(condition, message, {}, location, hit, must_hit, assert_type, display_type, id.c_str()); + } + } + + [[clang::always_inline]] inline void check_assertion(auto&& cond, const JSON& details) + requires requires { static_cast(std::forward(cond)); } { + #if defined(NO_ANTITHESIS_SDK) + #error "Antithesis SDK has been disabled" + #endif + if (__builtin_expect(state.false_not_seen || state.true_not_seen, false)) { + check_assertion_internal(static_cast(std::forward(cond)), details); + } + } + + private: + void check_assertion_internal(bool cond, const JSON& details) { + bool emit = false; + if (!cond && state.false_not_seen) { + emit = true; + state.false_not_seen = false; // TODO: is the race OK? + } + + if (cond && state.true_not_seen) { + emit = true; + state.true_not_seen = false; // TODO: is the race OK? + } + + if (emit) { + const bool hit = true; + const char* assert_type = get_assert_type_string(type); + const bool must_hit = get_must_hit(type); + const char* display_type = get_display_type_string(type); + std::string id = make_key(message, location); + assert_impl(cond, message, details, location, hit, must_hit, assert_type, display_type, id.c_str()); + } + } + }; + + enum GuidepostType { + GUIDEPOST_MAXIMIZE, + GUIDEPOST_MINIMIZE, + GUIDEPOST_EXPLORE, + GUIDEPOST_ALL, + GUIDEPOST_NONE + }; + + inline constexpr const char* get_guidance_type_string(GuidepostType type) { + switch (type) { + case GUIDEPOST_MAXIMIZE: + case GUIDEPOST_MINIMIZE: + return "numeric"; + case GUIDEPOST_ALL: + case GUIDEPOST_NONE: + return "boolean"; + case GUIDEPOST_EXPLORE: + return "json"; + } + } + + inline constexpr bool does_guidance_maximize(GuidepostType type) { + switch (type) { + case GUIDEPOST_MAXIMIZE: + case GUIDEPOST_ALL: + return true; + case GUIDEPOST_EXPLORE: + case GUIDEPOST_MINIMIZE: + case GUIDEPOST_NONE: + return false; + } + } + + template > + struct NumericGuidepost { + const char* message; + LocationInfo location; + GuidepostType type; + // an approximation of (left - right) / 2; contains an absolute value and a sign bit + std::pair extreme_half_gap; + + NumericGuidepost(const char* message, LocationInfo&& location, GuidepostType type) : + message(message), location(std::move(location)), type(type) { + this->add_to_catalog(); + if (type == GUIDEPOST_MAXIMIZE) { + extreme_half_gap = { std::numeric_limits::max(), false }; + } else { + extreme_half_gap = { std::numeric_limits::max(), true }; + } + } + + inline void add_to_catalog() { + std::string id = make_key(message, location); + JSON catalog{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(type)}, + {"message", message}, + {"id", id}, + {"location", location.to_json()}, + {"maximize", does_guidance_maximize(type)}, + {"hit", false} + }} + }; + get_lib_handler().output(catalog); + } + + std::pair compute_half_gap(NumericValue left, NumericValue right) { + // An extremely baroque way to compute (left - right) / 2, rounded toward 0, without overflowing or underflowing + if (std::is_integral_v) { + // If both numbers are odd then the gap doesn't change if we subtract 1 from both sides + // Also subtracting 1 from both sides won't underflow + if (left % 2 == 1 && right % 2 == 1) + return compute_half_gap( left - 1, right - 1); + // If one number is odd then we subtract 1 from the larger number + // This rounds the computation toward 0 but again won't underflow + if (left % 2 == 1 || right % 2 == 1) { + if (left > right) { + return compute_half_gap( left - 1, right ); + } else { + return compute_half_gap( left, right - 1 ); + } + } + // At this point both numbers are even, so the midpoint calculation is exact + NumericValue half_left = left / 2; + NumericValue half_right = right / 2; + NumericValue midpoint = half_left + half_right; + // This won't overflow or underflow because we're subtracting the midpoint + // We compute a positive value and a sign so that we don't have to do weird things with unsigned types + if (left > right) { + return { midpoint - right, true }; + } else { + return { right - midpoint, false }; + } + } else { + // If it's floating point we don't need to worry about overflowing, just do the arithmetic + return { left > right ? (left - right) / 2 : (right - left) / 2, left > right }; + } + } + + bool should_send_value(std::pair half_gap) { + if (this->type == GUIDEPOST_MAXIMIZE) { + if (half_gap.second && !extreme_half_gap.second) { + // we're positive and the extreme value isn't; always send back + return true; + } else if (!half_gap.second && extreme_half_gap.second) { + // we're negative and the extreme value is positive; never send back + return false; + } else if (half_gap.second && extreme_half_gap.second) { + // both positive; send back if our absolute value is at least as large + return half_gap.first >= extreme_half_gap.first; + } else { + // both negative; send back if our absolute value is at least as small + return half_gap.first <= extreme_half_gap.first; + } + } else { + if (half_gap.second && !extreme_half_gap.second) { + // we're positive and the extreme value isn't; never send back + return false; + } else if (!half_gap.second && extreme_half_gap.second) { + // we're negative and the extreme value is positive; always send back + return true; + } else if (half_gap.second && extreme_half_gap.second) { + // both positive; send back if our absolute value is at least as small + return half_gap.first <= extreme_half_gap.first; + } else { + // both negative; send back if our absolute value is at least as large + return half_gap.first >= extreme_half_gap.first; + } + } + } + + [[clang::always_inline]] inline void send_guidance(Value value) { + std::pair half_gap = compute_half_gap(value.first, value.second); + if (should_send_value(half_gap)) { + extreme_half_gap = half_gap; + std::string id = make_key(this->message, this->location); + JSON guidance{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(this->type)}, + {"message", this->message}, + {"id", id}, + {"location", this->location.to_json()}, + {"maximize", does_guidance_maximize(this->type)}, + {"guidance_data", JSON{ + { "left", value.first }, + { "right", value.second } }}, + {"hit", true} + }} + }; + get_lib_handler().output(guidance); + } + } + }; + + template + struct BooleanGuidepost { + const char* message; + LocationInfo location; + GuidepostType type; + + BooleanGuidepost(const char* message, LocationInfo&& location, GuidepostType type) : + message(message), location(std::move(location)), type(type) { + this->add_to_catalog(); + } + + inline void add_to_catalog() { + std::string id = make_key(message, location); + JSON catalog{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(type)}, + {"message", message}, + {"id", id}, + {"location", location.to_json()}, + {"maximize", does_guidance_maximize(type)}, + {"hit", false} + }} + }; + get_lib_handler().output(catalog); + } + + inline virtual void send_guidance(GuidanceType data) { + std::string id = make_key(this->message, this->location); + JSON guidance{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(this->type)}, + {"message", this->message}, + {"id", id}, + {"location", location.to_json()}, + {"maximize", does_guidance_maximize(this->type)}, + {"guidance_data", data}, + {"hit", true} + }} + }; + get_lib_handler().output(guidance); + } + }; +} + +namespace antithesis::internal { +namespace { // Anonymous namespace which is translation-unit-specific; certain symbols aren't exposed in the symbol table as a result + template + struct fixed_string { + std::array contents; + constexpr fixed_string() { + for(unsigned int i=0; i from_c_str( const char* s ) { + fixed_string it; + for(unsigned int i=0; i + fixed_string( const char (&arr)[N] ) -> fixed_string; + + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" + static constexpr size_t string_length( const char * s ) { + for(int l = 0; ; l++) + if (!s[l]) + return l; + } + #pragma clang diagnostic pop + + template + struct CatalogEntry { + [[clang::always_inline]] static inline antithesis::internal::assertions::Assertion create() { + antithesis::internal::assertions::LocationInfo location{ "", function_name.c_str(), file_name.c_str(), line, column }; + return antithesis::internal::assertions::Assertion(message.c_str(), type, std::move(location)); + } + + static inline antithesis::internal::assertions::Assertion assertion = create(); + }; + + template + struct BooleanGuidanceCatalogEntry { + [[clang::always_inline]] static inline antithesis::internal::assertions::BooleanGuidepost create() { + antithesis::internal::assertions::LocationInfo location{ "", function_name.c_str(), file_name.c_str(), line, column }; + switch (type) { + case antithesis::internal::assertions::GUIDEPOST_ALL: + case antithesis::internal::assertions::GUIDEPOST_NONE: + return antithesis::internal::assertions::BooleanGuidepost(message.c_str(), std::move(location), type); + default: + throw std::runtime_error("Can't create boolean guidepost with non-boolean type"); + } + } + + static inline antithesis::internal::assertions::BooleanGuidepost guidepost = create(); + }; + + template + struct NumericGuidanceCatalogEntry { + [[clang::always_inline]] static inline antithesis::internal::assertions::NumericGuidepost create() { + antithesis::internal::assertions::LocationInfo location{ "", function_name.c_str(), file_name.c_str(), line, column }; + switch (type) { + case antithesis::internal::assertions::GUIDEPOST_MAXIMIZE: + case antithesis::internal::assertions::GUIDEPOST_MINIMIZE: + return antithesis::internal::assertions::NumericGuidepost(message.c_str(), std::move(location), type); + default: + throw std::runtime_error("Can't create numeric guidepost with non-numeric type"); + } + } + + static inline antithesis::internal::assertions::NumericGuidepost guidepost = create(); + }; +} +} + +#endif + +/***************************************************************************** + * PUBLIC SDK: ASSERTIONS + *****************************************************************************/ + +#define _NL_1(foo) { #foo, foo } +#define _NL_2(foo, ...) { #foo, foo }, _NL_1(__VA_ARGS__) +#define _NL_3(foo, ...) { #foo, foo }, _NL_2(__VA_ARGS__) +#define _NL_4(foo, ...) { #foo, foo }, _NL_3(__VA_ARGS__) +#define _NL_5(foo, ...) { #foo, foo }, _NL_4(__VA_ARGS__) +#define _NL_6(foo, ...) { #foo, foo }, _NL_5(__VA_ARGS__) +#define _NL_7(foo, ...) { #foo, foo }, _NL_6(__VA_ARGS__) +#define _NL_8(foo, ...) { #foo, foo }, _NL_7(__VA_ARGS__) +#define _NL_9(foo, ...) { #foo, foo }, _NL_8(__VA_ARGS__) +#define _NL_10(foo, ...) { #foo, foo }, _NL_9(__VA_ARGS__) + +#define _ELEVENTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define _GET_NL(...) \ + _ELEVENTH_ARG(__VA_ARGS__, _NL_10, _NL_9, _NL_8, _NL_7, _NL_6, _NL_5, _NL_4, _NL_3, _NL_2, _NL_1) + +#define NAMED_LIST(...) { _GET_NL(__VA_ARGS__)(__VA_ARGS__) } + +#ifdef NO_ANTITHESIS_SDK + +#ifndef ANTITHESIS_SDK_ALWAYS_POLYFILL + #define ANTITHESIS_SDK_ALWAYS_POLYFILL(...) +#endif + +#ifndef ANTITHESIS_SDK_SOMETIMES_POLYFILL + #define ANTITHESIS_SDK_SOMETIMES_POLYFILL(...) +#endif + +#ifndef ANTITHESIS_SDK_ALWAYS_OR_UNREACHABLE_POLYFILL + #define ANTITHESIS_SDK_ALWAYS_OR_UNREACHABLE_POLYFILL(...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL(__VA_ARGS__) +#endif + +#define ALWAYS(cond, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL(cond, message, __VA_ARGS__) +#define ALWAYS_OR_UNREACHABLE(cond, message, ...) \ + ANTITHESIS_SDK_ALWAYS_OR_UNREACHABLE_POLYFILL(cond, message, __VA_ARGS__) +#define SOMETIMES(cond, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL(cond, message, __VA_ARGS__) +#define REACHABLE(message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL(true, message, __VA_ARGS__) +#define UNREACHABLE(message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL(false, message, __VA_ARGS__) +#define ALWAYS_GREATER_THAN(val, threshold, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL((val > threshold), message, __VA_ARGS__) +#define ALWAYS_GREATER_THAN_OR_EQUAL_TO(val, threshold, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL((val >= threshold), message, __VA_ARGS__) +#define SOMETIMES_GREATER_THAN(val, threshold, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL((val > threshold), message, __VA_ARGS__) +#define SOMETIMES_GREATER_THAN_OR_EQUAL_TO(val, threshold, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL((val >= threshold), message, __VA_ARGS__) +#define ALWAYS_LESS_THAN(val, threshold, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL((val < threshold), message, __VA_ARGS__) +#define ALWAYS_LESS_THAN_OR_EQUAL_TO(val, threshold, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL((val <= threshold), message, __VA_ARGS__) +#define SOMETIMES_LESS_THAN(val, threshold, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL((val < threshold), message, __VA_ARGS__) +#define SOMETIMES_LESS_THAN_OR_EQUAL_TO(val, threshold, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL((val <= threshold), message, __VA_ARGS__) +#define ALWAYS_SOME(pairs, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL(([&](){ \ + std::initializer_list> ps = pairs; \ + for (auto const& pair : ps) \ + if (pair.second) return true; \ + return false; }()), message, __VA_ARGS__) +#define SOMETIMES_ALL(pairs, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL(([&](){ \ + std::initializer_list> ps = pairs; \ + for (auto const& pair : ps) \ + if (!pair.second) return false; \ + return true; }()), message, __VA_ARGS__) + +#else + +#include + +#define FIXED_STRING_FROM_C_STR(s) (antithesis::internal::fixed_string::from_c_str(s)) + +#define ANTITHESIS_ASSERT_RAW(type, cond, message, ...) ( \ + antithesis::internal::CatalogEntry< \ + type, \ + antithesis::internal::fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(cond, (antithesis::JSON(__VA_ARGS__)) ) ) + +#define ALWAYS(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::ALWAYS_ASSERTION, cond, message, __VA_ARGS__) +#define ALWAYS_OR_UNREACHABLE(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::ALWAYS_OR_UNREACHABLE_ASSERTION, cond, message, __VA_ARGS__) +#define SOMETIMES(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::SOMETIMES_ASSERTION, cond, message, __VA_ARGS__) +#define REACHABLE(message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::REACHABLE_ASSERTION, true, message, __VA_ARGS__) +#define UNREACHABLE(message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::UNREACHABLE_ASSERTION, false, message, __VA_ARGS__) + +#define ANTITHESIS_NUMERIC_ASSERT_RAW(name, assertion_type, guidepost_type, left, cmp, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in " #name " must be of same type"); \ + ANTITHESIS_ASSERT_RAW(assertion_type, left cmp right, message, __VA_ARGS__ __VA_OPT__(,) {{ "left", left }, { "right", right }} ); \ + antithesis::internal::NumericGuidanceCatalogEntry< \ + decltype(left), \ + guidepost_type, \ + antithesis::internal::fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define ALWAYS_GREATER_THAN(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_GREATER_THAN, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, >, right, message, __VA_ARGS__) +#define ALWAYS_GREATER_THAN_OR_EQUAL_TO(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_GREATER_THAN_OR_EQUAL_TO, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, >=, right, message, __VA_ARGS__) +#define SOMETIMES_GREATER_THAN(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_GREATER_THAN, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, >, right, message, __VA_ARGS__) +#define SOMETIMES_GREATER_THAN_OR_EQUAL_TO(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_GREATER_THAN_OR_EQUAL_TO, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, >=, right, message, __VA_ARGS__) +#define ALWAYS_LESS_THAN(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_LESS_THAN, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, <, right, message, __VA_ARGS__) +#define ALWAYS_LESS_THAN_OR_EQUAL_TO(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_LESS_THAN_OR_EQUAL_TO, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, <=, right, message, __VA_ARGS__) +#define SOMETIMES_LESS_THAN(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_LESS_THAN, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, <, right, message, __VA_ARGS__) +#define SOMETIMES_LESS_THAN_OR_EQUAL_TO(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_LESS_THAN_OR_EQUAL_TO, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, <=, right, message, __VA_ARGS__) + +#define ALWAYS_SOME(pairs, message, ...) \ +do { \ + bool disjunction = false; \ + std::vector> vec_pairs = pairs; \ + for (std::pair pair : vec_pairs) { \ + if (pair.second) { \ + disjunction = true; \ + break; \ + } \ + } \ + ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::ALWAYS_ASSERTION, disjunction, message, __VA_ARGS__ __VA_OPT__(,) pairs); \ + antithesis::JSON json_pairs = antithesis::JSON(pairs); \ + antithesis::internal::BooleanGuidanceCatalogEntry< \ + decltype(json_pairs), \ + antithesis::internal::assertions::GUIDEPOST_NONE, \ + antithesis::internal::fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance(json_pairs); \ +} while (0) + +#define SOMETIMES_ALL(pairs, message, ...) \ +do { \ + bool conjunction = true; \ + std::vector> vec_pairs = pairs; \ + for (std::pair pair : vec_pairs) { \ + if (!pair.second) { \ + conjunction = false; \ + break; \ + } \ + } \ + ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::SOMETIMES_ASSERTION, conjunction, message, __VA_ARGS__ __VA_OPT__(,) pairs); \ + antithesis::JSON json_pairs = antithesis::JSON(pairs); \ + antithesis::internal::BooleanGuidanceCatalogEntry< \ + decltype(json_pairs), \ + antithesis::internal::assertions::GUIDEPOST_ALL, \ + antithesis::internal::fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance(json_pairs); \ +} while (0) + +#endif + +/***************************************************************************** + * PUBLIC SDK: LIFECYCLE + *****************************************************************************/ + +#ifdef NO_ANTITHESIS_SDK + +namespace antithesis { + inline void setup_complete(const JSON& details) { + } + + inline void send_event(const char* name, const JSON& details) { + } +} + +#else + +namespace antithesis { + inline void setup_complete(const JSON& details) { + JSON json{ + { "antithesis_setup", JSON{ + {"status", "complete"}, + {"details", details} + }} + }; + antithesis::internal::handlers::get_lib_handler().output(json); + } + + inline void send_event(const char* name, const JSON& details) { + JSON json = { { name, details } }; + antithesis::internal::handlers::get_lib_handler().output(json); + } +} +#endif + +/***************************************************************************** + * PUBLIC SDK: RANDOM + *****************************************************************************/ + +namespace antithesis { + // Declarations that we expose + uint64_t get_random(); +} + +#ifdef NO_ANTITHESIS_SDK + +namespace antithesis { + inline uint64_t get_random() { + static antithesis::internal::random::LocalRandom random_gen; + return random_gen.random(); + } +} + +#else + +namespace antithesis { + inline uint64_t get_random() { + return antithesis::internal::handlers::get_lib_handler().random(); + } +} + +#endif + +namespace antithesis { + template + Iter random_choice(Iter begin, Iter end) { + ssize_t num_things = end - begin; + if (num_things == 0) { + return end; + } + + uint64_t uval = get_random(); + ssize_t index = uval % num_things; + return begin + index; + } +} diff --git a/external/ed25519-donna/CMakeLists.txt b/external/ed25519-donna/CMakeLists.txt new file mode 100644 index 00000000000..418dc38326b --- /dev/null +++ b/external/ed25519-donna/CMakeLists.txt @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 3.11) + +project(ed25519 + LANGUAGES C +) + +if(PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/output/$/lib") +endif() + +if(NOT TARGET OpenSSL::SSL) + find_package(OpenSSL) +endif() + +add_library(ed25519 STATIC + ed25519.c +) +add_library(ed25519::ed25519 ALIAS ed25519) +target_link_libraries(ed25519 PUBLIC OpenSSL::SSL) + +include(GNUInstallDirs) + +#[=========================================================[ + NOTE for macos: + https://github.com/floodyberry/ed25519-donna/issues/29 + our source for ed25519-donna-portable.h has been + patched to workaround this. +#]=========================================================] +target_include_directories(ed25519 PUBLIC + $ + $ +) + +install( + TARGETS ed25519 + EXPORT ${PROJECT_NAME}-exports + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" +) +install( + EXPORT ${PROJECT_NAME}-exports + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" + FILE ${PROJECT_NAME}-targets.cmake + NAMESPACE ${PROJECT_NAME}:: +) +install( + FILES ed25519.h + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) diff --git a/src/ed25519-donna/README.md b/external/ed25519-donna/README.md similarity index 100% rename from src/ed25519-donna/README.md rename to external/ed25519-donna/README.md diff --git a/src/ed25519-donna/curve25519-donna-32bit.h b/external/ed25519-donna/curve25519-donna-32bit.h similarity index 100% rename from src/ed25519-donna/curve25519-donna-32bit.h rename to external/ed25519-donna/curve25519-donna-32bit.h diff --git a/src/ed25519-donna/curve25519-donna-64bit.h b/external/ed25519-donna/curve25519-donna-64bit.h similarity index 100% rename from src/ed25519-donna/curve25519-donna-64bit.h rename to external/ed25519-donna/curve25519-donna-64bit.h diff --git a/src/ed25519-donna/curve25519-donna-helpers.h b/external/ed25519-donna/curve25519-donna-helpers.h similarity index 100% rename from src/ed25519-donna/curve25519-donna-helpers.h rename to external/ed25519-donna/curve25519-donna-helpers.h diff --git a/src/ed25519-donna/curve25519-donna-sse2.h b/external/ed25519-donna/curve25519-donna-sse2.h similarity index 100% rename from src/ed25519-donna/curve25519-donna-sse2.h rename to external/ed25519-donna/curve25519-donna-sse2.h diff --git a/src/ed25519-donna/ed25519-donna-32bit-sse2.h b/external/ed25519-donna/ed25519-donna-32bit-sse2.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-32bit-sse2.h rename to external/ed25519-donna/ed25519-donna-32bit-sse2.h diff --git a/src/ed25519-donna/ed25519-donna-32bit-tables.h b/external/ed25519-donna/ed25519-donna-32bit-tables.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-32bit-tables.h rename to external/ed25519-donna/ed25519-donna-32bit-tables.h diff --git a/src/ed25519-donna/ed25519-donna-64bit-sse2.h b/external/ed25519-donna/ed25519-donna-64bit-sse2.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-64bit-sse2.h rename to external/ed25519-donna/ed25519-donna-64bit-sse2.h diff --git a/src/ed25519-donna/ed25519-donna-64bit-tables.h b/external/ed25519-donna/ed25519-donna-64bit-tables.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-64bit-tables.h rename to external/ed25519-donna/ed25519-donna-64bit-tables.h diff --git a/src/ed25519-donna/ed25519-donna-64bit-x86-32bit.h b/external/ed25519-donna/ed25519-donna-64bit-x86-32bit.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-64bit-x86-32bit.h rename to external/ed25519-donna/ed25519-donna-64bit-x86-32bit.h diff --git a/src/ed25519-donna/ed25519-donna-64bit-x86.h b/external/ed25519-donna/ed25519-donna-64bit-x86.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-64bit-x86.h rename to external/ed25519-donna/ed25519-donna-64bit-x86.h diff --git a/src/ed25519-donna/ed25519-donna-basepoint-table.h b/external/ed25519-donna/ed25519-donna-basepoint-table.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-basepoint-table.h rename to external/ed25519-donna/ed25519-donna-basepoint-table.h diff --git a/src/ed25519-donna/ed25519-donna-batchverify.h b/external/ed25519-donna/ed25519-donna-batchverify.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-batchverify.h rename to external/ed25519-donna/ed25519-donna-batchverify.h diff --git a/src/ed25519-donna/ed25519-donna-impl-base.h b/external/ed25519-donna/ed25519-donna-impl-base.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-impl-base.h rename to external/ed25519-donna/ed25519-donna-impl-base.h diff --git a/src/ed25519-donna/ed25519-donna-impl-sse2.h b/external/ed25519-donna/ed25519-donna-impl-sse2.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-impl-sse2.h rename to external/ed25519-donna/ed25519-donna-impl-sse2.h diff --git a/src/ed25519-donna/ed25519-donna-portable-identify.h b/external/ed25519-donna/ed25519-donna-portable-identify.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-portable-identify.h rename to external/ed25519-donna/ed25519-donna-portable-identify.h diff --git a/src/ed25519-donna/ed25519-donna-portable.h b/external/ed25519-donna/ed25519-donna-portable.h similarity index 100% rename from src/ed25519-donna/ed25519-donna-portable.h rename to external/ed25519-donna/ed25519-donna-portable.h diff --git a/src/ed25519-donna/ed25519-donna.h b/external/ed25519-donna/ed25519-donna.h similarity index 100% rename from src/ed25519-donna/ed25519-donna.h rename to external/ed25519-donna/ed25519-donna.h diff --git a/src/ed25519-donna/ed25519-hash-custom.h b/external/ed25519-donna/ed25519-hash-custom.h similarity index 100% rename from src/ed25519-donna/ed25519-hash-custom.h rename to external/ed25519-donna/ed25519-hash-custom.h diff --git a/src/ed25519-donna/ed25519-hash.h b/external/ed25519-donna/ed25519-hash.h similarity index 100% rename from src/ed25519-donna/ed25519-hash.h rename to external/ed25519-donna/ed25519-hash.h diff --git a/src/ed25519-donna/ed25519-randombytes-custom.h b/external/ed25519-donna/ed25519-randombytes-custom.h similarity index 100% rename from src/ed25519-donna/ed25519-randombytes-custom.h rename to external/ed25519-donna/ed25519-randombytes-custom.h diff --git a/src/ed25519-donna/ed25519-randombytes.h b/external/ed25519-donna/ed25519-randombytes.h similarity index 100% rename from src/ed25519-donna/ed25519-randombytes.h rename to external/ed25519-donna/ed25519-randombytes.h diff --git a/src/ed25519-donna/ed25519.c b/external/ed25519-donna/ed25519.c similarity index 100% rename from src/ed25519-donna/ed25519.c rename to external/ed25519-donna/ed25519.c diff --git a/src/ed25519-donna/ed25519.h b/external/ed25519-donna/ed25519.h similarity index 100% rename from src/ed25519-donna/ed25519.h rename to external/ed25519-donna/ed25519.h diff --git a/src/ed25519-donna/fuzz/README.md b/external/ed25519-donna/fuzz/README.md similarity index 100% rename from src/ed25519-donna/fuzz/README.md rename to external/ed25519-donna/fuzz/README.md diff --git a/src/ed25519-donna/fuzz/build-nix.php b/external/ed25519-donna/fuzz/build-nix.php similarity index 100% rename from src/ed25519-donna/fuzz/build-nix.php rename to external/ed25519-donna/fuzz/build-nix.php diff --git a/src/ed25519-donna/fuzz/curve25519-ref10.c b/external/ed25519-donna/fuzz/curve25519-ref10.c similarity index 100% rename from src/ed25519-donna/fuzz/curve25519-ref10.c rename to external/ed25519-donna/fuzz/curve25519-ref10.c diff --git a/src/ed25519-donna/fuzz/curve25519-ref10.h b/external/ed25519-donna/fuzz/curve25519-ref10.h similarity index 100% rename from src/ed25519-donna/fuzz/curve25519-ref10.h rename to external/ed25519-donna/fuzz/curve25519-ref10.h diff --git a/src/ed25519-donna/fuzz/ed25519-donna-sse2.c b/external/ed25519-donna/fuzz/ed25519-donna-sse2.c similarity index 100% rename from src/ed25519-donna/fuzz/ed25519-donna-sse2.c rename to external/ed25519-donna/fuzz/ed25519-donna-sse2.c diff --git a/src/ed25519-donna/fuzz/ed25519-donna.c b/external/ed25519-donna/fuzz/ed25519-donna.c similarity index 100% rename from src/ed25519-donna/fuzz/ed25519-donna.c rename to external/ed25519-donna/fuzz/ed25519-donna.c diff --git a/src/ed25519-donna/fuzz/ed25519-donna.h b/external/ed25519-donna/fuzz/ed25519-donna.h similarity index 100% rename from src/ed25519-donna/fuzz/ed25519-donna.h rename to external/ed25519-donna/fuzz/ed25519-donna.h diff --git a/src/ed25519-donna/fuzz/ed25519-ref10.c b/external/ed25519-donna/fuzz/ed25519-ref10.c similarity index 100% rename from src/ed25519-donna/fuzz/ed25519-ref10.c rename to external/ed25519-donna/fuzz/ed25519-ref10.c diff --git a/src/ed25519-donna/fuzz/ed25519-ref10.h b/external/ed25519-donna/fuzz/ed25519-ref10.h similarity index 100% rename from src/ed25519-donna/fuzz/ed25519-ref10.h rename to external/ed25519-donna/fuzz/ed25519-ref10.h diff --git a/src/ed25519-donna/fuzz/fuzz-curve25519.c b/external/ed25519-donna/fuzz/fuzz-curve25519.c similarity index 100% rename from src/ed25519-donna/fuzz/fuzz-curve25519.c rename to external/ed25519-donna/fuzz/fuzz-curve25519.c diff --git a/src/ed25519-donna/fuzz/fuzz-ed25519.c b/external/ed25519-donna/fuzz/fuzz-ed25519.c similarity index 100% rename from src/ed25519-donna/fuzz/fuzz-ed25519.c rename to external/ed25519-donna/fuzz/fuzz-ed25519.c diff --git a/src/ed25519-donna/modm-donna-32bit.h b/external/ed25519-donna/modm-donna-32bit.h similarity index 100% rename from src/ed25519-donna/modm-donna-32bit.h rename to external/ed25519-donna/modm-donna-32bit.h diff --git a/src/ed25519-donna/modm-donna-64bit.h b/external/ed25519-donna/modm-donna-64bit.h similarity index 100% rename from src/ed25519-donna/modm-donna-64bit.h rename to external/ed25519-donna/modm-donna-64bit.h diff --git a/src/ed25519-donna/regression.h b/external/ed25519-donna/regression.h similarity index 100% rename from src/ed25519-donna/regression.h rename to external/ed25519-donna/regression.h diff --git a/src/ed25519-donna/test-internals.c b/external/ed25519-donna/test-internals.c similarity index 100% rename from src/ed25519-donna/test-internals.c rename to external/ed25519-donna/test-internals.c diff --git a/src/ed25519-donna/test-ticks.h b/external/ed25519-donna/test-ticks.h similarity index 100% rename from src/ed25519-donna/test-ticks.h rename to external/ed25519-donna/test-ticks.h diff --git a/src/ed25519-donna/test.c b/external/ed25519-donna/test.c similarity index 100% rename from src/ed25519-donna/test.c rename to external/ed25519-donna/test.c diff --git a/external/nudb/conandata.yml b/external/nudb/conandata.yml new file mode 100644 index 00000000000..721129f88e7 --- /dev/null +++ b/external/nudb/conandata.yml @@ -0,0 +1,10 @@ +sources: + "2.0.8": + url: "https://github.com/CPPAlliance/NuDB/archive/2.0.8.tar.gz" + sha256: "9b71903d8ba111cd893ab064b9a8b6ac4124ed8bd6b4f67250205bc43c7f13a8" +patches: + "2.0.8": + - patch_file: "patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch" + patch_description: "Fix build for MSVC by including stdexcept" + patch_type: "portability" + patch_source: "https://github.com/cppalliance/NuDB/pull/100/files" diff --git a/external/nudb/conanfile.py b/external/nudb/conanfile.py new file mode 100644 index 00000000000..a046e2ba898 --- /dev/null +++ b/external/nudb/conanfile.py @@ -0,0 +1,72 @@ +import os + +from conan import ConanFile +from conan.tools.build import check_min_cppstd +from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get +from conan.tools.layout import basic_layout + +required_conan_version = ">=1.52.0" + + +class NudbConan(ConanFile): + name = "nudb" + description = "A fast key/value insert-only database for SSD drives in C++11" + license = "BSL-1.0" + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://github.com/CPPAlliance/NuDB" + topics = ("header-only", "KVS", "insert-only") + + package_type = "header-library" + settings = "os", "arch", "compiler", "build_type" + no_copy_source = True + + @property + def _min_cppstd(self): + return 11 + + def export_sources(self): + export_conandata_patches(self) + + def layout(self): + basic_layout(self, src_folder="src") + + def requirements(self): + self.requires("boost/1.83.0") + + def package_id(self): + self.info.clear() + + def validate(self): + if self.settings.compiler.cppstd: + check_min_cppstd(self, self._min_cppstd) + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def build(self): + apply_conandata_patches(self) + + def package(self): + copy(self, "LICENSE*", + dst=os.path.join(self.package_folder, "licenses"), + src=self.source_folder) + copy(self, "*", + dst=os.path.join(self.package_folder, "include"), + src=os.path.join(self.source_folder, "include")) + + def package_info(self): + self.cpp_info.bindirs = [] + self.cpp_info.libdirs = [] + + self.cpp_info.set_property("cmake_target_name", "NuDB") + self.cpp_info.set_property("cmake_target_aliases", ["NuDB::nudb"]) + self.cpp_info.set_property("cmake_find_mode", "both") + + self.cpp_info.components["core"].set_property("cmake_target_name", "nudb") + self.cpp_info.components["core"].names["cmake_find_package"] = "nudb" + self.cpp_info.components["core"].names["cmake_find_package_multi"] = "nudb" + self.cpp_info.components["core"].requires = ["boost::thread", "boost::system"] + + # TODO: to remove in conan v2 once cmake_find_package_* generators removed + self.cpp_info.names["cmake_find_package"] = "NuDB" + self.cpp_info.names["cmake_find_package_multi"] = "NuDB" diff --git a/external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch b/external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch new file mode 100644 index 00000000000..2d5264f3ce4 --- /dev/null +++ b/external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch @@ -0,0 +1,24 @@ +diff --git a/include/nudb/detail/stream.hpp b/include/nudb/detail/stream.hpp +index 6c07bf1..e0ce8ed 100644 +--- a/include/nudb/detail/stream.hpp ++++ b/include/nudb/detail/stream.hpp +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + namespace nudb { + namespace detail { +diff --git a/include/nudb/impl/context.ipp b/include/nudb/impl/context.ipp +index beb7058..ffde0b3 100644 +--- a/include/nudb/impl/context.ipp ++++ b/include/nudb/impl/context.ipp +@@ -9,6 +9,7 @@ + #define NUDB_IMPL_CONTEXT_IPP + + #include ++#include + + namespace nudb { + diff --git a/external/rocksdb/conandata.yml b/external/rocksdb/conandata.yml new file mode 100644 index 00000000000..7d7a575d980 --- /dev/null +++ b/external/rocksdb/conandata.yml @@ -0,0 +1,12 @@ +sources: + "9.7.3": + url: "https://github.com/facebook/rocksdb/archive/refs/tags/v9.7.3.tar.gz" + sha256: "acfabb989cbfb5b5c4d23214819b059638193ec33dad2d88373c46448d16d38b" +patches: + "9.7.3": + - patch_file: "patches/9.x.x-0001-exclude-thirdparty.patch" + patch_description: "Do not include thirdparty.inc" + patch_type: "portability" + - patch_file: "patches/9.7.3-0001-memory-leak.patch" + patch_description: "Fix a leak of obsolete blob files left open until DB::Close()" + patch_type: "portability" diff --git a/external/rocksdb/conanfile.py b/external/rocksdb/conanfile.py new file mode 100644 index 00000000000..8b85ce1540d --- /dev/null +++ b/external/rocksdb/conanfile.py @@ -0,0 +1,235 @@ +import os +import glob +import shutil + +from conan import ConanFile +from conan.errors import ConanInvalidConfiguration +from conan.tools.build import check_min_cppstd +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.files import apply_conandata_patches, collect_libs, copy, export_conandata_patches, get, rm, rmdir +from conan.tools.microsoft import check_min_vs, is_msvc, is_msvc_static_runtime +from conan.tools.scm import Version + +required_conan_version = ">=1.53.0" + + +class RocksDBConan(ConanFile): + name = "rocksdb" + description = "A library that provides an embeddable, persistent key-value store for fast storage" + license = ("GPL-2.0-only", "Apache-2.0") + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://github.com/facebook/rocksdb" + topics = ("database", "leveldb", "facebook", "key-value") + package_type = "library" + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + "lite": [True, False], + "with_gflags": [True, False], + "with_snappy": [True, False], + "with_lz4": [True, False], + "with_zlib": [True, False], + "with_zstd": [True, False], + "with_tbb": [True, False], + "with_jemalloc": [True, False], + "enable_sse": [False, "sse42", "avx2"], + "use_rtti": [True, False], + } + default_options = { + "shared": False, + "fPIC": True, + "lite": False, + "with_snappy": False, + "with_lz4": False, + "with_zlib": False, + "with_zstd": False, + "with_gflags": False, + "with_tbb": False, + "with_jemalloc": False, + "enable_sse": False, + "use_rtti": False, + } + + @property + def _min_cppstd(self): + return "11" if Version(self.version) < "8.8.1" else "17" + + @property + def _compilers_minimum_version(self): + return {} if self._min_cppstd == "11" else { + "apple-clang": "10", + "clang": "7", + "gcc": "7", + "msvc": "191", + "Visual Studio": "15", + } + + def export_sources(self): + export_conandata_patches(self) + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + if self.settings.arch != "x86_64": + del self.options.with_tbb + if self.settings.build_type == "Debug": + self.options.use_rtti = True # Rtti are used in asserts for debug mode... + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def layout(self): + cmake_layout(self, src_folder="src") + + def requirements(self): + if self.options.with_gflags: + self.requires("gflags/2.2.2") + if self.options.with_snappy: + self.requires("snappy/1.1.10") + if self.options.with_lz4: + self.requires("lz4/1.10.0") + if self.options.with_zlib: + self.requires("zlib/[>=1.2.11 <2]") + if self.options.with_zstd: + self.requires("zstd/1.5.6") + if self.options.get_safe("with_tbb"): + self.requires("onetbb/2021.12.0") + if self.options.with_jemalloc: + self.requires("jemalloc/5.3.0") + + def validate(self): + if self.settings.compiler.get_safe("cppstd"): + check_min_cppstd(self, self._min_cppstd) + + minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False) + if minimum_version and Version(self.settings.compiler.version) < minimum_version: + raise ConanInvalidConfiguration( + f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support." + ) + + if self.settings.arch not in ["x86_64", "ppc64le", "ppc64", "mips64", "armv8"]: + raise ConanInvalidConfiguration("Rocksdb requires 64 bits") + + check_min_vs(self, "191") + + if self.version == "6.20.3" and \ + self.settings.os == "Linux" and \ + self.settings.compiler == "gcc" and \ + Version(self.settings.compiler.version) < "5": + raise ConanInvalidConfiguration("Rocksdb 6.20.3 is not compilable with gcc <5.") # See https://github.com/facebook/rocksdb/issues/3522 + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def generate(self): + tc = CMakeToolchain(self) + tc.variables["FAIL_ON_WARNINGS"] = False + tc.variables["WITH_TESTS"] = False + tc.variables["WITH_TOOLS"] = False + tc.variables["WITH_CORE_TOOLS"] = False + tc.variables["WITH_BENCHMARK_TOOLS"] = False + tc.variables["WITH_FOLLY_DISTRIBUTED_MUTEX"] = False + if is_msvc(self): + tc.variables["WITH_MD_LIBRARY"] = not is_msvc_static_runtime(self) + tc.variables["ROCKSDB_INSTALL_ON_WINDOWS"] = self.settings.os == "Windows" + tc.variables["ROCKSDB_LITE"] = self.options.lite + tc.variables["WITH_GFLAGS"] = self.options.with_gflags + tc.variables["WITH_SNAPPY"] = self.options.with_snappy + tc.variables["WITH_LZ4"] = self.options.with_lz4 + tc.variables["WITH_ZLIB"] = self.options.with_zlib + tc.variables["WITH_ZSTD"] = self.options.with_zstd + tc.variables["WITH_TBB"] = self.options.get_safe("with_tbb", False) + tc.variables["WITH_JEMALLOC"] = self.options.with_jemalloc + tc.variables["ROCKSDB_BUILD_SHARED"] = self.options.shared + tc.variables["ROCKSDB_LIBRARY_EXPORTS"] = self.settings.os == "Windows" and self.options.shared + tc.variables["ROCKSDB_DLL" ] = self.settings.os == "Windows" and self.options.shared + tc.variables["USE_RTTI"] = self.options.use_rtti + if not bool(self.options.enable_sse): + tc.variables["PORTABLE"] = True + tc.variables["FORCE_SSE42"] = False + elif self.options.enable_sse == "sse42": + tc.variables["PORTABLE"] = True + tc.variables["FORCE_SSE42"] = True + elif self.options.enable_sse == "avx2": + tc.variables["PORTABLE"] = False + tc.variables["FORCE_SSE42"] = False + # not available yet in CCI + tc.variables["WITH_NUMA"] = False + tc.generate() + + deps = CMakeDeps(self) + if self.options.with_jemalloc: + deps.set_property("jemalloc", "cmake_file_name", "JeMalloc") + deps.set_property("jemalloc", "cmake_target_name", "JeMalloc::JeMalloc") + if self.options.with_zstd: + deps.set_property("zstd", "cmake_target_name", "zstd::zstd") + deps.generate() + + def build(self): + apply_conandata_patches(self) + cmake = CMake(self) + cmake.configure() + cmake.build() + + def _remove_static_libraries(self): + rm(self, "rocksdb.lib", os.path.join(self.package_folder, "lib")) + for lib in glob.glob(os.path.join(self.package_folder, "lib", "*.a")): + if not lib.endswith(".dll.a"): + os.remove(lib) + + def _remove_cpp_headers(self): + for path in glob.glob(os.path.join(self.package_folder, "include", "rocksdb", "*")): + if path != os.path.join(self.package_folder, "include", "rocksdb", "c.h"): + if os.path.isfile(path): + os.remove(path) + else: + shutil.rmtree(path) + + def package(self): + copy(self, "COPYING", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) + copy(self, "LICENSE*", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) + cmake = CMake(self) + cmake.install() + if self.options.shared: + self._remove_static_libraries() + self._remove_cpp_headers() # Force stable ABI for shared libraries + rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) + rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) + + def package_info(self): + cmake_target = "rocksdb-shared" if self.options.shared else "rocksdb" + self.cpp_info.set_property("cmake_file_name", "RocksDB") + self.cpp_info.set_property("cmake_target_name", f"RocksDB::{cmake_target}") + # TODO: back to global scope in conan v2 once cmake_find_package* generators removed + self.cpp_info.components["librocksdb"].libs = collect_libs(self) + if self.settings.os == "Windows": + self.cpp_info.components["librocksdb"].system_libs = ["shlwapi", "rpcrt4"] + if self.options.shared: + self.cpp_info.components["librocksdb"].defines = ["ROCKSDB_DLL"] + elif self.settings.os in ["Linux", "FreeBSD"]: + self.cpp_info.components["librocksdb"].system_libs = ["pthread", "m"] + if self.options.lite: + self.cpp_info.components["librocksdb"].defines.append("ROCKSDB_LITE") + + # TODO: to remove in conan v2 once cmake_find_package* generators removed + self.cpp_info.names["cmake_find_package"] = "RocksDB" + self.cpp_info.names["cmake_find_package_multi"] = "RocksDB" + self.cpp_info.components["librocksdb"].names["cmake_find_package"] = cmake_target + self.cpp_info.components["librocksdb"].names["cmake_find_package_multi"] = cmake_target + self.cpp_info.components["librocksdb"].set_property("cmake_target_name", f"RocksDB::{cmake_target}") + if self.options.with_gflags: + self.cpp_info.components["librocksdb"].requires.append("gflags::gflags") + if self.options.with_snappy: + self.cpp_info.components["librocksdb"].requires.append("snappy::snappy") + if self.options.with_lz4: + self.cpp_info.components["librocksdb"].requires.append("lz4::lz4") + if self.options.with_zlib: + self.cpp_info.components["librocksdb"].requires.append("zlib::zlib") + if self.options.with_zstd: + self.cpp_info.components["librocksdb"].requires.append("zstd::zstd") + if self.options.get_safe("with_tbb"): + self.cpp_info.components["librocksdb"].requires.append("onetbb::onetbb") + if self.options.with_jemalloc: + self.cpp_info.components["librocksdb"].requires.append("jemalloc::jemalloc") diff --git a/external/rocksdb/patches/9.7.3-0001-memory-leak.patch b/external/rocksdb/patches/9.7.3-0001-memory-leak.patch new file mode 100644 index 00000000000..bb086e6cb21 --- /dev/null +++ b/external/rocksdb/patches/9.7.3-0001-memory-leak.patch @@ -0,0 +1,319 @@ +diff --git a/HISTORY.md b/HISTORY.md +index 36d472229..05ad1a202 100644 +--- a/HISTORY.md ++++ b/HISTORY.md +@@ -1,6 +1,10 @@ + # Rocksdb Change Log + > NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt` + ++## 9.7.4 (10/31/2024) ++### Bug Fixes ++* Fix a leak of obsolete blob files left open until DB::Close(). This bug was introduced in version 9.4.0. ++ + ## 9.7.3 (10/16/2024) + ### Behavior Changes + * OPTIONS file to be loaded by remote worker is now preserved so that it does not get purged by the primary host. A similar technique as how we are preserving new SST files from getting purged is used for this. min_options_file_numbers_ is tracked like pending_outputs_ is tracked. +diff --git a/db/blob/blob_file_cache.cc b/db/blob/blob_file_cache.cc +index 5f340aadf..1b9faa238 100644 +--- a/db/blob/blob_file_cache.cc ++++ b/db/blob/blob_file_cache.cc +@@ -42,6 +42,7 @@ Status BlobFileCache::GetBlobFileReader( + assert(blob_file_reader); + assert(blob_file_reader->IsEmpty()); + ++ // NOTE: sharing same Cache with table_cache + const Slice key = GetSliceForKey(&blob_file_number); + + assert(cache_); +@@ -98,4 +99,13 @@ Status BlobFileCache::GetBlobFileReader( + return Status::OK(); + } + ++void BlobFileCache::Evict(uint64_t blob_file_number) { ++ // NOTE: sharing same Cache with table_cache ++ const Slice key = GetSliceForKey(&blob_file_number); ++ ++ assert(cache_); ++ ++ cache_.get()->Erase(key); ++} ++ + } // namespace ROCKSDB_NAMESPACE +diff --git a/db/blob/blob_file_cache.h b/db/blob/blob_file_cache.h +index 740e67ada..6858d012b 100644 +--- a/db/blob/blob_file_cache.h ++++ b/db/blob/blob_file_cache.h +@@ -36,6 +36,15 @@ class BlobFileCache { + uint64_t blob_file_number, + CacheHandleGuard* blob_file_reader); + ++ // Called when a blob file is obsolete to ensure it is removed from the cache ++ // to avoid effectively leaking the open file and assicated memory ++ void Evict(uint64_t blob_file_number); ++ ++ // Used to identify cache entries for blob files (not normally useful) ++ static const Cache::CacheItemHelper* GetHelper() { ++ return CacheInterface::GetBasicHelper(); ++ } ++ + private: + using CacheInterface = + BasicTypedCacheInterface; +diff --git a/db/column_family.h b/db/column_family.h +index e4b7adde8..86637736a 100644 +--- a/db/column_family.h ++++ b/db/column_family.h +@@ -401,6 +401,7 @@ class ColumnFamilyData { + SequenceNumber earliest_seq); + + TableCache* table_cache() const { return table_cache_.get(); } ++ BlobFileCache* blob_file_cache() const { return blob_file_cache_.get(); } + BlobSource* blob_source() const { return blob_source_.get(); } + + // See documentation in compaction_picker.h +diff --git a/db/db_impl/db_impl.cc b/db/db_impl/db_impl.cc +index 261593423..06573ac2e 100644 +--- a/db/db_impl/db_impl.cc ++++ b/db/db_impl/db_impl.cc +@@ -659,8 +659,9 @@ Status DBImpl::CloseHelper() { + // We need to release them before the block cache is destroyed. The block + // cache may be destroyed inside versions_.reset(), when column family data + // list is destroyed, so leaving handles in table cache after +- // versions_.reset() may cause issues. +- // Here we clean all unreferenced handles in table cache. ++ // versions_.reset() may cause issues. Here we clean all unreferenced handles ++ // in table cache, and (for certain builds/conditions) assert that no obsolete ++ // files are hanging around unreferenced (leak) in the table/blob file cache. + // Now we assume all user queries have finished, so only version set itself + // can possibly hold the blocks from block cache. After releasing unreferenced + // handles here, only handles held by version set left and inside +@@ -668,6 +669,9 @@ Status DBImpl::CloseHelper() { + // time a handle is released, we erase it from the cache too. By doing that, + // we can guarantee that after versions_.reset(), table cache is empty + // so the cache can be safely destroyed. ++#ifndef NDEBUG ++ TEST_VerifyNoObsoleteFilesCached(/*db_mutex_already_held=*/true); ++#endif // !NDEBUG + table_cache_->EraseUnRefEntries(); + + for (auto& txn_entry : recovered_transactions_) { +@@ -3227,6 +3231,8 @@ Status DBImpl::MultiGetImpl( + s = Status::Aborted(); + break; + } ++ // This could be a long-running operation ++ ROCKSDB_THREAD_YIELD_HOOK(); + } + + // Post processing (decrement reference counts and record statistics) +diff --git a/db/db_impl/db_impl.h b/db/db_impl/db_impl.h +index 5e4fa310b..ccc0abfa7 100644 +--- a/db/db_impl/db_impl.h ++++ b/db/db_impl/db_impl.h +@@ -1241,9 +1241,14 @@ class DBImpl : public DB { + static Status TEST_ValidateOptions(const DBOptions& db_options) { + return ValidateOptions(db_options); + } +- + #endif // NDEBUG + ++ // In certain configurations, verify that the table/blob file cache only ++ // contains entries for live files, to check for effective leaks of open ++ // files. This can only be called when purging of obsolete files has ++ // "settled," such as during parts of DB Close(). ++ void TEST_VerifyNoObsoleteFilesCached(bool db_mutex_already_held) const; ++ + // persist stats to column family "_persistent_stats" + void PersistStats(); + +diff --git a/db/db_impl/db_impl_debug.cc b/db/db_impl/db_impl_debug.cc +index 790a50d7a..67f5b4aaf 100644 +--- a/db/db_impl/db_impl_debug.cc ++++ b/db/db_impl/db_impl_debug.cc +@@ -9,6 +9,7 @@ + + #ifndef NDEBUG + ++#include "db/blob/blob_file_cache.h" + #include "db/column_family.h" + #include "db/db_impl/db_impl.h" + #include "db/error_handler.h" +@@ -328,5 +329,49 @@ size_t DBImpl::TEST_EstimateInMemoryStatsHistorySize() const { + InstrumentedMutexLock l(&const_cast(this)->stats_history_mutex_); + return EstimateInMemoryStatsHistorySize(); + } ++ ++void DBImpl::TEST_VerifyNoObsoleteFilesCached( ++ bool db_mutex_already_held) const { ++ // This check is somewhat expensive and obscure to make a part of every ++ // unit test in every build variety. Thus, we only enable it for ASAN builds. ++ if (!kMustFreeHeapAllocations) { ++ return; ++ } ++ ++ std::optional l; ++ if (db_mutex_already_held) { ++ mutex_.AssertHeld(); ++ } else { ++ l.emplace(&mutex_); ++ } ++ ++ std::vector live_files; ++ for (auto cfd : *versions_->GetColumnFamilySet()) { ++ if (cfd->IsDropped()) { ++ continue; ++ } ++ // Sneakily add both SST and blob files to the same list ++ cfd->current()->AddLiveFiles(&live_files, &live_files); ++ } ++ std::sort(live_files.begin(), live_files.end()); ++ ++ auto fn = [&live_files](const Slice& key, Cache::ObjectPtr, size_t, ++ const Cache::CacheItemHelper* helper) { ++ if (helper != BlobFileCache::GetHelper()) { ++ // Skip non-blob files for now ++ // FIXME: diagnose and fix the leaks of obsolete SST files revealed in ++ // unit tests. ++ return; ++ } ++ // See TableCache and BlobFileCache ++ assert(key.size() == sizeof(uint64_t)); ++ uint64_t file_number; ++ GetUnaligned(reinterpret_cast(key.data()), &file_number); ++ // Assert file is in sorted live_files ++ assert( ++ std::binary_search(live_files.begin(), live_files.end(), file_number)); ++ }; ++ table_cache_->ApplyToAllEntries(fn, {}); ++} + } // namespace ROCKSDB_NAMESPACE + #endif // NDEBUG +diff --git a/db/db_iter.cc b/db/db_iter.cc +index e02586377..bf4749eb9 100644 +--- a/db/db_iter.cc ++++ b/db/db_iter.cc +@@ -540,6 +540,8 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key, + } else { + iter_.Next(); + } ++ // This could be a long-running operation due to tombstones, etc. ++ ROCKSDB_THREAD_YIELD_HOOK(); + } while (iter_.Valid()); + + valid_ = false; +diff --git a/db/table_cache.cc b/db/table_cache.cc +index 71fc29c32..8a5be75e8 100644 +--- a/db/table_cache.cc ++++ b/db/table_cache.cc +@@ -164,6 +164,7 @@ Status TableCache::GetTableReader( + } + + Cache::Handle* TableCache::Lookup(Cache* cache, uint64_t file_number) { ++ // NOTE: sharing same Cache with BlobFileCache + Slice key = GetSliceForFileNumber(&file_number); + return cache->Lookup(key); + } +@@ -179,6 +180,7 @@ Status TableCache::FindTable( + size_t max_file_size_for_l0_meta_pin, Temperature file_temperature) { + PERF_TIMER_GUARD_WITH_CLOCK(find_table_nanos, ioptions_.clock); + uint64_t number = file_meta.fd.GetNumber(); ++ // NOTE: sharing same Cache with BlobFileCache + Slice key = GetSliceForFileNumber(&number); + *handle = cache_.Lookup(key); + TEST_SYNC_POINT_CALLBACK("TableCache::FindTable:0", +diff --git a/db/version_builder.cc b/db/version_builder.cc +index ed8ab8214..c98f53f42 100644 +--- a/db/version_builder.cc ++++ b/db/version_builder.cc +@@ -24,6 +24,7 @@ + #include + + #include "cache/cache_reservation_manager.h" ++#include "db/blob/blob_file_cache.h" + #include "db/blob/blob_file_meta.h" + #include "db/dbformat.h" + #include "db/internal_stats.h" +@@ -744,12 +745,9 @@ class VersionBuilder::Rep { + return Status::Corruption("VersionBuilder", oss.str()); + } + +- // Note: we use C++11 for now but in C++14, this could be done in a more +- // elegant way using generalized lambda capture. +- VersionSet* const vs = version_set_; +- const ImmutableCFOptions* const ioptions = ioptions_; +- +- auto deleter = [vs, ioptions](SharedBlobFileMetaData* shared_meta) { ++ auto deleter = [vs = version_set_, ioptions = ioptions_, ++ bc = cfd_ ? cfd_->blob_file_cache() ++ : nullptr](SharedBlobFileMetaData* shared_meta) { + if (vs) { + assert(ioptions); + assert(!ioptions->cf_paths.empty()); +@@ -758,6 +756,9 @@ class VersionBuilder::Rep { + vs->AddObsoleteBlobFile(shared_meta->GetBlobFileNumber(), + ioptions->cf_paths.front().path); + } ++ if (bc) { ++ bc->Evict(shared_meta->GetBlobFileNumber()); ++ } + + delete shared_meta; + }; +@@ -766,7 +767,7 @@ class VersionBuilder::Rep { + blob_file_number, blob_file_addition.GetTotalBlobCount(), + blob_file_addition.GetTotalBlobBytes(), + blob_file_addition.GetChecksumMethod(), +- blob_file_addition.GetChecksumValue(), deleter); ++ blob_file_addition.GetChecksumValue(), std::move(deleter)); + + mutable_blob_file_metas_.emplace( + blob_file_number, MutableBlobFileMetaData(std::move(shared_meta))); +diff --git a/db/version_set.h b/db/version_set.h +index 9336782b1..024f869e7 100644 +--- a/db/version_set.h ++++ b/db/version_set.h +@@ -1514,7 +1514,6 @@ class VersionSet { + void GetLiveFilesMetaData(std::vector* metadata); + + void AddObsoleteBlobFile(uint64_t blob_file_number, std::string path) { +- // TODO: Erase file from BlobFileCache? + obsolete_blob_files_.emplace_back(blob_file_number, std::move(path)); + } + +diff --git a/include/rocksdb/version.h b/include/rocksdb/version.h +index 2a19796b8..0afa2cab1 100644 +--- a/include/rocksdb/version.h ++++ b/include/rocksdb/version.h +@@ -13,7 +13,7 @@ + // minor or major version number planned for release. + #define ROCKSDB_MAJOR 9 + #define ROCKSDB_MINOR 7 +-#define ROCKSDB_PATCH 3 ++#define ROCKSDB_PATCH 4 + + // Do not use these. We made the mistake of declaring macros starting with + // double underscore. Now we have to live with our choice. We'll deprecate these +diff --git a/port/port.h b/port/port.h +index 13aa56d47..141716e5b 100644 +--- a/port/port.h ++++ b/port/port.h +@@ -19,3 +19,19 @@ + #elif defined(OS_WIN) + #include "port/win/port_win.h" + #endif ++ ++#ifdef OS_LINUX ++// A temporary hook into long-running RocksDB threads to support modifying their ++// priority etc. This should become a public API hook once the requirements ++// are better understood. ++extern "C" void RocksDbThreadYield() __attribute__((__weak__)); ++#define ROCKSDB_THREAD_YIELD_HOOK() \ ++ { \ ++ if (RocksDbThreadYield) { \ ++ RocksDbThreadYield(); \ ++ } \ ++ } ++#else ++#define ROCKSDB_THREAD_YIELD_HOOK() \ ++ {} ++#endif diff --git a/external/rocksdb/patches/9.x.x-0001-exclude-thirdparty.patch b/external/rocksdb/patches/9.x.x-0001-exclude-thirdparty.patch new file mode 100644 index 00000000000..7b5858bc1e9 --- /dev/null +++ b/external/rocksdb/patches/9.x.x-0001-exclude-thirdparty.patch @@ -0,0 +1,30 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 93b884d..b715cb6 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -106,14 +106,9 @@ endif() + include(CMakeDependentOption) + + if(MSVC) +- option(WITH_GFLAGS "build with GFlags" OFF) + option(WITH_XPRESS "build with windows built in compression" OFF) +- option(ROCKSDB_SKIP_THIRDPARTY "skip thirdparty.inc" OFF) +- +- if(NOT ROCKSDB_SKIP_THIRDPARTY) +- include(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty.inc) +- endif() +-else() ++endif() ++if(TRUE) + if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD" AND NOT CMAKE_SYSTEM_NAME MATCHES "kFreeBSD") + # FreeBSD has jemalloc as default malloc + # but it does not have all the jemalloc files in include/... +@@ -126,7 +121,7 @@ else() + endif() + endif() + +- if(MINGW) ++ if(MSVC OR MINGW) + option(WITH_GFLAGS "build with GFlags" OFF) + else() + option(WITH_GFLAGS "build with GFlags" ON) diff --git a/external/secp256k1/.cirrus.yml b/external/secp256k1/.cirrus.yml new file mode 100644 index 00000000000..81a4f043285 --- /dev/null +++ b/external/secp256k1/.cirrus.yml @@ -0,0 +1,101 @@ +env: + ### cirrus config + CIRRUS_CLONE_DEPTH: 1 + ### compiler options + HOST: + WRAPPER_CMD: + # Specific warnings can be disabled with -Wno-error=foo. + # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. + WERROR_CFLAGS: -Werror -pedantic-errors + MAKEFLAGS: -j4 + BUILD: check + ### secp256k1 config + ECMULTWINDOW: 15 + ECMULTGENKB: 22 + ASM: no + WIDEMUL: auto + WITH_VALGRIND: yes + EXTRAFLAGS: + ### secp256k1 modules + EXPERIMENTAL: no + ECDH: no + RECOVERY: no + EXTRAKEYS: no + SCHNORRSIG: no + MUSIG: no + ELLSWIFT: no + ### test options + SECP256K1_TEST_ITERS: 64 + BENCH: yes + SECP256K1_BENCH_ITERS: 2 + CTIMETESTS: yes + # Compile and run the tests + EXAMPLES: yes + +cat_logs_snippet: &CAT_LOGS + always: + cat_tests_log_script: + - cat tests.log || true + cat_noverify_tests_log_script: + - cat noverify_tests.log || true + cat_exhaustive_tests_log_script: + - cat exhaustive_tests.log || true + cat_ctime_tests_log_script: + - cat ctime_tests.log || true + cat_bench_log_script: + - cat bench.log || true + cat_config_log_script: + - cat config.log || true + cat_test_env_script: + - cat test_env.log || true + cat_ci_env_script: + - env + +linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER + env_script: + - env | tee /tmp/env + build_script: + - DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm" + - docker image prune --force # Cleanup stale layers + test_script: + - docker run --rm --mount "type=bind,src=./,dst=/ci_secp256k1" --env-file /tmp/env --replace --name "ci_secp256k1_arm" "ci_secp256k1_arm" bash -c "cd /ci_secp256k1/ && ./ci/ci.sh" + +task: + name: "ARM64: Linux (Debian stable)" + persistent_worker: + labels: + type: arm64 + env: + ECDH: yes + RECOVERY: yes + EXTRAKEYS: yes + SCHNORRSIG: yes + MUSIG: yes + ELLSWIFT: yes + matrix: + # Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU + - env: { CC: 'gcc-snapshot' } + << : *LINUX_ARM64_CONTAINER + << : *CAT_LOGS + +task: + name: "ARM64: Linux (Debian stable), Valgrind" + persistent_worker: + labels: + type: arm64 + env: + ECDH: yes + RECOVERY: yes + EXTRAKEYS: yes + SCHNORRSIG: yes + MUSIG: yes + ELLSWIFT: yes + WRAPPER_CMD: 'valgrind --error-exitcode=42' + SECP256K1_TEST_ITERS: 2 + matrix: + - env: { CC: 'gcc' } + - env: { CC: 'clang' } + - env: { CC: 'gcc-snapshot' } + - env: { CC: 'clang-snapshot' } + << : *LINUX_ARM64_CONTAINER + << : *CAT_LOGS diff --git a/external/secp256k1/.gitattributes b/external/secp256k1/.gitattributes new file mode 100644 index 00000000000..30efb2244fe --- /dev/null +++ b/external/secp256k1/.gitattributes @@ -0,0 +1,2 @@ +src/precomputed_ecmult.c linguist-generated +src/precomputed_ecmult_gen.c linguist-generated diff --git a/external/secp256k1/.gitignore b/external/secp256k1/.gitignore new file mode 100644 index 00000000000..bffba8cb2c9 --- /dev/null +++ b/external/secp256k1/.gitignore @@ -0,0 +1,67 @@ +bench +bench_ecmult +bench_internal +noverify_tests +tests +exhaustive_tests +precompute_ecmult_gen +precompute_ecmult +ctime_tests +ecdh_example +ecdsa_example +schnorr_example +ellswift_example +musig_example +*.exe +*.so +*.a +*.csv +*.log +*.trs +*.sage.py + +Makefile +configure +.libs/ +Makefile.in +aclocal.m4 +autom4te.cache/ +config.log +config.status +conftest* +*.tar.gz +*.la +libtool +.deps/ +.dirstamp +*.lo +*.o +*~ + +coverage/ +coverage.html +coverage.*.html +*.gcda +*.gcno +*.gcov + +build-aux/ar-lib +build-aux/config.guess +build-aux/config.sub +build-aux/depcomp +build-aux/install-sh +build-aux/ltmain.sh +build-aux/m4/libtool.m4 +build-aux/m4/lt~obsolete.m4 +build-aux/m4/ltoptions.m4 +build-aux/m4/ltsugar.m4 +build-aux/m4/ltversion.m4 +build-aux/missing +build-aux/compile +build-aux/test-driver +libsecp256k1.pc + +### CMake +/CMakeUserPresets.json +# Default CMake build directory. +/build diff --git a/external/secp256k1/CHANGELOG.md b/external/secp256k1/CHANGELOG.md new file mode 100644 index 00000000000..ee447c0c1c7 --- /dev/null +++ b/external/secp256k1/CHANGELOG.md @@ -0,0 +1,174 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.6.0] - 2024-11-04 + +#### Added + - New module `musig` implements the MuSig2 multisignature scheme according to the [BIP 327 specification](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). See: + - Header file `include/secp256k1_musig.h` which defines the new API. + - Document `doc/musig.md` for further notes on API usage. + - Usage example `examples/musig.c`. + - New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command. + +#### Changed + - API functions now use a significantly more robust method to clear secrets from the stack before returning. However, secret clearing remains a best-effort security measure and cannot guarantee complete removal. + - Any type `secp256k1_foo` can now be forward-declared using `typedef struct secp256k1_foo secp256k1_foo;` (or also `struct secp256k1_foo;` in C++). + - Organized CMake build artifacts into dedicated directories (`bin/` for executables, `lib/` for libraries) to improve build output structure and Windows shared library compatibility. + +#### Removed + - Removed the `secp256k1_scratch_space` struct and its associated functions `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` because the scratch space was unused in the API. + +#### ABI Compatibility +The symbols `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` were removed. +Otherwise, the library maintains backward compatibility with versions 0.3.x through 0.5.x. + +## [0.5.1] - 2024-08-01 + +#### Added + - Added usage example for an ElligatorSwift key exchange. + +#### Changed + - The default size of the precomputed table for signing was changed from 22 KiB to 86 KiB. The size can be changed with the configure option `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). + - "auto" is no longer an accepted value for the `--with-ecmult-window` and `--with-ecmult-gen-kb` configure options (this also applies to `SECP256K1_ECMULT_WINDOW_SIZE` and `SECP256K1_ECMULT_GEN_KB` in CMake). To achieve the same configuration as previously provided by the "auto" value, omit setting the configure option explicitly. + +#### Fixed + - Fixed compilation when the extrakeys module is disabled. + +#### ABI Compatibility +The ABI is backward compatible with versions 0.5.0, 0.4.x and 0.3.x. + +## [0.5.0] - 2024-05-06 + +#### Added + - New function `secp256k1_ec_pubkey_sort` that sorts public keys using lexicographic (of compressed serialization) order. + +#### Changed + - The implementation of the point multiplication algorithm used for signing and public key generation was changed, resulting in improved performance for those operations. + - The related configure option `--ecmult-gen-precision` was replaced with `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). + - This changes the supported precomputed table sizes for these operations. The new supported sizes are 2 KiB, 22 KiB, or 86 KiB (while the old supported sizes were 32 KiB, 64 KiB, or 512 KiB). + +#### ABI Compatibility +The ABI is backward compatible with versions 0.4.x and 0.3.x. + +## [0.4.1] - 2023-12-21 + +#### Changed + - The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one. + - Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`. + +#### ABI Compatibility +The ABI is backward compatible with versions 0.4.0 and 0.3.x. + +## [0.4.0] - 2023-09-04 + +#### Added + - New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them. + ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See: + - Header file `include/secp256k1_ellswift.h` which defines the new API. + - Document `doc/ellswift.md` which explains the mathematical background of the scheme. + - The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based. + - We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases). + +#### Fixed + - Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported. + +#### Changed + - When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`. + +#### ABI Compatibility +This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug. + +## [0.3.2] - 2023-05-13 +We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`. + +#### Security + - Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1. + +#### Fixed + - Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far. + +#### Changed + - Various improvements and changes to CMake builds. CMake builds remain experimental. + - Made API versioning consistent with GNU Autotools builds. + - Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library. + - Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts. + - Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake). + +#### ABI Compatibility +The ABI is compatible with versions 0.3.0 and 0.3.1. + +## [0.3.1] - 2023-04-10 +We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`. + +#### Security + - Fix "constant-timeness" issue with Clang >=14 that could leave applications using libsecp256k1 vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow and secret-dependent memory accesses in conditional moves of memory objects when libsecp256k1 is compiled with Clang >=14. + +#### Added + - Added tests against [Project Wycheproof's](https://github.com/google/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases. + +#### Changed + - Increased minimum required CMake version to 3.13. CMake builds remain experimental. + +#### ABI Compatibility +The ABI is compatible with version 0.3.0. + +## [0.3.0] - 2023-03-08 + +#### Added + - Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported. + - Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory. + - Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target. + +#### Fixed + - Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning. + +#### Changed + - Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.) + - Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization. + +#### Removed + - Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags). + +#### ABI Compatibility +Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions. + +## [0.2.0] - 2022-12-12 + +#### Added + - Added usage examples for common use cases in a new `examples/` directory. + - Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`. + - Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms. + +#### Changed + - Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`. + - The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API. + +#### Deprecated + - Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead. + - Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`. + - Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`. + +#### ABI Compatibility +Since this is the first release, we do not compare application binary interfaces. +However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version. + +## [0.1.0] - 2013-03-05 to 2021-12-25 + +This version was in fact never released. +The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). +Therefore, this version number does not uniquely identify a set of source files. + +[0.6.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.1...v0.6.0 +[0.5.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.0...v0.5.1 +[0.5.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...v0.5.0 +[0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1 +[0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0 +[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2 +[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1 +[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0 +[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0 +[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93 diff --git a/external/secp256k1/CMakeLists.txt b/external/secp256k1/CMakeLists.txt new file mode 100644 index 00000000000..041bfa3dca0 --- /dev/null +++ b/external/secp256k1/CMakeLists.txt @@ -0,0 +1,405 @@ +cmake_minimum_required(VERSION 3.16) + +#============================= +# Project / Package metadata +#============================= +project(libsecp256k1 + # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of + # the API. All changes in experimental modules are treated as + # backwards-compatible and therefore at most increase the minor version. + VERSION 0.6.0 + DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1." + HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1" + LANGUAGES C +) +enable_testing() +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +if(CMAKE_VERSION VERSION_LESS 3.21) + # Emulates CMake 3.21+ behavior. + if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(PROJECT_IS_TOP_LEVEL ON) + set(${PROJECT_NAME}_IS_TOP_LEVEL ON) + else() + set(PROJECT_IS_TOP_LEVEL OFF) + set(${PROJECT_NAME}_IS_TOP_LEVEL OFF) + endif() +endif() + +# The library version is based on libtool versioning of the ABI. The set of +# rules for updating the version can be found here: +# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +# All changes in experimental modules are treated as if they don't affect the +# interface and therefore only increase the revision. +set(${PROJECT_NAME}_LIB_VERSION_CURRENT 5) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 0) +set(${PROJECT_NAME}_LIB_VERSION_AGE 0) + +#============================= +# Language setup +#============================= +set(CMAKE_C_STANDARD 90) +set(CMAKE_C_EXTENSIONS OFF) + +#============================= +# Configurable options +#============================= +option(BUILD_SHARED_LIBS "Build shared libraries." ON) +option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF) +if(SECP256K1_DISABLE_SHARED) + set(BUILD_SHARED_LIBS OFF) +endif() + +option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL}) + +## Modules + +# We declare all options before processing them, to make sure we can express +# dependendencies while processing. +option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) +option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF) +option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON) +option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON) +option(SECP256K1_ENABLE_MODULE_MUSIG "Enable musig module." ON) +option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON) + +# Processing must be done in a topological sorting of the dependency graph +# (dependent module first). +if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1) +endif() + +if(SECP256K1_ENABLE_MODULE_MUSIG) + if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG) + message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.") + endif() + set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON) + add_compile_definitions(ENABLE_MODULE_MUSIG=1) +endif() + +if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS) + message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.") + endif() + set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON) + add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1) +endif() + +if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) + add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1) +endif() + +if(SECP256K1_ENABLE_MODULE_RECOVERY) + add_compile_definitions(ENABLE_MODULE_RECOVERY=1) +endif() + +if(SECP256K1_ENABLE_MODULE_ECDH) + add_compile_definitions(ENABLE_MODULE_ECDH=1) +endif() + +option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF) +if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS) + add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1) +endif() + +set(SECP256K1_ECMULT_WINDOW_SIZE 15 CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. The default value is a reasonable setting for desktop machines (currently 15). [default=15]") +set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24) +include(CheckStringOptionValue) +check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE) +add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}) + +set(SECP256K1_ECMULT_GEN_KB 86 CACHE STRING "The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms). Larger values result in possibly better signing or key generation performance at the cost of a larger table. Valid choices are 2, 22, 86. The default value is a reasonable setting for desktop machines (currently 86). [default=86]") +set_property(CACHE SECP256K1_ECMULT_GEN_KB PROPERTY STRINGS 2 22 86) +check_string_option_value(SECP256K1_ECMULT_GEN_KB) +if(SECP256K1_ECMULT_GEN_KB EQUAL 2) + add_compile_definitions(COMB_BLOCKS=2) + add_compile_definitions(COMB_TEETH=5) +elseif(SECP256K1_ECMULT_GEN_KB EQUAL 22) + add_compile_definitions(COMB_BLOCKS=11) + add_compile_definitions(COMB_TEETH=6) +elseif(SECP256K1_ECMULT_GEN_KB EQUAL 86) + add_compile_definitions(COMB_BLOCKS=43) + add_compile_definitions(COMB_TEETH=6) +endif() + +set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]") +set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64") +check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) +if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value) + add_compile_definitions(USE_FORCE_WIDEMUL_${widemul_upper_value}=1) +endif() +mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + +set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]") +set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32") +check_string_option_value(SECP256K1_ASM) +if(SECP256K1_ASM STREQUAL "arm32") + enable_language(ASM) + include(CheckArm32Assembly) + check_arm32_assembly() + if(HAVE_ARM32_ASM) + add_compile_definitions(USE_EXTERNAL_ASM=1) + else() + message(FATAL_ERROR "ARM32 assembly requested but not available.") + endif() +elseif(SECP256K1_ASM) + include(CheckX86_64Assembly) + check_x86_64_assembly() + if(HAVE_X86_64_ASM) + set(SECP256K1_ASM "x86_64") + add_compile_definitions(USE_ASM_X86_64=1) + elseif(SECP256K1_ASM STREQUAL "AUTO") + set(SECP256K1_ASM "OFF") + else() + message(FATAL_ERROR "x86_64 assembly requested but not available.") + endif() +endif() + +option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF) +if(NOT SECP256K1_EXPERIMENTAL) + if(SECP256K1_ASM STREQUAL "arm32") + message(FATAL_ERROR "ARM32 assembly is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.") + endif() +endif() + +set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]") +set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON") +check_string_option_value(SECP256K1_VALGRIND) +if(SECP256K1_VALGRIND) + find_package(Valgrind MODULE) + if(Valgrind_FOUND) + set(SECP256K1_VALGRIND ON) + include_directories(${Valgrind_INCLUDE_DIR}) + add_compile_definitions(VALGRIND) + elseif(SECP256K1_VALGRIND STREQUAL "AUTO") + set(SECP256K1_VALGRIND OFF) + else() + message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.") + endif() +endif() + +option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON) +option(SECP256K1_BUILD_TESTS "Build tests." ON) +option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON) +option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND}) +option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) + +# Redefine configuration flags. +# We leave assertions on, because they are only used in the examples, and we want them always on there. +if(MSVC) + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") +else() + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) + string(REGEX REPLACE "-O3( |$)" "-O2\\1" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") +endif() + +# Define custom "Coverage" build type. +set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage" CACHE STRING + "Flags used by the C compiler during \"Coverage\" builds." + FORCE +) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING + "Flags used for linking binaries during \"Coverage\" builds." + FORCE +) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING + "Flags used by the shared libraries linker during \"Coverage\" builds." + FORCE +) +mark_as_advanced( + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE +) + +if(PROJECT_IS_TOP_LEVEL) + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + set(default_build_type "RelWithDebInfo") + if(is_multi_config) + set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING + "Supported configuration types." + FORCE + ) + else() + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY + STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" + ) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING + "Choose the type of build." + FORCE + ) + endif() + endif() +endif() + +include(TryAppendCFlags) +if(MSVC) + # Keep the following commands ordered lexicographically. + try_append_c_flags(/W3) # Production quality warning level. + try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". + try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". + try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". + # Eliminate deprecation warnings for the older, less secure functions. + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +else() + # Keep the following commands ordered lexicographically. + try_append_c_flags(-pedantic) + try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers. + try_append_c_flags(-Wcast-align) # GCC >= 2.95. + try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0. + try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only. + try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. + try_append_c_flags(-Wnested-externs) + try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic. + try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. + try_append_c_flags(-Wno-unused-function) # GCC >= 3.0, -Wunused-function is implied by -Wall. + try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only. + try_append_c_flags(-Wshadow) + try_append_c_flags(-Wstrict-prototypes) + try_append_c_flags(-Wundef) +endif() + +set(CMAKE_C_VISIBILITY_PRESET hidden) + +set(print_msan_notice) +if(SECP256K1_BUILD_CTIME_TESTS) + include(CheckMemorySanitizer) + check_memory_sanitizer(msan_enabled) + if(msan_enabled) + try_append_c_flags(-fno-sanitize-memory-param-retval) + set(print_msan_notice YES) + endif() + unset(msan_enabled) +endif() + +set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +if(SECP256K1_APPEND_CFLAGS) + # Appending to this low-level rule variable is the only way to + # guarantee that the flags appear at the end of the command line. + string(APPEND CMAKE_C_COMPILE_OBJECT " ${SECP256K1_APPEND_CFLAGS}") +endif() + +set(SECP256K1_APPEND_LDFLAGS "" CACHE STRING "Linker flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +if(SECP256K1_APPEND_LDFLAGS) + # Appending to this low-level rule variable is the only way to + # guarantee that the flags appear at the end of the command line. + string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " ${SECP256K1_APPEND_LDFLAGS}") + string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}") +endif() + +if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) +endif() +if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +endif() +if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +endif() +add_subdirectory(src) +if(SECP256K1_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + +message("\n") +message("secp256k1 configure summary") +message("===========================") +message("Build artifacts:") +if(BUILD_SHARED_LIBS) + set(library_type "Shared") +else() + set(library_type "Static") +endif() + +message(" library type ........................ ${library_type}") +message("Optional modules:") +message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}") +message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}") +message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}") +message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}") +message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}") +message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}") +message("Parameters:") +message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}") +message(" ecmult gen table size ............... ${SECP256K1_ECMULT_GEN_KB} KiB") +message("Optional features:") +message(" assembly ............................ ${SECP256K1_ASM}") +message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}") +if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}") +endif() +message("Optional binaries:") +message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}") +message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}") +set(tests_status "${SECP256K1_BUILD_TESTS}") +if(CMAKE_BUILD_TYPE STREQUAL "Coverage") + set(tests_status OFF) +endif() +message(" tests ............................... ${tests_status}") +message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}") +message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}") +message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}") +message("") +if(CMAKE_CROSSCOMPILING) + set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}") +else() + set(cross_status "FALSE") +endif() +message("Cross compiling ....................... ${cross_status}") +message("Valgrind .............................. ${SECP256K1_VALGRIND}") +get_directory_property(definitions COMPILE_DEFINITIONS) +string(REPLACE ";" " " definitions "${definitions}") +message("Preprocessor defined macros ........... ${definitions}") +message("C compiler ............................ ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}, ${CMAKE_C_COMPILER}") +message("CFLAGS ................................ ${CMAKE_C_FLAGS}") +get_directory_property(compile_options COMPILE_OPTIONS) +string(REPLACE ";" " " compile_options "${compile_options}") +message("Compile options ....................... " ${compile_options}) +if(NOT is_multi_config) + message("Build type:") + message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") + string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}") +else() + message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}") + message("RelWithDebInfo configuration:") + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") + message("Debug configuration:") + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") +endif() +if(SECP256K1_APPEND_CFLAGS) + message("SECP256K1_APPEND_CFLAGS ............... ${SECP256K1_APPEND_CFLAGS}") +endif() +if(SECP256K1_APPEND_LDFLAGS) + message("SECP256K1_APPEND_LDFLAGS .............. ${SECP256K1_APPEND_LDFLAGS}") +endif() +message("") +if(print_msan_notice) + message( + "Note:\n" + " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to compile options\n" + " to avoid false positives in ctime_tests. Pass -DSECP256K1_BUILD_CTIME_TESTS=OFF to avoid this.\n" + ) +endif() +if(SECP256K1_EXPERIMENTAL) + message( + " ******\n" + " WARNING: experimental build\n" + " Experimental features do not have stable APIs or properties, and may not be safe for production use.\n" + " ******\n" + ) +endif() diff --git a/external/secp256k1/CMakePresets.json b/external/secp256k1/CMakePresets.json new file mode 100644 index 00000000000..b35cd80579f --- /dev/null +++ b/external/secp256k1/CMakePresets.json @@ -0,0 +1,19 @@ +{ + "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0}, + "version": 3, + "configurePresets": [ + { + "name": "dev-mode", + "displayName": "Development mode (intended only for developers of the library)", + "cacheVariables": { + "SECP256K1_EXPERIMENTAL": "ON", + "SECP256K1_ENABLE_MODULE_RECOVERY": "ON", + "SECP256K1_BUILD_EXAMPLES": "ON" + }, + "warnings": { + "dev": true, + "uninitialized": true + } + } + ] +} diff --git a/external/secp256k1/CONTRIBUTING.md b/external/secp256k1/CONTRIBUTING.md new file mode 100644 index 00000000000..a366d38b0ec --- /dev/null +++ b/external/secp256k1/CONTRIBUTING.md @@ -0,0 +1,108 @@ +# Contributing to libsecp256k1 + +## Scope + +libsecp256k1 is a library for elliptic curve cryptography on the curve secp256k1, not a general-purpose cryptography library. +The library primarily serves the needs of the Bitcoin Core project but provides additional functionality for the benefit of the wider Bitcoin ecosystem. + +## Adding new functionality or modules + +The libsecp256k1 project welcomes contributions in the form of new functionality or modules, provided they are within the project's scope. + +It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable. +Contributors are recommended to provide the following in addition to the new code: + +* **Specification:** + A specification can help significantly in reviewing the new code as it provides documentation and context. + It may justify various design decisions, give a motivation and outline security goals. + If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code. +* **Security Arguments:** + In addition to a defining the security goals, it should be argued that the new functionality meets these goals. + Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security. +* **Relevance Arguments:** + The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases. + +These are not the only factors taken into account when considering to add new functionality. +The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design. + +We recommend reaching out to other contributors (see [Communication Channels](#communication-channels)) and get feedback before implementing new functionality. + +## Communication channels + +Most communication about libsecp256k1 occurs on the GitHub repository: in issues, pull request or on the discussion board. + +Additionally, there is an IRC channel dedicated to libsecp256k1, with biweekly meetings (see channel topic). +The channel is `#secp256k1` on Libera Chat. +The easiest way to participate on IRC is with the web client, [web.libera.chat](https://web.libera.chat/#secp256k1). +Chat history logs can be found at https://gnusha.org/secp256k1/. + +## Contributor workflow & peer review + +The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Core's workflow and review processes described in its [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md). + +### Coding conventions + +In addition, libsecp256k1 tries to maintain the following coding conventions: + +* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Moreover, it should be possible to use the library without any heap allocations. +* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)). +* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)). +* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory. +* Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)). +* As a rule of thumb, the default values for configuration options should target standard desktop machines and align with Bitcoin Core's defaults, and the tests should mostly exercise the default configuration (see [#1549](https://github.com/bitcoin-core/secp256k1/issues/1549#issuecomment-2200559257)). + +#### Style conventions + +* Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures. +* New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting. +* The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block: + ```C + void secp256k_foo(void) { + unsigned int x; /* declaration */ + int y = 2*x; /* declaration */ + x = 17; /* statement */ + { + int a, b; /* declaration */ + a = x + y; /* statement */ + secp256k_bar(x, &b); /* statement */ + } + } + ``` +* Use `unsigned int` instead of just `unsigned`. +* Use `void *ptr` instead of `void* ptr`. +* Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h). +* User-facing comment lines in headers should be limited to 80 chars if possible. +* All identifiers in file scope should start with `secp256k1_`. +* Avoid trailing whitespace. + +### Tests + +#### Coverage + +This library aims to have full coverage of reachable lines and branches. + +To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary): + + $ ./configure --enable-coverage + +Run the tests: + + $ make check + +To create a report, `gcovr` is recommended, as it includes branch coverage reporting: + + $ gcovr --exclude 'src/bench*' --print-summary + +To create a HTML report with coloured and annotated source code: + + $ mkdir -p coverage + $ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html + +#### Exhaustive tests + +There are tests of several functions in which a small group replaces secp256k1. +These tests are *exhaustive* since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)). + +### Benchmarks + +See `src/bench*.c` for examples of benchmarks. diff --git a/src/secp256k1/COPYING b/external/secp256k1/COPYING similarity index 100% rename from src/secp256k1/COPYING rename to external/secp256k1/COPYING diff --git a/external/secp256k1/Makefile.am b/external/secp256k1/Makefile.am new file mode 100644 index 00000000000..a95b4809d48 --- /dev/null +++ b/external/secp256k1/Makefile.am @@ -0,0 +1,302 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 + +# AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo +# which does not have an explicit foo_CFLAGS variable set. +AM_CFLAGS = $(SECP_CFLAGS) + +lib_LTLIBRARIES = libsecp256k1.la +include_HEADERS = include/secp256k1.h +include_HEADERS += include/secp256k1_preallocated.h +noinst_HEADERS = +noinst_HEADERS += src/scalar.h +noinst_HEADERS += src/scalar_4x64.h +noinst_HEADERS += src/scalar_8x32.h +noinst_HEADERS += src/scalar_low.h +noinst_HEADERS += src/scalar_impl.h +noinst_HEADERS += src/scalar_4x64_impl.h +noinst_HEADERS += src/scalar_8x32_impl.h +noinst_HEADERS += src/scalar_low_impl.h +noinst_HEADERS += src/group.h +noinst_HEADERS += src/group_impl.h +noinst_HEADERS += src/ecdsa.h +noinst_HEADERS += src/ecdsa_impl.h +noinst_HEADERS += src/eckey.h +noinst_HEADERS += src/eckey_impl.h +noinst_HEADERS += src/ecmult.h +noinst_HEADERS += src/ecmult_impl.h +noinst_HEADERS += src/ecmult_compute_table.h +noinst_HEADERS += src/ecmult_compute_table_impl.h +noinst_HEADERS += src/ecmult_const.h +noinst_HEADERS += src/ecmult_const_impl.h +noinst_HEADERS += src/ecmult_gen.h +noinst_HEADERS += src/ecmult_gen_impl.h +noinst_HEADERS += src/ecmult_gen_compute_table.h +noinst_HEADERS += src/ecmult_gen_compute_table_impl.h +noinst_HEADERS += src/field_10x26.h +noinst_HEADERS += src/field_10x26_impl.h +noinst_HEADERS += src/field_5x52.h +noinst_HEADERS += src/field_5x52_impl.h +noinst_HEADERS += src/field_5x52_int128_impl.h +noinst_HEADERS += src/modinv32.h +noinst_HEADERS += src/modinv32_impl.h +noinst_HEADERS += src/modinv64.h +noinst_HEADERS += src/modinv64_impl.h +noinst_HEADERS += src/precomputed_ecmult.h +noinst_HEADERS += src/precomputed_ecmult_gen.h +noinst_HEADERS += src/assumptions.h +noinst_HEADERS += src/checkmem.h +noinst_HEADERS += src/testutil.h +noinst_HEADERS += src/util.h +noinst_HEADERS += src/int128.h +noinst_HEADERS += src/int128_impl.h +noinst_HEADERS += src/int128_native.h +noinst_HEADERS += src/int128_native_impl.h +noinst_HEADERS += src/int128_struct.h +noinst_HEADERS += src/int128_struct_impl.h +noinst_HEADERS += src/scratch.h +noinst_HEADERS += src/scratch_impl.h +noinst_HEADERS += src/selftest.h +noinst_HEADERS += src/testrand.h +noinst_HEADERS += src/testrand_impl.h +noinst_HEADERS += src/hash.h +noinst_HEADERS += src/hash_impl.h +noinst_HEADERS += src/field.h +noinst_HEADERS += src/field_impl.h +noinst_HEADERS += src/bench.h +noinst_HEADERS += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h +noinst_HEADERS += src/hsort.h +noinst_HEADERS += src/hsort_impl.h +noinst_HEADERS += contrib/lax_der_parsing.h +noinst_HEADERS += contrib/lax_der_parsing.c +noinst_HEADERS += contrib/lax_der_privatekey_parsing.h +noinst_HEADERS += contrib/lax_der_privatekey_parsing.c +noinst_HEADERS += examples/examples_util.h + +PRECOMPUTED_LIB = libsecp256k1_precomputed.la +noinst_LTLIBRARIES = $(PRECOMPUTED_LIB) +libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c +# We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree. +# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo). +libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_CONFIG_DEFINES) + +if USE_EXTERNAL_ASM +COMMON_LIB = libsecp256k1_common.la +else +COMMON_LIB = +endif +noinst_LTLIBRARIES += $(COMMON_LIB) + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libsecp256k1.pc + +if USE_EXTERNAL_ASM +if USE_ASM_ARM +libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s +endif +endif + +libsecp256k1_la_SOURCES = src/secp256k1.c +libsecp256k1_la_CPPFLAGS = $(SECP_CONFIG_DEFINES) +libsecp256k1_la_LIBADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE) + +noinst_PROGRAMS = +if USE_BENCHMARK +noinst_PROGRAMS += bench bench_internal bench_ecmult +bench_SOURCES = src/bench.c +bench_LDADD = libsecp256k1.la +bench_CPPFLAGS = $(SECP_CONFIG_DEFINES) +bench_internal_SOURCES = src/bench_internal.c +bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +bench_internal_CPPFLAGS = $(SECP_CONFIG_DEFINES) +bench_ecmult_SOURCES = src/bench_ecmult.c +bench_ecmult_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +bench_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) +endif + +TESTS = +if USE_TESTS +TESTS += noverify_tests +noinst_PROGRAMS += noverify_tests +noverify_tests_SOURCES = src/tests.c +noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) +noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +noverify_tests_LDFLAGS = -static +if !ENABLE_COVERAGE +TESTS += tests +noinst_PROGRAMS += tests +tests_SOURCES = $(noverify_tests_SOURCES) +tests_CPPFLAGS = $(noverify_tests_CPPFLAGS) -DVERIFY +tests_LDADD = $(noverify_tests_LDADD) +tests_LDFLAGS = $(noverify_tests_LDFLAGS) +endif +endif + +if USE_CTIME_TESTS +noinst_PROGRAMS += ctime_tests +ctime_tests_SOURCES = src/ctime_tests.c +ctime_tests_LDADD = libsecp256k1.la +ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) +endif + +if USE_EXHAUSTIVE_TESTS +noinst_PROGRAMS += exhaustive_tests +exhaustive_tests_SOURCES = src/tests_exhaustive.c +exhaustive_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) +if !ENABLE_COVERAGE +exhaustive_tests_CPPFLAGS += -DVERIFY +endif +# Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables). +exhaustive_tests_LDADD = $(COMMON_LIB) +exhaustive_tests_LDFLAGS = -static +TESTS += exhaustive_tests +endif + +if USE_EXAMPLES +noinst_PROGRAMS += ecdsa_example +ecdsa_example_SOURCES = examples/ecdsa.c +ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +ecdsa_example_LDADD = libsecp256k1.la +ecdsa_example_LDFLAGS = -static +if BUILD_WINDOWS +ecdsa_example_LDFLAGS += -lbcrypt +endif +TESTS += ecdsa_example +if ENABLE_MODULE_ECDH +noinst_PROGRAMS += ecdh_example +ecdh_example_SOURCES = examples/ecdh.c +ecdh_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +ecdh_example_LDADD = libsecp256k1.la +ecdh_example_LDFLAGS = -static +if BUILD_WINDOWS +ecdh_example_LDFLAGS += -lbcrypt +endif +TESTS += ecdh_example +endif +if ENABLE_MODULE_SCHNORRSIG +noinst_PROGRAMS += schnorr_example +schnorr_example_SOURCES = examples/schnorr.c +schnorr_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +schnorr_example_LDADD = libsecp256k1.la +schnorr_example_LDFLAGS = -static +if BUILD_WINDOWS +schnorr_example_LDFLAGS += -lbcrypt +endif +TESTS += schnorr_example +endif +if ENABLE_MODULE_ELLSWIFT +noinst_PROGRAMS += ellswift_example +ellswift_example_SOURCES = examples/ellswift.c +ellswift_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +ellswift_example_LDADD = libsecp256k1.la +ellswift_example_LDFLAGS = -static +if BUILD_WINDOWS +ellswift_example_LDFLAGS += -lbcrypt +endif +TESTS += ellswift_example +endif +if ENABLE_MODULE_MUSIG +noinst_PROGRAMS += musig_example +musig_example_SOURCES = examples/musig.c +musig_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +musig_example_LDADD = libsecp256k1.la +musig_example_LDFLAGS = -static +if BUILD_WINDOWS +musig_example_LDFLAGS += -lbcrypt +endif +TESTS += musig_example +endif +endif + +### Precomputed tables +EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen +CLEANFILES = $(EXTRA_PROGRAMS) + +precompute_ecmult_SOURCES = src/precompute_ecmult.c +precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY +precompute_ecmult_LDADD = $(COMMON_LIB) + +precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c +precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY +precompute_ecmult_gen_LDADD = $(COMMON_LIB) + +# See Automake manual, Section "Errors with distclean". +# We don't list any dependencies for the prebuilt files here because +# otherwise make's decision whether to rebuild them (even in the first +# build by a normal user) depends on mtimes, and thus is very fragile. +# This means that rebuilds of the prebuilt files always need to be +# forced by deleting them. +src/precomputed_ecmult.c: + $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT) + ./precompute_ecmult$(EXEEXT) +src/precomputed_ecmult_gen.c: + $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult_gen$(EXEEXT) + ./precompute_ecmult_gen$(EXEEXT) + +PRECOMP = src/precomputed_ecmult_gen.c src/precomputed_ecmult.c +precomp: $(PRECOMP) + +# Ensure the prebuilt files will be build first (only if they don't exist, +# e.g., after `make maintainer-clean`). +BUILT_SOURCES = $(PRECOMP) + +.PHONY: clean-precomp +clean-precomp: + rm -f $(PRECOMP) +maintainer-clean-local: clean-precomp + +### Pregenerated test vectors +### (see the comments in the previous section for detailed rationale) +TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h + +src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: + mkdir -p $(@D) + python3 $(top_srcdir)/tools/tests_wycheproof_generate.py $(top_srcdir)/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@ + +testvectors: $(TESTVECTORS) + +BUILT_SOURCES += $(TESTVECTORS) + +.PHONY: clean-testvectors +clean-testvectors: + rm -f $(TESTVECTORS) +maintainer-clean-local: clean-testvectors + +### Additional files to distribute +EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md +EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md +EXTRA_DIST += doc/ellswift.md doc/musig.md +EXTRA_DIST += examples/EXAMPLES_COPYING +EXTRA_DIST += sage/gen_exhaustive_groups.sage +EXTRA_DIST += sage/gen_split_lambda_constants.sage +EXTRA_DIST += sage/group_prover.sage +EXTRA_DIST += sage/prove_group_implementations.sage +EXTRA_DIST += sage/secp256k1_params.sage +EXTRA_DIST += sage/weierstrass_prover.sage +EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING +EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json +EXTRA_DIST += tools/tests_wycheproof_generate.py + +if ENABLE_MODULE_ECDH +include src/modules/ecdh/Makefile.am.include +endif + +if ENABLE_MODULE_RECOVERY +include src/modules/recovery/Makefile.am.include +endif + +if ENABLE_MODULE_EXTRAKEYS +include src/modules/extrakeys/Makefile.am.include +endif + +if ENABLE_MODULE_SCHNORRSIG +include src/modules/schnorrsig/Makefile.am.include +endif + +if ENABLE_MODULE_MUSIG +include src/modules/musig/Makefile.am.include +endif + +if ENABLE_MODULE_ELLSWIFT +include src/modules/ellswift/Makefile.am.include +endif diff --git a/external/secp256k1/README.md b/external/secp256k1/README.md new file mode 100644 index 00000000000..222e5fb7685 --- /dev/null +++ b/external/secp256k1/README.md @@ -0,0 +1,142 @@ +libsecp256k1 +============ + +![Dependencies: None](https://img.shields.io/badge/dependencies-none-success) +[![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](https://web.libera.chat/#secp256k1) + +High-performance high-assurance C library for digital signatures and other cryptographic primitives on the secp256k1 elliptic curve. + +This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose. + +Features: +* secp256k1 ECDSA signing/verification and key generation. +* Additive and multiplicative tweaking of secret/public keys. +* Serialization/parsing of secret keys, public keys, signatures. +* Constant time, constant memory access signing and public key generation. +* Derandomized ECDSA (via RFC6979 or with a caller provided function.) +* Very efficient implementation. +* Suitable for embedded systems. +* No runtime dependencies. +* Optional module for public key recovery. +* Optional module for ECDH key exchange. +* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). +* Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki). +* Optional module for MuSig2 Schnorr multi-signatures according to [BIP-327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). + +Implementation details +---------------------- + +* General + * No runtime heap allocation. + * Extensive testing infrastructure. + * Structured to facilitate review and analysis. + * Intended to be portable to any system with a C89 compiler and uint64_t support. + * No use of floating types. + * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") +* Field operations + * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). + * Using 5 52-bit limbs + * Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan). + * This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community. +* Scalar operations + * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. + * Using 4 64-bit limbs (relying on __int128 support in the compiler). + * Using 8 32-bit limbs. +* Modular inverses (both field elements and scalars) based on [safegcd](https://gcd.cr.yp.to/index.html) with some modifications, and a variable-time variant (by Peter Dettman). +* Group operations + * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). + * Use addition between points in Jacobian and affine coordinates where possible. + * Use a unified addition/doubling formula where necessary to avoid data-dependent branches. + * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space. +* Point multiplication for verification (a*P + b*G). + * Use wNAF notation for point multiplicands. + * Use a much larger window for multiples of G, using precomputed multiples. + * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. + * Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. +* Point multiplication for signing + * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. + * Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains) + * Access the table with branch-free conditional moves so memory access is uniform. + * No data-dependent branches + * Optional runtime blinding which attempts to frustrate differential power analysis. + * The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally. + +Building with Autotools +----------------------- + + $ ./autogen.sh + $ ./configure + $ make + $ make check # run the test suite + $ sudo make install # optional + +To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. + +Building with CMake (experimental) +---------------------------------- + +To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree. + +### Building on POSIX systems + + $ mkdir build && cd build + $ cmake .. + $ cmake --build . + $ ctest # run the test suite + $ sudo cmake --install . # optional + +To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags. + +### Cross compiling + +To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory. +For example, to cross compile for Windows: + + $ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-w64-mingw32.toolchain.cmake + +To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set): + + $ cmake .. -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28 + +### Building on Windows + +To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree. + +The following example assumes using of Visual Studio 2022 and CMake v3.21+. + +In "Developer Command Prompt for VS 2022": + + >cmake -G "Visual Studio 17 2022" -A x64 -S . -B build + >cmake --build build --config RelWithDebInfo + +Usage examples +----------- +Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`. + * [ECDSA example](examples/ecdsa.c) + * [Schnorr signatures example](examples/schnorr.c) + * [Deriving a shared secret (ECDH) example](examples/ecdh.c) + * [ElligatorSwift key exchange example](examples/ellswift.c) + +To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`. + +Benchmark +------------ +If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build. + +To print the benchmark result to the command line: + + $ ./bench_name + +To create a CSV file for the benchmark result : + + $ ./bench_name | sed '2d;s/ \{1,\}//g' > bench_name.csv + +Reporting a vulnerability +------------ + +See [SECURITY.md](SECURITY.md) + +Contributing to libsecp256k1 +------------ + +See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/external/secp256k1/SECURITY.md b/external/secp256k1/SECURITY.md new file mode 100644 index 00000000000..b515cc1c8e2 --- /dev/null +++ b/external/secp256k1/SECURITY.md @@ -0,0 +1,15 @@ +# Security Policy + +## Reporting a Vulnerability + +To report security issues send an email to secp256k1-security@bitcoincore.org (not for support). + +The following keys may be used to communicate sensitive information to developers: + +| Name | Fingerprint | +|------|-------------| +| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 | +| Jonas Nick | 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 | +| Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 | + +You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys ""` Ensure that you put quotes around fingerprints containing spaces. diff --git a/src/secp256k1/autogen.sh b/external/secp256k1/autogen.sh similarity index 100% rename from src/secp256k1/autogen.sh rename to external/secp256k1/autogen.sh diff --git a/external/secp256k1/build-aux/m4/bitcoin_secp.m4 b/external/secp256k1/build-aux/m4/bitcoin_secp.m4 new file mode 100644 index 00000000000..048267fa6ee --- /dev/null +++ b/external/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -0,0 +1,91 @@ +dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. +AC_DEFUN([SECP_X86_64_ASM_CHECK],[ +AC_MSG_CHECKING(for x86_64 assembly availability) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include ]],[[ + uint64_t a = 11, tmp; + __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); + ]])], [has_x86_64_asm=yes], [has_x86_64_asm=no]) +AC_MSG_RESULT([$has_x86_64_asm]) +]) + +AC_DEFUN([SECP_ARM32_ASM_CHECK], [ + AC_MSG_CHECKING(for ARM32 assembly availability) + SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS" + CFLAGS="-x assembler" + AC_LINK_IFELSE([AC_LANG_SOURCE([[ + .syntax unified + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .text + .global main + main: + ldr r0, =0x002A + mov r7, #1 + swi 0 + ]])], [has_arm32_asm=yes], [has_arm32_asm=no]) + AC_MSG_RESULT([$has_arm32_asm]) + CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS" +]) + +AC_DEFUN([SECP_VALGRIND_CHECK],[ +AC_MSG_CHECKING([for valgrind support]) +if test x"$has_valgrind" != x"yes"; then + CPPFLAGS_TEMP="$CPPFLAGS" + CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + ]], [[ + #if defined(NVALGRIND) + # error "Valgrind does not support this platform." + #endif + ]])], [has_valgrind=yes]) + CPPFLAGS="$CPPFLAGS_TEMP" +fi +AC_MSG_RESULT($has_valgrind) +]) + +AC_DEFUN([SECP_MSAN_CHECK], [ +AC_MSG_CHECKING(whether MemorySanitizer is enabled) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + /* MemorySanitizer is enabled. */ + # elif + # error "MemorySanitizer is disabled." + # endif + #else + # error "__has_feature is not defined." + #endif + ]])], [msan_enabled=yes], [msan_enabled=no]) +AC_MSG_RESULT([$msan_enabled]) +]) + +dnl SECP_TRY_APPEND_CFLAGS(flags, VAR) +dnl Append flags to VAR if CC accepts them. +AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [ + AC_MSG_CHECKING([if ${CC} supports $1]) + SECP_TRY_APPEND_CFLAGS_saved_CFLAGS="$CFLAGS" + CFLAGS="$1 $CFLAGS" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [flag_works=yes], [flag_works=no]) + AC_MSG_RESULT($flag_works) + CFLAGS="$SECP_TRY_APPEND_CFLAGS_saved_CFLAGS" + if test x"$flag_works" = x"yes"; then + $2="$$2 $1" + fi + unset flag_works + AC_SUBST($2) +]) + +dnl SECP_SET_DEFAULT(VAR, default, default-dev-mode) +dnl Set VAR to default or default-dev-mode, depending on whether dev mode is enabled +AC_DEFUN([SECP_SET_DEFAULT], [ + if test "${enable_dev_mode+set}" != set; then + AC_MSG_ERROR([[Set enable_dev_mode before calling SECP_SET_DEFAULT]]) + fi + if test x"$enable_dev_mode" = x"yes"; then + $1="$3" + else + $1="$2" + fi +]) diff --git a/external/secp256k1/ci/ci.sh b/external/secp256k1/ci/ci.sh new file mode 100755 index 00000000000..3636deafa11 --- /dev/null +++ b/external/secp256k1/ci/ci.sh @@ -0,0 +1,149 @@ +#!/bin/sh + +set -eux + +export LC_ALL=C + +# Print commit and relevant CI environment to allow reproducing the job outside of CI. +git show --no-patch +print_environment() { + # Turn off -x because it messes up the output + set +x + # There are many ways to print variable names and their content. This one + # does not rely on bash. + for var in WERROR_CFLAGS MAKEFLAGS BUILD \ + ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ + EXPERIMENTAL ECDH RECOVERY EXTRAKEYS MUSIG SCHNORRSIG ELLSWIFT \ + SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ + EXAMPLES \ + HOST WRAPPER_CMD \ + CC CFLAGS CPPFLAGS AR NM \ + UBSAN_OPTIONS ASAN_OPTIONS LSAN_OPTIONS + do + eval "isset=\${$var+x}" + if [ -n "$isset" ]; then + eval "val=\${$var}" + # shellcheck disable=SC2154 + printf '%s="%s" ' "$var" "$val" + fi + done + echo "$0" + set -x +} +print_environment + +env >> test_env.log + +# If gcc is requested, assert that it's in fact gcc (and not some symlinked Apple clang). +case "${CC:-undefined}" in + *gcc*) + $CC -v 2>&1 | grep -q "gcc version" || exit 1; + ;; +esac + +if [ -n "${CC+x}" ]; then + # The MSVC compiler "cl" doesn't understand "-v" + $CC -v || true +fi +if [ "$WITH_VALGRIND" = "yes" ]; then + valgrind --version +fi +if [ -n "$WRAPPER_CMD" ]; then + $WRAPPER_CMD --version +fi + +# Workaround for https://bugs.kde.org/show_bug.cgi?id=452758 (fixed in valgrind 3.20.0). +case "${CC:-undefined}" in + clang*) + if [ "$CTIMETESTS" = "yes" ] && [ "$WITH_VALGRIND" = "yes" ] + then + export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" + else + case "$WRAPPER_CMD" in + valgrind*) + export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" + ;; + esac + fi + ;; +esac + +./autogen.sh + +./configure \ + --enable-experimental="$EXPERIMENTAL" \ + --with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \ + --with-ecmult-window="$ECMULTWINDOW" \ + --with-ecmult-gen-kb="$ECMULTGENKB" \ + --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ + --enable-module-ellswift="$ELLSWIFT" \ + --enable-module-extrakeys="$EXTRAKEYS" \ + --enable-module-schnorrsig="$SCHNORRSIG" \ + --enable-module-musig="$MUSIG" \ + --enable-examples="$EXAMPLES" \ + --enable-ctime-tests="$CTIMETESTS" \ + --with-valgrind="$WITH_VALGRIND" \ + --host="$HOST" $EXTRAFLAGS + +# We have set "-j" in MAKEFLAGS. +build_exit_code=0 +make > make.log 2>&1 || build_exit_code=$? +cat make.log +if [ $build_exit_code -ne 0 ]; then + case "${CC:-undefined}" in + *snapshot*) + # Ignore internal compiler errors in gcc-snapshot and clang-snapshot + grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log + return $?; + ;; + *) + return 1; + ;; + esac +fi + +# Print information about binaries so that we can see that the architecture is correct +file *tests* || true +file bench* || true +file .libs/* || true + +# This tells `make check` to wrap test invocations. +export LOG_COMPILER="$WRAPPER_CMD" + +make "$BUILD" + +# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool +EXEC='./libtool --mode=execute' +if [ -n "$WRAPPER_CMD" ] +then + EXEC="$EXEC $WRAPPER_CMD" +fi + +if [ "$BENCH" = "yes" ] +then + { + $EXEC ./bench_ecmult + $EXEC ./bench_internal + $EXEC ./bench + } >> bench.log 2>&1 +fi + +if [ "$CTIMETESTS" = "yes" ] +then + if [ "$WITH_VALGRIND" = "yes" ]; then + ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1 + else + $EXEC ./ctime_tests > ctime_tests.log 2>&1 + fi +fi + +# Rebuild precomputed files (if not cross-compiling). +if [ -z "$HOST" ] +then + make clean-precomp clean-testvectors + make precomp testvectors +fi + +# Check that no repo files have been modified by the build. +# (This fails for example if the precomp files need to be updated in the repo.) +git diff --exit-code diff --git a/external/secp256k1/ci/linux-debian.Dockerfile b/external/secp256k1/ci/linux-debian.Dockerfile new file mode 100644 index 00000000000..241bfa97194 --- /dev/null +++ b/external/secp256k1/ci/linux-debian.Dockerfile @@ -0,0 +1,79 @@ +FROM debian:stable-slim + +SHELL ["/bin/bash", "-c"] + +WORKDIR /root + +# A too high maximum number of file descriptors (with the default value +# inherited from the docker host) can cause issues with some of our tools: +# - sanitizers hanging: https://github.com/google/sanitizers/issues/1662 +# - valgrind crashing: https://stackoverflow.com/a/75293014 +# This is not be a problem on our CI hosts, but developers who run the image +# on their machines may run into this (e.g., on Arch Linux), so warn them. +# (Note that .bashrc is only executed in interactive bash shells.) +RUN echo 'if [[ $(ulimit -n) -gt 200000 ]]; then echo "WARNING: Very high value reported by \"ulimit -n\". Consider passing \"--ulimit nofile=32768\" to \"docker run\"."; fi' >> /root/.bashrc + +RUN dpkg --add-architecture i386 && \ + dpkg --add-architecture s390x && \ + dpkg --add-architecture armhf && \ + dpkg --add-architecture arm64 && \ + dpkg --add-architecture ppc64el + +# dkpg-dev: to make pkg-config work in cross-builds +# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces +RUN apt-get update && apt-get install --no-install-recommends -y \ + git ca-certificates \ + make automake libtool pkg-config dpkg-dev valgrind qemu-user \ + gcc clang llvm libclang-rt-dev libc6-dbg \ + g++ \ + gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan8:i386 \ + gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \ + gcc-mingw-w64-x86-64-win32 wine64 wine \ + gcc-mingw-w64-i686-win32 wine32 \ + python3 && \ + if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \ + apt-get install --no-install-recommends -y \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\ + fi && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Build and install gcc snapshot +ARG GCC_SNAPSHOT_MAJOR=15 +RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ + mkdir gcc && cd gcc && \ + wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \ + wget "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}/sha512.sum" && \ + sha512sum --check --ignore-missing sha512.sum && \ + # We should have downloaded exactly one tar.xz file + ls && \ + [ $(ls *.tar.xz | wc -l) -eq "1" ] && \ + tar xf *.tar.xz && \ + mkdir gcc-build && cd gcc-build && \ + ../*/configure --prefix=/opt/gcc-snapshot --enable-languages=c --disable-bootstrap --disable-multilib --without-isl && \ + make -j $(nproc) && \ + make install && \ + cd ../.. && rm -rf gcc && \ + ln -s /opt/gcc-snapshot/bin/gcc /usr/bin/gcc-snapshot && \ + apt-get autoremove -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Install clang snapshot, see https://apt.llvm.org/ +RUN \ + # Setup GPG keys of LLVM repository + apt-get update && apt-get install --no-install-recommends -y wget && \ + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \ + # Add repository for this Debian release + . /etc/os-release && echo "deb http://apt.llvm.org/${VERSION_CODENAME} llvm-toolchain-${VERSION_CODENAME} main" >> /etc/apt/sources.list && \ + apt-get update && \ + # Determine the version number of the LLVM development branch + LLVM_VERSION=$(apt-cache search --names-only '^clang-[0-9]+$' | sort -V | tail -1 | cut -f1 -d" " | cut -f2 -d"-" ) && \ + # Install + apt-get install --no-install-recommends -y "clang-${LLVM_VERSION}" && \ + # Create symlink + ln -s "/usr/bin/clang-${LLVM_VERSION}" /usr/bin/clang-snapshot && \ + # Clean up + apt-get autoremove -y wget && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + diff --git a/external/secp256k1/cmake/CheckArm32Assembly.cmake b/external/secp256k1/cmake/CheckArm32Assembly.cmake new file mode 100644 index 00000000000..baeeff02923 --- /dev/null +++ b/external/secp256k1/cmake/CheckArm32Assembly.cmake @@ -0,0 +1,6 @@ +function(check_arm32_assembly) + try_compile(HAVE_ARM32_ASM + ${PROJECT_BINARY_DIR}/check_arm32_assembly + SOURCES ${PROJECT_SOURCE_DIR}/cmake/source_arm32.s + ) +endfunction() diff --git a/external/secp256k1/cmake/CheckMemorySanitizer.cmake b/external/secp256k1/cmake/CheckMemorySanitizer.cmake new file mode 100644 index 00000000000..d9ef681e658 --- /dev/null +++ b/external/secp256k1/cmake/CheckMemorySanitizer.cmake @@ -0,0 +1,18 @@ +include_guard(GLOBAL) +include(CheckCSourceCompiles) + +function(check_memory_sanitizer output) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_c_source_compiles(" + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + /* MemorySanitizer is enabled. */ + # elif + # error \"MemorySanitizer is disabled.\" + # endif + #else + # error \"__has_feature is not defined.\" + #endif + " HAVE_MSAN) + set(${output} ${HAVE_MSAN} PARENT_SCOPE) +endfunction() diff --git a/external/secp256k1/cmake/CheckStringOptionValue.cmake b/external/secp256k1/cmake/CheckStringOptionValue.cmake new file mode 100644 index 00000000000..5a4d939b9e8 --- /dev/null +++ b/external/secp256k1/cmake/CheckStringOptionValue.cmake @@ -0,0 +1,10 @@ +function(check_string_option_value option) + get_property(expected_values CACHE ${option} PROPERTY STRINGS) + if(expected_values) + if(${option} IN_LIST expected_values) + return() + endif() + message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.") + endif() + message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.") +endfunction() diff --git a/external/secp256k1/cmake/CheckX86_64Assembly.cmake b/external/secp256k1/cmake/CheckX86_64Assembly.cmake new file mode 100644 index 00000000000..ae82cd476e8 --- /dev/null +++ b/external/secp256k1/cmake/CheckX86_64Assembly.cmake @@ -0,0 +1,14 @@ +include(CheckCSourceCompiles) + +function(check_x86_64_assembly) + check_c_source_compiles(" + #include + + int main() + { + uint64_t a = 11, tmp; + __asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\"); + } + " HAVE_X86_64_ASM) + set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE) +endfunction() diff --git a/external/secp256k1/cmake/FindValgrind.cmake b/external/secp256k1/cmake/FindValgrind.cmake new file mode 100644 index 00000000000..3af5e691e45 --- /dev/null +++ b/external/secp256k1/cmake/FindValgrind.cmake @@ -0,0 +1,41 @@ +if(CMAKE_HOST_APPLE) + find_program(BREW_COMMAND brew) + execute_process( + COMMAND ${BREW_COMMAND} --prefix valgrind + OUTPUT_VARIABLE valgrind_brew_prefix + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif() + +set(hints_paths) +if(valgrind_brew_prefix) + set(hints_paths ${valgrind_brew_prefix}/include) +endif() + +find_path(Valgrind_INCLUDE_DIR + NAMES valgrind/memcheck.h + HINTS ${hints_paths} +) + +if(Valgrind_INCLUDE_DIR) + include(CheckCSourceCompiles) + set(CMAKE_REQUIRED_INCLUDES ${Valgrind_INCLUDE_DIR}) + check_c_source_compiles(" + #include + #if defined(NVALGRIND) + # error \"Valgrind does not support this platform.\" + #endif + + int main() {} + " Valgrind_WORKS) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Valgrind + REQUIRED_VARS Valgrind_INCLUDE_DIR Valgrind_WORKS +) + +mark_as_advanced( + Valgrind_INCLUDE_DIR +) diff --git a/external/secp256k1/cmake/GeneratePkgConfigFile.cmake b/external/secp256k1/cmake/GeneratePkgConfigFile.cmake new file mode 100644 index 00000000000..9c1d7f1ddd6 --- /dev/null +++ b/external/secp256k1/cmake/GeneratePkgConfigFile.cmake @@ -0,0 +1,8 @@ +function(generate_pkg_config_file in_file) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix \${prefix}) + set(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR}) + set(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR}) + set(PACKAGE_VERSION ${PROJECT_VERSION}) + configure_file(${in_file} ${PROJECT_NAME}.pc @ONLY) +endfunction() diff --git a/external/secp256k1/cmake/TryAppendCFlags.cmake b/external/secp256k1/cmake/TryAppendCFlags.cmake new file mode 100644 index 00000000000..1d81a9317a0 --- /dev/null +++ b/external/secp256k1/cmake/TryAppendCFlags.cmake @@ -0,0 +1,24 @@ +include(CheckCCompilerFlag) + +function(secp256k1_check_c_flags_internal flags output) + string(MAKE_C_IDENTIFIER "${flags}" result) + string(TOUPPER "${result}" result) + set(result "C_SUPPORTS_${result}") + if(NOT MSVC) + set(CMAKE_REQUIRED_FLAGS "-Werror") + endif() + + # This avoids running a linker. + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_c_compiler_flag("${flags}" ${result}) + + set(${output} ${${result}} PARENT_SCOPE) +endfunction() + +# Append flags to the COMPILE_OPTIONS directory property if CC accepts them. +macro(try_append_c_flags) + secp256k1_check_c_flags_internal("${ARGV}" result) + if(result) + add_compile_options(${ARGV}) + endif() +endmacro() diff --git a/external/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake b/external/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake new file mode 100644 index 00000000000..0d91912b6d2 --- /dev/null +++ b/external/secp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) diff --git a/external/secp256k1/cmake/config.cmake.in b/external/secp256k1/cmake/config.cmake.in new file mode 100644 index 00000000000..46b180ab19e --- /dev/null +++ b/external/secp256k1/cmake/config.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") + +check_required_components(@PROJECT_NAME@) diff --git a/external/secp256k1/cmake/source_arm32.s b/external/secp256k1/cmake/source_arm32.s new file mode 100644 index 00000000000..d3d9347057a --- /dev/null +++ b/external/secp256k1/cmake/source_arm32.s @@ -0,0 +1,9 @@ +.syntax unified +.eabi_attribute 24, 1 +.eabi_attribute 25, 1 +.text +.global main +main: + ldr r0, =0x002A + mov r7, #1 + swi 0 diff --git a/external/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake b/external/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake new file mode 100644 index 00000000000..96119b72d1a --- /dev/null +++ b/external/secp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) diff --git a/external/secp256k1/configure.ac b/external/secp256k1/configure.ac new file mode 100644 index 00000000000..f880a3578dd --- /dev/null +++ b/external/secp256k1/configure.ac @@ -0,0 +1,517 @@ +AC_PREREQ([2.60]) + +# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of +# the API. All changes in experimental modules are treated as +# backwards-compatible and therefore at most increase the minor version. +define(_PKG_VERSION_MAJOR, 0) +define(_PKG_VERSION_MINOR, 6) +define(_PKG_VERSION_PATCH, 0) +define(_PKG_VERSION_IS_RELEASE, true) + +# The library version is based on libtool versioning of the ABI. The set of +# rules for updating the version can be found here: +# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +# All changes in experimental modules are treated as if they don't affect the +# interface and therefore only increase the revision. +define(_LIB_VERSION_CURRENT, 5) +define(_LIB_VERSION_REVISION, 0) +define(_LIB_VERSION_AGE, 0) + +AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) + +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CANONICAL_HOST + +# Require Automake 1.11.2 for AM_PROG_AR +AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects]) + +# Make the compilation flags quiet unless V=1 is used. +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +if test "${CFLAGS+set}" = "set"; then + CFLAGS_overridden=yes +else + CFLAGS_overridden=no +fi +AC_PROG_CC +AM_PROG_AS +AM_PROG_AR + +# Clear some cache variables as a workaround for a bug that appears due to a bad +# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe. +# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421 +AS_UNSET(ac_cv_prog_AR) +AS_UNSET(ac_cv_prog_ac_ct_AR) +LT_INIT([win32-dll]) + +build_windows=no + +case $host_os in + *darwin*) + if test x$cross_compiling != xyes; then + AC_CHECK_PROG([BREW], brew, brew) + if test x$BREW = xbrew; then + # These Homebrew packages may be keg-only, meaning that they won't be found + # in expected paths because they may conflict with system files. Ask + # Homebrew where each one is located, then adjust paths accordingly. + if $BREW list --versions valgrind >/dev/null; then + valgrind_prefix=$($BREW --prefix valgrind 2>/dev/null) + VALGRIND_CPPFLAGS="-I$valgrind_prefix/include" + fi + else + AC_CHECK_PROG([PORT], port, port) + # If homebrew isn't installed and macports is, add the macports default paths + # as a last resort. + if test x$PORT = xport; then + CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" + LDFLAGS="$LDFLAGS -L/opt/local/lib" + fi + fi + fi + ;; + cygwin*|mingw*) + build_windows=yes + ;; +esac + +# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS. +# +# These are our own flags, so we append them to our own SECP_CFLAGS variable (instead of CFLAGS) as +# recommended in the automake manual (Section "Flag Variables Ordering"). CFLAGS belongs to the user +# and we are not supposed to touch it. In the Makefile, we will need to ensure that SECP_CFLAGS +# is prepended to CFLAGS when invoking the compiler so that the user always has the last word (flag). +# +# Another advantage of not touching CFLAGS is that the contents of CFLAGS will be picked up by +# libtool for compiling helper executables. For example, when compiling for Windows, libtool will +# generate entire wrapper executables (instead of simple wrapper scripts as on Unix) to ensure +# proper operation of uninstalled programs linked by libtool against the uninstalled shared library. +# These executables are compiled from C source file for which our flags may not be appropriate, +# e.g., -std=c89 flag has lead to undesirable warnings in the past. +# +# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues. +AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ + # GCC and compatible (incl. clang) + if test "x$GCC" = "xyes"; then + # Try to append -Werror to CFLAGS temporarily. Otherwise checks for some unsupported + # flags will succeed. + # Note that failure to append -Werror does not necessarily mean that -Werror is not + # supported. The compiler may already be warning about something unrelated, for example + # about some path issue. If that is the case, -Werror cannot be used because all + # of those warnings would be turned into errors. + SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS" + SECP_TRY_APPEND_CFLAGS([-Werror], CFLAGS) + + SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic. + SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. + SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers + SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall. + SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. + SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95 + SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 + SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only + SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only + SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 + + CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" + fi + + # MSVC + # Assume MSVC if we're building for Windows but not with GCC or compatible; + # libtool makes the same assumption internally. + # Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path. + if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then + SECP_TRY_APPEND_CFLAGS([-W3], $1) # Production quality warning level. + SECP_TRY_APPEND_CFLAGS([-wd4146], $1) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". + SECP_TRY_APPEND_CFLAGS([-wd4244], $1) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". + SECP_TRY_APPEND_CFLAGS([-wd4267], $1) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". + # Eliminate deprecation warnings for the older, less secure functions. + CPPFLAGS="-D_CRT_SECURE_NO_WARNINGS $CPPFLAGS" + fi +]) +SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS) + +### +### Define config arguments +### + +# In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly. +# Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set. +AC_ARG_ENABLE(dev_mode, [], [], + [enable_dev_mode=no]) + +AC_ARG_ENABLE(benchmark, + AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [], + [SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])]) + +AC_ARG_ENABLE(coverage, + AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [], + [SECP_SET_DEFAULT([enable_coverage], [no], [no])]) + +AC_ARG_ENABLE(tests, + AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [], + [SECP_SET_DEFAULT([enable_tests], [yes], [yes])]) + +AC_ARG_ENABLE(ctime_tests, + AS_HELP_STRING([--enable-ctime-tests],[compile constant-time tests [default=yes if valgrind enabled]]), [], + [SECP_SET_DEFAULT([enable_ctime_tests], [auto], [auto])]) + +AC_ARG_ENABLE(experimental, + AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [], + [SECP_SET_DEFAULT([enable_experimental], [no], [yes])]) + +AC_ARG_ENABLE(exhaustive_tests, + AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [], + [SECP_SET_DEFAULT([enable_exhaustive_tests], [yes], [yes])]) + +AC_ARG_ENABLE(examples, + AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [], + [SECP_SET_DEFAULT([enable_examples], [no], [yes])]) + +AC_ARG_ENABLE(module_ecdh, + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])]) + +AC_ARG_ENABLE(module_recovery, + AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [], + [SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])]) + +AC_ARG_ENABLE(module_extrakeys, + AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])]) + +AC_ARG_ENABLE(module_schnorrsig, + AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])]) + +AC_ARG_ENABLE(module_musig, + AS_HELP_STRING([--enable-module-musig],[enable MuSig2 module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_musig], [yes], [yes])]) + +AC_ARG_ENABLE(module_ellswift, + AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])]) + +AC_ARG_ENABLE(external_default_callbacks, + AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [], + [SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])]) + +# Test-only override of the (autodetected by the C code) "widemul" setting. +# Legal values are: +# * int64 (for [u]int64_t), +# * int128 (for [unsigned] __int128), +# * int128_struct (for int128 implemented as a structure), +# * and auto (the default). +AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto]) + +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto], +[assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto]) + +AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE], +[window size for ecmult precomputation for verification, specified as integer in range [2..24].] +[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] +[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] +[A window size larger than 15 will require you delete the prebuilt precomputed_ecmult.c file so that it can be rebuilt.] +[For very large window sizes, use "make -j 1" to reduce memory use during compilation.] +[The default value is a reasonable setting for desktop machines (currently 15). [default=15]] +)], +[set_ecmult_window=$withval], [set_ecmult_window=15]) + +AC_ARG_WITH([ecmult-gen-kb], [AS_HELP_STRING([--with-ecmult-gen-kb=2|22|86], +[The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms).] +[Larger values result in possibly better signing/keygeneration performance at the cost of a larger table.] +[The default value is a reasonable setting for desktop machines (currently 86). [default=86]] +)], +[set_ecmult_gen_kb=$withval], [set_ecmult_gen_kb=86]) + +AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto], +[Build with extra checks for running inside Valgrind [default=auto]] +)], +[req_valgrind=$withval], [req_valgrind=auto]) + +### +### Handle config options (except for modules) +### + +if test x"$req_valgrind" = x"no"; then + enable_valgrind=no +else + SECP_VALGRIND_CHECK + if test x"$has_valgrind" != x"yes"; then + if test x"$req_valgrind" = x"yes"; then + AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available]) + fi + enable_valgrind=no + else + enable_valgrind=yes + fi +fi + +if test x"$enable_ctime_tests" = x"auto"; then + enable_ctime_tests=$enable_valgrind +fi + +print_msan_notice=no +if test x"$enable_ctime_tests" = x"yes"; then + SECP_MSAN_CHECK + # MSan on Clang >=16 reports unitialized memory in function parameters and return values, even if + # the uninitalized variable is never actually "used". This is called "eager" checking, and it's + # sounds like good idea for normal use of MSan. However, it yields many false positives in the + # ctime_tests because many return values depend on secret (i.e., "uninitialized") values, and + # we're only interested in detecting branches (which count as "uses") on secret data. + if test x"$msan_enabled" = x"yes"; then + SECP_TRY_APPEND_CFLAGS([-fno-sanitize-memory-param-retval], SECP_CFLAGS) + print_msan_notice=yes + fi +fi + +if test x"$enable_coverage" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1" + SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS" + # If coverage is enabled, and the user has not overridden CFLAGS, + # override Autoconf's value "-g -O2" with "-g". Otherwise we'd end up + # with "-O0 --coverage -g -O2". + if test "$CFLAGS_overridden" = "no"; then + CFLAGS="-g" + fi + LDFLAGS="--coverage $LDFLAGS" +else + # Most likely the CFLAGS already contain -O2 because that is autoconf's default. + # We still add it here because passing it twice is not an issue, and handling + # this case would just add unnecessary complexity (see #896). + SECP_CFLAGS="-O2 $SECP_CFLAGS" +fi + +if test x"$req_asm" = x"auto"; then + SECP_X86_64_ASM_CHECK + if test x"$has_x86_64_asm" = x"yes"; then + set_asm=x86_64 + fi + if test x"$set_asm" = x; then + set_asm=no + fi +else + set_asm=$req_asm + case $set_asm in + x86_64) + SECP_X86_64_ASM_CHECK + if test x"$has_x86_64_asm" != x"yes"; then + AC_MSG_ERROR([x86_64 assembly requested but not available]) + fi + ;; + arm32) + SECP_ARM32_ASM_CHECK + if test x"$has_arm32_asm" != x"yes"; then + AC_MSG_ERROR([ARM32 assembly requested but not available]) + fi + ;; + no) + ;; + *) + AC_MSG_ERROR([invalid assembly selection]) + ;; + esac +fi + +# Select assembly +enable_external_asm=no + +case $set_asm in +x86_64) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1" + ;; +arm32) + enable_external_asm=yes + ;; +no) + ;; +*) + AC_MSG_ERROR([invalid assembly selection]) + ;; +esac + +if test x"$enable_external_asm" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_ASM=1" +fi + + +# Select wide multiplication implementation +case $set_widemul in +int128_struct) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128_STRUCT=1" + ;; +int128) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128=1" + ;; +int64) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT64=1" + ;; +auto) + ;; +*) + AC_MSG_ERROR([invalid wide multiplication implementation]) + ;; +esac + +error_window_size=['window size for ecmult precomputation not an integer in range [2..24]'] +case $set_ecmult_window in +''|*[[!0-9]]*) + # no valid integer + AC_MSG_ERROR($error_window_size) + ;; +*) + if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then + # not in range + AC_MSG_ERROR($error_window_size) + fi + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_WINDOW_SIZE=$set_ecmult_window" + ;; +esac + +case $set_ecmult_gen_kb in +2) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=2 -DCOMB_TEETH=5" + ;; +22) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=11 -DCOMB_TEETH=6" + ;; +86) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=43 -DCOMB_TEETH=6" + ;; +*) + AC_MSG_ERROR(['ecmult gen table size not 2, 22 or 86']) + ;; +esac + +if test x"$enable_valgrind" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES $VALGRIND_CPPFLAGS -DVALGRIND" +fi + +# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI). +# We don't want to set the user variable CFLAGS in CI because this would disable +# autoconf's logic for setting default CFLAGS, which we would like to test in CI. +SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS" + +### +### Handle module options +### + +# Processing must be done in a reverse topological sorting of the dependency graph +# (dependent module first). +if test x"$enable_module_ellswift" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1" +fi + +if test x"$enable_module_musig" = x"yes"; then + if test x"$enable_module_schnorrsig" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.]) + fi + enable_module_schnorrsig=yes + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_MUSIG=1" +fi + +if test x"$enable_module_schnorrsig" = x"yes"; then + if test x"$enable_module_extrakeys" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.]) + fi + enable_module_extrakeys=yes + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1" +fi + +if test x"$enable_module_extrakeys" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1" +fi + +if test x"$enable_module_recovery" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1" +fi + +if test x"$enable_module_ecdh" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1" +fi + +if test x"$enable_external_default_callbacks" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1" +fi + +### +### Check for --enable-experimental if necessary +### + +if test x"$enable_experimental" = x"no"; then + if test x"$set_asm" = x"arm32"; then + AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.]) + fi +fi + +### +### Generate output +### + +AC_CONFIG_FILES([Makefile libsecp256k1.pc]) +AC_SUBST(SECP_CFLAGS) +AC_SUBST(SECP_CONFIG_DEFINES) +AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) +AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"]) +AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"]) +AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) +AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) +AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"]) +AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"]) +AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"]) +AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"]) +AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT) +AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION) +AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE) + +AC_OUTPUT + +echo +echo "Build Options:" +echo " with external callbacks = $enable_external_default_callbacks" +echo " with benchmarks = $enable_benchmark" +echo " with tests = $enable_tests" +echo " with ctime tests = $enable_ctime_tests" +echo " with coverage = $enable_coverage" +echo " with examples = $enable_examples" +echo " module ecdh = $enable_module_ecdh" +echo " module recovery = $enable_module_recovery" +echo " module extrakeys = $enable_module_extrakeys" +echo " module schnorrsig = $enable_module_schnorrsig" +echo " module musig = $enable_module_musig" +echo " module ellswift = $enable_module_ellswift" +echo +echo " asm = $set_asm" +echo " ecmult window size = $set_ecmult_window" +echo " ecmult gen table size = $set_ecmult_gen_kb KiB" +# Hide test-only options unless they're used. +if test x"$set_widemul" != xauto; then +echo " wide multiplication = $set_widemul" +fi +echo +echo " valgrind = $enable_valgrind" +echo " CC = $CC" +echo " CPPFLAGS = $CPPFLAGS" +echo " SECP_CFLAGS = $SECP_CFLAGS" +echo " CFLAGS = $CFLAGS" +echo " LDFLAGS = $LDFLAGS" + +if test x"$print_msan_notice" = x"yes"; then + echo + echo "Note:" + echo " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to SECP_CFLAGS" + echo " to avoid false positives in ctime_tests. Pass --disable-ctime-tests to avoid this." +fi + +if test x"$enable_experimental" = x"yes"; then + echo + echo "WARNING: Experimental build" + echo " Experimental features do not have stable APIs or properties, and may not be safe for" + echo " production use." +fi diff --git a/src/secp256k1/contrib/lax_der_parsing.c b/external/secp256k1/contrib/lax_der_parsing.c similarity index 91% rename from src/secp256k1/contrib/lax_der_parsing.c rename to external/secp256k1/contrib/lax_der_parsing.c index 5b141a99481..bf562303edd 100644 --- a/src/secp256k1/contrib/lax_der_parsing.c +++ b/external/secp256k1/contrib/lax_der_parsing.c @@ -1,11 +1,10 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ #include -#include #include "lax_der_parsing.h" @@ -32,7 +31,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { + if (lenbyte > inputlen - pos) { return 0; } pos += lenbyte; @@ -51,7 +50,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { + if (lenbyte > inputlen - pos) { return 0; } while (lenbyte > 0 && input[pos] == 0) { @@ -89,7 +88,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { + if (lenbyte > inputlen - pos) { return 0; } while (lenbyte > 0 && input[pos] == 0) { @@ -112,7 +111,6 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ return 0; } spos = pos; - pos += slen; /* Ignore leading zeroes in R */ while (rlen > 0 && input[rpos] == 0) { @@ -122,7 +120,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ /* Copy R value */ if (rlen > 32) { overflow = 1; - } else { + } else if (rlen) { memcpy(tmpsig + 32 - rlen, input + rpos, rlen); } @@ -134,7 +132,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ /* Copy S value */ if (slen > 32) { overflow = 1; - } else { + } else if (slen) { memcpy(tmpsig + 64 - slen, input + spos, slen); } diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/external/secp256k1/contrib/lax_der_parsing.h similarity index 84% rename from src/secp256k1/contrib/lax_der_parsing.h rename to external/secp256k1/contrib/lax_der_parsing.h index 6d27871a7cc..37c8c691f2f 100644 --- a/src/secp256k1/contrib/lax_der_parsing.h +++ b/external/secp256k1/contrib/lax_der_parsing.h @@ -1,8 +1,8 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ /**** * Please do not link this file directly. It is not part of the libsecp256k1 @@ -48,21 +48,27 @@ * 8.3.1. */ -#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ -#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ +#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H +#define SECP256K1_CONTRIB_LAX_DER_PARSING_H +/* #include secp256k1.h only when it hasn't been included yet. + This enables this file to be #included directly in other project + files (such as tests.c) without the need to set an explicit -I flag, + which would be necessary to locate secp256k1.h. */ +#ifndef SECP256K1_H #include +#endif -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif /** Parse a signature in "lax DER" format * * Returns: 1 when the signature could be parsed, 0 otherwise. * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed + * Out: sig: pointer to a signature object + * In: input: pointer to the signature to be parsed * inputlen: the length of the array pointed to be input * * This function will accept any valid DER encoded signature, even if the @@ -88,4 +94,4 @@ int ecdsa_signature_parse_der_lax( } #endif -#endif +#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */ diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.c b/external/secp256k1/contrib/lax_der_privatekey_parsing.c similarity index 96% rename from src/secp256k1/contrib/lax_der_privatekey_parsing.c rename to external/secp256k1/contrib/lax_der_privatekey_parsing.c index c2e63b4b8d7..a1b8200079e 100644 --- a/src/secp256k1/contrib/lax_der_privatekey_parsing.c +++ b/external/secp256k1/contrib/lax_der_privatekey_parsing.c @@ -1,11 +1,10 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ #include -#include #include "lax_der_privatekey_parsing.h" @@ -45,7 +44,7 @@ int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, co if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { return 0; } - memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); + if (privkey[1]) memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); if (!secp256k1_ec_seckey_verify(ctx, out32)) { memset(out32, 0, 32); return 0; diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/external/secp256k1/contrib/lax_der_privatekey_parsing.h similarity index 84% rename from src/secp256k1/contrib/lax_der_privatekey_parsing.h rename to external/secp256k1/contrib/lax_der_privatekey_parsing.h index 2fd088f8abf..3749e418fe3 100644 --- a/src/secp256k1/contrib/lax_der_privatekey_parsing.h +++ b/external/secp256k1/contrib/lax_der_privatekey_parsing.h @@ -1,8 +1,8 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ /**** * Please do not link this file directly. It is not part of the libsecp256k1 @@ -25,20 +25,25 @@ * library are sufficient. */ -#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ -#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ +#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H +#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H +/* #include secp256k1.h only when it hasn't been included yet. + This enables this file to be #included directly in other project + files (such as tests.c) without the need to set an explicit -I flag, + which would be necessary to locate secp256k1.h. */ +#ifndef SECP256K1_H #include +#endif -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif /** Export a private key in DER format. * * Returns: 1 if the private key was valid. - * Args: ctx: pointer to a context object, initialized for signing (cannot - * be NULL) + * Args: ctx: pointer to a context object (not secp256k1_context_static). * Out: privkey: pointer to an array for storing the private key in BER. * Should have space for 279 bytes, and cannot be NULL. * privkeylen: Pointer to an int where the length of the private key in @@ -87,4 +92,4 @@ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( } #endif -#endif +#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */ diff --git a/external/secp256k1/doc/ellswift.md b/external/secp256k1/doc/ellswift.md new file mode 100644 index 00000000000..9d60e6be0b6 --- /dev/null +++ b/external/secp256k1/doc/ellswift.md @@ -0,0 +1,483 @@ +# ElligatorSwift for secp256k1 explained + +In this document we explain how the `ellswift` module implementation is related to the +construction in the +["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759) +paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi. + +* [1. Introduction](#1-introduction) +* [2. The decoding function](#2-the-decoding-function) + + [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1) +* [3. The encoding function](#3-the-encoding-function) + + [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates) + + [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses) + + [3.3 Finding the inverse](#33-finding-the-inverse) + + [3.4 Dealing with special cases](#34-dealing-with-special-cases) + + [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1) +* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates) + + [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1) + +## 1. Introduction + +The `ellswift` module effectively introduces a new 64-byte public key format, with the property +that (uniformly random) public keys can be encoded as 64-byte arrays which are computationally +indistinguishable from uniform byte arrays. The module provides functions to convert public keys +from and to this format, as well as convenience functions for key generation and ECDH that operate +directly on ellswift-encoded keys. + +The encoding consists of the concatenation of two (32-byte big endian) encoded field elements $u$ +and $t.$ Together they encode an x-coordinate on the curve $x$, or (see further) a full point $(x, y)$ on +the curve. + +**Decoding** consists of decoding the field elements $u$ and $t$ (values above the field size $p$ +are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$ results in a valid +x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function). + +**Encoding** a given $x$ coordinate is conceptually done as follows: +* Loop: + * Pick a uniformly random field element $u.$ + * Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements. + * With probability $1 - \dfrac{\\#L}{8}$, restart the loop. + * Select a uniformly random $t \in L$ and return $(u, t).$ + +This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full +$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates). +The algorithm finds a uniformly random $(u, t)$ among (almost all) those +for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for +almost all x-coordinates on the curve (all but at most 39) is close to two times the field size +(specifically, it lies in the range $2q \pm (22\sqrt{q} + O(1))$, where $q$ is the size of the field). + +## 2. The decoding function + +First some definitions: +* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$ + * For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement. +* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$ + public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square. + This implies that the order of $E$ is either odd, or a multiple of *4*. + If $a=0$, this condition is always fulfilled. + * For `secp256k1`, $a=0$ and $b=7.$ +* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$ +* Let the function $h(x) = 3x^3 + 4a.$ +* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$ +* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$ +* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below. +* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below. + +**Note**: In the paper: +* $F_u$ corresponds to $F_{0,u}$ there. +* $P_u(t)$ is called $P$ there. +* All $S_u$ sets together correspond to $S$ there. +* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there. + +Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right +hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$, +out of the three right-hand side factors an even number must be non-squares. +This implies that exactly *1* or exactly *3* out of +$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$, +at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception +to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate. + +**Define** the decoding function $F_u(t)$ as: +* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$ +* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square). + +$P_u(t) = (X(u, t), Y(u, t))$, where: + +$$ +\begin{array}{lcl} +X(u, t) & = & \left\\{\begin{array}{ll} + \dfrac{g(u) - t^2}{2t} & a = 0 \\ + \dfrac{g(u) + h(u)(Y_0(u) - X_0(u)t)^2}{X_0(u)(1 + h(u)t^2)} & a \neq 0 +\end{array}\right. \\ +Y(u, t) & = & \left\\{\begin{array}{ll} + \dfrac{X(u, t) + t}{u \sqrt{-3}} = \dfrac{g(u) + t^2}{2tu\sqrt{-3}} & a = 0 \\ + Y_0(u) + t(X(u, t) - X_0(u)) & a \neq 0 +\end{array}\right. +\end{array} +$$ + +$P_u(t)$ is defined: +* For $a=0$, unless: + * $u = 0$ or $t = 0$ (division by zero) + * $g(u) = -t^2$ (would give $Y=0$). +* For $a \neq 0$, unless: + * $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero) + * $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$). + +The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$ + +The function $\psi_u$ is the same for all curves: $\psi_u(X, Y) = (x_1, x_2, x_3, z)$, where: + +$$ +\begin{array}{lcl} + x_1 & = & \dfrac{X}{2Y} - \dfrac{u}{2} && \\ + x_2 & = & -\dfrac{X}{2Y} - \dfrac{u}{2} && \\ + x_3 & = & u + 4Y^2 && \\ + z & = & \dfrac{g(x_3)}{2Y}(u^2 + ux_1 + x_1^2 + a) = \dfrac{-g(u)g(x_3)}{8Y^3} +\end{array} +$$ + +### 2.1 Decoding for `secp256k1` + +Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is: + +**Define** $F_u(t)$ as: +* Let $X = \dfrac{u^3 + b - t^2}{2t}.$ +* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$ +* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square. + +To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case +$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$): + +**Define** $F_u(t)$ as: +* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$). +* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$). +* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$). +* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ +* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ +* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square. + +The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice, +but the approach here is simple enough and gives fairly uniform output even in these cases. + +**Note**: in the paper these conditions result in $\infty$ as output, due to the use of projective coordinates there. +We wish to avoid the need for callers to deal with this special case. + +This is implemented in `secp256k1_ellswift_xswiftec_frac_var` (which decodes to an x-coordinate represented as a fraction), and +in `secp256k1_ellswift_xswiftec_var` (which outputs the actual x-coordinate). + +## 3. The encoding function + +To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process: +* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$ +* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$ +* For each of the found $t$ values, verify that $F_u(t) = x.$ +* Return the remaining $t$ values. + +The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$ + +$$ +P_u^{-1}(X, Y) = \left\\{\begin{array}{ll} +Yu\sqrt{-3} - X & a = 0 \\ +\dfrac{Y-Y_0(u)}{X-X_0(u)} & a \neq 0 \land X \neq X_0(u) \\ +\dfrac{-X_0(u)}{h(u)Y_0(u)} & a \neq 0 \land X = X_0(u) \land Y = Y_0(u) +\end{array}\right. +$$ + +The third step above, verifying that $F_u(t) = x$, is necessary because for the $(X, Y)$ values found through the $x_1$ and $x_2$ expressions, +it is possible that decoding through $\psi_u(X, Y)$ yields a valid $x_3$ on the curve, which would take precedence over the +$x_1$ or $x_2$ decoding. These $(X, Y)$ solutions must be rejected. + +Since we know that exactly one or exactly three out of $\\{x_1, x_2, x_3\\}$ are valid x-coordinates for any $t$, +the case where either $x_1$ or $x_2$ is valid and in addition also $x_3$ is valid must mean that all three are valid. +This means that instead of checking whether $x_3$ is on the curve, it is also possible to check whether the other one out of +$x_1$ and $x_2$ is on the curve. This is significantly simpler, as it turns out. + +Observe that $\psi_u$ guarantees that $x_1 + x_2 = -u.$ So given either $x = x_1$ or $x = x_2$, the other one of the two can be computed as +$-u - x.$ Thus, when encoding $x$ through the $x_1$ or $x_2$ expressions, one can simply check whether $g(-u-x)$ is a square, +and if so, not include the corresponding $t$ values in the returned set. As this does not need $X$, $Y$, or $t$, this condition can be determined +before those values are computed. + +It is not possible that an encoding found through the $x_1$ expression decodes to a different valid x-coordinate using $x_2$ (which would +take precedence), for the same reason: if both $x_1$ and $x_2$ decodings were valid, $x_3$ would be valid as well, and thus take +precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$ and $x_2$ is the only test necessary to guarantee the found $t$ +values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder; +any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder. + +### 3.1 Switching to *v, w* coordinates + +Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and +$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$ +* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$ +* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$ +* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where + +$$ +\begin{array}{lcl} + x_1 & = & v \\ + x_2 & = & -u - v \\ + x_3 & = & u + w^2 \\ + z & = & \dfrac{g(x_3)}{w}(u^2 + uv + v^2 + a) = \dfrac{-g(u)g(x_3)}{w^3} +\end{array} +$$ + +We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$ +expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable: +* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions). +* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions). +* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions). + +### 3.2 Avoiding computing all inverses + +The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the +set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary. + +Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a +uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8, +picking a uniformly random element from that, restarting whenever $\bot$ is picked: + +**Define** *ElligatorSwift(x)* as: +* Loop: + * Pick a uniformly random field element $u.$ + * Compute the set $L = F_u^{-1}(x).$ + * Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$ + * Select a uniformly random $t \in T.$ + * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. + +Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly +random element in it, so we do not need to have all $\bot$ values at the end. +As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account), +we can associate every index in $T$ with exactly one of those formulas, making sure that: +* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$ +* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check). +* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those. + +The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting +to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases) +for an analysis of all the negligible cases. + +If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas, +the loop can be simplified to only compute one of the inverses instead of all of them: + +**Define** *ElligatorSwift(x)* as: +* Loop: + * Pick a uniformly random field element $u.$ + * Pick a uniformly random integer $c$ in $[0,8).$ + * Let $t = G_{c,u}(x).$ + * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. + +This is implemented in `secp256k1_ellswift_xelligatorswift_var`. + +### 3.3 Finding the inverse + +To implement $G_{c,u}$, we map $c=0$ to the $x_1$ formula, $c=1$ to the $x_2$ formula, and $c=2$ and $c=3$ to the $x_3$ formula. +Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting that in each formula, $w$ is a square root of some expression). +Ignoring the negligible cases, we get: + +**Define** $G_{c,u}(x)$ as: +* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas): + * If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence). + * If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula) + * Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows). +* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas): + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ + * Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise. +* Let $w = \sqrt{s}.$ +* Depending on $c:$ + * If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$ + * If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$ + +Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly +50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen +with negligible probability. A division by 0 in the first branch in fact cannot occur at all, because $u^2 + uv + v^2 + a = 0$ +implies $g(-u-x) = g(x)$ which would mean the $g(-u-x)$ is square condition has triggered +and $\bot$ would have been returned already. + +**Note**: In the paper, the $case$ variable corresponds roughly to the $c$ above, but only takes on 4 possible values (1 to 4). +The conditional negation of $w$ at the end is done randomly, which is equivalent, but makes testing harder. We choose to +have the $G_{c,u}$ be deterministic, and capture all choices in $c.$ + +Now observe that the $c \in \\{1, 5\\}$ and $c \in \\{3, 7\\}$ conditions effectively perform the same $v \rightarrow -u-v$ +transformation. Furthermore, that transformation has no effect on $s$ in the first branch +as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down: + +**Define** $G_{c,u}(x)$ as: +* If $c \in \\{0, 1, 4, 5\\}:$ + * If $g(-u-x)$ is square, return $\bot.$ + * Let $s = -g(u)/(u^2 + ux + x^2 + a).$ + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}.$ +* Depending on $c:$ + * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$ + * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$ + * If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$ + * If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$ + +This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input. +There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values. + +### 3.4 Dealing with special cases + +As mentioned before there are a few cases to deal with which only happen in a negligibly small subset of inputs. +For cryptographically sized fields, if only random inputs are going to be considered, it is unnecessary to deal with these. Still, for completeness +we analyse them here. They generally fall into two categories: cases in which the encoder would produce $t$ values that +do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same +$t$ value for multiple $c$ inputs (thereby biasing that encoding): + +* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$): + * When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves. + Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve + fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square). + This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$), + the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the + encoder anyway as there will generally be more than 8. + * When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence + as it can deal with $g(u)=0$. + This is again only possible on even-ordered curves. +* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$): + * When $s=0$, a division by zero would occur. + * When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases. + It is equivalent to checking whether $r=0$. + This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition. + A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first + it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero. +* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder: + * For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve. + * For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$. + +**Define** a version of $G_{c,u}(x)$ which deals with all these cases: +* If $a=0$ and $u=0$, return $\bot.$ +* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$ +* If $c \in \\{0, 1, 4, 5\\}:$ + * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). + * If $g(-u-x)$ is square, return $\bot.$ + * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. + * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ + * If $s = 0$, return $\bot.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}$; return $\bot$ if not square. +* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$ +* Depending on $c:$ + * If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$ + * If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$ + * If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$ + * If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$ +* If $a=0$ and $t=0$, return $\bot$ (even curves only). +* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$ +* Return $t.$ + +Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once, +for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached: +* All cases where $P_u(t)$ is not defined: + * For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$ + * For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$ +* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch. + +These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves. + +### 3.5 Encoding for `secp256k1` + +Specialized for odd-ordered $a=0$ curves: + +**Define** $G_{c,u}(x)$ as: +* If $u=0$, return $\bot.$ +* If $c \in \\{0, 1, 4, 5\\}:$ + * If $(-u-x)^3 + b$ is square, return $\bot$ + * Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0). + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square. + * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ + * If $s = 0$, return $\bot.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}$; return $\bot$ if not square. +* Depending on $c:$ + * If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$ + * If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$ + * If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$ + * If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$ + +This is implemented in `secp256k1_ellswift_xswiftec_inv_var`. + +And the x-only ElligatorSwift encoding algorithm is still: + +**Define** *ElligatorSwift(x)* as: +* Loop: + * Pick a uniformly random field element $u.$ + * Pick a uniformly random integer $c$ in $[0,8).$ + * Let $t = G_{c,u}(x).$ + * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. + +Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them. +While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$ +combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity. + +## 4. Encoding and decoding full *(x, y)* coordinates + +So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding +for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information +in $t$ as well. + +Note that for any $(X, Y) \in S_u$, $(\pm X, \pm Y)$ are all on $S_u.$ Moreover, all of these are +mapped to the same x-coordinate. Negating $X$ or negating $Y$ just results in $x_1$ and $x_2$ +being swapped, and does not affect $x_3.$ This will not change the outcome x-coordinate as the order +of $x_1$ and $x_2$ only matters if both were to be valid, and in that case $x_3$ would be used instead. + +Still, these four $(X, Y)$ combinations all correspond to distinct $t$ values, so we can encode +the sign of the y-coordinate in the sign of $X$ or the sign of $Y.$ They correspond to the +four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$ + +**Note**: In the paper, the sign of the y coordinate is encoded in a separately-coded bit. + +To encode the sign of $y$ in the sign of $Y:$ + +**Define** *Decode(u, t)* for full $(x, y)$ as: +* Let $(X, Y) = P_u(t).$ +* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square. +* Let $y = \sqrt{g(x)}.$ +* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$ + +And encoding would be done using a $G_{c,u}(x, y)$ function defined as: + +**Define** $G_{c,u}(x, y)$ as: +* If $c \in \\{0, 1\\}:$ + * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). + * If $g(-u-x)$ is square, return $\bot.$ + * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. + * If $c = 3$ and $r = 0$, return $\bot.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}$; return $\bot$ if not square. +* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise. +* Depending on $c:$ + * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$ + * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$ + +Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$ +This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$. + +In the above logic, $sign$ can be implemented in several ways, such as parity of the integer representation +of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where +$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$. + +### 4.1 Full *(x, y)* coordinates for `secp256k1` + +For $a=0$ curves, there is another option. Note that for those, +the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to +encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get +as decoder: + +**Define** *Decode(u, t)* as: +* Let $u'=u$ if $u \neq 0$; $1$ otherwise. +* Let $t'=t$ if $t \neq 0$; $1$ otherwise. +* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise. +* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ +* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ +* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square. +* Let $y = \sqrt{g(x)}.$ +* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise. + +This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$ + +The corresponding encoder would invoke the x-only one, but negating the output $t$ if $sign(t) \neq sign(y).$ + +This is implemented in `secp256k1_ellswift_elligatorswift_var`. + +Note that this is only intended for encoding points where both the x-coordinate and y-coordinate are unpredictable. When encoding x-only points +where the y-coordinate is implicitly even (or implicitly square, or implicitly in $[0,q/2]$), the encoder in +[Section 3.5](#35-encoding-for-secp256k1) must be used, or a bias is reintroduced that undoes all the benefit of using ElligatorSwift +in the first place. diff --git a/external/secp256k1/doc/musig.md b/external/secp256k1/doc/musig.md new file mode 100644 index 00000000000..ae21f9b131c --- /dev/null +++ b/external/secp256k1/doc/musig.md @@ -0,0 +1,54 @@ +Notes on the musig module API +=========================== + +The following sections contain additional notes on the API of the musig module (`include/secp256k1_musig.h`). +A usage example can be found in `examples/musig.c`. + +## API misuse + +The musig API is designed with a focus on misuse resistance. +However, due to the interactive nature of the MuSig protocol, there are additional failure modes that are not present in regular (single-party) Schnorr signature creation. +While the results can be catastrophic (e.g. leaking of the secret key), it is unfortunately not possible for the musig implementation to prevent all such failure modes. + +Therefore, users of the musig module must take great care to make sure of the following: + +1. A unique nonce per signing session is generated in `secp256k1_musig_nonce_gen`. + See the corresponding comment in `include/secp256k1_musig.h` for how to ensure that. +2. The `secp256k1_musig_secnonce` structure is never copied or serialized. + See also the comment on `secp256k1_musig_secnonce` in `include/secp256k1_musig.h`. +3. Opaque data structures are never written to or read from directly. + Instead, only the provided accessor functions are used. + +## Key Aggregation and (Taproot) Tweaking + +Given a set of public keys, the aggregate public key is computed with `secp256k1_musig_pubkey_agg`. +A plain tweak can be added to the resulting public key with `secp256k1_ec_pubkey_tweak_add` by setting the `tweak32` argument to the hash defined in BIP 32. Similarly, a Taproot tweak can be added with `secp256k1_xonly_pubkey_tweak_add` by setting the `tweak32` argument to the TapTweak hash defined in BIP 341. +Both types of tweaking can be combined and invoked multiple times if the specific application requires it. + +## Signing + +This is covered by `examples/musig.c`. +Essentially, the protocol proceeds in the following steps: + +1. Generate a keypair with `secp256k1_keypair_create` and obtain the public key with `secp256k1_keypair_pub`. +2. Call `secp256k1_musig_pubkey_agg` with the pubkeys of all participants. +3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_xonly_tweak_add` and a plain tweak with `secp256k1_musig_pubkey_ec_tweak_add`. +4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers. +5. Someone (not necessarily the signer) aggregates the public nonces with `secp256k1_musig_nonce_agg` and sends it to the signers. +6. Process the aggregate nonce with `secp256k1_musig_nonce_process`. +7. Create a partial signature with `secp256k1_musig_partial_sign`. +8. Verify the partial signatures (optional in some scenarios) with `secp256k1_musig_partial_sig_verify`. +9. Someone (not necessarily the signer) obtains all partial signatures and aggregates them into the final Schnorr signature using `secp256k1_musig_partial_sig_agg`. + +The aggregate signature can be verified with `secp256k1_schnorrsig_verify`. + +Steps 1 through 5 above can occur before or after the signers are aware of the message to be signed. +Whenever possible, it is recommended to generate the nonces only after the message is known. +This provides enhanced defense-in-depth measures, protecting against potential API misuse in certain scenarios. +However, it does require two rounds of communication during the signing process. +The alternative, generating the nonces in a pre-processing step before the message is known, eliminates these additional protective measures but allows for non-interactive signing. +Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 5). + +## Verification + +A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7. diff --git a/external/secp256k1/doc/release-process.md b/external/secp256k1/doc/release-process.md new file mode 100644 index 00000000000..a64bae0f0d6 --- /dev/null +++ b/external/secp256k1/doc/release-process.md @@ -0,0 +1,94 @@ +# Release process + +This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`. + +We distinguish between two types of releases: *regular* and *maintenance* releases. +Regular releases are releases of a new major or minor version as well as patches of the most recent release. +Maintenance releases, on the other hand, are required for patches of older releases. + +You should coordinate with the other maintainers on the release date, if possible. +This date will be part of the release entry in [CHANGELOG.md](../CHANGELOG.md) and it should match the dates of the remaining steps in the release process (including the date of the tag and the GitHub release). +It is best if the maintainers are present during the release, so they can help ensure that the process is followed correctly and, in the case of a regular release, they are aware that they should not modify the master branch between merging the PR in step 1 and the PR in step 3. + +This process also assumes that there will be no minor releases for old major releases. + +We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core. + +## Sanity checks +Perform these checks when reviewing the release PR (see below): + +1. Ensure `make distcheck` doesn't fail. + ```shell + ./autogen.sh && ./configure --enable-dev-mode && make distcheck + ``` +2. Check installation with autotools: + ```shell + dir=$(mktemp -d) + ./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir + gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa + ``` +3. Check installation with CMake: + ```shell + dir=$(mktemp -d) + build=$(mktemp -d) + cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build && cmake --install $build && ls -RlAh $dir + gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa + ``` +4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to verify that there are no unexpected ABI incompatibilities and that the version number and the release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required. + ```shell + tools/check-abi.sh + ``` + +## Regular release + +1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that + * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by + * adding a section for the release (make sure that the version number is a link to a diff between the previous and new version), + * removing the `[Unreleased]` section header, + * ensuring that the release notes are not missing entries (check the `needs-changelog` label on github), and + * including an entry for `### ABI Compatibility` if it doesn't exist, + * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and, + * if this is not a patch release, + * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and + * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`. +2. Perform the [sanity checks](#sanity-checks) on the PR branch. +3. After the PR is merged, tag the commit, and push the tag: + ``` + RELEASE_COMMIT= + git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT + git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH + ``` +4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that + * sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`, + * increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and + * adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md). + + If other maintainers are not present to approve the PR, it can be merged without ACKs. +5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +6. Send an announcement email to the bitcoin-dev mailing list. + +## Maintenance release + +Note that bug fixes need to be backported only to releases for which no compatible release without the bug exists. + +1. If there's no maintenance branch `$MAJOR.$MINOR`, create one: + ``` + git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.$((PATCH - 1)) + git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR + ``` +2. Open a pull request to the `$MAJOR.$MINOR` branch that + * includes the bug fixes, + * finalizes the release notes similar to a regular release, + * increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` + and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt` + (with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example). +3. Perform the [sanity checks](#sanity-checks) on the PR branch. +4. After the PRs are merged, update the release branch, tag the commit, and push the tag: + ``` + git checkout $MAJOR.$MINOR && git pull + git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" + git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH + ``` +6. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +7. Send an announcement email to the bitcoin-dev mailing list. +8. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md). diff --git a/external/secp256k1/doc/safegcd_implementation.md b/external/secp256k1/doc/safegcd_implementation.md new file mode 100644 index 00000000000..5dbbb7bbd2d --- /dev/null +++ b/external/secp256k1/doc/safegcd_implementation.md @@ -0,0 +1,819 @@ +# The safegcd implementation in libsecp256k1 explained + +This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files. +It is based on the paper +["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd) +by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version. + +The actual implementation is in C of course, but for demonstration purposes Python3 is used here. +Most implementation aspects and optimizations are explained, except those that depend on the specific +number representation used in the C code. + +## 1. Computing the Greatest Common Divisor (GCD) using divsteps + +The algorithm from the paper (section 11), at a very high level, is this: + +```python +def gcd(f, g): + """Compute the GCD of an odd integer f and another integer g.""" + assert f & 1 # require f to be odd + delta = 1 # additional state variable + while g != 0: + assert f & 1 # f will be odd in every iteration + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g - f) // 2 + elif g & 1: + delta, f, g = 1 + delta, f, (g + f) // 2 + else: + delta, f, g = 1 + delta, f, (g ) // 2 + return abs(f) +``` + +It computes the greatest common divisor of an odd integer *f* and any integer *g*. Its inner loop +keeps rewriting the variables *f* and *g* alongside a state variable *δ* that starts at *1*, until +*g=0* is reached. At that point, *|f|* gives the GCD. Each of the transitions in the loop is called a +"division step" (referred to as divstep in what follows). + +For example, *gcd(21, 14)* would be computed as: +- Start with *δ=1 f=21 g=14* +- Take the third branch: *δ=2 f=21 g=7* +- Take the first branch: *δ=-1 f=7 g=-7* +- Take the second branch: *δ=0 f=7 g=0* +- The answer *|f| = 7*. + +Why it works: +- Divsteps can be decomposed into two steps (see paragraph 8.2 in the paper): + - (a) If *g* is odd, replace *(f,g)* with *(g,g-f)* or (f,g+f), resulting in an even *g*. + - (b) Replace *(f,g)* with *(f,g/2)* (where *g* is guaranteed to be even). +- Neither of those two operations change the GCD: + - For (a), assume *gcd(f,g)=c*, then it must be the case that *f=a c* and *g=b c* for some integers *a* + and *b*. As *(g,g-f)=(b c,(b-a)c)* and *(f,f+g)=(a c,(a+b)c)*, the result clearly still has + common factor *c*. Reasoning in the other direction shows that no common factor can be added by + doing so either. + - For (b), we know that *f* is odd, so *gcd(f,g)* clearly has no factor *2*, and we can remove + it from *g*. +- The algorithm will eventually converge to *g=0*. This is proven in the paper (see theorem G.3). +- It follows that eventually we find a final value *f'* for which *gcd(f,g) = gcd(f',0)*. As the + gcd of *f'* and *0* is *|f'|* by definition, that is our answer. + +Compared to more [traditional GCD algorithms](https://en.wikipedia.org/wiki/Euclidean_algorithm), this one has the property of only ever looking at +the low-order bits of the variables to decide the next steps, and being easy to make +constant-time (in more low-level languages than Python). The *δ* parameter is necessary to +guide the algorithm towards shrinking the numbers' magnitudes without explicitly needing to look +at high order bits. + +Properties that will become important later: +- Performing more divsteps than needed is not a problem, as *f* does not change anymore after *g=0*. +- Only even numbers are divided by *2*. This means that when reasoning about it algebraically we + do not need to worry about rounding. +- At every point during the algorithm's execution the next *N* steps only depend on the bottom *N* + bits of *f* and *g*, and on *δ*. + + +## 2. From GCDs to modular inverses + +We want an algorithm to compute the inverse *a* of *x* modulo *M*, i.e. the number a such that *a x=1 +mod M*. This inverse only exists if the GCD of *x* and *M* is *1*, but that is always the case if *M* is +prime and *0 < x < M*. In what follows, assume that the modular inverse exists. +It turns out this inverse can be computed as a side effect of computing the GCD by keeping track +of how the internal variables can be written as linear combinations of the inputs at every step +(see the [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)). +Since the GCD is *1*, such an algorithm will compute numbers *a* and *b* such that a x + b M = 1*. +Taking that expression *mod M* gives *a x mod M = 1*, and we see that *a* is the modular inverse of *x +mod M*. + +A similar approach can be used to calculate modular inverses using the divsteps-based GCD +algorithm shown above, if the modulus *M* is odd. To do so, compute *gcd(f=M,g=x)*, while keeping +track of extra variables *d* and *e*, for which at every step *d = f/x (mod M)* and *e = g/x (mod M)*. +*f/x* here means the number which multiplied with *x* gives *f mod M*. As *f* and *g* are initialized to *M* +and *x* respectively, *d* and *e* just start off being *0* (*M/x mod M = 0/x mod M = 0*) and *1* (*x/x mod M += 1*). + +```python +def div2(M, x): + """Helper routine to compute x/2 mod M (where M is odd).""" + assert M & 1 + if x & 1: # If x is odd, make it even by adding M. + x += M + # x must be even now, so a clean division by 2 is possible. + return x // 2 + +def modinv(M, x): + """Compute the inverse of x mod M (given that it exists, and M is odd).""" + assert M & 1 + delta, f, g, d, e = 1, M, x, 0, 1 + while g != 0: + # Note that while division by two for f and g is only ever done on even inputs, this is + # not true for d and e, so we need the div2 helper function. + if delta > 0 and g & 1: + delta, f, g, d, e = 1 - delta, g, (g - f) // 2, e, div2(M, e - d) + elif g & 1: + delta, f, g, d, e = 1 + delta, f, (g + f) // 2, d, div2(M, e + d) + else: + delta, f, g, d, e = 1 + delta, f, (g ) // 2, d, div2(M, e ) + # Verify that the invariants d=f/x mod M, e=g/x mod M are maintained. + assert f % M == (d * x) % M + assert g % M == (e * x) % M + assert f == 1 or f == -1 # |f| is the GCD, it must be 1 + # Because of invariant d = f/x (mod M), 1/x = d/f (mod M). As |f|=1, d/f = d*f. + return (d * f) % M +``` + +Also note that this approach to track *d* and *e* throughout the computation to determine the inverse +is different from the paper. There (see paragraph 12.1 in the paper) a transition matrix for the +entire computation is determined (see section 3 below) and the inverse is computed from that. +The approach here avoids the need for 2x2 matrix multiplications of various sizes, and appears to +be faster at the level of optimization we're able to do in C. + + +## 3. Batching multiple divsteps + +Every divstep can be expressed as a matrix multiplication, applying a transition matrix *(1/2 t)* +to both vectors *[f, g]* and *[d, e]* (see paragraph 8.1 in the paper): + +``` + t = [ u, v ] + [ q, r ] + + [ out_f ] = (1/2 * t) * [ in_f ] + [ out_g ] = [ in_g ] + + [ out_d ] = (1/2 * t) * [ in_d ] (mod M) + [ out_e ] [ in_e ] +``` + +where *(u, v, q, r)* is *(0, 2, -1, 1)*, *(2, 0, 1, 1)*, or *(2, 0, 0, 1)*, depending on which branch is +taken. As above, the resulting *f* and *g* are always integers. + +Performing multiple divsteps corresponds to a multiplication with the product of all the +individual divsteps' transition matrices. As each transition matrix consists of integers +divided by *2*, the product of these matrices will consist of integers divided by *2N* (see also +theorem 9.2 in the paper). These divisions are expensive when updating *d* and *e*, so we delay +them: we compute the integer coefficients of the combined transition matrix scaled by *2N*, and +do one division by *2N* as a final step: + +```python +def divsteps_n_matrix(delta, f, g): + """Compute delta and transition matrix t after N divsteps (multiplied by 2^N).""" + u, v, q, r = 1, 0, 0, 1 # start with identity matrix + for _ in range(N): + if delta > 0 and g & 1: + delta, f, g, u, v, q, r = 1 - delta, g, (g - f) // 2, 2*q, 2*r, q-u, r-v + elif g & 1: + delta, f, g, u, v, q, r = 1 + delta, f, (g + f) // 2, 2*u, 2*v, q+u, r+v + else: + delta, f, g, u, v, q, r = 1 + delta, f, (g ) // 2, 2*u, 2*v, q , r + return delta, (u, v, q, r) +``` + +As the branches in the divsteps are completely determined by the bottom *N* bits of *f* and *g*, this +function to compute the transition matrix only needs to see those bottom bits. Furthermore all +intermediate results and outputs fit in *(N+1)*-bit numbers (unsigned for *f* and *g*; signed for *u*, *v*, +*q*, and *r*) (see also paragraph 8.3 in the paper). This means that an implementation using 64-bit +integers could set *N=62* and compute the full transition matrix for 62 steps at once without any +big integer arithmetic at all. This is the reason why this algorithm is efficient: it only needs +to update the full-size *f*, *g*, *d*, and *e* numbers once every *N* steps. + +We still need functions to compute: + +``` + [ out_f ] = (1/2^N * [ u, v ]) * [ in_f ] + [ out_g ] ( [ q, r ]) [ in_g ] + + [ out_d ] = (1/2^N * [ u, v ]) * [ in_d ] (mod M) + [ out_e ] ( [ q, r ]) [ in_e ] +``` + +Because the divsteps transformation only ever divides even numbers by two, the result of *t [f,g]* is always even. When *t* is a composition of *N* divsteps, it follows that the resulting *f* +and *g* will be multiple of *2N*, and division by *2N* is simply shifting them down: + +```python +def update_fg(f, g, t): + """Multiply matrix t/2^N with [f, g].""" + u, v, q, r = t + cf, cg = u*f + v*g, q*f + r*g + # (t / 2^N) should cleanly apply to [f,g] so the result of t*[f,g] should have N zero + # bottom bits. + assert cf % 2**N == 0 + assert cg % 2**N == 0 + return cf >> N, cg >> N +``` + +The same is not true for *d* and *e*, and we need an equivalent of the `div2` function for division by *2N mod M*. +This is easy if we have precomputed *1/M mod 2N* (which always exists for odd *M*): + +```python +def div2n(M, Mi, x): + """Compute x/2^N mod M, given Mi = 1/M mod 2^N.""" + assert (M * Mi) % 2**N == 1 + # Find a factor m such that m*M has the same bottom N bits as x. We want: + # (m * M) mod 2^N = x mod 2^N + # <=> m mod 2^N = (x / M) mod 2^N + # <=> m mod 2^N = (x * Mi) mod 2^N + m = (Mi * x) % 2**N + # Subtract that multiple from x, cancelling its bottom N bits. + x -= m * M + # Now a clean division by 2^N is possible. + assert x % 2**N == 0 + return (x >> N) % M + +def update_de(d, e, t, M, Mi): + """Multiply matrix t/2^N with [d, e], modulo M.""" + u, v, q, r = t + cd, ce = u*d + v*e, q*d + r*e + return div2n(M, Mi, cd), div2n(M, Mi, ce) +``` + +With all of those, we can write a version of `modinv` that performs *N* divsteps at once: + +```python3 +def modinv(M, Mi, x): + """Compute the modular inverse of x mod M, given Mi=1/M mod 2^N.""" + assert M & 1 + delta, f, g, d, e = 1, M, x, 0, 1 + while g != 0: + # Compute the delta and transition matrix t for the next N divsteps (this only needs + # (N+1)-bit signed integer arithmetic). + delta, t = divsteps_n_matrix(delta, f % 2**N, g % 2**N) + # Apply the transition matrix t to [f, g]: + f, g = update_fg(f, g, t) + # Apply the transition matrix t to [d, e]: + d, e = update_de(d, e, t, M, Mi) + return (d * f) % M +``` + +This means that in practice we'll always perform a multiple of *N* divsteps. This is not a problem +because once *g=0*, further divsteps do not affect *f*, *g*, *d*, or *e* anymore (only *δ* keeps +increasing). For variable time code such excess iterations will be mostly optimized away in later +sections. + + +## 4. Avoiding modulus operations + +So far, there are two places where we compute a remainder of big numbers modulo *M*: at the end of +`div2n` in every `update_de`, and at the very end of `modinv` after potentially negating *d* due to the +sign of *f*. These are relatively expensive operations when done generically. + +To deal with the modulus operation in `div2n`, we simply stop requiring *d* and *e* to be in range +*[0,M)* all the time. Let's start by inlining `div2n` into `update_de`, and dropping the modulus +operation at the end: + +```python +def update_de(d, e, t, M, Mi): + """Multiply matrix t/2^N with [d, e] mod M, given Mi=1/M mod 2^N.""" + u, v, q, r = t + cd, ce = u*d + v*e, q*d + r*e + # Cancel out bottom N bits of cd and ce. + md = -((Mi * cd) % 2**N) + me = -((Mi * ce) % 2**N) + cd += md * M + ce += me * M + # And cleanly divide by 2**N. + return cd >> N, ce >> N +``` + +Let's look at bounds on the ranges of these numbers. It can be shown that *|u|+|v|* and *|q|+|r|* +never exceed *2N* (see paragraph 8.3 in the paper), and thus a multiplication with *t* will have +outputs whose absolute values are at most *2N* times the maximum absolute input value. In case the +inputs *d* and *e* are in *(-M,M)*, which is certainly true for the initial values *d=0* and *e=1* assuming +*M > 1*, the multiplication results in numbers in range *(-2NM,2NM)*. Subtracting less than *2N* +times *M* to cancel out *N* bits brings that up to *(-2N+1M,2NM)*, and +dividing by *2N* at the end takes it to *(-2M,M)*. Another application of `update_de` would take that +to *(-3M,2M)*, and so forth. This progressive expansion of the variables' ranges can be +counteracted by incrementing *d* and *e* by *M* whenever they're negative: + +```python + ... + if d < 0: + d += M + if e < 0: + e += M + cd, ce = u*d + v*e, q*d + r*e + # Cancel out bottom N bits of cd and ce. + ... +``` + +With inputs in *(-2M,M)*, they will first be shifted into range *(-M,M)*, which means that the +output will again be in *(-2M,M)*, and this remains the case regardless of how many `update_de` +invocations there are. In what follows, we will try to make this more efficient. + +Note that increasing *d* by *M* is equal to incrementing *cd* by *u M* and *ce* by *q M*. Similarly, +increasing *e* by *M* is equal to incrementing *cd* by *v M* and *ce* by *r M*. So we could instead write: + +```python + ... + cd, ce = u*d + v*e, q*d + r*e + # Perform the equivalent of incrementing d, e by M when they're negative. + if d < 0: + cd += u*M + ce += q*M + if e < 0: + cd += v*M + ce += r*M + # Cancel out bottom N bits of cd and ce. + md = -((Mi * cd) % 2**N) + me = -((Mi * ce) % 2**N) + cd += md * M + ce += me * M + ... +``` + +Now note that we have two steps of corrections to *cd* and *ce* that add multiples of *M*: this +increment, and the decrement that cancels out bottom bits. The second one depends on the first +one, but they can still be efficiently combined by only computing the bottom bits of *cd* and *ce* +at first, and using that to compute the final *md*, *me* values: + +```python +def update_de(d, e, t, M, Mi): + """Multiply matrix t/2^N with [d, e], modulo M.""" + u, v, q, r = t + md, me = 0, 0 + # Compute what multiples of M to add to cd and ce. + if d < 0: + md += u + me += q + if e < 0: + md += v + me += r + # Compute bottom N bits of t*[d,e] + M*[md,me]. + cd, ce = (u*d + v*e + md*M) % 2**N, (q*d + r*e + me*M) % 2**N + # Correct md and me such that the bottom N bits of t*[d,e] + M*[md,me] are zero. + md -= (Mi * cd) % 2**N + me -= (Mi * ce) % 2**N + # Do the full computation. + cd, ce = u*d + v*e + md*M, q*d + r*e + me*M + # And cleanly divide by 2**N. + return cd >> N, ce >> N +``` + +One last optimization: we can avoid the *md M* and *me M* multiplications in the bottom bits of *cd* +and *ce* by moving them to the *md* and *me* correction: + +```python + ... + # Compute bottom N bits of t*[d,e]. + cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N + # Correct md and me such that the bottom N bits of t*[d,e]+M*[md,me] are zero. + # Note that this is not the same as {md = (-Mi * cd) % 2**N} etc. That would also result in N + # zero bottom bits, but isn't guaranteed to be a reduction of [0,2^N) compared to the + # previous md and me values, and thus would violate our bounds analysis. + md -= (Mi*cd + md) % 2**N + me -= (Mi*ce + me) % 2**N + ... +``` + +The resulting function takes *d* and *e* in range *(-2M,M)* as inputs, and outputs values in the same +range. That also means that the *d* value at the end of `modinv` will be in that range, while we want +a result in *[0,M)*. To do that, we need a normalization function. It's easy to integrate the +conditional negation of *d* (based on the sign of *f*) into it as well: + +```python +def normalize(sign, v, M): + """Compute sign*v mod M, where v is in range (-2*M,M); output in [0,M).""" + assert sign == 1 or sign == -1 + # v in (-2*M,M) + if v < 0: + v += M + # v in (-M,M). Now multiply v with sign (which can only be 1 or -1). + if sign == -1: + v = -v + # v in (-M,M) + if v < 0: + v += M + # v in [0,M) + return v +``` + +And calling it in `modinv` is simply: + +```python + ... + return normalize(f, d, M) +``` + + +## 5. Constant-time operation + +The primary selling point of the algorithm is fast constant-time operation. What code flow still +depends on the input data so far? + +- the number of iterations of the while *g ≠ 0* loop in `modinv` +- the branches inside `divsteps_n_matrix` +- the sign checks in `update_de` +- the sign checks in `normalize` + +To make the while loop in `modinv` constant time it can be replaced with a constant number of +iterations. The paper proves (Theorem 11.2) that *741* divsteps are sufficient for any *256*-bit +inputs, and [safegcd-bounds](https://github.com/sipa/safegcd-bounds) shows that the slightly better bound *724* is +sufficient even. Given that every loop iteration performs *N* divsteps, it will run a total of +*⌈724/N⌉* times. + +To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise +operations (and hope the C compiler isn't smart enough to turn them back into branches; see +`ctime_tests.c` for automated tests that this isn't the case). To do so, observe that a +divstep can be written instead as (compare to the inner loop of `gcd` in section 1). + +```python + x = -f if delta > 0 else f # set x equal to (input) -f or f + if g & 1: + g += x # set g to (input) g-f or g+f + if delta > 0: + delta = -delta + f += g # set f to (input) g (note that g was set to g-f before) + delta += 1 + g >>= 1 +``` + +To convert the above to bitwise operations, we rely on a trick to negate conditionally: per the +definition of negative numbers in two's complement, (*-v == ~v + 1*) holds for every number *v*. As +*-1* in two's complement is all *1* bits, bitflipping can be expressed as xor with *-1*. It follows +that *-v == (v ^ -1) - (-1)*. Thus, if we have a variable *c* that takes on values *0* or *-1*, then +*(v ^ c) - c* is *v* if *c=0* and *-v* if *c=-1*. + +Using this we can write: + +```python + x = -f if delta > 0 else f +``` + +in constant-time form as: + +```python + c1 = (-delta) >> 63 + # Conditionally negate f based on c1: + x = (f ^ c1) - c1 +``` + +To use that trick, we need a helper mask variable *c1* that resolves the condition *δ>0* to *-1* +(if true) or *0* (if false). We compute *c1* using right shifting, which is equivalent to dividing by +the specified power of *2* and rounding down (in Python, and also in C under the assumption of a typical two's complement system; see +`assumptions.h` for tests that this is the case). Right shifting by *63* thus maps all +numbers in range *[-263,0)* to *-1*, and numbers in range *[0,263)* to *0*. + +Using the facts that *x&0=0* and *x&(-1)=x* (on two's complement systems again), we can write: + +```python + if g & 1: + g += x +``` + +as: + +```python + # Compute c2=0 if g is even and c2=-1 if g is odd. + c2 = -(g & 1) + # This masks out x if g is even, and leaves x be if g is odd. + g += x & c2 +``` + +Using the conditional negation trick again we can write: + +```python + if g & 1: + if delta > 0: + delta = -delta +``` + +as: + +```python + # Compute c3=-1 if g is odd and delta>0, and 0 otherwise. + c3 = c1 & c2 + # Conditionally negate delta based on c3: + delta = (delta ^ c3) - c3 +``` + +Finally: + +```python + if g & 1: + if delta > 0: + f += g +``` + +becomes: + +```python + f += g & c3 +``` + +It turns out that this can be implemented more efficiently by applying the substitution +*η=-δ*. In this representation, negating *δ* corresponds to negating *η*, and incrementing +*δ* corresponds to decrementing *η*. This allows us to remove the negation in the *c1* +computation: + +```python + # Compute a mask c1 for eta < 0, and compute the conditional negation x of f: + c1 = eta >> 63 + x = (f ^ c1) - c1 + # Compute a mask c2 for odd g, and conditionally add x to g: + c2 = -(g & 1) + g += x & c2 + # Compute a mask c for (eta < 0) and odd (input) g, and use it to conditionally negate eta, + # and add g to f: + c3 = c1 & c2 + eta = (eta ^ c3) - c3 + f += g & c3 + # Incrementing delta corresponds to decrementing eta. + eta -= 1 + g >>= 1 +``` + +A variant of divsteps with better worst-case performance can be used instead: starting *δ* at +*1/2* instead of *1*. This reduces the worst case number of iterations to *590* for *256*-bit inputs +(which can be shown using convex hull analysis). In this case, the substitution *ζ=-(δ+1/2)* +is used instead to keep the variable integral. Incrementing *δ* by *1* still translates to +decrementing *ζ* by *1*, but negating *δ* now corresponds to going from *ζ* to *-(ζ+1)*, or +*~ζ*. Doing that conditionally based on *c3* is simply: + +```python + ... + c3 = c1 & c2 + zeta ^= c3 + ... +``` + +By replacing the loop in `divsteps_n_matrix` with a variant of the divstep code above (extended to +also apply all *f* operations to *u*, *v* and all *g* operations to *q*, *r*), a constant-time version of +`divsteps_n_matrix` is obtained. The full code will be in section 7. + +These bit fiddling tricks can also be used to make the conditional negations and additions in +`update_de` and `normalize` constant-time. + + +## 6. Variable-time optimizations + +In section 5, we modified the `divsteps_n_matrix` function (and a few others) to be constant time. +Constant time operations are only necessary when computing modular inverses of secret data. In +other cases, it slows down calculations unnecessarily. In this section, we will construct a +faster non-constant time `divsteps_n_matrix` function. + +To do so, first consider yet another way of writing the inner loop of divstep operations in +`gcd` from section 1. This decomposition is also explained in the paper in section 8.2. We use +the original version with initial *δ=1* and *η=-δ* here. + +```python +for _ in range(N): + if g & 1 and eta < 0: + eta, f, g = -eta, g, -f + if g & 1: + g += f + eta -= 1 + g >>= 1 +``` + +Whenever *g* is even, the loop only shifts *g* down and decreases *η*. When *g* ends in multiple zero +bits, these iterations can be consolidated into one step. This requires counting the bottom zero +bits efficiently, which is possible on most platforms; it is abstracted here as the function +`count_trailing_zeros`. + +```python +def count_trailing_zeros(v): + """ + When v is zero, consider all N zero bits as "trailing". + For a non-zero value v, find z such that v=(d<>= zeros + i -= zeros + if i == 0: + break + # We know g is odd now + if eta < 0: + eta, f, g = -eta, g, -f + g += f + # g is even now, and the eta decrement and g shift will happen in the next loop. +``` + +We can now remove multiple bottom *0* bits from *g* at once, but still need a full iteration whenever +there is a bottom *1* bit. In what follows, we will get rid of multiple *1* bits simultaneously as +well. + +Observe that as long as *η ≥ 0*, the loop does not modify *f*. Instead, it cancels out bottom +bits of *g* and shifts them out, and decreases *η* and *i* accordingly - interrupting only when *η* +becomes negative, or when *i* reaches *0*. Combined, this is equivalent to adding a multiple of *f* to +*g* to cancel out multiple bottom bits, and then shifting them out. + +It is easy to find what that multiple is: we want a number *w* such that *g+w f* has a few bottom +zero bits. If that number of bits is *L*, we want *g+w f mod 2L = 0*, or *w = -g/f mod 2L*. Since *f* +is odd, such a *w* exists for any *L*. *L* cannot be more than *i* steps (as we'd finish the loop before +doing more) or more than *η+1* steps (as we'd run `eta, f, g = -eta, g, -f` at that point), but +apart from that, we're only limited by the complexity of computing *w*. + +This code demonstrates how to cancel up to 4 bits per step: + +```python +NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n +i = N +while True: + zeros = min(i, count_trailing_zeros(g)) + eta -= zeros + g >>= zeros + i -= zeros + if i == 0: + break + # We know g is odd now + if eta < 0: + eta, f, g = -eta, g, -f + # Compute limit on number of bits to cancel + limit = min(min(eta + 1, i), 4) + # Compute w = -g/f mod 2**limit, using the table value for -1/f mod 2**4. Note that f is + # always odd, so its inverse modulo a power of two always exists. + w = (g * NEGINV16[(f & 15) // 2]) % (2**limit) + # As w = -g/f mod (2**limit), g+w*f mod 2**limit = 0 mod 2**limit. + g += w * f + assert g % (2**limit) == 0 + # The next iteration will now shift out at least limit bottom zero bits from g. +``` + +By using a bigger table more bits can be cancelled at once. The table can also be implemented +as a formula. Several formulas are known for computing modular inverses modulo powers of two; +some can be found in Hacker's Delight second edition by Henry S. Warren, Jr. pages 245-247. +Here we need the negated modular inverse, which is a simple transformation of those: + +- Instead of a 3-bit table: + - *-f* or *f ^ 6* +- Instead of a 4-bit table: + - *1 - f(f + 1)* + - *-(f + (((f + 1) & 4) << 1))* +- For larger tables the following technique can be used: if *w=-1/f mod 2L*, then *w(w f+2)* is + *-1/f mod 22L*. This allows extending the previous formulas (or tables). In particular we + have this 6-bit function (based on the 3-bit function above): + - *f(f2 - 2)* + +This loop, again extended to also handle *u*, *v*, *q*, and *r* alongside *f* and *g*, placed in +`divsteps_n_matrix`, gives a significantly faster, but non-constant time version. + + +## 7. Final Python version + +All together we need the following functions: + +- A way to compute the transition matrix in constant time, using the `divsteps_n_matrix` function + from section 2, but with its loop replaced by a variant of the constant-time divstep from + section 5, extended to handle *u*, *v*, *q*, *r*: + +```python +def divsteps_n_matrix(zeta, f, g): + """Compute zeta and transition matrix t after N divsteps (multiplied by 2^N).""" + u, v, q, r = 1, 0, 0, 1 # start with identity matrix + for _ in range(N): + c1 = zeta >> 63 + # Compute x, y, z as conditionally-negated versions of f, u, v. + x, y, z = (f ^ c1) - c1, (u ^ c1) - c1, (v ^ c1) - c1 + c2 = -(g & 1) + # Conditionally add x, y, z to g, q, r. + g, q, r = g + (x & c2), q + (y & c2), r + (z & c2) + c1 &= c2 # reusing c1 here for the earlier c3 variable + zeta = (zeta ^ c1) - 1 # inlining the unconditional zeta decrement here + # Conditionally add g, q, r to f, u, v. + f, u, v = f + (g & c1), u + (q & c1), v + (r & c1) + # When shifting g down, don't shift q, r, as we construct a transition matrix multiplied + # by 2^N. Instead, shift f's coefficients u and v up. + g, u, v = g >> 1, u << 1, v << 1 + return zeta, (u, v, q, r) +``` + +- The functions to update *f* and *g*, and *d* and *e*, from section 2 and section 4, with the constant-time + changes to `update_de` from section 5: + +```python +def update_fg(f, g, t): + """Multiply matrix t/2^N with [f, g].""" + u, v, q, r = t + cf, cg = u*f + v*g, q*f + r*g + return cf >> N, cg >> N + +def update_de(d, e, t, M, Mi): + """Multiply matrix t/2^N with [d, e], modulo M.""" + u, v, q, r = t + d_sign, e_sign = d >> 257, e >> 257 + md, me = (u & d_sign) + (v & e_sign), (q & d_sign) + (r & e_sign) + cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N + md -= (Mi*cd + md) % 2**N + me -= (Mi*ce + me) % 2**N + cd, ce = u*d + v*e + M*md, q*d + r*e + M*me + return cd >> N, ce >> N +``` + +- The `normalize` function from section 4, made constant time as well: + +```python +def normalize(sign, v, M): + """Compute sign*v mod M, where v in (-2*M,M); output in [0,M).""" + v_sign = v >> 257 + # Conditionally add M to v. + v += M & v_sign + c = (sign - 1) >> 1 + # Conditionally negate v. + v = (v ^ c) - c + v_sign = v >> 257 + # Conditionally add M to v again. + v += M & v_sign + return v +``` + +- And finally the `modinv` function too, adapted to use *ζ* instead of *δ*, and using the fixed + iteration count from section 5: + +```python +def modinv(M, Mi, x): + """Compute the modular inverse of x mod M, given Mi=1/M mod 2^N.""" + zeta, f, g, d, e = -1, M, x, 0, 1 + for _ in range((590 + N - 1) // N): + zeta, t = divsteps_n_matrix(zeta, f % 2**N, g % 2**N) + f, g = update_fg(f, g, t) + d, e = update_de(d, e, t, M, Mi) + return normalize(f, d, M) +``` + +- To get a variable time version, replace the `divsteps_n_matrix` function with one that uses the + divsteps loop from section 5, and a `modinv` version that calls it without the fixed iteration + count: + +```python +NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n +def divsteps_n_matrix_var(eta, f, g): + """Compute eta and transition matrix t after N divsteps (multiplied by 2^N).""" + u, v, q, r = 1, 0, 0, 1 + i = N + while True: + zeros = min(i, count_trailing_zeros(g)) + eta, i = eta - zeros, i - zeros + g, u, v = g >> zeros, u << zeros, v << zeros + if i == 0: + break + if eta < 0: + eta, f, u, v, g, q, r = -eta, g, q, r, -f, -u, -v + limit = min(min(eta + 1, i), 4) + w = (g * NEGINV16[(f & 15) // 2]) % (2**limit) + g, q, r = g + w*f, q + w*u, r + w*v + return eta, (u, v, q, r) + +def modinv_var(M, Mi, x): + """Compute the modular inverse of x mod M, given Mi = 1/M mod 2^N.""" + eta, f, g, d, e = -1, M, x, 0, 1 + while g != 0: + eta, t = divsteps_n_matrix_var(eta, f % 2**N, g % 2**N) + f, g = update_fg(f, g, t) + d, e = update_de(d, e, t, M, Mi) + return normalize(f, d, Mi) +``` + +## 8. From GCDs to Jacobi symbol + +We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an +extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we +make corresponding updates to *j* using +[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties): +* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*). +* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*). + +These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied +very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this +calculation is slightly simpler than the one for the modular inverse because we no longer need to +keep track of *d* and *e*. + +However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for +positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative +values. We resolve this by using the following modified steps: + +```python + # Before + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g - f) // 2 + + # After + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g + f) // 2 +``` + +The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4 +and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm +will converge. The justification for posdivsteps is completely empirical: in practice, it appears +that the vast majority of nonzero inputs converge to *f=g=gcd(f0, g0)* in a +number of steps proportional to their logarithm. + +Note that: +- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached. +- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect. +- We need to update the termination condition from *g=0* to *f=1*. + +We account for the possibility of nonconvergence by only performing a bounded number of +posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not +yet been found. + +The optimizations in sections 3-7 above are described in the context of the original divsteps, but +in the C implementation we also adapt most of them (not including "avoiding modulus operations", +since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate +Jacobi symbols for secret data) to the posdivsteps version. diff --git a/external/secp256k1/examples/CMakeLists.txt b/external/secp256k1/examples/CMakeLists.txt new file mode 100644 index 00000000000..c9da9de6be3 --- /dev/null +++ b/external/secp256k1/examples/CMakeLists.txt @@ -0,0 +1,31 @@ +function(add_example name) + set(target_name ${name}_example) + add_executable(${target_name} ${name}.c) + target_include_directories(${target_name} PRIVATE + ${PROJECT_SOURCE_DIR}/include + ) + target_link_libraries(${target_name} + secp256k1 + $<$:bcrypt> + ) + set(test_name ${name}_example) + add_test(NAME secp256k1_${test_name} COMMAND ${target_name}) +endfunction() + +add_example(ecdsa) + +if(SECP256K1_ENABLE_MODULE_ECDH) + add_example(ecdh) +endif() + +if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + add_example(schnorr) +endif() + +if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + add_example(ellswift) +endif() + +if(SECP256K1_ENABLE_MODULE_MUSIG) + add_example(musig) +endif() diff --git a/external/secp256k1/examples/EXAMPLES_COPYING b/external/secp256k1/examples/EXAMPLES_COPYING new file mode 100644 index 00000000000..0e259d42c99 --- /dev/null +++ b/external/secp256k1/examples/EXAMPLES_COPYING @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/external/secp256k1/examples/ecdh.c b/external/secp256k1/examples/ecdh.c new file mode 100644 index 00000000000..13aa760b2dc --- /dev/null +++ b/external/secp256k1/examples/ecdh.c @@ -0,0 +1,120 @@ +/************************************************************************* + * Written in 2020-2022 by Elichai Turkel * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +#include +#include +#include + +#include +#include + +#include "examples_util.h" + +int main(void) { + unsigned char seckey1[32]; + unsigned char seckey2[32]; + unsigned char compressed_pubkey1[33]; + unsigned char compressed_pubkey2[33]; + unsigned char shared_secret1[32]; + unsigned char shared_secret2[32]; + unsigned char randomize[32]; + int return_val; + size_t len; + secp256k1_pubkey pubkey1; + secp256k1_pubkey pubkey2; + + /* Before we can call actual API functions, we need to create a "context". */ + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage See `secp256k1_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = secp256k1_context_randomize(ctx, randomize); + assert(return_val); + + /*** Key Generation ***/ + if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ + if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; + } + + /* Public key creation using a valid context with a verified secret key should never fail */ + return_val = secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1); + assert(return_val); + return_val = secp256k1_ec_pubkey_create(ctx, &pubkey2, seckey2); + assert(return_val); + + /* Serialize pubkey1 in a compressed form (33 bytes), should always return 1 */ + len = sizeof(compressed_pubkey1); + return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED); + assert(return_val); + /* Should be the same size as the size of the output, because we passed a 33 byte array. */ + assert(len == sizeof(compressed_pubkey1)); + + /* Serialize pubkey2 in a compressed form (33 bytes) */ + len = sizeof(compressed_pubkey2); + return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED); + assert(return_val); + /* Should be the same size as the size of the output, because we passed a 33 byte array. */ + assert(len == sizeof(compressed_pubkey2)); + + /*** Creating the shared secret ***/ + + /* Perform ECDH with seckey1 and pubkey2. Should never fail with a verified + * seckey and valid pubkey */ + return_val = secp256k1_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL); + assert(return_val); + + /* Perform ECDH with seckey2 and pubkey1. Should never fail with a verified + * seckey and valid pubkey */ + return_val = secp256k1_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL); + assert(return_val); + + /* Both parties should end up with the same shared secret */ + return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)); + assert(return_val == 0); + + printf("Secret Key1: "); + print_hex(seckey1, sizeof(seckey1)); + printf("Compressed Pubkey1: "); + print_hex(compressed_pubkey1, sizeof(compressed_pubkey1)); + printf("\nSecret Key2: "); + print_hex(seckey2, sizeof(seckey2)); + printf("Compressed Pubkey2: "); + print_hex(compressed_pubkey2, sizeof(compressed_pubkey2)); + printf("\nShared Secret: "); + print_hex(shared_secret1, sizeof(shared_secret1)); + + /* This will clear everything from the context and free the memory */ + secp256k1_context_destroy(ctx); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + secure_erase(seckey1, sizeof(seckey1)); + secure_erase(seckey2, sizeof(seckey2)); + secure_erase(shared_secret1, sizeof(shared_secret1)); + secure_erase(shared_secret2, sizeof(shared_secret2)); + + return 0; +} diff --git a/external/secp256k1/examples/ecdsa.c b/external/secp256k1/examples/ecdsa.c new file mode 100644 index 00000000000..80ae9d46c52 --- /dev/null +++ b/external/secp256k1/examples/ecdsa.c @@ -0,0 +1,137 @@ +/************************************************************************* + * Written in 2020-2022 by Elichai Turkel * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +#include +#include +#include + +#include + +#include "examples_util.h" + +int main(void) { + /* Instead of signing the message directly, we must sign a 32-byte hash. + * Here the message is "Hello, world!" and the hash function was SHA-256. + * An actual implementation should just call SHA-256, but this example + * hardcodes the output to avoid depending on an additional library. + * See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 */ + unsigned char msg_hash[32] = { + 0x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4, + 0x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64, + 0x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34, + 0x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3, + }; + unsigned char seckey[32]; + unsigned char randomize[32]; + unsigned char compressed_pubkey[33]; + unsigned char serialized_signature[64]; + size_t len; + int is_signature_valid, is_signature_valid2; + int return_val; + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + /* Before we can call actual API functions, we need to create a "context". */ + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage See `secp256k1_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = secp256k1_context_randomize(ctx, randomize); + assert(return_val); + + /*** Key Generation ***/ + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ + if (!secp256k1_ec_seckey_verify(ctx, seckey)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; + } + + /* Public key creation using a valid context with a verified secret key should never fail */ + return_val = secp256k1_ec_pubkey_create(ctx, &pubkey, seckey); + assert(return_val); + + /* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */ + len = sizeof(compressed_pubkey); + return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED); + assert(return_val); + /* Should be the same size as the size of the output, because we passed a 33 byte array. */ + assert(len == sizeof(compressed_pubkey)); + + /*** Signing ***/ + + /* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a + * custom nonce function, passing `NULL` will use the RFC-6979 safe default. + * Signing with a valid context, verified secret key + * and the default nonce function should never fail. */ + return_val = secp256k1_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL); + assert(return_val); + + /* Serialize the signature in a compact form. Should always return 1 + * according to the documentation in secp256k1.h. */ + return_val = secp256k1_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig); + assert(return_val); + + + /*** Verification ***/ + + /* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */ + if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) { + printf("Failed parsing the signature\n"); + return 1; + } + + /* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */ + if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) { + printf("Failed parsing the public key\n"); + return 1; + } + + /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */ + is_signature_valid = secp256k1_ecdsa_verify(ctx, &sig, msg_hash, &pubkey); + + printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false"); + printf("Secret Key: "); + print_hex(seckey, sizeof(seckey)); + printf("Public Key: "); + print_hex(compressed_pubkey, sizeof(compressed_pubkey)); + printf("Signature: "); + print_hex(serialized_signature, sizeof(serialized_signature)); + + /* This will clear everything from the context and free the memory */ + secp256k1_context_destroy(ctx); + + /* Bonus example: if all we need is signature verification (and no key + generation or signing), we don't need to use a context created via + secp256k1_context_create(). We can simply use the static (i.e., global) + context secp256k1_context_static. See its description in + include/secp256k1.h for details. */ + is_signature_valid2 = secp256k1_ecdsa_verify(secp256k1_context_static, + &sig, msg_hash, &pubkey); + assert(is_signature_valid2 == is_signature_valid); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + secure_erase(seckey, sizeof(seckey)); + + return 0; +} diff --git a/external/secp256k1/examples/ellswift.c b/external/secp256k1/examples/ellswift.c new file mode 100644 index 00000000000..afb2fee40be --- /dev/null +++ b/external/secp256k1/examples/ellswift.c @@ -0,0 +1,121 @@ +/************************************************************************* + * Written in 2024 by Sebastian Falbesoner * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +/** This file demonstrates how to use the ElligatorSwift module to perform + * a key exchange according to BIP 324. Additionally, see the documentation + * in include/secp256k1_ellswift.h and doc/ellswift.md. + */ + +#include +#include +#include + +#include +#include + +#include "examples_util.h" + +int main(void) { + secp256k1_context* ctx; + unsigned char randomize[32]; + unsigned char auxrand1[32]; + unsigned char auxrand2[32]; + unsigned char seckey1[32]; + unsigned char seckey2[32]; + unsigned char ellswift_pubkey1[64]; + unsigned char ellswift_pubkey2[64]; + unsigned char shared_secret1[32]; + unsigned char shared_secret2[32]; + int return_val; + + /* Create a secp256k1 context */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage. See `secp256k1_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = secp256k1_context_randomize(ctx, randomize); + assert(return_val); + + /*** Generate secret keys ***/ + if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ + if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; + } + + /* Generate ElligatorSwift public keys. This should never fail with valid context and + verified secret keys. Note that providing additional randomness (fourth parameter) is + optional, but recommended. */ + if (!fill_random(auxrand1, sizeof(auxrand1)) || !fill_random(auxrand2, sizeof(auxrand2))) { + printf("Failed to generate randomness\n"); + return 1; + } + return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey1, seckey1, auxrand1); + assert(return_val); + return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey2, seckey2, auxrand2); + assert(return_val); + + /*** Create the shared secret on each side ***/ + + /* Perform x-only ECDH with seckey1 and ellswift_pubkey2. Should never fail + * with a verified seckey and valid pubkey. Note that both parties pass both + * EllSwift pubkeys in the same order; the pubkey of the calling party is + * determined by the "party" boolean (sixth parameter). */ + return_val = secp256k1_ellswift_xdh(ctx, shared_secret1, ellswift_pubkey1, ellswift_pubkey2, + seckey1, 0, secp256k1_ellswift_xdh_hash_function_bip324, NULL); + assert(return_val); + + /* Perform x-only ECDH with seckey2 and ellswift_pubkey1. Should never fail + * with a verified seckey and valid pubkey. */ + return_val = secp256k1_ellswift_xdh(ctx, shared_secret2, ellswift_pubkey1, ellswift_pubkey2, + seckey2, 1, secp256k1_ellswift_xdh_hash_function_bip324, NULL); + assert(return_val); + + /* Both parties should end up with the same shared secret */ + return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)); + assert(return_val == 0); + + printf( " Secret Key1: "); + print_hex(seckey1, sizeof(seckey1)); + printf( "EllSwift Pubkey1: "); + print_hex(ellswift_pubkey1, sizeof(ellswift_pubkey1)); + printf("\n Secret Key2: "); + print_hex(seckey2, sizeof(seckey2)); + printf( "EllSwift Pubkey2: "); + print_hex(ellswift_pubkey2, sizeof(ellswift_pubkey2)); + printf("\n Shared Secret: "); + print_hex(shared_secret1, sizeof(shared_secret1)); + + /* This will clear everything from the context and free the memory */ + secp256k1_context_destroy(ctx); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + secure_erase(seckey1, sizeof(seckey1)); + secure_erase(seckey2, sizeof(seckey2)); + secure_erase(shared_secret1, sizeof(shared_secret1)); + secure_erase(shared_secret2, sizeof(shared_secret2)); + + return 0; +} diff --git a/external/secp256k1/examples/examples_util.h b/external/secp256k1/examples/examples_util.h new file mode 100644 index 00000000000..3293b640321 --- /dev/null +++ b/external/secp256k1/examples/examples_util.h @@ -0,0 +1,108 @@ +/************************************************************************* + * Copyright (c) 2020-2021 Elichai Turkel * + * Distributed under the CC0 software license, see the accompanying file * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +/* + * This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems. + * It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below. + * + * Platform randomness sources: + * Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom + * macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html + * FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4 + * OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom + * Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom + */ + +#if defined(_WIN32) +/* + * The defined WIN32_NO_STATUS macro disables return code definitions in + * windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h. + */ +#define WIN32_NO_STATUS +#include +#undef WIN32_NO_STATUS +#include +#include +#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) +#include +#elif defined(__OpenBSD__) +#include +#else +#error "Couldn't identify the OS" +#endif + +#include +#include +#include + + +/* Returns 1 on success, and 0 on failure. */ +static int fill_random(unsigned char* data, size_t size) { +#if defined(_WIN32) + NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG); + if (res != STATUS_SUCCESS || size > ULONG_MAX) { + return 0; + } else { + return 1; + } +#elif defined(__linux__) || defined(__FreeBSD__) + /* If `getrandom(2)` is not available you should fallback to /dev/urandom */ + ssize_t res = getrandom(data, size, 0); + if (res < 0 || (size_t)res != size ) { + return 0; + } else { + return 1; + } +#elif defined(__APPLE__) || defined(__OpenBSD__) + /* If `getentropy(2)` is not available you should fallback to either + * `SecRandomCopyBytes` or /dev/urandom */ + int res = getentropy(data, size); + if (res == 0) { + return 1; + } else { + return 0; + } +#endif + return 0; +} + +static void print_hex(unsigned char* data, size_t size) { + size_t i; + printf("0x"); + for (i = 0; i < size; i++) { + printf("%02x", data[i]); + } + printf("\n"); +} + +#if defined(_MSC_VER) +// For SecureZeroMemory +#include +#endif +/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ +static void secure_erase(void *ptr, size_t len) { +#if defined(_MSC_VER) + /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ + SecureZeroMemory(ptr, len); +#elif defined(__GNUC__) + /* We use a memory barrier that scares the compiler away from optimizing out the memset. + * + * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f + * in BoringSSL (ISC License): + * As best as we can tell, this is sufficient to break any optimisations that + * might try to eliminate "superfluous" memsets. + * This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is + * pretty efficient, because the compiler can still implement the memset() efficiently, + * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by + * Yang et al. (USENIX Security 2017) for more background. + */ + memset(ptr, 0, len); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#else + void *(*volatile const volatile_memset)(void *, int, size_t) = memset; + volatile_memset(ptr, 0, len); +#endif +} diff --git a/external/secp256k1/examples/musig.c b/external/secp256k1/examples/musig.c new file mode 100644 index 00000000000..0352dc40f37 --- /dev/null +++ b/external/secp256k1/examples/musig.c @@ -0,0 +1,260 @@ +/************************************************************************* + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +/** This file demonstrates how to use the MuSig module to create a + * 3-of-3 multisignature. Additionally, see the documentation in + * include/secp256k1_musig.h and doc/musig.md. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "examples_util.h" + +struct signer_secrets { + secp256k1_keypair keypair; + secp256k1_musig_secnonce secnonce; +}; + +struct signer { + secp256k1_pubkey pubkey; + secp256k1_musig_pubnonce pubnonce; + secp256k1_musig_partial_sig partial_sig; +}; + + /* Number of public keys involved in creating the aggregate signature */ +#define N_SIGNERS 3 +/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */ +static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) { + unsigned char seckey[32]; + + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 0; + } + /* Try to create a keypair with a valid context. This only fails if the + * secret key is zero or out of range (greater than secp256k1's order). Note + * that the probability of this occurring is negligible with a properly + * functioning random number generator. */ + if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) { + return 0; + } + if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) { + return 0; + } + + secure_erase(seckey, sizeof(seckey)); + return 1; +} + +/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache + * and return the tweaked aggregate pk. */ +static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) { + secp256k1_pubkey output_pk; + /* For BIP 32 tweaking the plain_tweak is set to a hash as defined in BIP + * 32. */ + unsigned char plain_tweak[32] = "this could be a BIP32 tweak...."; + /* For Taproot tweaking the xonly_tweak is set to the TapTweak hash as + * defined in BIP 341 */ + unsigned char xonly_tweak[32] = "this could be a Taproot tweak.."; + + + /* Plain tweaking which, for example, allows deriving multiple child + * public keys from a single aggregate key using BIP32 */ + if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) { + return 0; + } + /* Note that we did not provide an output_pk argument, because the + * resulting pk is also saved in the cache and so if one is just interested + * in signing, the output_pk argument is unnecessary. On the other hand, if + * one is not interested in signing, the same output_pk can be obtained by + * calling `secp256k1_musig_pubkey_get` right after key aggregation to get + * the full pubkey and then call `secp256k1_ec_pubkey_tweak_add`. */ + + /* Xonly tweaking which, for example, allows creating Taproot commitments */ + if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) { + return 0; + } + /* Note that if we wouldn't care about signing, we can arrive at the same + * output_pk by providing the untweaked public key to + * `secp256k1_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey + * if necessary with `secp256k1_xonly_pubkey_from_pubkey`). */ + + /* Now we convert the output_pk to an xonly pubkey to allow to later verify + * the Schnorr signature against it. For this purpose we can ignore the + * `pk_parity` output argument; we would need it if we would have to open + * the Taproot commitment. */ + if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) { + return 0; + } + return 1; +} + +/* Sign a message hash with the given key pairs and store the result in sig */ +static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) { + int i; + const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS]; + const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS]; + /* The same for all signers */ + secp256k1_musig_session session; + secp256k1_musig_aggnonce agg_pubnonce; + + for (i = 0; i < N_SIGNERS; i++) { + unsigned char seckey[32]; + unsigned char session_secrand[32]; + /* Create random session ID. It is absolutely necessary that the session ID + * is unique for every call of secp256k1_musig_nonce_gen. Otherwise + * it's trivial for an attacker to extract the secret key! */ + if (!fill_random(session_secrand, sizeof(session_secrand))) { + return 0; + } + if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) { + return 0; + } + /* Initialize session and create secret nonce for signing and public + * nonce to send to the other signers. */ + if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) { + return 0; + } + pubnonces[i] = &signer[i].pubnonce; + + secure_erase(seckey, sizeof(seckey)); + } + + /* Communication round 1: Every signer sends their pubnonce to the + * coordinator. The coordinator runs secp256k1_musig_nonce_agg and sends + * agg_pubnonce to each signer */ + if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) { + return 0; + } + + /* Every signer creates a partial signature */ + for (i = 0; i < N_SIGNERS; i++) { + /* Initialize the signing session by processing the aggregate nonce */ + if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache)) { + return 0; + } + /* partial_sign will clear the secnonce by setting it to 0. That's because + * you must _never_ reuse the secnonce (or use the same session_secrand to + * create a secnonce). If you do, you effectively reuse the nonce and + * leak the secret key. */ + if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) { + return 0; + } + partial_sigs[i] = &signer[i].partial_sig; + } + /* Communication round 2: Every signer sends their partial signature to the + * coordinator, who verifies the partial signatures and aggregates them. */ + for (i = 0; i < N_SIGNERS; i++) { + /* To check whether signing was successful, it suffices to either verify + * the aggregate signature with the aggregate public key using + * secp256k1_schnorrsig_verify, or verify all partial signatures of all + * signers individually. Verifying the aggregate signature is cheaper but + * verifying the individual partial signatures has the advantage that it + * can be used to determine which of the partial signatures are invalid + * (if any), i.e., which of the partial signatures cause the aggregate + * signature to be invalid and thus the protocol run to fail. It's also + * fine to first verify the aggregate sig, and only verify the individual + * sigs if it does not work. + */ + if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) { + return 0; + } + } + return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS); +} + +int main(void) { + secp256k1_context* ctx; + int i; + struct signer_secrets signer_secrets[N_SIGNERS]; + struct signer signers[N_SIGNERS]; + const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_keyagg_cache cache; + unsigned char msg[32] = "this_could_be_the_hash_of_a_msg"; + unsigned char sig[64]; + + /* Create a secp256k1 context */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + printf("Creating key pairs......"); + fflush(stdout); + for (i = 0; i < N_SIGNERS; i++) { + if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) { + printf("FAILED\n"); + return 1; + } + pubkeys_ptr[i] = &signers[i].pubkey; + } + printf("ok\n"); + + /* The aggregate public key produced by secp256k1_musig_pubkey_agg depends + * on the order of the provided public keys. If there is no canonical order + * of the signers, the individual public keys can optionally be sorted with + * secp256k1_ec_pubkey_sort to ensure that the aggregate public key is + * independent of the order of signers. */ + printf("Sorting public keys....."); + fflush(stdout); + if (!secp256k1_ec_pubkey_sort(ctx, pubkeys_ptr, N_SIGNERS)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + + printf("Combining public keys..."); + fflush(stdout); + /* If you just want to aggregate and not sign, you can call + * secp256k1_musig_pubkey_agg with the keyagg_cache argument set to NULL + * while providing a non-NULL agg_pk argument. */ + if (!secp256k1_musig_pubkey_agg(ctx, NULL, &cache, pubkeys_ptr, N_SIGNERS)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Tweaking................"); + fflush(stdout); + /* Optionally tweak the aggregate key */ + if (!tweak(ctx, &agg_pk, &cache)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Signing message........."); + fflush(stdout); + if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Verifying signature....."); + fflush(stdout); + if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite secret key material with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + for (i = 0; i < N_SIGNERS; i++) { + secure_erase(&signer_secrets[i], sizeof(signer_secrets[i])); + } + secp256k1_context_destroy(ctx); + return 0; +} diff --git a/external/secp256k1/examples/schnorr.c b/external/secp256k1/examples/schnorr.c new file mode 100644 index 00000000000..909fcaa1f3f --- /dev/null +++ b/external/secp256k1/examples/schnorr.c @@ -0,0 +1,153 @@ +/************************************************************************* + * Written in 2020-2022 by Elichai Turkel * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include "examples_util.h" + +int main(void) { + unsigned char msg[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; + unsigned char msg_hash[32]; + unsigned char tag[] = {'m', 'y', '_', 'f', 'a', 'n', 'c', 'y', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l'}; + unsigned char seckey[32]; + unsigned char randomize[32]; + unsigned char auxiliary_rand[32]; + unsigned char serialized_pubkey[32]; + unsigned char signature[64]; + int is_signature_valid, is_signature_valid2; + int return_val; + secp256k1_xonly_pubkey pubkey; + secp256k1_keypair keypair; + /* Before we can call actual API functions, we need to create a "context". */ + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage See `secp256k1_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = secp256k1_context_randomize(ctx, randomize); + assert(return_val); + + /*** Key Generation ***/ + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* Try to create a keypair with a valid context. This only fails if the + * secret key is zero or out of range (greater than secp256k1's order). Note + * that the probability of this occurring is negligible with a properly + * functioning random number generator. */ + if (!secp256k1_keypair_create(ctx, &keypair, seckey)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; + } + + /* Extract the X-only public key from the keypair. We pass NULL for + * `pk_parity` as the parity isn't needed for signing or verification. + * `secp256k1_keypair_xonly_pub` supports returning the parity for + * other use cases such as tests or verifying Taproot tweaks. + * This should never fail with a valid context and public key. */ + return_val = secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &keypair); + assert(return_val); + + /* Serialize the public key. Should always return 1 for a valid public key. */ + return_val = secp256k1_xonly_pubkey_serialize(ctx, serialized_pubkey, &pubkey); + assert(return_val); + + /*** Signing ***/ + + /* Instead of signing (possibly very long) messages directly, we sign a + * 32-byte hash of the message in this example. + * + * We use secp256k1_tagged_sha256 to create this hash. This function expects + * a context-specific "tag", which restricts the context in which the signed + * messages should be considered valid. For example, if protocol A mandates + * to use the tag "my_fancy_protocol" and protocol B mandates to use the tag + * "my_boring_protocol", then signed messages from protocol A will never be + * valid in protocol B (and vice versa), even if keys are reused across + * protocols. This implements "domain separation", which is considered good + * practice. It avoids attacks in which users are tricked into signing a + * message that has intended consequences in the intended context (e.g., + * protocol A) but would have unintended consequences if it were valid in + * some other context (e.g., protocol B). */ + return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); + assert(return_val); + + /* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */ + if (!fill_random(auxiliary_rand, sizeof(auxiliary_rand))) { + printf("Failed to generate randomness\n"); + return 1; + } + + /* Generate a Schnorr signature. + * + * We use the secp256k1_schnorrsig_sign32 function that provides a simple + * interface for signing 32-byte messages (which in our case is a hash of + * the actual message). BIP-340 recommends passing 32 bytes of randomness + * to the signing function to improve security against side-channel attacks. + * Signing with a valid context, a 32-byte message, a verified keypair, and + * any 32 bytes of auxiliary random data should never fail. */ + return_val = secp256k1_schnorrsig_sign32(ctx, signature, msg_hash, &keypair, auxiliary_rand); + assert(return_val); + + /*** Verification ***/ + + /* Deserialize the public key. This will return 0 if the public key can't + * be parsed correctly */ + if (!secp256k1_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) { + printf("Failed parsing the public key\n"); + return 1; + } + + /* Compute the tagged hash on the received messages using the same tag as the signer. */ + return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); + assert(return_val); + + /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */ + is_signature_valid = secp256k1_schnorrsig_verify(ctx, signature, msg_hash, 32, &pubkey); + + + printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false"); + printf("Secret Key: "); + print_hex(seckey, sizeof(seckey)); + printf("Public Key: "); + print_hex(serialized_pubkey, sizeof(serialized_pubkey)); + printf("Signature: "); + print_hex(signature, sizeof(signature)); + + /* This will clear everything from the context and free the memory */ + secp256k1_context_destroy(ctx); + + /* Bonus example: if all we need is signature verification (and no key + generation or signing), we don't need to use a context created via + secp256k1_context_create(). We can simply use the static (i.e., global) + context secp256k1_context_static. See its description in + include/secp256k1.h for details. */ + is_signature_valid2 = secp256k1_schnorrsig_verify(secp256k1_context_static, + signature, msg_hash, 32, &pubkey); + assert(is_signature_valid2 == is_signature_valid); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + secure_erase(seckey, sizeof(seckey)); + return 0; +} diff --git a/external/secp256k1/include/secp256k1.h b/external/secp256k1/include/secp256k1.h new file mode 100644 index 00000000000..c6e9417f055 --- /dev/null +++ b/external/secp256k1/include/secp256k1.h @@ -0,0 +1,899 @@ +#ifndef SECP256K1_H +#define SECP256K1_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** Unless explicitly stated all pointer arguments must not be NULL. + * + * The following rules specify the order of arguments in API calls: + * + * 1. Context pointers go first, followed by output arguments, combined + * output/input arguments, and finally input-only arguments. + * 2. Array lengths always immediately follow the argument whose length + * they describe, even if this violates rule 1. + * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated + * later go first. This means: signatures, public nonces, secret nonces, + * messages, public keys, secret keys, tweaks. + * 4. Arguments that are not data pointers go last, from more complex to less + * complex: function pointers, algorithm names, messages, void pointers, + * counts, flags, booleans. + * 5. Opaque data pointers follow the function pointer they are to be passed to. + */ + +/** Opaque data structure that holds context information + * + * The primary purpose of context objects is to store randomization data for + * enhanced protection against side-channel leakage. This protection is only + * effective if the context is randomized after its creation. See + * secp256k1_context_create for creation of contexts and + * secp256k1_context_randomize for randomization. + * + * A secondary purpose of context objects is to store pointers to callback + * functions that the library will call when certain error states arise. See + * secp256k1_context_set_error_callback as well as + * secp256k1_context_set_illegal_callback for details. Future library versions + * may use context objects for additional purposes. + * + * A constructed context can safely be used from multiple threads + * simultaneously, but API calls that take a non-const pointer to a context + * need exclusive access to it. In particular this is the case for + * secp256k1_context_destroy, secp256k1_context_preallocated_destroy, + * and secp256k1_context_randomize. + * + * Regarding randomization, either do it once at creation time (in which case + * you do not need any locking for the other calls), or use a read-write lock. + */ +typedef struct secp256k1_context_struct secp256k1_context; + +/** Opaque data structure that holds a parsed and valid public key. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, + * use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To + * compare keys, use secp256k1_ec_pubkey_cmp. + */ +typedef struct secp256k1_pubkey { + unsigned char data[64]; +} secp256k1_pubkey; + +/** Opaque data structure that holds a parsed ECDSA signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_parse_* functions. + */ +typedef struct secp256k1_ecdsa_signature { + unsigned char data[64]; +} secp256k1_ecdsa_signature; + +/** A pointer to a function to deterministically generate a nonce. + * + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. + * Out: nonce32: pointer to a 32-byte array to be filled by the function. + * In: msg32: the 32-byte message hash being verified (will not be NULL) + * key32: pointer to a 32-byte secret key (will not be NULL) + * algo16: pointer to a 16-byte array describing the signature + * algorithm (will be NULL for ECDSA for compatibility). + * data: Arbitrary data pointer that is passed through. + * attempt: how many iterations we have tried to find a nonce. + * This will almost always be 0, but different attempt values + * are required to result in a different nonce. + * + * Except for test cases, this function should compute some cryptographic hash of + * the message, the algorithm, the key and the attempt. + */ +typedef int (*secp256k1_nonce_function)( + unsigned char *nonce32, + const unsigned char *msg32, + const unsigned char *key32, + const unsigned char *algo16, + void *data, + unsigned int attempt +); + +# if !defined(SECP256K1_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define SECP256K1_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define SECP256K1_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +/* When this header is used at build-time the SECP256K1_BUILD define needs to be set + * to correctly setup export attributes and nullness checks. This is normally done + * by secp256k1.c but to guard against this header being included before secp256k1.c + * has had a chance to set the define (e.g. via test harnesses that just includes + * secp256k1.c) we set SECP256K1_NO_BUILD when this header is processed without the + * BUILD define so this condition can be caught. + */ +#ifndef SECP256K1_BUILD +# define SECP256K1_NO_BUILD +#endif + +/* Symbol visibility. */ +#if defined(_WIN32) + /* GCC for Windows (e.g., MinGW) accepts the __declspec syntax + * for MSVC compatibility. A __declspec declaration implies (but is not + * exactly equivalent to) __attribute__ ((visibility("default"))), and so we + * actually want __declspec even on GCC, see "Microsoft Windows Function + * Attributes" in the GCC manual and the recommendations in + * https://gcc.gnu.org/wiki/Visibility. */ +# if defined(SECP256K1_BUILD) +# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT) + /* Building libsecp256k1 as a DLL. + * 1. If using Libtool, it defines DLL_EXPORT automatically. + * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */ +# define SECP256K1_API extern __declspec (dllexport) +# else + /* Building libsecp256k1 as a static library on Windows. + * No declspec is needed, and so we would want the non-Windows-specific + * logic below take care of this case. However, this may result in setting + * __attribute__ ((visibility("default"))), which is supposed to be a noop + * on Windows but may trigger warnings when compiling with -flto due to a + * bug in GCC, see + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */ +# define SECP256K1_API extern +# endif + /* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static + * library on Windows. */ +# elif !defined(SECP256K1_STATIC) + /* Consuming libsecp256k1 as a DLL. */ +# define SECP256K1_API extern __declspec (dllimport) +# endif +#endif +#ifndef SECP256K1_API +/* All cases not captured by the Windows-specific logic. */ +# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) + /* Building libsecp256k1 using GCC or compatible. */ +# define SECP256K1_API extern __attribute__ ((visibility ("default"))) +# else + /* Fall back to standard C's extern. */ +# define SECP256K1_API extern +# endif +#endif + +/* Warning attributes + * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out + * some paranoid null checks. */ +# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) +# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +# else +# define SECP256K1_WARN_UNUSED_RESULT +# endif +# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) +# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) +# else +# define SECP256K1_ARG_NONNULL(_x) +# endif + +/* Attribute for marking functions, types, and variables as deprecated */ +#if !defined(SECP256K1_BUILD) && defined(__has_attribute) +# if __has_attribute(__deprecated__) +# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg))) +# else +# define SECP256K1_DEPRECATED(_msg) +# endif +#else +# define SECP256K1_DEPRECATED(_msg) +#endif + +/* All flags' lower 8 bits indicate what they're for. Do not use directly. */ +#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) +#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) +#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) +/* The higher bits contain the actual data. Do not use directly. */ +#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) +#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) +#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10) +#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) + +/** Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and + * secp256k1_context_preallocated_create. */ +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) + +/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */ +#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) +#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) + +/* Testing flag. Do not use. */ +#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY) + +/** Flag to pass to secp256k1_ec_pubkey_serialize. */ +#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) +#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) + +/** Prefix byte used to tag various encoded curvepoints for specific purposes */ +#define SECP256K1_TAG_PUBKEY_EVEN 0x02 +#define SECP256K1_TAG_PUBKEY_ODD 0x03 +#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04 +#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 +#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 + +/** A built-in constant secp256k1 context object with static storage duration, to be + * used in conjunction with secp256k1_selftest. + * + * This context object offers *only limited functionality* , i.e., it cannot be used + * for API functions that perform computations involving secret keys, e.g., signing + * and public key generation. If this restriction applies to a specific API function, + * it is mentioned in its documentation. See secp256k1_context_create if you need a + * full context object that supports all functionality offered by the library. + * + * It is highly recommended to call secp256k1_selftest before using this context. + */ +SECP256K1_API const secp256k1_context *secp256k1_context_static; + +/** Deprecated alias for secp256k1_context_static. */ +SECP256K1_API const secp256k1_context *secp256k1_context_no_precomp +SECP256K1_DEPRECATED("Use secp256k1_context_static instead"); + +/** Perform basic self tests (to be used in conjunction with secp256k1_context_static) + * + * This function performs self tests that detect some serious usage errors and + * similar conditions, e.g., when the library is compiled for the wrong endianness. + * This is a last resort measure to be used in production. The performed tests are + * very rudimentary and are not intended as a replacement for running the test + * binaries. + * + * It is highly recommended to call this before using secp256k1_context_static. + * It is not necessary to call this function before using a context created with + * secp256k1_context_create (or secp256k1_context_preallocated_create), which will + * take care of performing the self tests. + * + * If the tests fail, this function will call the default error handler to abort the + * program (see secp256k1_context_set_error_callback). + */ +SECP256K1_API void secp256k1_selftest(void); + + +/** Create a secp256k1 context object (in dynamically allocated memory). + * + * This function uses malloc to allocate memory. It is guaranteed that malloc is + * called at most once for every call of this function. If you need to avoid dynamic + * memory allocation entirely, see secp256k1_context_static and the functions in + * secp256k1_preallocated.h. + * + * Returns: pointer to a newly created context object. + * In: flags: Always set to SECP256K1_CONTEXT_NONE (see below). + * + * The only valid non-deprecated flag in recent library versions is + * SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality + * offered by the library. All other (deprecated) flags will be treated as equivalent + * to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for + * historical reasons, future versions of the library may introduce new flags. + * + * If the context is intended to be used for API functions that perform computations + * involving secret keys, e.g., signing and public key generation, then it is highly + * recommended to call secp256k1_context_randomize on the context before calling + * those API functions. This will provide enhanced protection against side-channel + * leakage, see secp256k1_context_randomize for details. + * + * Do not create a new context object for each operation, as construction and + * randomization can take non-negligible time. + */ +SECP256K1_API secp256k1_context *secp256k1_context_create( + unsigned int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Copy a secp256k1 context object (into dynamically allocated memory). + * + * This function uses malloc to allocate memory. It is guaranteed that malloc is + * called at most once for every call of this function. If you need to avoid dynamic + * memory allocation entirely, see the functions in secp256k1_preallocated.h. + * + * Cloning secp256k1_context_static is not possible, and should not be emulated by + * the caller (e.g., using memcpy). Create a new context instead. + * + * Returns: pointer to a newly created context object. + * Args: ctx: pointer to a context to copy (not secp256k1_context_static). + */ +SECP256K1_API secp256k1_context *secp256k1_context_clone( + const secp256k1_context *ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object (created in dynamically allocated memory). + * + * The context pointer may not be used afterwards. + * + * The context to destroy must have been created using secp256k1_context_create + * or secp256k1_context_clone. If the context has instead been created using + * secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone, the + * behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must + * be used instead. + * + * Args: ctx: pointer to a context to destroy, constructed using + * secp256k1_context_create or secp256k1_context_clone + * (i.e., not secp256k1_context_static). + */ +SECP256K1_API void secp256k1_context_destroy( + secp256k1_context *ctx +) SECP256K1_ARG_NONNULL(1); + +/** Set a callback function to be called when an illegal argument is passed to + * an API call. It will only trigger for violations that are mentioned + * explicitly in the header. + * + * The philosophy is that these shouldn't be dealt with through a + * specific return value, as calling code should not have branches to deal with + * the case that this code itself is broken. + * + * On the other hand, during debug stage, one would want to be informed about + * such mistakes, and the default (crashing) may be inadvisable. + * When this callback is triggered, the API function called is guaranteed not + * to cause a crash, though its return value and output arguments are + * undefined. + * + * When this function has not been called (or called with fn==NULL), then the + * default handler will be used. The library provides a default handler which + * writes the message to stderr and calls abort. This default handler can be + * replaced at link time if the preprocessor macro + * USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build + * has been configured with --enable-external-default-callbacks. Then the + * following two symbols must be provided to link against: + * - void secp256k1_default_illegal_callback_fn(const char *message, void *data); + * - void secp256k1_default_error_callback_fn(const char *message, void *data); + * The library can call these default handlers even before a proper callback data + * pointer could have been set using secp256k1_context_set_illegal_callback or + * secp256k1_context_set_error_callback, e.g., when the creation of a context + * fails. In this case, the corresponding default handler will be called with + * the data pointer argument set to NULL. + * + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an illegal argument is + * passed to the API, taking a message and an opaque pointer. + * (NULL restores the default handler.) + * data: the opaque pointer to pass to fun above, must be NULL for the default handler. + * + * See also secp256k1_context_set_error_callback. + */ +SECP256K1_API void secp256k1_context_set_illegal_callback( + secp256k1_context *ctx, + void (*fun)(const char *message, void *data), + const void *data +) SECP256K1_ARG_NONNULL(1); + +/** Set a callback function to be called when an internal consistency check + * fails. + * + * The default callback writes an error message to stderr and calls abort + * to abort the program. + * + * This can only trigger in case of a hardware failure, miscompilation, + * memory corruption, serious bug in the library, or other error would can + * otherwise result in undefined behaviour. It will not trigger due to mere + * incorrect usage of the API (see secp256k1_context_set_illegal_callback + * for that). After this callback returns, anything may happen, including + * crashing. + * + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an internal error occurs, + * taking a message and an opaque pointer (NULL restores the + * default handler, see secp256k1_context_set_illegal_callback + * for details). + * data: the opaque pointer to pass to fun above, must be NULL for the default handler. + * + * See also secp256k1_context_set_illegal_callback. + */ +SECP256K1_API void secp256k1_context_set_error_callback( + secp256k1_context *ctx, + void (*fun)(const char *message, void *data), + const void *data +) SECP256K1_ARG_NONNULL(1); + +/** Parse a variable-length public key into the pubkey object. + * + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, its value is undefined. + * In: input: pointer to a serialized public key + * inputlen: length of the array pointed to by input + * + * This function supports parsing compressed (33 bytes, header byte 0x02 or + * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header + * byte 0x06 or 0x07) format public keys. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a pubkey object into a serialized byte sequence. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object. + * Out: output: pointer to a 65-byte (if compressed==0) or 33-byte (if + * compressed==1) byte array to place the serialized key + * in. + * In/Out: outputlen: pointer to an integer which is initially set to the + * size of output, and is overwritten with the written + * size. + * In: pubkey: pointer to a secp256k1_pubkey containing an + * initialized public key. + * flags: SECP256K1_EC_COMPRESSED if serialization should be in + * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. + */ +SECP256K1_API int secp256k1_ec_pubkey_serialize( + const secp256k1_context *ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_pubkey *pubkey, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Compare two public keys using lexicographic (of compressed serialization) order + * + * Returns: <0 if the first public key is less than the second + * >0 if the first public key is greater than the second + * 0 if the two public keys are equal + * Args: ctx: pointer to a context object + * In: pubkey1: first public key to compare + * pubkey2: second public key to compare + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp( + const secp256k1_context *ctx, + const secp256k1_pubkey *pubkey1, + const secp256k1_pubkey *pubkey2 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Sort public keys using lexicographic (of compressed serialization) order + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * + * Args: ctx: pointer to a context object + * In: pubkeys: array of pointers to pubkeys to sort + * n_pubkeys: number of elements in the pubkeys array + */ +SECP256K1_API int secp256k1_ec_pubkey_sort( + const secp256k1_context *ctx, + const secp256k1_pubkey **pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Parse an ECDSA signature in compact (64 bytes) format. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to the 64-byte array to parse + * + * The signature must consist of a 32-byte big endian R value, followed by a + * 32-byte big endian S value. If R or S fall outside of [0..order-1], the + * encoding is invalid. R and S with value 0 are allowed in the encoding. + * + * After the call, sig will always be initialized. If parsing failed or R or + * S are zero, the resulting sig value is guaranteed to fail verification for + * any message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( + const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, + const unsigned char *input64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a DER ECDSA signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input: pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature verification with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_der( + const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in DER format. + * + * Returns: 1 if enough space was available to serialize, 0 otherwise + * Args: ctx: pointer to a context object + * Out: output: pointer to an array to store the DER serialization + * In/Out: outputlen: pointer to a length integer. Initially, this integer + * should be set to the length of output. After the call + * it will be set to the length of the serialization (even + * if 0 was returned). + * In: sig: pointer to an initialized signature object + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( + const secp256k1_context *ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_ecdsa_signature *sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Serialize an ECDSA signature in compact (64 byte) format. + * + * Returns: 1 + * Args: ctx: pointer to a context object + * Out: output64: pointer to a 64-byte array to store the compact serialization + * In: sig: pointer to an initialized signature object + * + * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( + const secp256k1_context *ctx, + unsigned char *output64, + const secp256k1_ecdsa_signature *sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Verify an ECDSA signature. + * + * Returns: 1: correct signature + * 0: incorrect or unparseable signature + * Args: ctx: pointer to a context object + * In: sig: the signature being verified. + * msghash32: the 32-byte message hash being verified. + * The verifier must make sure to apply a cryptographic + * hash function to the message by itself and not accept an + * msghash32 value directly. Otherwise, it would be easy to + * create a "valid" signature without knowledge of the + * secret key. See also + * https://bitcoin.stackexchange.com/a/81116/35586 for more + * background on this topic. + * pubkey: pointer to an initialized public key to verify with. + * + * To avoid accepting malleable signatures, only ECDSA signatures in lower-S + * form are accepted. + * + * If you need to accept ECDSA signatures from sources that do not obey this + * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to + * verification, but be aware that doing so results in malleable signatures. + * + * For details, see the comments for that function. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( + const secp256k1_context *ctx, + const secp256k1_ecdsa_signature *sig, + const unsigned char *msghash32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Convert a signature to a normalized lower-S form. + * + * Returns: 1 if sigin was not normalized, 0 if it already was. + * Args: ctx: pointer to a context object + * Out: sigout: pointer to a signature to fill with the normalized form, + * or copy if the input was already normalized. (can be NULL if + * you're only interested in whether the input was already + * normalized). + * In: sigin: pointer to a signature to check/normalize (can be identical to sigout) + * + * With ECDSA a third-party can forge a second distinct signature of the same + * message, given a single initial signature, but without knowing the key. This + * is done by negating the S value modulo the order of the curve, 'flipping' + * the sign of the random point R which is not included in the signature. + * + * Forgery of the same message isn't universally problematic, but in systems + * where message malleability or uniqueness of signatures is important this can + * cause issues. This forgery can be blocked by all verifiers forcing signers + * to use a normalized form. + * + * The lower-S form reduces the size of signatures slightly on average when + * variable length encodings (such as DER) are used and is cheap to verify, + * making it a good choice. Security of always using lower-S is assured because + * anyone can trivially modify a signature after the fact to enforce this + * property anyway. + * + * The lower S value is always between 0x1 and + * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, + * inclusive. + * + * No other forms of ECDSA malleability are known and none seem likely, but + * there is no formal proof that ECDSA, even with this additional restriction, + * is free of other malleability. Commonly used serialization schemes will also + * accept various non-unique encodings, so care should be taken when this + * property is required for an application. + * + * The secp256k1_ecdsa_sign function will by default create signatures in the + * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case + * signatures come from a system that cannot enforce this property, + * secp256k1_ecdsa_signature_normalize must be called before verification. + */ +SECP256K1_API int secp256k1_ecdsa_signature_normalize( + const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sigout, + const secp256k1_ecdsa_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); + +/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. + * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of + * extra entropy. + */ +SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; + +/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ +SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default; + +/** Create an ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the secret key was invalid. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig: pointer to an array where the signature will be placed. + * In: msghash32: the 32-byte message hash being signed. + * seckey: pointer to a 32-byte secret key. + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used. + * ndata: pointer to arbitrary data used by the nonce generation function + * (can be NULL). If it is non-NULL and + * secp256k1_nonce_function_default is used, then ndata must be a + * pointer to 32-bytes of additional data. + * + * The created signature is always in lower-S form. See + * secp256k1_ecdsa_signature_normalize for more details. + */ +SECP256K1_API int secp256k1_ecdsa_sign( + const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, + const unsigned char *msghash32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verify an elliptic curve secret key. + * + * A secret key is valid if it is not 0 and less than the secp256k1 curve order + * when interpreted as an integer (most significant byte first). The + * probability of choosing a 32-byte string uniformly at random which is an + * invalid secret key is negligible. However, if it does happen it should + * be assumed that the randomness source is severely broken and there should + * be no retry. + * + * Returns: 1: secret key is valid + * 0: secret key is invalid + * Args: ctx: pointer to a context object. + * In: seckey: pointer to a 32-byte secret key. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( + const secp256k1_context *ctx, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Compute the public key for a secret key. + * + * Returns: 1: secret was valid, public key stores. + * 0: secret was invalid, try again. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: pubkey: pointer to the created public key. + * In: seckey: pointer to a 32-byte secret key. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Negates a secret key in place. + * + * Returns: 0 if the given secret key is invalid according to + * secp256k1_ec_seckey_verify. 1 otherwise + * Args: ctx: pointer to a context object + * In/Out: seckey: pointer to the 32-byte secret key to be negated. If the + * secret key is invalid according to + * secp256k1_ec_seckey_verify, this function returns 0 and + * seckey will be set to some unspecified value. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate( + const secp256k1_context *ctx, + unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in + * future versions. */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate( + const secp256k1_context *ctx, + unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) + SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead"); + +/** Negates a public key in place. + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * In/Out: pubkey: pointer to the public key to be negated. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Tweak a secret key by adding tweak to it. + * + * Returns: 0 if the arguments are invalid or the resulting secret key would be + * invalid (only when the tweak is the negation of the secret key). 1 + * otherwise. + * Args: ctx: pointer to a context object. + * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is + * invalid according to secp256k1_ec_seckey_verify, this + * function returns 0. seckey will be set to some unspecified + * value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add( + const secp256k1_context *ctx, + unsigned char *seckey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in + * future versions. */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( + const secp256k1_context *ctx, + unsigned char *seckey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) + SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead"); + +/** Tweak a public key by adding tweak times the generator to it. + * + * Returns: 0 if the arguments are invalid or the resulting public key would be + * invalid (only when the tweak is the negation of the corresponding + * secret key). 1 otherwise. + * Args: ctx: pointer to a context object. + * In/Out: pubkey: pointer to a public key object. pubkey will be set to an + * invalid value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a secret key by multiplying it by a tweak. + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * Args: ctx: pointer to a context object. + * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is + * invalid according to secp256k1_ec_seckey_verify, this + * function returns 0. seckey will be set to some unspecified + * value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to + * secp256k1_ec_seckey_verify, this function returns 0. For + * uniformly random 32-byte arrays the chance of being invalid + * is negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul( + const secp256k1_context *ctx, + unsigned char *seckey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in + * future versions. */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( + const secp256k1_context *ctx, + unsigned char *seckey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) + SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead"); + +/** Tweak a public key by multiplying it by a tweak value. + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * Args: ctx: pointer to a context object. + * In/Out: pubkey: pointer to a public key object. pubkey will be set to an + * invalid value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to + * secp256k1_ec_seckey_verify, this function returns 0. For + * uniformly random 32-byte arrays the chance of being invalid + * is negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Randomizes the context to provide enhanced protection against side-channel leakage. + * + * Returns: 1: randomization successful + * 0: error + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state). + * + * While secp256k1 code is written and tested to be constant-time no matter what + * secret values are, it is possible that a compiler may output code which is not, + * and also that the CPU may not emit the same radio frequencies or draw the same + * amount of power for all values. Randomization of the context shields against + * side-channel observations which aim to exploit secret-dependent behaviour in + * certain computations which involve secret keys. + * + * It is highly recommended to call this function on contexts returned from + * secp256k1_context_create or secp256k1_context_clone (or from the corresponding + * functions in secp256k1_preallocated.h) before using these contexts to call API + * functions that perform computations involving secret keys, e.g., signing and + * public key generation. It is possible to call this function more than once on + * the same context, and doing so before every few computations involving secret + * keys is recommended as a defense-in-depth measure. Randomization of the static + * context secp256k1_context_static is not supported. + * + * Currently, the random seed is mainly used for blinding multiplications of a + * secret scalar with the elliptic curve base point. Multiplications of this + * kind are performed by exactly those API functions which are documented to + * require a context that is not secp256k1_context_static. As a rule of thumb, + * these are all functions which take a secret key (or a keypair) as an input. + * A notable exception to that rule is the ECDH module, which relies on a different + * kind of elliptic curve point multiplication and thus does not benefit from + * enhanced protection against side-channel leakage currently. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( + secp256k1_context *ctx, + const unsigned char *seed32 +) SECP256K1_ARG_NONNULL(1); + +/** Add a number of public keys together. + * + * Returns: 1: the sum of the public keys is valid. + * 0: the sum of the public keys is not valid. + * Args: ctx: pointer to a context object. + * Out: out: pointer to a public key object for placing the resulting public key. + * In: ins: pointer to array of pointers to public keys. + * n: the number of public keys to add together (must be at least 1). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( + const secp256k1_context *ctx, + secp256k1_pubkey *out, + const secp256k1_pubkey * const *ins, + size_t n +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Compute a tagged hash as defined in BIP-340. + * + * This is useful for creating a message hash and achieving domain separation + * through an application-specific tag. This function returns + * SHA256(SHA256(tag)||SHA256(tag)||msg). Therefore, tagged hash + * implementations optimized for a specific tag can precompute the SHA256 state + * after hashing the tag hashes. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object + * Out: hash32: pointer to a 32-byte array to store the resulting hash + * In: tag: pointer to an array containing the tag + * taglen: length of the tag array + * msg: pointer to an array containing the message + * msglen: length of the message array + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256( + const secp256k1_context *ctx, + unsigned char *hash32, + const unsigned char *tag, + size_t taglen, + const unsigned char *msg, + size_t msglen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_H */ diff --git a/external/secp256k1/include/secp256k1_ecdh.h b/external/secp256k1/include/secp256k1_ecdh.h new file mode 100644 index 00000000000..4d9da3461d2 --- /dev/null +++ b/external/secp256k1/include/secp256k1_ecdh.h @@ -0,0 +1,63 @@ +#ifndef SECP256K1_ECDH_H +#define SECP256K1_ECDH_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** A pointer to a function that hashes an EC point to obtain an ECDH secret + * + * Returns: 1 if the point was successfully hashed. + * 0 will cause secp256k1_ecdh to fail and return 0. + * Other return values are not allowed, and the behaviour of + * secp256k1_ecdh is undefined for other return values. + * Out: output: pointer to an array to be filled by the function + * In: x32: pointer to a 32-byte x coordinate + * y32: pointer to a 32-byte y coordinate + * data: arbitrary data pointer that is passed through + */ +typedef int (*secp256k1_ecdh_hash_function)( + unsigned char *output, + const unsigned char *x32, + const unsigned char *y32, + void *data +); + +/** An implementation of SHA256 hash function that applies to compressed public key. + * Populates the output parameter with 32 bytes. */ +SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256; + +/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256). + * Populates the output parameter with 32 bytes. */ +SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default; + +/** Compute an EC Diffie-Hellman secret in constant time + * + * Returns: 1: exponentiation was successful + * 0: scalar was invalid (zero or overflow) or hashfp returned 0 + * Args: ctx: pointer to a context object. + * Out: output: pointer to an array to be filled by hashfp. + * In: pubkey: pointer to a secp256k1_pubkey containing an initialized public key. + * seckey: a 32-byte scalar with which to multiply the point. + * hashfp: pointer to a hash function. If NULL, + * secp256k1_ecdh_hash_function_sha256 is used + * (in which case, 32 bytes will be written to output). + * data: arbitrary data pointer that is passed through to hashfp + * (can be NULL for secp256k1_ecdh_hash_function_sha256). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( + const secp256k1_context *ctx, + unsigned char *output, + const secp256k1_pubkey *pubkey, + const unsigned char *seckey, + secp256k1_ecdh_hash_function hashfp, + void *data +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_ECDH_H */ diff --git a/external/secp256k1/include/secp256k1_ellswift.h b/external/secp256k1/include/secp256k1_ellswift.h new file mode 100644 index 00000000000..0d1293e94f5 --- /dev/null +++ b/external/secp256k1/include/secp256k1_ellswift.h @@ -0,0 +1,200 @@ +#ifndef SECP256K1_ELLSWIFT_H +#define SECP256K1_ELLSWIFT_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This module provides an implementation of ElligatorSwift as well as a + * version of x-only ECDH using it (including compatibility with BIP324). + * + * ElligatorSwift is described in https://eprint.iacr.org/2022/759 by + * Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding + * uniformly chosen public keys as 64-byte arrays which are indistinguishable + * from uniformly random arrays. + * + * Let f be the function from pairs of field elements to point X coordinates, + * defined as follows (all operations modulo p = 2^256 - 2^32 - 977) + * f(u,t): + * - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852, + * a square root of -3. + * - If u=0, set u=1 instead. + * - If t=0, set t=1 instead. + * - If u^3 + t^2 + 7 = 0, multiply t by 2. + * - Let X = (u^3 + 7 - t^2) / (2 * t) + * - Let Y = (X + t) / (C * u) + * - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an + * X coordinate on the curve (at least one of them is, for any u and t). + * + * Then an ElligatorSwift encoding of x consists of the 32-byte big-endian + * encodings of field elements u and t concatenated, where f(u,t) = x. + * The encoding algorithm is described in the paper, and effectively picks a + * uniformly random pair (u,t) among those which encode x. + * + * If the Y coordinate is relevant, it is given the same parity as t. + * + * Changes w.r.t. the paper: + * - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point + * at infinity in the paper. Here they are remapped to finite points. + * - The paper uses an additional encoding bit for the parity of y. Here the + * parity of t is used (negating t does not affect the decoded x coordinate, + * so this is possible). + * + * For mathematical background about the scheme, see the doc/ellswift.md file. + */ + +/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X + * coordinate along with the encoded public keys to a uniform shared secret. + * + * Returns: 1 if a shared secret was successfully computed. + * 0 will cause secp256k1_ellswift_xdh to fail and return 0. + * Other return values are not allowed, and the behaviour of + * secp256k1_ellswift_xdh is undefined for other return values. + * Out: output: pointer to an array to be filled by the function + * In: x32: pointer to the 32-byte serialized X coordinate + * of the resulting shared point (will not be NULL) + * ell_a64: pointer to the 64-byte encoded public key of party A + * (will not be NULL) + * ell_b64: pointer to the 64-byte encoded public key of party B + * (will not be NULL) + * data: arbitrary data pointer that is passed through + */ +typedef int (*secp256k1_ellswift_xdh_hash_function)( + unsigned char *output, + const unsigned char *x32, + const unsigned char *ell_a64, + const unsigned char *ell_b64, + void *data +); + +/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses + * SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte + * array pointed to by data. */ +SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix; + +/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with + * BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the + * BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent + * to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to + * SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh"). + * The data argument is ignored. */ +SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324; + +/** Construct a 64-byte ElligatorSwift encoding of a given pubkey. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object + * Out: ell64: pointer to a 64-byte array to be filled + * In: pubkey: pointer to a secp256k1_pubkey containing an + * initialized public key + * rnd32: pointer to 32 bytes of randomness + * + * It is recommended that rnd32 consists of 32 uniformly random bytes, not + * known to any adversary trying to detect whether public keys are being + * encoded, though 16 bytes of randomness (padded to an array of 32 bytes, + * e.g., with zeros) suffice to make the result indistinguishable from + * uniform. The randomness in rnd32 must not be a deterministic function of + * the pubkey (it can be derived from the private key, though). + * + * It is not guaranteed that the computed encoding is stable across versions + * of the library, even if all arguments to this function (including rnd32) + * are the same. + * + * This function runs in variable time. + */ +SECP256K1_API int secp256k1_ellswift_encode( + const secp256k1_context *ctx, + unsigned char *ell64, + const secp256k1_pubkey *pubkey, + const unsigned char *rnd32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Decode a 64-bytes ElligatorSwift encoded public key. + * + * Returns: always 1 + * Args: ctx: pointer to a context object + * Out: pubkey: pointer to a secp256k1_pubkey that will be filled + * In: ell64: pointer to a 64-byte array to decode + * + * This function runs in variable time. + */ +SECP256K1_API int secp256k1_ellswift_decode( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const unsigned char *ell64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Compute an ElligatorSwift public key for a secret key. + * + * Returns: 1: secret was valid, public key was stored. + * 0: secret was invalid, try again. + * Args: ctx: pointer to a context object + * Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift + * public key + * In: seckey32: pointer to a 32-byte secret key + * auxrnd32: (optional) pointer to 32 bytes of randomness + * + * Constant time in seckey and auxrnd32, but not in the resulting public key. + * + * It is recommended that auxrnd32 contains 32 uniformly random bytes, though + * it is optional (and does result in encodings that are indistinguishable from + * uniform even without any auxrnd32). It differs from the (mandatory) rnd32 + * argument to secp256k1_ellswift_encode in this regard. + * + * This function can be used instead of calling secp256k1_ec_pubkey_create + * followed by secp256k1_ellswift_encode. It is safer, as it uses the secret + * key as entropy for the encoding (supplemented with auxrnd32, if provided). + * + * Like secp256k1_ellswift_encode, this function does not guarantee that the + * computed encoding is stable across versions of the library, even if all + * arguments (including auxrnd32) are the same. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create( + const secp256k1_context *ctx, + unsigned char *ell64, + const unsigned char *seckey32, + const unsigned char *auxrnd32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Given a private key, and ElligatorSwift public keys sent in both directions, + * compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH). + * + * Returns: 1: shared secret was successfully computed + * 0: secret was invalid or hashfp returned 0 + * Args: ctx: pointer to a context object. + * Out: output: pointer to an array to be filled by hashfp. + * In: ell_a64: pointer to the 64-byte encoded public key of party A + * (will not be NULL) + * ell_b64: pointer to the 64-byte encoded public key of party B + * (will not be NULL) + * seckey32: pointer to our 32-byte secret key + * party: boolean indicating which party we are: zero if we are + * party A, non-zero if we are party B. seckey32 must be + * the private key corresponding to that party's ell_?64. + * This correspondence is not checked. + * hashfp: pointer to a hash function. + * data: arbitrary data pointer passed through to hashfp. + * + * Constant time in seckey32. + * + * This function is more efficient than decoding the public keys, and performing + * ECDH on them. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh( + const secp256k1_context *ctx, + unsigned char *output, + const unsigned char *ell_a64, + const unsigned char *ell_b64, + const unsigned char *seckey32, + int party, + secp256k1_ellswift_xdh_hash_function hashfp, + void *data +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_ELLSWIFT_H */ diff --git a/external/secp256k1/include/secp256k1_extrakeys.h b/external/secp256k1/include/secp256k1_extrakeys.h new file mode 100644 index 00000000000..48c98693cfa --- /dev/null +++ b/external/secp256k1/include/secp256k1_extrakeys.h @@ -0,0 +1,250 @@ +#ifndef SECP256K1_EXTRAKEYS_H +#define SECP256K1_EXTRAKEYS_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque data structure that holds a parsed and valid "x-only" public key. + * An x-only pubkey encodes a point whose Y coordinate is even. It is + * serialized using only its X coordinate (32 bytes). See BIP-340 for more + * information about x-only pubkeys. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, use + * use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To + * compare keys, use secp256k1_xonly_pubkey_cmp. + */ +typedef struct secp256k1_xonly_pubkey { + unsigned char data[64]; +} secp256k1_xonly_pubkey; + +/** Opaque data structure that holds a keypair consisting of a secret and a + * public key. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 96 bytes in size, and can be safely copied/moved. + */ +typedef struct secp256k1_keypair { + unsigned char data[96]; +} secp256k1_keypair; + +/** Parse a 32-byte sequence into a xonly_pubkey object. + * + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, it's set to an invalid value. + * In: input32: pointer to a serialized xonly_pubkey. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse( + const secp256k1_context *ctx, + secp256k1_xonly_pubkey *pubkey, + const unsigned char *input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an xonly_pubkey object into a 32-byte sequence. + * + * Returns: 1 always. + * + * Args: ctx: pointer to a context object. + * Out: output32: pointer to a 32-byte array to place the serialized key in. + * In: pubkey: pointer to a secp256k1_xonly_pubkey containing an initialized public key. + */ +SECP256K1_API int secp256k1_xonly_pubkey_serialize( + const secp256k1_context *ctx, + unsigned char *output32, + const secp256k1_xonly_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Compare two x-only public keys using lexicographic order + * + * Returns: <0 if the first public key is less than the second + * >0 if the first public key is greater than the second + * 0 if the two public keys are equal + * Args: ctx: pointer to a context object. + * In: pubkey1: first public key to compare + * pubkey2: second public key to compare + */ +SECP256K1_API int secp256k1_xonly_pubkey_cmp( + const secp256k1_context *ctx, + const secp256k1_xonly_pubkey *pk1, + const secp256k1_xonly_pubkey *pk2 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey. + * + * Returns: 1 always. + * + * Args: ctx: pointer to a context object. + * Out: xonly_pubkey: pointer to an x-only public key object for placing the converted public key. + * pk_parity: Ignored if NULL. Otherwise, pointer to an integer that + * will be set to 1 if the point encoded by xonly_pubkey is + * the negation of the pubkey and set to 0 otherwise. + * In: pubkey: pointer to a public key that is converted. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey( + const secp256k1_context *ctx, + secp256k1_xonly_pubkey *xonly_pubkey, + int *pk_parity, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Tweak an x-only public key by adding the generator multiplied with tweak32 + * to it. + * + * Note that the resulting point can not in general be represented by an x-only + * pubkey because it may have an odd Y coordinate. Instead, the output_pubkey + * is a normal secp256k1_pubkey. + * + * Returns: 0 if the arguments are invalid or the resulting public key would be + * invalid (only when the tweak is the negation of the corresponding + * secret key). 1 otherwise. + * + * Args: ctx: pointer to a context object. + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0. + * In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to. + * tweak32: pointer to a 32-byte tweak, which must be valid + * according to secp256k1_ec_seckey_verify or 32 zero + * bytes. For uniformly random 32-byte tweaks, the chance of + * being invalid is negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( + const secp256k1_context *ctx, + secp256k1_pubkey *output_pubkey, + const secp256k1_xonly_pubkey *internal_pubkey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Checks that a tweaked pubkey is the result of calling + * secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32. + * + * The tweaked pubkey is represented by its 32-byte x-only serialization and + * its pk_parity, which can both be obtained by converting the result of + * tweak_add to a secp256k1_xonly_pubkey. + * + * Note that this alone does _not_ verify that the tweaked pubkey is a + * commitment. If the tweak is not chosen in a specific way, the tweaked pubkey + * can easily be the result of a different internal_pubkey and tweak. + * + * Returns: 0 if the arguments are invalid or the tweaked pubkey is not the + * result of tweaking the internal_pubkey with tweak32. 1 otherwise. + * Args: ctx: pointer to a context object. + * In: tweaked_pubkey32: pointer to a serialized xonly_pubkey. + * tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization + * is passed in as tweaked_pubkey32). This must match the + * pk_parity value that is returned when calling + * secp256k1_xonly_pubkey with the tweaked pubkey, or + * this function will fail. + * internal_pubkey: pointer to an x-only public key object to apply the tweak to. + * tweak32: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check( + const secp256k1_context *ctx, + const unsigned char *tweaked_pubkey32, + int tweaked_pk_parity, + const secp256k1_xonly_pubkey *internal_pubkey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Compute the keypair for a valid secret key. + * + * See the documentation of `secp256k1_ec_seckey_verify` for more information + * about the validity of secret keys. + * + * Returns: 1: secret key is valid + * 0: secret key is invalid + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: keypair: pointer to the created keypair. + * In: seckey: pointer to a 32-byte secret key. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create( + const secp256k1_context *ctx, + secp256k1_keypair *keypair, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Get the secret key from a keypair. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object. + * Out: seckey: pointer to a 32-byte buffer for the secret key. + * In: keypair: pointer to a keypair. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec( + const secp256k1_context *ctx, + unsigned char *seckey, + const secp256k1_keypair *keypair +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Get the public key from a keypair. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to a pubkey object, set to the keypair public key. + * In: keypair: pointer to a keypair. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const secp256k1_keypair *keypair +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Get the x-only public key from a keypair. + * + * This is the same as calling secp256k1_keypair_pub and then + * secp256k1_xonly_pubkey_from_pubkey. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to an xonly_pubkey object, set to the keypair + * public key after converting it to an xonly_pubkey. + * pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the + * pk_parity argument of secp256k1_xonly_pubkey_from_pubkey. + * In: keypair: pointer to a keypair. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub( + const secp256k1_context *ctx, + secp256k1_xonly_pubkey *pubkey, + int *pk_parity, + const secp256k1_keypair *keypair +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Tweak a keypair by adding tweak32 to the secret key and updating the public + * key accordingly. + * + * Calling this function and then secp256k1_keypair_pub results in the same + * public key as calling secp256k1_keypair_xonly_pub and then + * secp256k1_xonly_pubkey_tweak_add. + * + * Returns: 0 if the arguments are invalid or the resulting keypair would be + * invalid (only when the tweak is the negation of the keypair's + * secret key). 1 otherwise. + * + * Args: ctx: pointer to a context object. + * In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to + * an invalid value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add( + const secp256k1_context *ctx, + secp256k1_keypair *keypair, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_EXTRAKEYS_H */ diff --git a/external/secp256k1/include/secp256k1_musig.h b/external/secp256k1/include/secp256k1_musig.h new file mode 100644 index 00000000000..11b8f08c883 --- /dev/null +++ b/external/secp256k1/include/secp256k1_musig.h @@ -0,0 +1,588 @@ +#ifndef SECP256K1_MUSIG_H +#define SECP256K1_MUSIG_H + +#include "secp256k1_extrakeys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** This module implements BIP 327 "MuSig2 for BIP340-compatible + * Multi-Signatures" + * (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki) + * v1.0.0. You can find an example demonstrating the musig module in + * examples/musig.c. + * + * The module also supports BIP 341 ("Taproot") public key tweaking. + * + * It is recommended to read the documentation in this include file carefully. + * Further notes on API usage can be found in doc/musig.md + * + * Since the first version of MuSig is essentially replaced by MuSig2, we use + * MuSig, musig and MuSig2 synonymously unless noted otherwise. + */ + +/** Opaque data structures + * + * The exact representation of data inside the opaque data structures is + * implementation defined and not guaranteed to be portable between different + * platforms or versions. With the exception of `secp256k1_musig_secnonce`, the + * data structures can be safely copied/moved. If you need to convert to a + * format suitable for storage, transmission, or comparison, use the + * corresponding serialization and parsing functions. + */ + +/** Opaque data structure that caches information about public key aggregation. + * + * Guaranteed to be 197 bytes in size. No serialization and parsing functions + * (yet). + */ +typedef struct secp256k1_musig_keyagg_cache { + unsigned char data[197]; +} secp256k1_musig_keyagg_cache; + +/** Opaque data structure that holds a signer's _secret_ nonce. + * + * Guaranteed to be 132 bytes in size. + * + * WARNING: This structure MUST NOT be copied or read or written to directly. A + * signer who is online throughout the whole process and can keep this + * structure in memory can use the provided API functions for a safe standard + * workflow. + * + * Copying this data structure can result in nonce reuse which will leak the + * secret signing key. + */ +typedef struct secp256k1_musig_secnonce { + unsigned char data[132]; +} secp256k1_musig_secnonce; + +/** Opaque data structure that holds a signer's public nonce. + * + * Guaranteed to be 132 bytes in size. Serialized and parsed with + * `musig_pubnonce_serialize` and `musig_pubnonce_parse`. + */ +typedef struct secp256k1_musig_pubnonce { + unsigned char data[132]; +} secp256k1_musig_pubnonce; + +/** Opaque data structure that holds an aggregate public nonce. + * + * Guaranteed to be 132 bytes in size. Serialized and parsed with + * `musig_aggnonce_serialize` and `musig_aggnonce_parse`. + */ +typedef struct secp256k1_musig_aggnonce { + unsigned char data[132]; +} secp256k1_musig_aggnonce; + +/** Opaque data structure that holds a MuSig session. + * + * This structure is not required to be kept secret for the signing protocol to + * be secure. Guaranteed to be 133 bytes in size. No serialization and parsing + * functions (yet). + */ +typedef struct secp256k1_musig_session { + unsigned char data[133]; +} secp256k1_musig_session; + +/** Opaque data structure that holds a partial MuSig signature. + * + * Guaranteed to be 36 bytes in size. Serialized and parsed with + * `musig_partial_sig_serialize` and `musig_partial_sig_parse`. + */ +typedef struct secp256k1_musig_partial_sig { + unsigned char data[36]; +} secp256k1_musig_partial_sig; + +/** Parse a signer's public nonce. + * + * Returns: 1 when the nonce could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: nonce: pointer to a nonce object + * In: in66: pointer to the 66-byte nonce to be parsed + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubnonce_parse( + const secp256k1_context *ctx, + secp256k1_musig_pubnonce *nonce, + const unsigned char *in66 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a signer's public nonce + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * Out: out66: pointer to a 66-byte array to store the serialized nonce + * In: nonce: pointer to the nonce + */ +SECP256K1_API int secp256k1_musig_pubnonce_serialize( + const secp256k1_context *ctx, + unsigned char *out66, + const secp256k1_musig_pubnonce *nonce +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse an aggregate public nonce. + * + * Returns: 1 when the nonce could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: nonce: pointer to a nonce object + * In: in66: pointer to the 66-byte nonce to be parsed + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_aggnonce_parse( + const secp256k1_context *ctx, + secp256k1_musig_aggnonce *nonce, + const unsigned char *in66 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an aggregate public nonce + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * Out: out66: pointer to a 66-byte array to store the serialized nonce + * In: nonce: pointer to the nonce + */ +SECP256K1_API int secp256k1_musig_aggnonce_serialize( + const secp256k1_context *ctx, + unsigned char *out66, + const secp256k1_musig_aggnonce *nonce +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a MuSig partial signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: in32: pointer to the 32-byte signature to be parsed + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_parse( + const secp256k1_context *ctx, + secp256k1_musig_partial_sig *sig, + const unsigned char *in32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a MuSig partial signature + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * Out: out32: pointer to a 32-byte array to store the serialized signature + * In: sig: pointer to the signature + */ +SECP256K1_API int secp256k1_musig_partial_sig_serialize( + const secp256k1_context *ctx, + unsigned char *out32, + const secp256k1_musig_partial_sig *sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Computes an aggregate public key and uses it to initialize a keyagg_cache + * + * Different orders of `pubkeys` result in different `agg_pk`s. + * + * Before aggregating, the pubkeys can be sorted with `secp256k1_ec_pubkey_sort` + * which ensures the same `agg_pk` result for the same multiset of pubkeys. + * This is useful to do before `pubkey_agg`, such that the order of pubkeys + * does not affect the aggregate public key. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it, + * this arg can be NULL. + * keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that + * is required for signing (or observing the signing session + * and verifying partial signatures). + * In: pubkeys: input array of pointers to public keys to aggregate. The order + * is important; a different order will result in a different + * aggregate public key. + * n_pubkeys: length of pubkeys array. Must be greater than 0. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_agg( + const secp256k1_context *ctx, + secp256k1_xonly_pubkey *agg_pk, + secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_pubkey * const *pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(4); + +/** Obtain the aggregate public key from a keyagg_cache. + * + * This is only useful if you need the non-xonly public key, in particular for + * plain (non-xonly) tweaking or batch-verifying multiple key aggregations + * (not implemented). + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: agg_pk: the MuSig-aggregated public key. + * In: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get( + const secp256k1_context *ctx, + secp256k1_pubkey *agg_pk, + const secp256k1_musig_keyagg_cache *keyagg_cache +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by adding + * the generator multiplied with `tweak32` to it. This is useful for deriving + * child keys from an aggregate public key via BIP 32 where `tweak32` is set to + * a hash as defined in BIP 32. + * + * Callers are responsible for deriving `tweak32` in a way that does not reduce + * the security of MuSig (for example, by following BIP 32). + * + * The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after + * the following pseudocode buf and buf2 have identical contents (absent + * earlier failures). + * + * secp256k1_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...) + * secp256k1_musig_pubkey_get(..., agg_pk, keyagg_cache) + * secp256k1_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache) + * secp256k1_ec_pubkey_serialize(..., buf, ..., output_pk, ...) + * secp256k1_ec_pubkey_tweak_add(..., agg_pk, tweak32) + * secp256k1_ec_pubkey_serialize(..., buf2, ..., agg_pk, ...) + * + * This function is required if you want to _sign_ for a tweaked aggregate key. + * If you are only computing a public key but not intending to create a + * signature for it, use `secp256k1_ec_pubkey_tweak_add` instead. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0. If you + * do not need it, this arg can be NULL. + * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes + * `secp256k1_ec_seckey_verify` and is not equal to the + * secret key corresponding to the public key represented + * by keyagg_cache or its negation. For uniformly random + * 32-byte arrays the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_add( + const secp256k1_context *ctx, + secp256k1_pubkey *output_pubkey, + secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the + * generator multiplied with `tweak32` to it. This is useful for creating + * Taproot outputs where `tweak32` is set to a TapTweak hash as defined in BIP + * 341. + * + * Callers are responsible for deriving `tweak32` in a way that does not reduce + * the security of MuSig (for example, by following Taproot BIP 341). + * + * The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in + * the following pseudocode xonly_pubkey_tweak_add_check (absent earlier + * failures) returns 1. + * + * secp256k1_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...) + * secp256k1_musig_pubkey_xonly_tweak_add(..., output_pk, keyagg_cache, tweak32) + * secp256k1_xonly_pubkey_serialize(..., buf, output_pk) + * secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32) + * + * This function is required if you want to _sign_ for a tweaked aggregate key. + * If you are only computing a public key but not intending to create a + * signature for it, use `secp256k1_xonly_pubkey_tweak_add` instead. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0. If you + * do not need it, this arg can be NULL. + * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes + * `secp256k1_ec_seckey_verify` and is not equal to the + * secret key corresponding to the public key represented + * by keyagg_cache or its negation. For uniformly random + * 32-byte arrays the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_tweak_add( + const secp256k1_context *ctx, + secp256k1_pubkey *output_pubkey, + secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Starts a signing session by generating a nonce + * + * This function outputs a secret nonce that will be required for signing and a + * corresponding public nonce that is intended to be sent to other signers. + * + * MuSig differs from regular Schnorr signing in that implementers _must_ take + * special care to not reuse a nonce. This can be ensured by following these rules: + * + * 1. Each call to this function must have a UNIQUE session_secrand32 that must + * NOT BE REUSED in subsequent calls to this function and must be KEPT + * SECRET (even from other signers). + * 2. If you already know the seckey, message or aggregate public key + * cache, they can be optionally provided to derive the nonce and increase + * misuse-resistance. The extra_input32 argument can be used to provide + * additional data that does not repeat in normal scenarios, such as the + * current time. + * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility + * that it is used more than once for signing. + * + * If you don't have access to good randomness for session_secrand32, but you + * have access to a non-repeating counter, then see + * secp256k1_musig_nonce_gen_counter. + * + * Remember that nonce reuse will leak the secret key! + * Note that using the same seckey for multiple MuSig sessions is fine. + * + * Returns: 0 if the arguments are invalid and 1 otherwise + * Args: ctx: pointer to a context object (not secp256k1_context_static) + * Out: secnonce: pointer to a structure to store the secret nonce + * pubnonce: pointer to a structure to store the public nonce + * In/Out: + * session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this + * call to secp256k1_musig_nonce_gen and must be uniformly + * random. If the function call is successful, the + * session_secrand32 buffer is invalidated to prevent reuse. + * In: + * seckey: the 32-byte secret key that will later be used for signing, if + * already known (can be NULL) + * pubkey: public key of the signer creating the nonce. The secnonce + * output of this function cannot be used to sign for any + * other public key. While the public key should correspond + * to the provided seckey, a mismatch will not cause the + * function to return 0. + * msg32: the 32-byte message that will later be signed, if already known + * (can be NULL) + * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate + * (and potentially tweaked) public key if already known + * (can be NULL) + * extra_input32: an optional 32-byte array that is input to the nonce + * derivation function (can be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen( + const secp256k1_context *ctx, + secp256k1_musig_secnonce *secnonce, + secp256k1_musig_pubnonce *pubnonce, + unsigned char *session_secrand32, + const unsigned char *seckey, + const secp256k1_pubkey *pubkey, + const unsigned char *msg32, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *extra_input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6); + + +/** Alternative way to generate a nonce and start a signing session + * + * This function outputs a secret nonce that will be required for signing and a + * corresponding public nonce that is intended to be sent to other signers. + * + * This function differs from `secp256k1_musig_nonce_gen` by accepting a + * non-repeating counter value instead of a secret random value. This requires + * that a secret key is provided to `secp256k1_musig_nonce_gen_counter` + * (through the keypair argument), as opposed to `secp256k1_musig_nonce_gen` + * where the seckey argument is optional. + * + * MuSig differs from regular Schnorr signing in that implementers _must_ take + * special care to not reuse a nonce. This can be ensured by following these rules: + * + * 1. The nonrepeating_cnt argument must be a counter value that never repeats, + * i.e., you must never call `secp256k1_musig_nonce_gen_counter` twice with + * the same keypair and nonrepeating_cnt value. For example, this implies + * that if the same keypair is used with `secp256k1_musig_nonce_gen_counter` + * on multiple devices, none of the devices should have the same counter + * value as any other device. + * 2. If the seckey, message or aggregate public key cache is already available + * at this stage, any of these can be optionally provided, in which case + * they will be used in the derivation of the nonce and increase + * misuse-resistance. The extra_input32 argument can be used to provide + * additional data that does not repeat in normal scenarios, such as the + * current time. + * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility + * that it is used more than once for signing. + * + * Remember that nonce reuse will leak the secret key! + * Note that using the same keypair for multiple MuSig sessions is fine. + * + * Returns: 0 if the arguments are invalid and 1 otherwise + * Args: ctx: pointer to a context object (not secp256k1_context_static) + * Out: secnonce: pointer to a structure to store the secret nonce + * pubnonce: pointer to a structure to store the public nonce + * In: + * nonrepeating_cnt: the value of a counter as explained above. Must be + * unique to this call to secp256k1_musig_nonce_gen. + * keypair: keypair of the signer creating the nonce. The secnonce + * output of this function cannot be used to sign for any + * other keypair. + * msg32: the 32-byte message that will later be signed, if already known + * (can be NULL) + * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate + * (and potentially tweaked) public key if already known + * (can be NULL) + * extra_input32: an optional 32-byte array that is input to the nonce + * derivation function (can be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen_counter( + const secp256k1_context *ctx, + secp256k1_musig_secnonce *secnonce, + secp256k1_musig_pubnonce *pubnonce, + uint64_t nonrepeating_cnt, + const secp256k1_keypair *keypair, + const unsigned char *msg32, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *extra_input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +/** Aggregates the nonces of all signers into a single nonce + * + * This can be done by an untrusted party to reduce the communication + * between signers. Instead of everyone sending nonces to everyone else, there + * can be one party receiving all nonces, aggregating the nonces with this + * function and then sending only the aggregate nonce back to the signers. + * + * If the aggregator does not compute the aggregate nonce correctly, the final + * signature will be invalid. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: aggnonce: pointer to an aggregate public nonce object for + * musig_nonce_process + * In: pubnonces: array of pointers to public nonces sent by the + * signers + * n_pubnonces: number of elements in the pubnonces array. Must be + * greater than 0. + */ +SECP256K1_API int secp256k1_musig_nonce_agg( + const secp256k1_context *ctx, + secp256k1_musig_aggnonce *aggnonce, + const secp256k1_musig_pubnonce * const *pubnonces, + size_t n_pubnonces +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Takes the aggregate nonce and creates a session that is required for signing + * and verification of partial signatures. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: session: pointer to a struct to store the session + * In: aggnonce: pointer to an aggregate public nonce object that is the + * output of musig_nonce_agg + * msg32: the 32-byte message to sign + * keyagg_cache: pointer to the keyagg_cache that was used to create the + * aggregate (and potentially tweaked) pubkey + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process( + const secp256k1_context *ctx, + secp256k1_musig_session *session, + const secp256k1_musig_aggnonce *aggnonce, + const unsigned char *msg32, + const secp256k1_musig_keyagg_cache *keyagg_cache +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Produces a partial signature + * + * This function overwrites the given secnonce with zeros and will abort if given a + * secnonce that is all zeros. This is a best effort attempt to protect against nonce + * reuse. However, this is of course easily defeated if the secnonce has been + * copied (or serialized). Remember that nonce reuse will leak the secret key! + * + * For signing to succeed, the secnonce provided to this function must have + * been generated for the provided keypair. This means that when signing for a + * keypair consisting of a seckey and pubkey, the secnonce must have been + * created by calling musig_nonce_gen with that pubkey. Otherwise, the + * illegal_callback is called. + * + * This function does not verify the output partial signature, deviating from + * the BIP 327 specification. It is recommended to verify the output partial + * signature with `secp256k1_musig_partial_sig_verify` to prevent random or + * adversarially provoked computation errors. + * + * Returns: 0 if the arguments are invalid or the provided secnonce has already + * been used for signing, 1 otherwise + * Args: ctx: pointer to a context object + * Out: partial_sig: pointer to struct to store the partial signature + * In/Out: secnonce: pointer to the secnonce struct created in + * musig_nonce_gen that has been never used in a + * partial_sign call before and has been created for the + * keypair + * In: keypair: pointer to keypair to sign the message with + * keyagg_cache: pointer to the keyagg_cache that was output when the + * aggregate public key for this session + * session: pointer to the session that was created with + * musig_nonce_process + */ +SECP256K1_API int secp256k1_musig_partial_sign( + const secp256k1_context *ctx, + secp256k1_musig_partial_sig *partial_sig, + secp256k1_musig_secnonce *secnonce, + const secp256k1_keypair *keypair, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_musig_session *session +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + +/** Verifies an individual signer's partial signature + * + * The signature is verified for a specific signing session. In order to avoid + * accidentally verifying a signature from a different or non-existing signing + * session, you must ensure the following: + * 1. The `keyagg_cache` argument is identical to the one used to create the + * `session` with `musig_nonce_process`. + * 2. The `pubkey` argument must be identical to the one sent by the signer + * before aggregating it with `musig_pubkey_agg` to create the + * `keyagg_cache`. + * 3. The `pubnonce` argument must be identical to the one sent by the signer + * before aggregating it with `musig_nonce_agg` and using the result to + * create the `session` with `musig_nonce_process`. + * + * It is not required to call this function in regular MuSig sessions, because + * if any partial signature does not verify, the final signature will not + * verify either, so the problem will be caught. However, this function + * provides the ability to identify which specific partial signature fails + * verification. + * + * Returns: 0 if the arguments are invalid or the partial signature does not + * verify, 1 otherwise + * Args ctx: pointer to a context object + * In: partial_sig: pointer to partial signature to verify, sent by + * the signer associated with `pubnonce` and `pubkey` + * pubnonce: public nonce of the signer in the signing session + * pubkey: public key of the signer in the signing session + * keyagg_cache: pointer to the keyagg_cache that was output when the + * aggregate public key for this signing session + * session: pointer to the session that was created with + * `musig_nonce_process` + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify( + const secp256k1_context *ctx, + const secp256k1_musig_partial_sig *partial_sig, + const secp256k1_musig_pubnonce *pubnonce, + const secp256k1_pubkey *pubkey, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_musig_session *session +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + +/** Aggregates partial signatures + * + * Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean + * the resulting signature verifies). + * Args: ctx: pointer to a context object + * Out: sig64: complete (but possibly invalid) Schnorr signature + * In: session: pointer to the session that was created with + * musig_nonce_process + * partial_sigs: array of pointers to partial signatures to aggregate + * n_sigs: number of elements in the partial_sigs array. Must be + * greater than 0. + */ +SECP256K1_API int secp256k1_musig_partial_sig_agg( + const secp256k1_context *ctx, + unsigned char *sig64, + const secp256k1_musig_session *session, + const secp256k1_musig_partial_sig * const *partial_sigs, + size_t n_sigs +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/secp256k1/include/secp256k1_preallocated.h b/external/secp256k1/include/secp256k1_preallocated.h new file mode 100644 index 00000000000..f2d95c245e2 --- /dev/null +++ b/external/secp256k1/include/secp256k1_preallocated.h @@ -0,0 +1,134 @@ +#ifndef SECP256K1_PREALLOCATED_H +#define SECP256K1_PREALLOCATED_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* The module provided by this header file is intended for settings in which it + * is not possible or desirable to rely on dynamic memory allocation. It provides + * functions for creating, cloning, and destroying secp256k1 context objects in a + * contiguous fixed-size block of memory provided by the caller. + * + * Context objects created by functions in this module can be used like contexts + * objects created by functions in secp256k1.h, i.e., they can be passed to any + * API function that expects a context object (see secp256k1.h for details). The + * only exception is that context objects created by functions in this module + * must be destroyed using secp256k1_context_preallocated_destroy (in this + * module) instead of secp256k1_context_destroy (in secp256k1.h). + * + * It is guaranteed that functions in this module will not call malloc or its + * friends realloc, calloc, and free. + */ + +/** Determine the memory size of a secp256k1 context object to be created in + * caller-provided memory. + * + * The purpose of this function is to determine how much memory must be provided + * to secp256k1_context_preallocated_create. + * + * Returns: the required size of the caller-provided memory block + * In: flags: which parts of the context to initialize. + */ +SECP256K1_API size_t secp256k1_context_preallocated_size( + unsigned int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Create a secp256k1 context object in caller-provided memory. + * + * The caller must provide a pointer to a rewritable contiguous block of memory + * of size at least secp256k1_context_preallocated_size(flags) bytes, suitably + * aligned to hold an object of any type. + * + * The block of memory is exclusively owned by the created context object during + * the lifetime of this context object, which begins with the call to this + * function and ends when a call to secp256k1_context_preallocated_destroy + * (which destroys the context object again) returns. During the lifetime of the + * context object, the caller is obligated not to access this block of memory, + * i.e., the caller may not read or write the memory, e.g., by copying the memory + * contents to a different location or trying to create a second context object + * in the memory. In simpler words, the prealloc pointer (or any pointer derived + * from it) should not be used during the lifetime of the context object. + * + * Returns: pointer to newly created context object. + * In: prealloc: pointer to a rewritable contiguous block of memory of + * size at least secp256k1_context_preallocated_size(flags) + * bytes, as detailed above. + * flags: which parts of the context to initialize. + * + * See secp256k1_context_create (in secp256k1.h) for further details. + * + * See also secp256k1_context_randomize (in secp256k1.h) + * and secp256k1_context_preallocated_destroy. + */ +SECP256K1_API secp256k1_context *secp256k1_context_preallocated_create( + void *prealloc, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Determine the memory size of a secp256k1 context object to be copied into + * caller-provided memory. + * + * Returns: the required size of the caller-provided memory block. + * In: ctx: pointer to a context to copy. + */ +SECP256K1_API size_t secp256k1_context_preallocated_clone_size( + const secp256k1_context *ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Copy a secp256k1 context object into caller-provided memory. + * + * The caller must provide a pointer to a rewritable contiguous block of memory + * of size at least secp256k1_context_preallocated_size(flags) bytes, suitably + * aligned to hold an object of any type. + * + * The block of memory is exclusively owned by the created context object during + * the lifetime of this context object, see the description of + * secp256k1_context_preallocated_create for details. + * + * Cloning secp256k1_context_static is not possible, and should not be emulated by + * the caller (e.g., using memcpy). Create a new context instead. + * + * Returns: pointer to a newly created context object. + * Args: ctx: pointer to a context to copy (not secp256k1_context_static). + * In: prealloc: pointer to a rewritable contiguous block of memory of + * size at least secp256k1_context_preallocated_size(flags) + * bytes, as detailed above. + */ +SECP256K1_API secp256k1_context *secp256k1_context_preallocated_clone( + const secp256k1_context *ctx, + void *prealloc +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object that has been created in + * caller-provided memory. + * + * The context pointer may not be used afterwards. + * + * The context to destroy must have been created using + * secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone. + * If the context has instead been created using secp256k1_context_create or + * secp256k1_context_clone, the behaviour is undefined. In that case, + * secp256k1_context_destroy must be used instead. + * + * If required, it is the responsibility of the caller to deallocate the block + * of memory properly after this function returns, e.g., by calling free on the + * preallocated pointer given to secp256k1_context_preallocated_create or + * secp256k1_context_preallocated_clone. + * + * Args: ctx: pointer to a context to destroy, constructed using + * secp256k1_context_preallocated_create or + * secp256k1_context_preallocated_clone + * (i.e., not secp256k1_context_static). + */ +SECP256K1_API void secp256k1_context_preallocated_destroy( + secp256k1_context *ctx +) SECP256K1_ARG_NONNULL(1); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_PREALLOCATED_H */ diff --git a/external/secp256k1/include/secp256k1_recovery.h b/external/secp256k1/include/secp256k1_recovery.h new file mode 100644 index 00000000000..93a2e4ccbde --- /dev/null +++ b/external/secp256k1/include/secp256k1_recovery.h @@ -0,0 +1,113 @@ +#ifndef SECP256K1_RECOVERY_H +#define SECP256K1_RECOVERY_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque data structure that holds a parsed ECDSA signature, + * supporting pubkey recovery. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 65 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_parse_* functions. + * + * Furthermore, it is guaranteed that identical signatures (including their + * recoverability) will have identical representation, so they can be + * memcmp'ed. + */ +typedef struct secp256k1_ecdsa_recoverable_signature { + unsigned char data[65]; +} secp256k1_ecdsa_recoverable_signature; + +/** Parse a compact ECDSA signature (64 bytes + recovery id). + * + * Returns: 1 when the signature could be parsed, 0 otherwise + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to a 64-byte compact signature + * recid: the recovery id (0, 1, 2 or 3) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( + const secp256k1_context *ctx, + secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *input64, + int recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Convert a recoverable signature into a normal signature. + * + * Returns: 1 + * Args: ctx: pointer to a context object. + * Out: sig: pointer to a normal signature. + * In: sigin: pointer to a recoverable signature. + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( + const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, + const secp256k1_ecdsa_recoverable_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). + * + * Returns: 1 + * Args: ctx: pointer to a context object. + * Out: output64: pointer to a 64-byte array of the compact signature. + * recid: pointer to an integer to hold the recovery id. + * In: sig: pointer to an initialized signature object. + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( + const secp256k1_context *ctx, + unsigned char *output64, + int *recid, + const secp256k1_ecdsa_recoverable_signature *sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Create a recoverable ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the secret key was invalid. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig: pointer to an array where the signature will be placed. + * In: msghash32: the 32-byte message hash being signed. + * seckey: pointer to a 32-byte secret key. + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used. + * ndata: pointer to arbitrary data used by the nonce generation function + * (can be NULL for secp256k1_nonce_function_default). + */ +SECP256K1_API int secp256k1_ecdsa_sign_recoverable( + const secp256k1_context *ctx, + secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msghash32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an ECDSA public key from a signature. + * + * Returns: 1: public key successfully recovered (which guarantees a correct signature). + * 0: otherwise. + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to the recovered public key. + * In: sig: pointer to initialized signature that supports pubkey recovery. + * msghash32: the 32-byte message hash assumed to be signed. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msghash32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_RECOVERY_H */ diff --git a/external/secp256k1/include/secp256k1_schnorrsig.h b/external/secp256k1/include/secp256k1_schnorrsig.h new file mode 100644 index 00000000000..013d4ee73d7 --- /dev/null +++ b/external/secp256k1/include/secp256k1_schnorrsig.h @@ -0,0 +1,190 @@ +#ifndef SECP256K1_SCHNORRSIG_H +#define SECP256K1_SCHNORRSIG_H + +#include "secp256k1.h" +#include "secp256k1_extrakeys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This module implements a variant of Schnorr signatures compliant with + * Bitcoin Improvement Proposal 340 "Schnorr Signatures for secp256k1" + * (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). + */ + +/** A pointer to a function to deterministically generate a nonce. + * + * Same as secp256k1_nonce function with the exception of accepting an + * additional pubkey argument and not requiring an attempt argument. The pubkey + * argument can protect signature schemes with key-prefixed challenge hash + * inputs against reusing the nonce when signing with the wrong precomputed + * pubkey. + * + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to + * return an error. + * Out: nonce32: pointer to a 32-byte array to be filled by the function + * In: msg: the message being verified. Is NULL if and only if msglen + * is 0. + * msglen: the length of the message + * key32: pointer to a 32-byte secret key (will not be NULL) + * xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32 + * (will not be NULL) + * algo: pointer to an array describing the signature + * algorithm (will not be NULL) + * algolen: the length of the algo array + * data: arbitrary data pointer that is passed through + * + * Except for test cases, this function should compute some cryptographic hash of + * the message, the key, the pubkey, the algorithm description, and data. + */ +typedef int (*secp256k1_nonce_function_hardened)( + unsigned char *nonce32, + const unsigned char *msg, + size_t msglen, + const unsigned char *key32, + const unsigned char *xonly_pk32, + const unsigned char *algo, + size_t algolen, + void *data +); + +/** An implementation of the nonce generation function as defined in Bitcoin + * Improvement Proposal 340 "Schnorr Signatures for secp256k1" + * (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). + * + * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of + * auxiliary random data as defined in BIP-340. If the data pointer is NULL, + * the nonce derivation procedure follows BIP-340 by setting the auxiliary + * random data to zero. The algo argument must be non-NULL, otherwise the + * function will fail and return 0. The hash will be tagged with algo. + * Therefore, to create BIP-340 compliant signatures, algo must be set to + * "BIP0340/nonce" and algolen to 13. + */ +SECP256K1_API const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340; + +/** Data structure that contains additional arguments for schnorrsig_sign_custom. + * + * A schnorrsig_extraparams structure object can be initialized correctly by + * setting it to SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT. + * + * Members: + * magic: set to SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC at initialization + * and has no other function than making sure the object is + * initialized. + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_bip340 is used + * ndata: pointer to arbitrary data used by the nonce generation function + * (can be NULL). If it is non-NULL and + * secp256k1_nonce_function_bip340 is used, then ndata must be a + * pointer to 32-byte auxiliary randomness as per BIP-340. + */ +typedef struct secp256k1_schnorrsig_extraparams { + unsigned char magic[4]; + secp256k1_nonce_function_hardened noncefp; + void *ndata; +} secp256k1_schnorrsig_extraparams; + +#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC { 0xda, 0x6f, 0xb3, 0x8c } +#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT {\ + SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC,\ + NULL,\ + NULL\ +} + +/** Create a Schnorr signature. + * + * Does _not_ strictly follow BIP-340 because it does not verify the resulting + * signature. Instead, you can manually use secp256k1_schnorrsig_verify and + * abort if it fails. + * + * This function only signs 32-byte messages. If you have messages of a + * different size (or the same size but without a context-specific tag + * prefix), it is recommended to create a 32-byte message hash with + * secp256k1_tagged_sha256 and then sign the hash. Tagged hashing allows + * providing an context-specific tag for domain separation. This prevents + * signatures from being valid in multiple contexts by accident. + * + * Returns 1 on success, 0 on failure. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig64: pointer to a 64-byte array to store the serialized signature. + * In: msg32: the 32-byte message being signed. + * keypair: pointer to an initialized keypair. + * aux_rand32: 32 bytes of fresh randomness. While recommended to provide + * this, it is only supplemental to security and can be NULL. A + * NULL argument is treated the same as an all-zero one. See + * BIP-340 "Default Signing" for a full explanation of this + * argument and for guidance if randomness is expensive. + */ +SECP256K1_API int secp256k1_schnorrsig_sign32( + const secp256k1_context *ctx, + unsigned char *sig64, + const unsigned char *msg32, + const secp256k1_keypair *keypair, + const unsigned char *aux_rand32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in + * future versions. */ +SECP256K1_API int secp256k1_schnorrsig_sign( + const secp256k1_context *ctx, + unsigned char *sig64, + const unsigned char *msg32, + const secp256k1_keypair *keypair, + const unsigned char *aux_rand32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) + SECP256K1_DEPRECATED("Use secp256k1_schnorrsig_sign32 instead"); + +/** Create a Schnorr signature with a more flexible API. + * + * Same arguments as secp256k1_schnorrsig_sign except that it allows signing + * variable length messages and accepts a pointer to an extraparams object that + * allows customizing signing by passing additional arguments. + * + * Equivalent to secp256k1_schnorrsig_sign32(..., aux_rand32) if msglen is 32 + * and extraparams is initialized as follows: + * ``` + * secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + * extraparams.ndata = (unsigned char*)aux_rand32; + * ``` + * + * Returns 1 on success, 0 on failure. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig64: pointer to a 64-byte array to store the serialized signature. + * In: msg: the message being signed. Can only be NULL if msglen is 0. + * msglen: length of the message. + * keypair: pointer to an initialized keypair. + * extraparams: pointer to an extraparams object (can be NULL). + */ +SECP256K1_API int secp256k1_schnorrsig_sign_custom( + const secp256k1_context *ctx, + unsigned char *sig64, + const unsigned char *msg, + size_t msglen, + const secp256k1_keypair *keypair, + secp256k1_schnorrsig_extraparams *extraparams +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5); + +/** Verify a Schnorr signature. + * + * Returns: 1: correct signature + * 0: incorrect signature + * Args: ctx: pointer to a context object. + * In: sig64: pointer to the 64-byte signature to verify. + * msg: the message being verified. Can only be NULL if msglen is 0. + * msglen: length of the message + * pubkey: pointer to an x-only public key to verify with + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( + const secp256k1_context *ctx, + const unsigned char *sig64, + const unsigned char *msg, + size_t msglen, + const secp256k1_xonly_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_SCHNORRSIG_H */ diff --git a/src/secp256k1/libsecp256k1.pc.in b/external/secp256k1/libsecp256k1.pc.in similarity index 92% rename from src/secp256k1/libsecp256k1.pc.in rename to external/secp256k1/libsecp256k1.pc.in index a0d006f1131..0fb6f48a6c9 100644 --- a/src/secp256k1/libsecp256k1.pc.in +++ b/external/secp256k1/libsecp256k1.pc.in @@ -8,6 +8,5 @@ Description: Optimized C library for EC operations on curve secp256k1 URL: https://github.com/bitcoin-core/secp256k1 Version: @PACKAGE_VERSION@ Cflags: -I${includedir} -Libs.private: @SECP_LIBS@ Libs: -L${libdir} -lsecp256k1 diff --git a/external/secp256k1/sage/gen_exhaustive_groups.sage b/external/secp256k1/sage/gen_exhaustive_groups.sage new file mode 100644 index 00000000000..070bc1285f7 --- /dev/null +++ b/external/secp256k1/sage/gen_exhaustive_groups.sage @@ -0,0 +1,156 @@ +load("secp256k1_params.sage") + +MAX_ORDER = 1000 + +# Set of (curve) orders we have encountered so far. +orders_done = set() + +# Map from (subgroup) orders to [b, int(gen.x), int(gen.y), gen, lambda] for those subgroups. +solutions = {} + +# Iterate over curves of the form y^2 = x^3 + B. +for b in range(1, P): + # There are only 6 curves (up to isomorphism) of the form y^2 = x^3 + B. Stop once we have tried all. + if len(orders_done) == 6: + break + + E = EllipticCurve(F, [0, b]) + print("Analyzing curve y^2 = x^3 + %i" % b) + n = E.order() + + # Skip curves with an order we've already tried + if n in orders_done: + print("- Isomorphic to earlier curve") + print() + continue + orders_done.add(n) + + # Skip curves isomorphic to the real secp256k1 + if n.is_pseudoprime(): + assert E.is_isomorphic(C) + print("- Isomorphic to secp256k1") + print() + continue + + print("- Finding prime subgroups") + + # Map from group_order to a set of independent generators for that order. + curve_gens = {} + + for g in E.gens(): + # Find what prime subgroups of group generated by g exist. + g_order = g.order() + for f, _ in g.order().factor(): + # Skip subgroups that have bad size. + if f < 4: + print(f" - Subgroup of size {f}: too small") + continue + if f > MAX_ORDER: + print(f" - Subgroup of size {f}: too large") + continue + + # Construct a generator for that subgroup. + gen = g * (g_order // f) + assert(gen.order() == f) + + # Add to set the minimal multiple of gen. + curve_gens.setdefault(f, set()).add(min([j*gen for j in range(1, f)])) + print(f" - Subgroup of size {f}: ok") + + for f in sorted(curve_gens.keys()): + print(f"- Constructing group of order {f}") + cbrts = sorted([int(c) for c in Integers(f)(1).nth_root(3, all=true) if c != 1]) + gens = list(curve_gens[f]) + sol_count = 0 + no_endo_count = 0 + + # Consider all non-zero linear combinations of the independent generators. + for j in range(1, f**len(gens)): + gen = sum(gens[k] * ((j // f**k) % f) for k in range(len(gens))) + assert not gen.is_zero() + assert (f*gen).is_zero() + + # Find lambda for endomorphism. Skip if none can be found. + lam = None + for l in cbrts: + if l*gen == E(BETA*gen[0], gen[1]): + lam = l + break + + if lam is None: + no_endo_count += 1 + else: + sol_count += 1 + solutions.setdefault(f, []).append((b, int(gen[0]), int(gen[1]), gen, lam)) + + print(f" - Found {sol_count} generators (plus {no_endo_count} without endomorphism)") + + print() + +def output_generator(g, name): + print(f"#define {name} SECP256K1_GE_CONST(\\") + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(")") + +def output_b(b): + print(f"#define SECP256K1_B {int(b)}") + +print() +print("To be put in src/group_impl.h:") +print() +print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") +for f in sorted(solutions.keys()): + # Use as generator/2 the one with lowest b, and lowest (x, y) generator (interpreted as non-negative integers). + b, _, _, HALF_G, lam = min(solutions[f]) + output_generator(2 * HALF_G, f"SECP256K1_G_ORDER_{f}") +print("/** Generator for secp256k1, value 'g' defined in") +print(" * \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.") +print(" */") +output_generator(G, "SECP256K1_G") +print("/* These exhaustive group test orders and generators are chosen such that:") +print(" * - The field size is equal to that of secp256k1, so field code is the same.") +print(" * - The curve equation is of the form y^2=x^3+B for some small constant B.") +print(" * - The subgroup has a generator 2*P, where P.x is as small as possible.") +print(f" * - The subgroup has size less than {MAX_ORDER} to permit exhaustive testing.") +print(" * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).") +print(" */") +print("#if defined(EXHAUSTIVE_TEST_ORDER)") +first = True +for f in sorted(solutions.keys()): + b, _, _, _, lam = min(solutions[f]) + print(f"# {'if' if first else 'elif'} EXHAUSTIVE_TEST_ORDER == {f}") + first = False + print() + print(f"static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_{f};") + output_b(b) + print() +print("# else") +print("# error No known generator for the specified exhaustive test group order.") +print("# endif") +print("#else") +print() +print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;") +output_b(7) +print() +print("#endif") +print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") + + +print() +print() +print("To be put in src/scalar_impl.h:") +print() +print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") +first = True +for f in sorted(solutions.keys()): + _, _, _, _, lam = min(solutions[f]) + print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) + first = False + print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam) +print("# else") +print("# error No known lambda for the specified exhaustive test group order.") +print("# endif") +print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") diff --git a/external/secp256k1/sage/gen_split_lambda_constants.sage b/external/secp256k1/sage/gen_split_lambda_constants.sage new file mode 100644 index 00000000000..7d4359e0f64 --- /dev/null +++ b/external/secp256k1/sage/gen_split_lambda_constants.sage @@ -0,0 +1,114 @@ +""" Generates the constants used in secp256k1_scalar_split_lambda. + +See the comments for secp256k1_scalar_split_lambda in src/scalar_impl.h for detailed explanations. +""" + +load("secp256k1_params.sage") + +def inf_norm(v): + """Returns the infinity norm of a vector.""" + return max(map(abs, v)) + +def gauss_reduction(i1, i2): + v1, v2 = i1.copy(), i2.copy() + while True: + if inf_norm(v2) < inf_norm(v1): + v1, v2 = v2, v1 + # This is essentially + # m = round((v1[0]*v2[0] + v1[1]*v2[1]) / (inf_norm(v1)**2)) + # (rounding to the nearest integer) without relying on floating point arithmetic. + m = ((v1[0]*v2[0] + v1[1]*v2[1]) + (inf_norm(v1)**2) // 2) // (inf_norm(v1)**2) + if m == 0: + return v1, v2 + v2[0] -= m*v1[0] + v2[1] -= m*v1[1] + +def find_split_constants_gauss(): + """Find constants for secp256k1_scalar_split_lamdba using gauss reduction.""" + (v11, v12), (v21, v22) = gauss_reduction([0, N], [1, int(LAMBDA)]) + + # We use related vectors in secp256k1_scalar_split_lambda. + A1, B1 = -v21, -v11 + A2, B2 = v22, -v21 + + return A1, B1, A2, B2 + +def find_split_constants_explicit_tof(): + """Find constants for secp256k1_scalar_split_lamdba using the trace of Frobenius. + + See Benjamin Smith: "Easy scalar decompositions for efficient scalar multiplication on + elliptic curves and genus 2 Jacobians" (https://eprint.iacr.org/2013/672), Example 2 + """ + assert P % 3 == 1 # The paper says P % 3 == 2 but that appears to be a mistake, see [10]. + assert C.j_invariant() == 0 + + t = C.trace_of_frobenius() + + c = Integer(sqrt((4*P - t**2)/3)) + A1 = Integer((t - c)/2 - 1) + B1 = c + + A2 = Integer((t + c)/2 - 1) + B2 = Integer(1 - (t - c)/2) + + # We use a negated b values in secp256k1_scalar_split_lambda. + B1, B2 = -B1, -B2 + + return A1, B1, A2, B2 + +A1, B1, A2, B2 = find_split_constants_explicit_tof() + +# For extra fun, use an independent method to recompute the constants. +assert (A1, B1, A2, B2) == find_split_constants_gauss() + +# PHI : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n. +def PHI(a,b): + return Z(a + LAMBDA*b) + +# Check that (A1, B1) and (A2, B2) are in the kernel of PHI. +assert PHI(A1, B1) == Z(0) +assert PHI(A2, B2) == Z(0) + +# Check that the parallelogram generated by (A1, A2) and (B1, B2) +# is a fundamental domain by containing exactly N points. +# Since the LHS is the determinant and N != 0, this also checks that +# (A1, A2) and (B1, B2) are linearly independent. By the previous +# assertions, (A1, A2) and (B1, B2) are a basis of the kernel. +assert A1*B2 - B1*A2 == N + +# Check that their components are short enough. +assert (A1 + A2)/2 < sqrt(N) +assert B1 < sqrt(N) +assert B2 < sqrt(N) + +G1 = round((2**384)*B2/N) +G2 = round((2**384)*(-B1)/N) + +def rnddiv2(v): + if v & 1: + v += 1 + return v >> 1 + +def scalar_lambda_split(k): + """Equivalent to secp256k1_scalar_lambda_split().""" + c1 = rnddiv2((k * G1) >> 383) + c2 = rnddiv2((k * G2) >> 383) + c1 = (c1 * -B1) % N + c2 = (c2 * -B2) % N + r2 = (c1 + c2) % N + r1 = (k + r2 * -LAMBDA) % N + return (r1, r2) + +# The result of scalar_lambda_split can depend on the representation of k (mod n). +SPECIAL = (2**383) // G2 + 1 +assert scalar_lambda_split(SPECIAL) != scalar_lambda_split(SPECIAL + N) + +print(' A1 =', hex(A1)) +print(' -B1 =', hex(-B1)) +print(' A2 =', hex(A2)) +print(' -B2 =', hex(-B2)) +print(' =', hex(Z(-B2))) +print(' -LAMBDA =', hex(-LAMBDA)) + +print(' G1 =', hex(G1)) +print(' G2 =', hex(G2)) diff --git a/src/secp256k1/sage/group_prover.sage b/external/secp256k1/sage/group_prover.sage similarity index 79% rename from src/secp256k1/sage/group_prover.sage rename to external/secp256k1/sage/group_prover.sage index ab580c5b23b..bb092953695 100644 --- a/src/secp256k1/sage/group_prover.sage +++ b/external/secp256k1/sage/group_prover.sage @@ -3,7 +3,7 @@ # to independently set assumptions on input or intermediary variables. # # The general approach is: -# * A constraint is a tuple of two sets of of symbolic expressions: +# * A constraint is a tuple of two sets of symbolic expressions: # the first of which are required to evaluate to zero, the second of which # are required to evaluate to nonzero. # - A constraint is said to be conflicting if any of its nonzero expressions @@ -17,7 +17,7 @@ # - A constraint describing the requirements of the law, called "require" # * Implementations are transliterated into functions that operate as well on # algebraic input points, and are called once per combination of branches -# exectured. Each execution returns: +# executed. Each execution returns: # - A constraint describing the assumptions this implementation requires # (such as Z1=1), called "assumeFormula" # - A constraint describing the assumptions this specific branch requires, @@ -42,7 +42,7 @@ # as we assume that all constraints in it are complementary with each other. # # Based on the sage verification scripts used in the Explicit-Formulas Database -# by Tanja Lange and others, see http://hyperelliptic.org/EFD +# by Tanja Lange and others, see https://hyperelliptic.org/EFD class fastfrac: """Fractions over rings.""" @@ -65,7 +65,7 @@ class fastfrac: return self.top in I and self.bot not in I def reduce(self,assumeZero): - zero = self.R.ideal(map(numerator, assumeZero)) + zero = self.R.ideal(list(map(numerator, assumeZero))) return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) def __add__(self,other): @@ -100,7 +100,7 @@ class fastfrac: """Multiply something else with a fraction.""" return self.__mul__(other) - def __div__(self,other): + def __truediv__(self,other): """Divide two fractions.""" if parent(other) == ZZ: return fastfrac(self.R,self.top,self.bot * other) @@ -108,6 +108,11 @@ class fastfrac: return fastfrac(self.R,self.top * other.bot,self.bot * other.top) return NotImplemented + # Compatibility wrapper for Sage versions based on Python 2 + def __div__(self,other): + """Divide two fractions.""" + return self.__truediv__(other) + def __pow__(self,other): """Compute a power of a fraction.""" if parent(other) == ZZ: @@ -159,6 +164,9 @@ class constraints: def negate(self): return constraints(zero=self.nonzero, nonzero=self.zero) + def map(self, fun): + return constraints(zero={fun(k): v for k, v in self.zero.items()}, nonzero={fun(k): v for k, v in self.nonzero.items()}) + def __add__(self, other): zero = self.zero.copy() zero.update(other.zero) @@ -172,10 +180,34 @@ class constraints: def __repr__(self): return "%s" % self +def normalize_factor(p): + """Normalizes the sign of primitive polynomials (as returned by factor()) + + This function ensures that the polynomial has a positive leading coefficient. + + This is necessary because recent sage versions (starting with v9.3 or v9.4, + we don't know) are inconsistent about the placement of the minus sign in + polynomial factorizations: + ``` + sage: R. = PolynomialRing(QQ,8,order='invlex') + sage: R((-2 * (bx - ax)) ^ 1).factor() + (-2) * (bx - ax) + sage: R((-2 * (bx - ax)) ^ 2).factor() + (4) * (-bx + ax)^2 + sage: R((-2 * (bx - ax)) ^ 3).factor() + (8) * (-bx + ax)^3 + ``` + """ + # Assert p is not 0 and that its non-zero coefficients are coprime. + # (We could just work with the primitive part p/p.content() but we want to be + # aware if factor() does not return a primitive part in future sage versions.) + assert p.content() == 1 + # Ensure that the first non-zero coefficient is positive. + return p if p.lc() > 0 else -p def conflicts(R, con): """Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" - zero = R.ideal(map(numerator, con.zero)) + zero = R.ideal(list(map(numerator, con.zero))) if 1 in zero: return True # First a cheap check whether any of the individual nonzero terms conflict on @@ -195,20 +227,20 @@ def conflicts(R, con): def get_nonzero_set(R, assume): """Calculate a simple set of nonzero expressions""" - zero = R.ideal(map(numerator, assume.zero)) + zero = R.ideal(list(map(numerator, assume.zero))) nonzero = set() for nz in map(numerator, assume.nonzero): for (f,n) in nz.factor(): - nonzero.add(f) + nonzero.add(normalize_factor(f)) rnz = zero.reduce(nz) for (f,n) in rnz.factor(): - nonzero.add(f) + nonzero.add(normalize_factor(f)) return nonzero def prove_nonzero(R, exprs, assume): """Check whether an expression is provably nonzero, given assumptions""" - zero = R.ideal(map(numerator, assume.zero)) + zero = R.ideal(list(map(numerator, assume.zero))) nonzero = get_nonzero_set(R, assume) expl = set() ok = True @@ -217,27 +249,27 @@ def prove_nonzero(R, exprs, assume): return (False, [exprs[expr]]) allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) for (f, n) in allexprs.factor(): - if f not in nonzero: + if normalize_factor(f) not in nonzero: ok = False if ok: return (True, None) ok = True - for (f, n) in zero.reduce(numerator(allexprs)).factor(): - if f not in nonzero: + for (f, n) in zero.reduce(allexprs).factor(): + if normalize_factor(f) not in nonzero: ok = False if ok: return (True, None) ok = True for expr in exprs: for (f,n) in numerator(expr).factor(): - if f not in nonzero: + if normalize_factor(f) not in nonzero: ok = False if ok: return (True, None) ok = True for expr in exprs: for (f,n) in zero.reduce(numerator(expr)).factor(): - if f not in nonzero: + if normalize_factor(f) not in nonzero: expl.add(exprs[expr]) if expl: return (False, list(expl)) @@ -249,8 +281,8 @@ def prove_zero(R, exprs, assume): """Check whether all of the passed expressions are provably zero, given assumptions""" r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) if not r: - return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) - zero = R.ideal(map(numerator, assume.zero)) + return (False, list(map(lambda x: "Possibly zero denominator: %s" % x, e))) + zero = R.ideal(list(map(numerator, assume.zero))) nonzero = prod(x for x in assume.nonzero) expl = [] for expr in exprs: @@ -265,8 +297,8 @@ def describe_extra(R, assume, assumeExtra): """Describe what assumptions are added, given existing assumptions""" zerox = assume.zero.copy() zerox.update(assumeExtra.zero) - zero = R.ideal(map(numerator, assume.zero)) - zeroextra = R.ideal(map(numerator, zerox)) + zero = R.ideal(list(map(numerator, assume.zero))) + zeroextra = R.ideal(list(map(numerator, zerox))) nonzero = get_nonzero_set(R, assume) ret = set() # Iterate over the extra zero expressions @@ -274,8 +306,8 @@ def describe_extra(R, assume, assumeExtra): if base not in zero: add = [] for (f, n) in numerator(base).factor(): - if f not in nonzero: - add += ["%s" % f] + if normalize_factor(f) not in nonzero: + add += ["%s" % normalize_factor(f)] if add: ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) # Iterate over the extra nonzero expressions @@ -283,8 +315,8 @@ def describe_extra(R, assume, assumeExtra): nzr = zeroextra.reduce(numerator(nz)) if nzr not in zeroextra: for (f,n) in nzr.factor(): - if zeroextra.reduce(f) not in nonzero: - ret.add("%s != 0" % zeroextra.reduce(f)) + if normalize_factor(zeroextra.reduce(f)) not in nonzero: + ret.add("%s != 0" % normalize_factor(zeroextra.reduce(f))) return ", ".join(x for x in ret) @@ -294,22 +326,21 @@ def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): if conflicts(R, assume): # This formula does not apply - return None + return (True, None) describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) + if describe != "": + describe = " (assuming " + describe + ")" ok, msg = prove_zero(R, require.zero, assume) if not ok: - return "FAIL, %s fails (assuming %s)" % (str(msg), describe) + return (False, "FAIL, %s fails%s" % (str(msg), describe)) res, expl = prove_nonzero(R, require.nonzero, assume) if not res: - return "FAIL, %s fails (assuming %s)" % (str(expl), describe) + return (False, "FAIL, %s fails%s" % (str(expl), describe)) - if describe != "": - return "OK (assuming %s)" % describe - else: - return "OK" + return (True, "OK%s" % describe) def concrete_verify(c): diff --git a/external/secp256k1/sage/prove_group_implementations.sage b/external/secp256k1/sage/prove_group_implementations.sage new file mode 100644 index 00000000000..23799be52b6 --- /dev/null +++ b/external/secp256k1/sage/prove_group_implementations.sage @@ -0,0 +1,285 @@ +# Test libsecp256k1' group operation implementations using prover.sage + +import sys + +load("group_prover.sage") +load("weierstrass_prover.sage") + +def formula_secp256k1_gej_double_var(a): + """libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" + rz = a.Z * a.Y + s = a.Y^2 + l = a.X^2 + l = l * 3 + l = l / 2 + t = -s + t = t * a.X + rx = l^2 + rx = rx + t + rx = rx + t + s = s^2 + t = t + rx + ry = t * l + ry = ry + s + ry = -ry + return jacobianpoint(rx, ry, rz) + +def formula_secp256k1_gej_add_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_var""" + if branch == 0: + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z22 = b.Z^2 + z12 = a.Z^2 + u1 = a.X * z22 + u2 = b.X * z12 + s1 = a.Y * z22 + s1 = s1 * b.Z + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s2 + i = i + s1 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) + if branch == 3: + return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) + t = h * b.Z + rz = a.Z * t + h2 = h^2 + h2 = -h2 + h3 = h2 * h + t = u1 * h2 + rx = i^2 + rx = rx + h3 + rx = rx + t + rx = rx + t + t = t + rx + ry = t * i + h3 = h3 * s1 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1""" + if branch == 0: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z12 = a.Z^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s2 + i = i + s1 + if (branch == 2): + r = formula_secp256k1_gej_double_var(a) + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if (branch == 3): + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + rz = a.Z * h + h2 = h^2 + h2 = -h2 + h3 = h2 * h + t = u1 * h2 + rx = i^2 + rx = rx + h3 + rx = rx + t + rx = rx + t + t = t + rx + ry = t * i + h3 = h3 * s1 + ry = ry + h3 + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_zinv_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_zinv_var""" + bzinv = b.Z^(-1) + if branch == 0: + rinf = b.Infinity + bzinv2 = bzinv^2 + bzinv3 = bzinv2 * bzinv + rx = b.X * bzinv2 + ry = b.Y * bzinv3 + rz = 1 + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz, rinf)) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + azz = a.Z * bzinv + z12 = azz^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * azz + h = -u1 + h = h + u2 + i = -s2 + i = i + s1 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if branch == 3: + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + rz = a.Z * h + h2 = h^2 + h2 = -h2 + h3 = h2 * h + t = u1 * h2 + rx = i^2 + rx = rx + h3 + rx = rx + t + rx = rx + t + t = t + rx + ry = t * i + h3 = h3 * s1 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge""" + zeroes = {} + nonzeroes = {} + a_infinity = False + if (branch & 2) != 0: + nonzeroes.update({a.Infinity : 'a_infinite'}) + a_infinity = True + else: + zeroes.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + rr = t^2 + m_alt = -u2 + tt = u1 * m_alt + rr = rr + tt + degenerate = (branch & 1) != 0 + if degenerate: + zeroes.update({m : 'm_zero'}) + else: + nonzeroes.update({m : 'm_nonzero'}) + rr_alt = s1 + rr_alt = rr_alt * 2 + m_alt = m_alt + u1 + if not degenerate: + rr_alt = rr + m_alt = m + n = m_alt^2 + q = -t + q = q * n + n = n^2 + if degenerate: + n = m + t = rr_alt^2 + rz = a.Z * m_alt + t = t + q + rx = t + t = t * 2 + t = t + q + t = t * rr_alt + t = t + n + ry = -t + ry = ry / 2 + if a_infinity: + rx = b.X + ry = b.Y + rz = 1 + if (branch & 4) != 0: + zeroes.update({rz : 'r.z = 0'}) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + else: + nonzeroes.update({rz : 'r.z != 0'}) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_old(branch, a, b): + """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx""" + a_infinity = (branch & 1) != 0 + zero = {} + nonzero = {} + if a_infinity: + nonzero.update({a.Infinity : 'a_infinite'}) + else: + zero.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + z = a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + n = m^2 + q = n * t + n = n^2 + rr = t^2 + t = u1 * u2 + t = -t + rr = rr + t + t = rr^2 + rz = m * z + infinity = False + if (branch & 2) != 0: + if not a_infinity: + infinity = True + else: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) + zero.update({rz : 'r.z=0'}) + else: + nonzero.update({rz : 'r.z!=0'}) + rz = rz * (0 if a_infinity else 2) + rx = t + q = -q + rx = rx + q + q = q * 3 + t = t * 2 + t = t + q + t = t * rr + t = t + n + ry = -t + rx = rx * (0 if a_infinity else 4) + ry = ry * (0 if a_infinity else 4) + t = b.X + t = t * (1 if a_infinity else 0) + rx = rx + t + t = b.Y + t = t * (1 if a_infinity else 0) + ry = ry + t + t = (1 if a_infinity else 0) + rz = rz + t + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) + +if __name__ == "__main__": + success = True + success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) + success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) + success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) + success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge) + success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)) + + if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": + success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) + success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) + success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) + success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge, 43) + success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)) + + sys.exit(int(not success)) diff --git a/external/secp256k1/sage/secp256k1_params.sage b/external/secp256k1/sage/secp256k1_params.sage new file mode 100644 index 00000000000..68f95adec4b --- /dev/null +++ b/external/secp256k1/sage/secp256k1_params.sage @@ -0,0 +1,39 @@ +"""Prime order of finite field underlying secp256k1 (2^256 - 2^32 - 977)""" +P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F + +"""Finite field underlying secp256k1""" +F = FiniteField(P) + +"""Elliptic curve secp256k1: y^2 = x^3 + 7""" +C = EllipticCurve([F(0), F(7)]) + +"""Base point of secp256k1""" +G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) +if int(G[1]) & 1: + # G.y is even + G = -G + +"""Prime order of secp256k1""" +N = C.order() + +"""Finite field of scalars of secp256k1""" +Z = FiniteField(N) + +""" Beta value of secp256k1 non-trivial endomorphism: lambda * (x, y) = (beta * x, y)""" +BETA = F(2)^((P-1)/3) + +""" Lambda value of secp256k1 non-trivial endomorphism: lambda * (x, y) = (beta * x, y)""" +LAMBDA = Z(3)^((N-1)/3) + +assert is_prime(P) +assert is_prime(N) + +assert BETA != F(1) +assert BETA^3 == F(1) +assert BETA^2 + BETA + 1 == 0 + +assert LAMBDA != Z(1) +assert LAMBDA^3 == Z(1) +assert LAMBDA^2 + LAMBDA + 1 == 0 + +assert Integer(LAMBDA)*G == C(BETA*G[0], G[1]) diff --git a/src/secp256k1/sage/weierstrass_prover.sage b/external/secp256k1/sage/weierstrass_prover.sage similarity index 89% rename from src/secp256k1/sage/weierstrass_prover.sage rename to external/secp256k1/sage/weierstrass_prover.sage index 03ef2ec901e..be9cfd4c76d 100644 --- a/src/secp256k1/sage/weierstrass_prover.sage +++ b/external/secp256k1/sage/weierstrass_prover.sage @@ -175,24 +175,25 @@ laws_jacobian_weierstrass = { def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" F = Integers(p) - print "Formula %s on Z%i:" % (name, p) + print("Formula %s on Z%i:" % (name, p)) points = [] - for x in xrange(0, p): - for y in xrange(0, p): + for x in range(0, p): + for y in range(0, p): point = affinepoint(F(x), F(y)) r, e = concrete_verify(on_weierstrass_curve(A, B, point)) if r: points.append(point) - for za in xrange(1, p): - for zb in xrange(1, p): + ret = True + for za in range(1, p): + for zb in range(1, p): for pa in points: for pb in points: - for ia in xrange(2): - for ib in xrange(2): + for ia in range(2): + for ib in range(2): pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) - for branch in xrange(0, branches): + for branch in range(0, branches): assumeAssert, assumeBranch, pC = formula(branch, pA, pB) pC.X = F(pC.X) pC.Y = F(pC.Y) @@ -206,13 +207,16 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): r, e = concrete_verify(assumeLaw) if r: if match: - print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) + print(" multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)) else: match = True r, e = concrete_verify(require) if not r: - print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) - print + ret = False + print(" failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)) + + print() + return ret def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): @@ -242,23 +246,30 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): for key in laws_jacobian_weierstrass: res[key] = [] - print ("Formula " + name + ":") + print("Formula " + name + ":") count = 0 - for branch in xrange(branches): + ret = True + for branch in range(branches): assumeFormula, assumeBranch, pC = formula(branch, pA, pB) + assumeBranch = assumeBranch.map(lift) + assumeFormula = assumeFormula.map(lift) pC.X = lift(pC.X) pC.Y = lift(pC.Y) pC.Z = lift(pC.Z) pC.Infinity = lift(pC.Infinity) for key in laws_jacobian_weierstrass: - res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) + success, msg = check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC) + if not success: + ret = False + res[key].append((msg, branch)) for key in res: - print " %s:" % key + print(" %s:" % key) val = res[key] for x in val: if x[0] is not None: - print " branch %i: %s" % (x[1], x[0]) + print(" branch %i: %s" % (x[1], x[0])) - print + print() + return ret diff --git a/external/secp256k1/src/CMakeLists.txt b/external/secp256k1/src/CMakeLists.txt new file mode 100644 index 00000000000..f31b8c8f551 --- /dev/null +++ b/external/secp256k1/src/CMakeLists.txt @@ -0,0 +1,176 @@ +# Must be included before CMAKE_INSTALL_INCLUDEDIR is used. +include(GNUInstallDirs) + +add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL + precomputed_ecmult.c + precomputed_ecmult_gen.c +) + +# Add objects explicitly rather than linking to the object libs to keep them +# from being exported. +add_library(secp256k1 secp256k1.c $) + +add_library(secp256k1_asm INTERFACE) +if(SECP256K1_ASM STREQUAL "arm32") + add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL) + target_sources(secp256k1_asm_arm PUBLIC + asm/field_10x26_arm.s + ) + target_sources(secp256k1 PRIVATE $) + target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm) +endif() + +if(WIN32) + # Define our export symbol only for shared libs. + set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL SECP256K1_DLL_EXPORT) + target_compile_definitions(secp256k1 INTERFACE $<$>:SECP256K1_STATIC>) +endif() + +# Object libs don't know if they're being built for a shared or static lib. +# Grab the PIC property from secp256k1 which knows. +get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE) +set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic}) + +target_include_directories(secp256k1 INTERFACE + # Add the include path for parent projects so that they don't have to manually add it. + $>:${PROJECT_SOURCE_DIR}/include>> + $ +) + +# This emulates Libtool to make sure Libtool and CMake agree on the ABI version, +# see below "Calculate the version variables" in build-aux/ltmain.sh. +math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}") +set_target_properties(secp256k1 PROPERTIES + SOVERSION ${${PROJECT_NAME}_soversion} +) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set_target_properties(secp256k1 PROPERTIES + VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION} + ) +elseif(APPLE) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17) + math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1") + set_target_properties(secp256k1 PROPERTIES + MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version} + MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION} + ) + unset(${PROJECT_NAME}_compatibility_version) + elseif(BUILD_SHARED_LIBS) + message(WARNING + "The 'compatibility version' and 'current version' values of the DYLIB " + "will diverge from the values set by the GNU Libtool. To ensure " + "compatibility, it is recommended to upgrade CMake to at least version 3.17." + ) + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(${PROJECT_NAME}_windows "secp256k1") + if(MSVC) + set(${PROJECT_NAME}_windows "${PROJECT_NAME}") + endif() + set_target_properties(secp256k1 PROPERTIES + ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}" + RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}" + ) + unset(${PROJECT_NAME}_windows) +endif() +unset(${PROJECT_NAME}_soversion) + +if(SECP256K1_BUILD_BENCHMARK) + add_executable(bench bench.c) + target_link_libraries(bench secp256k1) + add_executable(bench_internal bench_internal.c) + target_link_libraries(bench_internal secp256k1_precomputed secp256k1_asm) + add_executable(bench_ecmult bench_ecmult.c) + target_link_libraries(bench_ecmult secp256k1_precomputed secp256k1_asm) +endif() + +if(SECP256K1_BUILD_TESTS) + add_executable(noverify_tests tests.c) + target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm) + add_test(NAME secp256k1_noverify_tests COMMAND noverify_tests) + if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") + add_executable(tests tests.c) + target_compile_definitions(tests PRIVATE VERIFY) + target_link_libraries(tests secp256k1_precomputed secp256k1_asm) + add_test(NAME secp256k1_tests COMMAND tests) + endif() +endif() + +if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) + # Note: do not include secp256k1_precomputed in exhaustive_tests (it uses runtime-generated tables). + add_executable(exhaustive_tests tests_exhaustive.c) + target_link_libraries(exhaustive_tests secp256k1_asm) + target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) + add_test(NAME secp256k1_exhaustive_tests COMMAND exhaustive_tests) +endif() + +if(SECP256K1_BUILD_CTIME_TESTS) + add_executable(ctime_tests ctime_tests.c) + target_link_libraries(ctime_tests secp256k1) +endif() + +if(SECP256K1_INSTALL) + install(TARGETS secp256k1 + EXPORT ${PROJECT_NAME}-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + set(${PROJECT_NAME}_headers + "${PROJECT_SOURCE_DIR}/include/secp256k1.h" + "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h" + ) + if(SECP256K1_ENABLE_MODULE_ECDH) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h") + endif() + if(SECP256K1_ENABLE_MODULE_RECOVERY) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h") + endif() + if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h") + endif() + if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h") + endif() + if(SECP256K1_ENABLE_MODULE_MUSIG) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h") + endif() + if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h") + endif() + install(FILES ${${PROJECT_NAME}_headers} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install(EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}-targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + ) + + include(CMakePackageConfigHelpers) + configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in + ${PROJECT_NAME}-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + NO_SET_AND_CHECK_MACRO + ) + write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake + COMPATIBILITY SameMinorVersion + ) + + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + ) + + include(GeneratePkgConfigFile) + generate_pkg_config_file(${PROJECT_SOURCE_DIR}/libsecp256k1.pc.in) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + ) +endif() diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/external/secp256k1/src/asm/field_10x26_arm.s similarity index 98% rename from src/secp256k1/src/asm/field_10x26_arm.s rename to external/secp256k1/src/asm/field_10x26_arm.s index 5df561f2fc9..664b921400d 100644 --- a/src/secp256k1/src/asm/field_10x26_arm.s +++ b/external/secp256k1/src/asm/field_10x26_arm.s @@ -1,9 +1,9 @@ @ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: -/********************************************************************** - * Copyright (c) 2014 Wladimir J. van der Laan * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Wladimir J. van der Laan * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ /* ARM implementation of field_10x26 inner loops. @@ -11,20 +11,14 @@ Note: - To avoid unnecessary loads and make use of available registers, two 'passes' have every time been interleaved, with the odd passes accumulating c' and d' - which will be added to c and d respectively in the the even passes + which will be added to c and d respectively in the even passes */ .syntax unified - .arch armv7-a @ eabi attributes - see readelf -A - .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes - .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no - .eabi_attribute 10, 0 @ Tag_FP_arch = none .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP - .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed - .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 .text @ Field constants @@ -35,6 +29,7 @@ Note: .align 2 .global secp256k1_fe_mul_inner .type secp256k1_fe_mul_inner, %function + .hidden secp256k1_fe_mul_inner @ Arguments: @ r0 r Restrict: can overlap with a, not with b @ r1 a @@ -522,6 +517,7 @@ secp256k1_fe_mul_inner: .align 2 .global secp256k1_fe_sqr_inner .type secp256k1_fe_sqr_inner, %function + .hidden secp256k1_fe_sqr_inner @ Arguments: @ r0 r Can overlap with a @ r1 a @@ -917,3 +913,4 @@ secp256k1_fe_sqr_inner: ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner + .section .note.GNU-stack,"",%progbits diff --git a/external/secp256k1/src/assumptions.h b/external/secp256k1/src/assumptions.h new file mode 100644 index 00000000000..7961005350b --- /dev/null +++ b/external/secp256k1/src/assumptions.h @@ -0,0 +1,87 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ASSUMPTIONS_H +#define SECP256K1_ASSUMPTIONS_H + +#include + +#include "util.h" +#if defined(SECP256K1_INT128_NATIVE) +#include "int128_native.h" +#endif + +/* This library, like most software, relies on a number of compiler implementation defined (but not undefined) + behaviours. Although the behaviours we require are essentially universal we test them specifically here to + reduce the odds of experiencing an unwelcome surprise. +*/ + +#if defined(__has_attribute) +# if __has_attribute(__unavailable__) +__attribute__((__unavailable__("Don't call this function. It only exists because STATIC_ASSERT cannot be used outside a function."))) +# endif +#endif +static void secp256k1_assumption_checker(void) { + /* Bytes are 8 bits. */ + STATIC_ASSERT(CHAR_BIT == 8); + + /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32 + without signed overflow, which would be undefined behaviour. */ + STATIC_ASSERT(UINT_MAX <= UINT32_MAX); + + /* Conversions from unsigned to signed outside of the bounds of the signed type are + implementation-defined. Verify that they function as reinterpreting the lower + bits of the input in two's complement notation. Do this for conversions: + - from uint(N)_t to int(N)_t with negative result + - from uint(2N)_t to int(N)_t with negative result + - from int(2N)_t to int(N)_t with negative result + - from int(2N)_t to int(N)_t with positive result */ + + /* To int8_t. */ + STATIC_ASSERT(((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55)); + STATIC_ASSERT((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33); + STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF); + STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34); + + /* To int16_t. */ + STATIC_ASSERT((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322); + STATIC_ASSERT((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C); + STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4); + STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678); + + /* To int32_t. */ + STATIC_ASSERT((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B); + STATIC_ASSERT((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE); + STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8); + STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789); + + /* To int64_t. */ + STATIC_ASSERT((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL); +#if defined(SECP256K1_INT128_NATIVE) + STATIC_ASSERT((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL); + STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL); + STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL); + + /* To int128_t. */ + STATIC_ASSERT((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)); +#endif + + /* Right shift on negative signed values is implementation defined. Verify that it + acts as a right shift in two's complement with sign extension (i.e duplicating + the top bit into newly added bits). */ + STATIC_ASSERT((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA); + STATIC_ASSERT((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A); + STATIC_ASSERT((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48); + STATIC_ASSERT((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL); +#if defined(SECP256K1_INT128_NATIVE) + STATIC_ASSERT((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)); +#endif + + /* This function is not supposed to be called. */ + VERIFY_CHECK(0); +} + +#endif /* SECP256K1_ASSUMPTIONS_H */ diff --git a/external/secp256k1/src/bench.c b/external/secp256k1/src/bench.c new file mode 100644 index 00000000000..1127df67ae0 --- /dev/null +++ b/external/secp256k1/src/bench.c @@ -0,0 +1,279 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#include +#include + +#include "../include/secp256k1.h" +#include "util.h" +#include "bench.h" + +static void help(int default_iters) { + printf("Benchmarks the following algorithms:\n"); + printf(" - ECDSA signing/verification\n"); + +#ifdef ENABLE_MODULE_ECDH + printf(" - ECDH key exchange (optional module)\n"); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + printf(" - Public key recovery (optional module)\n"); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + printf(" - Schnorr signatures (optional module)\n"); +#endif + + printf("\n"); + printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); + printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); + printf("\n"); + printf("Usage: ./bench [args]\n"); + printf("By default, all benchmarks will be run.\n"); + printf("args:\n"); + printf(" help : display this help and exit\n"); + printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n"); + printf(" ecdsa_sign : ECDSA siging algorithm\n"); + printf(" ecdsa_verify : ECDSA verification algorithm\n"); + printf(" ec : all EC public key algorithms (keygen)\n"); + printf(" ec_keygen : EC public key generation\n"); + +#ifdef ENABLE_MODULE_RECOVERY + printf(" ecdsa_recover : ECDSA public key recovery algorithm\n"); +#endif + +#ifdef ENABLE_MODULE_ECDH + printf(" ecdh : ECDH key exchange algorithm\n"); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + printf(" schnorrsig : all Schnorr signature algorithms (sign, verify)\n"); + printf(" schnorrsig_sign : Schnorr sigining algorithm\n"); + printf(" schnorrsig_verify : Schnorr verification algorithm\n"); +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT + printf(" ellswift : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n"); + printf(" ellswift_encode : ElligatorSwift encoding\n"); + printf(" ellswift_decode : ElligatorSwift decoding\n"); + printf(" ellswift_keygen : ElligatorSwift key generation\n"); + printf(" ellswift_ecdh : ECDH on ElligatorSwift keys\n"); +#endif + + printf("\n"); +} + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + unsigned char key[32]; + unsigned char sig[72]; + size_t siglen; + unsigned char pubkey[33]; + size_t pubkeylen; +} bench_data; + +static void bench_verify(void* arg, int iters) { + int i; + bench_data* data = (bench_data*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); + CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} + +static void bench_sign_setup(void* arg) { + int i; + bench_data *data = (bench_data*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = i + 1; + } + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } +} + +static void bench_sign_run(void* arg, int iters) { + int i; + bench_data *data = (bench_data*)arg; + + unsigned char sig[74]; + for (i = 0; i < iters; i++) { + size_t siglen = 74; + int j; + secp256k1_ecdsa_signature signature; + CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); + for (j = 0; j < 32; j++) { + data->msg[j] = sig[j]; + data->key[j] = sig[j + 32]; + } + } +} + +static void bench_keygen_setup(void* arg) { + int i; + bench_data *data = (bench_data*)arg; + + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } +} + +static void bench_keygen_run(void *arg, int iters) { + int i; + bench_data *data = (bench_data*)arg; + + for (i = 0; i < iters; i++) { + unsigned char pub33[33]; + size_t len = 33; + secp256k1_pubkey pubkey; + CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED)); + memcpy(data->key, pub33 + 1, 32); + } +} + + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/bench_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/bench_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/bench_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/bench_impl.h" +#endif + +int main(int argc, char** argv) { + int i; + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + bench_data data; + + int d = argc == 1; + int default_iters = 20000; + int iters = get_iters(default_iters); + + /* Check for invalid user arguments */ + char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover", + "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec", + "keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode", + "ellswift_decode", "ellswift_keygen", "ellswift_ecdh"}; + size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]); + int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size); + + if (argc > 1) { + if (have_flag(argc, argv, "-h") + || have_flag(argc, argv, "--help") + || have_flag(argc, argv, "help")) { + help(default_iters); + return 0; + } else if (invalid_args) { + fprintf(stderr, "./bench: unrecognized argument.\n\n"); + help(default_iters); + return 1; + } + } + +/* Check if the user tries to benchmark optional module without building it */ +#ifndef ENABLE_MODULE_ECDH + if (have_flag(argc, argv, "ecdh")) { + fprintf(stderr, "./bench: ECDH module not enabled.\n"); + fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n"); + return 1; + } +#endif + +#ifndef ENABLE_MODULE_RECOVERY + if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) { + fprintf(stderr, "./bench: Public key recovery module not enabled.\n"); + fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n"); + return 1; + } +#endif + +#ifndef ENABLE_MODULE_SCHNORRSIG + if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) { + fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n"); + fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n"); + return 1; + } +#endif + +#ifndef ENABLE_MODULE_ELLSWIFT + if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") || + have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") || + have_flag(argc, argv, "ellswift_ecdh")) { + fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n"); + fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n"); + return 1; + } +#endif + + /* ECDSA benchmark */ + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + + for (i = 0; i < 32; i++) { + data.msg[i] = 1 + i; + } + for (i = 0; i < 32; i++) { + data.key[i] = 33 + i; + } + data.siglen = 72; + CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); + CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); + data.pubkeylen = 33; + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + + print_output_table_header_row(); + if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters); + + secp256k1_context_destroy(data.ctx); + +#ifdef ENABLE_MODULE_ECDH + /* ECDH benchmarks */ + run_ecdh_bench(iters, argc, argv); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + /* ECDSA recovery benchmarks */ + run_recovery_bench(iters, argc, argv); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + /* Schnorr signature benchmarks */ + run_schnorrsig_bench(iters, argc, argv); +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT + /* ElligatorSwift benchmarks */ + run_ellswift_bench(iters, argc, argv); +#endif + + return 0; +} diff --git a/external/secp256k1/src/bench.h b/external/secp256k1/src/bench.h new file mode 100644 index 00000000000..1564b1a1760 --- /dev/null +++ b/external/secp256k1/src/bench.h @@ -0,0 +1,188 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_BENCH_H +#define SECP256K1_BENCH_H + +#include +#include +#include +#include + +#if (defined(_MSC_VER) && _MSC_VER >= 1900) +# include +#else +# include +#endif + +static int64_t gettime_i64(void) { +#if (defined(_MSC_VER) && _MSC_VER >= 1900) + /* C11 way to get wallclock time */ + struct timespec tv; + if (!timespec_get(&tv, TIME_UTC)) { + fputs("timespec_get failed!", stderr); + exit(1); + } + return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL; +#endif +} + +#define FP_EXP (6) +#define FP_MULT (1000000LL) + +/* Format fixed point number. */ +static void print_number(const int64_t x) { + int64_t x_abs, y; + int c, i, rounding, g; /* g = integer part size, c = fractional part size */ + size_t ptr; + char buffer[30]; + + if (x == INT64_MIN) { + /* Prevent UB. */ + printf("ERR"); + return; + } + x_abs = x < 0 ? -x : x; + + /* Determine how many decimals we want to show (more than FP_EXP makes no + * sense). */ + y = x_abs; + c = 0; + while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) { + y *= 10LL; + c++; + } + + /* Round to 'c' decimals. */ + y = x_abs; + rounding = 0; + for (i = c; i < FP_EXP; ++i) { + rounding = (y % 10) >= 5; + y /= 10; + } + y += rounding; + + /* Format and print the number. */ + ptr = sizeof(buffer) - 1; + buffer[ptr] = 0; + g = 0; + if (c != 0) { /* non zero fractional part */ + for (i = 0; i < c; ++i) { + buffer[--ptr] = '0' + (y % 10); + y /= 10; + } + } else if (c == 0) { /* fractional part is 0 */ + buffer[--ptr] = '0'; + } + buffer[--ptr] = '.'; + do { + buffer[--ptr] = '0' + (y % 10); + y /= 10; + g++; + } while (y != 0); + if (x < 0) { + buffer[--ptr] = '-'; + g++; + } + printf("%5.*s", g, &buffer[ptr]); /* Prints integer part */ + printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */ +} + +static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) { + int i; + int64_t min = INT64_MAX; + int64_t sum = 0; + int64_t max = 0; + for (i = 0; i < count; i++) { + int64_t begin, total; + if (setup != NULL) { + setup(data); + } + begin = gettime_i64(); + benchmark(data, iter); + total = gettime_i64() - begin; + if (teardown != NULL) { + teardown(data, iter); + } + if (total < min) { + min = total; + } + if (total > max) { + max = total; + } + sum += total; + } + /* ',' is used as a column delimiter */ + printf("%-30s, ", name); + print_number(min * FP_MULT / iter); + printf(" , "); + print_number(((sum * FP_MULT) / count) / iter); + printf(" , "); + print_number(max * FP_MULT / iter); + printf("\n"); +} + +static int have_flag(int argc, char** argv, char *flag) { + char** argm = argv + argc; + argv++; + while (argv != argm) { + if (strcmp(*argv, flag) == 0) { + return 1; + } + argv++; + } + return 0; +} + +/* takes an array containing the arguments that the user is allowed to enter on the command-line + returns: + - 1 if the user entered an invalid argument + - 0 if all the user entered arguments are valid */ +static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { + size_t i; + int found_valid; + char** argm = argv + argc; + argv++; + + while (argv != argm) { + found_valid = 0; + for (i = 0; i < n; i++) { + if (strcmp(*argv, valid_args[i]) == 0) { + found_valid = 1; /* user entered a valid arg from the list */ + break; + } + } + if (found_valid == 0) { + return 1; /* invalid arg found */ + } + argv++; + } + return 0; +} + +static int get_iters(int default_iters) { + char* env = getenv("SECP256K1_BENCH_ITERS"); + if (env) { + return strtol(env, NULL, 0); + } else { + return default_iters; + } +} + +static void print_output_table_header_row(void) { + char* bench_str = "Benchmark"; /* left justified */ + char* min_str = " Min(us) "; /* center alignment */ + char* avg_str = " Avg(us) "; + char* max_str = " Max(us) "; + printf("%-30s,%-15s,%-15s,%-15s\n", bench_str, min_str, avg_str, max_str); + printf("\n"); +} + +#endif /* SECP256K1_BENCH_H */ diff --git a/external/secp256k1/src/bench_ecmult.c b/external/secp256k1/src/bench_ecmult.c new file mode 100644 index 00000000000..3974af75f44 --- /dev/null +++ b/external/secp256k1/src/bench_ecmult.c @@ -0,0 +1,367 @@ +/*********************************************************************** + * Copyright (c) 2017 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ +#include + +#include "secp256k1.c" +#include "../include/secp256k1.h" + +#include "util.h" +#include "hash_impl.h" +#include "field_impl.h" +#include "group_impl.h" +#include "scalar_impl.h" +#include "ecmult_impl.h" +#include "bench.h" + +#define POINTS 32768 + +static void help(char **argv) { + printf("Benchmark EC multiplication algorithms\n"); + printf("\n"); + printf("Usage: %s \n", argv[0]); + printf("The output shows the number of multiplied and summed points right after the\n"); + printf("function name. The letter 'g' indicates that one of the points is the generator.\n"); + printf("The benchmarks are divided by the number of points.\n"); + printf("\n"); + printf("default (ecmult_multi): picks pippenger_wnaf or strauss_wnaf depending on the\n"); + printf(" batch size\n"); + printf("pippenger_wnaf: for all batch sizes\n"); + printf("strauss_wnaf: for all batch sizes\n"); + printf("simple: multiply and sum each point individually\n"); +} + +typedef struct { + /* Setup once in advance */ + secp256k1_context* ctx; + secp256k1_scratch_space* scratch; + secp256k1_scalar* scalars; + secp256k1_ge* pubkeys; + secp256k1_gej* pubkeys_gej; + secp256k1_scalar* seckeys; + secp256k1_gej* expected_output; + secp256k1_ecmult_multi_func ecmult_multi; + + /* Changes per benchmark */ + size_t count; + int includes_g; + + /* Changes per benchmark iteration, used to pick different scalars and pubkeys + * in each run. */ + size_t offset1; + size_t offset2; + + /* Benchmark output. */ + secp256k1_gej* output; +} bench_data; + +/* Hashes x into [0, POINTS) twice and store the result in offset1 and offset2. */ +static void hash_into_offset(bench_data* data, size_t x) { + data->offset1 = (x * 0x537b7f6f + 0x8f66a481) % POINTS; + data->offset2 = (x * 0x7f6f537b + 0x6a1a8f49) % POINTS; +} + +/* Check correctness of the benchmark by computing + * sum(outputs) ?= (sum(scalars_gen) + sum(seckeys)*sum(scalars))*G */ +static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset, size_t* scalar_offset, size_t* scalar_gen_offset, int iters) { + int i; + secp256k1_gej sum_output, tmp; + secp256k1_scalar sum_scalars; + + secp256k1_gej_set_infinity(&sum_output); + secp256k1_scalar_set_int(&sum_scalars, 0); + for (i = 0; i < iters; ++i) { + secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL); + if (scalar_gen_offset != NULL) { + secp256k1_scalar_add(&sum_scalars, &sum_scalars, &data->scalars[(*scalar_gen_offset+i) % POINTS]); + } + if (seckey_offset != NULL) { + secp256k1_scalar s = data->seckeys[(*seckey_offset+i) % POINTS]; + secp256k1_scalar_mul(&s, &s, &data->scalars[(*scalar_offset+i) % POINTS]); + secp256k1_scalar_add(&sum_scalars, &sum_scalars, &s); + } + } + secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); + CHECK(secp256k1_gej_eq_var(&tmp, &sum_output)); +} + +static void bench_ecmult_setup(void* arg) { + bench_data* data = (bench_data*)arg; + /* Re-randomize offset to ensure that we're using different scalars and + * group elements in each run. */ + hash_into_offset(data, data->offset1); +} + +static void bench_ecmult_gen(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters; ++i) { + secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]); + } +} + +static void bench_ecmult_gen_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters); +} + +static void bench_ecmult_const(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters; ++i) { + secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS]); + } +} + +static void bench_ecmult_const_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters); +} + +static void bench_ecmult_1p(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters; ++i) { + secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], NULL); + } +} + +static void bench_ecmult_1p_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters); +} + +static void bench_ecmult_0p_g(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters; ++i) { + secp256k1_ecmult(&data->output[i], NULL, &secp256k1_scalar_zero, &data->scalars[(data->offset1+i) % POINTS]); + } +} + +static void bench_ecmult_0p_g_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters); +} + +static void bench_ecmult_1p_g(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters/2; ++i) { + secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], &data->scalars[(data->offset1+i) % POINTS]); + } +} + +static void bench_ecmult_1p_g_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, &data->offset1, iters/2); +} + +static void run_ecmult_bench(bench_data* data, int iters) { + char str[32]; + sprintf(str, "ecmult_gen"); + run_benchmark(str, bench_ecmult_gen, bench_ecmult_setup, bench_ecmult_gen_teardown, data, 10, iters); + sprintf(str, "ecmult_const"); + run_benchmark(str, bench_ecmult_const, bench_ecmult_setup, bench_ecmult_const_teardown, data, 10, iters); + /* ecmult with non generator point */ + sprintf(str, "ecmult_1p"); + run_benchmark(str, bench_ecmult_1p, bench_ecmult_setup, bench_ecmult_1p_teardown, data, 10, iters); + /* ecmult with generator point */ + sprintf(str, "ecmult_0p_g"); + run_benchmark(str, bench_ecmult_0p_g, bench_ecmult_setup, bench_ecmult_0p_g_teardown, data, 10, iters); + /* ecmult with generator and non-generator point. The reported time is per point. */ + sprintf(str, "ecmult_1p_g"); + run_benchmark(str, bench_ecmult_1p_g, bench_ecmult_setup, bench_ecmult_1p_g_teardown, data, 10, 2*iters); +} + +static int bench_ecmult_multi_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, void* arg) { + bench_data* data = (bench_data*)arg; + if (data->includes_g) ++idx; + if (idx == 0) { + *sc = data->scalars[data->offset1]; + *ge = secp256k1_ge_const_g; + } else { + *sc = data->scalars[(data->offset1 + idx) % POINTS]; + *ge = data->pubkeys[(data->offset2 + idx - 1) % POINTS]; + } + return 1; +} + +static void bench_ecmult_multi(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + + int includes_g = data->includes_g; + int iter; + int count = data->count; + iters = iters / data->count; + + for (iter = 0; iter < iters; ++iter) { + data->ecmult_multi(&data->ctx->error_callback, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_ecmult_multi_callback, arg, count - includes_g); + data->offset1 = (data->offset1 + count) % POINTS; + data->offset2 = (data->offset2 + count - 1) % POINTS; + } +} + +static void bench_ecmult_multi_setup(void* arg) { + bench_data* data = (bench_data*)arg; + hash_into_offset(data, data->count); +} + +static void bench_ecmult_multi_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int iter; + iters = iters / data->count; + /* Verify the results in teardown, to avoid doing comparisons while benchmarking. */ + for (iter = 0; iter < iters; ++iter) { + secp256k1_gej tmp; + secp256k1_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL); + CHECK(secp256k1_gej_is_infinity(&tmp)); + } +} + +static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) { + secp256k1_sha256 sha256; + unsigned char c[10] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0}; + unsigned char buf[32]; + int overflow = 0; + c[6] = num; + c[7] = num >> 8; + c[8] = num >> 16; + c[9] = num >> 24; + secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_write(&sha256, c, sizeof(c)); + secp256k1_sha256_finalize(&sha256, buf); + secp256k1_scalar_set_b32(scalar, buf, &overflow); + CHECK(!overflow); +} + +static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_g, int num_iters) { + char str[32]; + size_t iters = 1 + num_iters / count; + size_t iter; + + data->count = count; + data->includes_g = includes_g; + + /* Compute (the negation of) the expected results directly. */ + hash_into_offset(data, data->count); + for (iter = 0; iter < iters; ++iter) { + secp256k1_scalar tmp; + secp256k1_scalar total = data->scalars[(data->offset1++) % POINTS]; + size_t i = 0; + for (i = 0; i + 1 < count; ++i) { + secp256k1_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]); + secp256k1_scalar_add(&total, &total, &tmp); + } + secp256k1_scalar_negate(&total, &total); + secp256k1_ecmult(&data->expected_output[iter], NULL, &secp256k1_scalar_zero, &total); + } + + /* Run the benchmark. */ + if (includes_g) { + sprintf(str, "ecmult_multi_%ip_g", (int)count - 1); + } else { + sprintf(str, "ecmult_multi_%ip", (int)count); + } + run_benchmark(str, bench_ecmult_multi, bench_ecmult_multi_setup, bench_ecmult_multi_teardown, data, 10, count * iters); +} + +int main(int argc, char **argv) { + bench_data data; + int i, p; + size_t scratch_size; + + int iters = get_iters(10000); + + data.ecmult_multi = secp256k1_ecmult_multi_var; + + if (argc > 1) { + if(have_flag(argc, argv, "-h") + || have_flag(argc, argv, "--help") + || have_flag(argc, argv, "help")) { + help(argv); + return 0; + } else if(have_flag(argc, argv, "pippenger_wnaf")) { + printf("Using pippenger_wnaf:\n"); + data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single; + } else if(have_flag(argc, argv, "strauss_wnaf")) { + printf("Using strauss_wnaf:\n"); + data.ecmult_multi = secp256k1_ecmult_strauss_batch_single; + } else if(have_flag(argc, argv, "simple")) { + printf("Using simple algorithm:\n"); + } else { + fprintf(stderr, "%s: unrecognized argument '%s'.\n\n", argv[0], argv[1]); + help(argv); + return 1; + } + } + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16; + if (!have_flag(argc, argv, "simple")) { + data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size); + } else { + data.scratch = NULL; + } + + /* Allocate stuff */ + data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS); + data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS); + data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS); + data.pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS); + data.expected_output = malloc(sizeof(secp256k1_gej) * (iters + 1)); + data.output = malloc(sizeof(secp256k1_gej) * (iters + 1)); + + /* Generate a set of scalars, and private/public keypairs. */ + secp256k1_gej_set_ge(&data.pubkeys_gej[0], &secp256k1_ge_const_g); + secp256k1_scalar_set_int(&data.seckeys[0], 1); + for (i = 0; i < POINTS; ++i) { + generate_scalar(i, &data.scalars[i]); + if (i) { + secp256k1_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL); + secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]); + } + } + secp256k1_ge_set_all_gej_var(data.pubkeys, data.pubkeys_gej, POINTS); + + + print_output_table_header_row(); + /* Initialize offset1 and offset2 */ + hash_into_offset(&data, 0); + run_ecmult_bench(&data, iters); + + for (i = 1; i <= 8; ++i) { + run_ecmult_multi_bench(&data, i, 1, iters); + } + + /* This is disabled with low count of iterations because the loop runs 77 times even with iters=1 + * and the higher it goes the longer the computation takes(more points) + * So we don't run this benchmark with low iterations to prevent slow down */ + if (iters > 2) { + for (p = 0; p <= 11; ++p) { + for (i = 9; i <= 16; ++i) { + run_ecmult_multi_bench(&data, i << p, 1, iters); + } + } + } + + if (data.scratch != NULL) { + secp256k1_scratch_space_destroy(data.ctx, data.scratch); + } + secp256k1_context_destroy(data.ctx); + free(data.scalars); + free(data.pubkeys); + free(data.pubkeys_gej); + free(data.seckeys); + free(data.output); + free(data.expected_output); + + return(0); +} diff --git a/external/secp256k1/src/bench_internal.c b/external/secp256k1/src/bench_internal.c new file mode 100644 index 00000000000..a700684922a --- /dev/null +++ b/external/secp256k1/src/bench_internal.c @@ -0,0 +1,436 @@ +/*********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ +#include + +#include "secp256k1.c" +#include "../include/secp256k1.h" + +#include "assumptions.h" +#include "util.h" +#include "hash_impl.h" +#include "field_impl.h" +#include "group_impl.h" +#include "scalar_impl.h" +#include "ecmult_impl.h" +#include "bench.h" + +static void help(int default_iters) { + printf("Benchmarks various internal routines.\n"); + printf("\n"); + printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); + printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); + printf("\n"); + printf("Usage: ./bench_internal [args]\n"); + printf("By default, all benchmarks will be run.\n"); + printf("args:\n"); + printf(" help : display this help and exit\n"); + printf(" scalar : all scalar operations (add, half, inverse, mul, negate, split)\n"); + printf(" field : all field operations (half, inverse, issquare, mul, normalize, sqr, sqrt)\n"); + printf(" group : all group operations (add, double, to_affine)\n"); + printf(" ecmult : all point multiplication operations (ecmult_wnaf) \n"); + printf(" hash : all hash algorithms (hmac, rng6979, sha256)\n"); + printf(" context : all context object operations (context_create)\n"); + printf("\n"); +} + +typedef struct { + secp256k1_scalar scalar[2]; + secp256k1_fe fe[4]; + secp256k1_ge ge[2]; + secp256k1_gej gej[2]; + unsigned char data[64]; + int wnaf[256]; +} bench_inv; + +static void bench_setup(void* arg) { + bench_inv *data = (bench_inv*)arg; + + static const unsigned char init[4][32] = { + /* Initializer for scalar[0], fe[0], first half of data, the X coordinate of ge[0], + and the (implied affine) X coordinate of gej[0]. */ + { + 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, + 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, + 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, + 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 + }, + /* Initializer for scalar[1], fe[1], first half of data, the X coordinate of ge[1], + and the (implied affine) X coordinate of gej[1]. */ + { + 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83, + 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5, + 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9, + 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3 + }, + /* Initializer for fe[2] and the Z coordinate of gej[0]. */ + { + 0x3d, 0x2d, 0xef, 0xf4, 0x25, 0x98, 0x4f, 0x5d, + 0xe2, 0xca, 0x5f, 0x41, 0x3f, 0x3f, 0xce, 0x44, + 0xaa, 0x2c, 0x53, 0x8a, 0xc6, 0x59, 0x1f, 0x38, + 0x38, 0x23, 0xe4, 0x11, 0x27, 0xc6, 0xa0, 0xe7 + }, + /* Initializer for fe[3] and the Z coordinate of gej[1]. */ + { + 0xbd, 0x21, 0xa5, 0xe1, 0x13, 0x50, 0x73, 0x2e, + 0x52, 0x98, 0xc8, 0x9e, 0xab, 0x00, 0xa2, 0x68, + 0x43, 0xf5, 0xd7, 0x49, 0x80, 0x72, 0xa7, 0xf3, + 0xd7, 0x60, 0xe6, 0xab, 0x90, 0x92, 0xdf, 0xc5 + } + }; + + secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL); + secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL); + secp256k1_fe_set_b32_limit(&data->fe[0], init[0]); + secp256k1_fe_set_b32_limit(&data->fe[1], init[1]); + secp256k1_fe_set_b32_limit(&data->fe[2], init[2]); + secp256k1_fe_set_b32_limit(&data->fe[3], init[3]); + CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0)); + CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1)); + secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]); + secp256k1_gej_rescale(&data->gej[0], &data->fe[2]); + secp256k1_gej_set_ge(&data->gej[1], &data->ge[1]); + secp256k1_gej_rescale(&data->gej[1], &data->fe[3]); + memcpy(data->data, init[0], 32); + memcpy(data->data + 32, init[1], 32); +} + +static void bench_scalar_add(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + } + CHECK(j <= iters); +} + +static void bench_scalar_negate(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_scalar_negate(&data->scalar[0], &data->scalar[0]); + } +} + +static void bench_scalar_half(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_scalar s = data->scalar[0]; + + for (i = 0; i < iters; i++) { + secp256k1_scalar_half(&s, &s); + } + + data->scalar[0] = s; +} + +static void bench_scalar_mul(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_scalar_mul(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + } +} + +static void bench_scalar_split(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + secp256k1_scalar tmp; + + for (i = 0; i < iters; i++) { + secp256k1_scalar_split_lambda(&tmp, &data->scalar[1], &data->scalar[0]); + j += secp256k1_scalar_add(&data->scalar[0], &tmp, &data->scalar[1]); + } + CHECK(j <= iters); +} + +static void bench_scalar_inverse(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_scalar_inverse(&data->scalar[0], &data->scalar[0]); + j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + } + CHECK(j <= iters); +} + +static void bench_scalar_inverse_var(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_scalar_inverse_var(&data->scalar[0], &data->scalar[0]); + j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + } + CHECK(j <= iters); +} + +static void bench_field_half(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_fe_half(&data->fe[0]); + } +} + +static void bench_field_normalize(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_fe_normalize(&data->fe[0]); + } +} + +static void bench_field_normalize_weak(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_fe_normalize_weak(&data->fe[0]); + } +} + +static void bench_field_mul(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_fe_mul(&data->fe[0], &data->fe[0], &data->fe[1]); + } +} + +static void bench_field_sqr(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_fe_sqr(&data->fe[0], &data->fe[0]); + } +} + +static void bench_field_inverse(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_fe_inv(&data->fe[0], &data->fe[0]); + secp256k1_fe_add(&data->fe[0], &data->fe[1]); + } +} + +static void bench_field_inverse_var(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_fe_inv_var(&data->fe[0], &data->fe[0]); + secp256k1_fe_add(&data->fe[0], &data->fe[1]); + } +} + +static void bench_field_sqrt(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + secp256k1_fe t; + + for (i = 0; i < iters; i++) { + t = data->fe[0]; + j += secp256k1_fe_sqrt(&data->fe[0], &t); + secp256k1_fe_add(&data->fe[0], &data->fe[1]); + } + CHECK(j <= iters); +} + +static void bench_field_is_square_var(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + secp256k1_fe t = data->fe[0]; + + for (i = 0; i < iters; i++) { + j += secp256k1_fe_is_square_var(&t); + secp256k1_fe_add(&t, &data->fe[1]); + secp256k1_fe_normalize_var(&t); + } + CHECK(j <= iters); +} + +static void bench_group_double_var(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_gej_double_var(&data->gej[0], &data->gej[0], NULL); + } +} + +static void bench_group_add_var(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_gej_add_var(&data->gej[0], &data->gej[0], &data->gej[1], NULL); + } +} + +static void bench_group_add_affine(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_gej_add_ge(&data->gej[0], &data->gej[0], &data->ge[1]); + } +} + +static void bench_group_add_affine_var(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_gej_add_ge_var(&data->gej[0], &data->gej[0], &data->ge[1], NULL); + } +} + +static void bench_group_add_zinv_var(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_gej_add_zinv_var(&data->gej[0], &data->gej[0], &data->ge[1], &data->gej[0].y); + } +} + +static void bench_group_to_affine_var(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; ++i) { + secp256k1_ge_set_gej_var(&data->ge[1], &data->gej[0]); + /* Use the output affine X/Y coordinates to vary the input X/Y/Z coordinates. + Note that the resulting coordinates will generally not correspond to a point + on the curve, but this is not a problem for the code being benchmarked here. + Adding and normalizing have less overhead than EC operations (which could + guarantee the point remains on the curve). */ + secp256k1_fe_add(&data->gej[0].x, &data->ge[1].y); + secp256k1_fe_add(&data->gej[0].y, &data->fe[2]); + secp256k1_fe_add(&data->gej[0].z, &data->ge[1].x); + secp256k1_fe_normalize_var(&data->gej[0].x); + secp256k1_fe_normalize_var(&data->gej[0].y); + secp256k1_fe_normalize_var(&data->gej[0].z); + } +} + +static void bench_ecmult_wnaf(void* arg, int iters) { + int i, bits = 0, overflow = 0; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + bits += secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar[0], WINDOW_A); + overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + } + CHECK(overflow >= 0); + CHECK(bits <= 256*iters); +} + +static void bench_sha256(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_sha256 sha; + + for (i = 0; i < iters; i++) { + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, data->data, 32); + secp256k1_sha256_finalize(&sha, data->data); + } +} + +static void bench_hmac_sha256(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_hmac_sha256 hmac; + + for (i = 0; i < iters; i++) { + secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); + secp256k1_hmac_sha256_write(&hmac, data->data, 32); + secp256k1_hmac_sha256_finalize(&hmac, data->data); + } +} + +static void bench_rfc6979_hmac_sha256(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_rfc6979_hmac_sha256 rng; + + for (i = 0; i < iters; i++) { + secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); + secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); + } +} + +static void bench_context(void* arg, int iters) { + int i; + (void)arg; + for (i = 0; i < iters; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_NONE)); + } +} + +int main(int argc, char **argv) { + bench_inv data; + int default_iters = 20000; + int iters = get_iters(default_iters); + int d = argc == 1; /* default */ + + if (argc > 1) { + if (have_flag(argc, argv, "-h") + || have_flag(argc, argv, "--help") + || have_flag(argc, argv, "help")) { + help(default_iters); + return 0; + } + } + + print_output_table_header_row(); + + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "half")) run_benchmark("scalar_half", bench_scalar_half, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "half")) run_benchmark("field_half", bench_field_half, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "issquare")) run_benchmark("field_is_square_var", bench_field_is_square_var, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_zinv_var", bench_group_add_zinv_var, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "context")) run_benchmark("context_create", bench_context, bench_setup, NULL, &data, 10, iters); + + return 0; +} diff --git a/external/secp256k1/src/checkmem.h b/external/secp256k1/src/checkmem.h new file mode 100644 index 00000000000..7e333ce5f3c --- /dev/null +++ b/external/secp256k1/src/checkmem.h @@ -0,0 +1,102 @@ +/*********************************************************************** + * Copyright (c) 2022 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +/* The code here is inspired by Kris Kwiatkowski's approach in + * https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h + * to provide a general interface for memory-checking mechanisms, primarily + * for constant-time checking. + */ + +/* These macros are defined by this header file: + * + * - SECP256K1_CHECKMEM_ENABLED: + * - 1 if memory-checking integration is available, 0 otherwise. + * This is just a compile-time macro. Use the next macro to check it is actually + * available at runtime. + * - SECP256K1_CHECKMEM_RUNNING(): + * - Acts like a function call, returning 1 if memory checking is available + * at runtime. + * - SECP256K1_CHECKMEM_CHECK(p, len): + * - Assert or otherwise fail in case the len-byte memory block pointed to by p is + * not considered entirely defined. + * - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len): + * - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode. + * - SECP256K1_CHECKMEM_UNDEFINE(p, len): + * - marks the len-byte memory block pointed to by p as undefined data (secret data, + * in the context of constant-time checking). + * - SECP256K1_CHECKMEM_DEFINE(p, len): + * - marks the len-byte memory pointed to by p as defined data (public data, in the + * context of constant-time checking). + * - SECP256K1_CHECKMEM_MSAN_DEFINE(p, len): + * - Like SECP256K1_CHECKMEM_DEFINE, but applies only to memory_sanitizer. + * + */ + +#ifndef SECP256K1_CHECKMEM_H +#define SECP256K1_CHECKMEM_H + +/* Define a statement-like macro that ignores the arguments. */ +#define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0) + +/* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan. + * Choose this preferentially, even when VALGRIND is defined, as msan-compiled + * binaries can't be run under valgrind anyway. */ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# define SECP256K1_CHECKMEM_ENABLED 1 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len)) +# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len)) +# define SECP256K1_CHECKMEM_RUNNING() (1) +# endif +#endif + +#if !defined SECP256K1_CHECKMEM_MSAN_DEFINE +# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +#endif + +/* If valgrind integration is desired (through the VALGRIND define), implement the + * SECP256K1_CHECKMEM_* macros using valgrind. */ +#if !defined SECP256K1_CHECKMEM_ENABLED +# if defined VALGRIND +# include +# if defined(__clang__) && defined(__APPLE__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wreserved-identifier" +# endif +# include +# if defined(__clang__) && defined(__APPLE__) +# pragma clang diagnostic pop +# endif +# define SECP256K1_CHECKMEM_ENABLED 1 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len)) + /* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck. + * This is more precise than the RUNNING_ON_VALGRIND macro, which + * checks for valgrind in general instead of memcheck specifically. */ +# define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0) +# endif +#endif + +/* As a fall-back, map these macros to dummy statements. */ +#if !defined SECP256K1_CHECKMEM_ENABLED +# define SECP256K1_CHECKMEM_ENABLED 0 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_RUNNING() (0) +#endif + +#if defined VERIFY +#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len)) +#else +#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +#endif + +#endif /* SECP256K1_CHECKMEM_H */ diff --git a/external/secp256k1/src/ctime_tests.c b/external/secp256k1/src/ctime_tests.c new file mode 100644 index 00000000000..bbde863d969 --- /dev/null +++ b/external/secp256k1/src/ctime_tests.c @@ -0,0 +1,266 @@ +/*********************************************************************** + * Copyright (c) 2020 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#include +#include + +#include "../include/secp256k1.h" +#include "assumptions.h" +#include "checkmem.h" + +#if !SECP256K1_CHECKMEM_ENABLED +# error "This tool cannot be compiled without memory-checking interface (valgrind or msan)" +#endif + +#ifdef ENABLE_MODULE_ECDH +# include "../include/secp256k1_ecdh.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "../include/secp256k1_recovery.h" +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "../include/secp256k1_extrakeys.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +#include "../include/secp256k1_schnorrsig.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +#include "../include/secp256k1_musig.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +#include "../include/secp256k1_ellswift.h" +#endif + +static void run_tests(secp256k1_context *ctx, unsigned char *key); + +int main(void) { + secp256k1_context* ctx; + unsigned char key[32]; + int ret, i; + + if (!SECP256K1_CHECKMEM_RUNNING()) { + fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n"); + fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n"); + return 1; + } + ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY); + /** In theory, testing with a single secret input should be sufficient: + * If control flow depended on secrets the tool would generate an error. + */ + for (i = 0; i < 32; i++) { + key[i] = i + 65; + } + + run_tests(ctx, key); + + /* Test context randomisation. Do this last because it leaves the context + * tainted. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_context_randomize(ctx, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + + secp256k1_context_destroy(ctx); + return 0; +} + +static void run_tests(secp256k1_context *ctx, unsigned char *key) { + secp256k1_ecdsa_signature signature; + secp256k1_pubkey pubkey; + size_t siglen = 74; + size_t outputlen = 33; + int i; + int ret; + unsigned char msg[32]; + unsigned char sig[74]; + unsigned char spubkey[33]; +#ifdef ENABLE_MODULE_RECOVERY + secp256k1_ecdsa_recoverable_signature recoverable_signature; + int recid; +#endif +#ifdef ENABLE_MODULE_EXTRAKEYS + secp256k1_keypair keypair; +#endif +#ifdef ENABLE_MODULE_ELLSWIFT + unsigned char ellswift[64]; + static const unsigned char prefix[64] = {'t', 'e', 's', 't'}; +#endif + + for (i = 0; i < 32; i++) { + msg[i] = i + 1; + } + + /* Test keygen. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key); + SECP256K1_CHECKMEM_DEFINE(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + + /* Test signing. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL); + SECP256K1_CHECKMEM_DEFINE(&signature, sizeof(secp256k1_ecdsa_signature)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); + +#ifdef ENABLE_MODULE_ECDH + /* Test ECDH. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + /* Test signing a recoverable signature. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); + SECP256K1_CHECKMEM_DEFINE(&recoverable_signature, sizeof(recoverable_signature)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature)); + CHECK(recid >= 0 && recid <= 3); +#endif + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ec_seckey_verify(ctx, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ec_seckey_negate(ctx, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(msg, 32); + ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(msg, 32); + ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + /* Test keypair_create and keypair_xonly_tweak_add. */ +#ifdef ENABLE_MODULE_EXTRAKEYS + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_keypair_create(ctx, &keypair, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + /* The tweak is not treated as a secret in keypair_tweak_add */ + SECP256K1_CHECKMEM_DEFINE(msg, 32); + ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(&keypair, sizeof(keypair)); + ret = secp256k1_keypair_sec(ctx, key, &keypair); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_keypair_create(ctx, &keypair, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); +#endif + +#ifdef ENABLE_MODULE_MUSIG + { + secp256k1_pubkey pk; + const secp256k1_pubkey *pk_ptr[1]; + secp256k1_xonly_pubkey agg_pk; + unsigned char session_secrand[32]; + uint64_t nonrepeating_cnt = 0; + secp256k1_musig_secnonce secnonce; + secp256k1_musig_pubnonce pubnonce; + const secp256k1_musig_pubnonce *pubnonce_ptr[1]; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_keyagg_cache cache; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + unsigned char extra_input[32]; + + pk_ptr[0] = &pk; + pubnonce_ptr[0] = &pubnonce; + SECP256K1_CHECKMEM_DEFINE(key, 32); + memcpy(session_secrand, key, sizeof(session_secrand)); + session_secrand[0] = session_secrand[0] + 1; + memcpy(extra_input, key, sizeof(extra_input)); + extra_input[0] = extra_input[0] + 2; + + CHECK(secp256k1_keypair_create(ctx, &keypair, key)); + CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair)); + CHECK(secp256k1_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1)); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand)); + SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input)); + ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, msg, &cache, extra_input); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1)); + /* Make sure that previous tests don't undefine msg. It's not used as a secret here. */ + SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg)); + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache) == 1); + + ret = secp256k1_keypair_create(ctx, &keypair, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + } +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + for (i = 0; i < 2; i++) { + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); + ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); + ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + } + +#endif +} diff --git a/external/secp256k1/src/ecdsa.h b/external/secp256k1/src/ecdsa.h new file mode 100644 index 00000000000..4441b083984 --- /dev/null +++ b/external/secp256k1/src/ecdsa.h @@ -0,0 +1,21 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECDSA_H +#define SECP256K1_ECDSA_H + +#include + +#include "scalar.h" +#include "group.h" +#include "ecmult.h" + +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size); +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s); +static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid); + +#endif /* SECP256K1_ECDSA_H */ diff --git a/external/secp256k1/src/ecdsa_impl.h b/external/secp256k1/src/ecdsa_impl.h new file mode 100644 index 00000000000..ce36e85e6a0 --- /dev/null +++ b/external/secp256k1/src/ecdsa_impl.h @@ -0,0 +1,304 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + + +#ifndef SECP256K1_ECDSA_IMPL_H +#define SECP256K1_ECDSA_IMPL_H + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult.h" +#include "ecmult_gen.h" +#include "ecdsa.h" + +/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1 + * $ sage -c 'load("secp256k1_params.sage"); print(hex(N))' + * 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 + */ +static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL +); + +/** Difference between field and order, values 'p' and 'n' values defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + * $ sage -c 'load("secp256k1_params.sage"); print(hex(P-N))' + * 0x14551231950b75fc4402da1722fc9baee + */ +static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( + 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL +); + +static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) { + size_t lenleft; + unsigned char b1; + VERIFY_CHECK(len != NULL); + *len = 0; + if (*sigp >= sigend) { + return 0; + } + b1 = *((*sigp)++); + if (b1 == 0xFF) { + /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ + return 0; + } + if ((b1 & 0x80) == 0) { + /* X.690-0207 8.1.3.4 short form length octets */ + *len = b1; + return 1; + } + if (b1 == 0x80) { + /* Indefinite length is not allowed in DER. */ + return 0; + } + /* X.690-207 8.1.3.5 long form length octets */ + lenleft = b1 & 0x7F; /* lenleft is at least 1 */ + if (lenleft > (size_t)(sigend - *sigp)) { + return 0; + } + if (**sigp == 0) { + /* Not the shortest possible length encoding. */ + return 0; + } + if (lenleft > sizeof(size_t)) { + /* The resulting length would exceed the range of a size_t, so + * it is certainly longer than the passed array size. */ + return 0; + } + while (lenleft > 0) { + *len = (*len << 8) | **sigp; + (*sigp)++; + lenleft--; + } + if (*len > (size_t)(sigend - *sigp)) { + /* Result exceeds the length of the passed array. + (Checking this is the responsibility of the caller but it + can't hurt do it here, too.) */ + return 0; + } + if (*len < 128) { + /* Not the shortest possible length encoding. */ + return 0; + } + return 1; +} + +static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { + int overflow = 0; + unsigned char ra[32] = {0}; + size_t rlen; + + if (*sig == sigend || **sig != 0x02) { + /* Not a primitive integer (X.690-0207 8.3.1). */ + return 0; + } + (*sig)++; + if (secp256k1_der_read_len(&rlen, sig, sigend) == 0) { + return 0; + } + if (rlen == 0 || rlen > (size_t)(sigend - *sig)) { + /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ + return 0; + } + if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { + /* Excessive 0x00 padding. */ + return 0; + } + if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { + /* Excessive 0xFF padding. */ + return 0; + } + if ((**sig & 0x80) == 0x80) { + /* Negative. */ + overflow = 1; + } + /* There is at most one leading zero byte: + * if there were two leading zero bytes, we would have failed and returned 0 + * because of excessive 0x00 padding already. */ + if (rlen > 0 && **sig == 0) { + /* Skip leading zero byte */ + rlen--; + (*sig)++; + } + if (rlen > 32) { + overflow = 1; + } + if (!overflow) { + if (rlen) memcpy(ra + 32 - rlen, *sig, rlen); + secp256k1_scalar_set_b32(r, ra, &overflow); + } + if (overflow) { + secp256k1_scalar_set_int(r, 0); + } + (*sig) += rlen; + return 1; +} + +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { + const unsigned char *sigend = sig + size; + size_t rlen; + if (sig == sigend || *(sig++) != 0x30) { + /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ + return 0; + } + if (secp256k1_der_read_len(&rlen, &sig, sigend) == 0) { + return 0; + } + if (rlen != (size_t)(sigend - sig)) { + /* Tuple exceeds bounds or garage after tuple. */ + return 0; + } + + if (!secp256k1_der_parse_integer(rr, &sig, sigend)) { + return 0; + } + if (!secp256k1_der_parse_integer(rs, &sig, sigend)) { + return 0; + } + + if (sig != sigend) { + /* Trailing garbage inside tuple. */ + return 0; + } + + return 1; +} + +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) { + unsigned char r[33] = {0}, s[33] = {0}; + unsigned char *rp = r, *sp = s; + size_t lenR = 33, lenS = 33; + secp256k1_scalar_get_b32(&r[1], ar); + secp256k1_scalar_get_b32(&s[1], as); + while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } + while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } + if (*size < 6+lenS+lenR) { + *size = 6 + lenS + lenR; + return 0; + } + *size = 6 + lenS + lenR; + sig[0] = 0x30; + sig[1] = 4 + lenS + lenR; + sig[2] = 0x02; + sig[3] = lenR; + memcpy(sig+4, rp, lenR); + sig[4+lenR] = 0x02; + sig[5+lenR] = lenS; + memcpy(sig+lenR+6, sp, lenS); + return 1; +} + +static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { + unsigned char c[32]; + secp256k1_scalar sn, u1, u2; +#if !defined(EXHAUSTIVE_TEST_ORDER) + secp256k1_fe xr; +#endif + secp256k1_gej pubkeyj; + secp256k1_gej pr; + + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_scalar_inverse_var(&sn, sigs); + secp256k1_scalar_mul(&u1, &sn, message); + secp256k1_scalar_mul(&u2, &sn, sigr); + secp256k1_gej_set_ge(&pubkeyj, pubkey); + secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1); + if (secp256k1_gej_is_infinity(&pr)) { + return 0; + } + +#if defined(EXHAUSTIVE_TEST_ORDER) +{ + secp256k1_scalar computed_r; + secp256k1_ge pr_ge; + secp256k1_ge_set_gej(&pr_ge, &pr); + secp256k1_fe_normalize(&pr_ge.x); + + secp256k1_fe_get_b32(c, &pr_ge.x); + secp256k1_scalar_set_b32(&computed_r, c, NULL); + return secp256k1_scalar_eq(sigr, &computed_r); +} +#else + secp256k1_scalar_get_b32(c, sigr); + /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */ + (void)secp256k1_fe_set_b32_limit(&xr, c); + + /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) + * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), + * compute the remainder modulo n, and compare it to xr. However: + * + * xr == X(pr) mod n + * <=> exists h. (xr + h * n < p && xr + h * n == X(pr)) + * [Since 2 * n > p, h can only be 0 or 1] + * <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr)) + * [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p] + * <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p) + * [Multiplying both sides of the equations by pr.z^2 mod p] + * <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x) + * + * Thus, we can avoid the inversion, but we have to check both cases separately. + * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. + */ + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ + return 1; + } + if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + /* xr + n >= p, so we can skip testing the second case. */ + return 0; + } + secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */ + return 1; + } + return 0; +#endif +} + +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { + unsigned char b[32]; + secp256k1_gej rp; + secp256k1_ge r; + secp256k1_scalar n; + int overflow = 0; + int high; + + secp256k1_ecmult_gen(ctx, &rp, nonce); + secp256k1_ge_set_gej(&r, &rp); + secp256k1_fe_normalize(&r.x); + secp256k1_fe_normalize(&r.y); + secp256k1_fe_get_b32(b, &r.x); + secp256k1_scalar_set_b32(sigr, b, &overflow); + if (recid) { + /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log + * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. + */ + *recid = (overflow << 1) | secp256k1_fe_is_odd(&r.y); + } + secp256k1_scalar_mul(&n, sigr, seckey); + secp256k1_scalar_add(&n, &n, message); + secp256k1_scalar_inverse(sigs, nonce); + secp256k1_scalar_mul(sigs, sigs, &n); + secp256k1_scalar_clear(&n); + secp256k1_gej_clear(&rp); + secp256k1_ge_clear(&r); + high = secp256k1_scalar_is_high(sigs); + secp256k1_scalar_cond_negate(sigs, high); + if (recid) { + *recid ^= high; + } + /* P.x = order is on the curve, so technically sig->r could end up being zero, which would be an invalid signature. + * This is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N. + */ + return (int)(!secp256k1_scalar_is_zero(sigr)) & (int)(!secp256k1_scalar_is_zero(sigs)); +} + +#endif /* SECP256K1_ECDSA_IMPL_H */ diff --git a/external/secp256k1/src/eckey.h b/external/secp256k1/src/eckey.h new file mode 100644 index 00000000000..d54d44c997b --- /dev/null +++ b/external/secp256k1/src/eckey.h @@ -0,0 +1,25 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECKEY_H +#define SECP256K1_ECKEY_H + +#include + +#include "group.h" +#include "scalar.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); + +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak); + +#endif /* SECP256K1_ECKEY_H */ diff --git a/external/secp256k1/src/eckey_impl.h b/external/secp256k1/src/eckey_impl.h new file mode 100644 index 00000000000..121966f8b5f --- /dev/null +++ b/external/secp256k1/src/eckey_impl.h @@ -0,0 +1,92 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECKEY_IMPL_H +#define SECP256K1_ECKEY_IMPL_H + +#include "eckey.h" + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult_gen.h" + +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { + if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { + secp256k1_fe x; + return secp256k1_fe_set_b32_limit(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); + } else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { + secp256k1_fe x, y; + if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) { + return 0; + } + secp256k1_ge_set_xy(elem, &x, &y); + if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && + secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { + return 0; + } + return secp256k1_ge_is_valid_var(elem); + } else { + return 0; + } +} + +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { + if (secp256k1_ge_is_infinity(elem)) { + return 0; + } + secp256k1_fe_normalize_var(&elem->x); + secp256k1_fe_normalize_var(&elem->y); + secp256k1_fe_get_b32(&pub[1], &elem->x); + if (compressed) { + *size = 33; + pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; + } else { + *size = 65; + pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; + secp256k1_fe_get_b32(&pub[33], &elem->y); + } + return 1; +} + +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { + secp256k1_scalar_add(key, key, tweak); + return !secp256k1_scalar_is_zero(key); +} + +static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_gej pt; + secp256k1_gej_set_ge(&pt, key); + secp256k1_ecmult(&pt, &pt, &secp256k1_scalar_one, tweak); + + if (secp256k1_gej_is_infinity(&pt)) { + return 0; + } + secp256k1_ge_set_gej(key, &pt); + return 1; +} + +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) { + int ret; + ret = !secp256k1_scalar_is_zero(tweak); + + secp256k1_scalar_mul(key, key, tweak); + return ret; +} + +static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_gej pt; + if (secp256k1_scalar_is_zero(tweak)) { + return 0; + } + + secp256k1_gej_set_ge(&pt, key); + secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero); + secp256k1_ge_set_gej(key, &pt); + return 1; +} + +#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/external/secp256k1/src/ecmult.h b/external/secp256k1/src/ecmult.h new file mode 100644 index 00000000000..326a5eeb434 --- /dev/null +++ b/external/secp256k1/src/ecmult.h @@ -0,0 +1,61 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_H +#define SECP256K1_ECMULT_H + +#include "group.h" +#include "scalar.h" +#include "scratch.h" + +#ifndef ECMULT_WINDOW_SIZE +# define ECMULT_WINDOW_SIZE 15 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value") +# endif +#endif + +#ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE) +#endif + +/* No one will ever need more than a window size of 24. The code might + * be correct for larger values of ECMULT_WINDOW_SIZE but this is not + * tested. + * + * The following limitations are known, and there are probably more: + * If WINDOW_G > 27 and size_t has 32 bits, then the code is incorrect + * because the size of the memory object that we allocate (in bytes) + * will not fit in a size_t. + * If WINDOW_G > 31 and int has 32 bits, then the code is incorrect + * because certain expressions will overflow. + */ +#if ECMULT_WINDOW_SIZE < 2 || ECMULT_WINDOW_SIZE > 24 +# error Set ECMULT_WINDOW_SIZE to an integer in range [2..24]. +#endif + +/** The number of entries a table with precomputed multiples needs to have. */ +#define ECMULT_TABLE_SIZE(w) (1L << ((w)-2)) + +/** Double multiply: R = na*A + ng*G */ +static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); + +typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data); + +/** + * Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai. + * Chooses the right algorithm for a given number of points and scratch space + * size. Resets and overwrites the given scratch space. If the points do not + * fit in the scratch space the algorithm is repeatedly run with batches of + * points. If no scratch space is given then a simple algorithm is used that + * simply multiplies the points with the corresponding scalars and adds them up. + * Returns: 1 on success (including when inp_g_sc is NULL and n is 0) + * 0 if there is not enough scratch space for a single point or + * callback returns 0 + */ +static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n); + +#endif /* SECP256K1_ECMULT_H */ diff --git a/external/secp256k1/src/ecmult_compute_table.h b/external/secp256k1/src/ecmult_compute_table.h new file mode 100644 index 00000000000..665f87ff3d5 --- /dev/null +++ b/external/secp256k1/src/ecmult_compute_table.h @@ -0,0 +1,16 @@ +/***************************************************************************************************** + * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************************************/ + +#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_H +#define SECP256K1_ECMULT_COMPUTE_TABLE_H + +/* Construct table of all odd multiples of gen in range 1..(2**(window_g-1)-1). */ +static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen); + +/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */ +static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen); + +#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_H */ diff --git a/external/secp256k1/src/ecmult_compute_table_impl.h b/external/secp256k1/src/ecmult_compute_table_impl.h new file mode 100644 index 00000000000..69d59ce5956 --- /dev/null +++ b/external/secp256k1/src/ecmult_compute_table_impl.h @@ -0,0 +1,49 @@ +/***************************************************************************************************** + * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************************************/ + +#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H +#define SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H + +#include "ecmult_compute_table.h" +#include "group_impl.h" +#include "field_impl.h" +#include "ecmult.h" +#include "util.h" + +static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen) { + secp256k1_gej gj; + secp256k1_ge ge, dgen; + int j; + + gj = *gen; + secp256k1_ge_set_gej_var(&ge, &gj); + secp256k1_ge_to_storage(&table[0], &ge); + + secp256k1_gej_double_var(&gj, gen, NULL); + secp256k1_ge_set_gej_var(&dgen, &gj); + + for (j = 1; j < ECMULT_TABLE_SIZE(window_g); ++j) { + secp256k1_gej_set_ge(&gj, &ge); + secp256k1_gej_add_ge_var(&gj, &gj, &dgen, NULL); + secp256k1_ge_set_gej_var(&ge, &gj); + secp256k1_ge_to_storage(&table[j], &ge); + } +} + +/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */ +static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen) { + secp256k1_gej gj; + int i; + + secp256k1_gej_set_ge(&gj, gen); + secp256k1_ecmult_compute_table(table, window_g, &gj); + for (i = 0; i < 128; ++i) { + secp256k1_gej_double_var(&gj, &gj, NULL); + } + secp256k1_ecmult_compute_table(table_128, window_g, &gj); +} + +#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H */ diff --git a/external/secp256k1/src/ecmult_const.h b/external/secp256k1/src/ecmult_const.h new file mode 100644 index 00000000000..080e04bc882 --- /dev/null +++ b/external/secp256k1/src/ecmult_const.h @@ -0,0 +1,38 @@ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_H +#define SECP256K1_ECMULT_CONST_H + +#include "scalar.h" +#include "group.h" + +/** + * Multiply: R = q*A (in constant-time for q) + */ +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); + +/** + * Same as secp256k1_ecmult_const, but takes in an x coordinate of the base point + * only, specified as fraction n/d (numerator/denominator). Only the x coordinate of the result is + * returned. + * + * If known_on_curve is 0, a verification is performed that n/d is a valid X + * coordinate, and 0 is returned if not. Otherwise, 1 is returned. + * + * d being NULL is interpreted as d=1. If non-NULL, d must not be zero. q must not be zero. + * + * Constant time in the value of q, but not any other inputs. + */ +static int secp256k1_ecmult_const_xonly( + secp256k1_fe *r, + const secp256k1_fe *n, + const secp256k1_fe *d, + const secp256k1_scalar *q, + int known_on_curve +); + +#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/external/secp256k1/src/ecmult_const_impl.h b/external/secp256k1/src/ecmult_const_impl.h new file mode 100644 index 00000000000..0d78f7c3ce3 --- /dev/null +++ b/external/secp256k1/src/ecmult_const_impl.h @@ -0,0 +1,399 @@ +/*********************************************************************** + * Copyright (c) 2015, 2022 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_IMPL_H +#define SECP256K1_ECMULT_CONST_IMPL_H + +#include "scalar.h" +#include "group.h" +#include "ecmult_const.h" +#include "ecmult_impl.h" + +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need 2^ECMULT_CONST_GROUP_SIZE - 1 to be less than EXHAUSTIVE_TEST_ORDER, because + * the tables cannot have infinities in them (this breaks the effective-affine technique's + * z-ratio tracking) */ +# if EXHAUSTIVE_TEST_ORDER == 199 +# define ECMULT_CONST_GROUP_SIZE 4 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define ECMULT_CONST_GROUP_SIZE 3 +# elif EXHAUSTIVE_TEST_ORDER == 7 +# define ECMULT_CONST_GROUP_SIZE 2 +# else +# error "Unknown EXHAUSTIVE_TEST_ORDER" +# endif +#else +/* Group size 4 or 5 appears optimal. */ +# define ECMULT_CONST_GROUP_SIZE 5 +#endif + +#define ECMULT_CONST_TABLE_SIZE (1L << (ECMULT_CONST_GROUP_SIZE - 1)) +#define ECMULT_CONST_GROUPS ((129 + ECMULT_CONST_GROUP_SIZE - 1) / ECMULT_CONST_GROUP_SIZE) +#define ECMULT_CONST_BITS (ECMULT_CONST_GROUPS * ECMULT_CONST_GROUP_SIZE) + +/** Fill a table 'pre' with precomputed odd multiples of a. + * + * The resulting point set is brought to a single constant Z denominator, stores the X and Y + * coordinates as ge points in pre, and stores the global Z in globalz. + * + * 'pre' must be an array of size ECMULT_CONST_TABLE_SIZE. + */ +static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { + secp256k1_fe zr[ECMULT_CONST_TABLE_SIZE]; + + secp256k1_ecmult_odd_multiples_table(ECMULT_CONST_TABLE_SIZE, pre, zr, globalz, a); + secp256k1_ge_table_set_globalz(ECMULT_CONST_TABLE_SIZE, pre, zr); +} + +/* Given a table 'pre' with odd multiples of a point, put in r the signed-bit multiplication of n with that point. + * + * For example, if ECMULT_CONST_GROUP_SIZE is 4, then pre is expected to contain 8 entries: + * [1*P, 3*P, 5*P, 7*P, 9*P, 11*P, 13*P, 15*P]. n is then expected to be a 4-bit integer (range 0-15), and its + * bits are interpreted as signs of powers of two to look up. + * + * For example, if n=4, which is 0100 in binary, which is interpreted as [- + - -], so the looked up value is + * [ -(2^3) + (2^2) - (2^1) - (2^0) ]*P = -7*P. Every valid n translates to an odd number in range [-15,15], + * which means we just need to look up one of the precomputed values, and optionally negate it. + */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n) do { \ + unsigned int m = 0; \ + /* If the top bit of n is 0, we want the negation. */ \ + volatile unsigned int negative = ((n) >> (ECMULT_CONST_GROUP_SIZE - 1)) ^ 1; \ + /* Let n[i] be the i-th bit of n, then the index is + * sum(cnot(n[i]) * 2^i, i=0..l-2) + * where cnot(b) = b if n[l-1] = 1 and 1 - b otherwise. + * For example, if n = 4, in binary 0100, the index is 3, in binary 011. + * + * Proof: + * Let + * x = sum((2*n[i] - 1)*2^i, i=0..l-1) + * = 2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 1 + * be the value represented by n. + * The index is (x - 1)/2 if x > 0 and -(x + 1)/2 otherwise. + * Case x > 0: + * n[l-1] = 1 + * index = sum(n[i] * 2^i, i=0..l-1) - 2^(l-1) + * = sum(n[i] * 2^i, i=0..l-2) + * Case x <= 0: + * n[l-1] = 0 + * index = -(2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 2)/2 + * = 2^(l-1) - 1 - sum(n[i] * 2^i, i=0..l-1) + * = sum((1 - n[i]) * 2^i, i=0..l-2) + */ \ + unsigned int index = ((unsigned int)(-negative) ^ n) & ((1U << (ECMULT_CONST_GROUP_SIZE - 1)) - 1U); \ + secp256k1_fe neg_y; \ + VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \ + VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \ + /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one + * or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \ + (r)->x = (pre)[m].x; \ + (r)->y = (pre)[m].y; \ + for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \ + /* This loop is used to avoid secret data in array indices. See + * the comment in ecmult_gen_impl.h for rationale. */ \ + secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \ + secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \ + } \ + (r)->infinity = 0; \ + secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ + secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \ +} while(0) + +/* For K as defined in the comment of secp256k1_ecmult_const, we have several precomputed + * formulas/constants. + * - in exhaustive test mode, we give an explicit expression to compute it at compile time: */ +#ifdef EXHAUSTIVE_TEST_ORDER +static const secp256k1_scalar secp256k1_ecmult_const_K = ((SECP256K1_SCALAR_CONST(0, 0, 0, (1U << (ECMULT_CONST_BITS - 128)) - 2U, 0, 0, 0, 0) + EXHAUSTIVE_TEST_ORDER - 1U) * (1U + EXHAUSTIVE_TEST_LAMBDA)) % EXHAUSTIVE_TEST_ORDER; +/* - for the real secp256k1 group we have constants for various ECMULT_CONST_BITS values. */ +#elif ECMULT_CONST_BITS == 129 +/* For GROUP_SIZE = 1,3. */ +static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xac9c52b3ul, 0x3fa3cf1ful, 0x5ad9e3fdul, 0x77ed9ba4ul, 0xa880b9fcul, 0x8ec739c2ul, 0xe0cfc810ul, 0xb51283ceul); +#elif ECMULT_CONST_BITS == 130 +/* For GROUP_SIZE = 2,5. */ +static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xa4e88a7dul, 0xcb13034eul, 0xc2bdd6bful, 0x7c118d6bul, 0x589ae848ul, 0x26ba29e4ul, 0xb5c2c1dcul, 0xde9798d9ul); +#elif ECMULT_CONST_BITS == 132 +/* For GROUP_SIZE = 4,6 */ +static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0x76b1d93dul, 0x0fae3c6bul, 0x3215874bul, 0x94e93813ul, 0x7937fe0dul, 0xb66bcaaful, 0xb3749ca5ul, 0xd7b6171bul); +#else +# error "Unknown ECMULT_CONST_BITS" +#endif + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q) { + /* The approach below combines the signed-digit logic from Mike Hamburg's + * "Fast and compact elliptic-curve cryptography" (https://eprint.iacr.org/2012/309) + * Section 3.3, with the GLV endomorphism. + * + * The idea there is to interpret the bits of a scalar as signs (1 = +, 0 = -), and compute a + * point multiplication in that fashion. Let v be an n-bit non-negative integer (0 <= v < 2^n), + * and v[i] its i'th bit (so v = sum(v[i] * 2^i, i=0..n-1)). Then define: + * + * C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) + * + * Then it holds that C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) + * = (2*sum(v[i] * 2^i, i=0..l-1) + 1 - 2^l) * A + * = (2*v + 1 - 2^l) * A + * + * Thus, one can compute q*A as C_256((q + 2^256 - 1) / 2, A). This is the basis for the + * paper's signed-digit multi-comb algorithm for multiplication using a precomputed table. + * + * It is appealing to try to combine this with the GLV optimization: the idea that a scalar + * s can be written as s1 + lambda*s2, where lambda is a curve-specific constant such that + * lambda*A is easy to compute, and where s1 and s2 are small. In particular we have the + * secp256k1_scalar_split_lambda function which performs such a split with the resulting s1 + * and s2 in range (-2^128, 2^128) mod n. This does work, but is uninteresting: + * + * To compute q*A: + * - Let s1, s2 = split_lambda(q) + * - Let R1 = C_256((s1 + 2^256 - 1) / 2, A) + * - Let R2 = C_256((s2 + 2^256 - 1) / 2, lambda*A) + * - Return R1 + R2 + * + * The issue is that while s1 and s2 are small-range numbers, (s1 + 2^256 - 1) / 2 (mod n) + * and (s2 + 2^256 - 1) / 2 (mod n) are not, undoing the benefit of the splitting. + * + * To make it work, we want to modify the input scalar q first, before splitting, and then only + * add a 2^128 offset of the split results (so that they end up in the single 129-bit range + * [0,2^129]). A slightly smaller offset would work due to the bounds on the split, but we pick + * 2^128 for simplicity. Let s be the scalar fed to split_lambda, and f(q) the function to + * compute it from q: + * + * To compute q*A: + * - Compute s = f(q) + * - Let s1, s2 = split_lambda(s) + * - Let v1 = s1 + 2^128 (mod n) + * - Let v2 = s2 + 2^128 (mod n) + * - Let R1 = C_l(v1, A) + * - Let R2 = C_l(v2, lambda*A) + * - Return R1 + R2 + * + * l will thus need to be at least 129, but we may overshoot by a few bits (see + * further), so keep it as a variable. + * + * To solve for s, we reason: + * q*A = R1 + R2 + * <=> q*A = C_l(s1 + 2^128, A) + C_l(s2 + 2^128, lambda*A) + * <=> q*A = (2*(s1 + 2^128) + 1 - 2^l) * A + (2*(s2 + 2^128) + 1 - 2^l) * lambda*A + * <=> q*A = (2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda)) * A + * <=> q = 2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) + * <=> q = 2*s + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) + * <=> s = (q + (2^l - 2^129 - 1) * (1 + lambda)) / 2 (mod n) + * <=> f(q) = (q + K) / 2 (mod n) + * where K = (2^l - 2^129 - 1)*(1 + lambda) (mod n) + * + * We will process the computation of C_l(v1, A) and C_l(v2, lambda*A) in groups of + * ECMULT_CONST_GROUP_SIZE, so we set l to the smallest multiple of ECMULT_CONST_GROUP_SIZE + * that is not less than 129; this equals ECMULT_CONST_BITS. + */ + + /* The offset to add to s1 and s2 to make them non-negative. Equal to 2^128. */ + static const secp256k1_scalar S_OFFSET = SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0); + secp256k1_scalar s, v1, v2; + secp256k1_ge pre_a[ECMULT_CONST_TABLE_SIZE]; + secp256k1_ge pre_a_lam[ECMULT_CONST_TABLE_SIZE]; + secp256k1_fe global_z; + int group, i; + + /* We're allowed to be non-constant time in the point, and the code below (in particular, + * secp256k1_ecmult_const_odd_multiples_table_globalz) cannot deal with infinity in a + * constant-time manner anyway. */ + if (secp256k1_ge_is_infinity(a)) { + secp256k1_gej_set_infinity(r); + return; + } + + /* Compute v1 and v2. */ + secp256k1_scalar_add(&s, q, &secp256k1_ecmult_const_K); + secp256k1_scalar_half(&s, &s); + secp256k1_scalar_split_lambda(&v1, &v2, &s); + secp256k1_scalar_add(&v1, &v1, &S_OFFSET); + secp256k1_scalar_add(&v2, &v2, &S_OFFSET); + +#ifdef VERIFY + /* Verify that v1 and v2 are in range [0, 2^129-1]. */ + for (i = 129; i < 256; ++i) { + VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v1, i, 1) == 0); + VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v2, i, 1) == 0); + } +#endif + + /* Calculate odd multiples of A and A*lambda. + * All multiples are brought to the same Z 'denominator', which is stored + * in global_z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + */ + secp256k1_gej_set_ge(r, a); + secp256k1_ecmult_const_odd_multiples_table_globalz(pre_a, &global_z, r); + for (i = 0; i < ECMULT_CONST_TABLE_SIZE; i++) { + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } + + /* Next, we compute r = C_l(v1, A) + C_l(v2, lambda*A). + * + * We proceed in groups of ECMULT_CONST_GROUP_SIZE bits, operating on that many bits + * at a time, from high in v1, v2 to low. Call these bits1 (from v1) and bits2 (from v2). + * + * Now note that ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1) loads into t a point equal + * to C_{ECMULT_CONST_GROUP_SIZE}(bits1, A), and analogously for pre_lam_a / bits2. + * This means that all we need to do is add these looked up values together, multiplied + * by 2^(ECMULT_GROUP_SIZE * group). + */ + for (group = ECMULT_CONST_GROUPS - 1; group >= 0; --group) { + /* Using the _var get_bits function is ok here, since it's only variable in offset and count, not in the scalar. */ + unsigned int bits1 = secp256k1_scalar_get_bits_var(&v1, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); + unsigned int bits2 = secp256k1_scalar_get_bits_var(&v2, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); + secp256k1_ge t; + int j; + + ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1); + if (group == ECMULT_CONST_GROUPS - 1) { + /* Directly set r in the first iteration. */ + secp256k1_gej_set_ge(r, &t); + } else { + /* Shift the result so far up. */ + for (j = 0; j < ECMULT_CONST_GROUP_SIZE; ++j) { + secp256k1_gej_double(r, r); + } + secp256k1_gej_add_ge(r, r, &t); + } + ECMULT_CONST_TABLE_GET_GE(&t, pre_a_lam, bits2); + secp256k1_gej_add_ge(r, r, &t); + } + + /* Map the result back to the secp256k1 curve from the isomorphic curve. */ + secp256k1_fe_mul(&r->z, &r->z, &global_z); +} + +static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) { + + /* This algorithm is a generalization of Peter Dettman's technique for + * avoiding the square root in a random-basepoint x-only multiplication + * on a Weierstrass curve: + * https://mailarchive.ietf.org/arch/msg/cfrg/7DyYY6gg32wDgHAhgSb6XxMDlJA/ + * + * + * === Background: the effective affine technique === + * + * Let phi_u be the isomorphism that maps (x, y) on secp256k1 curve y^2 = x^3 + 7 to + * x' = u^2*x, y' = u^3*y on curve y'^2 = x'^3 + u^6*7. This new curve has the same order as + * the original (it is isomorphic), but moreover, has the same addition/doubling formulas, as + * the curve b=7 coefficient does not appear in those formulas (or at least does not appear in + * the formulas implemented in this codebase, both affine and Jacobian). See also Example 9.5.2 + * in https://www.math.auckland.ac.nz/~sgal018/crypto-book/ch9.pdf. + * + * This means any linear combination of secp256k1 points can be computed by applying phi_u + * (with non-zero u) on all input points (including the generator, if used), computing the + * linear combination on the isomorphic curve (using the same group laws), and then applying + * phi_u^{-1} to get back to secp256k1. + * + * Switching to Jacobian coordinates, note that phi_u applied to (X, Y, Z) is simply + * (X, Y, Z/u). Thus, if we want to compute (X1, Y1, Z) + (X2, Y2, Z), with identical Z + * coordinates, we can use phi_Z to transform it to (X1, Y1, 1) + (X2, Y2, 1) on an isomorphic + * curve where the affine addition formula can be used instead. + * If (X3, Y3, Z3) = (X1, Y1) + (X2, Y2) on that curve, then our answer on secp256k1 is + * (X3, Y3, Z3*Z). + * + * This is the effective affine technique: if we have a linear combination of group elements + * to compute, and all those group elements have the same Z coordinate, we can simply pretend + * that all those Z coordinates are 1, perform the computation that way, and then multiply the + * original Z coordinate back in. + * + * The technique works on any a=0 short Weierstrass curve. It is possible to generalize it to + * other curves too, but there the isomorphic curves will have different 'a' coefficients, + * which typically does affect the group laws. + * + * + * === Avoiding the square root for x-only point multiplication === + * + * In this function, we want to compute the X coordinate of q*(n/d, y), for + * y = sqrt((n/d)^3 + 7). Its negation would also be a valid Y coordinate, but by convention + * we pick whatever sqrt returns (which we assume to be a deterministic function). + * + * Let g = y^2*d^3 = n^3 + 7*d^3. This also means y = sqrt(g/d^3). + * Further let v = sqrt(d*g), which must exist as d*g = y^2*d^4 = (y*d^2)^2. + * + * The input point (n/d, y) also has Jacobian coordinates: + * + * (n/d, y, 1) + * = (n/d * v^2, y * v^3, v) + * = (n/d * d*g, y * sqrt(d^3*g^3), v) + * = (n/d * d*g, sqrt(y^2 * d^3*g^3), v) + * = (n*g, sqrt(g/d^3 * d^3*g^3), v) + * = (n*g, sqrt(g^4), v) + * = (n*g, g^2, v) + * + * It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X + * coordinate n/d, and this holds even when the square root function doesn't have a + * deterministic sign. We choose the (n*g, g^2, v) version. + * + * Now switch to the effective affine curve using phi_v, where the input point has coordinates + * (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there. + * + * Back on secp256k1, that means q * (n*g, g^2, v) = (X, Y, v*Z). This last point has affine X + * coordinate X / (v^2*Z^2) = X / (d*g*Z^2). Determining the affine Y coordinate would involve + * a square root, but as long as we only care about the resulting X coordinate, no square root + * is needed anywhere in this computation. + */ + + secp256k1_fe g, i; + secp256k1_ge p; + secp256k1_gej rj; + + /* Compute g = (n^3 + B*d^3). */ + secp256k1_fe_sqr(&g, n); + secp256k1_fe_mul(&g, &g, n); + if (d) { + secp256k1_fe b; + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d)); + secp256k1_fe_sqr(&b, d); + VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */ + secp256k1_fe_mul_int(&b, SECP256K1_B); + secp256k1_fe_mul(&b, &b, d); + secp256k1_fe_add(&g, &b); + if (!known_on_curve) { + /* We need to determine whether (n/d)^3 + 7 is square. + * + * is_square((n/d)^3 + 7) + * <=> is_square(((n/d)^3 + 7) * d^4) + * <=> is_square((n^3 + 7*d^3) * d) + * <=> is_square(g * d) + */ + secp256k1_fe c; + secp256k1_fe_mul(&c, &g, d); + if (!secp256k1_fe_is_square_var(&c)) return 0; + } + } else { + secp256k1_fe_add_int(&g, SECP256K1_B); + if (!known_on_curve) { + /* g at this point equals x^3 + 7. Test if it is square. */ + if (!secp256k1_fe_is_square_var(&g)) return 0; + } + } + + /* Compute base point P = (n*g, g^2), the effective affine version of (n*g, g^2, v), which has + * corresponding affine X coordinate n/d. */ + secp256k1_fe_mul(&p.x, &g, n); + secp256k1_fe_sqr(&p.y, &g); + p.infinity = 0; + + /* Perform x-only EC multiplication of P with q. */ + VERIFY_CHECK(!secp256k1_scalar_is_zero(q)); + secp256k1_ecmult_const(&rj, &p, q); + VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj)); + + /* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to + * (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate + * (X / (Z^2*d*g)). */ + secp256k1_fe_sqr(&i, &rj.z); + secp256k1_fe_mul(&i, &i, &g); + if (d) secp256k1_fe_mul(&i, &i, d); + secp256k1_fe_inv(&i, &i); + secp256k1_fe_mul(r, &rj.x, &i); + + return 1; +} + +#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/external/secp256k1/src/ecmult_gen.h b/external/secp256k1/src/ecmult_gen.h new file mode 100644 index 00000000000..43dd10c38d7 --- /dev/null +++ b/external/secp256k1/src/ecmult_gen.h @@ -0,0 +1,143 @@ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_H +#define SECP256K1_ECMULT_GEN_H + +#include "scalar.h" +#include "group.h" + + +/* Configuration parameters for the signed-digit multi-comb algorithm: + * + * - COMB_BLOCKS is the number of blocks the input is split into. Each + * has a corresponding table. + * - COMB_TEETH is the number of bits simultaneously covered by one table. + * - COMB_RANGE is the number of bits in supported scalars. For production + * purposes, only 256 is reasonable, but smaller numbers are supported for + * exhaustive test mode. + * + * The comb's spacing (COMB_SPACING), or the distance between the teeth, + * is defined as ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)). Each block covers + * COMB_SPACING * COMB_TEETH consecutive bits in the input. + * + * The size of the precomputed table is COMB_BLOCKS * (1 << (COMB_TEETH - 1)) + * secp256k1_ge_storages. + * + * The number of point additions equals COMB_BLOCKS * COMB_SPACING. Each point + * addition involves a cmov from (1 << (COMB_TEETH - 1)) table entries and a + * conditional negation. + * + * The number of point doublings is COMB_SPACING - 1. */ + +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to control these values for exhaustive tests because + * the table cannot have infinities in them (secp256k1_ge_storage + * doesn't support infinities) */ +# undef COMB_BLOCKS +# undef COMB_TEETH +# if EXHAUSTIVE_TEST_ORDER == 7 +# define COMB_RANGE 3 +# define COMB_BLOCKS 1 +# define COMB_TEETH 2 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define COMB_RANGE 4 +# define COMB_BLOCKS 1 +# define COMB_TEETH 2 +# elif EXHAUSTIVE_TEST_ORDER == 199 +# define COMB_RANGE 8 +# define COMB_BLOCKS 2 +# define COMB_TEETH 3 +# else +# error "Unknown exhaustive test order" +# endif +# if (COMB_RANGE >= 32) || ((EXHAUSTIVE_TEST_ORDER >> (COMB_RANGE - 1)) != 1) +# error "COMB_RANGE != ceil(log2(EXHAUSTIVE_TEST_ORDER+1))" +# endif +#else /* !defined(EXHAUSTIVE_TEST_ORDER) */ +# define COMB_RANGE 256 +#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ + +/* Use (11, 6) as default configuration, which results in a 22 kB table. */ +#ifndef COMB_BLOCKS +# define COMB_BLOCKS 11 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("COMB_BLOCKS undefined, assuming default value") +# endif +#endif +#ifndef COMB_TEETH +# define COMB_TEETH 6 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("COMB_TEETH undefined, assuming default value") +# endif +#endif +/* Use ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)) as COMB_SPACING. */ +#define COMB_SPACING CEIL_DIV(COMB_RANGE, COMB_BLOCKS * COMB_TEETH) + +/* Range checks on the parameters. */ + +/* The remaining COMB_* parameters are derived values, don't modify these. */ +/* - The number of bits covered by all the blocks; must be at least COMB_RANGE. */ +#define COMB_BITS (COMB_BLOCKS * COMB_TEETH * COMB_SPACING) +/* - The number of entries per table. */ +#define COMB_POINTS (1 << (COMB_TEETH - 1)) + +/* Sanity checks. */ +#if !(1 <= COMB_BLOCKS && COMB_BLOCKS <= 256) +# error "COMB_BLOCKS must be in the range [1, 256]" +#endif +#if !(1 <= COMB_TEETH && COMB_TEETH <= 8) +# error "COMB_TEETH must be in the range [1, 8]" +#endif +#if COMB_BITS < COMB_RANGE +# error "COMB_BLOCKS * COMB_TEETH * COMB_SPACING is too low" +#endif + +/* These last 2 checks are not strictly required, but prevent gratuitously inefficient + * configurations. Note that they compare with 256 rather than COMB_RANGE, so they do + * permit somewhat excessive values for the exhaustive test case, where testing with + * suboptimal parameters may be desirable. */ +#if (COMB_BLOCKS - 1) * COMB_TEETH * COMB_SPACING >= 256 +# error "COMB_BLOCKS can be reduced" +#endif +#if COMB_BLOCKS * (COMB_TEETH - 1) * COMB_SPACING >= 256 +# error "COMB_TEETH can be reduced" +#endif + +#ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_DEF(COMB_RANGE) +# pragma message DEBUG_CONFIG_DEF(COMB_BLOCKS) +# pragma message DEBUG_CONFIG_DEF(COMB_TEETH) +# pragma message DEBUG_CONFIG_DEF(COMB_SPACING) +#endif + +typedef struct { + /* Whether the context has been built. */ + int built; + + /* Values chosen such that + * + * n*G == comb(n + scalar_offset, G/2) + ge_offset. + * + * This expression lets us use scalar blinding and optimize the comb precomputation. See + * ecmult_gen_impl.h for more details. */ + secp256k1_scalar scalar_offset; + secp256k1_ge ge_offset; + + /* Factor used for projective blinding. This value is used to rescale the Z + * coordinate of the first table lookup. */ + secp256k1_fe proj_blind; +} secp256k1_ecmult_gen_context; + +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx); +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); + +/** Multiply with the generator: R = a*G */ +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); + +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); + +#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/external/secp256k1/src/ecmult_gen_compute_table.h b/external/secp256k1/src/ecmult_gen_compute_table.h new file mode 100644 index 00000000000..bd41803a87c --- /dev/null +++ b/external/secp256k1/src/ecmult_gen_compute_table.h @@ -0,0 +1,14 @@ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H +#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H + +#include "ecmult_gen.h" + +static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing); + +#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H */ diff --git a/external/secp256k1/src/ecmult_gen_compute_table_impl.h b/external/secp256k1/src/ecmult_gen_compute_table_impl.h new file mode 100644 index 00000000000..6aa8d840828 --- /dev/null +++ b/external/secp256k1/src/ecmult_gen_compute_table_impl.h @@ -0,0 +1,108 @@ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H +#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H + +#include "ecmult_gen_compute_table.h" +#include "group_impl.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "ecmult_gen.h" +#include "util.h" + +static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing) { + size_t points = ((size_t)1) << (teeth - 1); + size_t points_total = points * blocks; + secp256k1_ge* prec = checked_malloc(&default_error_callback, points_total * sizeof(*prec)); + secp256k1_gej* ds = checked_malloc(&default_error_callback, teeth * sizeof(*ds)); + secp256k1_gej* vs = checked_malloc(&default_error_callback, points_total * sizeof(*vs)); + secp256k1_gej u; + size_t vs_pos = 0; + secp256k1_scalar half; + int block, i; + + VERIFY_CHECK(points_total > 0); + + /* u is the running power of two times gen we're working with, initially gen/2. */ + secp256k1_scalar_half(&half, &secp256k1_scalar_one); + secp256k1_gej_set_infinity(&u); + for (i = 255; i >= 0; --i) { + /* Use a very simple multiplication ladder to avoid dependency on ecmult. */ + secp256k1_gej_double_var(&u, &u, NULL); + if (secp256k1_scalar_get_bits_limb32(&half, i, 1)) { + secp256k1_gej_add_ge_var(&u, &u, gen, NULL); + } + } +#ifdef VERIFY + { + /* Verify that u*2 = gen. */ + secp256k1_gej double_u; + secp256k1_gej_double_var(&double_u, &u, NULL); + VERIFY_CHECK(secp256k1_gej_eq_ge_var(&double_u, gen)); + } +#endif + + for (block = 0; block < blocks; ++block) { + int tooth; + /* Here u = 2^(block*teeth*spacing) * gen/2. */ + secp256k1_gej sum; + secp256k1_gej_set_infinity(&sum); + for (tooth = 0; tooth < teeth; ++tooth) { + /* Here u = 2^((block*teeth + tooth)*spacing) * gen/2. */ + /* Make sum = sum(2^((block*teeth + t)*spacing), t=0..tooth) * gen/2. */ + secp256k1_gej_add_var(&sum, &sum, &u, NULL); + /* Make u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ + secp256k1_gej_double_var(&u, &u, NULL); + /* Make ds[tooth] = u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ + ds[tooth] = u; + /* Make u = 2^((block*teeth + tooth + 1)*spacing) * gen/2, unless at the end. */ + if (block + tooth != blocks + teeth - 2) { + int bit_off; + for (bit_off = 1; bit_off < spacing; ++bit_off) { + secp256k1_gej_double_var(&u, &u, NULL); + } + } + } + /* Now u = 2^((block*teeth + teeth)*spacing) * gen/2 + * = 2^((block+1)*teeth*spacing) * gen/2 */ + + /* Next, compute the table entries for block number block in Jacobian coordinates. + * The entries will occupy vs[block*points + i] for i=0..points-1. + * We start by computing the first (i=0) value corresponding to all summed + * powers of two times G being negative. */ + secp256k1_gej_neg(&vs[vs_pos++], &sum); + /* And then teeth-1 times "double" the range of i values for which the table + * is computed: in each iteration, double the table by taking an existing + * table entry and adding ds[tooth]. */ + for (tooth = 0; tooth < teeth - 1; ++tooth) { + size_t stride = ((size_t)1) << tooth; + size_t index; + for (index = 0; index < stride; ++index, ++vs_pos) { + secp256k1_gej_add_var(&vs[vs_pos], &vs[vs_pos - stride], &ds[tooth], NULL); + } + } + } + VERIFY_CHECK(vs_pos == points_total); + + /* Convert all points simultaneously from secp256k1_gej to secp256k1_ge. */ + secp256k1_ge_set_all_gej_var(prec, vs, points_total); + /* Convert all points from secp256k1_ge to secp256k1_ge_storage output. */ + for (block = 0; block < blocks; ++block) { + size_t index; + for (index = 0; index < points; ++index) { + VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[block * points + index])); + secp256k1_ge_to_storage(&table[block * points + index], &prec[block * points + index]); + } + } + + /* Free memory. */ + free(vs); + free(ds); + free(prec); +} + +#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H */ diff --git a/external/secp256k1/src/ecmult_gen_impl.h b/external/secp256k1/src/ecmult_gen_impl.h new file mode 100644 index 00000000000..070a1213087 --- /dev/null +++ b/external/secp256k1/src/ecmult_gen_impl.h @@ -0,0 +1,341 @@ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_IMPL_H +#define SECP256K1_ECMULT_GEN_IMPL_H + +#include "util.h" +#include "scalar.h" +#include "group.h" +#include "ecmult_gen.h" +#include "hash_impl.h" +#include "precomputed_ecmult_gen.h" + +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx) { + secp256k1_ecmult_gen_blind(ctx, NULL); + ctx->built = 1; +} + +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { + return ctx->built; +} + +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { + ctx->built = 0; + secp256k1_scalar_clear(&ctx->scalar_offset); + secp256k1_ge_clear(&ctx->ge_offset); + secp256k1_fe_clear(&ctx->proj_blind); +} + +/* Compute the scalar (2^COMB_BITS - 1) / 2, the difference between the gn argument to + * secp256k1_ecmult_gen, and the scalar whose encoding the table lookup bits are drawn + * from (before applying blinding). */ +static void secp256k1_ecmult_gen_scalar_diff(secp256k1_scalar* diff) { + int i; + + /* Compute scalar -1/2. */ + secp256k1_scalar neghalf; + secp256k1_scalar_half(&neghalf, &secp256k1_scalar_one); + secp256k1_scalar_negate(&neghalf, &neghalf); + + /* Compute offset = 2^(COMB_BITS - 1). */ + *diff = secp256k1_scalar_one; + for (i = 0; i < COMB_BITS - 1; ++i) { + secp256k1_scalar_add(diff, diff, diff); + } + + /* The result is the sum 2^(COMB_BITS - 1) + (-1/2). */ + secp256k1_scalar_add(diff, diff, &neghalf); +} + +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { + uint32_t comb_off; + secp256k1_ge add; + secp256k1_fe neg; + secp256k1_ge_storage adds; + secp256k1_scalar d; + /* Array of uint32_t values large enough to store COMB_BITS bits. Only the bottom + * 8 are ever nonzero, but having the zero padding at the end if COMB_BITS>256 + * avoids the need to deal with out-of-bounds reads from a scalar. */ + uint32_t recoded[(COMB_BITS + 31) >> 5] = {0}; + int first = 1, i; + + memset(&adds, 0, sizeof(adds)); + + /* We want to compute R = gn*G. + * + * To blind the scalar used in the computation, we rewrite this to be + * R = (gn - b)*G + b*G, with a blinding value b determined by the context. + * + * The multiplication (gn-b)*G will be performed using a signed-digit multi-comb (see Section + * 3.3 of "Fast and compact elliptic-curve cryptography" by Mike Hamburg, + * https://eprint.iacr.org/2012/309). + * + * Let comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1), where s[i] is the i'th bit of + * the binary representation of scalar s. So the s[i] values determine whether -2^i*P (s[i]=0) + * or +2^i*P (s[i]=1) are added together. COMB_BITS is at least 256, so all bits of s are + * covered. By manipulating: + * + * comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1) + * <=> comb(s, P) = sum((2*s[i]-1)*2^i for i=0..COMB_BITS-1) * P + * <=> comb(s, P) = (2*sum(s[i]*2^i for i=0..COMB_BITS-1) - sum(2^i for i=0..COMB_BITS-1)) * P + * <=> comb(s, P) = (2*s - (2^COMB_BITS - 1)) * P + * + * If we wanted to compute (gn-b)*G as comb(s, G), it would need to hold that + * + * (gn - b) * G = (2*s - (2^COMB_BITS - 1)) * G + * <=> s = (gn - b + (2^COMB_BITS - 1))/2 (mod order) + * + * We use an alternative here that avoids the modular division by two: instead we compute + * (gn-b)*G as comb(d, G/2). For that to hold it must be the case that + * + * (gn - b) * G = (2*d - (2^COMB_BITS - 1)) * (G/2) + * <=> d = gn - b + (2^COMB_BITS - 1)/2 (mod order) + * + * Adding precomputation, our final equations become: + * + * ctx->scalar_offset = (2^COMB_BITS - 1)/2 - b (mod order) + * ctx->ge_offset = b*G + * d = gn + ctx->scalar_offset (mod order) + * R = comb(d, G/2) + ctx->ge_offset + * + * comb(d, G/2) function is then computed by summing + or - 2^(i-1)*G, for i=0..COMB_BITS-1, + * depending on the value of the bits d[i] of the binary representation of scalar d. + */ + + /* Compute the scalar d = (gn + ctx->scalar_offset). */ + secp256k1_scalar_add(&d, &ctx->scalar_offset, gn); + /* Convert to recoded array. */ + for (i = 0; i < 8 && i < ((COMB_BITS + 31) >> 5); ++i) { + recoded[i] = secp256k1_scalar_get_bits_limb32(&d, 32 * i, 32); + } + secp256k1_scalar_clear(&d); + + /* In secp256k1_ecmult_gen_prec_table we have precomputed sums of the + * (2*d[i]-1) * 2^(i-1) * G points, for various combinations of i positions. + * We rewrite our equation in terms of these table entries. + * + * Let mask(b) = sum(2^((b*COMB_TEETH + t)*COMB_SPACING) for t=0..COMB_TEETH-1), + * with b ranging from 0 to COMB_BLOCKS-1. So for example with COMB_BLOCKS=11, + * COMB_TEETH=6, COMB_SPACING=4, we would have: + * mask(0) = 2^0 + 2^4 + 2^8 + 2^12 + 2^16 + 2^20, + * mask(1) = 2^24 + 2^28 + 2^32 + 2^36 + 2^40 + 2^44, + * mask(2) = 2^48 + 2^52 + 2^56 + 2^60 + 2^64 + 2^68, + * ... + * mask(10) = 2^240 + 2^244 + 2^248 + 2^252 + 2^256 + 2^260 + * + * We will split up the bits d[i] using these masks. Specifically, each mask is + * used COMB_SPACING times, with different shifts: + * + * d = (d & mask(0)<<0) + (d & mask(1)<<0) + ... + (d & mask(COMB_BLOCKS-1)<<0) + + * (d & mask(0)<<1) + (d & mask(1)<<1) + ... + (d & mask(COMB_BLOCKS-1)<<1) + + * ... + * (d & mask(0)<<(COMB_SPACING-1)) + ... + * + * Now define table(b, m) = (m - mask(b)/2) * G, and we will precompute these values for + * b=0..COMB_BLOCKS-1, and for all values m which (d & mask(b)) can take (so m can take on + * 2^COMB_TEETH distinct values). + * + * If m=(d & mask(b)), then table(b, m) is the sum of 2^i * (2*d[i]-1) * G/2, with i + * iterating over the set bits in mask(b). In our example, table(2, 2^48 + 2^56 + 2^68) + * would equal (2^48 - 2^52 + 2^56 - 2^60 - 2^64 + 2^68) * G/2. + * + * With that, we can rewrite comb(d, G/2) as: + * + * 2^0 * (table(0, d>>0 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>0 & mask(COMP_BLOCKS-1))) + * + 2^1 * (table(0, d>>1 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>1 & mask(COMP_BLOCKS-1))) + * + 2^2 * (table(0, d>>2 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>2 & mask(COMP_BLOCKS-1))) + * + ... + * + 2^(COMB_SPACING-1) * (table(0, d>>(COMB_SPACING-1) & mask(0)) + ...) + * + * Or more generically as + * + * sum(2^i * sum(table(b, d>>i & mask(b)), b=0..COMB_BLOCKS-1), i=0..COMB_SPACING-1) + * + * This is implemented using an outer loop that runs in reverse order over the lines of this + * equation, which in each iteration runs an inner loop that adds the terms of that line and + * then doubles the result before proceeding to the next line. + * + * In pseudocode: + * c = infinity + * for comb_off in range(COMB_SPACING - 1, -1, -1): + * for block in range(COMB_BLOCKS): + * c += table(block, (d >> comb_off) & mask(block)) + * if comb_off > 0: + * c = 2*c + * return c + * + * This computes c = comb(d, G/2), and thus finally R = c + ctx->ge_offset. Note that it would + * be possible to apply an initial offset instead of a final offset (moving ge_offset to take + * the place of infinity above), but the chosen approach allows using (in a future improvement) + * an incomplete addition formula for most of the multiplication. + * + * The last question is how to implement the table(b, m) function. For any value of b, + * m=(d & mask(b)) can only take on at most 2^COMB_TEETH possible values (the last one may have + * fewer as there mask(b) may exceed the curve order). So we could create COMB_BLOCK tables + * which contain a value for each such m value. + * + * Now note that if m=(d & mask(b)), then flipping the relevant bits of m results in negating + * the result of table(b, m). This is because table(b,m XOR mask(b)) = table(b, mask(b) - m) = + * (mask(b) - m - mask(b)/2)*G = (-m + mask(b)/2)*G = -(m - mask(b)/2)*G = -table(b, m). + * Because of this it suffices to only store the first half of the m values for every b. If an + * entry from the second half is needed, we look up its bit-flipped version instead, and negate + * it. + * + * secp256k1_ecmult_gen_prec_table[b][index] stores the table(b, m) entries. Index + * is the relevant mask(b) bits of m packed together without gaps. */ + + /* Outer loop: iterate over comb_off from COMB_SPACING - 1 down to 0. */ + comb_off = COMB_SPACING - 1; + while (1) { + uint32_t block; + uint32_t bit_pos = comb_off; + /* Inner loop: for each block, add table entries to the result. */ + for (block = 0; block < COMB_BLOCKS; ++block) { + /* Gather the mask(block)-selected bits of d into bits. They're packed: + * bits[tooth] = d[(block*COMB_TEETH + tooth)*COMB_SPACING + comb_off]. */ + uint32_t bits = 0, sign, abs, index, tooth; + /* Instead of reading individual bits here to construct the bits variable, + * build up the result by xoring rotated reads together. In every iteration, + * one additional bit is made correct, starting at the bottom. The bits + * above that contain junk. This reduces leakage by avoiding computations + * on variables that can have only a low number of possible values (e.g., + * just two values when reading a single bit into a variable.) See: + * https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf + */ + for (tooth = 0; tooth < COMB_TEETH; ++tooth) { + /* Construct bitdata s.t. the bottom bit is the bit we'd like to read. + * + * We could just set bitdata = recoded[bit_pos >> 5] >> (bit_pos & 0x1f) + * but this would simply discard the bits that fall off at the bottom, + * and thus, for example, bitdata could still have only two values if we + * happen to shift by exactly 31 positions. We use a rotation instead, + * which ensures that bitdata doesn't loose entropy. This relies on the + * rotation being atomic, i.e., the compiler emitting an actual rot + * instruction. */ + uint32_t bitdata = secp256k1_rotr32(recoded[bit_pos >> 5], bit_pos & 0x1f); + + /* Clear the bit at position tooth, but sssh, don't tell clang. */ + uint32_t volatile vmask = ~(1 << tooth); + bits &= vmask; + + /* Write the bit into position tooth (and junk into higher bits). */ + bits ^= bitdata << tooth; + bit_pos += COMB_SPACING; + } + + /* If the top bit of bits is 1, flip them all (corresponding to looking up + * the negated table value), and remember to negate the result in sign. */ + sign = (bits >> (COMB_TEETH - 1)) & 1; + abs = (bits ^ -sign) & (COMB_POINTS - 1); + VERIFY_CHECK(sign == 0 || sign == 1); + VERIFY_CHECK(abs < COMB_POINTS); + + /** This uses a conditional move to avoid any secret data in array indexes. + * _Any_ use of secret indexes has been demonstrated to result in timing + * sidechannels, even when the cache-line access patterns are uniform. + * See also: + * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe + * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and + * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, + * by Dag Arne Osvik, Adi Shamir, and Eran Tromer + * (https://www.tau.ac.il/~tromer/papers/cache.pdf) + */ + for (index = 0; index < COMB_POINTS; ++index) { + secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[block][index], index == abs); + } + + /* Set add=adds or add=-adds, in constant time, based on sign. */ + secp256k1_ge_from_storage(&add, &adds); + secp256k1_fe_negate(&neg, &add.y, 1); + secp256k1_fe_cmov(&add.y, &neg, sign); + + /* Add the looked up and conditionally negated value to r. */ + if (EXPECT(first, 0)) { + /* If this is the first table lookup, we can skip addition. */ + secp256k1_gej_set_ge(r, &add); + /* Give the entry a random Z coordinate to blind intermediary results. */ + secp256k1_gej_rescale(r, &ctx->proj_blind); + first = 0; + } else { + secp256k1_gej_add_ge(r, r, &add); + } + } + + /* Double the result, except in the last iteration. */ + if (comb_off-- == 0) break; + secp256k1_gej_double(r, r); + } + + /* Correct for the scalar_offset added at the start (ge_offset = b*G, while b was + * subtracted from the input scalar gn). */ + secp256k1_gej_add_ge(r, r, &ctx->ge_offset); + + /* Cleanup. */ + secp256k1_fe_clear(&neg); + secp256k1_ge_clear(&add); + secp256k1_memclear(&adds, sizeof(adds)); + secp256k1_memclear(&recoded, sizeof(recoded)); +} + +/* Setup blinding values for secp256k1_ecmult_gen. */ +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) { + secp256k1_scalar b; + secp256k1_scalar diff; + secp256k1_gej gb; + secp256k1_fe f; + unsigned char nonce32[32]; + secp256k1_rfc6979_hmac_sha256 rng; + unsigned char keydata[64]; + + /* Compute the (2^COMB_BITS - 1)/2 term once. */ + secp256k1_ecmult_gen_scalar_diff(&diff); + + if (seed32 == NULL) { + /* When seed is NULL, reset the final point and blinding value. */ + secp256k1_ge_neg(&ctx->ge_offset, &secp256k1_ge_const_g); + secp256k1_scalar_add(&ctx->scalar_offset, &secp256k1_scalar_one, &diff); + ctx->proj_blind = secp256k1_fe_one; + return; + } + /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ + secp256k1_scalar_get_b32(keydata, &ctx->scalar_offset); + /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, + * and guards against weak or adversarial seeds. This is a simpler and safer interface than + * asking the caller for blinding values directly and expecting them to retry on failure. + */ + VERIFY_CHECK(seed32 != NULL); + memcpy(keydata + 32, seed32, 32); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64); + secp256k1_memclear(keydata, sizeof(keydata)); + + /* Compute projective blinding factor (cannot be 0). */ + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_fe_set_b32_mod(&f, nonce32); + secp256k1_fe_cmov(&f, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&f)); + ctx->proj_blind = f; + + /* For a random blinding value b, set scalar_offset=diff-b, ge_offset=bG */ + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_scalar_set_b32(&b, nonce32, NULL); + /* The blinding value cannot be zero, as that would mean ge_offset = infinity, + * which secp256k1_gej_add_ge cannot handle. */ + secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b)); + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + secp256k1_ecmult_gen(ctx, &gb, &b); + secp256k1_scalar_negate(&b, &b); + secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff); + secp256k1_ge_set_gej(&ctx->ge_offset, &gb); + + /* Clean up. */ + secp256k1_memclear(nonce32, sizeof(nonce32)); + secp256k1_scalar_clear(&b); + secp256k1_gej_clear(&gb); + secp256k1_fe_clear(&f); + secp256k1_rfc6979_hmac_sha256_clear(&rng); +} + +#endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/external/secp256k1/src/ecmult_impl.h b/external/secp256k1/src/ecmult_impl.h new file mode 100644 index 00000000000..0b53b3fcb98 --- /dev/null +++ b/external/secp256k1/src/ecmult_impl.h @@ -0,0 +1,853 @@ +/****************************************************************************** + * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + ******************************************************************************/ + +#ifndef SECP256K1_ECMULT_IMPL_H +#define SECP256K1_ECMULT_IMPL_H + +#include +#include + +#include "util.h" +#include "group.h" +#include "scalar.h" +#include "ecmult.h" +#include "precomputed_ecmult.h" + +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to lower these values for exhaustive tests because + * the tables cannot have infinities in them (this breaks the + * affine-isomorphism stuff which tracks z-ratios) */ +# if EXHAUSTIVE_TEST_ORDER > 128 +# define WINDOW_A 5 +# elif EXHAUSTIVE_TEST_ORDER > 8 +# define WINDOW_A 4 +# else +# define WINDOW_A 2 +# endif +#else +/* optimal for 128-bit and 256-bit exponents. */ +# define WINDOW_A 5 +/** Larger values for ECMULT_WINDOW_SIZE result in possibly better + * performance at the cost of an exponentially larger precomputed + * table. The exact table size is + * (1 << (WINDOW_G - 2)) * sizeof(secp256k1_ge_storage) bytes, + * where sizeof(secp256k1_ge_storage) is typically 64 bytes but can + * be larger due to platform-specific padding and alignment. + * Two tables of this size are used (due to the endomorphism + * optimization). + */ +#endif + +#define WNAF_BITS 128 +#define WNAF_SIZE_BITS(bits, w) CEIL_DIV(bits, w) +#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w) + +/* The number of objects allocated on the scratch space for ecmult_multi algorithms */ +#define PIPPENGER_SCRATCH_OBJECTS 6 +#define STRAUSS_SCRATCH_OBJECTS 5 + +#define PIPPENGER_MAX_BUCKET_WINDOW 12 + +/* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */ +#define ECMULT_PIPPENGER_THRESHOLD 88 + +#define ECMULT_MAX_POINTS_PER_BATCH 5000000 + +/** Fill a table 'pre_a' with precomputed odd multiples of a. + * pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements. + * zr needs space for n field elements. + * + * Although pre_a is an array of _ge rather than _gej, it actually represents elements + * in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates + * can be recovered using z and zr. Using the notation z(b) to represent the omitted + * z coordinate of b: + * - z(pre_a[n-1]) = 'z' + * - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0 + * + * Lastly the zr[0] value, which isn't used above, is set so that: + * - a.z = z(pre_a[0]) / zr[0] + */ +static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) { + secp256k1_gej d, ai; + secp256k1_ge d_ge; + int i; + + VERIFY_CHECK(!a->infinity); + + secp256k1_gej_double_var(&d, a, NULL); + + /* + * Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z. + * The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve. + * In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C). + * + * phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C) + * d_ge := phi(d) = (d.x, d.y, 1) + * ai := phi(a) = (a.x*C^2, a.y*C^3, a.z) + * + * The group addition functions work correctly on these isomorphic curves. + * In particular phi(d) is easy to represent in affine coordinates under this isomorphism. + * This lets us use the faster secp256k1_gej_add_ge_var group addition function that we wouldn't be able to use otherwise. + */ + secp256k1_ge_set_xy(&d_ge, &d.x, &d.y); + secp256k1_ge_set_gej_zinv(&pre_a[0], a, &d.z); + secp256k1_gej_set_ge(&ai, &pre_a[0]); + ai.z = a->z; + + /* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equivalent to a. + * Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z. + */ + zr[0] = d.z; + + for (i = 1; i < n; i++) { + secp256k1_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]); + secp256k1_ge_set_xy(&pre_a[i], &ai.x, &ai.y); + } + + /* Multiply the last z-coordinate by C to undo the isomorphism. + * Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios, + * undoing the isomorphism here undoes the isomorphism for all pre_a values. + */ + secp256k1_fe_mul(z, &ai.z, &d.z); +} + +SECP256K1_INLINE static void secp256k1_ecmult_table_verify(int n, int w) { + (void)n; + (void)w; + VERIFY_CHECK(((n) & 1) == 1); + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); +} + +SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, const secp256k1_ge *pre, int n, int w) { + secp256k1_ecmult_table_verify(n,w); + if (n > 0) { + *r = pre[(n-1)/2]; + } else { + *r = pre[(-n-1)/2]; + secp256k1_fe_negate(&(r->y), &(r->y), 1); + } +} + +SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *r, const secp256k1_ge *pre, const secp256k1_fe *x, int n, int w) { + secp256k1_ecmult_table_verify(n,w); + if (n > 0) { + secp256k1_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y); + } else { + secp256k1_ge_set_xy(r, &x[(-n-1)/2], &pre[(-n-1)/2].y); + secp256k1_fe_negate(&(r->y), &(r->y), 1); + } +} + +SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_storage(secp256k1_ge *r, const secp256k1_ge_storage *pre, int n, int w) { + secp256k1_ecmult_table_verify(n,w); + if (n > 0) { + secp256k1_ge_from_storage(r, &pre[(n-1)/2]); + } else { + secp256k1_ge_from_storage(r, &pre[(-n-1)/2]); + secp256k1_fe_negate(&(r->y), &(r->y), 1); + } +} + +/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), + * with the following guarantees: + * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) + * - two non-zero entries in wnaf are separated by at least w-1 zeroes. + * - the number of set values in wnaf is returned. This number is at most 256, and at most one more + * than the number of bits in the (absolute value) of the input. + */ +static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) { + secp256k1_scalar s; + int last_set_bit = -1; + int bit = 0; + int sign = 1; + int carry = 0; + + VERIFY_CHECK(wnaf != NULL); + VERIFY_CHECK(0 <= len && len <= 256); + VERIFY_CHECK(a != NULL); + VERIFY_CHECK(2 <= w && w <= 31); + + for (bit = 0; bit < len; bit++) { + wnaf[bit] = 0; + } + + s = *a; + if (secp256k1_scalar_get_bits_limb32(&s, 255, 1)) { + secp256k1_scalar_negate(&s, &s); + sign = -1; + } + + bit = 0; + while (bit < len) { + int now; + int word; + if (secp256k1_scalar_get_bits_limb32(&s, bit, 1) == (unsigned int)carry) { + bit++; + continue; + } + + now = w; + if (now > len - bit) { + now = len - bit; + } + + word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry; + + carry = (word >> (w-1)) & 1; + word -= carry << w; + + wnaf[bit] = sign * word; + last_set_bit = bit; + + bit += now; + } +#ifdef VERIFY + { + int verify_bit = bit; + + VERIFY_CHECK(carry == 0); + + while (verify_bit < 256) { + VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&s, verify_bit, 1) == 0); + verify_bit++; + } + } +#endif + return last_set_bit + 1; +} + +struct secp256k1_strauss_point_state { + int wnaf_na_1[129]; + int wnaf_na_lam[129]; + int bits_na_1; + int bits_na_lam; +}; + +struct secp256k1_strauss_state { + /* aux is used to hold z-ratios, and then used to hold pre_a[i].x * BETA values. */ + secp256k1_fe* aux; + secp256k1_ge* pre_a; + struct secp256k1_strauss_point_state* ps; +}; + +static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *state, secp256k1_gej *r, size_t num, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { + secp256k1_ge tmpa; + secp256k1_fe Z; + /* Split G factors. */ + secp256k1_scalar ng_1, ng_128; + int wnaf_ng_1[129]; + int bits_ng_1 = 0; + int wnaf_ng_128[129]; + int bits_ng_128 = 0; + int i; + int bits = 0; + size_t np; + size_t no = 0; + + secp256k1_fe_set_int(&Z, 1); + for (np = 0; np < num; ++np) { + secp256k1_gej tmp; + secp256k1_scalar na_1, na_lam; + if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) { + continue; + } + /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ + secp256k1_scalar_split_lambda(&na_1, &na_lam, &na[np]); + + /* build wnaf representation for na_1 and na_lam. */ + state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A); + state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A); + VERIFY_CHECK(state->ps[no].bits_na_1 <= 129); + VERIFY_CHECK(state->ps[no].bits_na_lam <= 129); + if (state->ps[no].bits_na_1 > bits) { + bits = state->ps[no].bits_na_1; + } + if (state->ps[no].bits_na_lam > bits) { + bits = state->ps[no].bits_na_lam; + } + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + * The exception is the precomputed G table points, which are actually + * affine. Compared to the base used for other points, they have a Z ratio + * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same + * isomorphism to efficiently add with a known Z inverse. + */ + tmp = a[np]; + if (no) { + secp256k1_gej_rescale(&tmp, &Z); + } + secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp); + if (no) secp256k1_fe_mul(state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &(a[np].z)); + + ++no; + } + + /* Bring them to the same Z denominator. */ + if (no) { + secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux); + } + + for (np = 0; np < no; ++np) { + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &secp256k1_const_beta); + } + } + + if (ng) { + /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ + secp256k1_scalar_split_128(&ng_1, &ng_128, ng); + + /* Build wnaf representation for ng_1 and ng_128 */ + bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); + bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); + if (bits_ng_1 > bits) { + bits = bits_ng_1; + } + if (bits_ng_128 > bits) { + bits = bits_ng_128; + } + } + + secp256k1_gej_set_infinity(r); + + for (i = bits - 1; i >= 0; i--) { + int n; + secp256k1_gej_double_var(r, r, NULL); + for (np = 0; np < no; ++np) { + if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) { + secp256k1_ecmult_table_get_ge(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } + if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) { + secp256k1_ecmult_table_get_ge_lambda(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } + } + if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { + secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g, n, WINDOW_G); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); + } + if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { + secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g_128, n, WINDOW_G); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); + } + } + + if (!r->infinity) { + secp256k1_fe_mul(&r->z, &r->z, &Z); + } +} + +static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { + secp256k1_fe aux[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + struct secp256k1_strauss_point_state ps[1]; + struct secp256k1_strauss_state state; + + state.aux = aux; + state.pre_a = pre_a; + state.ps = ps; + secp256k1_ecmult_strauss_wnaf(&state, r, 1, a, na, ng); +} + +static size_t secp256k1_strauss_scratch_size(size_t n_points) { + static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); + return n_points*point_size; +} + +static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { + secp256k1_gej* points; + secp256k1_scalar* scalars; + struct secp256k1_strauss_state state; + size_t i; + const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); + + secp256k1_gej_set_infinity(r); + if (inp_g_sc == NULL && n_points == 0) { + return 1; + } + + /* We allocate STRAUSS_SCRATCH_OBJECTS objects on the scratch space. If these + * allocations change, make sure to update the STRAUSS_SCRATCH_OBJECTS + * constant and strauss_scratch_size accordingly. */ + points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej)); + scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar)); + state.aux = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe)); + state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); + state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state)); + + if (points == NULL || scalars == NULL || state.aux == NULL || state.pre_a == NULL || state.ps == NULL) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + + for (i = 0; i < n_points; i++) { + secp256k1_ge point; + if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + secp256k1_gej_set_ge(&points[i], &point); + } + secp256k1_ecmult_strauss_wnaf(&state, r, n_points, points, scalars, inp_g_sc); + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 1; +} + +/* Wrapper for secp256k1_ecmult_multi_func interface */ +static int secp256k1_ecmult_strauss_batch_single(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { + return secp256k1_ecmult_strauss_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0); +} + +static size_t secp256k1_strauss_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) { + return secp256k1_scratch_max_allocation(error_callback, scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1); +} + +/** Convert a number to WNAF notation. + * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. + * It has the following guarantees: + * - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w) + * - the number of words set is always WNAF_SIZE(w) + * - the returned skew is 0 or 1 + */ +static int secp256k1_wnaf_fixed(int *wnaf, const secp256k1_scalar *s, int w) { + int skew = 0; + int pos; + int max_pos; + int last_w; + const secp256k1_scalar *work = s; + + if (secp256k1_scalar_is_zero(s)) { + for (pos = 0; pos < WNAF_SIZE(w); pos++) { + wnaf[pos] = 0; + } + return 0; + } + + if (secp256k1_scalar_is_even(s)) { + skew = 1; + } + + wnaf[0] = secp256k1_scalar_get_bits_var(work, 0, w) + skew; + /* Compute last window size. Relevant when window size doesn't divide the + * number of bits in the scalar */ + last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w; + + /* Store the position of the first nonzero word in max_pos to allow + * skipping leading zeros when calculating the wnaf. */ + for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) { + int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if(val != 0) { + break; + } + wnaf[pos] = 0; + } + max_pos = pos; + pos = 1; + + while (pos <= max_pos) { + int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if ((val & 1) == 0) { + wnaf[pos - 1] -= (1 << w); + wnaf[pos] = (val + 1); + } else { + wnaf[pos] = val; + } + /* Set a coefficient to zero if it is 1 or -1 and the proceeding digit + * is strictly negative or strictly positive respectively. Only change + * coefficients at previous positions because above code assumes that + * wnaf[pos - 1] is odd. + */ + if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) { + if (wnaf[pos - 1] == 1) { + wnaf[pos - 2] += 1 << w; + } else { + wnaf[pos - 2] -= 1 << w; + } + wnaf[pos - 1] = 0; + } + ++pos; + } + + return skew; +} + +struct secp256k1_pippenger_point_state { + int skew_na; + size_t input_pos; +}; + +struct secp256k1_pippenger_state { + int *wnaf_na; + struct secp256k1_pippenger_point_state* ps; +}; + +/* + * pippenger_wnaf computes the result of a multi-point multiplication as + * follows: The scalars are brought into wnaf with n_wnaf elements each. Then + * for every i < n_wnaf, first each point is added to a "bucket" corresponding + * to the point's wnaf[i]. Second, the buckets are added together such that + * r += 1*bucket[0] + 3*bucket[1] + 5*bucket[2] + ... + */ +static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_window, struct secp256k1_pippenger_state *state, secp256k1_gej *r, const secp256k1_scalar *sc, const secp256k1_ge *pt, size_t num) { + size_t n_wnaf = WNAF_SIZE(bucket_window+1); + size_t np; + size_t no = 0; + int i; + int j; + + for (np = 0; np < num; ++np) { + if (secp256k1_scalar_is_zero(&sc[np]) || secp256k1_ge_is_infinity(&pt[np])) { + continue; + } + state->ps[no].input_pos = np; + state->ps[no].skew_na = secp256k1_wnaf_fixed(&state->wnaf_na[no*n_wnaf], &sc[np], bucket_window+1); + no++; + } + secp256k1_gej_set_infinity(r); + + if (no == 0) { + return 1; + } + + for (i = n_wnaf - 1; i >= 0; i--) { + secp256k1_gej running_sum; + + for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) { + secp256k1_gej_set_infinity(&buckets[j]); + } + + for (np = 0; np < no; ++np) { + int n = state->wnaf_na[np*n_wnaf + i]; + struct secp256k1_pippenger_point_state point_state = state->ps[np]; + secp256k1_ge tmp; + int idx; + + if (i == 0) { + /* correct for wnaf skew */ + int skew = point_state.skew_na; + if (skew) { + secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]); + secp256k1_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL); + } + } + if (n > 0) { + idx = (n - 1)/2; + secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL); + } else if (n < 0) { + idx = -(n + 1)/2; + secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]); + secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL); + } + } + + for(j = 0; j < bucket_window; j++) { + secp256k1_gej_double_var(r, r, NULL); + } + + secp256k1_gej_set_infinity(&running_sum); + /* Accumulate the sum: bucket[0] + 3*bucket[1] + 5*bucket[2] + 7*bucket[3] + ... + * = bucket[0] + bucket[1] + bucket[2] + bucket[3] + ... + * + 2 * (bucket[1] + 2*bucket[2] + 3*bucket[3] + ...) + * using an intermediate running sum: + * running_sum = bucket[0] + bucket[1] + bucket[2] + ... + * + * The doubling is done implicitly by deferring the final window doubling (of 'r'). + */ + for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) { + secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL); + secp256k1_gej_add_var(r, r, &running_sum, NULL); + } + + secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[0], NULL); + secp256k1_gej_double_var(r, r, NULL); + secp256k1_gej_add_var(r, r, &running_sum, NULL); + } + return 1; +} + +/** + * Returns optimal bucket_window (number of bits of a scalar represented by a + * set of buckets) for a given number of points. + */ +static int secp256k1_pippenger_bucket_window(size_t n) { + if (n <= 1) { + return 1; + } else if (n <= 4) { + return 2; + } else if (n <= 20) { + return 3; + } else if (n <= 57) { + return 4; + } else if (n <= 136) { + return 5; + } else if (n <= 235) { + return 6; + } else if (n <= 1260) { + return 7; + } else if (n <= 4420) { + return 9; + } else if (n <= 7880) { + return 10; + } else if (n <= 16050) { + return 11; + } else { + return PIPPENGER_MAX_BUCKET_WINDOW; + } +} + +/** + * Returns the maximum optimal number of points for a bucket_window. + */ +static size_t secp256k1_pippenger_bucket_window_inv(int bucket_window) { + switch(bucket_window) { + case 1: return 1; + case 2: return 4; + case 3: return 20; + case 4: return 57; + case 5: return 136; + case 6: return 235; + case 7: return 1260; + case 8: return 1260; + case 9: return 4420; + case 10: return 7880; + case 11: return 16050; + case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; + } + return 0; +} + + +SECP256K1_INLINE static void secp256k1_ecmult_endo_split(secp256k1_scalar *s1, secp256k1_scalar *s2, secp256k1_ge *p1, secp256k1_ge *p2) { + secp256k1_scalar tmp = *s1; + secp256k1_scalar_split_lambda(s1, s2, &tmp); + secp256k1_ge_mul_lambda(p2, p1); + + if (secp256k1_scalar_is_high(s1)) { + secp256k1_scalar_negate(s1, s1); + secp256k1_ge_neg(p1, p1); + } + if (secp256k1_scalar_is_high(s2)) { + secp256k1_scalar_negate(s2, s2); + secp256k1_ge_neg(p2, p2); + } +} + +/** + * Returns the scratch size required for a given number of points (excluding + * base point G) without considering alignment. + */ +static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_window) { + size_t entries = 2*n_points + 2; + size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); + return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size; +} + +static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { + const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); + /* Use 2(n+1) with the endomorphism, when calculating batch + * sizes. The reason for +1 is that we add the G scalar to the list of + * other scalars. */ + size_t entries = 2*n_points + 2; + secp256k1_ge *points; + secp256k1_scalar *scalars; + secp256k1_gej *buckets; + struct secp256k1_pippenger_state *state_space; + size_t idx = 0; + size_t point_idx = 0; + int bucket_window; + + secp256k1_gej_set_infinity(r); + if (inp_g_sc == NULL && n_points == 0) { + return 1; + } + bucket_window = secp256k1_pippenger_bucket_window(n_points); + + /* We allocate PIPPENGER_SCRATCH_OBJECTS objects on the scratch space. If + * these allocations change, make sure to update the + * PIPPENGER_SCRATCH_OBJECTS constant and pippenger_scratch_size + * accordingly. */ + points = (secp256k1_ge *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*points)); + scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars)); + state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(error_callback, scratch, sizeof(*state_space)); + if (points == NULL || scalars == NULL || state_space == NULL) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps)); + state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); + buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, ((size_t)1 << bucket_window) * sizeof(*buckets)); + if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + + if (inp_g_sc != NULL) { + scalars[0] = *inp_g_sc; + points[0] = secp256k1_ge_const_g; + idx++; + secp256k1_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]); + idx++; + } + + while (point_idx < n_points) { + if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + idx++; + secp256k1_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]); + idx++; + point_idx++; + } + + secp256k1_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx); + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 1; +} + +/* Wrapper for secp256k1_ecmult_multi_func interface */ +static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { + return secp256k1_ecmult_pippenger_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0); +} + +/** + * Returns the maximum number of points in addition to G that can be used with + * a given scratch space. The function ensures that fewer points may also be + * used. + */ +static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) { + size_t max_alloc = secp256k1_scratch_max_allocation(error_callback, scratch, PIPPENGER_SCRATCH_OBJECTS); + int bucket_window; + size_t res = 0; + + for (bucket_window = 1; bucket_window <= PIPPENGER_MAX_BUCKET_WINDOW; bucket_window++) { + size_t n_points; + size_t max_points = secp256k1_pippenger_bucket_window_inv(bucket_window); + size_t space_for_points; + size_t space_overhead; + size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); + + entry_size = 2*entry_size; + space_overhead = (sizeof(secp256k1_gej) << bucket_window) + entry_size + sizeof(struct secp256k1_pippenger_state); + if (space_overhead > max_alloc) { + break; + } + space_for_points = max_alloc - space_overhead; + + n_points = space_for_points/entry_size; + n_points = n_points > max_points ? max_points : n_points; + if (n_points > res) { + res = n_points; + } + if (n_points < max_points) { + /* A larger bucket_window may support even more points. But if we + * would choose that then the caller couldn't safely use any number + * smaller than what this function returns */ + break; + } + } + return res; +} + +/* Computes ecmult_multi by simply multiplying and adding each point. Does not + * require a scratch space */ +static int secp256k1_ecmult_multi_simple_var(secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) { + size_t point_idx; + secp256k1_gej tmpj; + + secp256k1_gej_set_infinity(r); + secp256k1_gej_set_infinity(&tmpj); + /* r = inp_g_sc*G */ + secp256k1_ecmult(r, &tmpj, &secp256k1_scalar_zero, inp_g_sc); + for (point_idx = 0; point_idx < n_points; point_idx++) { + secp256k1_ge point; + secp256k1_gej pointj; + secp256k1_scalar scalar; + if (!cb(&scalar, &point, point_idx, cbdata)) { + return 0; + } + /* r += scalar*point */ + secp256k1_gej_set_ge(&pointj, &point); + secp256k1_ecmult(&tmpj, &pointj, &scalar, NULL); + secp256k1_gej_add_var(r, r, &tmpj, NULL); + } + return 1; +} + +/* Compute the number of batches and the batch size given the maximum batch size and the + * total number of points */ +static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) { + if (max_n_batch_points == 0) { + return 0; + } + if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) { + max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH; + } + if (n == 0) { + *n_batches = 0; + *n_batch_points = 0; + return 1; + } + /* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */ + *n_batches = CEIL_DIV(n, max_n_batch_points); + *n_batch_points = CEIL_DIV(n, *n_batches); + return 1; +} + +typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_callback* error_callback, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t); +static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { + size_t i; + + int (*f)(const secp256k1_callback* error_callback, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t); + size_t n_batches; + size_t n_batch_points; + + secp256k1_gej_set_infinity(r); + if (inp_g_sc == NULL && n == 0) { + return 1; + } else if (n == 0) { + secp256k1_ecmult(r, r, &secp256k1_scalar_zero, inp_g_sc); + return 1; + } + if (scratch == NULL) { + return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); + } + + /* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than + * a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm. + * As a first step check if there's enough space for Pippenger's algo (which requires less space + * than Strauss' algo) and if not, use the simple algorithm. */ + if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(error_callback, scratch), n)) { + return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); + } + if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) { + f = secp256k1_ecmult_pippenger_batch; + } else { + if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(error_callback, scratch), n)) { + return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); + } + f = secp256k1_ecmult_strauss_batch; + } + for(i = 0; i < n_batches; i++) { + size_t nbp = n < n_batch_points ? n : n_batch_points; + size_t offset = n_batch_points*i; + secp256k1_gej tmp; + if (!f(error_callback, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { + return 0; + } + secp256k1_gej_add_var(r, r, &tmp, NULL); + n -= nbp; + } + return 1; +} + +#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/external/secp256k1/src/field.h b/external/secp256k1/src/field.h new file mode 100644 index 00000000000..1f6ba7460f7 --- /dev/null +++ b/external/secp256k1/src/field.h @@ -0,0 +1,350 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_FIELD_H +#define SECP256K1_FIELD_H + +#include "util.h" + +/* This file defines the generic interface for working with secp256k1_fe + * objects, which represent field elements (integers modulo 2^256 - 2^32 - 977). + * + * The actual definition of the secp256k1_fe type depends on the chosen field + * implementation; see the field_5x52.h and field_10x26.h files for details. + * + * All secp256k1_fe objects have implicit properties that determine what + * operations are permitted on it. These are purely a function of what + * secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at + * compile time, and do not depend on the chosen field implementation. Despite + * that, what these properties actually entail for the field representation + * values depends on the chosen field implementation. These properties are: + * - magnitude: an integer in [0,32] + * - normalized: 0 or 1; normalized=1 implies magnitude <= 1. + * + * In VERIFY mode, they are materialized explicitly as fields in the struct, + * allowing run-time verification of these properties. In that case, the field + * implementation also provides a secp256k1_fe_verify routine to verify that + * these fields match the run-time value and perform internal consistency + * checks. */ +#ifdef VERIFY +# define SECP256K1_FE_VERIFY_FIELDS \ + int magnitude; \ + int normalized; +#else +# define SECP256K1_FE_VERIFY_FIELDS +#endif + +#if defined(SECP256K1_WIDEMUL_INT128) +#include "field_5x52.h" +#elif defined(SECP256K1_WIDEMUL_INT64) +#include "field_10x26.h" +#else +#error "Please select wide multiplication implementation" +#endif + +#ifdef VERIFY +/* Magnitude and normalized value for constants. */ +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \ + /* Magnitude is 0 for constant 0; 1 otherwise. */ \ + , (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \ + /* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \ + , (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f))))) +#else +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) +#endif + +/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p. + * + * It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0. + * It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p. + * + * SECP256K1_FE_CONST_INNER is provided by the implementation. + */ +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) } + +static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); +static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( + 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, + 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul +); + +#ifndef VERIFY +/* In non-VERIFY mode, we #define the fe operations to be identical to their + * internal field implementation, to avoid the potential overhead of a + * function call (even though presumably inlinable). */ +# define secp256k1_fe_normalize secp256k1_fe_impl_normalize +# define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak +# define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var +# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero +# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var +# define secp256k1_fe_set_int secp256k1_fe_impl_set_int +# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero +# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd +# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var +# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod +# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit +# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 +# define secp256k1_fe_negate_unchecked secp256k1_fe_impl_negate_unchecked +# define secp256k1_fe_mul_int_unchecked secp256k1_fe_impl_mul_int_unchecked +# define secp256k1_fe_add secp256k1_fe_impl_add +# define secp256k1_fe_mul secp256k1_fe_impl_mul +# define secp256k1_fe_sqr secp256k1_fe_impl_sqr +# define secp256k1_fe_cmov secp256k1_fe_impl_cmov +# define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage +# define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage +# define secp256k1_fe_inv secp256k1_fe_impl_inv +# define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var +# define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds +# define secp256k1_fe_half secp256k1_fe_impl_half +# define secp256k1_fe_add_int secp256k1_fe_impl_add_int +# define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var +#endif /* !defined(VERIFY) */ + +/** Normalize a field element. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has normalized=1 and magnitude=1. + */ +static void secp256k1_fe_normalize(secp256k1_fe *r); + +/** Give a field element magnitude 1. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has magnitude=1. Normalized is unchanged. + */ +static void secp256k1_fe_normalize_weak(secp256k1_fe *r); + +/** Normalize a field element, without constant-time guarantee. + * + * Identical in behavior to secp256k1_fe_normalize, but not constant time in r. + */ +static void secp256k1_fe_normalize_var(secp256k1_fe *r); + +/** Determine whether r represents field element 0. + * + * On input, r must be a valid field element. + * Returns whether r = 0 (mod p). + */ +static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r); + +/** Determine whether r represents field element 0, without constant-time guarantee. + * + * Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r. + */ +static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r); + +/** Set a field element to an integer in range [0,0x7FFF]. + * + * On input, r does not need to be initialized, a must be in [0,0x7FFF]. + * On output, r represents value a, is normalized and has magnitude (a!=0). + */ +static void secp256k1_fe_set_int(secp256k1_fe *r, int a); + +/** Clear a field element to prevent leaking sensitive information. */ +static void secp256k1_fe_clear(secp256k1_fe *a); + +/** Determine whether a represents field element 0. + * + * On input, a must be a valid normalized field element. + * Returns whether a = 0 (mod p). + * + * This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires + * normalized input (and is much faster). + */ +static int secp256k1_fe_is_zero(const secp256k1_fe *a); + +/** Determine whether a (mod p) is odd. + * + * On input, a must be a valid normalized field element. + * Returns (int(a) mod p) & 1. + */ +static int secp256k1_fe_is_odd(const secp256k1_fe *a); + +/** Determine whether two field elements are equal. + * + * On input, a and b must be valid field elements with magnitudes not exceeding + * 1 and 31, respectively. + * Returns a = b (mod p). + */ +static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); + +/** Compare the values represented by 2 field elements, without constant-time guarantee. + * + * On input, a and b must be valid normalized field elements. + * Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers + * in range 0..p-1). + */ +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); + +/** Set a field element equal to the element represented by a provided 32-byte big endian value + * interpreted modulo p. + * + * On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array. + * On output, r = a (mod p). It will have magnitude 1, and not be normalized. + */ +static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a); + +/** Set a field element equal to a provided 32-byte big endian value, checking for overflow. + * + * On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array. + * On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned. + * If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting). + */ +static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a); + +/** Convert a field element to 32-byte big endian byte array. + * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array. + * On output, r = a (mod p). + */ +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); + +/** Negate a field element. + * + * On input, r does not need to be initialized. a must be a valid field element with + * magnitude not exceeding m. m must be an integer constant expression in [0,31]. + * Performs {r = -a}. + * On output, r will not be normalized, and will have magnitude m+1. + */ +#define secp256k1_fe_negate(r, a, m) ASSERT_INT_CONST_AND_DO(m, secp256k1_fe_negate_unchecked(r, a, m)) + +/** Like secp256k1_fe_negate_unchecked but m is not checked to be an integer constant expression. + * + * Should not be called directly outside of tests. + */ +static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m); + +/** Add a small integer to a field element. + * + * Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared. + * a must be in range [0,0x7FFF]. + */ +static void secp256k1_fe_add_int(secp256k1_fe *r, int a); + +/** Multiply a field element with a small integer. + * + * On input, r must be a valid field element. a must be an integer constant expression in [0,32]. + * The magnitude of r times a must not exceed 32. + * Performs {r *= a}. + * On output, r's magnitude is multiplied by a, and r will not be normalized. + */ +#define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a)) + +/** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression. + * + * Should not be called directly outside of tests. + */ +static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a); + +/** Increment a field element by another. + * + * On input, r and a must be valid field elements, not necessarily normalized. + * The sum of their magnitudes must not exceed 32. + * Performs {r += a}. + * On output, r will not be normalized, and will have magnitude incremented by a's. + */ +static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); + +/** Multiply two field elements. + * + * On input, a and b must be valid field elements; r does not need to be initialized. + * r and a may point to the same object, but neither may point to the object pointed + * to by b. The magnitudes of a and b must not exceed 8. + * Performs {r = a * b} + * On output, r will have magnitude 1, but won't be normalized. + */ +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); + +/** Square a field element. + * + * On input, a must be a valid field element; r does not need to be initialized. The magnitude + * of a must not exceed 8. + * Performs {r = a**2} + * On output, r will have magnitude 1, but won't be normalized. + */ +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); + +/** Compute a square root of a field element. + * + * On input, a must be a valid field element with magnitude<=8; r need not be initialized. + * If sqrt(a) exists, performs {r = sqrt(a)} and returns 1. + * Otherwise, sqrt(-a) exists. The function performs {r = sqrt(-a)} and returns 0. + * The resulting value represented by r will be a square itself. + * Variables r and a must not point to the same object. + * On output, r will have magnitude 1 but will not be normalized. + */ +static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a); + +/** Compute the modular inverse of a field element. + * + * On input, a must be a valid field element; r need not be initialized. + * Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its + * inverse). + * On output, r will have magnitude (a.magnitude != 0) and be normalized. + */ +static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); + +/** Compute the modular inverse of a field element, without constant-time guarantee. + * + * Behaves identically to secp256k1_fe_inv, but is not constant-time in a. + */ +static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); + +/** Convert a field element to secp256k1_fe_storage. + * + * On input, a must be a valid normalized field element. + * Performs {r = a}. + */ +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); + +/** Convert a field element back from secp256k1_fe_storage. + * + * On input, r need not be initialized. + * Performs {r = a}. + * On output, r will be normalized and will have magnitude 1. + */ +static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); + +/** Conditionally move a field element in constant time. + * + * On input, both r and a must be valid field elements. Flag must be 0 or 1. + * Performs {r = flag ? a : r}. + * + * On output, r's magnitude will be the maximum of both input magnitudes. + * It will be normalized if and only if both inputs were normalized. + */ +static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); + +/** Halve the value of a field element modulo the field prime in constant-time. + * + * On input, r must be a valid field element. + * On output, r will be normalized and have magnitude floor(m/2) + 1 where m is + * the magnitude of r on input. + */ +static void secp256k1_fe_half(secp256k1_fe *r); + +/** Sets r to a field element with magnitude m, normalized if (and only if) m==0. + * The value is chosen so that it is likely to trigger edge cases related to + * internal overflows. */ +static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); + +/** Determine whether a is a square (modulo p). + * + * On input, a must be a valid field element. + */ +static int secp256k1_fe_is_square_var(const secp256k1_fe *a); + +/** Check invariants on a field element (no-op unless VERIFY is enabled). */ +static void secp256k1_fe_verify(const secp256k1_fe *a); +#define SECP256K1_FE_VERIFY(a) secp256k1_fe_verify(a) + +/** Check that magnitude of a is at most m (no-op unless VERIFY is enabled). */ +static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m); +#define SECP256K1_FE_VERIFY_MAGNITUDE(a, m) secp256k1_fe_verify_magnitude(a, m) + +#endif /* SECP256K1_FIELD_H */ diff --git a/external/secp256k1/src/field_10x26.h b/external/secp256k1/src/field_10x26.h new file mode 100644 index 00000000000..203c10167c3 --- /dev/null +++ b/external/secp256k1/src/field_10x26.h @@ -0,0 +1,57 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H + +#include + +/** This field implementation represents the value as 10 uint32_t limbs in base + * 2^26. */ +typedef struct { + /* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is + * normalized. */ + uint32_t n[10]; + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^26 - 1) for i=0..8 + * n[9] <= 2 * m * (2^22 - 1) + * + * Normalized requires: + * n[i] <= (2^26 - 1) for i=0..8 + * sum(i=0..9, n[i] << (i*26)) < p + * (together these imply n[9] <= 2^22 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS +} secp256k1_fe; + +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) & 0x3FFFFFFUL, \ + (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \ + (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \ + (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \ + (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \ + (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \ + (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \ + (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \ + (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \ + (((uint32_t)d7) >> 10) \ +} + +typedef struct { + uint32_t n[8]; +} secp256k1_fe_storage; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} +#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] + +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/src/secp256k1/src/field_10x26_impl.h b/external/secp256k1/src/field_10x26_impl.h similarity index 76% rename from src/secp256k1/src/field_10x26_impl.h rename to external/secp256k1/src/field_10x26_impl.h index 5fb092f1beb..ea14c273187 100644 --- a/src/secp256k1/src/field_10x26_impl.h +++ b/external/secp256k1/src/field_10x26_impl.h @@ -1,46 +1,56 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H +#include "checkmem.h" #include "util.h" -#include "num.h" #include "field.h" +#include "modinv32_impl.h" #ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe *a) { +static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint32_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; - r &= (d[0] <= 0x3FFFFFFUL * m); - r &= (d[1] <= 0x3FFFFFFUL * m); - r &= (d[2] <= 0x3FFFFFFUL * m); - r &= (d[3] <= 0x3FFFFFFUL * m); - r &= (d[4] <= 0x3FFFFFFUL * m); - r &= (d[5] <= 0x3FFFFFFUL * m); - r &= (d[6] <= 0x3FFFFFFUL * m); - r &= (d[7] <= 0x3FFFFFFUL * m); - r &= (d[8] <= 0x3FFFFFFUL * m); - r &= (d[9] <= 0x03FFFFFUL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 32); + int m = a->normalized ? 1 : 2 * a->magnitude; + VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m); if (a->normalized) { - r &= (a->magnitude <= 1); - if (r && (d[9] == 0x03FFFFFUL)) { + if (d[9] == 0x03FFFFFUL) { uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; if (mid == 0x3FFFFFFUL) { - r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); + VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); } } } - VERIFY_CHECK(r == 1); } #endif -static void secp256k1_fe_normalize(secp256k1_fe *r) { +static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { + r->n[0] = 0x3FFFFFFUL * 2 * m; + r->n[1] = 0x3FFFFFFUL * 2 * m; + r->n[2] = 0x3FFFFFFUL * 2 * m; + r->n[3] = 0x3FFFFFFUL * 2 * m; + r->n[4] = 0x3FFFFFFUL * 2 * m; + r->n[5] = 0x3FFFFFFUL * 2 * m; + r->n[6] = 0x3FFFFFFUL * 2 * m; + r->n[7] = 0x3FFFFFFUL * 2 * m; + r->n[8] = 0x3FFFFFFUL * 2 * m; + r->n[9] = 0x03FFFFFUL * 2 * m; +} + +static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -87,15 +97,9 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -119,14 +123,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_normalize_var(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -174,15 +173,9 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -211,7 +204,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; uint32_t z0, z1; uint32_t x; @@ -263,52 +256,22 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { +SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { const uint32_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { - int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif - for (i=0; i<10; i++) { - a->n[i] = 0; - } -} - -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif for (i = 9; i >= 0; i--) { if (a->n[i] > b->n[i]) { return 1; @@ -320,53 +283,69 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - int i; - r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; - r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; - for (i=0; i<32; i++) { - int j; - for (j=0; j<4; j++) { - int limb = (8*i+2*j)/26; - int shift = (8*i+2*j)%26; - r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift; - } - } - if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) { - return 0; - } -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif - return 1; +static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { + r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); + r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); + r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); + r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18); + r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24); + r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22); + r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20); + r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18); + r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); + r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); +} + +static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { + secp256k1_fe_impl_set_b32_mod(r, a); + return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { - int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif - for (i=0; i<32; i++) { - int j; - int c = 0; - for (j=0; j<4; j++) { - int limb = (8*i+2*j)/26; - int shift = (8*i+2*j)%26; - c |= ((a->n[limb] >> shift) & 0x3) << (2 * j); - } - r[31-i] = c; - } +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { + r[0] = (a->n[9] >> 14) & 0xff; + r[1] = (a->n[9] >> 6) & 0xff; + r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); + r[3] = (a->n[8] >> 16) & 0xff; + r[4] = (a->n[8] >> 8) & 0xff; + r[5] = a->n[8] & 0xff; + r[6] = (a->n[7] >> 18) & 0xff; + r[7] = (a->n[7] >> 10) & 0xff; + r[8] = (a->n[7] >> 2) & 0xff; + r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f); + r[10] = (a->n[6] >> 12) & 0xff; + r[11] = (a->n[6] >> 4) & 0xff; + r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf); + r[13] = (a->n[5] >> 14) & 0xff; + r[14] = (a->n[5] >> 6) & 0xff; + r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3); + r[16] = (a->n[4] >> 16) & 0xff; + r[17] = (a->n[4] >> 8) & 0xff; + r[18] = a->n[4] & 0xff; + r[19] = (a->n[3] >> 18) & 0xff; + r[20] = (a->n[3] >> 10) & 0xff; + r[21] = (a->n[3] >> 2) & 0xff; + r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f); + r[23] = (a->n[2] >> 12) & 0xff; + r[24] = (a->n[2] >> 4) & 0xff; + r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf); + r[26] = (a->n[1] >> 14) & 0xff; + r[27] = (a->n[1] >> 6) & 0xff; + r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3); + r[29] = (a->n[0] >> 16) & 0xff; + r[30] = (a->n[0] >> 8) & 0xff; + r[31] = a->n[0] & 0xff; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ + VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); + VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); + VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); + VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m); + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; @@ -377,14 +356,9 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -395,17 +369,9 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[7] *= a; r->n[8] *= a; r->n[9] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; @@ -416,11 +382,10 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f r->n[7] += a->n[7]; r->n[8] += a->n[8]; r->n[9] += a->n[9]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif +} + +SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { + r->n[0] += a; } #if defined(USE_EXTERNAL_ASM) @@ -431,11 +396,7 @@ void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a); #else -#ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) -#else -#define VERIFY_BITS(x, n) do { } while(0) -#endif SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { uint64_t c, d; @@ -465,7 +426,8 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t VERIFY_BITS(b[9], 26); /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. - * px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * for 0 <= x <= 9, px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * for 9 <= x <= 18, px is a shorthand for sum(a[i]*b[x-i], i=(x-9)..9) * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. */ @@ -1041,38 +1003,19 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t } #endif -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(r != b); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { +SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint32_t mask0, mask1; - mask0 = flag + ~((uint32_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); @@ -1084,17 +1027,78 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_ r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); -#ifdef VERIFY - if (a->magnitude > r->magnitude) { - r->magnitude = a->magnitude; - } - r->normalized &= a->normalized; -#endif +} + +static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + uint32_t one = (uint32_t)1; + uint32_t mask = -(t0 & one) >> 6; + + /* Bounds analysis (over the rationals). + * + * Let m = r->magnitude + * C = 0x3FFFFFFUL * 2 + * D = 0x03FFFFFUL * 2 + * + * Initial bounds: t0..t8 <= C * m + * t9 <= D * m + */ + + t0 += 0x3FFFC2FUL & mask; + t1 += 0x3FFFFBFUL & mask; + t2 += mask; + t3 += mask; + t4 += mask; + t5 += mask; + t6 += mask; + t7 += mask; + t8 += mask; + t9 += mask >> 4; + + VERIFY_CHECK((t0 & one) == 0); + + /* t0..t8: added <= C/2 + * t9: added <= D/2 + * + * Current bounds: t0..t8 <= C * (m + 1/2) + * t9 <= D * (m + 1/2) + */ + + r->n[0] = (t0 >> 1) + ((t1 & one) << 25); + r->n[1] = (t1 >> 1) + ((t2 & one) << 25); + r->n[2] = (t2 >> 1) + ((t3 & one) << 25); + r->n[3] = (t3 >> 1) + ((t4 & one) << 25); + r->n[4] = (t4 >> 1) + ((t5 & one) << 25); + r->n[5] = (t5 >> 1) + ((t6 & one) << 25); + r->n[6] = (t6 >> 1) + ((t7 & one) << 25); + r->n[7] = (t7 >> 1) + ((t8 & one) << 25); + r->n[8] = (t8 >> 1) + ((t9 & one) << 25); + r->n[9] = (t9 >> 1); + + /* t0..t8: shifted right and added <= C/4 + 1/2 + * t9: shifted right + * + * Current bounds: t0..t8 <= C * (m/2 + 1/2) + * t9 <= D * (m/2 + 1/4) + * + * Therefore the output magnitude (M) has to be set such that: + * t0..t8: C * M >= C * (m/2 + 1/2) + * t9: D * M >= D * (m/2 + 1/4) + * + * It suffices for all limbs that, for any input magnitude m: + * M >= m/2 + 1/2 + * + * and since we want the smallest such integer value for M: + * M == floor(m/2) + 1 + */ } static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { uint32_t mask0, mask1; - mask0 = flag + ~((uint32_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); @@ -1106,10 +1110,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { r->n[0] = a->n[0] | a->n[1] << 26; r->n[1] = a->n[1] >> 6 | a->n[2] << 20; r->n[2] = a->n[2] >> 12 | a->n[3] << 14; @@ -1120,7 +1121,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe r->n[7] = a->n[8] >> 16 | a->n[9] << 10; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { +static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0x3FFFFFFUL; r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); @@ -1131,10 +1132,101 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); r->n[9] = a->n[7] >> 10; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; -#endif } -#endif +static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) { + const uint32_t M26 = UINT32_MAX >> 6; + const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4], + a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8]; + + /* The output from secp256k1_modinv32{_var} should be normalized to range [0,modulus), and + * have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8). + */ + VERIFY_CHECK(a0 >> 30 == 0); + VERIFY_CHECK(a1 >> 30 == 0); + VERIFY_CHECK(a2 >> 30 == 0); + VERIFY_CHECK(a3 >> 30 == 0); + VERIFY_CHECK(a4 >> 30 == 0); + VERIFY_CHECK(a5 >> 30 == 0); + VERIFY_CHECK(a6 >> 30 == 0); + VERIFY_CHECK(a7 >> 30 == 0); + VERIFY_CHECK(a8 >> 16 == 0); + + r->n[0] = a0 & M26; + r->n[1] = (a0 >> 26 | a1 << 4) & M26; + r->n[2] = (a1 >> 22 | a2 << 8) & M26; + r->n[3] = (a2 >> 18 | a3 << 12) & M26; + r->n[4] = (a3 >> 14 | a4 << 16) & M26; + r->n[5] = (a4 >> 10 | a5 << 20) & M26; + r->n[6] = (a5 >> 6 | a6 << 24) & M26; + r->n[7] = (a6 >> 2 ) & M26; + r->n[8] = (a6 >> 28 | a7 << 2) & M26; + r->n[9] = (a7 >> 24 | a8 << 6); +} + +static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) { + const uint32_t M30 = UINT32_MAX >> 2; + const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4], + a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9]; + + r->v[0] = (a0 | a1 << 26) & M30; + r->v[1] = (a1 >> 4 | a2 << 22) & M30; + r->v[2] = (a2 >> 8 | a3 << 18) & M30; + r->v[3] = (a3 >> 12 | a4 << 14) & M30; + r->v[4] = (a4 >> 16 | a5 << 10) & M30; + r->v[5] = (a5 >> 20 | a6 << 6) & M30; + r->v[6] = (a6 >> 24 | a7 << 2 + | a8 << 28) & M30; + r->v[7] = (a8 >> 2 | a9 << 24) & M30; + r->v[8] = a9 >> 6; +} + +static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = { + {{-0x3D1, -4, 0, 0, 0, 0, 0, 0, 65536}}, + 0x2DDACACFL +}; + +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; + secp256k1_modinv32_signed30 s; + + secp256k1_fe_normalize(&tmp); + secp256k1_fe_to_signed30(&s, &tmp); + secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe); + secp256k1_fe_from_signed30(r, &s); +} + +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; + secp256k1_modinv32_signed30 s; + + secp256k1_fe_normalize_var(&tmp); + secp256k1_fe_to_signed30(&s, &tmp); + secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe); + secp256k1_fe_from_signed30(r, &s); +} + +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { + secp256k1_fe tmp; + secp256k1_modinv32_signed30 s; + int jac, ret; + + tmp = *x; + secp256k1_fe_normalize_var(&tmp); + /* secp256k1_jacobi32_maybe_var cannot deal with input 0. */ + if (secp256k1_fe_is_zero(&tmp)) return 1; + secp256k1_fe_to_signed30(&s, &tmp); + jac = secp256k1_jacobi32_maybe_var(&s, &secp256k1_const_modinfo_fe); + if (jac == 0) { + /* secp256k1_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back + * to computing a square root. This should be extremely rare with random + * input (except in VERIFY mode, where a lower iteration count is used). */ + secp256k1_fe dummy; + ret = secp256k1_fe_sqrt(&dummy, &tmp); + } else { + ret = jac >= 0; + } + return ret; +} + +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/external/secp256k1/src/field_5x52.h b/external/secp256k1/src/field_5x52.h new file mode 100644 index 00000000000..f20c246fdd5 --- /dev/null +++ b/external/secp256k1/src/field_5x52.h @@ -0,0 +1,62 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H + +#include + +/** This field implementation represents the value as 5 uint64_t limbs in base + * 2^52. */ +typedef struct { + /* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is + * normalized. */ + uint64_t n[5]; + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^52 - 1) for i=0..3 + * n[4] <= 2 * m * (2^48 - 1) + * + * Normalized requires: + * n[i] <= (2^52 - 1) for i=0..3 + * sum(i=0..4, n[i] << (i*52)) < p + * (together these imply n[4] <= 2^48 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS +} secp256k1_fe; + +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \ + ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \ + ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \ + ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \ + ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ +} + +typedef struct { + uint64_t n[4]; +} secp256k1_fe_storage; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ + (d0) | (((uint64_t)(d1)) << 32), \ + (d2) | (((uint64_t)(d3)) << 32), \ + (d4) | (((uint64_t)(d5)) << 32), \ + (d6) | (((uint64_t)(d7)) << 32) \ +}} + +#define SECP256K1_FE_STORAGE_CONST_GET(d) \ + (uint32_t)(d.n[3] >> 32), (uint32_t)d.n[3], \ + (uint32_t)(d.n[2] >> 32), (uint32_t)d.n[2], \ + (uint32_t)(d.n[1] >> 32), (uint32_t)d.n[1], \ + (uint32_t)(d.n[0] >> 32), (uint32_t)d.n[0] + +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/external/secp256k1/src/field_5x52_impl.h b/external/secp256k1/src/field_5x52_impl.h new file mode 100644 index 00000000000..46dca6b9814 --- /dev/null +++ b/external/secp256k1/src/field_5x52_impl.h @@ -0,0 +1,522 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H + +#include "checkmem.h" +#include "util.h" +#include "field.h" +#include "modinv64_impl.h" + +#include "field_5x52_int128_impl.h" + +#ifdef VERIFY +static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { + const uint64_t *d = a->n; + int m = a->normalized ? 1 : 2 * a->magnitude; + /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m); + if (a->normalized) { + if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { + VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL); + } + } +} +#endif + +static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { + r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m; + r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m; + r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m; + r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m; + r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m; +} + +static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) + & (t0 >= 0xFFFFEFFFFFC2FULL)); + + /* Apply the final reduction (for constant-time behaviour, we do it always) */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ + VERIFY_CHECK(t4 >> 48 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t4 &= 0x0FFFFFFFFFFFFULL; + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; +} + +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; +} + +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) + & (t0 >= 0xFFFFEFFFFFC2FULL)); + + if (x) { + t0 += 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ + VERIFY_CHECK(t4 >> 48 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t4 &= 0x0FFFFFFFFFFFFULL; + } + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; +} + +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint64_t z0, z1; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { + uint64_t t0, t1, t2, t3, t4; + uint64_t z0, z1; + uint64_t x; + + t0 = r->n[0]; + t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + x = t4 >> 48; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + z0 = t0 & 0xFFFFFFFFFFFFFULL; + z1 = z0 ^ 0x1000003D0ULL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) { + return 0; + } + + t1 = r->n[1]; + t2 = r->n[2]; + t3 = r->n[3]; + + t4 &= 0x0FFFFFFFFFFFFULL; + + t1 += (t0 >> 52); + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { + r->n[0] = a; + r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; +} + +SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { + const uint64_t *t = a->n; + return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; +} + +SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { + return a->n[0] & 1; +} + +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { + int i; + for (i = 4; i >= 0; i--) { + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } + } + return 0; +} + +static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { + r->n[0] = (uint64_t)a[31] + | ((uint64_t)a[30] << 8) + | ((uint64_t)a[29] << 16) + | ((uint64_t)a[28] << 24) + | ((uint64_t)a[27] << 32) + | ((uint64_t)a[26] << 40) + | ((uint64_t)(a[25] & 0xF) << 48); + r->n[1] = (uint64_t)((a[25] >> 4) & 0xF) + | ((uint64_t)a[24] << 4) + | ((uint64_t)a[23] << 12) + | ((uint64_t)a[22] << 20) + | ((uint64_t)a[21] << 28) + | ((uint64_t)a[20] << 36) + | ((uint64_t)a[19] << 44); + r->n[2] = (uint64_t)a[18] + | ((uint64_t)a[17] << 8) + | ((uint64_t)a[16] << 16) + | ((uint64_t)a[15] << 24) + | ((uint64_t)a[14] << 32) + | ((uint64_t)a[13] << 40) + | ((uint64_t)(a[12] & 0xF) << 48); + r->n[3] = (uint64_t)((a[12] >> 4) & 0xF) + | ((uint64_t)a[11] << 4) + | ((uint64_t)a[10] << 12) + | ((uint64_t)a[9] << 20) + | ((uint64_t)a[8] << 28) + | ((uint64_t)a[7] << 36) + | ((uint64_t)a[6] << 44); + r->n[4] = (uint64_t)a[5] + | ((uint64_t)a[4] << 8) + | ((uint64_t)a[3] << 16) + | ((uint64_t)a[2] << 24) + | ((uint64_t)a[1] << 32) + | ((uint64_t)a[0] << 40); +} + +static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { + secp256k1_fe_impl_set_b32_mod(r, a); + return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); +} + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { + r[0] = (a->n[4] >> 40) & 0xFF; + r[1] = (a->n[4] >> 32) & 0xFF; + r[2] = (a->n[4] >> 24) & 0xFF; + r[3] = (a->n[4] >> 16) & 0xFF; + r[4] = (a->n[4] >> 8) & 0xFF; + r[5] = a->n[4] & 0xFF; + r[6] = (a->n[3] >> 44) & 0xFF; + r[7] = (a->n[3] >> 36) & 0xFF; + r[8] = (a->n[3] >> 28) & 0xFF; + r[9] = (a->n[3] >> 20) & 0xFF; + r[10] = (a->n[3] >> 12) & 0xFF; + r[11] = (a->n[3] >> 4) & 0xFF; + r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4); + r[13] = (a->n[2] >> 40) & 0xFF; + r[14] = (a->n[2] >> 32) & 0xFF; + r[15] = (a->n[2] >> 24) & 0xFF; + r[16] = (a->n[2] >> 16) & 0xFF; + r[17] = (a->n[2] >> 8) & 0xFF; + r[18] = a->n[2] & 0xFF; + r[19] = (a->n[1] >> 44) & 0xFF; + r[20] = (a->n[1] >> 36) & 0xFF; + r[21] = (a->n[1] >> 28) & 0xFF; + r[22] = (a->n[1] >> 20) & 0xFF; + r[23] = (a->n[1] >> 12) & 0xFF; + r[24] = (a->n[1] >> 4) & 0xFF; + r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4); + r[26] = (a->n[0] >> 40) & 0xFF; + r[27] = (a->n[0] >> 32) & 0xFF; + r[28] = (a->n[0] >> 24) & 0xFF; + r[29] = (a->n[0] >> 16) & 0xFF; + r[30] = (a->n[0] >> 8) & 0xFF; + r[31] = a->n[0] & 0xFF; +} + +SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ + VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); + VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); + VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m); + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ + r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; + r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; + r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; + r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; + r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; +} + +SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) { + r->n[0] *= a; + r->n[1] *= a; + r->n[2] *= a; + r->n[3] *= a; + r->n[4] *= a; +} + +SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { + r->n[0] += a; +} + +SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { + r->n[0] += a->n[0]; + r->n[1] += a->n[1]; + r->n[2] += a->n[2]; + r->n[3] += a->n[3]; + r->n[4] += a->n[4]; +} + +SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { + secp256k1_fe_mul_inner(r->n, a->n, b->n); +} + +SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe_sqr_inner(r->n, a->n); +} + +SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { + uint64_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); +} + +static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + uint64_t one = (uint64_t)1; + uint64_t mask = -(t0 & one) >> 12; + + /* Bounds analysis (over the rationals). + * + * Let m = r->magnitude + * C = 0xFFFFFFFFFFFFFULL * 2 + * D = 0x0FFFFFFFFFFFFULL * 2 + * + * Initial bounds: t0..t3 <= C * m + * t4 <= D * m + */ + + t0 += 0xFFFFEFFFFFC2FULL & mask; + t1 += mask; + t2 += mask; + t3 += mask; + t4 += mask >> 4; + + VERIFY_CHECK((t0 & one) == 0); + + /* t0..t3: added <= C/2 + * t4: added <= D/2 + * + * Current bounds: t0..t3 <= C * (m + 1/2) + * t4 <= D * (m + 1/2) + */ + + r->n[0] = (t0 >> 1) + ((t1 & one) << 51); + r->n[1] = (t1 >> 1) + ((t2 & one) << 51); + r->n[2] = (t2 >> 1) + ((t3 & one) << 51); + r->n[3] = (t3 >> 1) + ((t4 & one) << 51); + r->n[4] = (t4 >> 1); + + /* t0..t3: shifted right and added <= C/4 + 1/2 + * t4: shifted right + * + * Current bounds: t0..t3 <= C * (m/2 + 1/2) + * t4 <= D * (m/2 + 1/4) + * + * Therefore the output magnitude (M) has to be set such that: + * t0..t3: C * M >= C * (m/2 + 1/2) + * t4: D * M >= D * (m/2 + 1/4) + * + * It suffices for all limbs that, for any input magnitude m: + * M >= m/2 + 1/2 + * + * and since we want the smallest such integer value for M: + * M == floor(m/2) + 1 + */ +} + +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { + uint64_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); +} + +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { + r->n[0] = a->n[0] | a->n[1] << 52; + r->n[1] = a->n[1] >> 12 | a->n[2] << 40; + r->n[2] = a->n[2] >> 24 | a->n[3] << 28; + r->n[3] = a->n[3] >> 36 | a->n[4] << 16; +} + +static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { + r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; + r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); + r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); + r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); + r->n[4] = a->n[3] >> 16; +} + +static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) { + const uint64_t M52 = UINT64_MAX >> 12; + const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4]; + + /* The output from secp256k1_modinv64{_var} should be normalized to range [0,modulus), and + * have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4). + */ + VERIFY_CHECK(a0 >> 62 == 0); + VERIFY_CHECK(a1 >> 62 == 0); + VERIFY_CHECK(a2 >> 62 == 0); + VERIFY_CHECK(a3 >> 62 == 0); + VERIFY_CHECK(a4 >> 8 == 0); + + r->n[0] = a0 & M52; + r->n[1] = (a0 >> 52 | a1 << 10) & M52; + r->n[2] = (a1 >> 42 | a2 << 20) & M52; + r->n[3] = (a2 >> 32 | a3 << 30) & M52; + r->n[4] = (a3 >> 22 | a4 << 40); +} + +static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) { + const uint64_t M62 = UINT64_MAX >> 2; + const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4]; + + r->v[0] = (a0 | a1 << 52) & M62; + r->v[1] = (a1 >> 10 | a2 << 42) & M62; + r->v[2] = (a2 >> 20 | a3 << 32) & M62; + r->v[3] = (a3 >> 30 | a4 << 22) & M62; + r->v[4] = a4 >> 40; +} + +static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = { + {{-0x1000003D1LL, 0, 0, 0, 256}}, + 0x27C7F6E22DDACACFLL +}; + +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; + secp256k1_modinv64_signed62 s; + + secp256k1_fe_normalize(&tmp); + secp256k1_fe_to_signed62(&s, &tmp); + secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe); + secp256k1_fe_from_signed62(r, &s); +} + +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; + secp256k1_modinv64_signed62 s; + + secp256k1_fe_normalize_var(&tmp); + secp256k1_fe_to_signed62(&s, &tmp); + secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe); + secp256k1_fe_from_signed62(r, &s); +} + +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { + secp256k1_fe tmp; + secp256k1_modinv64_signed62 s; + int jac, ret; + + tmp = *x; + secp256k1_fe_normalize_var(&tmp); + /* secp256k1_jacobi64_maybe_var cannot deal with input 0. */ + if (secp256k1_fe_is_zero(&tmp)) return 1; + secp256k1_fe_to_signed62(&s, &tmp); + jac = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe); + if (jac == 0) { + /* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back + * to computing a square root. This should be extremely rare with random + * input (except in VERIFY mode, where a lower iteration count is used). */ + secp256k1_fe dummy; + ret = secp256k1_fe_sqrt(&dummy, &tmp); + } else { + ret = jac >= 0; + } + return ret; +} + +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/external/secp256k1/src/field_5x52_int128_impl.h b/external/secp256k1/src/field_5x52_int128_impl.h new file mode 100644 index 00000000000..f23f8ee1c44 --- /dev/null +++ b/external/secp256k1/src/field_5x52_int128_impl.h @@ -0,0 +1,274 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H + +#include + +#include "int128.h" +#include "util.h" + +#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) +#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n))) + +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { + secp256k1_uint128 c, d; + uint64_t t3, t4, tx, u0; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + VERIFY_BITS(b[0], 56); + VERIFY_BITS(b[1], 56); + VERIFY_BITS(b[2], 56); + VERIFY_BITS(b[3], 56); + VERIFY_BITS(b[4], 52); + VERIFY_CHECK(r != b); + VERIFY_CHECK(a != b); + + /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4) + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + secp256k1_u128_mul(&d, a0, b[3]); + secp256k1_u128_accum_mul(&d, a1, b[2]); + secp256k1_u128_accum_mul(&d, a2, b[1]); + secp256k1_u128_accum_mul(&d, a3, b[0]); + VERIFY_BITS_128(&d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + secp256k1_u128_mul(&c, a4, b[4]); + VERIFY_BITS_128(&c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64); + VERIFY_BITS_128(&d, 115); + VERIFY_BITS_128(&c, 48); + /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); + VERIFY_BITS(t3, 52); + VERIFY_BITS_128(&d, 63); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + secp256k1_u128_accum_mul(&d, a0, b[4]); + secp256k1_u128_accum_mul(&d, a1, b[3]); + secp256k1_u128_accum_mul(&d, a2, b[2]); + secp256k1_u128_accum_mul(&d, a3, b[1]); + secp256k1_u128_accum_mul(&d, a4, b[0]); + VERIFY_BITS_128(&d, 115); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c)); + VERIFY_BITS_128(&d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); + VERIFY_BITS(t4, 52); + VERIFY_BITS_128(&d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + secp256k1_u128_mul(&c, a0, b[0]); + VERIFY_BITS_128(&c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + secp256k1_u128_accum_mul(&d, a1, b[4]); + secp256k1_u128_accum_mul(&d, a2, b[3]); + secp256k1_u128_accum_mul(&d, a3, b[2]); + secp256k1_u128_accum_mul(&d, a4, b[1]); + VERIFY_BITS_128(&d, 114); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); + VERIFY_BITS(u0, 52); + VERIFY_BITS_128(&d, 62); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + secp256k1_u128_accum_mul(&c, u0, R >> 4); + VERIFY_BITS_128(&c, 113); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); + VERIFY_BITS(r[0], 52); + VERIFY_BITS_128(&c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + secp256k1_u128_accum_mul(&c, a0, b[1]); + secp256k1_u128_accum_mul(&c, a1, b[0]); + VERIFY_BITS_128(&c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + secp256k1_u128_accum_mul(&d, a2, b[4]); + secp256k1_u128_accum_mul(&d, a3, b[3]); + secp256k1_u128_accum_mul(&d, a4, b[2]); + VERIFY_BITS_128(&d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); + VERIFY_BITS(r[1], 52); + VERIFY_BITS_128(&c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + secp256k1_u128_accum_mul(&c, a0, b[2]); + secp256k1_u128_accum_mul(&c, a1, b[1]); + secp256k1_u128_accum_mul(&c, a2, b[0]); + VERIFY_BITS_128(&c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + secp256k1_u128_accum_mul(&d, a3, b[4]); + secp256k1_u128_accum_mul(&d, a4, b[3]); + VERIFY_BITS_128(&d, 114); + /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 50); + /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); + VERIFY_BITS(r[2], 52); + VERIFY_BITS_128(&c, 63); + /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d)); + secp256k1_u128_accum_u64(&c, t3); + VERIFY_BITS_128(&c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); + VERIFY_BITS(r[3], 52); + VERIFY_BITS_128(&c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = secp256k1_u128_to_u64(&c) + t4; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { + secp256k1_uint128 c, d; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + uint64_t t3, t4, tx, u0; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + + /** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * px is a shorthand for sum(a[i]*a[x-i], i=0..x). + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + secp256k1_u128_mul(&d, a0*2, a3); + secp256k1_u128_accum_mul(&d, a1*2, a2); + VERIFY_BITS_128(&d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + secp256k1_u128_mul(&c, a4, a4); + VERIFY_BITS_128(&c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64); + VERIFY_BITS_128(&d, 115); + VERIFY_BITS_128(&c, 48); + /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); + VERIFY_BITS(t3, 52); + VERIFY_BITS_128(&d, 63); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + a4 *= 2; + secp256k1_u128_accum_mul(&d, a0, a4); + secp256k1_u128_accum_mul(&d, a1*2, a3); + secp256k1_u128_accum_mul(&d, a2, a2); + VERIFY_BITS_128(&d, 115); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c)); + VERIFY_BITS_128(&d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); + VERIFY_BITS(t4, 52); + VERIFY_BITS_128(&d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + secp256k1_u128_mul(&c, a0, a0); + VERIFY_BITS_128(&c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + secp256k1_u128_accum_mul(&d, a1, a4); + secp256k1_u128_accum_mul(&d, a2*2, a3); + VERIFY_BITS_128(&d, 114); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); + VERIFY_BITS(u0, 52); + VERIFY_BITS_128(&d, 62); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + secp256k1_u128_accum_mul(&c, u0, R >> 4); + VERIFY_BITS_128(&c, 113); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); + VERIFY_BITS(r[0], 52); + VERIFY_BITS_128(&c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + a0 *= 2; + secp256k1_u128_accum_mul(&c, a0, a1); + VERIFY_BITS_128(&c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + secp256k1_u128_accum_mul(&d, a2, a4); + secp256k1_u128_accum_mul(&d, a3, a3); + VERIFY_BITS_128(&d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); + VERIFY_BITS(r[1], 52); + VERIFY_BITS_128(&c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + secp256k1_u128_accum_mul(&c, a0, a2); + secp256k1_u128_accum_mul(&c, a1, a1); + VERIFY_BITS_128(&c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + secp256k1_u128_accum_mul(&d, a3, a4); + VERIFY_BITS_128(&d, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 50); + /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); + VERIFY_BITS(r[2], 52); + VERIFY_BITS_128(&c, 63); + /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d)); + secp256k1_u128_accum_u64(&c, t3); + VERIFY_BITS_128(&c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); + VERIFY_BITS(r[3], 52); + VERIFY_BITS_128(&c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = secp256k1_u128_to_u64(&c) + t4; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/external/secp256k1/src/field_impl.h b/external/secp256k1/src/field_impl.h new file mode 100644 index 00000000000..896507a3a49 --- /dev/null +++ b/external/secp256k1/src/field_impl.h @@ -0,0 +1,457 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_FIELD_IMPL_H +#define SECP256K1_FIELD_IMPL_H + +#include "field.h" +#include "util.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +#include "field_5x52_impl.h" +#elif defined(SECP256K1_WIDEMUL_INT64) +#include "field_10x26_impl.h" +#else +#error "Please select wide multiplication implementation" +#endif + +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { + secp256k1_memclear(a, sizeof(secp256k1_fe)); +} + +SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); + SECP256K1_FE_VERIFY_MAGNITUDE(b, 31); + + secp256k1_fe_negate(&na, a, 1); + secp256k1_fe_add(&na, b); + return secp256k1_fe_normalizes_to_zero(&na); +} + +static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a) { + /** Given that p is congruent to 3 mod 4, we can compute the square root of + * a mod p as the (p+1)/4'th power of a. + * + * As (p+1)/4 is an even number, it will have the same result for a and for + * (-a). Only one of these two numbers actually has a square root however, + * so we test at the end by squaring and comparing to the input. + * Also because (p+1)/4 is an even number, the computed square root is + * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). + */ + secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j, ret; + + VERIFY_CHECK(r != a); + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); + + /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in + * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: + * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + */ + + secp256k1_fe_sqr(&x2, a); + secp256k1_fe_mul(&x2, &x2, a); + + secp256k1_fe_sqr(&x3, &x2); + secp256k1_fe_mul(&x3, &x3, a); + + x6 = x3; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x6, &x6); + } + secp256k1_fe_mul(&x6, &x6, &x3); + + x9 = x6; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x9, &x9); + } + secp256k1_fe_mul(&x9, &x9, &x3); + + x11 = x9; + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&x11, &x11); + } + secp256k1_fe_mul(&x11, &x11, &x2); + + x22 = x11; + for (j=0; j<11; j++) { + secp256k1_fe_sqr(&x22, &x22); + } + secp256k1_fe_mul(&x22, &x22, &x11); + + x44 = x22; + for (j=0; j<22; j++) { + secp256k1_fe_sqr(&x44, &x44); + } + secp256k1_fe_mul(&x44, &x44, &x22); + + x88 = x44; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x88, &x88); + } + secp256k1_fe_mul(&x88, &x88, &x44); + + x176 = x88; + for (j=0; j<88; j++) { + secp256k1_fe_sqr(&x176, &x176); + } + secp256k1_fe_mul(&x176, &x176, &x88); + + x220 = x176; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x220, &x220); + } + secp256k1_fe_mul(&x220, &x220, &x44); + + x223 = x220; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x223, &x223); + } + secp256k1_fe_mul(&x223, &x223, &x3); + + /* The final result is then assembled using a sliding window over the blocks. */ + + t1 = x223; + for (j=0; j<23; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x22); + for (j=0; j<6; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x2); + secp256k1_fe_sqr(&t1, &t1); + secp256k1_fe_sqr(r, &t1); + + /* Check that a square root was actually calculated */ + + secp256k1_fe_sqr(&t1, r); + ret = secp256k1_fe_equal(&t1, a); + +#ifdef VERIFY + if (!ret) { + secp256k1_fe_negate(&t1, &t1, 1); + secp256k1_fe_normalize_var(&t1); + VERIFY_CHECK(secp256k1_fe_equal(&t1, a)); + } +#endif + return ret; +} + +#ifndef VERIFY +static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } +static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { (void)a; (void)m; } +#else +static void secp256k1_fe_impl_verify(const secp256k1_fe *a); +static void secp256k1_fe_verify(const secp256k1_fe *a) { + /* Magnitude between 0 and 32. */ + SECP256K1_FE_VERIFY_MAGNITUDE(a, 32); + /* Normalized is 0 or 1. */ + VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1)); + /* If normalized, magnitude must be 0 or 1. */ + if (a->normalized) SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); + /* Invoke implementation-specific checks. */ + secp256k1_fe_impl_verify(a); +} + +static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { + VERIFY_CHECK(m >= 0); + VERIFY_CHECK(m <= 32); + VERIFY_CHECK(a->magnitude <= m); +} + +static void secp256k1_fe_impl_normalize(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); + + secp256k1_fe_impl_normalize(r); + r->magnitude = 1; + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); + + secp256k1_fe_impl_normalize_weak(r); + r->magnitude = 1; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); + + secp256k1_fe_impl_normalize_var(r); + r->magnitude = 1; + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); +} + +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r); +SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); + + return secp256k1_fe_impl_normalizes_to_zero(r); +} + +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r); +SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); + + return secp256k1_fe_impl_normalizes_to_zero_var(r); +} + +static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + + secp256k1_fe_impl_set_int(r, a); + r->magnitude = (a != 0); + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + SECP256K1_FE_VERIFY(r); + + secp256k1_fe_impl_add_int(r, a); + r->magnitude += 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a); +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + return secp256k1_fe_impl_is_zero(a); +} + +static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a); +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + return secp256k1_fe_impl_is_odd(a); +} + +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); +SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + + return secp256k1_fe_impl_cmp_var(a, b); +} + +static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a); +SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { + secp256k1_fe_impl_set_b32_mod(r, a); + r->magnitude = 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a); +SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { + if (secp256k1_fe_impl_set_b32_limit(r, a)) { + r->magnitude = 1; + r->normalized = 1; + SECP256K1_FE_VERIFY(r); + return 1; + } else { + /* Mark the output field element as invalid. */ + r->magnitude = -1; + return 0; + } +} + +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + secp256k1_fe_impl_get_b32(r, a); +} + +static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m); +SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(m >= 0 && m <= 31); + SECP256K1_FE_VERIFY_MAGNITUDE(a, m); + + secp256k1_fe_impl_negate_unchecked(r, a, m); + r->magnitude = m + 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) { + SECP256K1_FE_VERIFY(r); + + VERIFY_CHECK(a >= 0 && a <= 32); + VERIFY_CHECK(a*r->magnitude <= 32); + secp256k1_fe_impl_mul_int_unchecked(r, a); + r->magnitude *= a; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(r); + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(r->magnitude + a->magnitude <= 32); + + secp256k1_fe_impl_add(r, a); + r->magnitude += a->magnitude; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); +SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); + SECP256K1_FE_VERIFY_MAGNITUDE(b, 8); + VERIFY_CHECK(r != b); + VERIFY_CHECK(a != b); + + secp256k1_fe_impl_mul(r, a, b); + r->magnitude = 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); + + secp256k1_fe_impl_sqr(r, a); + r->magnitude = 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); +SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { + VERIFY_CHECK(flag == 0 || flag == 1); + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(r); + + secp256k1_fe_impl_cmov(r, a, flag); + if (a->magnitude > r->magnitude) r->magnitude = a->magnitude; + if (!a->normalized) r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + secp256k1_fe_impl_to_storage(r, a); +} + +static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); +SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { + secp256k1_fe_impl_from_storage(r, a); + r->magnitude = 1; + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x); +SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { + int input_is_zero = secp256k1_fe_normalizes_to_zero(x); + SECP256K1_FE_VERIFY(x); + + secp256k1_fe_impl_inv(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x); +SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + int input_is_zero = secp256k1_fe_normalizes_to_zero(x); + SECP256K1_FE_VERIFY(x); + + secp256k1_fe_impl_inv_var(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); + SECP256K1_FE_VERIFY(r); +} + +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x); +SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { + int ret; + secp256k1_fe tmp = *x, sqrt; + SECP256K1_FE_VERIFY(x); + + ret = secp256k1_fe_impl_is_square_var(x); + secp256k1_fe_normalize_weak(&tmp); + VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp)); + return ret; +} + +static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m); +SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { + VERIFY_CHECK(m >= 0); + VERIFY_CHECK(m <= 32); + + secp256k1_fe_impl_get_bounds(r, m); + r->magnitude = m; + r->normalized = (m == 0); + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_half(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); + SECP256K1_FE_VERIFY_MAGNITUDE(r, 31); + + secp256k1_fe_impl_half(r); + r->magnitude = (r->magnitude >> 1) + 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +#endif /* defined(VERIFY) */ + +#endif /* SECP256K1_FIELD_IMPL_H */ diff --git a/external/secp256k1/src/group.h b/external/secp256k1/src/group.h new file mode 100644 index 00000000000..992ff5c98cf --- /dev/null +++ b/external/secp256k1/src/group.h @@ -0,0 +1,212 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_GROUP_H +#define SECP256K1_GROUP_H + +#include "field.h" + +/** A group element in affine coordinates on the secp256k1 curve, + * or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6. + * Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve. + */ +typedef struct { + secp256k1_fe x; + secp256k1_fe y; + int infinity; /* whether this represents the point at infinity */ +} secp256k1_ge; + +#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} +#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +/** A group element of the secp256k1 curve, in jacobian coordinates. + * Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve. + */ +typedef struct { + secp256k1_fe x; /* actual X: x/z^2 */ + secp256k1_fe y; /* actual Y: y/z^3 */ + secp256k1_fe z; + int infinity; /* whether this represents the point at infinity */ +} secp256k1_gej; + +#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} +#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +typedef struct { + secp256k1_fe_storage x; + secp256k1_fe_storage y; +} secp256k1_ge_storage; + +#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} + +#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) + +/** Maximum allowed magnitudes for group element coordinates + * in affine (x, y) and jacobian (x, y, z) representation. */ +#define SECP256K1_GE_X_MAGNITUDE_MAX 4 +#define SECP256K1_GE_Y_MAGNITUDE_MAX 3 +#define SECP256K1_GEJ_X_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Y_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Z_MAGNITUDE_MAX 1 + +/** Set a group element equal to the point with given X and Y coordinates */ +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); + +/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness + * for Y. Return value indicates whether the result is valid. */ +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); + +/** Determine whether x is a valid X coordinate on the curve. */ +static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x); + +/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */ +static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd); + +/** Check whether a group element is the point at infinity. */ +static int secp256k1_ge_is_infinity(const secp256k1_ge *a); + +/** Check whether a group element is valid (i.e., on the curve). */ +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a); + +/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); + +/** Set a group element equal to another which is given in jacobian coordinates. Constant time. */ +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); + +/** Set a group element equal to another which is given in jacobian coordinates. */ +static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a); + +/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len); + +/** Bring a batch of inputs to the same global z "denominator", based on ratios between + * (omitted) z coordinates of adjacent elements. + * + * Although the elements a[i] are _ge rather than _gej, they actually represent elements + * in Jacobian coordinates with their z coordinates omitted. + * + * Using the notation z(b) to represent the omitted z coordinate of b, the array zr of + * z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len. + * The zr[0] value is unused. + * + * This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]). + * In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the + * a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is + * implicit. + * + * The coordinates of the final element a[len-1] are not changed. + */ +static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr); + +/** Check two group elements (affine) for equality in variable time. */ +static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b); + +/** Set a group element (affine) equal to the point at infinity. */ +static void secp256k1_ge_set_infinity(secp256k1_ge *r); + +/** Set a group element (jacobian) equal to the point at infinity. */ +static void secp256k1_gej_set_infinity(secp256k1_gej *r); + +/** Set a group element (jacobian) equal to another which is given in affine coordinates. */ +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); + +/** Check two group elements (jacobian) for equality in variable time. */ +static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b); + +/** Check two group elements (jacobian and affine) for equality in variable time. */ +static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b); + +/** Compare the X coordinate of a group element (jacobian). + * The magnitude of the group element's X coordinate must not exceed 31. */ +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); + +/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a); + +/** Check whether a group element is the point at infinity. */ +static int secp256k1_gej_is_infinity(const secp256k1_gej *a); + +/** Set r equal to the double of a. Constant time. */ +static void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a); + +/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */ +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b); + +/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient + than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time + guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv); + +/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); + +/** Clear a secp256k1_gej to prevent leaking sensitive information. */ +static void secp256k1_gej_clear(secp256k1_gej *r); + +/** Clear a secp256k1_ge to prevent leaking sensitive information. */ +static void secp256k1_ge_clear(secp256k1_ge *r); + +/** Convert a group element to the storage type. */ +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a); + +/** Convert a group element back from the storage type. */ +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag); + +/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); + +/** Convert a group element that is not infinity to a 64-byte array. The output + * array is platform-dependent. */ +static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a); + +/** Convert a 64-byte array into group element. This function assumes that the + * provided buffer correctly encodes a group element. */ +static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf); + +/** Convert a group element (that is allowed to be infinity) to a 64-byte + * array. The output array is platform-dependent. */ +static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge); + +/** Convert a 64-byte array into a group element. This function assumes that the + * provided buffer is the output of secp256k1_ge_to_bytes_ext. */ +static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data); + +/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve. + * + * In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the + * group, and this function returns always true. + * + * When compiling in exhaustive test mode, a slightly different curve equation is used, leading to a group with a + * (very) small subgroup, and that subgroup is what is used for all cryptographic operations. In that mode, this + * function checks whether a point that is on the curve is in fact also in that subgroup. + */ +static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge); + +/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */ +static void secp256k1_ge_verify(const secp256k1_ge *a); +#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a) + +/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */ +static void secp256k1_gej_verify(const secp256k1_gej *a); +#define SECP256K1_GEJ_VERIFY(a) secp256k1_gej_verify(a) + +#endif /* SECP256K1_GROUP_H */ diff --git a/external/secp256k1/src/group_impl.h b/external/secp256k1/src/group_impl.h new file mode 100644 index 00000000000..c668fb24010 --- /dev/null +++ b/external/secp256k1/src/group_impl.h @@ -0,0 +1,974 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_GROUP_IMPL_H +#define SECP256K1_GROUP_IMPL_H + +#include + +#include "field.h" +#include "group.h" +#include "util.h" + +/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ +#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\ + 0x66625d13, 0x317ffe44, 0x63d32cff, 0x1ca02b9b,\ + 0xe5c6d070, 0x50b4b05e, 0x81cc30db, 0xf5166f0a,\ + 0x1e60e897, 0xa7c00c7c, 0x2df53eb6, 0x98274ff4,\ + 0x64252f42, 0x8ca44e17, 0x3b25418c, 0xff4ab0cf\ +) +#define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\ + 0xa2482ff8, 0x4bf34edf, 0xa51262fd, 0xe57921db,\ + 0xe0dd2cb7, 0xa5914790, 0xbc71631f, 0xc09704fb,\ + 0x942536cb, 0xa3e49492, 0x3a701cc3, 0xee3e443f,\ + 0xdf182aa9, 0x15b8aa6a, 0x166d3b19, 0xba84b045\ +) +#define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\ + 0x7fb07b5c, 0xd07c3bda, 0x553902e2, 0x7a87ea2c,\ + 0x35108a7f, 0x051f41e5, 0xb76abad5, 0x1f2703ad,\ + 0x0a251539, 0x5b4c4438, 0x952a634f, 0xac10dd4d,\ + 0x6d6f4745, 0x98990c27, 0x3a4f3116, 0xd32ff969\ +) +/** Generator for secp256k1, value 'g' defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + */ +#define SECP256K1_G SECP256K1_GE_CONST(\ + 0x79be667e, 0xf9dcbbac, 0x55a06295, 0xce870b07,\ + 0x029bfcdb, 0x2dce28d9, 0x59f2815b, 0x16f81798,\ + 0x483ada77, 0x26a3c465, 0x5da4fbfc, 0x0e1108a8,\ + 0xfd17b448, 0xa6855419, 0x9c47d08f, 0xfb10d4b8\ +) +/* These exhaustive group test orders and generators are chosen such that: + * - The field size is equal to that of secp256k1, so field code is the same. + * - The curve equation is of the form y^2=x^3+B for some small constant B. + * - The subgroup has a generator 2*P, where P.x is as small as possible. + * - The subgroup has size less than 1000 to permit exhaustive testing. + * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y). + */ +#if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 7 + +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_7; +#define SECP256K1_B 6 + +# elif EXHAUSTIVE_TEST_ORDER == 13 + +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_13; +#define SECP256K1_B 2 + +# elif EXHAUSTIVE_TEST_ORDER == 199 + +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_199; +#define SECP256K1_B 4 + +# else +# error No known generator for the specified exhaustive test group order. +# endif +#else + +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G; +#define SECP256K1_B 7 + +#endif +/* End of section generated by sage/gen_exhaustive_groups.sage. */ + +static void secp256k1_ge_verify(const secp256k1_ge *a) { + SECP256K1_FE_VERIFY(&a->x); + SECP256K1_FE_VERIFY(&a->y); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GE_X_MAGNITUDE_MAX); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GE_Y_MAGNITUDE_MAX); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); + (void)a; +} + +static void secp256k1_gej_verify(const secp256k1_gej *a) { + SECP256K1_FE_VERIFY(&a->x); + SECP256K1_FE_VERIFY(&a->y); + SECP256K1_FE_VERIFY(&a->z); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); + (void)a; +} + +/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ +static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { + secp256k1_fe zi2; + secp256k1_fe zi3; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_FE_VERIFY(zi); + VERIFY_CHECK(!a->infinity); + + secp256k1_fe_sqr(&zi2, zi); + secp256k1_fe_mul(&zi3, &zi2, zi); + secp256k1_fe_mul(&r->x, &a->x, &zi2); + secp256k1_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; + + SECP256K1_GE_VERIFY(r); +} + +/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ +static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) { + secp256k1_fe zi2; + secp256k1_fe zi3; + SECP256K1_GE_VERIFY(a); + SECP256K1_FE_VERIFY(zi); + VERIFY_CHECK(!a->infinity); + + secp256k1_fe_sqr(&zi2, zi); + secp256k1_fe_mul(&zi3, &zi2, zi); + secp256k1_fe_mul(&r->x, &a->x, &zi2); + secp256k1_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; + + SECP256K1_GE_VERIFY(r); +} + +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { + SECP256K1_FE_VERIFY(x); + SECP256K1_FE_VERIFY(y); + + r->infinity = 0; + r->x = *x; + r->y = *y; + + SECP256K1_GE_VERIFY(r); +} + +static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { + SECP256K1_GE_VERIFY(a); + + return a->infinity; +} + +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { + SECP256K1_GE_VERIFY(a); + + *r = *a; + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_negate(&r->y, &r->y, 1); + + SECP256K1_GE_VERIFY(r); +} + +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; + SECP256K1_GEJ_VERIFY(a); + + r->infinity = a->infinity; + secp256k1_fe_inv(&a->z, &a->z); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_mul(&z3, &a->z, &z2); + secp256k1_fe_mul(&a->x, &a->x, &z2); + secp256k1_fe_mul(&a->y, &a->y, &z3); + secp256k1_fe_set_int(&a->z, 1); + r->x = a->x; + r->y = a->y; + + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(r); +} + +static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; + SECP256K1_GEJ_VERIFY(a); + + if (secp256k1_gej_is_infinity(a)) { + secp256k1_ge_set_infinity(r); + return; + } + r->infinity = 0; + secp256k1_fe_inv_var(&a->z, &a->z); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_mul(&z3, &a->z, &z2); + secp256k1_fe_mul(&a->x, &a->x, &z2); + secp256k1_fe_mul(&a->y, &a->y, &z3); + secp256k1_fe_set_int(&a->z, 1); + secp256k1_ge_set_xy(r, &a->x, &a->y); + + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(r); +} + +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { + secp256k1_fe u; + size_t i; + size_t last_i = SIZE_MAX; +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GEJ_VERIFY(&a[i]); + } +#endif + + for (i = 0; i < len; i++) { + if (a[i].infinity) { + secp256k1_ge_set_infinity(&r[i]); + } else { + /* Use destination's x coordinates as scratch space */ + if (last_i == SIZE_MAX) { + r[i].x = a[i].z; + } else { + secp256k1_fe_mul(&r[i].x, &r[last_i].x, &a[i].z); + } + last_i = i; + } + } + if (last_i == SIZE_MAX) { + return; + } + secp256k1_fe_inv_var(&u, &r[last_i].x); + + i = last_i; + while (i > 0) { + i--; + if (!a[i].infinity) { + secp256k1_fe_mul(&r[last_i].x, &r[i].x, &u); + secp256k1_fe_mul(&u, &u, &a[last_i].z); + last_i = i; + } + } + VERIFY_CHECK(!a[last_i].infinity); + r[last_i].x = u; + + for (i = 0; i < len; i++) { + if (!a[i].infinity) { + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); + } + } + +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&r[i]); + } +#endif +} + +static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr) { + size_t i; + secp256k1_fe zs; +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&a[i]); + SECP256K1_FE_VERIFY(&zr[i]); + } +#endif + + if (len > 0) { + i = len - 1; + /* Ensure all y values are in weak normal form for fast negation of points */ + secp256k1_fe_normalize_weak(&a[i].y); + zs = zr[i]; + + /* Work our way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + if (i != len - 1) { + secp256k1_fe_mul(&zs, &zs, &zr[i]); + } + i--; + secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs); + } + } + +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&a[i]); + } +#endif +} + +static void secp256k1_gej_set_infinity(secp256k1_gej *r) { + r->infinity = 1; + secp256k1_fe_set_int(&r->x, 0); + secp256k1_fe_set_int(&r->y, 0); + secp256k1_fe_set_int(&r->z, 0); + + SECP256K1_GEJ_VERIFY(r); +} + +static void secp256k1_ge_set_infinity(secp256k1_ge *r) { + r->infinity = 1; + secp256k1_fe_set_int(&r->x, 0); + secp256k1_fe_set_int(&r->y, 0); + + SECP256K1_GE_VERIFY(r); +} + +static void secp256k1_gej_clear(secp256k1_gej *r) { + secp256k1_memclear(r, sizeof(secp256k1_gej)); +} + +static void secp256k1_ge_clear(secp256k1_ge *r) { + secp256k1_memclear(r, sizeof(secp256k1_ge)); +} + +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { + secp256k1_fe x2, x3; + int ret; + SECP256K1_FE_VERIFY(x); + + r->x = *x; + secp256k1_fe_sqr(&x2, x); + secp256k1_fe_mul(&x3, x, &x2); + r->infinity = 0; + secp256k1_fe_add_int(&x3, SECP256K1_B); + ret = secp256k1_fe_sqrt(&r->y, &x3); + secp256k1_fe_normalize_var(&r->y); + if (secp256k1_fe_is_odd(&r->y) != odd) { + secp256k1_fe_negate(&r->y, &r->y, 1); + } + + SECP256K1_GE_VERIFY(r); + return ret; +} + +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { + SECP256K1_GE_VERIFY(a); + + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + secp256k1_fe_set_int(&r->z, 1); + + SECP256K1_GEJ_VERIFY(r); +} + +static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej tmp; + SECP256K1_GEJ_VERIFY(b); + SECP256K1_GEJ_VERIFY(a); + + secp256k1_gej_neg(&tmp, a); + secp256k1_gej_add_var(&tmp, &tmp, b, NULL); + return secp256k1_gej_is_infinity(&tmp); +} + +static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b) { + secp256k1_gej tmp; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + secp256k1_gej_neg(&tmp, a); + secp256k1_gej_add_ge_var(&tmp, &tmp, b, NULL); + return secp256k1_gej_is_infinity(&tmp); +} + +static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b) { + secp256k1_fe tmp; + SECP256K1_GE_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + if (a->infinity != b->infinity) return 0; + if (a->infinity) return 1; + + tmp = a->x; + secp256k1_fe_normalize_weak(&tmp); + if (!secp256k1_fe_equal(&tmp, &b->x)) return 0; + + tmp = a->y; + secp256k1_fe_normalize_weak(&tmp); + if (!secp256k1_fe_equal(&tmp, &b->y)) return 0; + + return 1; +} + +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { + secp256k1_fe r; + SECP256K1_FE_VERIFY(x); + SECP256K1_GEJ_VERIFY(a); + VERIFY_CHECK(!a->infinity); + + secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); + return secp256k1_fe_equal(&r, &a->x); +} + +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { + SECP256K1_GEJ_VERIFY(a); + + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + r->z = a->z; + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_negate(&r->y, &r->y, 1); + + SECP256K1_GEJ_VERIFY(r); +} + +static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { + SECP256K1_GEJ_VERIFY(a); + + return a->infinity; +} + +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { + secp256k1_fe y2, x3; + SECP256K1_GE_VERIFY(a); + + if (a->infinity) { + return 0; + } + /* y^2 = x^3 + 7 */ + secp256k1_fe_sqr(&y2, &a->y); + secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); + secp256k1_fe_add_int(&x3, SECP256K1_B); + return secp256k1_fe_equal(&y2, &x3); +} + +static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) { + /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */ + secp256k1_fe l, s, t; + SECP256K1_GEJ_VERIFY(a); + + r->infinity = a->infinity; + + /* Formula used: + * L = (3/2) * X1^2 + * S = Y1^2 + * T = -X1*S + * X3 = L^2 + 2*T + * Y3 = -(L*(X3 + T) + S^2) + * Z3 = Y1*Z1 + */ + + secp256k1_fe_mul(&r->z, &a->z, &a->y); /* Z3 = Y1*Z1 (1) */ + secp256k1_fe_sqr(&s, &a->y); /* S = Y1^2 (1) */ + secp256k1_fe_sqr(&l, &a->x); /* L = X1^2 (1) */ + secp256k1_fe_mul_int(&l, 3); /* L = 3*X1^2 (3) */ + secp256k1_fe_half(&l); /* L = 3/2*X1^2 (2) */ + secp256k1_fe_negate(&t, &s, 1); /* T = -S (2) */ + secp256k1_fe_mul(&t, &t, &a->x); /* T = -X1*S (1) */ + secp256k1_fe_sqr(&r->x, &l); /* X3 = L^2 (1) */ + secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + T (2) */ + secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + 2*T (3) */ + secp256k1_fe_sqr(&s, &s); /* S' = S^2 (1) */ + secp256k1_fe_add(&t, &r->x); /* T' = X3 + T (4) */ + secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */ + secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */ + secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */ + + SECP256K1_GEJ_VERIFY(r); +} + +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + SECP256K1_GEJ_VERIFY(a); + + /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, + * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have + * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. + * + * Having said this, if this function receives a point on a sextic twist, e.g. by + * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, + * since -6 does have a cube root mod p. For this point, this function will not set + * the infinity flag even though the point doubles to infinity, and the result + * point will be gibberish (z = 0 but infinity = 0). + */ + if (a->infinity) { + secp256k1_gej_set_infinity(r); + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } + return; + } + + if (rzr != NULL) { + *rzr = a->y; + secp256k1_fe_normalize_weak(rzr); + } + + secp256k1_gej_double(r, a); + + SECP256K1_GEJ_VERIFY(r); +} + +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { + /* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ + secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GEJ_VERIFY(b); + + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); + *r = *b; + return; + } + if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } + *r = *a; + return; + } + + secp256k1_fe_sqr(&z22, &b->z); + secp256k1_fe_sqr(&z12, &a->z); + secp256k1_fe_mul(&u1, &a->x, &z22); + secp256k1_fe_mul(&u2, &b->x, &z12); + secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } + secp256k1_gej_set_infinity(r); + } + return; + } + + r->infinity = 0; + secp256k1_fe_mul(&t, &h, &b->z); + if (rzr != NULL) { + *rzr = t; + } + secp256k1_fe_mul(&r->z, &a->z, &t); + + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_negate(&h2, &h2, 1); + secp256k1_fe_mul(&h3, &h2, &h); + secp256k1_fe_mul(&t, &u1, &h2); + + secp256k1_fe_sqr(&r->x, &i); + secp256k1_fe_add(&r->x, &h3); + secp256k1_fe_add(&r->x, &t); + secp256k1_fe_add(&r->x, &t); + + secp256k1_fe_add(&t, &r->x); + secp256k1_fe_mul(&r->y, &t, &i); + secp256k1_fe_mul(&h3, &h3, &s1); + secp256k1_fe_add(&r->y, &h3); + + SECP256K1_GEJ_VERIFY(r); +} + +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { + /* Operations: 8 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ + secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); + secp256k1_gej_set_ge(r, b); + return; + } + if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } + *r = *a; + return; + } + + secp256k1_fe_sqr(&z12, &a->z); + u1 = a->x; + secp256k1_fe_mul(&u2, &b->x, &z12); + s1 = a->y; + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); + secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } + secp256k1_gej_set_infinity(r); + } + return; + } + + r->infinity = 0; + if (rzr != NULL) { + *rzr = h; + } + secp256k1_fe_mul(&r->z, &a->z, &h); + + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_negate(&h2, &h2, 1); + secp256k1_fe_mul(&h3, &h2, &h); + secp256k1_fe_mul(&t, &u1, &h2); + + secp256k1_fe_sqr(&r->x, &i); + secp256k1_fe_add(&r->x, &h3); + secp256k1_fe_add(&r->x, &t); + secp256k1_fe_add(&r->x, &t); + + secp256k1_fe_add(&t, &r->x); + secp256k1_fe_mul(&r->y, &t, &i); + secp256k1_fe_mul(&h3, &h3, &s1); + secp256k1_fe_add(&r->y, &h3); + + SECP256K1_GEJ_VERIFY(r); + if (rzr != NULL) SECP256K1_FE_VERIFY(rzr); +} + +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { + /* Operations: 9 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ + secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + SECP256K1_FE_VERIFY(bzinv); + + if (a->infinity) { + secp256k1_fe bzinv2, bzinv3; + r->infinity = b->infinity; + secp256k1_fe_sqr(&bzinv2, bzinv); + secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv); + secp256k1_fe_mul(&r->x, &b->x, &bzinv2); + secp256k1_fe_mul(&r->y, &b->y, &bzinv3); + secp256k1_fe_set_int(&r->z, 1); + SECP256K1_GEJ_VERIFY(r); + return; + } + if (b->infinity) { + *r = *a; + return; + } + + /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to + * secp256k1's isomorphism we can multiply the Z coordinates on both sides + * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). + * This means that (rx,ry,rz) can be calculated as + * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. + * The variable az below holds the modified Z coordinate for a, which is used + * for the computation of rx and ry, but not for rz. + */ + secp256k1_fe_mul(&az, &a->z, bzinv); + + secp256k1_fe_sqr(&z12, &az); + u1 = a->x; + secp256k1_fe_mul(&u2, &b->x, &z12); + s1 = a->y; + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az); + secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, NULL); + } else { + secp256k1_gej_set_infinity(r); + } + return; + } + + r->infinity = 0; + secp256k1_fe_mul(&r->z, &a->z, &h); + + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_negate(&h2, &h2, 1); + secp256k1_fe_mul(&h3, &h2, &h); + secp256k1_fe_mul(&t, &u1, &h2); + + secp256k1_fe_sqr(&r->x, &i); + secp256k1_fe_add(&r->x, &h3); + secp256k1_fe_add(&r->x, &t); + secp256k1_fe_add(&r->x, &t); + + secp256k1_fe_add(&t, &r->x); + secp256k1_fe_mul(&r->y, &t, &i); + secp256k1_fe_mul(&h3, &h3, &s1); + secp256k1_fe_add(&r->y, &h3); + + SECP256K1_GEJ_VERIFY(r); +} + + +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) { + /* Operations: 7 mul, 5 sqr, 21 add/cmov/half/mul_int/negate/normalizes_to_zero */ + secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; + secp256k1_fe m_alt, rr_alt; + int degenerate; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + VERIFY_CHECK(!b->infinity); + + /* In: + * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. + * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. + * we find as solution for a unified addition/doubling formula: + * lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation. + * x3 = lambda^2 - (x1 + x2) + * 2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2). + * + * Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives: + * U1 = X1*Z2^2, U2 = X2*Z1^2 + * S1 = Y1*Z2^3, S2 = Y2*Z1^3 + * Z = Z1*Z2 + * T = U1+U2 + * M = S1+S2 + * Q = -T*M^2 + * R = T^2-U1*U2 + * X3 = R^2+Q + * Y3 = -(R*(2*X3+Q)+M^4)/2 + * Z3 = M*Z + * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) + * + * This formula has the benefit of being the same for both addition + * of distinct points and doubling. However, it breaks down in the + * case that either point is infinity, or that y1 = -y2. We handle + * these cases in the following ways: + * + * - If b is infinity we simply bail by means of a VERIFY_CHECK. + * + * - If a is infinity, we detect this, and at the end of the + * computation replace the result (which will be meaningless, + * but we compute to be constant-time) with b.x : b.y : 1. + * + * - If a = -b, we have y1 = -y2, which is a degenerate case. + * But here the answer is infinity, so we simply set the + * infinity flag of the result, overriding the computed values + * without even needing to cmov. + * + * - If y1 = -y2 but x1 != x2, which does occur thanks to certain + * properties of our curve (specifically, 1 has nontrivial cube + * roots in our field, and the curve equation has no x coefficient) + * then the answer is not infinity but also not given by the above + * equation. In this case, we cmov in place an alternate expression + * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these + * expressions for lambda are defined, they are equal, and can be + * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) + * then substitution of x^3 + 7 for y^2 (using the curve equation). + * For all pairs of nonzero points (a, b) at least one is defined, + * so this covers everything. + */ + + secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ + u1 = a->x; /* u1 = U1 = X1*Z2^2 (GEJ_X_M) */ + secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ + s1 = a->y; /* s1 = S1 = Y1*Z2^3 (GEJ_Y_M) */ + secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ + secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ + t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (GEJ_X_M+1) */ + m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (GEJ_Y_M+1) */ + secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ + secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 (2) */ + secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (1) */ + secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (2) */ + /* If lambda = R/M = R/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ + degenerate = secp256k1_fe_normalizes_to_zero(&m); + /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. + * This means either x1 == beta*x2 or beta*x1 == x2, where beta is + * a nontrivial cube root of one. In either case, an alternate + * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), + * so we set R/M equal to this. */ + rr_alt = s1; + secp256k1_fe_mul_int(&rr_alt, 2); /* rr_alt = Y1*Z2^3 - Y2*Z1^3 (GEJ_Y_M*2) */ + secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 (GEJ_X_M+2) */ + + secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); /* rr_alt (GEJ_Y_M*2) */ + secp256k1_fe_cmov(&m_alt, &m, !degenerate); /* m_alt (GEJ_X_M+2) */ + /* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0. + * From here on out Ralt and Malt represent the numerator + * and denominator of lambda; R and M represent the explicit + * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ + secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ + secp256k1_fe_negate(&q, &t, + SECP256K1_GEJ_X_MAGNITUDE_MAX + 1); /* q = -T (GEJ_X_M+2) */ + secp256k1_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */ + /* These two lines use the observation that either M == Malt or M == 0, + * so M^3 * Malt is either Malt^4 (which is computed by squaring), or + * zero (which is "computed" by cmov). So the cost is one squaring + * versus two multiplications. */ + secp256k1_fe_sqr(&n, &n); /* n = Malt^4 (1) */ + secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (GEJ_Y_M+1) */ + secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ + secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */ + secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */ + r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */ + secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */ + secp256k1_fe_add(&t, &q); /* t = 2*X3 + Q (5) */ + secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */ + secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (GEJ_Y_M+2) */ + secp256k1_fe_negate(&r->y, &t, + SECP256K1_GEJ_Y_MAGNITUDE_MAX + 2); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (GEJ_Y_M+3) */ + secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 ((GEJ_Y_M+3)/2 + 1) */ + + /* In case a->infinity == 1, replace r with (b->x, b->y, 1). */ + secp256k1_fe_cmov(&r->x, &b->x, a->infinity); + secp256k1_fe_cmov(&r->y, &b->y, a->infinity); + secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity); + + /* Set r->infinity if r->z is 0. + * + * If a->infinity is set, then r->infinity = (r->z == 0) = (1 == 0) = false, + * which is correct because the function assumes that b is not infinity. + * + * Now assume !a->infinity. This implies Z = Z1 != 0. + * + * Case y1 = -y2: + * In this case we could have a = -b, namely if x1 = x2. + * We have degenerate = true, r->z = (x1 - x2) * Z. + * Then r->infinity = ((x1 - x2)Z == 0) = (x1 == x2) = (a == -b). + * + * Case y1 != -y2: + * In this case, we can't have a = -b. + * We have degenerate = false, r->z = (y1 + y2) * Z. + * Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */ + r->infinity = secp256k1_fe_normalizes_to_zero(&r->z); + + SECP256K1_GEJ_VERIFY(r); +} + +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { + /* Operations: 4 mul, 1 sqr */ + secp256k1_fe zz; + SECP256K1_GEJ_VERIFY(r); + SECP256K1_FE_VERIFY(s); + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s)); + + secp256k1_fe_sqr(&zz, s); + secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ + secp256k1_fe_mul(&r->y, &r->y, &zz); + secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ + secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ + + SECP256K1_GEJ_VERIFY(r); +} + +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { + secp256k1_fe x, y; + SECP256K1_GE_VERIFY(a); + VERIFY_CHECK(!a->infinity); + + x = a->x; + secp256k1_fe_normalize(&x); + y = a->y; + secp256k1_fe_normalize(&y); + secp256k1_fe_to_storage(&r->x, &x); + secp256k1_fe_to_storage(&r->y, &y); +} + +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) { + secp256k1_fe_from_storage(&r->x, &a->x); + secp256k1_fe_from_storage(&r->y, &a->y); + r->infinity = 0; + + SECP256K1_GE_VERIFY(r); +} + +static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) { + SECP256K1_GEJ_VERIFY(r); + SECP256K1_GEJ_VERIFY(a); + + secp256k1_fe_cmov(&r->x, &a->x, flag); + secp256k1_fe_cmov(&r->y, &a->y, flag); + secp256k1_fe_cmov(&r->z, &a->z, flag); + r->infinity ^= (r->infinity ^ a->infinity) & flag; + + SECP256K1_GEJ_VERIFY(r); +} + +static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { + secp256k1_fe_storage_cmov(&r->x, &a->x, flag); + secp256k1_fe_storage_cmov(&r->y, &a->y, flag); +} + +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { + SECP256K1_GE_VERIFY(a); + + *r = *a; + secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta); + + SECP256K1_GE_VERIFY(r); +} + +static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { +#ifdef EXHAUSTIVE_TEST_ORDER + secp256k1_gej out; + int i; + SECP256K1_GE_VERIFY(ge); + + /* A very simple EC multiplication ladder that avoids a dependency on ecmult. */ + secp256k1_gej_set_infinity(&out); + for (i = 0; i < 32; ++i) { + secp256k1_gej_double_var(&out, &out, NULL); + if ((((uint32_t)EXHAUSTIVE_TEST_ORDER) >> (31 - i)) & 1) { + secp256k1_gej_add_ge_var(&out, &out, ge, NULL); + } + } + return secp256k1_gej_is_infinity(&out); +#else + SECP256K1_GE_VERIFY(ge); + + (void)ge; + /* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */ + return 1; +#endif +} + +static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) { + secp256k1_fe c; + secp256k1_fe_sqr(&c, x); + secp256k1_fe_mul(&c, &c, x); + secp256k1_fe_add_int(&c, SECP256K1_B); + return secp256k1_fe_is_square_var(&c); +} + +static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) { + /* We want to determine whether (xn/xd) is on the curve. + * + * (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square). + */ + secp256k1_fe r, t; + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd)); + + secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */ + secp256k1_fe_sqr(&t, xn); /* t = xn^2 */ + secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */ + secp256k1_fe_sqr(&t, xd); /* t = xd^2 */ + secp256k1_fe_sqr(&t, &t); /* t = xd^4 */ + VERIFY_CHECK(SECP256K1_B <= 31); + secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */ + secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */ + return secp256k1_fe_is_square_var(&r); +} + +static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a) { + secp256k1_ge_storage s; + + /* We require that the secp256k1_ge_storage type is exactly 64 bytes. + * This is formally not guaranteed by the C standard, but should hold on any + * sane compiler in the real world. */ + STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); + VERIFY_CHECK(!secp256k1_ge_is_infinity(a)); + secp256k1_ge_to_storage(&s, a); + memcpy(buf, &s, 64); +} + +static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) { + secp256k1_ge_storage s; + + STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); + memcpy(&s, buf, 64); + secp256k1_ge_from_storage(r, &s); +} + +static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge) { + if (secp256k1_ge_is_infinity(ge)) { + memset(data, 0, 64); + } else { + secp256k1_ge_to_bytes(data, ge); + } +} + +static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data) { + static const unsigned char zeros[64] = { 0 }; + if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) { + secp256k1_ge_set_infinity(ge); + } else { + secp256k1_ge_from_bytes(ge, data); + } +} + +#endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/external/secp256k1/src/hash.h b/external/secp256k1/src/hash.h new file mode 100644 index 00000000000..6d903ca7e07 --- /dev/null +++ b/external/secp256k1/src/hash.h @@ -0,0 +1,44 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_HASH_H +#define SECP256K1_HASH_H + +#include +#include + +typedef struct { + uint32_t s[8]; + unsigned char buf[64]; + uint64_t bytes; +} secp256k1_sha256; + +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash); +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32); +static void secp256k1_sha256_clear(secp256k1_sha256 *hash); + +typedef struct { + secp256k1_sha256 inner, outer; +} secp256k1_hmac_sha256; + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32); +static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash); + +typedef struct { + unsigned char v[32]; + unsigned char k[32]; + int retry; +} secp256k1_rfc6979_hmac_sha256; + +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng); +static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng); + +#endif /* SECP256K1_HASH_H */ diff --git a/external/secp256k1/src/hash_impl.h b/external/secp256k1/src/hash_impl.h new file mode 100644 index 00000000000..956e0ea48b3 --- /dev/null +++ b/external/secp256k1/src/hash_impl.h @@ -0,0 +1,299 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_HASH_IMPL_H +#define SECP256K1_HASH_IMPL_H + +#include "hash.h" +#include "util.h" + +#include +#include +#include + +#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) +#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) +#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) +#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) + +#define Round(a,b,c,d,e,f,g,h,k,w) do { \ + uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ + uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ + (d) += t1; \ + (h) = t1 + t2; \ +} while(0) + +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { + hash->s[0] = 0x6a09e667ul; + hash->s[1] = 0xbb67ae85ul; + hash->s[2] = 0x3c6ef372ul; + hash->s[3] = 0xa54ff53aul; + hash->s[4] = 0x510e527ful; + hash->s[5] = 0x9b05688cul; + hash->s[6] = 0x1f83d9abul; + hash->s[7] = 0x5be0cd19ul; + hash->bytes = 0; +} + +/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ +static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) { + uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; + uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; + + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0])); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4])); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8])); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12])); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16])); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20])); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24])); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28])); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32])); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36])); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40])); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44])); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48])); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52])); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56])); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60])); + + Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); + + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; +} + +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { + size_t bufsize = hash->bytes & 0x3F; + hash->bytes += len; + VERIFY_CHECK(hash->bytes >= len); + while (len >= 64 - bufsize) { + /* Fill the buffer, and process it. */ + size_t chunk_len = 64 - bufsize; + memcpy(hash->buf + bufsize, data, chunk_len); + data += chunk_len; + len -= chunk_len; + secp256k1_sha256_transform(hash->s, hash->buf); + bufsize = 0; + } + if (len) { + /* Fill the buffer with what remains. */ + memcpy(hash->buf + bufsize, data, len); + } +} + +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) { + static const unsigned char pad[64] = {0x80}; + unsigned char sizedesc[8]; + int i; + /* The maximum message size of SHA256 is 2^64-1 bits. */ + VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61)); + secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29); + secp256k1_write_be32(&sizedesc[4], hash->bytes << 3); + secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); + secp256k1_sha256_write(hash, sizedesc, 8); + for (i = 0; i < 8; i++) { + secp256k1_write_be32(&out32[4*i], hash->s[i]); + hash->s[i] = 0; + } +} + +/* Initializes a sha256 struct and writes the 64 byte string + * SHA256(tag)||SHA256(tag) into it. */ +static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) { + unsigned char buf[32]; + secp256k1_sha256_initialize(hash); + secp256k1_sha256_write(hash, tag, taglen); + secp256k1_sha256_finalize(hash, buf); + + secp256k1_sha256_initialize(hash); + secp256k1_sha256_write(hash, buf, 32); + secp256k1_sha256_write(hash, buf, 32); +} + +static void secp256k1_sha256_clear(secp256k1_sha256 *hash) { + secp256k1_memclear(hash, sizeof(*hash)); +} + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { + size_t n; + unsigned char rkey[64]; + if (keylen <= sizeof(rkey)) { + memcpy(rkey, key, keylen); + memset(rkey + keylen, 0, sizeof(rkey) - keylen); + } else { + secp256k1_sha256 sha256; + secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_write(&sha256, key, keylen); + secp256k1_sha256_finalize(&sha256, rkey); + memset(rkey + 32, 0, 32); + } + + secp256k1_sha256_initialize(&hash->outer); + for (n = 0; n < sizeof(rkey); n++) { + rkey[n] ^= 0x5c; + } + secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey)); + + secp256k1_sha256_initialize(&hash->inner); + for (n = 0; n < sizeof(rkey); n++) { + rkey[n] ^= 0x5c ^ 0x36; + } + secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey)); + secp256k1_memclear(rkey, sizeof(rkey)); +} + +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) { + secp256k1_sha256_write(&hash->inner, data, size); +} + +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) { + unsigned char temp[32]; + secp256k1_sha256_finalize(&hash->inner, temp); + secp256k1_sha256_write(&hash->outer, temp, 32); + secp256k1_memclear(temp, sizeof(temp)); + secp256k1_sha256_finalize(&hash->outer, out32); +} + +static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) { + secp256k1_memclear(hash, sizeof(*hash)); +} + +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { + secp256k1_hmac_sha256 hmac; + static const unsigned char zero[1] = {0x00}; + static const unsigned char one[1] = {0x01}; + + memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */ + memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ + + /* RFC6979 3.2.d. */ + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + + /* RFC6979 3.2.f. */ + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, one, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + rng->retry = 0; +} + +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { + /* RFC6979 3.2.h. */ + static const unsigned char zero[1] = {0x00}; + if (rng->retry) { + secp256k1_hmac_sha256 hmac; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + } + + while (outlen > 0) { + secp256k1_hmac_sha256 hmac; + int now = outlen; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + if (now > 32) { + now = 32; + } + memcpy(out, rng->v, now); + out += now; + outlen -= now; + } + + rng->retry = 1; +} + +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) { + (void) rng; +} + +static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng) { + secp256k1_memclear(rng, sizeof(*rng)); +} + +#undef Round +#undef sigma1 +#undef sigma0 +#undef Sigma1 +#undef Sigma0 +#undef Maj +#undef Ch + +#endif /* SECP256K1_HASH_IMPL_H */ diff --git a/external/secp256k1/src/hsort.h b/external/secp256k1/src/hsort.h new file mode 100644 index 00000000000..d54995caadf --- /dev/null +++ b/external/secp256k1/src/hsort.h @@ -0,0 +1,33 @@ +/*********************************************************************** + * Copyright (c) 2021 Russell O'Connor, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_HSORT_H +#define SECP256K1_HSORT_H + +#include +#include + +/* In-place, iterative heapsort with an interface matching glibc's qsort_r. This + * is preferred over standard library implementations because they generally + * make no guarantee about being fast for malicious inputs. + * Remember that heapsort is unstable. + * + * In/Out: ptr: pointer to the array to sort. The contents of the array are + * sorted in ascending order according to the comparison function. + * In: count: number of elements in the array. + * size: size in bytes of each element. + * cmp: pointer to a comparison function that is called with two + * arguments that point to the objects being compared. The cmp_data + * argument of secp256k1_hsort is passed as third argument. The + * function must return an integer less than, equal to, or greater + * than zero if the first argument is considered to be respectively + * less than, equal to, or greater than the second. + * cmp_data: pointer passed as third argument to cmp. + */ +static void secp256k1_hsort(void *ptr, size_t count, size_t size, + int (*cmp)(const void *, const void *, void *), + void *cmp_data); +#endif diff --git a/external/secp256k1/src/hsort_impl.h b/external/secp256k1/src/hsort_impl.h new file mode 100644 index 00000000000..1c674ff1c43 --- /dev/null +++ b/external/secp256k1/src/hsort_impl.h @@ -0,0 +1,125 @@ +/*********************************************************************** + * Copyright (c) 2021 Russell O'Connor, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_HSORT_IMPL_H +#define SECP256K1_HSORT_IMPL_H + +#include "hsort.h" + +/* An array is a heap when, for all non-zero indexes i, the element at index i + * compares as less than or equal to the element at index parent(i) = (i-1)/2. + */ + +static SECP256K1_INLINE size_t secp256k1_heap_child1(size_t i) { + VERIFY_CHECK(i <= (SIZE_MAX - 1)/2); + return 2*i + 1; +} + +static SECP256K1_INLINE size_t secp256k1_heap_child2(size_t i) { + VERIFY_CHECK(i <= SIZE_MAX/2 - 1); + return secp256k1_heap_child1(i)+1; +} + +static SECP256K1_INLINE void secp256k1_heap_swap64(unsigned char *a, unsigned char *b, size_t len) { + unsigned char tmp[64]; + VERIFY_CHECK(len <= 64); + memcpy(tmp, a, len); + memmove(a, b, len); + memcpy(b, tmp, len); +} + +static SECP256K1_INLINE void secp256k1_heap_swap(unsigned char *arr, size_t i, size_t j, size_t stride) { + unsigned char *a = arr + i*stride; + unsigned char *b = arr + j*stride; + size_t len = stride; + while (64 < len) { + secp256k1_heap_swap64(a + (len - 64), b + (len - 64), 64); + len -= 64; + } + secp256k1_heap_swap64(a, b, len); +} + +/* This function accepts an array arr containing heap_size elements, each of + * size stride. The elements in the array at indices >i satisfy the max-heap + * property, i.e., for any element at index j (where j > i), all of its children + * are smaller than the element itself. The purpose of the function is to update + * the array so that all elements at indices >=i satisfy the max-heap + * property. */ +static SECP256K1_INLINE void secp256k1_heap_down(unsigned char *arr, size_t i, size_t heap_size, size_t stride, + int (*cmp)(const void *, const void *, void *), void *cmp_data) { + while (i < heap_size/2) { + VERIFY_CHECK(i <= SIZE_MAX/2 - 1); + /* Proof: + * i < heap_size/2 + * i + 1 <= heap_size/2 + * 2*i + 2 <= heap_size <= SIZE_MAX + * 2*i <= SIZE_MAX - 2 + */ + + VERIFY_CHECK(secp256k1_heap_child1(i) < heap_size); + /* Proof: + * i < heap_size/2 + * i + 1 <= heap_size/2 + * 2*i + 2 <= heap_size + * 2*i + 1 < heap_size + * child1(i) < heap_size + */ + + /* Let [x] be notation for the contents at arr[x*stride]. + * + * If [child1(i)] > [i] and [child2(i)] > [i], + * swap [i] with the larger child to ensure the new parent is larger + * than both children. When [child1(i)] == [child2(i)], swap [i] with + * [child2(i)]. + * Else if [child1(i)] > [i], swap [i] with [child1(i)]. + * Else if [child2(i)] > [i], swap [i] with [child2(i)]. + */ + if (secp256k1_heap_child2(i) < heap_size + && 0 <= cmp(arr + secp256k1_heap_child2(i)*stride, arr + secp256k1_heap_child1(i)*stride, cmp_data)) { + if (0 < cmp(arr + secp256k1_heap_child2(i)*stride, arr + i*stride, cmp_data)) { + secp256k1_heap_swap(arr, i, secp256k1_heap_child2(i), stride); + i = secp256k1_heap_child2(i); + } else { + /* At this point we have [child2(i)] >= [child1(i)] and we have + * [child2(i)] <= [i], and thus [child1(i)] <= [i] which means + * that the next comparison can be skipped. */ + return; + } + } else if (0 < cmp(arr + secp256k1_heap_child1(i)*stride, arr + i*stride, cmp_data)) { + secp256k1_heap_swap(arr, i, secp256k1_heap_child1(i), stride); + i = secp256k1_heap_child1(i); + } else { + return; + } + } + /* heap_size/2 <= i + * heap_size/2 < i + 1 + * heap_size < 2*i + 2 + * heap_size <= 2*i + 1 + * heap_size <= child1(i) + * Thus child1(i) and child2(i) are now out of bounds and we are at a leaf. + */ +} + +/* In-place heap sort. */ +static void secp256k1_hsort(void *ptr, size_t count, size_t size, + int (*cmp)(const void *, const void *, void *), + void *cmp_data) { + size_t i; + + for (i = count/2; 0 < i; --i) { + secp256k1_heap_down(ptr, i-1, count, size, cmp, cmp_data); + } + for (i = count; 1 < i; --i) { + /* Extract the largest value from the heap */ + secp256k1_heap_swap(ptr, 0, i-1, size); + + /* Repair the heap condition */ + secp256k1_heap_down(ptr, 0, i-1, size, cmp, cmp_data); + } +} + +#endif diff --git a/external/secp256k1/src/int128.h b/external/secp256k1/src/int128.h new file mode 100644 index 00000000000..5355fbfae0f --- /dev/null +++ b/external/secp256k1/src/int128.h @@ -0,0 +1,90 @@ +#ifndef SECP256K1_INT128_H +#define SECP256K1_INT128_H + +#include "util.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +# if defined(SECP256K1_INT128_NATIVE) +# include "int128_native.h" +# elif defined(SECP256K1_INT128_STRUCT) +# include "int128_struct.h" +# else +# error "Please select int128 implementation" +# endif + +/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */ +static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo); + +/* Multiply two unsigned 64-bit values a and b and write the result to r. */ +static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b); + +/* Multiply two unsigned 64-bit values a and b and add the result to r. + * The final result is taken modulo 2^128. + */ +static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b); + +/* Add an unsigned 64-bit value a to r. + * The final result is taken modulo 2^128. + */ +static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a); + +/* Unsigned (logical) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n); + +/* Return the low 64-bits of a 128-bit value as an unsigned 64-bit value. */ +static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a); + +/* Return the high 64-bits of a 128-bit value as an unsigned 64-bit value. */ +static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a); + +/* Write an unsigned 64-bit value to r. */ +static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a); + +/* Tests if r is strictly less than to 2^n. + * n must be strictly less than 128. + */ +static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n); + +/* Construct an signed 128-bit value from a high and a low 64-bit value. */ +static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo); + +/* Multiply two signed 64-bit values a and b and write the result to r. */ +static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b); + +/* Multiply two signed 64-bit values a and b and add the result to r. + * Overflow or underflow from the addition is undefined behaviour. + */ +static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b); + +/* Compute a*d - b*c from signed 64-bit values and write the result to r. */ +static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d); + +/* Signed (arithmetic) right shift. + * Non-constant time in b. + */ +static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b); + +/* Return the input value modulo 2^64. */ +static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a); + +/* Return the value as a signed 64-bit value. + * Requires the input to be between INT64_MIN and INT64_MAX. + */ +static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a); + +/* Write a signed 64-bit value to r. */ +static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a); + +/* Compare two 128-bit values for equality. */ +static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b); + +/* Tests if r is equal to sign*2^n (sign must be 1 or -1). + * n must be strictly less than 127. + */ +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign); + +#endif + +#endif diff --git a/external/secp256k1/src/int128_impl.h b/external/secp256k1/src/int128_impl.h new file mode 100644 index 00000000000..cfc573408a0 --- /dev/null +++ b/external/secp256k1/src/int128_impl.h @@ -0,0 +1,18 @@ +#ifndef SECP256K1_INT128_IMPL_H +#define SECP256K1_INT128_IMPL_H + +#include "util.h" + +#include "int128.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +# if defined(SECP256K1_INT128_NATIVE) +# include "int128_native_impl.h" +# elif defined(SECP256K1_INT128_STRUCT) +# include "int128_struct_impl.h" +# else +# error "Please select int128 implementation" +# endif +#endif + +#endif diff --git a/external/secp256k1/src/int128_native.h b/external/secp256k1/src/int128_native.h new file mode 100644 index 00000000000..7c97aafc749 --- /dev/null +++ b/external/secp256k1/src/int128_native.h @@ -0,0 +1,19 @@ +#ifndef SECP256K1_INT128_NATIVE_H +#define SECP256K1_INT128_NATIVE_H + +#include +#include "util.h" + +#if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__) +SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; +SECP256K1_GNUC_EXT typedef __int128 int128_t; +# define UINT128_MAX ((uint128_t)(-1)) +# define INT128_MAX ((int128_t)(UINT128_MAX >> 1)) +# define INT128_MIN (-INT128_MAX - 1) +/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */ +#endif + +typedef uint128_t secp256k1_uint128; +typedef int128_t secp256k1_int128; + +#endif diff --git a/external/secp256k1/src/int128_native_impl.h b/external/secp256k1/src/int128_native_impl.h new file mode 100644 index 00000000000..7f02e1590bb --- /dev/null +++ b/external/secp256k1/src/int128_native_impl.h @@ -0,0 +1,94 @@ +#ifndef SECP256K1_INT128_NATIVE_IMPL_H +#define SECP256K1_INT128_NATIVE_IMPL_H + +#include "int128.h" +#include "util.h" + +static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) { + *r = (((uint128_t)hi) << 64) + lo; +} + +static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + *r = (uint128_t)a * b; +} + +static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + *r += (uint128_t)a * b; +} + +static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) { + *r += a; +} + +static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + *r >>= n; +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) { + return (uint64_t)(*a); +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) { + return (uint64_t)(*a >> 64); +} + +static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) { + *r = a; +} + +static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + return (*r >> n == 0); +} + +static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) { + *r = (((uint128_t)(uint64_t)hi) << 64) + lo; +} + +static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + *r = (int128_t)a * b; +} + +static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int128_t ab = (int128_t)a * b; + VERIFY_CHECK(0 <= ab ? *r <= INT128_MAX - ab : INT128_MIN - ab <= *r); + *r += ab; +} + +static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { + int128_t ad = (int128_t)a * d; + int128_t bc = (int128_t)b * c; + VERIFY_CHECK(0 <= bc ? INT128_MIN + bc <= ad : ad <= INT128_MAX + bc); + *r = ad - bc; +} + +static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + *r >>= n; +} + +static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) { + return (uint64_t)*a; +} + +static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { + VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX); + return *a; +} + +static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) { + *r = a; +} + +static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) { + return *a == *b; +} + +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { + VERIFY_CHECK(n < 127); + VERIFY_CHECK(sign == 1 || sign == -1); + return (*r == (int128_t)((uint128_t)sign << n)); +} + +#endif diff --git a/external/secp256k1/src/int128_struct.h b/external/secp256k1/src/int128_struct.h new file mode 100644 index 00000000000..6156f82cc2d --- /dev/null +++ b/external/secp256k1/src/int128_struct.h @@ -0,0 +1,14 @@ +#ifndef SECP256K1_INT128_STRUCT_H +#define SECP256K1_INT128_STRUCT_H + +#include +#include "util.h" + +typedef struct { + uint64_t lo; + uint64_t hi; +} secp256k1_uint128; + +typedef secp256k1_uint128 secp256k1_int128; + +#endif diff --git a/external/secp256k1/src/int128_struct_impl.h b/external/secp256k1/src/int128_struct_impl.h new file mode 100644 index 00000000000..962a71d13bc --- /dev/null +++ b/external/secp256k1/src/int128_struct_impl.h @@ -0,0 +1,205 @@ +#ifndef SECP256K1_INT128_STRUCT_IMPL_H +#define SECP256K1_INT128_STRUCT_IMPL_H + +#include "int128.h" +#include "util.h" + +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */ +# include +# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) +/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications. + (Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64, + which supports both __(u)mulh and _umul128.) */ +# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) +# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.") +# endif +static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) { + *hi = __umulh(a, b); + return a * b; +} + +static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) { + *hi = __mulh(a, b); + return (uint64_t)a * (uint64_t)b; +} +# else +/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */ +# define secp256k1_umul128 _umul128 +# define secp256k1_mul128 _mul128 +# endif +#else +/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */ +static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) { + uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; + uint64_t lh = (uint32_t)a * (b >> 32); + uint64_t hl = (a >> 32) * (uint32_t)b; + uint64_t hh = (a >> 32) * (b >> 32); + uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; + *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); + return (mid34 << 32) + (uint32_t)ll; +} + +static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) { + uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; + int64_t lh = (uint32_t)a * (b >> 32); + int64_t hl = (a >> 32) * (uint32_t)b; + int64_t hh = (a >> 32) * (b >> 32); + uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; + *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); + return (mid34 << 32) + (uint32_t)ll; +} +#endif + +static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) { + r->hi = hi; + r->lo = lo; +} + +static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + r->lo = secp256k1_umul128(a, b, &r->hi); +} + +static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + uint64_t lo, hi; + lo = secp256k1_umul128(a, b, &hi); + r->lo += lo; + r->hi += hi + (r->lo < lo); +} + +static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) { + r->lo += a; + r->hi += r->lo < a; +} + +/* Unsigned (logical) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + if (n >= 64) { + r->lo = r->hi >> (n-64); + r->hi = 0; + } else if (n > 0) { +#if defined(_MSC_VER) && defined(_M_X64) + VERIFY_CHECK(n < 64); + r->lo = __shiftright128(r->lo, r->hi, n); +#else + r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; +#endif + r->hi >>= n; + } +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) { + return a->lo; +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) { + return a->hi; +} + +static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) { + r->hi = 0; + r->lo = a; +} + +static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + return n >= 64 ? r->hi >> (n - 64) == 0 + : r->hi == 0 && r->lo >> n == 0; +} + +static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) { + r->hi = hi; + r->lo = lo; +} + +static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int64_t hi; + r->lo = (uint64_t)secp256k1_mul128(a, b, &hi); + r->hi = (uint64_t)hi; +} + +static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int64_t hi; + uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi); + r->lo += lo; + hi += r->lo < lo; + /* Verify no overflow. + * If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set), + * then we require that the resulting value also be positive (the sign bit is not set). + * Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1). + */ + VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu)); + /* Verify no underflow. + * If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set), + * then we require that the resulting value also be negative (the sign bit is set). + */ + VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu)); + r->hi += hi; +} + +static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int64_t hi; + uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi); + hi += r->lo < lo; + /* Verify no overflow. + * If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set), + * then we require that the resulting value also be positive (the sign bit is not set). + */ + VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu)); + /* Verify no underflow. + * If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set), + * then we require that the resulting value also be negative (the sign bit is set). + */ + VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu)); + r->hi -= hi; + r->lo -= lo; +} + +static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { + secp256k1_i128_mul(r, a, d); + secp256k1_i128_dissip_mul(r, b, c); +} + +/* Signed (arithmetic) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + if (n >= 64) { + r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64)); + r->hi = (uint64_t)((int64_t)(r->hi) >> 63); + } else if (n > 0) { + r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; + r->hi = (uint64_t)((int64_t)(r->hi) >> n); + } +} + +static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) { + return a->lo; +} + +static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { + /* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */ + VERIFY_CHECK(a->hi == -(a->lo >> 63)); + return (int64_t)secp256k1_i128_to_u64(a); +} + +static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) { + r->hi = (uint64_t)(a >> 63); + r->lo = (uint64_t)a; +} + +static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) { + return a->hi == b->hi && a->lo == b->lo; +} + +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { + VERIFY_CHECK(n < 127); + VERIFY_CHECK(sign == 1 || sign == -1); + return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0 + : r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n; +} + +#endif diff --git a/external/secp256k1/src/modinv32.h b/external/secp256k1/src/modinv32.h new file mode 100644 index 00000000000..846c642f8c9 --- /dev/null +++ b/external/secp256k1/src/modinv32.h @@ -0,0 +1,43 @@ +/*********************************************************************** + * Copyright (c) 2020 Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODINV32_H +#define SECP256K1_MODINV32_H + +#include "util.h" + +/* A signed 30-bit limb representation of integers. + * + * Its value is sum(v[i] * 2^(30*i), i=0..8). */ +typedef struct { + int32_t v[9]; +} secp256k1_modinv32_signed30; + +typedef struct { + /* The modulus in signed30 notation, must be odd and in [3, 2^256]. */ + secp256k1_modinv32_signed30 modulus; + + /* modulus^{-1} mod 2^30 */ + uint32_t modulus_inv30; +} secp256k1_modinv32_modinfo; + +/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus). + * If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of + * x and modulus must be 1). These rules are automatically satisfied if the modulus is prime. + * + * On output, all of x's limbs will be in [0, 2^30). + */ +static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); + +/* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */ +static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); + +/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus + * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result + * cannot be computed. */ +static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); + +#endif /* SECP256K1_MODINV32_H */ diff --git a/external/secp256k1/src/modinv32_impl.h b/external/secp256k1/src/modinv32_impl.h new file mode 100644 index 00000000000..981d2abc6da --- /dev/null +++ b/external/secp256k1/src/modinv32_impl.h @@ -0,0 +1,725 @@ +/*********************************************************************** + * Copyright (c) 2020 Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODINV32_IMPL_H +#define SECP256K1_MODINV32_IMPL_H + +#include "modinv32.h" + +#include "util.h" + +#include + +/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and + * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. + * + * For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an + * implementation for N=30, using 30-bit signed limbs represented as int32_t. + */ + +#ifdef VERIFY +static const secp256k1_modinv32_signed30 SECP256K1_SIGNED30_ONE = {{1}}; + +/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^30). */ +static void secp256k1_modinv32_mul_30(secp256k1_modinv32_signed30 *r, const secp256k1_modinv32_signed30 *a, int alen, int32_t factor) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + int64_t c = 0; + int i; + for (i = 0; i < 8; ++i) { + if (i < alen) c += (int64_t)a->v[i] * factor; + r->v[i] = (int32_t)c & M30; c >>= 30; + } + if (8 < alen) c += (int64_t)a->v[8] * factor; + VERIFY_CHECK(c == (int32_t)c); + r->v[8] = (int32_t)c; +} + +/* Return -1 for ab*factor. A consists of alen limbs; b has 9. */ +static int secp256k1_modinv32_mul_cmp_30(const secp256k1_modinv32_signed30 *a, int alen, const secp256k1_modinv32_signed30 *b, int32_t factor) { + int i; + secp256k1_modinv32_signed30 am, bm; + secp256k1_modinv32_mul_30(&am, a, alen, 1); /* Normalize all but the top limb of a. */ + secp256k1_modinv32_mul_30(&bm, b, 9, factor); + for (i = 0; i < 8; ++i) { + /* Verify that all but the top limb of a and b are normalized. */ + VERIFY_CHECK(am.v[i] >> 30 == 0); + VERIFY_CHECK(bm.v[i] >> 30 == 0); + } + for (i = 8; i >= 0; --i) { + if (am.v[i] < bm.v[i]) return -1; + if (am.v[i] > bm.v[i]) return 1; + } + return 0; +} +#endif + +/* Take as input a signed30 number in range (-2*modulus,modulus), and add a multiple of the modulus + * to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the + * process. The input must have limbs in range (-2^30,2^30). The output will have limbs in range + * [0,2^30). */ +static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int32_t sign, const secp256k1_modinv32_modinfo *modinfo) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4], + r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8]; + volatile int32_t cond_add, cond_negate; + +#ifdef VERIFY + /* Verify that all limbs are in range (-2^30,2^30). */ + int i; + for (i = 0; i < 9; ++i) { + VERIFY_CHECK(r->v[i] >= -M30); + VERIFY_CHECK(r->v[i] <= M30); + } + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ +#endif + + /* In a first step, add the modulus if the input is negative, and then negate if requested. + * This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input + * limbs are in range (-2^30,2^30), this cannot overflow an int32_t. Note that the right + * shifts below are signed sign-extending shifts (see assumptions.h for tests that that is + * indeed the behavior of the right shift operator). */ + cond_add = r8 >> 31; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + r5 += modinfo->modulus.v[5] & cond_add; + r6 += modinfo->modulus.v[6] & cond_add; + r7 += modinfo->modulus.v[7] & cond_add; + r8 += modinfo->modulus.v[8] & cond_add; + cond_negate = sign >> 31; + r0 = (r0 ^ cond_negate) - cond_negate; + r1 = (r1 ^ cond_negate) - cond_negate; + r2 = (r2 ^ cond_negate) - cond_negate; + r3 = (r3 ^ cond_negate) - cond_negate; + r4 = (r4 ^ cond_negate) - cond_negate; + r5 = (r5 ^ cond_negate) - cond_negate; + r6 = (r6 ^ cond_negate) - cond_negate; + r7 = (r7 ^ cond_negate) - cond_negate; + r8 = (r8 ^ cond_negate) - cond_negate; + /* Propagate the top bits, to bring limbs back to range (-2^30,2^30). */ + r1 += r0 >> 30; r0 &= M30; + r2 += r1 >> 30; r1 &= M30; + r3 += r2 >> 30; r2 &= M30; + r4 += r3 >> 30; r3 &= M30; + r5 += r4 >> 30; r4 &= M30; + r6 += r5 >> 30; r5 &= M30; + r7 += r6 >> 30; r6 &= M30; + r8 += r7 >> 30; r7 &= M30; + + /* In a second step add the modulus again if the result is still negative, bringing r to range + * [0,modulus). */ + cond_add = r8 >> 31; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + r5 += modinfo->modulus.v[5] & cond_add; + r6 += modinfo->modulus.v[6] & cond_add; + r7 += modinfo->modulus.v[7] & cond_add; + r8 += modinfo->modulus.v[8] & cond_add; + /* And propagate again. */ + r1 += r0 >> 30; r0 &= M30; + r2 += r1 >> 30; r1 &= M30; + r3 += r2 >> 30; r2 &= M30; + r4 += r3 >> 30; r3 &= M30; + r5 += r4 >> 30; r4 &= M30; + r6 += r5 >> 30; r5 &= M30; + r7 += r6 >> 30; r6 &= M30; + r8 += r7 >> 30; r7 &= M30; + + r->v[0] = r0; + r->v[1] = r1; + r->v[2] = r2; + r->v[3] = r3; + r->v[4] = r4; + r->v[5] = r5; + r->v[6] = r6; + r->v[7] = r7; + r->v[8] = r8; + + VERIFY_CHECK(r0 >> 30 == 0); + VERIFY_CHECK(r1 >> 30 == 0); + VERIFY_CHECK(r2 >> 30 == 0); + VERIFY_CHECK(r3 >> 30 == 0); + VERIFY_CHECK(r4 >> 30 == 0); + VERIFY_CHECK(r5 >> 30 == 0); + VERIFY_CHECK(r6 >> 30 == 0); + VERIFY_CHECK(r7 >> 30 == 0); + VERIFY_CHECK(r8 >> 30 == 0); + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ +} + +/* Data type for transition matrices (see section 3 of explanation). + * + * t = [ u v ] + * [ q r ] + */ +typedef struct { + int32_t u, v, q, r; +} secp256k1_modinv32_trans2x2; + +/* Compute the transition matrix and zeta for 30 divsteps. + * + * Input: zeta: initial zeta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final zeta + * + * Implements the divsteps_n_matrix function from the explanation. + */ +static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) { + /* u,v,q,r are the elements of the transformation matrix being built up, + * starting with the identity matrix. Semantically they are signed integers + * in range [-2^30,2^30], but here represented as unsigned mod 2^32. This + * permits left shifting (which is UB for negative numbers). The range + * being inside [-2^31,2^31) means that casting to signed works correctly. + */ + uint32_t u = 1, v = 0, q = 0, r = 1; + volatile uint32_t c1, c2; + uint32_t mask1, mask2, f = f0, g = g0, x, y, z; + int i; + + for (i = 0; i < 30; ++i) { + VERIFY_CHECK((f & 1) == 1); /* f must always be odd */ + VERIFY_CHECK((u * f0 + v * g0) == f << i); + VERIFY_CHECK((q * f0 + r * g0) == g << i); + /* Compute conditional masks for (zeta < 0) and for (g & 1). */ + c1 = zeta >> 31; + mask1 = c1; + c2 = g & 1; + mask2 = -c2; + /* Compute x,y,z, conditionally negated versions of f,u,v. */ + x = (f ^ mask1) - mask1; + y = (u ^ mask1) - mask1; + z = (v ^ mask1) - mask1; + /* Conditionally add x,y,z to g,q,r. */ + g += x & mask2; + q += y & mask2; + r += z & mask2; + /* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */ + mask1 &= mask2; + /* Conditionally change zeta into -zeta-2 or zeta-1. */ + zeta = (zeta ^ mask1) - 1; + /* Conditionally add g,q,r to f,u,v. */ + f += g & mask1; + u += q & mask1; + v += r & mask1; + /* Shifts */ + g >>= 1; + u <<= 1; + v <<= 1; + /* Bounds on zeta that follow from the bounds on iteration count (max 20*30 divsteps). */ + VERIFY_CHECK(zeta >= -601 && zeta <= 601); + } + /* Return data in t and return value. */ + t->u = (int32_t)u; + t->v = (int32_t)v; + t->q = (int32_t)q; + t->r = (int32_t)r; + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 30 of them will have determinant 2^30. */ + VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30); + return zeta; +} + +/* secp256k1_modinv32_inv256[i] = -(2*i+1)^-1 (mod 256) */ +static const uint8_t secp256k1_modinv32_inv256[128] = { + 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59, + 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31, + 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89, + 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61, + 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9, + 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91, + 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9, + 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1, + 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19, + 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1, + 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01 +}; + +/* Compute the transition matrix and eta for 30 divsteps (variable time). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final eta + * + * Implements the divsteps_n_matrix_var function from the explanation. + */ +static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) { + /* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */ + uint32_t u = 1, v = 0, q = 0, r = 1; + uint32_t f = f0, g = g0, m; + uint16_t w; + int i = 30, limit, zeros; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* We're done once we've done 30 divsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i)); + /* Bounds on eta that follow from the bounds on iteration count (max 25*30 divsteps). */ + VERIFY_CHECK(eta >= -751 && eta <= 751); + /* If eta is negative, negate it and replace f,g with g,-f. */ + if (eta < 0) { + uint32_t tmp; + eta = -eta; + tmp = f; f = g; g = -tmp; + tmp = u; u = q; q = -tmp; + tmp = v; v = r; r = -tmp; + } + /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more + * than i can be cancelled out (as we'd be done before that point), and no more than eta+1 + * can be done as its sign will flip once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */ + VERIFY_CHECK(limit > 0 && limit <= 30); + m = (UINT32_MAX >> (32 - limit)) & 255U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ + w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m; + /* Do so. */ + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int32_t)u; + t->v = (int32_t)v; + t->q = (int32_t)q; + t->r = (int32_t)r; + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 30 of them will have determinant 2^30. */ + VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30); + return eta; +} + +/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track + * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because + * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign + * by applying the returned transformation matrix to it. The other bits of *jacp may + * change, but are meaningless. + * Return: final eta + */ +static int32_t secp256k1_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t, int *jacp) { + /* Transformation matrix. */ + uint32_t u = 1, v = 0, q = 0, r = 1; + uint32_t f = f0, g = g0, m; + uint16_t w; + int i = 30, limit, zeros; + int jac = *jacp; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* Update the bottom bit of jac: when dividing g by an odd power of 2, + * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ + jac ^= (zeros & ((f >> 1) ^ (f >> 2))); + /* We're done once we've done 30 posdivsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i)); + /* If eta is negative, negate it and replace f,g with g,f. */ + if (eta < 0) { + uint32_t tmp; + eta = -eta; + /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign + * if both f and g are 3 mod 4. */ + jac ^= ((f & g) >> 1); + tmp = f; f = g; g = tmp; + tmp = u; u = q; q = tmp; + tmp = v; v = r; r = tmp; + } + /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more + * than i can be cancelled out (as we'd be done before that point), and no more than eta+1 + * can be done as its sign will flip once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */ + VERIFY_CHECK(limit > 0 && limit <= 30); + m = (UINT32_MAX >> (32 - limit)) & 255U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ + w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m; + /* Do so. */ + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int32_t)u; + t->v = (int32_t)v; + t->q = (int32_t)q; + t->r = (int32_t)r; + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, + * the aggregate of 30 of them will have determinant 2^30 or -2^30. */ + VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 || + (int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30)); + *jacp = jac; + return eta; +} + +/* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps. + * + * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range + * (-2^30,2^30). + * + * This implements the update_de function from the explanation. + */ +static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp256k1_modinv32_signed30 *e, const secp256k1_modinv32_trans2x2 *t, const secp256k1_modinv32_modinfo* modinfo) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + const int32_t u = t->u, v = t->v, q = t->q, r = t->r; + int32_t di, ei, md, me, sd, se; + int64_t cd, ce; + int i; + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ + VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */ + VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */ + + /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ + sd = d->v[8] >> 31; + se = e->v[8] >> 31; + md = (u & sd) + (v & se); + me = (q & sd) + (r & se); + /* Begin computing t*[d,e]. */ + di = d->v[0]; + ei = e->v[0]; + cd = (int64_t)u * di + (int64_t)v * ei; + ce = (int64_t)q * di + (int64_t)r * ei; + /* Correct md,me so that t*[d,e]+modulus*[md,me] has 30 zero bottom bits. */ + md -= (modinfo->modulus_inv30 * (uint32_t)cd + md) & M30; + me -= (modinfo->modulus_inv30 * (uint32_t)ce + me) & M30; + /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ + cd += (int64_t)modinfo->modulus.v[0] * md; + ce += (int64_t)modinfo->modulus.v[0] * me; + /* Verify that the low 30 bits of the computation are indeed zero, and then throw them away. */ + VERIFY_CHECK(((int32_t)cd & M30) == 0); cd >>= 30; + VERIFY_CHECK(((int32_t)ce & M30) == 0); ce >>= 30; + /* Now iteratively compute limb i=1..8 of t*[d,e]+modulus*[md,me], and store them in output + * limb i-1 (shifting down by 30 bits). */ + for (i = 1; i < 9; ++i) { + di = d->v[i]; + ei = e->v[i]; + cd += (int64_t)u * di + (int64_t)v * ei; + ce += (int64_t)q * di + (int64_t)r * ei; + cd += (int64_t)modinfo->modulus.v[i] * md; + ce += (int64_t)modinfo->modulus.v[i] * me; + d->v[i - 1] = (int32_t)cd & M30; cd >>= 30; + e->v[i - 1] = (int32_t)ce & M30; ce >>= 30; + } + /* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */ + d->v[8] = (int32_t)cd; + e->v[8] = (int32_t)ce; + + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ +} + +/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. + * + * This implements the update_fg function from the explanation. + */ +static void secp256k1_modinv32_update_fg_30(secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + const int32_t u = t->u, v = t->v, q = t->q, r = t->r; + int32_t fi, gi; + int64_t cf, cg; + int i; + /* Start computing t*[f,g]. */ + fi = f->v[0]; + gi = g->v[0]; + cf = (int64_t)u * fi + (int64_t)v * gi; + cg = (int64_t)q * fi + (int64_t)r * gi; + /* Verify that the bottom 30 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30; + VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30; + /* Now iteratively compute limb i=1..8 of t*[f,g], and store them in output limb i-1 (shifting + * down by 30 bits). */ + for (i = 1; i < 9; ++i) { + fi = f->v[i]; + gi = g->v[i]; + cf += (int64_t)u * fi + (int64_t)v * gi; + cg += (int64_t)q * fi + (int64_t)r * gi; + f->v[i - 1] = (int32_t)cf & M30; cf >>= 30; + g->v[i - 1] = (int32_t)cg & M30; cg >>= 30; + } + /* What remains is limb 9 of t*[f,g]; store it as output limb 8. */ + f->v[8] = (int32_t)cf; + g->v[8] = (int32_t)cg; +} + +/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. + * + * Version that operates on a variable number of limbs in f and g. + * + * This implements the update_fg function from the explanation in modinv64_impl.h. + */ +static void secp256k1_modinv32_update_fg_30_var(int len, secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + const int32_t u = t->u, v = t->v, q = t->q, r = t->r; + int32_t fi, gi; + int64_t cf, cg; + int i; + VERIFY_CHECK(len > 0); + /* Start computing t*[f,g]. */ + fi = f->v[0]; + gi = g->v[0]; + cf = (int64_t)u * fi + (int64_t)v * gi; + cg = (int64_t)q * fi + (int64_t)r * gi; + /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30; + VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30; + /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting + * down by 30 bits). */ + for (i = 1; i < len; ++i) { + fi = f->v[i]; + gi = g->v[i]; + cf += (int64_t)u * fi + (int64_t)v * gi; + cg += (int64_t)q * fi + (int64_t)r * gi; + f->v[i - 1] = (int32_t)cf & M30; cf >>= 30; + g->v[i - 1] = (int32_t)cg & M30; cg >>= 30; + } + /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ + f->v[len - 1] = (int32_t)cf; + g->v[len - 1] = (int32_t)cg; +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ +static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */ + secp256k1_modinv32_signed30 d = {{0}}; + secp256k1_modinv32_signed30 e = {{1}}; + secp256k1_modinv32_signed30 f = modinfo->modulus; + secp256k1_modinv32_signed30 g = *x; + int i; + int32_t zeta = -1; /* zeta = -(delta+1/2); delta is initially 1/2. */ + + /* Do 20 iterations of 30 divsteps each = 600 divsteps. 590 suffices for 256-bit inputs. */ + for (i = 0; i < 20; ++i) { + /* Compute transition matrix and new zeta after 30 divsteps. */ + secp256k1_modinv32_trans2x2 t; + zeta = secp256k1_modinv32_divsteps_30(zeta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv32_update_fg_30(&f, &g, &t); + + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point sufficient iterations have been performed that g must have reached 0 + * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g + * values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, -1) == 0 || + secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 || + (secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo); + *x = d; +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */ +static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ + secp256k1_modinv32_signed30 d = {{0, 0, 0, 0, 0, 0, 0, 0, 0}}; + secp256k1_modinv32_signed30 e = {{1, 0, 0, 0, 0, 0, 0, 0, 0}}; + secp256k1_modinv32_signed30 f = modinfo->modulus; + secp256k1_modinv32_signed30 g = *x; +#ifdef VERIFY + int i = 0; +#endif + int j, len = 9; + int32_t eta = -1; /* eta = -delta; delta is initially 1 (faster for the variable-time code) */ + int32_t cond, fn, gn; + + /* Do iterations of 30 divsteps each until g=0. */ + while (1) { + /* Compute transition matrix and new eta after 30 divsteps. */ + secp256k1_modinv32_trans2x2 t; + eta = secp256k1_modinv32_divsteps_30_var(eta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t); + /* If the bottom limb of g is 0, there is a chance g=0. */ + if (g.v[0] == 0) { + cond = 0; + /* Check if all other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= g.v[j]; + } + /* If so, we're done. */ + if (cond == 0) break; + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int32_t)len - 2) >> 31; + cond |= fn ^ (fn >> 31); + cond |= gn ^ (gn >> 31); + /* If so, reduce length, propagating the sign of f and g's top limb into the one below. */ + if (cond == 0) { + f.v[len - 2] |= (uint32_t)fn << 30; + g.v[len - 2] |= (uint32_t)gn << 30; + --len; + } + + VERIFY_CHECK(++i < 25); /* We should never need more than 25*30 = 750 divsteps */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of + * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, -1) == 0 || + secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 || + (secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo); + *x = d; +} + +/* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1. + * In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */ +#ifdef VERIFY +#define JACOBI32_ITERATIONS 25 +#else +#define JACOBI32_ITERATIONS 50 +#endif + +/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ +static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { + /* Start with f=modulus, g=x, eta=-1. */ + secp256k1_modinv32_signed30 f = modinfo->modulus; + secp256k1_modinv32_signed30 g = *x; + int j, len = 9; + int32_t eta = -1; /* eta = -delta; delta is initially 1 */ + int32_t cond, fn, gn; + int jac = 0; + int count; + + /* The input limbs must all be non-negative. */ + VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0); + + /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we + * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or + * time out). */ + VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8]) != 0); + + for (count = 0; count < JACOBI32_ITERATIONS; ++count) { + /* Compute transition matrix and new eta after 30 posdivsteps. */ + secp256k1_modinv32_trans2x2 t; + eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t); + /* If the bottom limb of f is 1, there is a chance that f=1. */ + if (f.v[0] == 1) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= f.v[j]; + } + /* If so, we're done. If f=1, the Jacobi symbol (g | f)=1. */ + if (cond == 0) return 1 - 2*(jac & 1); + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int32_t)len - 2) >> 31; + cond |= fn; + cond |= gn; + /* If so, reduce length. */ + if (cond == 0) --len; + + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */ + return 0; +} + +#endif /* SECP256K1_MODINV32_IMPL_H */ diff --git a/external/secp256k1/src/modinv64.h b/external/secp256k1/src/modinv64.h new file mode 100644 index 00000000000..f4208e6c239 --- /dev/null +++ b/external/secp256k1/src/modinv64.h @@ -0,0 +1,47 @@ +/*********************************************************************** + * Copyright (c) 2020 Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODINV64_H +#define SECP256K1_MODINV64_H + +#include "util.h" + +#ifndef SECP256K1_WIDEMUL_INT128 +#error "modinv64 requires 128-bit wide multiplication support" +#endif + +/* A signed 62-bit limb representation of integers. + * + * Its value is sum(v[i] * 2^(62*i), i=0..4). */ +typedef struct { + int64_t v[5]; +} secp256k1_modinv64_signed62; + +typedef struct { + /* The modulus in signed62 notation, must be odd and in [3, 2^256]. */ + secp256k1_modinv64_signed62 modulus; + + /* modulus^{-1} mod 2^62 */ + uint64_t modulus_inv62; +} secp256k1_modinv64_modinfo; + +/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus). + * If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of + * x and modulus must be 1). These rules are automatically satisfied if the modulus is prime. + * + * On output, all of x's limbs will be in [0, 2^62). + */ +static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); + +/* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */ +static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); + +/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus + * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result + * cannot be computed. */ +static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); + +#endif /* SECP256K1_MODINV64_H */ diff --git a/external/secp256k1/src/modinv64_impl.h b/external/secp256k1/src/modinv64_impl.h new file mode 100644 index 00000000000..548787bedff --- /dev/null +++ b/external/secp256k1/src/modinv64_impl.h @@ -0,0 +1,780 @@ +/*********************************************************************** + * Copyright (c) 2020 Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODINV64_IMPL_H +#define SECP256K1_MODINV64_IMPL_H + +#include "int128.h" +#include "modinv64.h" + +/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and + * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. + * + * For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an + * implementation for N=62, using 62-bit signed limbs represented as int64_t. + */ + +/* Data type for transition matrices (see section 3 of explanation). + * + * t = [ u v ] + * [ q r ] + */ +typedef struct { + int64_t u, v, q, r; +} secp256k1_modinv64_trans2x2; + +#ifdef VERIFY +/* Helper function to compute the absolute value of an int64_t. + * (we don't use abs/labs/llabs as it depends on the int sizes). */ +static int64_t secp256k1_modinv64_abs(int64_t v) { + VERIFY_CHECK(v > INT64_MIN); + if (v < 0) return -v; + return v; +} + +static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}}; + +/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */ +static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) { + const uint64_t M62 = UINT64_MAX >> 2; + secp256k1_int128 c, d; + int i; + secp256k1_i128_from_i64(&c, 0); + for (i = 0; i < 4; ++i) { + if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor); + r->v[i] = secp256k1_i128_to_u64(&c) & M62; secp256k1_i128_rshift(&c, 62); + } + if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor); + secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c)); + VERIFY_CHECK(secp256k1_i128_eq_var(&c, &d)); + r->v[4] = secp256k1_i128_to_i64(&c); +} + +/* Return -1 for ab*factor. A has alen limbs; b has 5. */ +static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, int alen, const secp256k1_modinv64_signed62 *b, int64_t factor) { + int i; + secp256k1_modinv64_signed62 am, bm; + secp256k1_modinv64_mul_62(&am, a, alen, 1); /* Normalize all but the top limb of a. */ + secp256k1_modinv64_mul_62(&bm, b, 5, factor); + for (i = 0; i < 4; ++i) { + /* Verify that all but the top limb of a and b are normalized. */ + VERIFY_CHECK(am.v[i] >> 62 == 0); + VERIFY_CHECK(bm.v[i] >> 62 == 0); + } + for (i = 4; i >= 0; --i) { + if (am.v[i] < bm.v[i]) return -1; + if (am.v[i] > bm.v[i]) return 1; + } + return 0; +} + +/* Check if the determinant of t is equal to 1 << n. If abs, check if |det t| == 1 << n. */ +static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n, int abs) { + secp256k1_int128 a; + secp256k1_i128_det(&a, t->u, t->v, t->q, t->r); + if (secp256k1_i128_check_pow2(&a, n, 1)) return 1; + if (abs && secp256k1_i128_check_pow2(&a, n, -1)) return 1; + return 0; +} +#endif + +/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus + * to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the + * process. The input must have limbs in range (-2^62,2^62). The output will have limbs in range + * [0,2^62). */ +static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) { + const int64_t M62 = (int64_t)(UINT64_MAX >> 2); + int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4]; + volatile int64_t cond_add, cond_negate; + +#ifdef VERIFY + /* Verify that all limbs are in range (-2^62,2^62). */ + int i; + for (i = 0; i < 5; ++i) { + VERIFY_CHECK(r->v[i] >= -M62); + VERIFY_CHECK(r->v[i] <= M62); + } + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ +#endif + + /* In a first step, add the modulus if the input is negative, and then negate if requested. + * This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input + * limbs are in range (-2^62,2^62), this cannot overflow an int64_t. Note that the right + * shifts below are signed sign-extending shifts (see assumptions.h for tests that that is + * indeed the behavior of the right shift operator). */ + cond_add = r4 >> 63; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + cond_negate = sign >> 63; + r0 = (r0 ^ cond_negate) - cond_negate; + r1 = (r1 ^ cond_negate) - cond_negate; + r2 = (r2 ^ cond_negate) - cond_negate; + r3 = (r3 ^ cond_negate) - cond_negate; + r4 = (r4 ^ cond_negate) - cond_negate; + /* Propagate the top bits, to bring limbs back to range (-2^62,2^62). */ + r1 += r0 >> 62; r0 &= M62; + r2 += r1 >> 62; r1 &= M62; + r3 += r2 >> 62; r2 &= M62; + r4 += r3 >> 62; r3 &= M62; + + /* In a second step add the modulus again if the result is still negative, bringing + * r to range [0,modulus). */ + cond_add = r4 >> 63; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + /* And propagate again. */ + r1 += r0 >> 62; r0 &= M62; + r2 += r1 >> 62; r1 &= M62; + r3 += r2 >> 62; r2 &= M62; + r4 += r3 >> 62; r3 &= M62; + + r->v[0] = r0; + r->v[1] = r1; + r->v[2] = r2; + r->v[3] = r3; + r->v[4] = r4; + + VERIFY_CHECK(r0 >> 62 == 0); + VERIFY_CHECK(r1 >> 62 == 0); + VERIFY_CHECK(r2 >> 62 == 0); + VERIFY_CHECK(r3 >> 62 == 0); + VERIFY_CHECK(r4 >> 62 == 0); + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ +} + +/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)). + * Note that the transformation matrix is scaled by 2^62 and not 2^59. + * + * Input: zeta: initial zeta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final zeta + * + * Implements the divsteps_n_matrix function from the explanation. + */ +static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) { + /* u,v,q,r are the elements of the transformation matrix being built up, + * starting with the identity matrix times 8 (because the caller expects + * a result scaled by 2^62). Semantically they are signed integers + * in range [-2^62,2^62], but here represented as unsigned mod 2^64. This + * permits left shifting (which is UB for negative numbers). The range + * being inside [-2^63,2^63) means that casting to signed works correctly. + */ + uint64_t u = 8, v = 0, q = 0, r = 8; + volatile uint64_t c1, c2; + uint64_t mask1, mask2, f = f0, g = g0, x, y, z; + int i; + + for (i = 3; i < 62; ++i) { + VERIFY_CHECK((f & 1) == 1); /* f must always be odd */ + VERIFY_CHECK((u * f0 + v * g0) == f << i); + VERIFY_CHECK((q * f0 + r * g0) == g << i); + /* Compute conditional masks for (zeta < 0) and for (g & 1). */ + c1 = zeta >> 63; + mask1 = c1; + c2 = g & 1; + mask2 = -c2; + /* Compute x,y,z, conditionally negated versions of f,u,v. */ + x = (f ^ mask1) - mask1; + y = (u ^ mask1) - mask1; + z = (v ^ mask1) - mask1; + /* Conditionally add x,y,z to g,q,r. */ + g += x & mask2; + q += y & mask2; + r += z & mask2; + /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */ + mask1 &= mask2; + /* Conditionally change zeta into -zeta-2 or zeta-1. */ + zeta = (zeta ^ mask1) - 1; + /* Conditionally add g,q,r to f,u,v. */ + f += g & mask1; + u += q & mask1; + v += r & mask1; + /* Shifts */ + g >>= 1; + u <<= 1; + v <<= 1; + /* Bounds on zeta that follow from the bounds on iteration count (max 10*59 divsteps). */ + VERIFY_CHECK(zeta >= -591 && zeta <= 591); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 59 of them will have determinant 2^59. Multiplying with the initial + * 8*identity (which has determinant 2^6) means the overall outputs has determinant + * 2^65. */ + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0)); + + return zeta; +} + +/* Compute the transition matrix and eta for 62 divsteps (variable time, eta=-delta). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final eta + * + * Implements the divsteps_n_matrix_var function from the explanation. + */ +static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) { + /* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */ + uint64_t u = 1, v = 0, q = 0, r = 1; + uint64_t f = f0, g = g0, m; + uint32_t w; + int i = 62, limit, zeros; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* We're done once we've done 62 divsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); + /* Bounds on eta that follow from the bounds on iteration count (max 12*62 divsteps). */ + VERIFY_CHECK(eta >= -745 && eta <= 745); + /* If eta is negative, negate it and replace f,g with g,-f. */ + if (eta < 0) { + uint64_t tmp; + eta = -eta; + tmp = f; f = g; g = -tmp; + tmp = u; u = q; q = -tmp; + tmp = v; v = r; r = -tmp; + /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled + * out (as we'd be done before that point), and no more than eta+1 can be done as its + * sign will flip again once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 6) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 63U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) + * bits. */ + w = (f * g * (f * f - 2)) & m; + } else { + /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as + * eta tends to be smaller here. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 4) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 15U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) + * bits. */ + w = f + (((f + 1) & 4) << 1); + w = (-w * g) & m; + } + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 62 of them will have determinant 2^62. */ + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0)); + + return eta; +} + +/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track + * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because + * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign + * by applying the returned transformation matrix to it. The other bits of *jacp may + * change, but are meaningless. + * Return: final eta + */ +static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t, int *jacp) { + /* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */ + uint64_t u = 1, v = 0, q = 0, r = 1; + uint64_t f = f0, g = g0, m; + uint32_t w; + int i = 62, limit, zeros; + int jac = *jacp; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* Update the bottom bit of jac: when dividing g by an odd power of 2, + * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ + jac ^= (zeros & ((f >> 1) ^ (f >> 2))); + /* We're done once we've done 62 posdivsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); + /* If eta is negative, negate it and replace f,g with g,f. */ + if (eta < 0) { + uint64_t tmp; + eta = -eta; + tmp = f; f = g; g = tmp; + tmp = u; u = q; q = tmp; + tmp = v; v = r; r = tmp; + /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign + * if both f and g are 3 mod 4. */ + jac ^= ((f & g) >> 1); + /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled + * out (as we'd be done before that point), and no more than eta+1 can be done as its + * sign will flip again once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 6) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 63U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) + * bits. */ + w = (f * g * (f * f - 2)) & m; + } else { + /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as + * eta tends to be smaller here. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 4) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 15U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) + * bits. */ + w = f + (((f + 1) & 4) << 1); + w = (-w * g) & m; + } + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, + * the aggregate of 62 of them will have determinant 2^62 or -2^62. */ + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1)); + + *jacp = jac; + return eta; +} + +/* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62. + * + * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range + * (-2^62,2^62). + * + * This implements the update_de function from the explanation. + */ +static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) { + const uint64_t M62 = UINT64_MAX >> 2; + const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4]; + const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4]; + const int64_t u = t->u, v = t->v, q = t->q, r = t->r; + int64_t md, me, sd, se; + secp256k1_int128 cd, ce; + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ + VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */ + VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */ + + /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ + sd = d4 >> 63; + se = e4 >> 63; + md = (u & sd) + (v & se); + me = (q & sd) + (r & se); + /* Begin computing t*[d,e]. */ + secp256k1_i128_mul(&cd, u, d0); + secp256k1_i128_accum_mul(&cd, v, e0); + secp256k1_i128_mul(&ce, q, d0); + secp256k1_i128_accum_mul(&ce, r, e0); + /* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */ + md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62; + me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62; + /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me); + /* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */ + VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62); + VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62); + /* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */ + secp256k1_i128_accum_mul(&cd, u, d1); + secp256k1_i128_accum_mul(&cd, v, e1); + secp256k1_i128_accum_mul(&ce, q, d1); + secp256k1_i128_accum_mul(&ce, r, e1); + if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */ + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me); + } + d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); + /* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */ + secp256k1_i128_accum_mul(&cd, u, d2); + secp256k1_i128_accum_mul(&cd, v, e2); + secp256k1_i128_accum_mul(&ce, q, d2); + secp256k1_i128_accum_mul(&ce, r, e2); + if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */ + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me); + } + d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); + /* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */ + secp256k1_i128_accum_mul(&cd, u, d3); + secp256k1_i128_accum_mul(&cd, v, e3); + secp256k1_i128_accum_mul(&ce, q, d3); + secp256k1_i128_accum_mul(&ce, r, e3); + if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */ + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me); + } + d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); + /* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */ + secp256k1_i128_accum_mul(&cd, u, d4); + secp256k1_i128_accum_mul(&cd, v, e4); + secp256k1_i128_accum_mul(&ce, q, d4); + secp256k1_i128_accum_mul(&ce, r, e4); + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me); + d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); + /* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */ + d->v[4] = secp256k1_i128_to_i64(&cd); + e->v[4] = secp256k1_i128_to_i64(&ce); + + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ +} + +/* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62. + * + * This implements the update_fg function from the explanation. + */ +static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) { + const uint64_t M62 = UINT64_MAX >> 2; + const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4]; + const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4]; + const int64_t u = t->u, v = t->v, q = t->q, r = t->r; + secp256k1_int128 cf, cg; + /* Start computing t*[f,g]. */ + secp256k1_i128_mul(&cf, u, f0); + secp256k1_i128_accum_mul(&cf, v, g0); + secp256k1_i128_mul(&cg, q, f0); + secp256k1_i128_accum_mul(&cg, r, g0); + /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); + VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); + /* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */ + secp256k1_i128_accum_mul(&cf, u, f1); + secp256k1_i128_accum_mul(&cf, v, g1); + secp256k1_i128_accum_mul(&cg, q, f1); + secp256k1_i128_accum_mul(&cg, r, g1); + f->v[0] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[0] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + /* Compute limb 2 of t*[f,g], and store it as output limb 1. */ + secp256k1_i128_accum_mul(&cf, u, f2); + secp256k1_i128_accum_mul(&cf, v, g2); + secp256k1_i128_accum_mul(&cg, q, f2); + secp256k1_i128_accum_mul(&cg, r, g2); + f->v[1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + /* Compute limb 3 of t*[f,g], and store it as output limb 2. */ + secp256k1_i128_accum_mul(&cf, u, f3); + secp256k1_i128_accum_mul(&cf, v, g3); + secp256k1_i128_accum_mul(&cg, q, f3); + secp256k1_i128_accum_mul(&cg, r, g3); + f->v[2] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[2] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + /* Compute limb 4 of t*[f,g], and store it as output limb 3. */ + secp256k1_i128_accum_mul(&cf, u, f4); + secp256k1_i128_accum_mul(&cf, v, g4); + secp256k1_i128_accum_mul(&cg, q, f4); + secp256k1_i128_accum_mul(&cg, r, g4); + f->v[3] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[3] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + /* What remains is limb 5 of t*[f,g]; store it as output limb 4. */ + f->v[4] = secp256k1_i128_to_i64(&cf); + g->v[4] = secp256k1_i128_to_i64(&cg); +} + +/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps. + * + * Version that operates on a variable number of limbs in f and g. + * + * This implements the update_fg function from the explanation. + */ +static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) { + const uint64_t M62 = UINT64_MAX >> 2; + const int64_t u = t->u, v = t->v, q = t->q, r = t->r; + int64_t fi, gi; + secp256k1_int128 cf, cg; + int i; + VERIFY_CHECK(len > 0); + /* Start computing t*[f,g]. */ + fi = f->v[0]; + gi = g->v[0]; + secp256k1_i128_mul(&cf, u, fi); + secp256k1_i128_accum_mul(&cf, v, gi); + secp256k1_i128_mul(&cg, q, fi); + secp256k1_i128_accum_mul(&cg, r, gi); + /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); + VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); + /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting + * down by 62 bits). */ + for (i = 1; i < len; ++i) { + fi = f->v[i]; + gi = g->v[i]; + secp256k1_i128_accum_mul(&cf, u, fi); + secp256k1_i128_accum_mul(&cf, v, gi); + secp256k1_i128_accum_mul(&cg, q, fi); + secp256k1_i128_accum_mul(&cg, r, gi); + f->v[i - 1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[i - 1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + } + /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ + f->v[len - 1] = secp256k1_i128_to_i64(&cf); + g->v[len - 1] = secp256k1_i128_to_i64(&cg); +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ +static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */ + secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; + secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; + secp256k1_modinv64_signed62 f = modinfo->modulus; + secp256k1_modinv64_signed62 g = *x; + int i; + int64_t zeta = -1; /* zeta = -(delta+1/2); delta starts at 1/2. */ + + /* Do 10 iterations of 59 divsteps each = 590 divsteps. This suffices for 256-bit inputs. */ + for (i = 0; i < 10; ++i) { + /* Compute transition matrix and new zeta after 59 divsteps. */ + secp256k1_modinv64_trans2x2 t; + zeta = secp256k1_modinv64_divsteps_59(zeta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv64_update_fg_62(&f, &g, &t); + + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point sufficient iterations have been performed that g must have reached 0 + * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g + * values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, -1) == 0 || + secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 || + (secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo); + *x = d; +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */ +static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ + secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; + secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; + secp256k1_modinv64_signed62 f = modinfo->modulus; + secp256k1_modinv64_signed62 g = *x; +#ifdef VERIFY + int i = 0; +#endif + int j, len = 5; + int64_t eta = -1; /* eta = -delta; delta is initially 1 */ + int64_t cond, fn, gn; + + /* Do iterations of 62 divsteps each until g=0. */ + while (1) { + /* Compute transition matrix and new eta after 62 divsteps. */ + secp256k1_modinv64_trans2x2 t; + eta = secp256k1_modinv64_divsteps_62_var(eta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t); + /* If the bottom limb of g is zero, there is a chance that g=0. */ + if (g.v[0] == 0) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= g.v[j]; + } + /* If so, we're done. */ + if (cond == 0) break; + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int64_t)len - 2) >> 63; + cond |= fn ^ (fn >> 63); + cond |= gn ^ (gn >> 63); + /* If so, reduce length, propagating the sign of f and g's top limb into the one below. */ + if (cond == 0) { + f.v[len - 2] |= (uint64_t)fn << 62; + g.v[len - 2] |= (uint64_t)gn << 62; + --len; + } + + VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of + * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, -1) == 0 || + secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 || + (secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo); + *x = d; +} + +/* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1. + * In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */ +#ifdef VERIFY +#define JACOBI64_ITERATIONS 12 +#else +#define JACOBI64_ITERATIONS 25 +#endif + +/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ +static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { + /* Start with f=modulus, g=x, eta=-1. */ + secp256k1_modinv64_signed62 f = modinfo->modulus; + secp256k1_modinv64_signed62 g = *x; + int j, len = 5; + int64_t eta = -1; /* eta = -delta; delta is initially 1 */ + int64_t cond, fn, gn; + int jac = 0; + int count; + + /* The input limbs must all be non-negative. */ + VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0); + + /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we + * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or + * time out). */ + VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4]) != 0); + + for (count = 0; count < JACOBI64_ITERATIONS; ++count) { + /* Compute transition matrix and new eta after 62 posdivsteps. */ + secp256k1_modinv64_trans2x2 t; + eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t); + /* If the bottom limb of f is 1, there is a chance that f=1. */ + if (f.v[0] == 1) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= f.v[j]; + } + /* If so, we're done. When f=1, the Jacobi symbol (g | f)=1. */ + if (cond == 0) return 1 - 2*(jac & 1); + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int64_t)len - 2) >> 63; + cond |= fn; + cond |= gn; + /* If so, reduce length. */ + if (cond == 0) --len; + + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */ + return 0; +} + +#endif /* SECP256K1_MODINV64_IMPL_H */ diff --git a/external/secp256k1/src/modules/ecdh/Makefile.am.include b/external/secp256k1/src/modules/ecdh/Makefile.am.include new file mode 100644 index 00000000000..7f7f95f1fd6 --- /dev/null +++ b/external/secp256k1/src/modules/ecdh/Makefile.am.include @@ -0,0 +1,4 @@ +include_HEADERS += include/secp256k1_ecdh.h +noinst_HEADERS += src/modules/ecdh/main_impl.h +noinst_HEADERS += src/modules/ecdh/tests_impl.h +noinst_HEADERS += src/modules/ecdh/bench_impl.h diff --git a/external/secp256k1/src/modules/ecdh/bench_impl.h b/external/secp256k1/src/modules/ecdh/bench_impl.h new file mode 100644 index 00000000000..c23aaa94d17 --- /dev/null +++ b/external/secp256k1/src/modules/ecdh/bench_impl.h @@ -0,0 +1,57 @@ +/*********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_BENCH_H +#define SECP256K1_MODULE_ECDH_BENCH_H + +#include "../../../include/secp256k1_ecdh.h" + +typedef struct { + secp256k1_context *ctx; + secp256k1_pubkey point; + unsigned char scalar[32]; +} bench_ecdh_data; + +static void bench_ecdh_setup(void* arg) { + int i; + bench_ecdh_data *data = (bench_ecdh_data*)arg; + const unsigned char point[] = { + 0x03, + 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, + 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, + 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, + 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f + }; + + for (i = 0; i < 32; i++) { + data->scalar[i] = i + 1; + } + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); +} + +static void bench_ecdh(void* arg, int iters) { + int i; + unsigned char res[32]; + bench_ecdh_data *data = (bench_ecdh_data*)arg; + + for (i = 0; i < iters; i++) { + CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1); + } +} + +static void run_ecdh_bench(int iters, int argc, char** argv) { + bench_ecdh_data data; + int d = argc == 1; + + /* create a context with no capabilities */ + data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); + + if (d || have_flag(argc, argv, "ecdh")) run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters); + + secp256k1_context_destroy(data.ctx); +} + +#endif /* SECP256K1_MODULE_ECDH_BENCH_H */ diff --git a/external/secp256k1/src/modules/ecdh/main_impl.h b/external/secp256k1/src/modules/ecdh/main_impl.h new file mode 100644 index 00000000000..842b5359e37 --- /dev/null +++ b/external/secp256k1/src/modules/ecdh/main_impl.h @@ -0,0 +1,74 @@ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_MAIN_H +#define SECP256K1_MODULE_ECDH_MAIN_H + +#include "../../../include/secp256k1_ecdh.h" +#include "../../ecmult_const_impl.h" + +static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { + unsigned char version = (y32[31] & 0x01) | 0x02; + secp256k1_sha256 sha; + (void)data; + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &version, 1); + secp256k1_sha256_write(&sha, x32, 32); + secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_clear(&sha); + + return 1; +} + +const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; +const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256; + +int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) { + int ret = 0; + int overflow = 0; + secp256k1_gej res; + secp256k1_ge pt; + secp256k1_scalar s; + unsigned char x[32]; + unsigned char y[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + + if (hashfp == NULL) { + hashfp = secp256k1_ecdh_hash_function_default; + } + + secp256k1_pubkey_load(ctx, &pt, point); + secp256k1_scalar_set_b32(&s, scalar, &overflow); + + overflow |= secp256k1_scalar_is_zero(&s); + secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow); + + secp256k1_ecmult_const(&res, &pt, &s); + secp256k1_ge_set_gej(&pt, &res); + + /* Compute a hash of the point */ + secp256k1_fe_normalize(&pt.x); + secp256k1_fe_normalize(&pt.y); + secp256k1_fe_get_b32(x, &pt.x); + secp256k1_fe_get_b32(y, &pt.y); + + ret = hashfp(output, x, y, data); + + secp256k1_memclear(x, sizeof(x)); + secp256k1_memclear(y, sizeof(y)); + secp256k1_scalar_clear(&s); + secp256k1_ge_clear(&pt); + secp256k1_gej_clear(&res); + + return !!ret & !overflow; +} + +#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/external/secp256k1/src/modules/ecdh/tests_impl.h b/external/secp256k1/src/modules/ecdh/tests_impl.h new file mode 100644 index 00000000000..3c3acdaf8c3 --- /dev/null +++ b/external/secp256k1/src/modules/ecdh/tests_impl.h @@ -0,0 +1,152 @@ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_TESTS_H +#define SECP256K1_MODULE_ECDH_TESTS_H + +static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)output; + (void)x; + (void)y; + (void)data; + return 0; +} + +static int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)data; + /* Save x and y as uncompressed public key */ + output[0] = 0x04; + memcpy(output + 1, x, 32); + memcpy(output + 33, y, 32); + return 1; +} + +static void test_ecdh_api(void) { + secp256k1_pubkey point; + unsigned char res[32]; + unsigned char s_one[32] = { 0 }; + s_one[31] = 1; + + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1); + + /* Check all NULLs are detected */ + CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, NULL, &point, s_one, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, NULL, s_one, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, &point, NULL, NULL, NULL)); + CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); +} + +static void test_ecdh_generator_basepoint(void) { + unsigned char s_one[32] = { 0 }; + secp256k1_pubkey point[2]; + int i; + + s_one[31] = 1; + /* Check against pubkey creation when the basepoint is the generator */ + for (i = 0; i < 2 * COUNT; ++i) { + secp256k1_sha256 sha; + unsigned char s_b32[32]; + unsigned char output_ecdh[65]; + unsigned char output_ser[32]; + unsigned char point_ser[65]; + size_t point_ser_len = sizeof(point_ser); + secp256k1_scalar s; + + testutil_random_scalar_order(&s); + secp256k1_scalar_get_b32(s_b32, &s); + + CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &point[1], s_b32) == 1); + + /* compute using ECDH function with custom hash function */ + CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); + /* compare */ + CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0); + + /* compute using ECDH function with default hash function */ + CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, point_ser, point_ser_len); + secp256k1_sha256_finalize(&sha, output_ser); + /* compare */ + CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0); + } +} + +static void test_bad_scalar(void) { + unsigned char s_zero[32] = { 0 }; + unsigned char s_overflow[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + unsigned char s_rand[32] = { 0 }; + unsigned char output[32]; + secp256k1_scalar rand; + secp256k1_pubkey point; + + /* Create random point */ + testutil_random_scalar_order(&rand); + secp256k1_scalar_get_b32(s_rand, &rand); + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1); + + /* Try to multiply it by bad values */ + CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0); + CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 0); + /* ...and a good one */ + s_overflow[31] -= 1; + CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 1); + + /* Hash function failure results in ecdh failure */ + CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0); +} + +/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */ +static void test_result_basepoint(void) { + secp256k1_pubkey point; + secp256k1_scalar rand; + unsigned char s[32]; + unsigned char s_inv[32]; + unsigned char out[32]; + unsigned char out_inv[32]; + unsigned char out_base[32]; + int i; + + unsigned char s_one[32] = { 0 }; + s_one[31] = 1; + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1); + CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1); + + for (i = 0; i < 2 * COUNT; i++) { + testutil_random_scalar_order(&rand); + secp256k1_scalar_get_b32(s, &rand); + secp256k1_scalar_inverse(&rand, &rand); + secp256k1_scalar_get_b32(s_inv, &rand); + + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s) == 1); + CHECK(secp256k1_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1); + CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0); + + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_inv) == 1); + CHECK(secp256k1_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1); + CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0); + } +} + +static void run_ecdh_tests(void) { + test_ecdh_api(); + test_ecdh_generator_basepoint(); + test_bad_scalar(); + test_result_basepoint(); +} + +#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/external/secp256k1/src/modules/ellswift/Makefile.am.include b/external/secp256k1/src/modules/ellswift/Makefile.am.include new file mode 100644 index 00000000000..8251231ea3c --- /dev/null +++ b/external/secp256k1/src/modules/ellswift/Makefile.am.include @@ -0,0 +1,5 @@ +include_HEADERS += include/secp256k1_ellswift.h +noinst_HEADERS += src/modules/ellswift/bench_impl.h +noinst_HEADERS += src/modules/ellswift/main_impl.h +noinst_HEADERS += src/modules/ellswift/tests_impl.h +noinst_HEADERS += src/modules/ellswift/tests_exhaustive_impl.h diff --git a/external/secp256k1/src/modules/ellswift/bench_impl.h b/external/secp256k1/src/modules/ellswift/bench_impl.h new file mode 100644 index 00000000000..b16a3a36870 --- /dev/null +++ b/external/secp256k1/src/modules/ellswift/bench_impl.h @@ -0,0 +1,106 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_BENCH_H +#define SECP256K1_MODULE_ELLSWIFT_BENCH_H + +#include "../../../include/secp256k1_ellswift.h" + +typedef struct { + secp256k1_context *ctx; + secp256k1_pubkey point[256]; + unsigned char rnd64[64]; +} bench_ellswift_data; + +static void bench_ellswift_setup(void *arg) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + static const unsigned char init[64] = { + 0x78, 0x1f, 0xb7, 0xd4, 0x67, 0x7f, 0x08, 0x68, + 0xdb, 0xe3, 0x1d, 0x7f, 0x1b, 0xb0, 0xf6, 0x9e, + 0x0a, 0x64, 0xca, 0x32, 0x9e, 0xc6, 0x20, 0x79, + 0x03, 0xf3, 0xd0, 0x46, 0x7a, 0x0f, 0xd2, 0x21, + 0xb0, 0x2c, 0x46, 0xd8, 0xba, 0xca, 0x26, 0x4f, + 0x8f, 0x8c, 0xd4, 0xdd, 0x2d, 0x04, 0xbe, 0x30, + 0x48, 0x51, 0x1e, 0xd4, 0x16, 0xfd, 0x42, 0x85, + 0x62, 0xc9, 0x02, 0xf9, 0x89, 0x84, 0xff, 0xdc + }; + memcpy(data->rnd64, init, 64); + for (i = 0; i < 256; ++i) { + int j; + CHECK(secp256k1_ellswift_decode(data->ctx, &data->point[i], data->rnd64)); + for (j = 0; j < 64; ++j) { + data->rnd64[j] += 1; + } + } + CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[255], init + 16)); +} + +static void bench_ellswift_encode(void *arg, int iters) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[i & 255], data->rnd64 + 16)); + } +} + +static void bench_ellswift_create(void *arg, int iters) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + unsigned char buf[64]; + CHECK(secp256k1_ellswift_create(data->ctx, buf, data->rnd64, data->rnd64 + 32)); + memcpy(data->rnd64, buf, 64); + } +} + +static void bench_ellswift_decode(void *arg, int iters) { + int i; + secp256k1_pubkey out; + size_t len; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + CHECK(secp256k1_ellswift_decode(data->ctx, &out, data->rnd64) == 1); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->rnd64 + (i % 32), &len, &out, SECP256K1_EC_COMPRESSED)); + } +} + +static void bench_ellswift_xdh(void *arg, int iters) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + int party = i & 1; + CHECK(secp256k1_ellswift_xdh(data->ctx, + data->rnd64 + (i % 33), + data->rnd64, + data->rnd64, + data->rnd64 + ((i + 16) % 33), + party, + secp256k1_ellswift_xdh_hash_function_bip324, + NULL) == 1); + } +} + +void run_ellswift_bench(int iters, int argc, char **argv) { + bench_ellswift_data data; + int d = argc == 1; + + /* create a context with signing capabilities */ + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "encode") || have_flag(argc, argv, "ellswift_encode")) run_benchmark("ellswift_encode", bench_ellswift_encode, bench_ellswift_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_decode")) run_benchmark("ellswift_decode", bench_ellswift_decode, bench_ellswift_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ellswift_keygen")) run_benchmark("ellswift_keygen", bench_ellswift_create, bench_ellswift_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ecdh") || have_flag(argc, argv, "ellswift_ecdh")) run_benchmark("ellswift_ecdh", bench_ellswift_xdh, bench_ellswift_setup, NULL, &data, 10, iters); + + secp256k1_context_destroy(data.ctx); +} + +#endif diff --git a/external/secp256k1/src/modules/ellswift/main_impl.h b/external/secp256k1/src/modules/ellswift/main_impl.h new file mode 100644 index 00000000000..745a969139b --- /dev/null +++ b/external/secp256k1/src/modules/ellswift/main_impl.h @@ -0,0 +1,592 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_MAIN_H +#define SECP256K1_MODULE_ELLSWIFT_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_ellswift.h" +#include "../../eckey.h" +#include "../../hash.h" + +/** c1 = (sqrt(-3)-1)/2 */ +static const secp256k1_fe secp256k1_ellswift_c1 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40); +/** c2 = (-sqrt(-3)-1)/2 = -(c1+1) */ +static const secp256k1_fe secp256k1_ellswift_c2 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee); +/** c3 = (-sqrt(-3)+1)/2 = -c1 = c2+1 */ +static const secp256k1_fe secp256k1_ellswift_c3 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ef); +/** c4 = (sqrt(-3)+1)/2 = -c2 = c1+1 */ +static const secp256k1_fe secp256k1_ellswift_c4 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa41); + +/** Decode ElligatorSwift encoding (u, t) to a fraction xn/xd representing a curve X coordinate. */ +static void secp256k1_ellswift_xswiftec_frac_var(secp256k1_fe *xn, secp256k1_fe *xd, const secp256k1_fe *u, const secp256k1_fe *t) { + /* The implemented algorithm is the following (all operations in GF(p)): + * + * - Let c0 = sqrt(-3) = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852. + * - If u = 0, set u = 1. + * - If t = 0, set t = 1. + * - If u^3+7+t^2 = 0, set t = 2*t. + * - Let X = (u^3+7-t^2)/(2*t). + * - Let Y = (X+t)/(c0*u). + * - If x3 = u+4*Y^2 is a valid x coordinate, return it. + * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it. + * - Return x1 = (X/Y-u)/2 (which is now guaranteed to be a valid x coordinate). + * + * Introducing s=t^2, g=u^3+7, and simplifying x1=-(x2+u) we get: + * + * - Let c0 = ... + * - If u = 0, set u = 1. + * - If t = 0, set t = 1. + * - Let s = t^2 + * - Let g = u^3+7 + * - If g+s = 0, set t = 2*t, s = 4*s + * - Let X = (g-s)/(2*t). + * - Let Y = (X+t)/(c0*u) = (g+s)/(2*c0*t*u). + * - If x3 = u+4*Y^2 is a valid x coordinate, return it. + * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it. + * - Return x1 = -(x2+u). + * + * Now substitute Y^2 = -(g+s)^2/(12*s*u^2) and X/Y = c0*u*(g-s)/(g+s). This + * means X and Y do not need to be evaluated explicitly anymore. + * + * - ... + * - If g+s = 0, set s = 4*s. + * - If x3 = u-(g+s)^2/(3*s*u^2) is a valid x coordinate, return it. + * - If x2 = (-c0*u*(g-s)/(g+s)-u)/2 is a valid x coordinate, return it. + * - Return x1 = -(x2+u). + * + * Simplifying x2 using 2 additional constants: + * + * - Let c1 = (c0-1)/2 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40. + * - Let c2 = (-c0-1)/2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee. + * - ... + * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it. + * - ... + * + * Writing x3 as a fraction: + * + * - ... + * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) ... + * - ... + + * Overall, we get: + * + * - Let c1 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40. + * - Let c2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee. + * - If u = 0, set u = 1. + * - If t = 0, set s = 1, else set s = t^2. + * - Let g = u^3+7. + * - If g+s = 0, set s = 4*s. + * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) is a valid x coordinate, return it. + * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it. + * - Return x1 = -(x2+u). + */ + secp256k1_fe u1, s, g, p, d, n, l; + u1 = *u; + if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&u1), 0)) u1 = secp256k1_fe_one; + secp256k1_fe_sqr(&s, t); + if (EXPECT(secp256k1_fe_normalizes_to_zero_var(t), 0)) s = secp256k1_fe_one; + secp256k1_fe_sqr(&l, &u1); /* l = u^2 */ + secp256k1_fe_mul(&g, &l, &u1); /* g = u^3 */ + secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3 + 7 */ + p = g; /* p = g */ + secp256k1_fe_add(&p, &s); /* p = g+s */ + if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&p), 0)) { + secp256k1_fe_mul_int(&s, 4); + /* Recompute p = g+s */ + p = g; /* p = g */ + secp256k1_fe_add(&p, &s); /* p = g+s */ + } + secp256k1_fe_mul(&d, &s, &l); /* d = s*u^2 */ + secp256k1_fe_mul_int(&d, 3); /* d = 3*s*u^2 */ + secp256k1_fe_sqr(&l, &p); /* l = (g+s)^2 */ + secp256k1_fe_negate(&l, &l, 1); /* l = -(g+s)^2 */ + secp256k1_fe_mul(&n, &d, &u1); /* n = 3*s*u^3 */ + secp256k1_fe_add(&n, &l); /* n = 3*s*u^3-(g+s)^2 */ + if (secp256k1_ge_x_frac_on_curve_var(&n, &d)) { + /* Return x3 = n/d = (3*s*u^3-(g+s)^2)/(3*s*u^2) */ + *xn = n; + *xd = d; + return; + } + *xd = p; + secp256k1_fe_mul(&l, &secp256k1_ellswift_c1, &s); /* l = c1*s */ + secp256k1_fe_mul(&n, &secp256k1_ellswift_c2, &g); /* n = c2*g */ + secp256k1_fe_add(&n, &l); /* n = c1*s+c2*g */ + secp256k1_fe_mul(&n, &n, &u1); /* n = u*(c1*s+c2*g) */ + /* Possible optimization: in the invocation below, p^2 = (g+s)^2 is computed, + * which we already have computed above. This could be deduplicated. */ + if (secp256k1_ge_x_frac_on_curve_var(&n, &p)) { + /* Return x2 = n/p = u*(c1*s+c2*g)/(g+s) */ + *xn = n; + return; + } + secp256k1_fe_mul(&l, &p, &u1); /* l = u*(g+s) */ + secp256k1_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */ + secp256k1_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */ + + VERIFY_CHECK(secp256k1_ge_x_frac_on_curve_var(xn, &p)); + /* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */ +} + +/** Decode ElligatorSwift encoding (u, t) to X coordinate. */ +static void secp256k1_ellswift_xswiftec_var(secp256k1_fe *x, const secp256k1_fe *u, const secp256k1_fe *t) { + secp256k1_fe xn, xd; + secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, u, t); + secp256k1_fe_inv_var(&xd, &xd); + secp256k1_fe_mul(x, &xn, &xd); +} + +/** Decode ElligatorSwift encoding (u, t) to point P. */ +static void secp256k1_ellswift_swiftec_var(secp256k1_ge *p, const secp256k1_fe *u, const secp256k1_fe *t) { + secp256k1_fe x; + secp256k1_ellswift_xswiftec_var(&x, u, t); + secp256k1_ge_set_xo_var(p, &x, secp256k1_fe_is_odd(t)); +} + +/* Try to complete an ElligatorSwift encoding (u, t) for X coordinate x, given u and x. + * + * There may be up to 8 distinct t values such that (u, t) decodes back to x, but also + * fewer, or none at all. Each such partial inverse can be accessed individually using a + * distinct input argument c (in range 0-7), and some or all of these may return failure. + * The following guarantees exist: + * - Given (x, u), no two distinct c values give the same successful result t. + * - Every successful result maps back to x through secp256k1_ellswift_xswiftec_var. + * - Given (x, u), all t values that map back to x can be reached by combining the + * successful results from this function over all c values, with the exception of: + * - this function cannot be called with u=0 + * - no result with t=0 will be returned + * - no result for which u^3 + t^2 + 7 = 0 will be returned. + * + * The rather unusual encoding of bits in c (a large "if" based on the middle bit, and then + * using the low and high bits to pick signs of square roots) is to match the paper's + * encoding more closely: c=0 through c=3 match branches 1..4 in the paper, while c=4 through + * c=7 are copies of those with an additional negation of sqrt(w). + */ +static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_fe *x_in, const secp256k1_fe *u_in, int c) { + /* The implemented algorithm is this (all arithmetic, except involving c, is mod p): + * + * - If (c & 2) = 0: + * - If (-x-u) is a valid X coordinate, fail. + * - Let s=-(u^3+7)/(u^2+u*x+x^2). + * - If s is not square, fail. + * - Let v=x. + * - If (c & 2) = 2: + * - Let s=x-u. + * - If s is not square, fail. + * - Let r=sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. + * - If (c & 1) = 1 and r = 0, fail. + * - If s=0, fail. + * - Let v=(r/s-u)/2. + * - Let w=sqrt(s). + * - If (c & 5) = 0: return -w*(c3*u + v). + * - If (c & 5) = 1: return w*(c4*u + v). + * - If (c & 5) = 4: return w*(c3*u + v). + * - If (c & 5) = 5: return -w*(c4*u + v). + */ + secp256k1_fe x = *x_in, u = *u_in, g, v, s, m, r, q; + int ret; + + secp256k1_fe_normalize_weak(&x); + secp256k1_fe_normalize_weak(&u); + + VERIFY_CHECK(c >= 0 && c < 8); + VERIFY_CHECK(secp256k1_ge_x_on_curve_var(&x)); + + if (!(c & 2)) { + /* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or + * c=4) formula, or x2 (if c=1 or c=5) formula. */ + + /* If -u-x is a valid X coordinate, fail. This would yield an encoding that roundtrips + * back under the x3 formula instead (which has priority over x1 and x2, so the decoding + * would not match x). */ + m = x; /* m = x */ + secp256k1_fe_add(&m, &u); /* m = u+x */ + secp256k1_fe_negate(&m, &m, 2); /* m = -u-x */ + /* Test if (-u-x) is a valid X coordinate. If so, fail. */ + if (secp256k1_ge_x_on_curve_var(&m)) return 0; + + /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [first part] */ + secp256k1_fe_sqr(&s, &m); /* s = (u+x)^2 */ + secp256k1_fe_negate(&s, &s, 1); /* s = -(u+x)^2 */ + secp256k1_fe_mul(&m, &u, &x); /* m = u*x */ + secp256k1_fe_add(&s, &m); /* s = -(u^2 + u*x + x^2) */ + + /* Note that at this point, s = 0 is impossible. If it were the case: + * s = -(u^2 + u*x + x^2) = 0 + * => u^2 + u*x + x^2 = 0 + * => (u + 2*x) * (u^2 + u*x + x^2) = 0 + * => 2*x^3 + 3*x^2*u + 3*x*u^2 + u^3 = 0 + * => (x + u)^3 + x^3 = 0 + * => x^3 = -(x + u)^3 + * => x^3 + B = (-u - x)^3 + B + * + * However, we know x^3 + B is square (because x is on the curve) and + * that (-u-x)^3 + B is not square (the secp256k1_ge_x_on_curve_var(&m) + * test above would have failed). This is a contradiction, and thus the + * assumption s=0 is false. */ + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&s)); + + /* If s is not square, fail. We have not fully computed s yet, but s is square iff + * -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is + * nonzero). */ + secp256k1_fe_sqr(&g, &u); /* g = u^2 */ + secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */ + secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3+7 */ + secp256k1_fe_mul(&m, &s, &g); /* m = -(u^3 + 7)*(u^2 + u*x + x^2) */ + if (!secp256k1_fe_is_square_var(&m)) return 0; + + /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [second part] */ + secp256k1_fe_inv_var(&s, &s); /* s = -1/(u^2 + u*x + x^2) [no div by 0] */ + secp256k1_fe_mul(&s, &s, &g); /* s = -(u^3 + 7)/(u^2 + u*x + x^2) */ + + /* Let v = x. */ + v = x; + } else { + /* c is in {2, 3, 6, 7}. In this case we look for an inverse under the x3 formula. */ + + /* Let s = x-u. */ + secp256k1_fe_negate(&m, &u, 1); /* m = -u */ + s = m; /* s = -u */ + secp256k1_fe_add(&s, &x); /* s = x-u */ + + /* If s is not square, fail. */ + if (!secp256k1_fe_is_square_var(&s)) return 0; + + /* Let r = sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. */ + secp256k1_fe_sqr(&g, &u); /* g = u^2 */ + secp256k1_fe_mul(&q, &s, &g); /* q = s*u^2 */ + secp256k1_fe_mul_int(&q, 3); /* q = 3*s*u^2 */ + secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */ + secp256k1_fe_mul_int(&g, 4); /* g = 4*u^3 */ + secp256k1_fe_add_int(&g, 4 * SECP256K1_B); /* g = 4*(u^3+7) */ + secp256k1_fe_add(&q, &g); /* q = 4*(u^3+7)+3*s*u^2 */ + secp256k1_fe_mul(&q, &q, &s); /* q = s*(4*(u^3+7)+3*u^2*s) */ + secp256k1_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */ + if (!secp256k1_fe_is_square_var(&q)) return 0; + ret = secp256k1_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */ +#ifdef VERIFY + VERIFY_CHECK(ret); +#else + (void)ret; +#endif + + /* If (c & 1) = 1 and r = 0, fail. */ + if (EXPECT((c & 1) && secp256k1_fe_normalizes_to_zero_var(&r), 0)) return 0; + + /* If s = 0, fail. */ + if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&s), 0)) return 0; + + /* Let v = (r/s-u)/2. */ + secp256k1_fe_inv_var(&v, &s); /* v = 1/s [no div by 0] */ + secp256k1_fe_mul(&v, &v, &r); /* v = r/s */ + secp256k1_fe_add(&v, &m); /* v = r/s-u */ + secp256k1_fe_half(&v); /* v = (r/s-u)/2 */ + } + + /* Let w = sqrt(s). */ + ret = secp256k1_fe_sqrt(&m, &s); /* m = sqrt(s) = w */ + VERIFY_CHECK(ret); + + /* Return logic. */ + if ((c & 5) == 0 || (c & 5) == 5) { + secp256k1_fe_negate(&m, &m, 1); /* m = -w */ + } + /* Now m = {-w if c&5=0 or c&5=5; w otherwise}. */ + secp256k1_fe_mul(&u, &u, c&1 ? &secp256k1_ellswift_c4 : &secp256k1_ellswift_c3); + /* u = {c4 if c&1=1; c3 otherwise}*u */ + secp256k1_fe_add(&u, &v); /* u = {c4 if c&1=1; c3 otherwise}*u + v */ + secp256k1_fe_mul(t, &m, &u); + return 1; +} + +/** Use SHA256 as a PRNG, returning SHA256(hasher || cnt). + * + * hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness. + * Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a + * 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */ +static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) { + secp256k1_sha256 hash = *hasher; + unsigned char buf4[4]; +#ifdef VERIFY + size_t blocks = hash.bytes >> 6; +#endif + buf4[0] = cnt; + buf4[1] = cnt >> 8; + buf4[2] = cnt >> 16; + buf4[3] = cnt >> 24; + secp256k1_sha256_write(&hash, buf4, 4); + secp256k1_sha256_finalize(&hash, out32); + + /* Writing and finalizing together should trigger exactly one SHA256 compression. */ + VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1)); +} + +/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate. + * + * u32 is the 32-byte big endian encoding of u; t is the output field element t that still + * needs encoding. + * + * hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */ +static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) { + /* Pool of 3-bit branch values. */ + unsigned char branch_hash[32]; + /* Number of 3-bit values in branch_hash left. */ + int branches_left = 0; + /* Field elements u and branch values are extracted from RNG based on hasher for consecutive + * values of cnt. cnt==0 is first used to populate a pool of 64 4-bit branch values. The 64 + * cnt values that follow are used to generate field elements u. cnt==65 (and multiples + * thereof) are used to repopulate the pool and start over, if that were ever necessary. + * On average, 4 iterations are needed. */ + uint32_t cnt = 0; + while (1) { + int branch; + secp256k1_fe u; + /* If the pool of branch values is empty, populate it. */ + if (branches_left == 0) { + secp256k1_ellswift_prng(branch_hash, hasher, cnt++); + branches_left = 64; + } + /* Take a 3-bit branch value from the branch pool (top bit is discarded). */ + --branches_left; + branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7; + /* Compute a new u value by hashing. */ + secp256k1_ellswift_prng(u32, hasher, cnt++); + /* overflow is not a problem (we prefer uniform u32 over uniform u). */ + secp256k1_fe_set_b32_mod(&u, u32); + /* Since u is the output of a hash, it should practically never be 0. We could apply the + * u=0 to u=1 correction here too to deal with that case still, but it's such a low + * probability event that we do not bother. */ + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u)); + + /* Find a remainder t, and return it if found. */ + if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break; + } +} + +/** Find an ElligatorSwift encoding (u, t) for point P. + * + * This is similar secp256k1_ellswift_xelligatorswift_var, except it takes a full group element p + * as input, and returns an encoding that matches the provided Y coordinate rather than a random + * one. + */ +static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) { + secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher); + secp256k1_fe_normalize_var(t); + if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) { + secp256k1_fe_negate(t, t, 1); + secp256k1_fe_normalize_var(t); + } +} + +/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */ +static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) { + secp256k1_sha256_initialize(hash); + hash->s[0] = 0xd1a6524bul; + hash->s[1] = 0x028594b3ul; + hash->s[2] = 0x96e42f4eul; + hash->s[3] = 0x1037a177ul; + hash->s[4] = 0x1b8fcb8bul; + hash->s[5] = 0x56023885ul; + hash->s[6] = 0x2560ede1ul; + hash->s[7] = 0xd626b715ul; + + hash->bytes = 64; +} + +int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) { + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(ell64 != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(rnd32 != NULL); + + if (secp256k1_pubkey_load(ctx, &p, pubkey)) { + secp256k1_fe t; + unsigned char p64[64] = {0}; + size_t ser_size; + int ser_ret; + secp256k1_sha256 hash; + + /* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using + * BIP340 tagged hash with tag "secp256k1_ellswift_encode". */ + secp256k1_ellswift_sha256_init_encode(&hash); + ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1); +#ifdef VERIFY + VERIFY_CHECK(ser_ret && ser_size == 33); +#else + (void)ser_ret; +#endif + secp256k1_sha256_write(&hash, p64, sizeof(p64)); + secp256k1_sha256_write(&hash, rnd32, 32); + + /* Compute ElligatorSwift encoding and construct output. */ + secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ + secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ + return 1; + } + /* Only reached in case the provided pubkey is invalid. */ + memset(ell64, 0, 64); + return 0; +} + +/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_create". */ +static void secp256k1_ellswift_sha256_init_create(secp256k1_sha256* hash) { + secp256k1_sha256_initialize(hash); + hash->s[0] = 0xd29e1bf5ul; + hash->s[1] = 0xf7025f42ul; + hash->s[2] = 0x9b024773ul; + hash->s[3] = 0x094cb7d5ul; + hash->s[4] = 0xe59ed789ul; + hash->s[5] = 0x03bc9786ul; + hash->s[6] = 0x68335b35ul; + hash->s[7] = 0x4e363b53ul; + + hash->bytes = 64; +} + +int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) { + secp256k1_ge p; + secp256k1_fe t; + secp256k1_sha256 hash; + secp256k1_scalar seckey_scalar; + int ret; + static const unsigned char zero32[32] = {0}; + + /* Sanity check inputs. */ + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(ell64 != NULL); + memset(ell64, 0, 64); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey32 != NULL); + + /* Compute (affine) public key */ + ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey32); + secp256k1_declassify(ctx, &p, sizeof(p)); /* not constant time in produced pubkey */ + secp256k1_fe_normalize_var(&p.x); + secp256k1_fe_normalize_var(&p.y); + + /* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++), + * using BIP340 tagged hash with tag "secp256k1_ellswift_create". */ + secp256k1_ellswift_sha256_init_create(&hash); + secp256k1_sha256_write(&hash, seckey32, 32); + secp256k1_sha256_write(&hash, zero32, sizeof(zero32)); + secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */ + if (auxrnd32) secp256k1_sha256_write(&hash, auxrnd32, 32); + + /* Compute ElligatorSwift encoding and construct output. */ + secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ + secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ + + secp256k1_memczero(ell64, 64, !ret); + secp256k1_scalar_clear(&seckey_scalar); + + return ret; +} + +int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *ell64) { + secp256k1_fe u, t; + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(ell64 != NULL); + + secp256k1_fe_set_b32_mod(&u, ell64); + secp256k1_fe_set_b32_mod(&t, ell64 + 32); + secp256k1_fe_normalize_var(&t); + secp256k1_ellswift_swiftec_var(&p, &u, &t); + secp256k1_pubkey_save(pubkey, &p); + return 1; +} + +static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + secp256k1_sha256 sha; + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, data, 64); + secp256k1_sha256_write(&sha, ell_a64, 64); + secp256k1_sha256_write(&sha, ell_b64, 64); + secp256k1_sha256_write(&sha, x32, 32); + secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_clear(&sha); + + return 1; +} + +/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */ +static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) { + secp256k1_sha256_initialize(hash); + hash->s[0] = 0x8c12d730ul; + hash->s[1] = 0x827bd392ul; + hash->s[2] = 0x9e4fb2eeul; + hash->s[3] = 0x207b373eul; + hash->s[4] = 0x2292bd7aul; + hash->s[5] = 0xaa5441bcul; + hash->s[6] = 0x15c3779ful; + hash->s[7] = 0xcfb52549ul; + + hash->bytes = 64; +} + +static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + secp256k1_sha256 sha; + + (void)data; + + secp256k1_ellswift_sha256_init_bip324(&sha); + secp256k1_sha256_write(&sha, ell_a64, 64); + secp256k1_sha256_write(&sha, ell_b64, 64); + secp256k1_sha256_write(&sha, x32, 32); + secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_clear(&sha); + + return 1; +} + +const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix; +const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324; + +int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, const unsigned char *ell_a64, const unsigned char *ell_b64, const unsigned char *seckey32, int party, secp256k1_ellswift_xdh_hash_function hashfp, void *data) { + int ret = 0; + int overflow; + secp256k1_scalar s; + secp256k1_fe xn, xd, px, u, t; + unsigned char sx[32]; + const unsigned char* theirs64; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(ell_a64 != NULL); + ARG_CHECK(ell_b64 != NULL); + ARG_CHECK(seckey32 != NULL); + ARG_CHECK(hashfp != NULL); + + /* Load remote public key (as fraction). */ + theirs64 = party ? ell_a64 : ell_b64; + secp256k1_fe_set_b32_mod(&u, theirs64); + secp256k1_fe_set_b32_mod(&t, theirs64 + 32); + secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, &u, &t); + + /* Load private key (using one if invalid). */ + secp256k1_scalar_set_b32(&s, seckey32, &overflow); + overflow = secp256k1_scalar_is_zero(&s); + secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow); + + /* Compute shared X coordinate. */ + secp256k1_ecmult_const_xonly(&px, &xn, &xd, &s, 1); + secp256k1_fe_normalize(&px); + secp256k1_fe_get_b32(sx, &px); + + /* Invoke hasher */ + ret = hashfp(output, sx, ell_a64, ell_b64, data); + + secp256k1_memclear(sx, sizeof(sx)); + secp256k1_fe_clear(&px); + secp256k1_scalar_clear(&s); + + return !!ret & !overflow; +} + +#endif diff --git a/external/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h b/external/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h new file mode 100644 index 00000000000..839c24aee45 --- /dev/null +++ b/external/secp256k1/src/modules/ellswift/tests_exhaustive_impl.h @@ -0,0 +1,39 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_ellswift.h" +#include "main_impl.h" + +static void test_exhaustive_ellswift(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i; + + /* Note that SwiftEC/ElligatorSwift are inherently curve operations, not + * group operations, and this test only checks the curve points which are in + * a tiny subgroup. In that sense it can't be really seen as exhaustive as + * it doesn't (and for computational reasons obviously cannot) test the + * entire domain ellswift operates under. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_scalar scalar_i; + unsigned char sec32[32]; + unsigned char ell64[64]; + secp256k1_pubkey pub_decoded; + secp256k1_ge ge_decoded; + + /* Construct ellswift pubkey from exhaustive loop scalar i. */ + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_scalar_get_b32(sec32, &scalar_i); + CHECK(secp256k1_ellswift_create(ctx, ell64, sec32, NULL)); + + /* Decode ellswift pubkey and check that it matches the precomputed group element. */ + secp256k1_ellswift_decode(ctx, &pub_decoded, ell64); + secp256k1_pubkey_load(ctx, &ge_decoded, &pub_decoded); + CHECK(secp256k1_ge_eq_var(&ge_decoded, &group[i])); + } +} + +#endif diff --git a/external/secp256k1/src/modules/ellswift/tests_impl.h b/external/secp256k1/src/modules/ellswift/tests_impl.h new file mode 100644 index 00000000000..3c314c9b502 --- /dev/null +++ b/external/secp256k1/src/modules/ellswift/tests_impl.h @@ -0,0 +1,436 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_H +#define SECP256K1_MODULE_ELLSWIFT_TESTS_H + +#include "../../../include/secp256k1_ellswift.h" + +struct ellswift_xswiftec_inv_test { + int enc_bitmap; + secp256k1_fe u; + secp256k1_fe x; + secp256k1_fe encs[8]; +}; + +struct ellswift_decode_test { + unsigned char enc[64]; + secp256k1_fe x; + int odd_y; +}; + +struct ellswift_xdh_test { + unsigned char priv_ours[32]; + unsigned char ellswift_ours[64]; + unsigned char ellswift_theirs[64]; + int initiating; + unsigned char shared_secret[32]; +}; + +/* Set of (point, encodings) test vectors, selected to maximize branch coverage, part of the BIP324 + * test vectors. Created using an independent implementation, and tested decoding against paper + * authors' code. */ +static const struct ellswift_xswiftec_inv_test ellswift_xswiftec_inv_tests[] = { + {0xcc, SECP256K1_FE_CONST(0x05ff6bda, 0xd900fc32, 0x61bc7fe3, 0x4e2fb0f5, 0x69f06e09, 0x1ae437d3, 0xa52e9da0, 0xcbfb9590), SECP256K1_FE_CONST(0x80cdf637, 0x74ec7022, 0xc89a5a85, 0x58e373a2, 0x79170285, 0xe0ab2741, 0x2dbce510, 0xbdfe23fc), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x45654798, 0xece071ba, 0x79286d04, 0xf7f3eb1c, 0x3f1d17dd, 0x883610f2, 0xad2efd82, 0xa287466b), SECP256K1_FE_CONST(0x0aeaa886, 0xf6b76c71, 0x58452418, 0xcbf5033a, 0xdc5747e9, 0xe9b5d3b2, 0x303db969, 0x36528557), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xba9ab867, 0x131f8e45, 0x86d792fb, 0x080c14e3, 0xc0e2e822, 0x77c9ef0d, 0x52d1027c, 0x5d78b5c4), SECP256K1_FE_CONST(0xf5155779, 0x0948938e, 0xa7badbe7, 0x340afcc5, 0x23a8b816, 0x164a2c4d, 0xcfc24695, 0xc9ad76d8)}}, + {0x33, SECP256K1_FE_CONST(0x1737a85f, 0x4c8d146c, 0xec96e3ff, 0xdca76d99, 0x03dcf3bd, 0x53061868, 0xd478c78c, 0x63c2aa9e), SECP256K1_FE_CONST(0x39e48dd1, 0x50d2f429, 0xbe088dfd, 0x5b61882e, 0x7e840748, 0x3702ae9a, 0x5ab35927, 0xb15f85ea), {SECP256K1_FE_CONST(0x1be8cc0b, 0x04be0c68, 0x1d0c6a68, 0xf733f82c, 0x6c896e0c, 0x8a262fcd, 0x392918e3, 0x03a7abf4), SECP256K1_FE_CONST(0x605b5814, 0xbf9b8cb0, 0x66667c9e, 0x5480d22d, 0xc5b6c92f, 0x14b4af3e, 0xe0a9eb83, 0xb03685e3), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe41733f4, 0xfb41f397, 0xe2f39597, 0x08cc07d3, 0x937691f3, 0x75d9d032, 0xc6d6e71b, 0xfc58503b), SECP256K1_FE_CONST(0x9fa4a7eb, 0x4064734f, 0x99998361, 0xab7f2dd2, 0x3a4936d0, 0xeb4b50c1, 0x1f56147b, 0x4fc9764c), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0x1aaa1cce, 0xbf9c7241, 0x91033df3, 0x66b36f69, 0x1c4d902c, 0x228033ff, 0x4516d122, 0xb2564f68), SECP256K1_FE_CONST(0xc7554125, 0x9d3ba98f, 0x207eaa30, 0xc69634d1, 0x87d0b6da, 0x594e719e, 0x420f4898, 0x638fc5b0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x2323a1d0, 0x79b0fd72, 0xfc8bb62e, 0xc34230a8, 0x15cb0596, 0xc2bfac99, 0x8bd6b842, 0x60f5dc26), SECP256K1_FE_CONST(0x239342df, 0xb675500a, 0x34a19631, 0x0b8d87d5, 0x4f49dcac, 0x9da50c17, 0x43ceab41, 0xa7b249ff), {SECP256K1_FE_CONST(0xf63580b8, 0xaa49c484, 0x6de56e39, 0xe1b3e73f, 0x171e881e, 0xba8c66f6, 0x14e67e5c, 0x975dfc07), SECP256K1_FE_CONST(0xb6307b33, 0x2e699f1c, 0xf77841d9, 0x0af25365, 0x404deb7f, 0xed5edb30, 0x90db49e6, 0x42a156b6), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x09ca7f47, 0x55b63b7b, 0x921a91c6, 0x1e4c18c0, 0xe8e177e1, 0x45739909, 0xeb1981a2, 0x68a20028), SECP256K1_FE_CONST(0x49cf84cc, 0xd19660e3, 0x0887be26, 0xf50dac9a, 0xbfb21480, 0x12a124cf, 0x6f24b618, 0xbd5ea579), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x2dc90e64, 0x0cb646ae, 0x9164c0b5, 0xa9ef0169, 0xfebe34dc, 0x4437d6e4, 0x6acb0e27, 0xe219d1e8), SECP256K1_FE_CONST(0xd236f19b, 0xf349b951, 0x6e9b3f4a, 0x5610fe96, 0x0141cb23, 0xbbc8291b, 0x9534f1d7, 0x1de62a47), {SECP256K1_FE_CONST(0xe69df7d9, 0xc026c366, 0x00ebdf58, 0x80726758, 0x47c0c431, 0xc8eb7306, 0x82533e96, 0x4b6252c9), SECP256K1_FE_CONST(0x4f18bbdf, 0x7c2d6c5f, 0x818c1880, 0x2fa35cd0, 0x69eaa79f, 0xff74e4fc, 0x837c80d9, 0x3fece2f8), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x19620826, 0x3fd93c99, 0xff1420a7, 0x7f8d98a7, 0xb83f3bce, 0x37148cf9, 0x7dacc168, 0xb49da966), SECP256K1_FE_CONST(0xb0e74420, 0x83d293a0, 0x7e73e77f, 0xd05ca32f, 0x96155860, 0x008b1b03, 0x7c837f25, 0xc0131937), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0x3edd7b39, 0x80e2f2f3, 0x4d1409a2, 0x07069f88, 0x1fda5f96, 0xf08027ac, 0x4465b63d, 0xc278d672), SECP256K1_FE_CONST(0x053a98de, 0x4a27b196, 0x1155822b, 0x3a3121f0, 0x3b2a1445, 0x8bd80eb4, 0xa560c4c7, 0xa85c149c), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb3dae4b7, 0xdcf858e4, 0xc6968057, 0xcef2b156, 0x46543152, 0x6538199c, 0xf52dc1b2, 0xd62fda30), SECP256K1_FE_CONST(0x4aa77dd5, 0x5d6b6d3c, 0xfa10cc9d, 0x0fe42f79, 0x232e4575, 0x661049ae, 0x36779c1d, 0x0c666d88), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x4c251b48, 0x2307a71b, 0x39697fa8, 0x310d4ea9, 0xb9abcead, 0x9ac7e663, 0x0ad23e4c, 0x29d021ff), SECP256K1_FE_CONST(0xb558822a, 0xa29492c3, 0x05ef3362, 0xf01bd086, 0xdcd1ba8a, 0x99efb651, 0xc98863e1, 0xf3998ea7)}}, + {0x00, SECP256K1_FE_CONST(0x4295737e, 0xfcb1da6f, 0xb1d96b9c, 0xa7dcd1e3, 0x20024b37, 0xa736c494, 0x8b625981, 0x73069f70), SECP256K1_FE_CONST(0xfa7ffe4f, 0x25f88362, 0x831c087a, 0xfe2e8a9b, 0x0713e2ca, 0xc1ddca6a, 0x383205a2, 0x66f14307), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xff, SECP256K1_FE_CONST(0x587c1a0c, 0xee91939e, 0x7f784d23, 0xb963004a, 0x3bf44f5d, 0x4e32a008, 0x1995ba20, 0xb0fca59e), SECP256K1_FE_CONST(0x2ea98853, 0x0715e8d1, 0x0363907f, 0xf2512452, 0x4d471ba2, 0x454d5ce3, 0xbe3f0419, 0x4dfd3a3c), {SECP256K1_FE_CONST(0xcfd5a094, 0xaa0b9b88, 0x91b76c6a, 0xb9438f66, 0xaa1c095a, 0x65f9f701, 0x35e81712, 0x92245e74), SECP256K1_FE_CONST(0xa89057d7, 0xc6563f0d, 0x6efa19ae, 0x84412b8a, 0x7b47e791, 0xa191ecdf, 0xdf2af84f, 0xd97bc339), SECP256K1_FE_CONST(0x475d0ae9, 0xef46920d, 0xf07b3411, 0x7be5a081, 0x7de1023e, 0x3cc32689, 0xe9be145b, 0x406b0aef), SECP256K1_FE_CONST(0xa0759178, 0xad802324, 0x54f827ef, 0x05ea3e72, 0xad8d7541, 0x8e6d4cc1, 0xcd4f5306, 0xc5e7c453), SECP256K1_FE_CONST(0x302a5f6b, 0x55f46477, 0x6e489395, 0x46bc7099, 0x55e3f6a5, 0x9a0608fe, 0xca17e8ec, 0x6ddb9dbb), SECP256K1_FE_CONST(0x576fa828, 0x39a9c0f2, 0x9105e651, 0x7bbed475, 0x84b8186e, 0x5e6e1320, 0x20d507af, 0x268438f6), SECP256K1_FE_CONST(0xb8a2f516, 0x10b96df2, 0x0f84cbee, 0x841a5f7e, 0x821efdc1, 0xc33cd976, 0x1641eba3, 0xbf94f140), SECP256K1_FE_CONST(0x5f8a6e87, 0x527fdcdb, 0xab07d810, 0xfa15c18d, 0x52728abe, 0x7192b33e, 0x32b0acf8, 0x3a1837dc)}}, + {0xcc, SECP256K1_FE_CONST(0x5fa88b33, 0x65a635cb, 0xbcee003c, 0xce9ef51d, 0xd1a310de, 0x277e441a, 0xbccdb7be, 0x1e4ba249), SECP256K1_FE_CONST(0x79461ff6, 0x2bfcbcac, 0x4249ba84, 0xdd040f2c, 0xec3c63f7, 0x25204dc7, 0xf464c16b, 0xf0ff3170), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x6bb700e1, 0xf4d7e236, 0xe8d193ff, 0x4a76c1b3, 0xbcd4e2b2, 0x5acac3d5, 0x1c8dac65, 0x3fe909a0), SECP256K1_FE_CONST(0xf4c73410, 0x633da7f6, 0x3a4f1d55, 0xaec6dd32, 0xc4c6d89e, 0xe74075ed, 0xb5515ed9, 0x0da9e683), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x9448ff1e, 0x0b281dc9, 0x172e6c00, 0xb5893e4c, 0x432b1d4d, 0xa5353c2a, 0xe3725399, 0xc016f28f), SECP256K1_FE_CONST(0x0b38cbef, 0x9cc25809, 0xc5b0e2aa, 0x513922cd, 0x3b392761, 0x18bf8a12, 0x4aaea125, 0xf25615ac)}}, + {0xcc, SECP256K1_FE_CONST(0x6fb31c75, 0x31f03130, 0xb42b155b, 0x952779ef, 0xbb46087d, 0xd9807d24, 0x1a48eac6, 0x3c3d96d6), SECP256K1_FE_CONST(0x56f81be7, 0x53e8d4ae, 0x4940ea6f, 0x46f6ec9f, 0xda66a6f9, 0x6cc95f50, 0x6cb2b574, 0x90e94260), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x59059774, 0x795bdb7a, 0x837fbe11, 0x40a5fa59, 0x984f48af, 0x8df95d57, 0xdd6d1c05, 0x437dcec1), SECP256K1_FE_CONST(0x22a644db, 0x79376ad4, 0xe7b3a009, 0xe58b3f13, 0x137c54fd, 0xf911122c, 0xc93667c4, 0x7077d784), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xa6fa688b, 0x86a42485, 0x7c8041ee, 0xbf5a05a6, 0x67b0b750, 0x7206a2a8, 0x2292e3f9, 0xbc822d6e), SECP256K1_FE_CONST(0xdd59bb24, 0x86c8952b, 0x184c5ff6, 0x1a74c0ec, 0xec83ab02, 0x06eeedd3, 0x36c9983a, 0x8f8824ab)}}, + {0x00, SECP256K1_FE_CONST(0x704cd226, 0xe71cb682, 0x6a590e80, 0xdac90f2d, 0x2f5830f0, 0xfdf135a3, 0xeae3965b, 0xff25ff12), SECP256K1_FE_CONST(0x138e0afa, 0x68936ee6, 0x70bd2b8d, 0xb53aedbb, 0x7bea2a85, 0x97388b24, 0xd0518edd, 0x22ad66ec), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x725e9147, 0x92cb8c89, 0x49e7e116, 0x8b7cdd8a, 0x8094c91c, 0x6ec2202c, 0xcd53a6a1, 0x8771edeb), SECP256K1_FE_CONST(0x8da16eb8, 0x6d347376, 0xb6181ee9, 0x74832275, 0x7f6b36e3, 0x913ddfd3, 0x32ac595d, 0x788e0e44), {SECP256K1_FE_CONST(0xdd357786, 0xb9f68733, 0x30391aa5, 0x62580965, 0x4e43116e, 0x82a5a5d8, 0x2ffd1d66, 0x24101fc4), SECP256K1_FE_CONST(0xa0b7efca, 0x01814594, 0xc59c9aae, 0x8e497001, 0x86ca5d95, 0xe88bcc80, 0x399044d9, 0xc2d8613d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x22ca8879, 0x460978cc, 0xcfc6e55a, 0x9da7f69a, 0xb1bcee91, 0x7d5a5a27, 0xd002e298, 0xdbefdc6b), SECP256K1_FE_CONST(0x5f481035, 0xfe7eba6b, 0x3a636551, 0x71b68ffe, 0x7935a26a, 0x1774337f, 0xc66fbb25, 0x3d279af2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0x78fe6b71, 0x7f2ea4a3, 0x2708d79c, 0x151bf503, 0xa5312a18, 0xc0963437, 0xe865cc6e, 0xd3f6ae97), SECP256K1_FE_CONST(0x8701948e, 0x80d15b5c, 0xd8f72863, 0xeae40afc, 0x5aced5e7, 0x3f69cbc8, 0x179a3390, 0x2c094d98), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x44, SECP256K1_FE_CONST(0x7c37bb9c, 0x5061dc07, 0x413f11ac, 0xd5a34006, 0xe64c5c45, 0x7fdb9a43, 0x8f217255, 0xa961f50d), SECP256K1_FE_CONST(0x5c1a76b4, 0x4568eb59, 0xd6789a74, 0x42d9ed7c, 0xdc6226b7, 0x752b4ff8, 0xeaf8e1a9, 0x5736e507), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb94d30cd, 0x7dbff60b, 0x64620c17, 0xca0fafaa, 0x40b3d1f5, 0x2d077a60, 0xa2e0cafd, 0x145086c2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x46b2cf32, 0x824009f4, 0x9b9df3e8, 0x35f05055, 0xbf4c2e0a, 0xd2f8859f, 0x5d1f3501, 0xebaf756d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0x82388888, 0x967f82a6, 0xb444438a, 0x7d44838e, 0x13c0d478, 0xb9ca060d, 0xa95a41fb, 0x94303de6), SECP256K1_FE_CONST(0x29e96541, 0x70628fec, 0x8b497289, 0x8b113cf9, 0x8807f460, 0x9274f4f3, 0x140d0674, 0x157c90a0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x91298f57, 0x70af7a27, 0xf0a47188, 0xd24c3b7b, 0xf98ab299, 0x0d84b0b8, 0x98507e3c, 0x561d6472), SECP256K1_FE_CONST(0x144f4ccb, 0xd9a74698, 0xa88cbf6f, 0xd00ad886, 0xd339d29e, 0xa19448f2, 0xc572cac0, 0xa07d5562), {SECP256K1_FE_CONST(0xe6a0ffa3, 0x807f09da, 0xdbe71e0f, 0x4be4725f, 0x2832e76c, 0xad8dc1d9, 0x43ce8393, 0x75eff248), SECP256K1_FE_CONST(0x837b8e68, 0xd4917544, 0x764ad090, 0x3cb11f86, 0x15d2823c, 0xefbb06d8, 0x9049dbab, 0xc69befda), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x195f005c, 0x7f80f625, 0x2418e1f0, 0xb41b8da0, 0xd7cd1893, 0x52723e26, 0xbc317c6b, 0x8a1009e7), SECP256K1_FE_CONST(0x7c847197, 0x2b6e8abb, 0x89b52f6f, 0xc34ee079, 0xea2d7dc3, 0x1044f927, 0x6fb62453, 0x39640c55), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0xb682f3d0, 0x3bbb5dee, 0x4f54b5eb, 0xfba931b4, 0xf52f6a19, 0x1e5c2f48, 0x3c73c66e, 0x9ace97e1), SECP256K1_FE_CONST(0x904717bf, 0x0bc0cb78, 0x73fcdc38, 0xaa97f19e, 0x3a626309, 0x72acff92, 0xb24cc6dd, 0xa197cb96), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x77, SECP256K1_FE_CONST(0xc17ec69e, 0x665f0fb0, 0xdbab48d9, 0xc2f94d12, 0xec8a9d7e, 0xacb58084, 0x83309180, 0x1eb0b80b), SECP256K1_FE_CONST(0x147756e6, 0x6d96e31c, 0x426d3cc8, 0x5ed0c4cf, 0xbef6341d, 0xd8b28558, 0x5aa574ea, 0x0204b55e), {SECP256K1_FE_CONST(0x6f4aea43, 0x1a0043bd, 0xd03134d6, 0xd9159119, 0xce034b88, 0xc32e50e8, 0xe36c4ee4, 0x5eac7ae9), SECP256K1_FE_CONST(0xfd5be16d, 0x4ffa2690, 0x126c67c3, 0xef7cb9d2, 0x9b74d397, 0xc78b06b3, 0x605fda34, 0xdc9696a6), SECP256K1_FE_CONST(0x5e9c6079, 0x2a2f000e, 0x45c6250f, 0x296f875e, 0x174efc0e, 0x9703e628, 0x706103a9, 0xdd2d82c7), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x90b515bc, 0xe5ffbc42, 0x2fcecb29, 0x26ea6ee6, 0x31fcb477, 0x3cd1af17, 0x1c93b11a, 0xa1538146), SECP256K1_FE_CONST(0x02a41e92, 0xb005d96f, 0xed93983c, 0x1083462d, 0x648b2c68, 0x3874f94c, 0x9fa025ca, 0x23696589), SECP256K1_FE_CONST(0xa1639f86, 0xd5d0fff1, 0xba39daf0, 0xd69078a1, 0xe8b103f1, 0x68fc19d7, 0x8f9efc55, 0x22d27968), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0xc25172fc, 0x3f29b6fc, 0x4a1155b8, 0x57523315, 0x5486b274, 0x64b74b8b, 0x260b499a, 0x3f53cb14), SECP256K1_FE_CONST(0x1ea9cbdb, 0x35cf6e03, 0x29aa31b0, 0xbb0a702a, 0x65123ed0, 0x08655a93, 0xb7dcd528, 0x0e52e1ab), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x7422edc7, 0x843136af, 0x0053bb88, 0x54448a82, 0x99994f9d, 0xdcefd3a9, 0xa92d4546, 0x2c59298a), SECP256K1_FE_CONST(0x78c7774a, 0x266f8b97, 0xea23d05d, 0x064f033c, 0x77319f92, 0x3f6b78bc, 0xe4e20bf0, 0x5fa5398d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x8bdd1238, 0x7bcec950, 0xffac4477, 0xabbb757d, 0x6666b062, 0x23102c56, 0x56d2bab8, 0xd3a6d2a5), SECP256K1_FE_CONST(0x873888b5, 0xd9907468, 0x15dc2fa2, 0xf9b0fcc3, 0x88ce606d, 0xc0948743, 0x1b1df40e, 0xa05ac2a2)}}, + {0x00, SECP256K1_FE_CONST(0xcab6626f, 0x832a4b12, 0x80ba7add, 0x2fc5322f, 0xf011caed, 0xedf7ff4d, 0xb6735d50, 0x26dc0367), SECP256K1_FE_CONST(0x2b2bef08, 0x52c6f7c9, 0x5d72ac99, 0xa23802b8, 0x75029cd5, 0x73b248d1, 0xf1b3fc80, 0x33788eb6), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0xd8621b4f, 0xfc85b9ed, 0x56e99d8d, 0xd1dd24ae, 0xdcecb147, 0x63b861a1, 0x7112dc77, 0x1a104fd2), SECP256K1_FE_CONST(0x812cabe9, 0x72a22aa6, 0x7c7da0c9, 0x4d8a9362, 0x96eb9949, 0xd70c37cb, 0x2b248757, 0x4cb3ce58), {SECP256K1_FE_CONST(0xfbc5febc, 0x6fdbc9ae, 0x3eb88a93, 0xb982196e, 0x8b6275a6, 0xd5a73c17, 0x387e000c, 0x711bd0e3), SECP256K1_FE_CONST(0x8724c96b, 0xd4e5527f, 0x2dd195a5, 0x1c468d2d, 0x211ba2fa, 0xc7cbe0b4, 0xb3434253, 0x409fb42d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x043a0143, 0x90243651, 0xc147756c, 0x467de691, 0x749d8a59, 0x2a58c3e8, 0xc781fff2, 0x8ee42b4c), SECP256K1_FE_CONST(0x78db3694, 0x2b1aad80, 0xd22e6a5a, 0xe3b972d2, 0xdee45d05, 0x38341f4b, 0x4cbcbdab, 0xbf604802), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0xda463164, 0xc6f4bf71, 0x29ee5f0e, 0xc00f65a6, 0x75a8adf1, 0xbd931b39, 0xb64806af, 0xdcda9a22), SECP256K1_FE_CONST(0x25b9ce9b, 0x390b408e, 0xd611a0f1, 0x3ff09a59, 0x8a57520e, 0x426ce4c6, 0x49b7f94f, 0x2325620d), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0xdafc971e, 0x4a3a7b6d, 0xcfb42a08, 0xd9692d82, 0xad9e7838, 0x523fcbda, 0x1d4827e1, 0x4481ae2d), SECP256K1_FE_CONST(0x250368e1, 0xb5c58492, 0x304bd5f7, 0x2696d27d, 0x526187c7, 0xadc03425, 0xe2b7d81d, 0xbb7e4e02), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x370c28f1, 0xbe665efa, 0xcde6aa43, 0x6bf86fe2, 0x1e6e314c, 0x1e53dd04, 0x0e6c73a4, 0x6b4c8c49), SECP256K1_FE_CONST(0xcd8acee9, 0x8ffe5653, 0x1a84d7eb, 0x3e48fa40, 0x34206ce8, 0x25ace907, 0xd0edf0ea, 0xeb5e9ca2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xc8f3d70e, 0x4199a105, 0x321955bc, 0x9407901d, 0xe191ceb3, 0xe1ac22fb, 0xf1938c5a, 0x94b36fe6), SECP256K1_FE_CONST(0x32753116, 0x7001a9ac, 0xe57b2814, 0xc1b705bf, 0xcbdf9317, 0xda5316f8, 0x2f120f14, 0x14a15f8d)}}, + {0x44, SECP256K1_FE_CONST(0xe0294c8b, 0xc1a36b41, 0x66ee92bf, 0xa70a5c34, 0x976fa982, 0x9405efea, 0x8f9cd54d, 0xcb29b99e), SECP256K1_FE_CONST(0xae9690d1, 0x3b8d20a0, 0xfbbf37be, 0xd8474f67, 0xa04e142f, 0x56efd787, 0x70a76b35, 0x9165d8a1), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xdcd45d93, 0x5613916a, 0xf167b029, 0x058ba3a7, 0x00d37150, 0xb9df3472, 0x8cb05412, 0xc16d4182), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x232ba26c, 0xa9ec6e95, 0x0e984fd6, 0xfa745c58, 0xff2c8eaf, 0x4620cb8d, 0x734fabec, 0x3e92baad), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0xe148441c, 0xd7b92b8b, 0x0e4fa3bd, 0x68712cfd, 0x0d709ad1, 0x98cace61, 0x1493c10e, 0x97f5394e), SECP256K1_FE_CONST(0x164a6397, 0x94d74c53, 0xafc4d329, 0x4e79cdb3, 0xcd25f99f, 0x6df45c00, 0x0f758aba, 0x54d699c0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xff, SECP256K1_FE_CONST(0xe4b00ec9, 0x7aadcca9, 0x7644d3b0, 0xc8a931b1, 0x4ce7bcf7, 0xbc877954, 0x6d6e35aa, 0x5937381c), SECP256K1_FE_CONST(0x94e9588d, 0x41647b3f, 0xcc772dc8, 0xd83c67ce, 0x3be00353, 0x8517c834, 0x103d2cd4, 0x9d62ef4d), {SECP256K1_FE_CONST(0xc88d25f4, 0x1407376b, 0xb2c03a7f, 0xffeb3ec7, 0x811cc434, 0x91a0c3aa, 0xc0378cdc, 0x78357bee), SECP256K1_FE_CONST(0x51c02636, 0xce00c234, 0x5ecd89ad, 0xb6089fe4, 0xd5e18ac9, 0x24e3145e, 0x6669501c, 0xd37a00d4), SECP256K1_FE_CONST(0x205b3512, 0xdb40521c, 0xb200952e, 0x67b46f67, 0xe09e7839, 0xe0de4400, 0x4138329e, 0xbd9138c5), SECP256K1_FE_CONST(0x58aab390, 0xab6fb55c, 0x1d1b8089, 0x7a207ce9, 0x4a78fa5b, 0x4aa61a33, 0x398bcae9, 0xadb20d3e), SECP256K1_FE_CONST(0x3772da0b, 0xebf8c894, 0x4d3fc580, 0x0014c138, 0x7ee33bcb, 0x6e5f3c55, 0x3fc87322, 0x87ca8041), SECP256K1_FE_CONST(0xae3fd9c9, 0x31ff3dcb, 0xa1327652, 0x49f7601b, 0x2a1e7536, 0xdb1ceba1, 0x9996afe2, 0x2c85fb5b), SECP256K1_FE_CONST(0xdfa4caed, 0x24bfade3, 0x4dff6ad1, 0x984b9098, 0x1f6187c6, 0x1f21bbff, 0xbec7cd60, 0x426ec36a), SECP256K1_FE_CONST(0xa7554c6f, 0x54904aa3, 0xe2e47f76, 0x85df8316, 0xb58705a4, 0xb559e5cc, 0xc6743515, 0x524deef1)}}, + {0x00, SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xff, SECP256K1_FE_CONST(0xe6bcb5c3, 0xd63467d4, 0x90bfa54f, 0xbbc6092a, 0x7248c25e, 0x11b248dc, 0x2964a6e1, 0x5edb1457), SECP256K1_FE_CONST(0x19434a3c, 0x29cb982b, 0x6f405ab0, 0x4439f6d5, 0x8db73da1, 0xee4db723, 0xd69b591d, 0xa124e7d8), {SECP256K1_FE_CONST(0x67119877, 0x832ab8f4, 0x59a82165, 0x6d8261f5, 0x44a553b8, 0x9ae4f25c, 0x52a97134, 0xb70f3426), SECP256K1_FE_CONST(0xffee02f5, 0xe649c07f, 0x0560eff1, 0x867ec7b3, 0x2d0e595e, 0x9b1c0ea6, 0xe2a4fc70, 0xc97cd71f), SECP256K1_FE_CONST(0xb5e0c189, 0xeb5b4bac, 0xd025b744, 0x4d74178b, 0xe8d5246c, 0xfa4a9a20, 0x7964a057, 0xee969992), SECP256K1_FE_CONST(0x5746e459, 0x1bf7f4c3, 0x044609ea, 0x372e9086, 0x03975d27, 0x9fdef834, 0x9f0b08d3, 0x2f07619d), SECP256K1_FE_CONST(0x98ee6788, 0x7cd5470b, 0xa657de9a, 0x927d9e0a, 0xbb5aac47, 0x651b0da3, 0xad568eca, 0x48f0c809), SECP256K1_FE_CONST(0x0011fd0a, 0x19b63f80, 0xfa9f100e, 0x7981384c, 0xd2f1a6a1, 0x64e3f159, 0x1d5b038e, 0x36832510), SECP256K1_FE_CONST(0x4a1f3e76, 0x14a4b453, 0x2fda48bb, 0xb28be874, 0x172adb93, 0x05b565df, 0x869b5fa7, 0x1169629d), SECP256K1_FE_CONST(0xa8b91ba6, 0xe4080b3c, 0xfbb9f615, 0xc8d16f79, 0xfc68a2d8, 0x602107cb, 0x60f4f72b, 0xd0f89a92)}}, + {0x33, SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), {SECP256K1_FE_CONST(0x4f867ad8, 0xbb3d8404, 0x09d26b67, 0x307e6210, 0x0153273f, 0x72fa4b74, 0x84becfa1, 0x4ebe7408), SECP256K1_FE_CONST(0x5bbc4f59, 0xe452cc5f, 0x22a99144, 0xb10ce898, 0x9a89a995, 0xec3cea1c, 0x91ae10e8, 0xf721bb5d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb0798527, 0x44c27bfb, 0xf62d9498, 0xcf819def, 0xfeacd8c0, 0x8d05b48b, 0x7b41305d, 0xb1418827), SECP256K1_FE_CONST(0xa443b0a6, 0x1bad33a0, 0xdd566ebb, 0x4ef31767, 0x6576566a, 0x13c315e3, 0x6e51ef16, 0x08de40d2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0xf455605b, 0xc85bf48e, 0x3a908c31, 0x023faf98, 0x381504c6, 0xc6d3aeb9, 0xede55f8d, 0xd528924d), SECP256K1_FE_CONST(0xd31fbcd5, 0xcdb798f6, 0xc00db669, 0x2f8fe896, 0x7fa9c79d, 0xd10958f4, 0xa194f013, 0x74905e99), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x0c00c571, 0x5b56fe63, 0x2d814ad8, 0xa77f8e66, 0x628ea47a, 0x6116834f, 0x8c1218f3, 0xa03cbd50), SECP256K1_FE_CONST(0xdf88e44f, 0xac84fa52, 0xdf4d59f4, 0x8819f18f, 0x6a8cd415, 0x1d162afa, 0xf773166f, 0x57c7ff46), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xf3ff3a8e, 0xa4a9019c, 0xd27eb527, 0x58807199, 0x9d715b85, 0x9ee97cb0, 0x73ede70b, 0x5fc33edf), SECP256K1_FE_CONST(0x20771bb0, 0x537b05ad, 0x20b2a60b, 0x77e60e70, 0x95732bea, 0xe2e9d505, 0x088ce98f, 0xa837fce9)}}, + {0xff, SECP256K1_FE_CONST(0xf58cd4d9, 0x830bad32, 0x2699035e, 0x8246007d, 0x4be27e19, 0xb6f53621, 0x317b4f30, 0x9b3daa9d), SECP256K1_FE_CONST(0x78ec2b3d, 0xc0948de5, 0x60148bbc, 0x7c6dc963, 0x3ad5df70, 0xa5a5750c, 0xbed72180, 0x4f082a3b), {SECP256K1_FE_CONST(0x6c4c580b, 0x76c75940, 0x43569f9d, 0xae16dc28, 0x01c16a1f, 0xbe128608, 0x81b75f8e, 0xf929bce5), SECP256K1_FE_CONST(0x94231355, 0xe7385c5f, 0x25ca436a, 0xa6419147, 0x1aea4393, 0xd6e86ab7, 0xa35fe2af, 0xacaefd0d), SECP256K1_FE_CONST(0xdff2a195, 0x1ada6db5, 0x74df8340, 0x48149da3, 0x397a75b8, 0x29abf58c, 0x7e69db1b, 0x41ac0989), SECP256K1_FE_CONST(0xa52b66d3, 0xc9070355, 0x48028bf8, 0x04711bf4, 0x22aba95f, 0x1a666fc8, 0x6f4648e0, 0x5f29caae), SECP256K1_FE_CONST(0x93b3a7f4, 0x8938a6bf, 0xbca96062, 0x51e923d7, 0xfe3e95e0, 0x41ed79f7, 0x7e48a070, 0x06d63f4a), SECP256K1_FE_CONST(0x6bdcecaa, 0x18c7a3a0, 0xda35bc95, 0x59be6eb8, 0xe515bc6c, 0x29179548, 0x5ca01d4f, 0x5350ff22), SECP256K1_FE_CONST(0x200d5e6a, 0xe525924a, 0x8b207cbf, 0xb7eb625c, 0xc6858a47, 0xd6540a73, 0x819624e3, 0xbe53f2a6), SECP256K1_FE_CONST(0x5ad4992c, 0x36f8fcaa, 0xb7fd7407, 0xfb8ee40b, 0xdd5456a0, 0xe5999037, 0x90b9b71e, 0xa0d63181)}}, + {0x00, SECP256K1_FE_CONST(0xfd7d912a, 0x40f182a3, 0x588800d6, 0x9ebfb504, 0x8766da20, 0x6fd7ebc8, 0xd2436c81, 0xcbef6421), SECP256K1_FE_CONST(0x8d37c862, 0x054debe7, 0x31694536, 0xff46b273, 0xec122b35, 0xa9bf1445, 0xac3c4ff9, 0xf262c952), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, +}; + +/* Set of (encoding, xcoord) test vectors, selected to maximize branch coverage, part of the BIP324 + * test vectors. Created using an independent implementation, and tested decoding against the paper + * authors' code. */ +static const struct ellswift_decode_test ellswift_decode_tests[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 1}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0}, + {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0}, + {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0}, + {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x74e880b3, 0xffd18fe3, 0xcddf7902, 0x522551dd, 0xf97fa4a3, 0x5a3cfda8, 0x197f9470, 0x81a57b8f), 0}, + {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x377b643f, 0xce2271f6, 0x4e5c8101, 0x566107c1, 0xbe498074, 0x50917838, 0x04f65478, 0x1ac9217c), 1}, + {{0x12, 0x36, 0x58, 0x44, 0x4f, 0x32, 0xbe, 0x8f, 0x02, 0xea, 0x20, 0x34, 0xaf, 0xa7, 0xef, 0x4b, 0xbe, 0x8a, 0xdc, 0x91, 0x8c, 0xeb, 0x49, 0xb1, 0x27, 0x73, 0xb6, 0x25, 0xf4, 0x90, 0xb3, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xc5, 0xfe, 0x11}, SECP256K1_FE_CONST(0xed16d65c, 0xf3a9538f, 0xcb2c139f, 0x1ecbc143, 0xee148271, 0x20cbc265, 0x9e667256, 0x800b8142), 0}, + {{0x14, 0x6f, 0x92, 0x46, 0x4d, 0x15, 0xd3, 0x6e, 0x35, 0x38, 0x2b, 0xd3, 0xca, 0x5b, 0x0f, 0x97, 0x6c, 0x95, 0xcb, 0x08, 0xac, 0xdc, 0xf2, 0xd5, 0xb3, 0x57, 0x06, 0x17, 0x99, 0x08, 0x39, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x45, 0xe9, 0x3b}, SECP256K1_FE_CONST(0x0d5cd840, 0x427f941f, 0x65193079, 0xab8e2e83, 0x024ef2ee, 0x7ca558d8, 0x8879ffd8, 0x79fb6657), 0}, + {{0x15, 0xfd, 0xf5, 0xcf, 0x09, 0xc9, 0x07, 0x59, 0xad, 0xd2, 0x27, 0x2d, 0x57, 0x4d, 0x2b, 0xb5, 0xfe, 0x14, 0x29, 0xf9, 0xf3, 0xc1, 0x4c, 0x65, 0xe3, 0x19, 0x4b, 0xf6, 0x1b, 0x82, 0xaa, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0xcf, 0xd9, 0x06}, SECP256K1_FE_CONST(0x16d0e439, 0x46aec93f, 0x62d57eb8, 0xcde68951, 0xaf136cf4, 0xb307938d, 0xd1447411, 0xe07bffe1), 1}, + {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0}, + {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0}, + {{0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x98bec3b2, 0xa351fa96, 0xcfd191c1, 0x77835193, 0x1b9e9ba9, 0xad1149f6, 0xd9eadca8, 0x0981b801), 0}, + {{0x40, 0x56, 0xa3, 0x4a, 0x21, 0x0e, 0xec, 0x78, 0x92, 0xe8, 0x82, 0x06, 0x75, 0xc8, 0x60, 0x09, 0x9f, 0x85, 0x7b, 0x26, 0xaa, 0xd8, 0x54, 0x70, 0xee, 0x6d, 0x3c, 0xf1, 0x30, 0x4a, 0x9d, 0xcf, 0x37, 0x5e, 0x70, 0x37, 0x42, 0x71, 0xf2, 0x0b, 0x13, 0xc9, 0x98, 0x6e, 0xd7, 0xd3, 0xc1, 0x77, 0x99, 0x69, 0x8c, 0xfc, 0x43, 0x5d, 0xbe, 0xd3, 0xa9, 0xf3, 0x4b, 0x38, 0xc8, 0x23, 0xc2, 0xb4}, SECP256K1_FE_CONST(0x868aac20, 0x03b29dbc, 0xad1a3e80, 0x3855e078, 0xa89d1654, 0x3ac64392, 0xd1224172, 0x98cec76e), 0}, + {{0x41, 0x97, 0xec, 0x37, 0x23, 0xc6, 0x54, 0xcf, 0xdd, 0x32, 0xab, 0x07, 0x55, 0x06, 0x64, 0x8b, 0x2f, 0xf5, 0x07, 0x03, 0x62, 0xd0, 0x1a, 0x4f, 0xff, 0x14, 0xb3, 0x36, 0xb7, 0x8f, 0x96, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0xab, 0x1e, 0x95}, SECP256K1_FE_CONST(0xba5a6314, 0x502a8952, 0xb8f456e0, 0x85928105, 0xf665377a, 0x8ce27726, 0xa5b0eb7e, 0xc1ac0286), 0}, + {{0x47, 0xeb, 0x3e, 0x20, 0x8f, 0xed, 0xcd, 0xf8, 0x23, 0x4c, 0x94, 0x21, 0xe9, 0xcd, 0x9a, 0x7a, 0xe8, 0x73, 0xbf, 0xbd, 0xbc, 0x39, 0x37, 0x23, 0xd1, 0xba, 0x1e, 0x1e, 0x6a, 0x8e, 0x6b, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xd1, 0x2c, 0xb1}, SECP256K1_FE_CONST(0xd192d520, 0x07e541c9, 0x807006ed, 0x0468df77, 0xfd214af0, 0xa795fe11, 0x9359666f, 0xdcf08f7c), 0}, + {{0x5e, 0xb9, 0x69, 0x6a, 0x23, 0x36, 0xfe, 0x2c, 0x3c, 0x66, 0x6b, 0x02, 0xc7, 0x55, 0xdb, 0x4c, 0x0c, 0xfd, 0x62, 0x82, 0x5c, 0x7b, 0x58, 0x9a, 0x7b, 0x7b, 0xb4, 0x42, 0xe1, 0x41, 0xc1, 0xd6, 0x93, 0x41, 0x3f, 0x00, 0x52, 0xd4, 0x9e, 0x64, 0xab, 0xec, 0x6d, 0x58, 0x31, 0xd6, 0x6c, 0x43, 0x61, 0x28, 0x30, 0xa1, 0x7d, 0xf1, 0xfe, 0x43, 0x83, 0xdb, 0x89, 0x64, 0x68, 0x10, 0x02, 0x21}, SECP256K1_FE_CONST(0xef6e1da6, 0xd6c7627e, 0x80f7a723, 0x4cb08a02, 0x2c1ee1cf, 0x29e4d0f9, 0x642ae924, 0xcef9eb38), 1}, + {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0}, + {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0}, + {{0x85, 0x1b, 0x1c, 0xa9, 0x45, 0x49, 0x37, 0x1c, 0x4f, 0x1f, 0x71, 0x87, 0x32, 0x1d, 0x39, 0xbf, 0x51, 0xc6, 0xb7, 0xfb, 0x61, 0xf7, 0xcb, 0xf0, 0x27, 0xc9, 0xda, 0x62, 0x02, 0x1b, 0x7a, 0x65, 0xfc, 0x54, 0xc9, 0x68, 0x37, 0xfb, 0x22, 0xb3, 0x62, 0xed, 0xa6, 0x3e, 0xc5, 0x2e, 0xc8, 0x3d, 0x81, 0xbe, 0xdd, 0x16, 0x0c, 0x11, 0xb2, 0x2d, 0x96, 0x5d, 0x9f, 0x4a, 0x6d, 0x64, 0xd2, 0x51}, SECP256K1_FE_CONST(0x3e731051, 0xe12d3323, 0x7eb324f2, 0xaa5b16bb, 0x868eb49a, 0x1aa1fadc, 0x19b6e876, 0x1b5a5f7b), 1}, + {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0}, + {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0}, + {{0xa0, 0xf1, 0x84, 0x92, 0x18, 0x3e, 0x61, 0xe8, 0x06, 0x3e, 0x57, 0x36, 0x06, 0x59, 0x14, 0x21, 0xb0, 0x6b, 0xc3, 0x51, 0x36, 0x31, 0x57, 0x8a, 0x73, 0xa3, 0x9c, 0x1c, 0x33, 0x06, 0x23, 0x9f, 0x2f, 0x32, 0x90, 0x4f, 0x0d, 0x2a, 0x33, 0xec, 0xca, 0x8a, 0x54, 0x51, 0x70, 0x5b, 0xb5, 0x37, 0xd3, 0xbf, 0x44, 0xe0, 0x71, 0x22, 0x60, 0x25, 0xcd, 0xbf, 0xd2, 0x49, 0xfe, 0x0f, 0x7a, 0xd6}, SECP256K1_FE_CONST(0x97a09cf1, 0xa2eae7c4, 0x94df3c6f, 0x8a9445bf, 0xb8c09d60, 0x832f9b0b, 0x9d5eabe2, 0x5fbd14b9), 0}, + {{0xa1, 0xed, 0x0a, 0x0b, 0xd7, 0x9d, 0x8a, 0x23, 0xcf, 0xe4, 0xec, 0x5f, 0xef, 0x5b, 0xa5, 0xcc, 0xcf, 0xd8, 0x44, 0xe4, 0xff, 0x5c, 0xb4, 0xb0, 0xf2, 0xe7, 0x16, 0x27, 0x34, 0x1f, 0x1c, 0x5b, 0x17, 0xc4, 0x99, 0x24, 0x9e, 0x0a, 0xc0, 0x8d, 0x5d, 0x11, 0xea, 0x1c, 0x2c, 0x8c, 0xa7, 0x00, 0x16, 0x16, 0x55, 0x9a, 0x79, 0x94, 0xea, 0xde, 0xc9, 0xca, 0x10, 0xfb, 0x4b, 0x85, 0x16, 0xdc}, SECP256K1_FE_CONST(0x65a89640, 0x744192cd, 0xac64b2d2, 0x1ddf989c, 0xdac75007, 0x25b645be, 0xf8e2200a, 0xe39691f2), 0}, + {{0xba, 0x94, 0x59, 0x4a, 0x43, 0x27, 0x21, 0xaa, 0x35, 0x80, 0xb8, 0x4c, 0x16, 0x1d, 0x0d, 0x13, 0x4b, 0xc3, 0x54, 0xb6, 0x90, 0x40, 0x4d, 0x7c, 0xd4, 0xec, 0x57, 0xc1, 0x6d, 0x3f, 0xbe, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x50, 0x7d, 0xd7}, SECP256K1_FE_CONST(0x5e0d7656, 0x4aae92cb, 0x347e01a6, 0x2afd389a, 0x9aa401c7, 0x6c8dd227, 0x543dc9cd, 0x0efe685a), 0}, + {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x2d97f96c, 0xac882dfe, 0x73dc44db, 0x6ce0f1d3, 0x1d624135, 0x8dd5d74e, 0xb3d3b500, 0x03d24c2b), 0}, + {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x65, 0x07, 0xd0, 0x9a}, SECP256K1_FE_CONST(0xe7008afe, 0x6e8cbd50, 0x55df120b, 0xd748757c, 0x686dadb4, 0x1cce75e4, 0xaddcc5e0, 0x2ec02b44), 1}, + {{0xc5, 0x98, 0x1b, 0xae, 0x27, 0xfd, 0x84, 0x40, 0x1c, 0x72, 0xa1, 0x55, 0xe5, 0x70, 0x7f, 0xbb, 0x81, 0x1b, 0x2b, 0x62, 0x06, 0x45, 0xd1, 0x02, 0x8e, 0xa2, 0x70, 0xcb, 0xe0, 0xee, 0x22, 0x5d, 0x4b, 0x62, 0xaa, 0x4d, 0xca, 0x65, 0x06, 0xc1, 0xac, 0xdb, 0xec, 0xc0, 0x55, 0x25, 0x69, 0xb4, 0xb2, 0x14, 0x36, 0xa5, 0x69, 0x2e, 0x25, 0xd9, 0x0d, 0x3b, 0xc2, 0xeb, 0x7c, 0xe2, 0x40, 0x78}, SECP256K1_FE_CONST(0x948b40e7, 0x181713bc, 0x018ec170, 0x2d3d054d, 0x15746c59, 0xa7020730, 0xdd13ecf9, 0x85a010d7), 0}, + {{0xc8, 0x94, 0xce, 0x48, 0xbf, 0xec, 0x43, 0x30, 0x14, 0xb9, 0x31, 0xa6, 0xad, 0x42, 0x26, 0xd7, 0xdb, 0xd8, 0xea, 0xa7, 0xb6, 0xe3, 0xfa, 0xa8, 0xd0, 0xef, 0x94, 0x05, 0x2b, 0xcf, 0x8c, 0xff, 0x33, 0x6e, 0xeb, 0x39, 0x19, 0xe2, 0xb4, 0xef, 0xb7, 0x46, 0xc7, 0xf7, 0x1b, 0xbc, 0xa7, 0xe9, 0x38, 0x32, 0x30, 0xfb, 0xbc, 0x48, 0xff, 0xaf, 0xe7, 0x7e, 0x8b, 0xcc, 0x69, 0x54, 0x24, 0x71}, SECP256K1_FE_CONST(0xf1c91acd, 0xc2525330, 0xf9b53158, 0x434a4d43, 0xa1c547cf, 0xf29f1550, 0x6f5da4eb, 0x4fe8fa5a), 1}, + {{0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x872d81ed, 0x8831d999, 0x8b67cb71, 0x05243edb, 0xf86c10ed, 0xfebb786c, 0x110b02d0, 0x7b2e67cd), 0}, + {{0xd9, 0x17, 0xb7, 0x86, 0xda, 0xc3, 0x56, 0x70, 0xc3, 0x30, 0xc9, 0xc5, 0xae, 0x59, 0x71, 0xdf, 0xb4, 0x95, 0xc8, 0xae, 0x52, 0x3e, 0xd9, 0x7e, 0xe2, 0x42, 0x01, 0x17, 0xb1, 0x71, 0xf4, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x01, 0xf6, 0xf6}, SECP256K1_FE_CONST(0xe45b71e1, 0x10b831f2, 0xbdad8651, 0x994526e5, 0x8393fde4, 0x328b1ec0, 0x4d598971, 0x42584691), 1}, + {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0}, + {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0}, + {{0xe7, 0xee, 0x58, 0x14, 0xc1, 0x70, 0x6b, 0xf8, 0xa8, 0x93, 0x96, 0xa9, 0xb0, 0x32, 0xbc, 0x01, 0x4c, 0x2c, 0xac, 0x9c, 0x12, 0x11, 0x27, 0xdb, 0xf6, 0xc9, 0x92, 0x78, 0xf8, 0xbb, 0x53, 0xd1, 0xdf, 0xd0, 0x4d, 0xbc, 0xda, 0x8e, 0x35, 0x24, 0x66, 0xb6, 0xfc, 0xd5, 0xf2, 0xde, 0xa3, 0xe1, 0x7d, 0x5e, 0x13, 0x31, 0x15, 0x88, 0x6e, 0xda, 0x20, 0xdb, 0x8a, 0x12, 0xb5, 0x4d, 0xe7, 0x1b}, SECP256K1_FE_CONST(0xe842c6e3, 0x529b2342, 0x70a5e977, 0x44edc34a, 0x04d7ba94, 0xe44b6d25, 0x23c9cf01, 0x95730a50), 1}, + {{0xf2, 0x92, 0xe4, 0x68, 0x25, 0xf9, 0x22, 0x5a, 0xd2, 0x3d, 0xc0, 0x57, 0xc1, 0xd9, 0x1c, 0x4f, 0x57, 0xfc, 0xb1, 0x38, 0x6f, 0x29, 0xef, 0x10, 0x48, 0x1c, 0xb1, 0xd2, 0x25, 0x18, 0x59, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x11, 0xc9, 0x89}, SECP256K1_FE_CONST(0x3cea2c53, 0xb8b01701, 0x66ac7da6, 0x7194694a, 0xdacc84d5, 0x6389225e, 0x330134da, 0xb85a4d55), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x02, 0x8c, 0x59, 0x00, 0x63, 0xf6, 0x4d, 0x5a, 0x7f, 0x1c, 0x14, 0x91, 0x5c, 0xd6, 0x1e, 0xac, 0x88, 0x6a, 0xb2, 0x95, 0xbe, 0xbd, 0x91, 0x99, 0x25, 0x04, 0xcf, 0x77, 0xed, 0xb0, 0x28, 0xbd, 0xd6, 0x26, 0x7f}, SECP256K1_FE_CONST(0x3fde5713, 0xf8282eea, 0xd7d39d42, 0x01f44a7c, 0x85a5ac8a, 0x0681f35e, 0x54085c6b, 0x69543374), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x57, 0x09, 0xe7, 0x15, 0x6c, 0x41, 0x77, 0x17, 0xf2, 0xfe, 0xab, 0x14, 0x71, 0x41, 0xec, 0x3d, 0xa1, 0x9f, 0xb7, 0x59, 0x57, 0x5c, 0xc6, 0xe3, 0x7b, 0x2e, 0xa5, 0xac, 0x93, 0x09, 0xf2, 0x6f, 0x0f, 0x66}, SECP256K1_FE_CONST(0xd2469ab3, 0xe04acbb2, 0x1c65a180, 0x9f39caaf, 0xe7a77c13, 0xd10f9dd3, 0x8f391c01, 0xdc499c52), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3a, 0x08, 0xcc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x60, 0xe9, 0xf0}, SECP256K1_FE_CONST(0x38e2a5ce, 0x6a93e795, 0xe16d2c39, 0x8bc99f03, 0x69202ce2, 0x1e8f09d5, 0x6777b40f, 0xc512bccc), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x91, 0x25, 0x7d, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x864b3dc9, 0x02c37670, 0x9c10a93a, 0xd4bbe29f, 0xce0012f3, 0xdc8672c6, 0x286bba28, 0xd7d6d6fc), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0x5d, 0x6c, 0x1c, 0x32, 0x2c, 0xad, 0xf5, 0x99, 0xdb, 0xb8, 0x64, 0x81, 0x52, 0x2b, 0x3c, 0xc5, 0x5f, 0x15, 0xa6, 0x79, 0x32, 0xdb, 0x2a, 0xfa, 0x01, 0x11, 0xd9, 0xed, 0x69, 0x81, 0xbc, 0xd1, 0x24, 0xbf, 0x44}, SECP256K1_FE_CONST(0x766dfe4a, 0x700d9bee, 0x288b903a, 0xd58870e3, 0xd4fe2f0e, 0xf780bcac, 0x5c823f32, 0x0d9a9bef), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8e, 0x42, 0x6f, 0x03, 0x92, 0x38, 0x90, 0x78, 0xc1, 0x2b, 0x1a, 0x89, 0xe9, 0x54, 0x2f, 0x05, 0x93, 0xbc, 0x96, 0xb6, 0xbf, 0xde, 0x82, 0x24, 0xf8, 0x65, 0x4e, 0xf5, 0xd5, 0xcd, 0xa9, 0x35, 0xa3, 0x58, 0x21, 0x94}, SECP256K1_FE_CONST(0xfaec7bc1, 0x987b6323, 0x3fbc5f95, 0x6edbf37d, 0x54404e74, 0x61c58ab8, 0x631bc68e, 0x451a0478), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x91, 0x19, 0x21, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0xf0, 0xf1, 0xeb}, SECP256K1_FE_CONST(0xec29a50b, 0xae138dbf, 0x7d8e2482, 0x5006bb5f, 0xc1a2cc12, 0x43ba335b, 0xc6116fb9, 0xe498ec1f), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x98, 0xeb, 0x9a, 0xb7, 0x6e, 0x84, 0x49, 0x9c, 0x48, 0x3b, 0x3b, 0xf0, 0x62, 0x14, 0xab, 0xfe, 0x06, 0x5d, 0xdd, 0xf4, 0x3b, 0x86, 0x01, 0xde, 0x59, 0x6d, 0x63, 0xb9, 0xe4, 0x5a, 0x16, 0x6a, 0x58, 0x05, 0x41, 0xfe}, SECP256K1_FE_CONST(0x1e0ff2de, 0xe9b09b13, 0x6292a9e9, 0x10f0d6ac, 0x3e552a64, 0x4bba39e6, 0x4e9dd3e3, 0xbbd3d4d4), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x8b7dd5c3, 0xedba9ee9, 0x7b70eff4, 0x38f22dca, 0x9849c825, 0x4a2f3345, 0xa0a572ff, 0xeaae0928), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x0881950c, 0x8f51d6b9, 0xa6387465, 0xd5f12609, 0xef1bb254, 0x12a08a74, 0xcb2dfb20, 0x0c74bfbf), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0xf5, 0xcd, 0x83, 0x88, 0x16, 0xc1, 0x6c, 0x4f, 0xe8, 0xa1, 0x66, 0x1d, 0x60, 0x6f, 0xdb, 0x13, 0xcf, 0x9a, 0xf0, 0x4b, 0x97, 0x9a, 0x2e, 0x15, 0x9a, 0x09, 0x40, 0x9e, 0xbc, 0x86, 0x45, 0xd5, 0x8f, 0xde, 0x02}, SECP256K1_FE_CONST(0x2f083207, 0xb9fd9b55, 0x0063c31c, 0xd62b8746, 0xbd543bdc, 0x5bbf10e3, 0xa35563e9, 0x27f440c8), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x64, 0xd1, 0x62, 0x75, 0x05, 0x46, 0xce, 0x42, 0xb0, 0x43, 0x13, 0x61, 0xe5, 0x2d, 0x4f, 0x52, 0x42, 0xd8, 0xf2, 0x4f, 0x33, 0xe6, 0xb1, 0xf9, 0x9b, 0x59, 0x16, 0x47, 0xcb, 0xc8, 0x08, 0xf4, 0x62, 0xaf, 0x51}, SECP256K1_FE_CONST(0xd41244d1, 0x1ca4f652, 0x40687759, 0xf95ca9ef, 0xbab767ed, 0xedb38fd1, 0x8c36e18c, 0xd3b6f6a9), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe5, 0xbe, 0x52, 0x37, 0x2d, 0xd6, 0xe8, 0x94, 0xb2, 0xa3, 0x26, 0xfc, 0x36, 0x05, 0xa6, 0xe8, 0xf3, 0xc6, 0x9c, 0x71, 0x0b, 0xf2, 0x7d, 0x63, 0x0d, 0xfe, 0x20, 0x04, 0x98, 0x8b, 0x78, 0xeb, 0x6e, 0xab, 0x36}, SECP256K1_FE_CONST(0x64bf84dd, 0x5e03670f, 0xdb24c0f5, 0xd3c2c365, 0x736f51db, 0x6c92d950, 0x10716ad2, 0xd36134c8), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb, 0xb9, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xd6, 0xdb, 0x1f}, SECP256K1_FE_CONST(0x1c92ccdf, 0xcf4ac550, 0xc28db57c, 0xff0c8515, 0xcb26936c, 0x786584a7, 0x0114008d, 0x6c33a34b), 0}, +}; + +/* Set of expected ellswift_xdh BIP324 shared secrets, given private key, encodings, initiating, + * taken from the BIP324 test vectors. Created using an independent implementation, and tested + * against the paper authors' decoding code. */ +static const struct ellswift_xdh_test ellswift_xdh_tests_bip324[] = { + {{0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b, 0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b, 0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7}, {0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4, 0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef, 0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85, 0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9, 0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b}, {0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1, 0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c, 0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5}, 1, {0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3, 0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a, 0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92}}, + {{0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9, 0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31, 0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f}, {0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16, 0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47, 0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64, 0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba, 0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, {0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac, 0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6, 0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84}}, + {{0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e, 0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76, 0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d}, {0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25, 0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee, 0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36, 0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89, 0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde, 0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed, 0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae}, 1, {0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b, 0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c, 0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c}}, + {{0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44, 0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82, 0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38}, {0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96, 0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7, 0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97, 0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b, 0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9}, {0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9, 0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f, 0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa, 0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87, 0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a}, 0, {0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1, 0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0, 0xcd, 0x43, 0x24, 0x15, 0x08, 0x53}}, + {{0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b, 0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36, 0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9, 0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59, 0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1, {0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda, 0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54, 0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2}}, + {{0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95, 0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8, 0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9, 0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19, 0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d}, {0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62, 0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1, 0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70}, 0, {0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b, 0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f, 0xf8, 0xec, 0x92, 0xff, 0x66, 0x55}}, + {{0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01, 0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc, 0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3, 0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd, 0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9}, {0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3, 0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91, 0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e, 0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7, 0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46}, 1, {0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8, 0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9, 0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d}}, +}; + +/** This is a hasher for ellswift_xdh which just returns the shared X coordinate. + * + * This is generally a bad idea as it means changes to the encoding of the + * exchanged public keys do not affect the shared secret. However, it's used here + * in tests to be able to verify the X coordinate through other means. + */ +static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + (void)ell_a64; + (void)ell_b64; + (void)data; + memcpy(output, x32, 32); + return 1; +} + +void run_ellswift_tests(void) { + int i = 0; + /* Test vectors. */ + for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) { + const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i]; + int c; + for (c = 0; c < 8; ++c) { + secp256k1_fe t; + int ret = secp256k1_ellswift_xswiftec_inv_var(&t, &testcase->x, &testcase->u, c); + CHECK(ret == ((testcase->enc_bitmap >> c) & 1)); + if (ret) { + secp256k1_fe x2; + CHECK(fe_equal(&t, &testcase->encs[c])); + secp256k1_ellswift_xswiftec_var(&x2, &testcase->u, &testcase->encs[c]); + CHECK(fe_equal(&testcase->x, &x2)); + } + } + } + for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) { + const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i]; + secp256k1_pubkey pubkey; + secp256k1_ge ge; + int ret; + ret = secp256k1_ellswift_decode(CTX, &pubkey, testcase->enc); + CHECK(ret); + ret = secp256k1_pubkey_load(CTX, &ge, &pubkey); + CHECK(ret); + CHECK(fe_equal(&testcase->x, &ge.x)); + CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y); + } + for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) { + const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i]; + unsigned char shared_secret[32]; + int ret; + int party = !test->initiating; + const unsigned char* ell_a64 = party ? test->ellswift_theirs : test->ellswift_ours; + const unsigned char* ell_b64 = party ? test->ellswift_ours : test->ellswift_theirs; + ret = secp256k1_ellswift_xdh(CTX, shared_secret, + ell_a64, ell_b64, + test->priv_ours, + party, + secp256k1_ellswift_xdh_hash_function_bip324, + NULL); + CHECK(ret); + CHECK(secp256k1_memcmp_var(shared_secret, test->shared_secret, 32) == 0); + } + /* Verify that secp256k1_ellswift_encode + decode roundtrips. */ + for (i = 0; i < 1000 * COUNT; i++) { + unsigned char rnd32[32]; + unsigned char ell64[64]; + secp256k1_ge g, g2; + secp256k1_pubkey pubkey, pubkey2; + /* Generate random public key and random randomizer. */ + testutil_random_ge_test(&g); + secp256k1_pubkey_save(&pubkey, &g); + testrand256(rnd32); + /* Convert the public key to ElligatorSwift and back. */ + secp256k1_ellswift_encode(CTX, ell64, &pubkey, rnd32); + secp256k1_ellswift_decode(CTX, &pubkey2, ell64); + secp256k1_pubkey_load(CTX, &g2, &pubkey2); + /* Compare with original. */ + CHECK(secp256k1_ge_eq_var(&g, &g2)); + } + /* Verify the behavior of secp256k1_ellswift_create */ + for (i = 0; i < 400 * COUNT; i++) { + unsigned char auxrnd32[32], sec32[32]; + secp256k1_scalar sec; + secp256k1_gej res; + secp256k1_ge dec; + secp256k1_pubkey pub; + unsigned char ell64[64]; + int ret; + /* Generate random secret key and random randomizer. */ + if (i & 1) testrand256_test(auxrnd32); + testutil_random_scalar_order_test(&sec); + secp256k1_scalar_get_b32(sec32, &sec); + /* Construct ElligatorSwift-encoded public keys for that key. */ + ret = secp256k1_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL); + CHECK(ret); + /* Decode it, and compare with traditionally-computed public key. */ + secp256k1_ellswift_decode(CTX, &pub, ell64); + secp256k1_pubkey_load(CTX, &dec, &pub); + secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec); + CHECK(secp256k1_gej_eq_ge_var(&res, &dec)); + } + /* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */ + for (i = 0; i < 800 * COUNT; i++) { + unsigned char ell64[64], sec32[32], share32[32]; + secp256k1_scalar sec; + secp256k1_ge dec, res; + secp256k1_fe share_x; + secp256k1_gej decj, resj; + secp256k1_pubkey pub; + int ret; + /* Generate random secret key. */ + testutil_random_scalar_order_test(&sec); + secp256k1_scalar_get_b32(sec32, &sec); + /* Generate random ElligatorSwift encoding for the remote key and decode it. */ + testrand256_test(ell64); + testrand256_test(ell64 + 32); + secp256k1_ellswift_decode(CTX, &pub, ell64); + secp256k1_pubkey_load(CTX, &dec, &pub); + secp256k1_gej_set_ge(&decj, &dec); + /* Compute the X coordinate of seckey*pubkey using ellswift_xdh. Note that we + * pass ell64 as claimed (but incorrect) encoding for sec32 here; this works + * because the "hasher" function we use here ignores the ell64 arguments. */ + ret = secp256k1_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL); + CHECK(ret); + (void)secp256k1_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */ + SECP256K1_FE_VERIFY(&share_x); + /* Compute seckey*pubkey directly. */ + secp256k1_ecmult(&resj, &decj, &sec, NULL); + secp256k1_ge_set_gej(&res, &resj); + /* Compare. */ + CHECK(fe_equal(&res.x, &share_x)); + } + /* Verify the joint behavior of secp256k1_ellswift_xdh */ + for (i = 0; i < 200 * COUNT; i++) { + unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32]; + unsigned char sec32a[32], sec32b[32], sec32a_bad[32], sec32b_bad[32]; + secp256k1_scalar seca, secb; + unsigned char ell64a[64], ell64b[64], ell64a_bad[64], ell64b_bad[64]; + unsigned char share32a[32], share32b[32], share32_bad[32]; + unsigned char prefix64[64]; + secp256k1_ellswift_xdh_hash_function hash_function; + void* data; + int ret; + + /* Pick hasher to use. */ + if ((i % 3) == 0) { + hash_function = ellswift_xdh_hash_x32; + data = NULL; + } else if ((i % 3) == 1) { + hash_function = secp256k1_ellswift_xdh_hash_function_bip324; + data = NULL; + } else { + hash_function = secp256k1_ellswift_xdh_hash_function_prefix; + testrand256_test(prefix64); + testrand256_test(prefix64 + 32); + data = prefix64; + } + + /* Generate random secret keys and random randomizers. */ + testrand256_test(auxrnd32a); + testrand256_test(auxrnd32b); + testutil_random_scalar_order_test(&seca); + /* Draw secb uniformly at random to make sure that the secret keys + * differ */ + testutil_random_scalar_order(&secb); + secp256k1_scalar_get_b32(sec32a, &seca); + secp256k1_scalar_get_b32(sec32b, &secb); + + /* Construct ElligatorSwift-encoded public keys for those keys. */ + /* For A: */ + ret = secp256k1_ellswift_create(CTX, ell64a, sec32a, auxrnd32a); + CHECK(ret); + /* For B: */ + ret = secp256k1_ellswift_create(CTX, ell64b, sec32b, auxrnd32b); + CHECK(ret); + + /* Compute the shared secret both ways and compare with each other. */ + /* For A: */ + ret = secp256k1_ellswift_xdh(CTX, share32a, ell64a, ell64b, sec32a, 0, hash_function, data); + CHECK(ret); + /* For B: */ + ret = secp256k1_ellswift_xdh(CTX, share32b, ell64a, ell64b, sec32b, 1, hash_function, data); + CHECK(ret); + /* And compare: */ + CHECK(secp256k1_memcmp_var(share32a, share32b, 32) == 0); + + /* Verify that the shared secret doesn't match if other side's public key is incorrect. */ + /* For A (using a bad public key for B): */ + memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad)); + testrand_flip(ell64b_bad, sizeof(ell64b_bad)); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); + CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */ + CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B (using a bad public key for A): */ + memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad)); + testrand_flip(ell64a_bad, sizeof(ell64a_bad)); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); + + /* Verify that the shared secret doesn't match if the private key is incorrect. */ + /* For A: */ + memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad)); + testrand_flip(sec32a_bad, sizeof(sec32a_bad)); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data); + CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B: */ + memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad)); + testrand_flip(sec32b_bad, sizeof(sec32b_bad)); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data); + CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); + + if (hash_function != ellswift_xdh_hash_x32) { + /* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */ + /* For A (changing B's public key): */ + memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad)); + testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad)); + ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad); + CHECK(ret); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B (changing A's public key): */ + memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad)); + testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad)); + ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad); + CHECK(ret); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); + + /* Verify that swapping sides changes the shared secret. */ + /* For A (claiming to be B): */ + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B (claiming to be A): */ + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); + } + } + + /* Test hash initializers. */ + { + secp256k1_sha256 sha, sha_optimized; + static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'}; + static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'}; + static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'}; + + /* Check that hash initialized by + * secp256k1_ellswift_sha256_init_encode has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag)); + secp256k1_ellswift_sha256_init_encode(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * secp256k1_ellswift_sha256_init_create has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag)); + secp256k1_ellswift_sha256_init_create(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * secp256k1_ellswift_sha256_init_bip324 has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag)); + secp256k1_ellswift_sha256_init_bip324(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + } +} + +#endif diff --git a/external/secp256k1/src/modules/extrakeys/Makefile.am.include b/external/secp256k1/src/modules/extrakeys/Makefile.am.include new file mode 100644 index 00000000000..0d901ec1f44 --- /dev/null +++ b/external/secp256k1/src/modules/extrakeys/Makefile.am.include @@ -0,0 +1,4 @@ +include_HEADERS += include/secp256k1_extrakeys.h +noinst_HEADERS += src/modules/extrakeys/tests_impl.h +noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h +noinst_HEADERS += src/modules/extrakeys/main_impl.h diff --git a/external/secp256k1/src/modules/extrakeys/main_impl.h b/external/secp256k1/src/modules/extrakeys/main_impl.h new file mode 100644 index 00000000000..0c7e266777c --- /dev/null +++ b/external/secp256k1/src/modules/extrakeys/main_impl.h @@ -0,0 +1,285 @@ +/*********************************************************************** + * Copyright (c) 2020 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_EXTRAKEYS_MAIN_H +#define SECP256K1_MODULE_EXTRAKEYS_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../util.h" + +static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) { + return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey); +} + +static SECP256K1_INLINE void secp256k1_xonly_pubkey_save(secp256k1_xonly_pubkey *pubkey, secp256k1_ge *ge) { + secp256k1_pubkey_save((secp256k1_pubkey *) pubkey, ge); +} + +int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) { + secp256k1_ge pk; + secp256k1_fe x; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input32 != NULL); + + if (!secp256k1_fe_set_b32_limit(&x, input32)) { + return 0; + } + if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) { + return 0; + } + if (!secp256k1_ge_is_in_correct_subgroup(&pk)) { + return 0; + } + secp256k1_xonly_pubkey_save(pubkey, &pk); + return 1; +} + +int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) { + secp256k1_ge pk; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output32 != NULL); + memset(output32, 0, 32); + ARG_CHECK(pubkey != NULL); + + if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + secp256k1_fe_get_b32(output32, &pk.x); + return 1; +} + +int secp256k1_xonly_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_xonly_pubkey* pk0, const secp256k1_xonly_pubkey* pk1) { + unsigned char out[2][32]; + const secp256k1_xonly_pubkey* pk[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + pk[0] = pk0; pk[1] = pk1; + for (i = 0; i < 2; i++) { + /* If the public key is NULL or invalid, xonly_pubkey_serialize will + * call the illegal_callback and return 0. In that case we will + * serialize the key as all zeros which is less than any valid public + * key. This results in consistent comparisons even if NULL or invalid + * pubkeys are involved and prevents edge cases such as sorting + * algorithms that use this function and do not terminate as a + * result. */ + if (!secp256k1_xonly_pubkey_serialize(ctx, out[i], pk[i])) { + /* Note that xonly_pubkey_serialize should already set the output to + * zero in that case, but it's not guaranteed by the API, we can't + * test it and writing a VERIFY_CHECK is more complex than + * explicitly memsetting (again). */ + memset(out[i], 0, sizeof(out[i])); + } + } + return secp256k1_memcmp_var(out[0], out[1], sizeof(out[1])); +} + +/** Keeps a group element as is if it has an even Y and otherwise negates it. + * y_parity is set to 0 in the former case and to 1 in the latter case. + * Requires that the coordinates of r are normalized. */ +static int secp256k1_extrakeys_ge_even_y(secp256k1_ge *r) { + int y_parity = 0; + VERIFY_CHECK(!secp256k1_ge_is_infinity(r)); + + if (secp256k1_fe_is_odd(&r->y)) { + secp256k1_fe_negate(&r->y, &r->y, 1); + y_parity = 1; + } + return y_parity; +} + +int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey) { + secp256k1_ge pk; + int tmp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(xonly_pubkey != NULL); + ARG_CHECK(pubkey != NULL); + + if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + tmp = secp256k1_extrakeys_ge_even_y(&pk); + if (pk_parity != NULL) { + *pk_parity = tmp; + } + secp256k1_xonly_pubkey_save(xonly_pubkey, &pk); + return 1; +} + +int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + secp256k1_ge pk; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output_pubkey != NULL); + memset(output_pubkey, 0, sizeof(*output_pubkey)); + ARG_CHECK(internal_pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey) + || !secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32)) { + return 0; + } + secp256k1_pubkey_save(output_pubkey, &pk); + return 1; +} + +int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + secp256k1_ge pk; + unsigned char pk_expected32[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(internal_pubkey != NULL); + ARG_CHECK(tweaked_pubkey32 != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey) + || !secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32)) { + return 0; + } + secp256k1_fe_normalize_var(&pk.x); + secp256k1_fe_normalize_var(&pk.y); + secp256k1_fe_get_b32(pk_expected32, &pk.x); + + return secp256k1_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0 + && secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity; +} + +static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) { + secp256k1_scalar_get_b32(&keypair->data[0], sk); + secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk); +} + + +static int secp256k1_keypair_seckey_load(const secp256k1_context* ctx, secp256k1_scalar *sk, const secp256k1_keypair *keypair) { + int ret; + + ret = secp256k1_scalar_set_b32_seckey(sk, &keypair->data[0]); + /* We can declassify ret here because sk is only zero if a keypair function + * failed (which zeroes the keypair) and its return value is ignored. */ + secp256k1_declassify(ctx, &ret, sizeof(ret)); + ARG_CHECK(ret); + return ret; +} + +/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk + * and ARG_CHECKs that the keypair is not invalid. It always initializes sk and + * pk with dummy values. */ +static int secp256k1_keypair_load(const secp256k1_context* ctx, secp256k1_scalar *sk, secp256k1_ge *pk, const secp256k1_keypair *keypair) { + int ret; + const secp256k1_pubkey *pubkey = (const secp256k1_pubkey *)&keypair->data[32]; + + /* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's + * invalid. */ + secp256k1_declassify(ctx, pubkey, sizeof(*pubkey)); + ret = secp256k1_pubkey_load(ctx, pk, pubkey); + if (sk != NULL) { + ret = ret && secp256k1_keypair_seckey_load(ctx, sk, keypair); + } + if (!ret) { + *pk = secp256k1_ge_const_g; + if (sk != NULL) { + *sk = secp256k1_scalar_one; + } + } + return ret; +} + +int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey32) { + secp256k1_scalar sk; + secp256k1_ge pk; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(keypair != NULL); + memset(keypair, 0, sizeof(*keypair)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey32 != NULL); + + ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32); + secp256k1_keypair_save(keypair, &sk, &pk); + secp256k1_memczero(keypair, sizeof(*keypair), !ret); + + secp256k1_scalar_clear(&sk); + return ret; +} + +int secp256k1_keypair_sec(const secp256k1_context* ctx, unsigned char *seckey, const secp256k1_keypair *keypair) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + memset(seckey, 0, 32); + ARG_CHECK(keypair != NULL); + + memcpy(seckey, &keypair->data[0], 32); + return 1; +} + +int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(keypair != NULL); + + memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey)); + return 1; +} + +int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) { + secp256k1_ge pk; + int tmp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(keypair != NULL); + + if (!secp256k1_keypair_load(ctx, NULL, &pk, keypair)) { + return 0; + } + tmp = secp256k1_extrakeys_ge_even_y(&pk); + if (pk_parity != NULL) { + *pk_parity = tmp; + } + secp256k1_xonly_pubkey_save(pubkey, &pk); + + return 1; +} + +int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) { + secp256k1_ge pk; + secp256k1_scalar sk; + int y_parity; + int ret; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(keypair != NULL); + ARG_CHECK(tweak32 != NULL); + + ret = secp256k1_keypair_load(ctx, &sk, &pk, keypair); + memset(keypair, 0, sizeof(*keypair)); + + y_parity = secp256k1_extrakeys_ge_even_y(&pk); + if (y_parity == 1) { + secp256k1_scalar_negate(&sk, &sk); + } + + ret &= secp256k1_ec_seckey_tweak_add_helper(&sk, tweak32); + ret &= secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32); + + secp256k1_declassify(ctx, &ret, sizeof(ret)); + if (ret) { + secp256k1_keypair_save(keypair, &sk, &pk); + } + + secp256k1_scalar_clear(&sk); + return ret; +} + +#endif diff --git a/external/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/external/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h new file mode 100644 index 00000000000..645bae2d470 --- /dev/null +++ b/external/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h @@ -0,0 +1,68 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_extrakeys.h" +#include "main_impl.h" + +static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) { + secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; + secp256k1_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + int parities[EXHAUSTIVE_TEST_ORDER - 1]; + unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; + int i; + + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_fe fe; + secp256k1_scalar scalar_i; + unsigned char buf[33]; + int parity; + + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_scalar_get_b32(buf, &scalar_i); + + /* Construct pubkey and keypair. */ + CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey[i - 1], buf)); + + /* Construct serialized xonly_pubkey from keypair. */ + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); + + /* Parse the xonly_pubkey back and verify it matches the previously serialized value. */ + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); + CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); + + /* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */ + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1])); + CHECK(parity == parities[i - 1]); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); + CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); + + /* Compare the xonly_pubkey bytes against the precomputed group. */ + secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]); + CHECK(secp256k1_fe_equal(&fe, &group[i].x)); + + /* Check the parity against the precomputed group. */ + fe = group[i].y; + secp256k1_fe_normalize_var(&fe); + CHECK(secp256k1_fe_is_odd(&fe) == parities[i - 1]); + + /* Verify that the higher half is identical to the lower half mirrored. */ + if (i > EXHAUSTIVE_TEST_ORDER / 2) { + CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0); + CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]); + } + } + + /* TODO: keypair/xonly_pubkey tweak tests */ +} + +#endif diff --git a/external/secp256k1/src/modules/extrakeys/tests_impl.h b/external/secp256k1/src/modules/extrakeys/tests_impl.h new file mode 100644 index 00000000000..ab4ef4a74b5 --- /dev/null +++ b/external/secp256k1/src/modules/extrakeys/tests_impl.h @@ -0,0 +1,483 @@ +/*********************************************************************** + * Copyright (c) 2020 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_H +#define SECP256K1_MODULE_EXTRAKEYS_TESTS_H + +#include "../../../include/secp256k1_extrakeys.h" + +static void test_xonly_pubkey(void) { + secp256k1_pubkey pk; + secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; + secp256k1_ge pk1; + secp256k1_ge pk2; + secp256k1_fe y; + unsigned char sk[32]; + unsigned char xy_sk[32]; + unsigned char buf32[32]; + unsigned char ones32[32]; + unsigned char zeros64[64] = { 0 }; + int pk_parity; + int i; + + testrand256(sk); + memset(ones32, 0xFF, 32); + testrand256(xy_sk); + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + + /* Test xonly_pubkey_from_pubkey */ + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk)); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL)); + memset(&pk, 0, sizeof(pk)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk)); + + /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */ + memset(sk, 0, sizeof(sk)); + sk[0] = 1; + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0); + CHECK(pk_parity == 0); + + /* Choose a secret key such that pubkey and xonly_pubkey are each others + * negation. */ + sk[0] = 2; + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0); + CHECK(pk_parity == 1); + secp256k1_pubkey_load(CTX, &pk1, &pk); + secp256k1_pubkey_load(CTX, &pk2, (secp256k1_pubkey *) &xonly_pk); + CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1); + secp256k1_fe_negate(&y, &pk2.y, 1); + CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); + + /* Test xonly_pubkey_serialize and xonly_pubkey_parse */ + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL)); + CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0); + { + /* A pubkey filled with 0s will fail to serialize due to pubkey_load + * special casing. */ + secp256k1_xonly_pubkey pk_tmp; + memset(&pk_tmp, 0, sizeof(pk_tmp)); + /* pubkey_load calls illegal callback */ + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp)); + } + + CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, NULL, buf32)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL)); + + /* Serialization and parse roundtrip */ + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk_tmp, buf32) == 1); + CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); + + /* Test parsing invalid field elements */ + memset(&xonly_pk, 1, sizeof(xonly_pk)); + /* Overflowing field element */ + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, ones32) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + memset(&xonly_pk, 1, sizeof(xonly_pk)); + /* There's no point with x-coordinate 0 on secp256k1 */ + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, zeros64) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + /* If a random 32-byte string can not be parsed with ec_pubkey_parse + * (because interpreted as X coordinate it does not correspond to a point on + * the curve) then xonly_pubkey_parse should fail as well. */ + for (i = 0; i < COUNT; i++) { + unsigned char rand33[33]; + testrand256(&rand33[1]); + rand33[0] = SECP256K1_TAG_PUBKEY_EVEN; + if (!secp256k1_ec_pubkey_parse(CTX, &pk, rand33, 33)) { + memset(&xonly_pk, 1, sizeof(xonly_pk)); + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + } else { + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1); + } + } +} + +static void test_xonly_pubkey_comparison(void) { + unsigned char pk1_ser[32] = { + 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, + 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 + }; + const unsigned char pk2_ser[32] = { + 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, + 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c + }; + secp256k1_xonly_pubkey pk1; + secp256k1_xonly_pubkey pk2; + + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1); + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1); + + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0)); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0)); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0); + memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0)); + { + int32_t ecount = 0; + secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(ecount == 2); + secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + } + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0)); +} + +static void test_xonly_pubkey_tweak(void) { + unsigned char zeros64[64] = { 0 }; + unsigned char overflows[32]; + unsigned char sk[32]; + secp256k1_pubkey internal_pk; + secp256k1_xonly_pubkey internal_xonly_pk; + secp256k1_pubkey output_pk; + int pk_parity; + unsigned char tweak[32]; + int i; + + memset(overflows, 0xff, sizeof(overflows)); + testrand256(tweak); + testrand256(sk); + CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); + + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak)); + /* NULL internal_xonly_pk zeroes the output_pk */ + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL)); + /* NULL tweak zeroes the output_pk */ + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + + /* Invalid tweak zeroes the output_pk */ + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + + /* A zero tweak is fine */ + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, zeros64) == 1); + + /* Fails if the resulting key was infinity */ + for (i = 0; i < COUNT; i++) { + secp256k1_scalar scalar_tweak; + /* Because sk may be negated before adding, we need to try with tweak = + * sk as well as tweak = -sk. */ + secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); + secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); + secp256k1_scalar_get_b32(tweak, &scalar_tweak); + CHECK((secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, sk) == 0) + || (secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0)); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + } + + /* Invalid pk with a valid tweak */ + memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); + testrand256(tweak); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak)); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); +} + +static void test_xonly_pubkey_tweak_check(void) { + unsigned char zeros64[64] = { 0 }; + unsigned char overflows[32]; + unsigned char sk[32]; + secp256k1_pubkey internal_pk; + secp256k1_xonly_pubkey internal_xonly_pk; + secp256k1_pubkey output_pk; + secp256k1_xonly_pubkey output_xonly_pk; + unsigned char output_pk32[32]; + unsigned char buf32[32]; + int pk_parity; + unsigned char tweak[32]; + + memset(overflows, 0xff, sizeof(overflows)); + testrand256(tweak); + testrand256(sk); + CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); + + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak)); + /* invalid pk_parity value */ + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL)); + + memset(tweak, 1, sizeof(tweak)); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk32, &output_xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1); + + /* Wrong pk_parity */ + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0); + /* Wrong public key */ + CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &internal_xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 0); + + /* Overflowing tweak not allowed */ + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); +} + +/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 + * additional pubkeys by calling tweak_add. Then verifies every tweak starting + * from the last pubkey. */ +#define N_PUBKEYS 32 +static void test_xonly_pubkey_tweak_recursive(void) { + unsigned char sk[32]; + secp256k1_pubkey pk[N_PUBKEYS]; + unsigned char pk_serialized[32]; + unsigned char tweak[N_PUBKEYS - 1][32]; + int i; + + testrand256(sk); + CHECK(secp256k1_ec_pubkey_create(CTX, &pk[0], sk) == 1); + /* Add tweaks */ + for (i = 0; i < N_PUBKEYS - 1; i++) { + secp256k1_xonly_pubkey xonly_pk; + memset(tweak[i], i + 1, sizeof(tweak[i])); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i]) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &pk[i + 1], &xonly_pk, tweak[i]) == 1); + } + + /* Verify tweaks */ + for (i = N_PUBKEYS - 1; i > 0; i--) { + secp256k1_xonly_pubkey xonly_pk; + int pk_parity; + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk[i]) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk_serialized, &xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i - 1]) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1); + } +} +#undef N_PUBKEYS + +static void test_keypair(void) { + unsigned char sk[32]; + unsigned char sk_tmp[32]; + unsigned char zeros96[96] = { 0 }; + unsigned char overflows[32]; + secp256k1_keypair keypair; + secp256k1_pubkey pk, pk_tmp; + secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; + int pk_parity, pk_parity_tmp; + + CHECK(sizeof(zeros96) == sizeof(keypair)); + memset(overflows, 0xFF, sizeof(overflows)); + + /* Test keypair_create */ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); + CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, NULL, sk)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, &keypair, NULL)); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_keypair_create(STATIC_CTX, &keypair, sk)); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + + /* Invalid secret key */ + CHECK(secp256k1_keypair_create(CTX, &keypair, zeros96) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(secp256k1_keypair_create(CTX, &keypair, overflows) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + + /* Test keypair_pub */ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, NULL, &keypair)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, &pk, NULL)); + CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); + + /* Using an invalid keypair is fine for keypair_pub */ + memset(&keypair, 0, sizeof(keypair)); + CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1); + CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); + + /* keypair holds the same pubkey as pubkey_create */ + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_pub(CTX, &pk_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); + + /** Test keypair_xonly_pub **/ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair)); + CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL)); + CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); + /* Using an invalid keypair will set the xonly_pk to 0 (first reset + * xonly_pk). */ + CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); + memset(&keypair, 0, sizeof(keypair)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair)); + CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); + + /** keypair holds the same xonly pubkey as pubkey_create **/ + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); + CHECK(pk_parity == pk_parity_tmp); + + /* Test keypair_seckey */ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, NULL, &keypair)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, sk_tmp, NULL)); + CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); + + /* keypair returns the same seckey it got */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0); + + + /* Using an invalid keypair is fine for keypair_seckey */ + memset(&keypair, 0, sizeof(keypair)); + CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); +} + +static void test_keypair_add(void) { + unsigned char sk[32]; + secp256k1_keypair keypair; + unsigned char overflows[32]; + unsigned char zeros96[96] = { 0 }; + unsigned char tweak[32]; + int i; + + CHECK(sizeof(zeros96) == sizeof(keypair)); + testrand256(sk); + testrand256(tweak); + memset(overflows, 0xFF, 32); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL)); + /* This does not set the keypair to zeroes */ + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0); + + /* Invalid tweak zeroes the keypair */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, overflows) == 0); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); + + /* A zero tweak is fine */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, zeros96) == 1); + + /* Fails if the resulting keypair was (sk=0, pk=infinity) */ + for (i = 0; i < COUNT; i++) { + secp256k1_scalar scalar_tweak; + secp256k1_keypair keypair_tmp; + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + memcpy(&keypair_tmp, &keypair, sizeof(keypair)); + /* Because sk may be negated before adding, we need to try with tweak = + * sk as well as tweak = -sk. */ + secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); + secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); + secp256k1_scalar_get_b32(tweak, &scalar_tweak); + CHECK((secp256k1_keypair_xonly_tweak_add(CTX, &keypair, sk) == 0) + || (secp256k1_keypair_xonly_tweak_add(CTX, &keypair_tmp, tweak) == 0)); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0 + || secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); + } + + /* Invalid keypair with a valid tweak */ + memset(&keypair, 0, sizeof(keypair)); + testrand256(tweak); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); + /* Only seckey part of keypair invalid */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + memset(&keypair, 0, 32); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); + /* Only pubkey part of keypair invalid */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + memset(&keypair.data[32], 0, 64); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); + + /* Check that the keypair_tweak_add implementation is correct */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + for (i = 0; i < COUNT; i++) { + secp256k1_xonly_pubkey internal_pk; + secp256k1_xonly_pubkey output_pk; + secp256k1_pubkey output_pk_xy; + secp256k1_pubkey output_pk_expected; + unsigned char pk32[32]; + unsigned char sk32[32]; + int pk_parity; + + testrand256(tweak); + CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1); + + /* Check that it passes xonly_pubkey_tweak_add_check */ + CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk32, &output_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk32, pk_parity, &internal_pk, tweak) == 1); + + /* Check that the resulting pubkey matches xonly_pubkey_tweak_add */ + CHECK(secp256k1_keypair_pub(CTX, &output_pk_xy, &keypair) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk_expected, &internal_pk, tweak) == 1); + CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); + + /* Check that the secret key in the keypair is tweaked correctly */ + CHECK(secp256k1_keypair_sec(CTX, sk32, &keypair) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &output_pk_expected, sk32) == 1); + CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); + } +} + +static void run_extrakeys_tests(void) { + /* xonly key test cases */ + test_xonly_pubkey(); + test_xonly_pubkey_tweak(); + test_xonly_pubkey_tweak_check(); + test_xonly_pubkey_tweak_recursive(); + test_xonly_pubkey_comparison(); + + /* keypair tests */ + test_keypair(); + test_keypair_add(); +} + +#endif diff --git a/external/secp256k1/src/modules/musig/Makefile.am.include b/external/secp256k1/src/modules/musig/Makefile.am.include new file mode 100644 index 00000000000..796443c93b3 --- /dev/null +++ b/external/secp256k1/src/modules/musig/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_musig.h +noinst_HEADERS += src/modules/musig/main_impl.h +noinst_HEADERS += src/modules/musig/keyagg.h +noinst_HEADERS += src/modules/musig/keyagg_impl.h +noinst_HEADERS += src/modules/musig/session.h +noinst_HEADERS += src/modules/musig/session_impl.h +noinst_HEADERS += src/modules/musig/tests_impl.h +noinst_HEADERS += src/modules/musig/vectors.h diff --git a/external/secp256k1/src/modules/musig/keyagg.h b/external/secp256k1/src/modules/musig/keyagg.h new file mode 100644 index 00000000000..a0b37252f8a --- /dev/null +++ b/external/secp256k1/src/modules/musig/keyagg.h @@ -0,0 +1,32 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_H +#define SECP256K1_MODULE_MUSIG_KEYAGG_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_musig.h" + +#include "../../group.h" +#include "../../scalar.h" + +typedef struct { + secp256k1_ge pk; + /* If there is no "second" public key, second_pk is set to the point at + * infinity */ + secp256k1_ge second_pk; + unsigned char pks_hash[32]; + /* tweak is identical to value tacc[v] in the specification. */ + secp256k1_scalar tweak; + /* parity_acc corresponds to (1 - gacc[v])/2 in the spec. So if gacc[v] is + * -1, parity_acc is 1. Otherwise, parity_acc is 0. */ + int parity_acc; +} secp256k1_keyagg_cache_internal; + +static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache); + +static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk); + +#endif diff --git a/external/secp256k1/src/modules/musig/keyagg_impl.h b/external/secp256k1/src/modules/musig/keyagg_impl.h new file mode 100644 index 00000000000..0db4fce8596 --- /dev/null +++ b/external/secp256k1/src/modules/musig/keyagg_impl.h @@ -0,0 +1,291 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H +#define SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H + +#include + +#include "keyagg.h" +#include "../../eckey.h" +#include "../../ecmult.h" +#include "../../field.h" +#include "../../group.h" +#include "../../hash.h" +#include "../../util.h" + +static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf }; + +/* A keyagg cache consists of + * - 4 byte magic set during initialization to allow detecting an uninitialized + * object. + * - 64 byte aggregate (and potentially tweaked) public key + * - 64 byte "second" public key (set to the point at infinity if not present) + * - 32 byte hash of all public keys + * - 1 byte the parity of the internal key (if tweaked, otherwise 0) + * - 32 byte tweak + */ +/* Requires that cache_i->pk is not infinity. */ +static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, const secp256k1_keyagg_cache_internal *cache_i) { + unsigned char *ptr = cache->data; + memcpy(ptr, secp256k1_musig_keyagg_cache_magic, 4); + ptr += 4; + secp256k1_ge_to_bytes(ptr, &cache_i->pk); + ptr += 64; + secp256k1_ge_to_bytes_ext(ptr, &cache_i->second_pk); + ptr += 64; + memcpy(ptr, cache_i->pks_hash, 32); + ptr += 32; + *ptr = cache_i->parity_acc; + ptr += 1; + secp256k1_scalar_get_b32(ptr, &cache_i->tweak); +} + +static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache) { + const unsigned char *ptr = cache->data; + ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_keyagg_cache_magic, 4) == 0); + ptr += 4; + secp256k1_ge_from_bytes(&cache_i->pk, ptr); + ptr += 64; + secp256k1_ge_from_bytes_ext(&cache_i->second_pk, ptr); + ptr += 64; + memcpy(cache_i->pks_hash, ptr, 32); + ptr += 32; + cache_i->parity_acc = *ptr & 1; + ptr += 1; + secp256k1_scalar_set_b32(&cache_i->tweak, ptr, NULL); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */ +static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + + sha->s[0] = 0xb399d5e0ul; + sha->s[1] = 0xc8fff302ul; + sha->s[2] = 0x6badac71ul; + sha->s[3] = 0x07c5b7f1ul; + sha->s[4] = 0x9701e2eful; + sha->s[5] = 0x2a72ecf8ul; + sha->s[6] = 0x201a4c7bul; + sha->s[7] = 0xab148a38ul; + sha->bytes = 64; +} + +/* Computes pks_hash = tagged_hash(pk[0], ..., pk[np-1]) */ +static int secp256k1_musig_compute_pks_hash(const secp256k1_context *ctx, unsigned char *pks_hash, const secp256k1_pubkey * const* pks, size_t np) { + secp256k1_sha256 sha; + size_t i; + + secp256k1_musig_keyagglist_sha256(&sha); + for (i = 0; i < np; i++) { + unsigned char ser[33]; + size_t ser_len = sizeof(ser); + if (!secp256k1_ec_pubkey_serialize(ctx, ser, &ser_len, pks[i], SECP256K1_EC_COMPRESSED)) { + return 0; + } + VERIFY_CHECK(ser_len == sizeof(ser)); + secp256k1_sha256_write(&sha, ser, sizeof(ser)); + } + secp256k1_sha256_finalize(&sha, pks_hash); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */ +static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + + sha->s[0] = 0x6ef02c5aul; + sha->s[1] = 0x06a480deul; + sha->s[2] = 0x1f298665ul; + sha->s[3] = 0x1d1134f2ul; + sha->s[4] = 0x56a0b063ul; + sha->s[5] = 0x52da4147ul; + sha->s[6] = 0xf280d9d4ul; + sha->s[7] = 0x4484be15ul; + sha->bytes = 64; +} + +/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and + * otherwise tagged_hash(pks_hash, pk) where pks_hash is the hash of public keys. + * second_pk is the point at infinity in case there is no second_pk. Assumes + * that pk is not the point at infinity and that the Y-coordinates of pk and + * second_pk are normalized. */ +static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pks_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) { + VERIFY_CHECK(!secp256k1_ge_is_infinity(pk)); + + if (!secp256k1_ge_is_infinity(second_pk) + && secp256k1_ge_eq_var(pk, second_pk)) { + secp256k1_scalar_set_int(r, 1); + } else { + secp256k1_sha256 sha; + unsigned char buf[33]; + size_t buflen = sizeof(buf); + int ret; + secp256k1_musig_keyaggcoef_sha256(&sha); + secp256k1_sha256_write(&sha, pks_hash, 32); + ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1); +#ifdef VERIFY + /* Serialization does not fail since the pk is not the point at infinity + * (according to this function's precondition). */ + VERIFY_CHECK(ret && buflen == sizeof(buf)); +#else + (void) ret; +#endif + secp256k1_sha256_write(&sha, buf, sizeof(buf)); + secp256k1_sha256_finalize(&sha, buf); + secp256k1_scalar_set_b32(r, buf, NULL); + } +} + +/* Assumes that pk is not the point at infinity and that the Y-coordinates of pk + * and cache_i->second_pk are normalized. */ +static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) { + secp256k1_musig_keyaggcoef_internal(r, cache_i->pks_hash, pk, &cache_i->second_pk); +} + +typedef struct { + const secp256k1_context *ctx; + /* pks_hash is the hash of the public keys */ + unsigned char pks_hash[32]; + const secp256k1_pubkey * const* pks; + secp256k1_ge second_pk; +} secp256k1_musig_pubkey_agg_ecmult_data; + +/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */ +static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { + secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data; + int ret; + ret = secp256k1_pubkey_load(ctx->ctx, pt, ctx->pks[idx]); +#ifdef VERIFY + /* pubkey_load can't fail because the same pks have already been loaded in + * `musig_compute_pks_hash` (and we test this). */ + VERIFY_CHECK(ret); +#else + (void) ret; +#endif + secp256k1_musig_keyaggcoef_internal(sc, ctx->pks_hash, pt, &ctx->second_pk); + return 1; +} + +int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey * const* pubkeys, size_t n_pubkeys) { + secp256k1_musig_pubkey_agg_ecmult_data ecmult_data; + secp256k1_gej pkj; + secp256k1_ge pkp; + size_t i; + + VERIFY_CHECK(ctx != NULL); + if (agg_pk != NULL) { + memset(agg_pk, 0, sizeof(*agg_pk)); + } + ARG_CHECK(pubkeys != NULL); + ARG_CHECK(n_pubkeys > 0); + + ecmult_data.ctx = ctx; + ecmult_data.pks = pubkeys; + + secp256k1_ge_set_infinity(&ecmult_data.second_pk); + for (i = 1; i < n_pubkeys; i++) { + if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) { + secp256k1_ge pk; + if (!secp256k1_pubkey_load(ctx, &pk, pubkeys[i])) { + return 0; + } + ecmult_data.second_pk = pk; + break; + } + } + + if (!secp256k1_musig_compute_pks_hash(ctx, ecmult_data.pks_hash, pubkeys, n_pubkeys)) { + return 0; + } + /* TODO: actually use optimized ecmult_multi algorithms by providing a + * scratch space */ + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) { + /* In order to reach this line with the current implementation of + * ecmult_multi_var one would need to provide a callback that can + * fail. */ + return 0; + } + secp256k1_ge_set_gej(&pkp, &pkj); + secp256k1_fe_normalize_var(&pkp.y); + /* The resulting public key is infinity with negligible probability */ + VERIFY_CHECK(!secp256k1_ge_is_infinity(&pkp)); + if (keyagg_cache != NULL) { + secp256k1_keyagg_cache_internal cache_i = { 0 }; + cache_i.pk = pkp; + cache_i.second_pk = ecmult_data.second_pk; + memcpy(cache_i.pks_hash, ecmult_data.pks_hash, sizeof(cache_i.pks_hash)); + secp256k1_keyagg_cache_save(keyagg_cache, &cache_i); + } + + if (agg_pk != NULL) { + secp256k1_extrakeys_ge_even_y(&pkp); + secp256k1_xonly_pubkey_save(agg_pk, &pkp); + } + return 1; +} + +int secp256k1_musig_pubkey_get(const secp256k1_context* ctx, secp256k1_pubkey *agg_pk, const secp256k1_musig_keyagg_cache *keyagg_cache) { + secp256k1_keyagg_cache_internal cache_i; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(agg_pk != NULL); + memset(agg_pk, 0, sizeof(*agg_pk)); + ARG_CHECK(keyagg_cache != NULL); + + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + secp256k1_pubkey_save(agg_pk, &cache_i.pk); + return 1; +} + +static int secp256k1_musig_pubkey_tweak_add_internal(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32, int xonly) { + secp256k1_keyagg_cache_internal cache_i; + int overflow = 0; + secp256k1_scalar tweak; + + VERIFY_CHECK(ctx != NULL); + if (output_pubkey != NULL) { + memset(output_pubkey, 0, sizeof(*output_pubkey)); + } + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + secp256k1_scalar_set_b32(&tweak, tweak32, &overflow); + if (overflow) { + return 0; + } + if (xonly && secp256k1_extrakeys_ge_even_y(&cache_i.pk)) { + cache_i.parity_acc ^= 1; + secp256k1_scalar_negate(&cache_i.tweak, &cache_i.tweak); + } + secp256k1_scalar_add(&cache_i.tweak, &cache_i.tweak, &tweak); + if (!secp256k1_eckey_pubkey_tweak_add(&cache_i.pk, &tweak)) { + return 0; + } + /* eckey_pubkey_tweak_add fails if cache_i.pk is infinity */ + VERIFY_CHECK(!secp256k1_ge_is_infinity(&cache_i.pk)); + secp256k1_keyagg_cache_save(keyagg_cache, &cache_i); + if (output_pubkey != NULL) { + secp256k1_pubkey_save(output_pubkey, &cache_i.pk); + } + return 1; +} + +int secp256k1_musig_pubkey_ec_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { + return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 0); +} + +int secp256k1_musig_pubkey_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { + return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 1); +} + +#endif diff --git a/external/secp256k1/src/modules/musig/main_impl.h b/external/secp256k1/src/modules/musig/main_impl.h new file mode 100644 index 00000000000..a1311e41912 --- /dev/null +++ b/external/secp256k1/src/modules/musig/main_impl.h @@ -0,0 +1,12 @@ +/********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_MAIN_H +#define SECP256K1_MODULE_MUSIG_MAIN_H + +#include "keyagg_impl.h" +#include "session_impl.h" + +#endif diff --git a/external/secp256k1/src/modules/musig/session.h b/external/secp256k1/src/modules/musig/session.h new file mode 100644 index 00000000000..d6d76bc6c11 --- /dev/null +++ b/external/secp256k1/src/modules/musig/session.h @@ -0,0 +1,24 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_SESSION_H +#define SECP256K1_MODULE_MUSIG_SESSION_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_musig.h" + +#include "../../scalar.h" + +typedef struct { + int fin_nonce_parity; + unsigned char fin_nonce[32]; + secp256k1_scalar noncecoef; + secp256k1_scalar challenge; + secp256k1_scalar s_part; +} secp256k1_musig_session_internal; + +static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session); + +#endif diff --git a/external/secp256k1/src/modules/musig/session_impl.h b/external/secp256k1/src/modules/musig/session_impl.h new file mode 100644 index 00000000000..dde38085827 --- /dev/null +++ b/external/secp256k1/src/modules/musig/session_impl.h @@ -0,0 +1,816 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_SESSION_IMPL_H +#define SECP256K1_MODULE_MUSIG_SESSION_IMPL_H + +#include + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../../include/secp256k1_musig.h" + +#include "keyagg.h" +#include "session.h" +#include "../../eckey.h" +#include "../../hash.h" +#include "../../scalar.h" +#include "../../util.h" + +/* Outputs 33 zero bytes if the given group element is the point at infinity and + * otherwise outputs the compressed serialization */ +static void secp256k1_musig_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) { + if (secp256k1_ge_is_infinity(ge)) { + memset(out33, 0, 33); + } else { + int ret; + size_t size = 33; + ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1); +#ifdef VERIFY + /* Serialize must succeed because the point is not at infinity */ + VERIFY_CHECK(ret && size == 33); +#else + (void) ret; +#endif + } +} + +/* Outputs the point at infinity if the given byte array is all zero, otherwise + * attempts to parse compressed point serialization. */ +static int secp256k1_musig_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) { + unsigned char zeros[33] = { 0 }; + + if (secp256k1_memcmp_var(in33, zeros, sizeof(zeros)) == 0) { + secp256k1_ge_set_infinity(ge); + return 1; + } + if (!secp256k1_eckey_pubkey_parse(ge, in33, 33)) { + return 0; + } + return secp256k1_ge_is_in_correct_subgroup(ge); +} + +static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 }; + +static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, const secp256k1_scalar *k, const secp256k1_ge *pk) { + memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4); + secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]); + secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]); + secp256k1_ge_to_bytes(&secnonce->data[68], pk); +} + +static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_ge *pk, const secp256k1_musig_secnonce *secnonce) { + int is_zero; + ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0); + /* We make very sure that the nonce isn't invalidated by checking the values + * in addition to the magic. */ + is_zero = secp256k1_is_zero_array(&secnonce->data[4], 2 * 32); + secp256k1_declassify(ctx, &is_zero, sizeof(is_zero)); + ARG_CHECK(!is_zero); + + secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL); + secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL); + secp256k1_ge_from_bytes(pk, &secnonce->data[68]); + return 1; +} + +/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */ +static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) { + secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag); + /* The flag argument is usually classified. So, the line above makes the + * magic and public key classified. However, we need both to be + * declassified. Note that we don't declassify the entire object, because if + * flag is 0, then k[0] and k[1] have not been zeroed. */ + secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic)); + secp256k1_declassify(ctx, &secnonce->data[68], 64); +} + +static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 }; + +/* Saves two group elements into a pubnonce. Requires that none of the provided + * group elements is infinity. */ +static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, const secp256k1_ge* ges) { + int i; + memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4); + for (i = 0; i < 2; i++) { + secp256k1_ge_to_bytes(nonce->data + 4+64*i, &ges[i]); + } +} + +/* Loads two group elements from a pubnonce. Returns 1 unless the nonce wasn't + * properly initialized */ +static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_pubnonce* nonce) { + int i; + + ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4) == 0); + for (i = 0; i < 2; i++) { + secp256k1_ge_from_bytes(&ges[i], nonce->data + 4 + 64*i); + } + return 1; +} + +static const unsigned char secp256k1_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 }; + +static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, const secp256k1_ge* ges) { + int i; + memcpy(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4); + for (i = 0; i < 2; i++) { + secp256k1_ge_to_bytes_ext(&nonce->data[4 + 64*i], &ges[i]); + } +} + +static int secp256k1_musig_aggnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_aggnonce* nonce) { + int i; + + ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4) == 0); + for (i = 0; i < 2; i++) { + secp256k1_ge_from_bytes_ext(&ges[i], &nonce->data[4 + 64*i]); + } + return 1; +} + +static const unsigned char secp256k1_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 }; + +/* A session consists of + * - 4 byte session cache magic + * - 1 byte the parity of the final nonce + * - 32 byte serialized x-only final nonce + * - 32 byte nonce coefficient b + * - 32 byte signature challenge hash e + * - 32 byte scalar s that is added to the partial signatures of the signers + */ +static void secp256k1_musig_session_save(secp256k1_musig_session *session, const secp256k1_musig_session_internal *session_i) { + unsigned char *ptr = session->data; + + memcpy(ptr, secp256k1_musig_session_cache_magic, 4); + ptr += 4; + *ptr = session_i->fin_nonce_parity; + ptr += 1; + memcpy(ptr, session_i->fin_nonce, 32); + ptr += 32; + secp256k1_scalar_get_b32(ptr, &session_i->noncecoef); + ptr += 32; + secp256k1_scalar_get_b32(ptr, &session_i->challenge); + ptr += 32; + secp256k1_scalar_get_b32(ptr, &session_i->s_part); +} + +static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session) { + const unsigned char *ptr = session->data; + + ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_session_cache_magic, 4) == 0); + ptr += 4; + session_i->fin_nonce_parity = *ptr; + ptr += 1; + memcpy(session_i->fin_nonce, ptr, 32); + ptr += 32; + secp256k1_scalar_set_b32(&session_i->noncecoef, ptr, NULL); + ptr += 32; + secp256k1_scalar_set_b32(&session_i->challenge, ptr, NULL); + ptr += 32; + secp256k1_scalar_set_b32(&session_i->s_part, ptr, NULL); + return 1; +} + +static const unsigned char secp256k1_musig_partial_sig_magic[4] = { 0xeb, 0xfb, 0x1a, 0x32 }; + +static void secp256k1_musig_partial_sig_save(secp256k1_musig_partial_sig* sig, secp256k1_scalar *s) { + memcpy(&sig->data[0], secp256k1_musig_partial_sig_magic, 4); + secp256k1_scalar_get_b32(&sig->data[4], s); +} + +static int secp256k1_musig_partial_sig_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_musig_partial_sig* sig) { + int overflow; + + ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0); + secp256k1_scalar_set_b32(s, &sig->data[4], &overflow); + /* Parsed signatures can not overflow */ + VERIFY_CHECK(!overflow); + return 1; +} + +int secp256k1_musig_pubnonce_parse(const secp256k1_context* ctx, secp256k1_musig_pubnonce* nonce, const unsigned char *in66) { + secp256k1_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(in66 != NULL); + + for (i = 0; i < 2; i++) { + if (!secp256k1_eckey_pubkey_parse(&ges[i], &in66[33*i], 33)) { + return 0; + } + if (!secp256k1_ge_is_in_correct_subgroup(&ges[i])) { + return 0; + } + } + secp256k1_musig_pubnonce_save(nonce, ges); + return 1; +} + +int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_pubnonce* nonce) { + secp256k1_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out66 != NULL); + memset(out66, 0, 66); + ARG_CHECK(nonce != NULL); + + if (!secp256k1_musig_pubnonce_load(ctx, ges, nonce)) { + return 0; + } + for (i = 0; i < 2; i++) { + int ret; + size_t size = 33; + ret = secp256k1_eckey_pubkey_serialize(&ges[i], &out66[33*i], &size, 1); +#ifdef VERIFY + /* serialize must succeed because the point was just loaded */ + VERIFY_CHECK(ret && size == 33); +#else + (void) ret; +#endif + } + return 1; +} + +int secp256k1_musig_aggnonce_parse(const secp256k1_context* ctx, secp256k1_musig_aggnonce* nonce, const unsigned char *in66) { + secp256k1_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(in66 != NULL); + + for (i = 0; i < 2; i++) { + if (!secp256k1_musig_ge_parse_ext(&ges[i], &in66[33*i])) { + return 0; + } + } + secp256k1_musig_aggnonce_save(nonce, ges); + return 1; +} + +int secp256k1_musig_aggnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_aggnonce* nonce) { + secp256k1_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out66 != NULL); + memset(out66, 0, 66); + ARG_CHECK(nonce != NULL); + + if (!secp256k1_musig_aggnonce_load(ctx, ges, nonce)) { + return 0; + } + for (i = 0; i < 2; i++) { + secp256k1_musig_ge_serialize_ext(&out66[33*i], &ges[i]); + } + return 1; +} + +int secp256k1_musig_partial_sig_parse(const secp256k1_context* ctx, secp256k1_musig_partial_sig* sig, const unsigned char *in32) { + secp256k1_scalar tmp; + int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(in32 != NULL); + + /* Ensure that using the signature will fail if parsing fails (and the user + * doesn't check the return value). */ + memset(sig, 0, sizeof(*sig)); + + secp256k1_scalar_set_b32(&tmp, in32, &overflow); + if (overflow) { + return 0; + } + secp256k1_musig_partial_sig_save(sig, &tmp); + return 1; +} + +int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_sig* sig) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0); + + memcpy(out32, &sig->data[4], 32); + return 1; +} + +/* Write optional inputs into the hash */ +static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) { + unsigned char zero[7] = { 0 }; + /* The spec requires length prefixes to be between 1 and 8 bytes + * (inclusive) */ + VERIFY_CHECK(prefix_size >= 1 && prefix_size <= 8); + /* Since the length of all input data fits in a byte, we can always pad the + * length prefix with prefix_size - 1 zero bytes. */ + secp256k1_sha256_write(sha, zero, prefix_size - 1); + if (data != NULL) { + secp256k1_sha256_write(sha, &len, 1); + secp256k1_sha256_write(sha, data, len); + } else { + len = 0; + secp256k1_sha256_write(sha, &len, 1); + } +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig/aux")||SHA256("MuSig/aux"). */ +static void secp256k1_nonce_function_musig_sha256_tagged_aux(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0xa19e884bul; + sha->s[1] = 0xf463fe7eul; + sha->s[2] = 0x2f18f9a2ul; + sha->s[3] = 0xbeb0f9fful; + sha->s[4] = 0x0f37e8b0ul; + sha->s[5] = 0x06ebd26ful; + sha->s[6] = 0xe3b243d2ul; + sha->s[7] = 0x522fb150ul; + sha->bytes = 64; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig/nonce")||SHA256("MuSig/nonce"). */ +static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x07101b64ul; + sha->s[1] = 0x18003414ul; + sha->s[2] = 0x0391bc43ul; + sha->s[3] = 0x0e6258eeul; + sha->s[4] = 0x29d26b72ul; + sha->s[5] = 0x8343937eul; + sha->s[6] = 0xb7a0a4fbul; + sha->s[7] = 0xff568a30ul; + sha->bytes = 64; +} + +static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { + secp256k1_sha256 sha; + unsigned char rand[32]; + unsigned char i; + unsigned char msg_present; + + if (seckey32 != NULL) { + secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); + secp256k1_sha256_write(&sha, session_secrand, 32); + secp256k1_sha256_finalize(&sha, rand); + for (i = 0; i < 32; i++) { + rand[i] ^= seckey32[i]; + } + } else { + memcpy(rand, session_secrand, sizeof(rand)); + } + + secp256k1_nonce_function_musig_sha256_tagged(&sha); + secp256k1_sha256_write(&sha, rand, sizeof(rand)); + secp256k1_nonce_function_musig_helper(&sha, 1, pk33, 33); + secp256k1_nonce_function_musig_helper(&sha, 1, agg_pk32, 32); + msg_present = msg32 != NULL; + secp256k1_sha256_write(&sha, &msg_present, 1); + if (msg_present) { + secp256k1_nonce_function_musig_helper(&sha, 8, msg32, 32); + } + secp256k1_nonce_function_musig_helper(&sha, 4, extra_input32, 32); + + for (i = 0; i < 2; i++) { + unsigned char buf[32]; + secp256k1_sha256 sha_tmp = sha; + secp256k1_sha256_write(&sha_tmp, &i, 1); + secp256k1_sha256_finalize(&sha_tmp, buf); + secp256k1_scalar_set_b32(&k[i], buf, NULL); + + /* Attempt to erase secret data */ + secp256k1_memclear(buf, sizeof(buf)); + secp256k1_sha256_clear(&sha_tmp); + } + secp256k1_memclear(rand, sizeof(rand)); + secp256k1_sha256_clear(&sha); +} + +static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *input_nonce, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + secp256k1_scalar k[2]; + secp256k1_ge nonce_pts[2]; + int i; + unsigned char pk_ser[33]; + size_t pk_ser_len = sizeof(pk_ser); + unsigned char aggpk_ser[32]; + unsigned char *aggpk_ser_ptr = NULL; + secp256k1_ge pk; + int pk_serialize_success; + int ret = 1; + + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + + /* Check that the seckey is valid to be able to sign for it later. */ + if (seckey != NULL) { + secp256k1_scalar sk; + ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey); + secp256k1_scalar_clear(&sk); + } + + if (keyagg_cache != NULL) { + secp256k1_keyagg_cache_internal cache_i; + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + /* The loaded point cache_i.pk can not be the point at infinity. */ + secp256k1_fe_get_b32(aggpk_ser, &cache_i.pk.x); + aggpk_ser_ptr = aggpk_ser; + } + if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, 1); + +#ifdef VERIFY + /* A pubkey cannot be the point at infinity */ + VERIFY_CHECK(pk_serialize_success); + VERIFY_CHECK(pk_ser_len == sizeof(pk_ser)); +#else + (void) pk_serialize_success; +#endif + + secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); + VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0])); + VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1])); + secp256k1_musig_secnonce_save(secnonce, k, &pk); + secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret); + + for (i = 0; i < 2; i++) { + secp256k1_gej nonce_ptj; + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]); + secp256k1_ge_set_gej(&nonce_pts[i], &nonce_ptj); + secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i])); + secp256k1_scalar_clear(&k[i]); + secp256k1_gej_clear(&nonce_ptj); + } + /* None of the nonce_pts will be infinity because k != 0 with overwhelming + * probability */ + secp256k1_musig_pubnonce_save(pubnonce, nonce_pts); + return ret; +} + +int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, unsigned char *session_secrand32, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + int ret = 1; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secnonce != NULL); + memset(secnonce, 0, sizeof(*secnonce)); + ARG_CHECK(session_secrand32 != NULL); + + /* Check in constant time that the session_secrand32 is not 0 as a + * defense-in-depth measure that may protect against a faulty RNG. */ + ret &= !secp256k1_is_zero_array(session_secrand32, 32); + + /* We can declassify because branching on ret is only relevant when this + * function called with an invalid session_secrand32 argument */ + secp256k1_declassify(ctx, &ret, sizeof(ret)); + if (ret == 0) { + secp256k1_musig_secnonce_invalidate(ctx, secnonce, 1); + return 0; + } + + ret &= secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, session_secrand32, seckey, pubkey, msg32, keyagg_cache, extra_input32); + + /* Set the session_secrand32 buffer to zero to prevent the caller from using + * nonce_gen multiple times with the same buffer. */ + secp256k1_memczero(session_secrand32, 32, ret); + return ret; +} + +int secp256k1_musig_nonce_gen_counter(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, uint64_t nonrepeating_cnt, const secp256k1_keypair *keypair, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + unsigned char buf[32] = { 0 }; + unsigned char seckey[32]; + secp256k1_pubkey pubkey; + int ret; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secnonce != NULL); + memset(secnonce, 0, sizeof(*secnonce)); + ARG_CHECK(keypair != NULL); + + secp256k1_write_be64(buf, nonrepeating_cnt); + /* keypair_sec and keypair_pub do not fail if the arguments are not NULL */ + ret = secp256k1_keypair_sec(ctx, seckey, keypair); + VERIFY_CHECK(ret); + ret = secp256k1_keypair_pub(ctx, &pubkey, keypair); + VERIFY_CHECK(ret); +#ifndef VERIFY + (void) ret; +#endif + + if (!secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, &pubkey, msg32, keyagg_cache, extra_input32)) { + return 0; + } + secp256k1_memclear(seckey, sizeof(seckey)); + return 1; +} + +static int secp256k1_musig_sum_pubnonces(const secp256k1_context* ctx, secp256k1_gej *summed_pubnonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { + size_t i; + int j; + + secp256k1_gej_set_infinity(&summed_pubnonces[0]); + secp256k1_gej_set_infinity(&summed_pubnonces[1]); + + for (i = 0; i < n_pubnonces; i++) { + secp256k1_ge nonce_pts[2]; + if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonces[i])) { + return 0; + } + for (j = 0; j < 2; j++) { + secp256k1_gej_add_ge_var(&summed_pubnonces[j], &summed_pubnonces[j], &nonce_pts[j], NULL); + } + } + return 1; +} + +int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { + secp256k1_gej aggnonce_ptsj[2]; + secp256k1_ge aggnonce_pts[2]; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(aggnonce != NULL); + ARG_CHECK(pubnonces != NULL); + ARG_CHECK(n_pubnonces > 0); + + if (!secp256k1_musig_sum_pubnonces(ctx, aggnonce_ptsj, pubnonces, n_pubnonces)) { + return 0; + } + secp256k1_ge_set_all_gej_var(aggnonce_pts, aggnonce_ptsj, 2); + secp256k1_musig_aggnonce_save(aggnonce, aggnonce_pts); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig/noncecoef")||SHA256("MuSig/noncecoef"). */ +static void secp256k1_musig_compute_noncehash_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x2c7d5a45ul; + sha->s[1] = 0x06bf7e53ul; + sha->s[2] = 0x89be68a6ul; + sha->s[3] = 0x971254c0ul; + sha->s[4] = 0x60ac12d2ul; + sha->s[5] = 0x72846dcdul; + sha->s[6] = 0x6c81212ful; + sha->s[7] = 0xde7a2500ul; + sha->bytes = 64; +} + +/* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */ +static void secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { + unsigned char buf[33]; + secp256k1_sha256 sha; + int i; + + secp256k1_musig_compute_noncehash_sha256_tagged(&sha); + for (i = 0; i < 2; i++) { + secp256k1_musig_ge_serialize_ext(buf, &aggnonce[i]); + secp256k1_sha256_write(&sha, buf, sizeof(buf)); + } + secp256k1_sha256_write(&sha, agg_pk32, 32); + secp256k1_sha256_write(&sha, msg, 32); + secp256k1_sha256_finalize(&sha, noncehash); +} + +/* out_nonce = nonce_pts[0] + b*nonce_pts[1] */ +static void secp256k1_effective_nonce(secp256k1_gej *out_nonce, const secp256k1_ge *nonce_pts, const secp256k1_scalar *b) { + secp256k1_gej tmp; + + secp256k1_gej_set_ge(&tmp, &nonce_pts[1]); + secp256k1_ecmult(out_nonce, &tmp, b, NULL); + secp256k1_gej_add_ge_var(out_nonce, out_nonce, &nonce_pts[0], NULL); +} + +static void secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) { + unsigned char noncehash[32]; + secp256k1_ge fin_nonce_pt; + secp256k1_gej fin_nonce_ptj; + + secp256k1_musig_compute_noncehash(noncehash, aggnonce_pts, agg_pk32, msg); + secp256k1_scalar_set_b32(b, noncehash, NULL); + /* fin_nonce = aggnonce_pts[0] + b*aggnonce_pts[1] */ + secp256k1_effective_nonce(&fin_nonce_ptj, aggnonce_pts, b); + secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj); + if (secp256k1_ge_is_infinity(&fin_nonce_pt)) { + fin_nonce_pt = secp256k1_ge_const_g; + } + /* fin_nonce_pt is not the point at infinity */ + secp256k1_fe_normalize_var(&fin_nonce_pt.x); + secp256k1_fe_get_b32(fin_nonce, &fin_nonce_pt.x); + secp256k1_fe_normalize_var(&fin_nonce_pt.y); + *fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y); +} + +int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_aggnonce *aggnonce, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache) { + secp256k1_keyagg_cache_internal cache_i; + secp256k1_ge aggnonce_pts[2]; + unsigned char fin_nonce[32]; + secp256k1_musig_session_internal session_i; + unsigned char agg_pk32[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(aggnonce != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(keyagg_cache != NULL); + + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + secp256k1_fe_get_b32(agg_pk32, &cache_i.pk.x); + + if (!secp256k1_musig_aggnonce_load(ctx, aggnonce_pts, aggnonce)) { + return 0; + } + + secp256k1_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32); + secp256k1_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32); + + /* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/ + secp256k1_scalar_set_int(&session_i.s_part, 0); + if (!secp256k1_scalar_is_zero(&cache_i.tweak)) { + secp256k1_scalar e_tmp; + secp256k1_scalar_mul(&e_tmp, &session_i.challenge, &cache_i.tweak); + if (secp256k1_fe_is_odd(&cache_i.pk.y)) { + secp256k1_scalar_negate(&e_tmp, &e_tmp); + } + session_i.s_part = e_tmp; + } + memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce)); + secp256k1_musig_session_save(session, &session_i); + return 1; +} + +static void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) { + secp256k1_scalar_clear(sk); + secp256k1_scalar_clear(&k[0]); + secp256k1_scalar_clear(&k[1]); +} + +int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_partial_sig *partial_sig, secp256k1_musig_secnonce *secnonce, const secp256k1_keypair *keypair, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) { + secp256k1_scalar sk; + secp256k1_ge pk, keypair_pk; + secp256k1_scalar k[2]; + secp256k1_scalar mu, s; + secp256k1_keyagg_cache_internal cache_i; + secp256k1_musig_session_internal session_i; + int ret; + + VERIFY_CHECK(ctx != NULL); + + ARG_CHECK(secnonce != NULL); + /* Fails if the magic doesn't match */ + ret = secp256k1_musig_secnonce_load(ctx, k, &pk, secnonce); + /* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls + * of this function to fail */ + memset(secnonce, 0, sizeof(*secnonce)); + if (!ret) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(keypair != NULL); + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(session != NULL); + + if (!secp256k1_keypair_load(ctx, &sk, &keypair_pk, keypair)) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + ARG_CHECK(secp256k1_fe_equal(&pk.x, &keypair_pk.x) + && secp256k1_fe_equal(&pk.y, &keypair_pk.y)); + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + + /* Negate sk if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. + * This corresponds to the line "Let d = g⋅gacc⋅d' mod n" in the + * specification. */ + if ((secp256k1_fe_is_odd(&cache_i.pk.y) + != cache_i.parity_acc)) { + secp256k1_scalar_negate(&sk, &sk); + } + + /* Multiply KeyAgg coefficient */ + secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk); + secp256k1_scalar_mul(&sk, &sk, &mu); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + + if (session_i.fin_nonce_parity) { + secp256k1_scalar_negate(&k[0], &k[0]); + secp256k1_scalar_negate(&k[1], &k[1]); + } + + /* Sign */ + secp256k1_scalar_mul(&s, &session_i.challenge, &sk); + secp256k1_scalar_mul(&k[1], &session_i.noncecoef, &k[1]); + secp256k1_scalar_add(&k[0], &k[0], &k[1]); + secp256k1_scalar_add(&s, &s, &k[0]); + secp256k1_musig_partial_sig_save(partial_sig, &s); + secp256k1_musig_partial_sign_clear(&sk, k); + return 1; +} + +int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) { + secp256k1_keyagg_cache_internal cache_i; + secp256k1_musig_session_internal session_i; + secp256k1_scalar mu, e, s; + secp256k1_gej pkj; + secp256k1_ge nonce_pts[2]; + secp256k1_gej rj; + secp256k1_gej tmp; + secp256k1_ge pkp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(pubnonce != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(session != NULL); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + return 0; + } + + if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonce)) { + return 0; + } + /* Compute "effective" nonce rj = nonce_pts[0] + b*nonce_pts[1] */ + /* TODO: use multiexp to compute -s*G + e*mu*pubkey + nonce_pts[0] + b*nonce_pts[1] */ + secp256k1_effective_nonce(&rj, nonce_pts, &session_i.noncecoef); + + if (!secp256k1_pubkey_load(ctx, &pkp, pubkey)) { + return 0; + } + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + /* Multiplying the challenge by the KeyAgg coefficient is equivalent + * to multiplying the signer's public key by the coefficient, except + * much easier to do. */ + secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp); + secp256k1_scalar_mul(&e, &session_i.challenge, &mu); + + /* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. + * This corresponds to the line "Let g' = g⋅gacc mod n" and the multiplication "g'⋅e" + * in the specification. */ + if (secp256k1_fe_is_odd(&cache_i.pk.y) + != cache_i.parity_acc) { + secp256k1_scalar_negate(&e, &e); + } + + if (!secp256k1_musig_partial_sig_load(ctx, &s, partial_sig)) { + return 0; + } + /* Compute -s*G + e*pkj + rj (e already includes the keyagg coefficient mu) */ + secp256k1_scalar_negate(&s, &s); + secp256k1_gej_set_ge(&pkj, &pkp); + secp256k1_ecmult(&tmp, &pkj, &e, &s); + if (session_i.fin_nonce_parity) { + secp256k1_gej_neg(&rj, &rj); + } + secp256k1_gej_add_var(&tmp, &tmp, &rj, NULL); + + return secp256k1_gej_is_infinity(&tmp); +} + +int secp256k1_musig_partial_sig_agg(const secp256k1_context* ctx, unsigned char *sig64, const secp256k1_musig_session *session, const secp256k1_musig_partial_sig * const* partial_sigs, size_t n_sigs) { + size_t i; + secp256k1_musig_session_internal session_i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(partial_sigs != NULL); + ARG_CHECK(n_sigs > 0); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + return 0; + } + for (i = 0; i < n_sigs; i++) { + secp256k1_scalar term; + if (!secp256k1_musig_partial_sig_load(ctx, &term, partial_sigs[i])) { + return 0; + } + secp256k1_scalar_add(&session_i.s_part, &session_i.s_part, &term); + } + secp256k1_scalar_get_b32(&sig64[32], &session_i.s_part); + memcpy(&sig64[0], session_i.fin_nonce, 32); + return 1; +} + +#endif diff --git a/external/secp256k1/src/modules/musig/tests_impl.h b/external/secp256k1/src/modules/musig/tests_impl.h new file mode 100644 index 00000000000..ce6ae1784d1 --- /dev/null +++ b/external/secp256k1/src/modules/musig/tests_impl.h @@ -0,0 +1,1143 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_TESTS_IMPL_H +#define SECP256K1_MODULE_MUSIG_TESTS_IMPL_H + +#include +#include + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../../include/secp256k1_musig.h" + +#include "session.h" +#include "keyagg.h" +#include "../../scalar.h" +#include "../../field.h" +#include "../../group.h" +#include "../../hash.h" +#include "../../util.h" + +#include "vectors.h" + +static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_pubkey *pk, const unsigned char *sk) { + int ret; + secp256k1_keypair keypair_tmp; + ret = secp256k1_keypair_create(CTX, &keypair_tmp, sk); + ret &= secp256k1_keypair_pub(CTX, pk, &keypair_tmp); + if (keypair != NULL) { + *keypair = keypair_tmp; + } + return ret; +} + +/* Just a simple (non-tweaked) 2-of-2 MuSig aggregate, sign, verify + * test. */ +static void musig_simple_test(void) { + unsigned char sk[2][32]; + secp256k1_keypair keypair[2]; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + secp256k1_musig_aggnonce aggnonce; + unsigned char msg[32]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_keyagg_cache keyagg_cache; + unsigned char session_secrand[2][32]; + secp256k1_musig_secnonce secnonce[2]; + secp256k1_pubkey pk[2]; + const secp256k1_pubkey *pk_ptr[2]; + secp256k1_musig_partial_sig partial_sig[2]; + const secp256k1_musig_partial_sig *partial_sig_ptr[2]; + unsigned char final_sig[64]; + secp256k1_musig_session session; + int i; + + testrand256(msg); + for (i = 0; i < 2; i++) { + testrand256(sk[i]); + pk_ptr[i] = &pk[i]; + pubnonce_ptr[i] = &pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + + CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); + if (i == 0) { + testrand256(session_secrand[i]); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[i], &pubnonce[i], session_secrand[i], sk[i], &pk[i], NULL, NULL, NULL) == 1); + } else { + uint64_t nonrepeating_cnt = 0; + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[i], &pubnonce[i], nonrepeating_cnt, &keypair[i], NULL, NULL, NULL) == 1); + } + } + + CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); + + for (i = 0; i < 2; i++) { + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[i], &secnonce[i], &keypair[i], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[i], &pubnonce[i], &pk[i], &keyagg_cache, &session) == 1); + } + + CHECK(secp256k1_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 2) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &agg_pk) == 1); +} + +/* Generate two pubnonces such that both group elements of their sum (calculated + * with secp256k1_musig_sum_pubnonces) are infinity. */ +static void pubnonce_summing_to_inf(secp256k1_musig_pubnonce *pubnonce) { + secp256k1_ge ge[2]; + int i; + secp256k1_gej summed_pubnonces[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + + testutil_random_ge_test(&ge[0]); + testutil_random_ge_test(&ge[1]); + + for (i = 0; i < 2; i++) { + secp256k1_musig_pubnonce_save(&pubnonce[i], ge); + pubnonce_ptr[i] = &pubnonce[i]; + secp256k1_ge_neg(&ge[0], &ge[0]); + secp256k1_ge_neg(&ge[1], &ge[1]); + } + + secp256k1_musig_sum_pubnonces(CTX, summed_pubnonces, pubnonce_ptr, 2); + CHECK(secp256k1_gej_is_infinity(&summed_pubnonces[0])); + CHECK(secp256k1_gej_is_infinity(&summed_pubnonces[1])); +} + +int memcmp_and_randomize(unsigned char *value, const unsigned char *expected, size_t len) { + int ret; + size_t i; + ret = secp256k1_memcmp_var(value, expected, len); + for (i = 0; i < len; i++) { + value[i] = testrand_bits(8); + } + return ret; +} + +static void musig_api_tests(void) { + secp256k1_musig_partial_sig partial_sig[2]; + const secp256k1_musig_partial_sig *partial_sig_ptr[2]; + secp256k1_musig_partial_sig invalid_partial_sig; + const secp256k1_musig_partial_sig *invalid_partial_sig_ptr[2]; + unsigned char pre_sig[64]; + unsigned char buf[32]; + unsigned char sk[2][32]; + secp256k1_keypair keypair[2]; + secp256k1_keypair invalid_keypair; + unsigned char max64[64]; + unsigned char zeros132[132] = { 0 }; + unsigned char session_secrand[2][32]; + unsigned char nonrepeating_cnt = 0; + secp256k1_musig_secnonce secnonce[2]; + secp256k1_musig_secnonce secnonce_tmp; + secp256k1_musig_secnonce invalid_secnonce; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + unsigned char pubnonce_ser[66]; + secp256k1_musig_pubnonce inf_pubnonce[2]; + const secp256k1_musig_pubnonce *inf_pubnonce_ptr[2]; + secp256k1_musig_pubnonce invalid_pubnonce; + const secp256k1_musig_pubnonce *invalid_pubnonce_ptr[1]; + secp256k1_musig_aggnonce aggnonce; + unsigned char aggnonce_ser[66]; + unsigned char msg[32]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_pubkey full_agg_pk; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_keyagg_cache invalid_keyagg_cache; + secp256k1_musig_session session; + secp256k1_musig_session invalid_session; + secp256k1_pubkey pk[2]; + const secp256k1_pubkey *pk_ptr[2]; + secp256k1_pubkey invalid_pk; + const secp256k1_pubkey *invalid_pk_ptr2[2]; + const secp256k1_pubkey *invalid_pk_ptr3[3]; + unsigned char tweak[32]; + int i; + + /** setup **/ + memset(max64, 0xff, sizeof(max64)); + memset(&invalid_keypair, 0, sizeof(invalid_keypair)); + memset(&invalid_pk, 0, sizeof(invalid_pk)); + memset(&invalid_secnonce, 0, sizeof(invalid_secnonce)); + memset(&invalid_partial_sig, 0, sizeof(invalid_partial_sig)); + pubnonce_summing_to_inf(inf_pubnonce); + /* Simulate structs being uninitialized by setting it to 0s. We don't want + * to produce undefined behavior by actually providing uninitialized + * structs. */ + memset(&invalid_keyagg_cache, 0, sizeof(invalid_keyagg_cache)); + memset(&invalid_pk, 0, sizeof(invalid_pk)); + memset(&invalid_pubnonce, 0, sizeof(invalid_pubnonce)); + memset(&invalid_session, 0, sizeof(invalid_session)); + + testrand256(msg); + testrand256(tweak); + for (i = 0; i < 2; i++) { + pk_ptr[i] = &pk[i]; + invalid_pk_ptr2[i] = &invalid_pk; + invalid_pk_ptr3[i] = &pk[i]; + pubnonce_ptr[i] = &pubnonce[i]; + inf_pubnonce_ptr[i] = &inf_pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + invalid_partial_sig_ptr[i] = &partial_sig[i]; + testrand256(session_secrand[i]); + testrand256(sk[i]); + CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); + } + invalid_pubnonce_ptr[0] = &invalid_pubnonce; + invalid_partial_sig_ptr[0] = &invalid_partial_sig; + /* invalid_pk_ptr3 has two valid, one invalid pk, which is important to test + * musig_pubkey_agg */ + invalid_pk_ptr3[2] = &invalid_pk; + + /** main test body **/ + + /** Key aggregation **/ + CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(CTX, NULL, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, NULL, pk_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 2)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr3, 3)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 0)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 0)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + + CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + + /* pubkey_get */ + CHECK(secp256k1_musig_pubkey_get(CTX, &full_agg_pk, &keyagg_cache) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_get(CTX, NULL, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_get(CTX, &full_agg_pk, NULL)); + CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros132, sizeof(full_agg_pk)) == 0); + + /** Tweaking **/ + { + int (*tweak_func[2]) (const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32); + tweak_func[0] = secp256k1_musig_pubkey_ec_tweak_add; + tweak_func[1] = secp256k1_musig_pubkey_xonly_tweak_add; + for (i = 0; i < 2; i++) { + secp256k1_pubkey tmp_output_pk; + secp256k1_musig_keyagg_cache tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + /* Reset keyagg_cache */ + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(CTX, NULL, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, NULL, tweak)); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, NULL)); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + /* Uninitialized keyagg_cache */ + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &invalid_keyagg_cache, tweak)); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + } + } + + /** Session creation with nonce_gen **/ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); + /* nonce_gen, if successful, sets session_secrand to the zero array, which + * makes subsequent nonce_gen calls with the same session_secrand fail. So + * check that session_secrand is indeed the zero array and fill it with + * random values again. */ + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, NULL, &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], NULL, session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + /* session_secrand = 0 is disallowed because it indicates a faulty RNG */ + memcpy(&session_secrand[0], zeros132, sizeof(session_secrand[0])); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros132, sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + /* invalid seckey */ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], NULL, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, NULL, max64) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + /* Every in-argument except session_secrand and pubkey can be NULL */ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk[1], &pk[1], NULL, NULL, NULL) == 1); + + /** Session creation with nonce_gen_counter **/ + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64) == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen_counter(STATIC_CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, NULL, &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], NULL, nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + /* using nonce_gen_counter requires keypair */ + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, NULL, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + /* invalid keypair */ + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &invalid_keypair, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], NULL, &keyagg_cache, max64) == 1); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, NULL, max64) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &invalid_keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt,&keypair[0], msg, &keyagg_cache, NULL) == 1); + + /* Every in-argument except nonrepeating_cnt and keypair can be NULL */ + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[1], &pubnonce[1], nonrepeating_cnt, &keypair[1], NULL, NULL, NULL) == 1); + + + /** Serialize and parse public nonces **/ + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, NULL, &pubnonce[0])); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, NULL)); + CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &invalid_pubnonce)); + CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); + CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1); + + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_parse(CTX, NULL, pubnonce_ser)); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], NULL)); + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], zeros132) == 0); + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); + + { + /* Check that serialize and parse results in the same value */ + secp256k1_musig_pubnonce tmp; + CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1); + CHECK(secp256k1_musig_pubnonce_parse(CTX, &tmp, pubnonce_ser) == 1); + CHECK(secp256k1_memcmp_var(&tmp, &pubnonce[0], sizeof(tmp)) == 0); + } + + /** Receive nonces and aggregate **/ + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, NULL, pubnonce_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, NULL, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 0)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, invalid_pubnonce_ptr, 1)); + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, inf_pubnonce_ptr, 2) == 1); + { + /* Check that the aggnonce encodes two points at infinity */ + secp256k1_ge aggnonce_pt[2]; + secp256k1_musig_aggnonce_load(CTX, aggnonce_pt, &aggnonce); + for (i = 0; i < 2; i++) { + secp256k1_ge_is_infinity(&aggnonce_pt[i]); + } + } + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + + /** Serialize and parse aggregate nonces **/ + CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, NULL, &aggnonce)); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, NULL)); + CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, (secp256k1_musig_aggnonce*) &invalid_pubnonce)); + CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); + CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); + + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_parse(CTX, NULL, aggnonce_ser)); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_parse(CTX, &aggnonce, NULL)); + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, zeros132) == 1); + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); + + { + /* Check that serialize and parse results in the same value */ + secp256k1_musig_aggnonce tmp; + CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); + CHECK(secp256k1_musig_aggnonce_parse(CTX, &tmp, aggnonce_ser) == 1); + CHECK(secp256k1_memcmp_var(&tmp, &aggnonce, sizeof(tmp)) == 0); + } + + /** Process nonces **/ + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, NULL, &aggnonce, msg, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, NULL, msg, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, (secp256k1_musig_aggnonce*) &invalid_pubnonce, msg, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, NULL, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &invalid_keyagg_cache)); + + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); + + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 1); + /* The secnonce is set to 0 and subsequent signing attempts fail */ + CHECK(secp256k1_memcmp_var(&secnonce_tmp, zeros132, sizeof(secnonce_tmp)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, NULL, &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], NULL, &keypair[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &invalid_secnonce, &keypair[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, NULL, &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &invalid_keypair, &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + { + unsigned char sk_tmp[32]; + secp256k1_keypair keypair_tmp; + testrand256(sk_tmp); + CHECK(secp256k1_keypair_create(CTX, &keypair_tmp, sk_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair_tmp, &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + } + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], NULL, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &invalid_keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, NULL)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &invalid_session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce[0], &keypair[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[1], &secnonce[1], &keypair[1], &keyagg_cache, &session) == 1); + + CHECK(secp256k1_musig_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, NULL, &partial_sig[0])); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, buf, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, buf, &invalid_partial_sig)); + CHECK(secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], buf) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_parse(CTX, NULL, buf)); + { + /* Check that parsing failure results in an invalid sig */ + secp256k1_musig_partial_sig tmp; + CHECK(secp256k1_musig_partial_sig_parse(CTX, &tmp, max64) == 0); + CHECK(secp256k1_memcmp_var(&tmp, zeros132, sizeof(partial_sig[0])) == 0); + } + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], NULL)); + + { + /* Check that serialize and parse results in the same value */ + secp256k1_musig_partial_sig tmp; + CHECK(secp256k1_musig_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1); + CHECK(secp256k1_musig_partial_sig_parse(CTX, &tmp, buf) == 1); + CHECK(secp256k1_memcmp_var(&tmp, &partial_sig[0], sizeof(tmp)) == 0); + } + + /** Partial signature verification */ + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, NULL, &pubnonce[0], &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &invalid_partial_sig, &pubnonce[0], &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], NULL, &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &invalid_pubnonce, &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], NULL, &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &invalid_pk, &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], NULL, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &invalid_keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &invalid_session)); + + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pk[1], &keyagg_cache, &session) == 1); + + /** Signature aggregation and verification */ + CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, NULL, &session, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, NULL, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &invalid_session, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, NULL, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, invalid_partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 0)); + CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 1) == 1); + CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); +} + +static void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { + secp256k1_scalar k1[2], k2[2]; + + secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4], args[5]); + testrand_flip(args[n_flip], n_bytes); + secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4], args[5]); + CHECK(secp256k1_scalar_eq(&k1[0], &k2[0]) == 0); + CHECK(secp256k1_scalar_eq(&k1[1], &k2[1]) == 0); +} + +static void musig_nonce_test(void) { + unsigned char *args[6]; + unsigned char session_secrand[32]; + unsigned char sk[32]; + unsigned char pk[33]; + unsigned char msg[32]; + unsigned char agg_pk[32]; + unsigned char extra_input[32]; + int i, j; + secp256k1_scalar k[6][2]; + + testrand_bytes_test(session_secrand, sizeof(session_secrand)); + testrand_bytes_test(sk, sizeof(sk)); + testrand_bytes_test(pk, sizeof(pk)); + testrand_bytes_test(msg, sizeof(msg)); + testrand_bytes_test(agg_pk, sizeof(agg_pk)); + testrand_bytes_test(extra_input, sizeof(extra_input)); + + /* Check that a bitflip in an argument results in different nonces. */ + args[0] = session_secrand; + args[1] = msg; + args[2] = sk; + args[3] = pk; + args[4] = agg_pk; + args[5] = extra_input; + for (i = 0; i < COUNT; i++) { + musig_nonce_bitflip(args, 0, sizeof(session_secrand)); + musig_nonce_bitflip(args, 1, sizeof(msg)); + musig_nonce_bitflip(args, 2, sizeof(sk)); + musig_nonce_bitflip(args, 3, sizeof(pk)); + musig_nonce_bitflip(args, 4, sizeof(agg_pk)); + musig_nonce_bitflip(args, 5, sizeof(extra_input)); + } + /* Check that if any argument is NULL, a different nonce is produced than if + * any other argument is NULL. */ + memcpy(msg, session_secrand, sizeof(msg)); + memcpy(sk, session_secrand, sizeof(sk)); + memcpy(pk, session_secrand, sizeof(session_secrand)); + memcpy(agg_pk, session_secrand, sizeof(agg_pk)); + memcpy(extra_input, session_secrand, sizeof(extra_input)); + secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]); + secp256k1_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4], args[5]); + secp256k1_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL, args[5]); + secp256k1_nonce_function_musig(k[5], args[0], args[1], args[2], args[3], args[4], NULL); + for (i = 0; i < 6; i++) { + CHECK(!secp256k1_scalar_eq(&k[i][0], &k[i][1])); + for (j = i+1; j < 6; j++) { + CHECK(!secp256k1_scalar_eq(&k[i][0], &k[j][0])); + CHECK(!secp256k1_scalar_eq(&k[i][1], &k[j][1])); + } + } +} + +static void sha256_tag_test_internal(secp256k1_sha256 *sha_tagged, unsigned char *tag, size_t taglen) { + secp256k1_sha256 sha; + secp256k1_sha256_initialize_tagged(&sha, tag, taglen); + test_sha256_eq(&sha, sha_tagged); +} + +/* Checks that the initialized tagged hashes have the expected + * state. */ +static void sha256_tag_test(void) { + secp256k1_sha256 sha; + { + char tag[] = "KeyAgg list"; + secp256k1_musig_keyagglist_sha256(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + char tag[] = "KeyAgg coefficient"; + secp256k1_musig_keyaggcoef_sha256(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + unsigned char tag[] = "MuSig/aux"; + secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + unsigned char tag[] = "MuSig/nonce"; + secp256k1_nonce_function_musig_sha256_tagged(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + unsigned char tag[] = "MuSig/noncecoef"; + secp256k1_musig_compute_noncehash_sha256_tagged(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } +} + +/* Attempts to create a signature for the aggregate public key using given secret + * keys and keyagg_cache. */ +static void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_keyagg_cache *keyagg_cache) { + secp256k1_pubkey pk[2]; + unsigned char session_secrand[2][32]; + unsigned char msg[32]; + secp256k1_musig_secnonce secnonce[2]; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + secp256k1_musig_aggnonce aggnonce; + secp256k1_keypair keypair[2]; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig[2]; + const secp256k1_musig_partial_sig *partial_sig_ptr[2]; + unsigned char final_sig[64]; + int i; + + for (i = 0; i < 2; i++) { + pubnonce_ptr[i] = &pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + + testrand256(session_secrand[i]); + } + CHECK(create_keypair_and_pk(&keypair[0], &pk[0], sk0) == 1); + CHECK(create_keypair_and_pk(&keypair[1], &pk[1], sk1) == 1); + testrand256(msg); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk0, &pk[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk1, &pk[1], NULL, NULL, NULL) == 1); + + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, keyagg_cache) == 1); + + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce[0], &keypair[0], keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[1], &secnonce[1], &keypair[1], keyagg_cache, &session) == 1); + + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pk[1], keyagg_cache, &session) == 1); + + CHECK(secp256k1_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 2) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), agg_pk) == 1); +} + +/* Create aggregate public key P[0], tweak multiple times (using xonly and + * plain tweaking) and test signing. */ +static void musig_tweak_test(void) { + unsigned char sk[2][32]; + secp256k1_pubkey pk[2]; + const secp256k1_pubkey *pk_ptr[2]; + secp256k1_musig_keyagg_cache keyagg_cache; + enum { N_TWEAKS = 8 }; + secp256k1_pubkey P[N_TWEAKS + 1]; + secp256k1_xonly_pubkey P_xonly[N_TWEAKS + 1]; + int i; + + /* Key Setup */ + for (i = 0; i < 2; i++) { + pk_ptr[i] = &pk[i]; + testrand256(sk[i]); + CHECK(create_keypair_and_pk(NULL, &pk[i], sk[i]) == 1); + } + /* Compute P0 = keyagg(pk0, pk1) and test signing for it */ + CHECK(secp256k1_musig_pubkey_agg(CTX, &P_xonly[0], &keyagg_cache, pk_ptr, 2) == 1); + musig_tweak_test_helper(&P_xonly[0], sk[0], sk[1], &keyagg_cache); + CHECK(secp256k1_musig_pubkey_get(CTX, &P[0], &keyagg_cache)); + + /* Compute Pi = f(Pj) + tweaki*G where where j = i-1 and try signing for + * that key. If xonly is set to true, the function f normalizes the input + * point to have an even X-coordinate ("xonly-tweaking"). + * Otherwise, the function f is the identity function. */ + for (i = 1; i <= N_TWEAKS; i++) { + unsigned char tweak[32]; + int P_parity; + int xonly = testrand_bits(1); + + testrand256(tweak); + if (xonly) { + CHECK(secp256k1_musig_pubkey_xonly_tweak_add(CTX, &P[i], &keyagg_cache, tweak) == 1); + } else { + CHECK(secp256k1_musig_pubkey_ec_tweak_add(CTX, &P[i], &keyagg_cache, tweak) == 1); + } + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &P_xonly[i], &P_parity, &P[i])); + /* Check that musig_pubkey_tweak_add produces same result as + * xonly_pubkey_tweak_add or ec_pubkey_tweak_add. */ + if (xonly) { + unsigned char P_serialized[32]; + CHECK(secp256k1_xonly_pubkey_serialize(CTX, P_serialized, &P_xonly[i])); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, P_serialized, P_parity, &P_xonly[i-1], tweak) == 1); + } else { + secp256k1_pubkey tmp_key = P[i-1]; + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &tmp_key, tweak)); + CHECK(secp256k1_memcmp_var(&tmp_key, &P[i], sizeof(tmp_key)) == 0); + } + /* Test signing for P[i] */ + musig_tweak_test_helper(&P_xonly[i], sk[0], sk[1], &keyagg_cache); + } +} + +int musig_vectors_keyagg_and_tweak(enum MUSIG_ERROR *error, + secp256k1_musig_keyagg_cache *keyagg_cache, + unsigned char *agg_pk_ser, + const unsigned char pubkeys33[][33], + const unsigned char tweaks32[][32], + size_t key_indices_len, + const size_t *key_indices, + size_t tweak_indices_len, + const size_t *tweak_indices, + const int *is_xonly) { + secp256k1_pubkey pubkeys[MUSIG_VECTORS_MAX_PUBKEYS]; + const secp256k1_pubkey *pk_ptr[MUSIG_VECTORS_MAX_PUBKEYS]; + int i; + secp256k1_pubkey agg_pk; + secp256k1_xonly_pubkey agg_pk_xonly; + + for (i = 0; i < (int)key_indices_len; i++) { + if (!secp256k1_ec_pubkey_parse(CTX, &pubkeys[i], pubkeys33[key_indices[i]], 33)) { + *error = MUSIG_PUBKEY; + return 0; + } + pk_ptr[i] = &pubkeys[i]; + } + if (!secp256k1_musig_pubkey_agg(CTX, NULL, keyagg_cache, pk_ptr, key_indices_len)) { + *error = MUSIG_OTHER; + return 0; + } + + for (i = 0; i < (int)tweak_indices_len; i++) { + if (is_xonly[i]) { + if (!secp256k1_musig_pubkey_xonly_tweak_add(CTX, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { + *error = MUSIG_TWEAK; + return 0; + } + } else { + if (!secp256k1_musig_pubkey_ec_tweak_add(CTX, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { + *error = MUSIG_TWEAK; + return 0; + } + } + } + if (!secp256k1_musig_pubkey_get(CTX, &agg_pk, keyagg_cache)) { + *error = MUSIG_OTHER; + return 0; + } + + if (!secp256k1_xonly_pubkey_from_pubkey(CTX, &agg_pk_xonly, NULL, &agg_pk)) { + *error = MUSIG_OTHER; + return 0; + } + + if (agg_pk_ser != NULL) { + if (!secp256k1_xonly_pubkey_serialize(CTX, agg_pk_ser, &agg_pk_xonly)) { + *error = MUSIG_OTHER; + return 0; + } + } + + return 1; +} + +static void musig_test_vectors_keyagg(void) { + size_t i; + const struct musig_key_agg_vector *vector = &musig_key_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_key_agg_valid_test_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + unsigned char agg_pk[32]; + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(secp256k1_memcmp_var(agg_pk, c->expected, sizeof(agg_pk)) == 0); + } + + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_key_agg_error_test_case *c = &vector->error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + + CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(c->error == error); + } +} + +static void musig_test_vectors_noncegen(void) { + size_t i; + const struct musig_nonce_gen_vector *vector = &musig_nonce_gen_vector; + + for (i = 0; i < sizeof(vector->test_case)/sizeof(vector->test_case[0]); i++) { + const struct musig_nonce_gen_test_case *c = &vector->test_case[i]; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_keyagg_cache *keyagg_cache_ptr = NULL; + unsigned char session_secrand32[32]; + secp256k1_musig_secnonce secnonce; + secp256k1_musig_pubnonce pubnonce; + const unsigned char *sk = NULL; + const unsigned char *msg = NULL; + const unsigned char *extra_in = NULL; + secp256k1_pubkey pk; + unsigned char pubnonce66[66]; + + memcpy(session_secrand32, c->rand_, 32); + if (c->has_sk) { + sk = c->sk; + } + if (c->has_aggpk) { + /* Create keyagg_cache from aggpk */ + secp256k1_keyagg_cache_internal cache_i; + secp256k1_xonly_pubkey aggpk; + memset(&cache_i, 0, sizeof(cache_i)); + CHECK(secp256k1_xonly_pubkey_parse(CTX, &aggpk, c->aggpk)); + CHECK(secp256k1_xonly_pubkey_load(CTX, &cache_i.pk, &aggpk)); + secp256k1_keyagg_cache_save(&keyagg_cache, &cache_i); + keyagg_cache_ptr = &keyagg_cache; + } + if (c->has_msg) { + msg = c->msg; + } + if (c->has_extra_in) { + extra_in = c->extra_in; + } + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk, c->pk, sizeof(c->pk))); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce, &pubnonce, session_secrand32, sk, &pk, msg, keyagg_cache_ptr, extra_in) == 1); + CHECK(secp256k1_memcmp_var(&secnonce.data[4], c->expected_secnonce, 2*32) == 0); + /* The last element of the secnonce is the public key (uncompressed in + * secp256k1_musig_secnonce, compressed in the test vector secnonce). */ + CHECK(secp256k1_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); + CHECK(secp256k1_memcmp_var(&c->expected_secnonce[2*32], c->pk, sizeof(c->pk)) == 0); + + CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce66, &pubnonce) == 1); + CHECK(sizeof(c->expected_pubnonce) == sizeof(pubnonce66)); + CHECK(secp256k1_memcmp_var(pubnonce66, c->expected_pubnonce, sizeof(pubnonce66)) == 0); + } +} + + +static void musig_test_vectors_nonceagg(void) { + size_t i; + int j; + const struct musig_nonce_agg_vector *vector = &musig_nonce_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_nonce_agg_test_case *c = &vector->valid_case[i]; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + secp256k1_musig_aggnonce aggnonce; + unsigned char aggnonce66[66]; + + for (j = 0; j < 2; j++) { + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]]) == 1); + pubnonce_ptr[j] = &pubnonce[j]; + } + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2)); + CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce66, &aggnonce)); + CHECK(secp256k1_memcmp_var(aggnonce66, c->expected, 33) == 0); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_nonce_agg_test_case *c = &vector->error_case[i]; + secp256k1_musig_pubnonce pubnonce[2]; + for (j = 0; j < 2; j++) { + int expected = c->invalid_nonce_idx != j; + CHECK(expected == secp256k1_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]])); + } + } +} + +static void musig_test_set_secnonce(secp256k1_musig_secnonce *secnonce, const unsigned char *secnonce64, const secp256k1_pubkey *pubkey) { + secp256k1_ge pk; + secp256k1_scalar k[2]; + + secp256k1_scalar_set_b32(&k[0], &secnonce64[0], NULL); + secp256k1_scalar_set_b32(&k[1], &secnonce64[32], NULL); + CHECK(secp256k1_pubkey_load(CTX, &pk, pubkey)); + secp256k1_musig_secnonce_save(secnonce, k, &pk); +} + +static void musig_test_vectors_signverify(void) { + size_t i; + const struct musig_sign_verify_vector *vector = &musig_sign_verify_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_valid_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_pubkey pubkey; + secp256k1_musig_pubnonce pubnonce; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + secp256k1_musig_secnonce secnonce; + secp256k1_keypair keypair; + unsigned char partial_sig32[32]; + + CHECK(secp256k1_keypair_create(CTX, &keypair, vector->sk)); + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonces[c->aggnonce_index])); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + musig_test_set_secnonce(&secnonce, vector->secnonces[0], &pubkey); + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + CHECK(secp256k1_musig_partial_sig_serialize(CTX, partial_sig32, &partial_sig)); + CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); + + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[0])); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->sign_error_case)/sizeof(vector->sign_error_case[0]); i++) { + const struct musig_sign_error_case *c = &vector->sign_error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_pubkey pubkey; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + secp256k1_musig_secnonce secnonce; + secp256k1_keypair keypair; + int expected; + + if (i == 0) { + /* Skip this vector since the implementation does not error out when + * the signing key does not belong to any pubkey. */ + continue; + } + expected = c->error != MUSIG_PUBKEY; + CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(expected || c->error == error); + if (!expected) { + continue; + } + + expected = c->error != MUSIG_AGGNONCE; + CHECK(expected == secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonces[c->aggnonce_index])); + if (!expected) { + continue; + } + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + musig_test_set_secnonce(&secnonce, vector->secnonces[c->secnonce_index], &pubkey); + expected = c->error != MUSIG_SECNONCE; + if (expected) { + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + } else { + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + } + } + for (i = 0; i < sizeof(vector->verify_fail_case)/sizeof(vector->verify_fail_case[0]); i++) { + const struct musig_verify_fail_error_case *c = &vector->verify_fail_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + enum { NUM_PUBNONCES = 3 }; + secp256k1_musig_pubnonce pubnonce[NUM_PUBNONCES]; + const secp256k1_musig_pubnonce *pubnonce_ptr[NUM_PUBNONCES]; + secp256k1_pubkey pubkey; + int expected; + size_t j; + + CHECK(NUM_PUBNONCES <= c->nonce_indices_len); + for (j = 0; j < c->nonce_indices_len; j++) { + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pubnonces[c->nonce_indices[j]])); + pubnonce_ptr[j] = &pubnonce[j]; + } + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, c->nonce_indices_len) == 1); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[c->signer_index], sizeof(vector->pubkeys[0]))); + + expected = c->error != MUSIG_SIG; + CHECK(expected == secp256k1_musig_partial_sig_parse(CTX, &partial_sig, c->sig)); + if (!expected) { + continue; + } + expected = c->error != MUSIG_SIG_VERIFY; + CHECK(expected == secp256k1_musig_partial_sig_verify(CTX, &partial_sig, pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->verify_error_case)/sizeof(vector->verify_error_case[0]); i++) { + const struct musig_verify_fail_error_case *c = &vector->verify_error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_pubnonce pubnonce; + int expected; + + expected = c->error != MUSIG_PUBKEY; + CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(expected || c->error == error); + if (!expected) { + continue; + } + expected = c->error != MUSIG_PUBNONCE; + CHECK(expected == secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); + } +} + +static void musig_test_vectors_tweak(void) { + size_t i; + const struct musig_tweak_vector *vector = &musig_tweak_vector; + secp256k1_pubkey pubkey; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_secnonce secnonce; + + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonce)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_tweak_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_pubnonce pubnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + secp256k1_keypair keypair; + unsigned char partial_sig32[32]; + + musig_test_set_secnonce(&secnonce, vector->secnonce, &pubkey); + + CHECK(secp256k1_keypair_create(CTX, &keypair, vector->sk)); + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msg, &keyagg_cache)); + + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + CHECK(secp256k1_musig_partial_sig_serialize(CTX, partial_sig32, &partial_sig)); + CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); + + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_tweak_case *c = &vector->error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(error == MUSIG_TWEAK); + } +} + +static void musig_test_vectors_sigagg(void) { + size_t i, j; + const struct musig_sig_agg_vector *vector = &musig_sig_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_sig_agg_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + unsigned char final_sig[64]; + secp256k1_musig_keyagg_cache keyagg_cache; + unsigned char agg_pk32[32]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + const secp256k1_musig_partial_sig *partial_sig_ptr[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk32, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, c->aggnonce)); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msg, &keyagg_cache)); + for (j = 0; j < c->psig_indices_len; j++) { + CHECK(secp256k1_musig_partial_sig_parse(CTX, &partial_sig[j], vector->psigs[c->psig_indices[j]])); + partial_sig_ptr[j] = &partial_sig[j]; + } + + CHECK(secp256k1_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, c->psig_indices_len) == 1); + CHECK(secp256k1_memcmp_var(final_sig, c->expected, sizeof(final_sig)) == 0); + + CHECK(secp256k1_xonly_pubkey_parse(CTX, &agg_pk, agg_pk32)); + CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, vector->msg, sizeof(vector->msg), &agg_pk) == 1); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_sig_agg_case *c = &vector->error_case[i]; + secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + for (j = 0; j < c->psig_indices_len; j++) { + int expected = c->invalid_sig_idx != (int)j; + CHECK(expected == secp256k1_musig_partial_sig_parse(CTX, &partial_sig[j], vector->psigs[c->psig_indices[j]])); + } + } +} + +/* Since the BIP doesn't provide static test vectors for nonce_gen_counter, we + * define a static test here */ +static void musig_test_static_nonce_gen_counter(void) { + secp256k1_musig_secnonce secnonce; + secp256k1_musig_pubnonce pubnonce; + unsigned char pubnonce66[66]; + secp256k1_pubkey pk; + secp256k1_keypair keypair; + uint64_t nonrepeating_cnt = 0; + unsigned char sk[32] = { + 0xEE, 0xC1, 0xCB, 0x7D, 0x1B, 0x72, 0x54, 0xC5, + 0xCA, 0xB0, 0xD9, 0xC6, 0x1A, 0xB0, 0x2E, 0x64, + 0x3D, 0x46, 0x4A, 0x59, 0xFE, 0x6C, 0x96, 0xA7, + 0xEF, 0xE8, 0x71, 0xF0, 0x7C, 0x5A, 0xEF, 0x54, + }; + unsigned char expected_secnonce[64] = { + 0x84, 0x2F, 0x13, 0x80, 0xCD, 0x17, 0xA1, 0x98, + 0xFC, 0x3D, 0xAD, 0x3B, 0x7D, 0xA7, 0x49, 0x29, + 0x41, 0xF4, 0x69, 0x76, 0xF2, 0x70, 0x2F, 0xF7, + 0xC6, 0x6F, 0x24, 0xF4, 0x72, 0x03, 0x6A, 0xF1, + 0xDA, 0x3F, 0x95, 0x2D, 0xDE, 0x4A, 0x2D, 0xA6, + 0xB6, 0x32, 0x57, 0x07, 0xCE, 0x87, 0xA4, 0xE3, + 0x61, 0x6D, 0x06, 0xFC, 0x5F, 0x81, 0xA9, 0xC9, + 0x93, 0x86, 0xD2, 0x0A, 0x99, 0xCE, 0xCF, 0x99, + }; + unsigned char expected_pubnonce[66] = { + 0x03, 0xA5, 0xB9, 0xB6, 0x90, 0x79, 0x42, 0xEA, + 0xCD, 0xDA, 0x49, 0xA3, 0x66, 0x01, 0x6E, 0xC2, + 0xE6, 0x24, 0x04, 0xA1, 0xBF, 0x4A, 0xB6, 0xD4, + 0xDB, 0x82, 0x06, 0x7B, 0xC3, 0xAD, 0xF0, 0x86, + 0xD7, 0x03, 0x32, 0x05, 0xDB, 0x9E, 0xB3, 0x4D, + 0x5C, 0x7C, 0xE0, 0x28, 0x48, 0xCA, 0xC6, 0x8A, + 0x83, 0xED, 0x73, 0xE3, 0x88, 0x34, 0x77, 0xF5, + 0x63, 0xF2, 0x3C, 0xE9, 0xA1, 0x1A, 0x77, 0x21, + 0xEC, 0x64, + }; + + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); + CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair)); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, NULL, NULL, NULL) == 1); + + CHECK(secp256k1_memcmp_var(&secnonce.data[4], expected_secnonce, 2*32) == 0); + CHECK(secp256k1_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); + + CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce66, &pubnonce) == 1); + CHECK(secp256k1_memcmp_var(pubnonce66, expected_pubnonce, sizeof(pubnonce66)) == 0); +} + +static void run_musig_tests(void) { + int i; + + for (i = 0; i < COUNT; i++) { + musig_simple_test(); + } + musig_api_tests(); + musig_nonce_test(); + for (i = 0; i < COUNT; i++) { + /* Run multiple times to ensure that pk and nonce have different y + * parities */ + musig_tweak_test(); + } + sha256_tag_test(); + musig_test_vectors_keyagg(); + musig_test_vectors_noncegen(); + musig_test_vectors_nonceagg(); + musig_test_vectors_signverify(); + musig_test_vectors_tweak(); + musig_test_vectors_sigagg(); + + musig_test_static_nonce_gen_counter(); +} + +#endif diff --git a/external/secp256k1/src/modules/musig/vectors.h b/external/secp256k1/src/modules/musig/vectors.h new file mode 100644 index 00000000000..8407c2a69a9 --- /dev/null +++ b/external/secp256k1/src/modules/musig/vectors.h @@ -0,0 +1,346 @@ +/** + * Automatically generated by ./tools/test_vectors_musig2_generate.py. + * + * The test vectors for the KeySort function are included in this file. They can + * be found in src/modules/extrakeys/tests_impl.h. */ + +enum MUSIG_ERROR { + MUSIG_PUBKEY, + MUSIG_TWEAK, + MUSIG_PUBNONCE, + MUSIG_AGGNONCE, + MUSIG_SECNONCE, + MUSIG_SIG, + MUSIG_SIG_VERIFY, + MUSIG_OTHER +}; + +struct musig_key_agg_valid_test_case { + size_t key_indices_len; + size_t key_indices[4]; + unsigned char expected[32]; +}; + +struct musig_key_agg_error_test_case { + size_t key_indices_len; + size_t key_indices[4]; + size_t tweak_indices_len; + size_t tweak_indices[1]; + int is_xonly[1]; + enum MUSIG_ERROR error; +}; + +struct musig_key_agg_vector { + unsigned char pubkeys[7][33]; + unsigned char tweaks[2][32]; + struct musig_key_agg_valid_test_case valid_case[4]; + struct musig_key_agg_error_test_case error_case[5]; +}; + +static const struct musig_key_agg_vector musig_key_agg_vector = { + { + { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }, + { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 }, + { 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 }, + { 0x04, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 } + }, + { + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, + { 0x25, 0x2E, 0x4B, 0xD6, 0x74, 0x10, 0xA7, 0x6C, 0xDF, 0x93, 0x3D, 0x30, 0xEA, 0xA1, 0x60, 0x82, 0x14, 0x03, 0x7F, 0x1B, 0x10, 0x5A, 0x01, 0x3E, 0xCC, 0xD3, 0xC5, 0xC1, 0x84, 0xA6, 0x11, 0x0B } + }, + { + { 3, { 0, 1, 2 }, { 0x90, 0x53, 0x9E, 0xED, 0xE5, 0x65, 0xF5, 0xD0, 0x54, 0xF3, 0x2C, 0xC0, 0xC2, 0x20, 0x12, 0x68, 0x89, 0xED, 0x1E, 0x5D, 0x19, 0x3B, 0xAF, 0x15, 0xAE, 0xF3, 0x44, 0xFE, 0x59, 0xD4, 0x61, 0x0C }}, + { 3, { 2, 1, 0 }, { 0x62, 0x04, 0xDE, 0x8B, 0x08, 0x34, 0x26, 0xDC, 0x6E, 0xAF, 0x95, 0x02, 0xD2, 0x70, 0x24, 0xD5, 0x3F, 0xC8, 0x26, 0xBF, 0x7D, 0x20, 0x12, 0x14, 0x8A, 0x05, 0x75, 0x43, 0x5D, 0xF5, 0x4B, 0x2B }}, + { 3, { 0, 0, 0 }, { 0xB4, 0x36, 0xE3, 0xBA, 0xD6, 0x2B, 0x8C, 0xD4, 0x09, 0x96, 0x9A, 0x22, 0x47, 0x31, 0xC1, 0x93, 0xD0, 0x51, 0x16, 0x2D, 0x8C, 0x5A, 0xE8, 0xB1, 0x09, 0x30, 0x61, 0x27, 0xDA, 0x3A, 0xA9, 0x35 }}, + { 4, { 0, 0, 1, 1 }, { 0x69, 0xBC, 0x22, 0xBF, 0xA5, 0xD1, 0x06, 0x30, 0x6E, 0x48, 0xA2, 0x06, 0x79, 0xDE, 0x1D, 0x73, 0x89, 0x38, 0x61, 0x24, 0xD0, 0x75, 0x71, 0xD0, 0xD8, 0x72, 0x68, 0x60, 0x28, 0xC2, 0x6A, 0x3E }}, + }, + { + { 2, { 0, 3 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, + { 2, { 0, 4 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, + { 2, { 5, 0 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, + { 2, { 0, 1 }, 1, { 0 }, { 1 }, MUSIG_TWEAK }, + { 1, { 6 }, 1, { 1 }, { 0 }, MUSIG_TWEAK }, + }, +}; + +struct musig_nonce_gen_test_case { + unsigned char rand_[32]; + int has_sk; + unsigned char sk[32]; + unsigned char pk[33]; + int has_aggpk; + unsigned char aggpk[32]; + int has_msg; + unsigned char msg[32]; + int has_extra_in; + unsigned char extra_in[32]; + unsigned char expected_secnonce[97]; + unsigned char expected_pubnonce[66]; +}; + +struct musig_nonce_gen_vector { + struct musig_nonce_gen_test_case test_case[2]; +}; + +static const struct musig_nonce_gen_vector musig_nonce_gen_vector = { + { + { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 1 , { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, { 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, 1 , { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }, 1 , { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, 1 , { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, { 0xB1, 0x14, 0xE5, 0x02, 0xBE, 0xAA, 0x4E, 0x30, 0x1D, 0xD0, 0x8A, 0x50, 0x26, 0x41, 0x72, 0xC8, 0x4E, 0x41, 0x65, 0x0E, 0x6C, 0xB7, 0x26, 0xB4, 0x10, 0xC0, 0x69, 0x4D, 0x59, 0xEF, 0xFB, 0x64, 0x95, 0xB5, 0xCA, 0xF2, 0x8D, 0x04, 0x5B, 0x97, 0x3D, 0x63, 0xE3, 0xC9, 0x9A, 0x44, 0xB8, 0x07, 0xBD, 0xE3, 0x75, 0xFD, 0x6C, 0xB3, 0x9E, 0x46, 0xDC, 0x4A, 0x51, 0x17, 0x08, 0xD0, 0xE9, 0xD2, 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, { 0x02, 0xF7, 0xBE, 0x70, 0x89, 0xE8, 0x37, 0x6E, 0xB3, 0x55, 0x27, 0x23, 0x68, 0x76, 0x6B, 0x17, 0xE8, 0x8E, 0x7D, 0xB7, 0x20, 0x47, 0xD0, 0x5E, 0x56, 0xAA, 0x88, 0x1E, 0xA5, 0x2B, 0x3B, 0x35, 0xDF, 0x02, 0xC2, 0x9C, 0x80, 0x46, 0xFD, 0xD0, 0xDE, 0xD4, 0xC7, 0xE5, 0x58, 0x69, 0x13, 0x72, 0x00, 0xFB, 0xDB, 0xFE, 0x2E, 0xB6, 0x54, 0x26, 0x7B, 0x6D, 0x70, 0x13, 0x60, 0x2C, 0xAE, 0xD3, 0x11, 0x5A } }, + { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 0 , { 0 }, { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, 0 , { 0 }, 0 , { 0 }, 0 , { 0 }, { 0x89, 0xBD, 0xD7, 0x87, 0xD0, 0x28, 0x4E, 0x5E, 0x4D, 0x5F, 0xC5, 0x72, 0xE4, 0x9E, 0x31, 0x6B, 0xAB, 0x7E, 0x21, 0xE3, 0xB1, 0x83, 0x0D, 0xE3, 0x7D, 0xFE, 0x80, 0x15, 0x6F, 0xA4, 0x1A, 0x6D, 0x0B, 0x17, 0xAE, 0x8D, 0x02, 0x4C, 0x53, 0x67, 0x96, 0x99, 0xA6, 0xFD, 0x79, 0x44, 0xD9, 0xC4, 0xA3, 0x66, 0xB5, 0x14, 0xBA, 0xF4, 0x30, 0x88, 0xE0, 0x70, 0x8B, 0x10, 0x23, 0xDD, 0x28, 0x97, 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, { 0x02, 0xC9, 0x6E, 0x7C, 0xB1, 0xE8, 0xAA, 0x5D, 0xAC, 0x64, 0xD8, 0x72, 0x94, 0x79, 0x14, 0x19, 0x8F, 0x60, 0x7D, 0x90, 0xEC, 0xDE, 0x52, 0x00, 0xDE, 0x52, 0x97, 0x8A, 0xD5, 0xDE, 0xD6, 0x3C, 0x00, 0x02, 0x99, 0xEC, 0x51, 0x17, 0xC2, 0xD2, 0x9E, 0xDE, 0xE8, 0xA2, 0x09, 0x25, 0x87, 0xC3, 0x90, 0x9B, 0xE6, 0x94, 0xD5, 0xCF, 0xF0, 0x66, 0x7D, 0x6C, 0x02, 0xEA, 0x40, 0x59, 0xF7, 0xCD, 0x97, 0x86 } }, + }, +}; + +struct musig_nonce_agg_test_case { + size_t pnonce_indices[2]; + /* if valid case */ + unsigned char expected[66]; + /* if error case */ + int invalid_nonce_idx; +}; + +struct musig_nonce_agg_vector { + unsigned char pnonces[7][66]; + struct musig_nonce_agg_test_case valid_case[2]; + struct musig_nonce_agg_test_case error_case[3]; +}; + +static const struct musig_nonce_agg_vector musig_nonce_agg_vector = { + { + { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x03, 0xBA, 0x47, 0xFB, 0xC1, 0x83, 0x44, 0x37, 0xB3, 0x21, 0x2E, 0x89, 0xA8, 0x4D, 0x84, 0x25, 0xE7, 0xBF, 0x12, 0xE0, 0x24, 0x5D, 0x98, 0x26, 0x22, 0x68, 0xEB, 0xDC, 0xB3, 0x85, 0xD5, 0x06, 0x41 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 }, + { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x03, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x04, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x31 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 } + }, + { + { { 0, 1 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x02, 0x47, 0x25, 0x37, 0x73, 0x45, 0xBD, 0xE0, 0xE9, 0xC3, 0x3A, 0xF3, 0xC4, 0x3C, 0x0A, 0x29, 0xA9, 0x24, 0x9F, 0x2F, 0x29, 0x56, 0xFA, 0x8C, 0xFE, 0xB5, 0x5C, 0x85, 0x73, 0xD0, 0x26, 0x2D, 0xC8 }, 0 }, + { { 2, 3 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0 }, + }, + { + { { 0, 4 }, { 0 }, 1 }, + { { 5, 1 }, { 0 }, 0 }, + { { 6, 1 }, { 0 }, 0 }, + }, +}; + +/* Omit pubnonces in the test vectors because our partial signature verification + * implementation is able to accept the aggnonce directly. */ +struct musig_valid_case { + size_t key_indices_len; + size_t key_indices[3]; + size_t aggnonce_index; + size_t msg_index; + size_t signer_index; + unsigned char expected[32]; +}; + +struct musig_sign_error_case { + size_t key_indices_len; + size_t key_indices[3]; + size_t aggnonce_index; + size_t msg_index; + size_t secnonce_index; + enum MUSIG_ERROR error; +}; + +struct musig_verify_fail_error_case { + unsigned char sig[32]; + size_t key_indices_len; + size_t key_indices[3]; + size_t nonce_indices_len; + size_t nonce_indices[3]; + size_t msg_index; + size_t signer_index; + enum MUSIG_ERROR error; +}; + +struct musig_sign_verify_vector { + unsigned char sk[32]; + unsigned char pubkeys[4][33]; + unsigned char secnonces[2][194]; + unsigned char pubnonces[5][194]; + unsigned char aggnonces[5][66]; + unsigned char msgs[1][32]; + struct musig_valid_case valid_case[4]; + struct musig_sign_error_case sign_error_case[6]; + struct musig_verify_fail_error_case verify_fail_case[3]; + struct musig_verify_fail_error_case verify_error_case[2]; +}; + +static const struct musig_sign_verify_vector musig_sign_verify_vector = { + { 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 }, + { + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x61 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 } + }, + { + { 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 } + }, + { + { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, + { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 }, + { 0x02, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x03, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 } + }, + { + { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x04, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 }, + { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 }, + { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 } + }, + { + { 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF } + }, + { + { 3, { 0, 1, 2 }, 0, 0, 0, { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }}, + { 3, { 1, 0, 2 }, 0, 0, 1, { 0x9F, 0xF2, 0xF7, 0xAA, 0xA8, 0x56, 0x15, 0x0C, 0xC8, 0x81, 0x92, 0x54, 0x21, 0x8D, 0x3A, 0xDE, 0xEB, 0x05, 0x35, 0x26, 0x90, 0x51, 0x89, 0x77, 0x24, 0xF9, 0xDB, 0x37, 0x89, 0x51, 0x3A, 0x52 }}, + { 3, { 1, 2, 0 }, 0, 0, 2, { 0xFA, 0x23, 0xC3, 0x59, 0xF6, 0xFA, 0xC4, 0xE7, 0x79, 0x6B, 0xB9, 0x3B, 0xC9, 0xF0, 0x53, 0x2A, 0x95, 0x46, 0x8C, 0x53, 0x9B, 0xA2, 0x0F, 0xF8, 0x6D, 0x7C, 0x76, 0xED, 0x92, 0x22, 0x79, 0x00 }}, + { 2, { 0, 1 }, 1, 0, 0, { 0xAE, 0x38, 0x60, 0x64, 0xB2, 0x61, 0x05, 0x40, 0x47, 0x98, 0xF7, 0x5D, 0xE2, 0xEB, 0x9A, 0xF5, 0xED, 0xA5, 0x38, 0x7B, 0x06, 0x4B, 0x83, 0xD0, 0x49, 0xCB, 0x7C, 0x5E, 0x08, 0x87, 0x95, 0x31 }}, + }, + { + { 2, { 1, 2 }, 0, 0, 0, MUSIG_PUBKEY }, + { 3, { 1, 0, 3 }, 0, 0, 0, MUSIG_PUBKEY }, + { 3, { 1, 2, 0 }, 2, 0, 0, MUSIG_AGGNONCE }, + { 3, { 1, 2, 0 }, 3, 0, 0, MUSIG_AGGNONCE }, + { 3, { 1, 2, 0 }, 4, 0, 0, MUSIG_AGGNONCE }, + { 3, { 0, 1, 2 }, 0, 0, 1, MUSIG_SECNONCE }, + }, + { + { { 0xFE, 0xD5, 0x44, 0x34, 0xAD, 0x4C, 0xFE, 0x95, 0x3F, 0xC5, 0x27, 0xDC, 0x6A, 0x5E, 0x5B, 0xE8, 0xF6, 0x23, 0x49, 0x07, 0xB7, 0xC1, 0x87, 0x55, 0x95, 0x57, 0xCE, 0x87, 0xA0, 0x54, 0x1C, 0x46 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG_VERIFY }, + { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 1, MUSIG_SIG_VERIFY }, + { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG }, + }, + { + { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 4, 1, 2 }, 0, 0, MUSIG_PUBNONCE }, + { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 3, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_PUBKEY }, + }, +}; + +struct musig_tweak_case { + size_t key_indices_len; + size_t key_indices[3]; + size_t nonce_indices_len; + size_t nonce_indices[3]; + size_t tweak_indices_len; + size_t tweak_indices[4]; + int is_xonly[4]; + size_t signer_index; + unsigned char expected[32]; +}; + +struct musig_tweak_vector { + unsigned char sk[32]; + unsigned char secnonce[97]; + unsigned char aggnonce[66]; + unsigned char msg[32]; + unsigned char pubkeys[3][33]; + unsigned char pubnonces[3][194]; + unsigned char tweaks[5][32]; + struct musig_tweak_case valid_case[5]; + struct musig_tweak_case error_case[1]; +}; + +static const struct musig_tweak_vector musig_tweak_vector = { + { 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 }, + { 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 }, + { 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF }, + { + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 } + }, + { + { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, + { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 } + }, + { + { 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF, 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D, 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79, 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB }, + { 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A, 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D, 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0, 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55 }, + { 0xF5, 0x2E, 0xCB, 0xC5, 0x65, 0xB3, 0xD8, 0xBE, 0xA2, 0xDF, 0xD5, 0xB7, 0x5A, 0x4F, 0x45, 0x7E, 0x54, 0x36, 0x98, 0x09, 0x32, 0x2E, 0x41, 0x20, 0x83, 0x16, 0x26, 0xF2, 0x90, 0xFA, 0x87, 0xE0 }, + { 0x19, 0x69, 0xAD, 0x73, 0xCC, 0x17, 0x7F, 0xA0, 0xB4, 0xFC, 0xED, 0x6D, 0xF1, 0xF7, 0xBF, 0x99, 0x07, 0xE6, 0x65, 0xFD, 0xE9, 0xBA, 0x19, 0x6A, 0x74, 0xFE, 0xD0, 0xA3, 0xCF, 0x5A, 0xEF, 0x9D }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 } + }, + { + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 1 }, 2, { 0xE2, 0x8A, 0x5C, 0x66, 0xE6, 0x1E, 0x17, 0x8C, 0x2B, 0xA1, 0x9D, 0xB7, 0x7B, 0x6C, 0xF9, 0xF7, 0xE2, 0xF0, 0xF5, 0x6C, 0x17, 0x91, 0x8C, 0xD1, 0x31, 0x35, 0xE6, 0x0C, 0xC8, 0x48, 0xFE, 0x91 }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 0 }, 2, { 0x38, 0xB0, 0x76, 0x77, 0x98, 0x25, 0x2F, 0x21, 0xBF, 0x57, 0x02, 0xC4, 0x80, 0x28, 0xB0, 0x95, 0x42, 0x83, 0x20, 0xF7, 0x3A, 0x4B, 0x14, 0xDB, 0x1E, 0x25, 0xDE, 0x58, 0x54, 0x3D, 0x2D, 0x2D }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 2, { 0, 1 }, { 0, 1 }, 2, { 0x40, 0x8A, 0x0A, 0x21, 0xC4, 0xA0, 0xF5, 0xDA, 0xCA, 0xF9, 0x64, 0x6A, 0xD6, 0xEB, 0x6F, 0xEC, 0xD7, 0xF7, 0xA1, 0x1F, 0x03, 0xED, 0x1F, 0x48, 0xDF, 0xFF, 0x21, 0x85, 0xBC, 0x2C, 0x24, 0x08 }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 0, 0, 1, 1 }, 2, { 0x45, 0xAB, 0xD2, 0x06, 0xE6, 0x1E, 0x3D, 0xF2, 0xEC, 0x9E, 0x26, 0x4A, 0x6F, 0xEC, 0x82, 0x92, 0x14, 0x1A, 0x63, 0x3C, 0x28, 0x58, 0x63, 0x88, 0x23, 0x55, 0x41, 0xF9, 0xAD, 0xE7, 0x54, 0x35 }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 1, 0, 1, 0 }, 2, { 0xB2, 0x55, 0xFD, 0xCA, 0xC2, 0x7B, 0x40, 0xC7, 0xCE, 0x78, 0x48, 0xE2, 0xD3, 0xB7, 0xBF, 0x5E, 0xA0, 0xED, 0x75, 0x6D, 0xA8, 0x15, 0x65, 0xAC, 0x80, 0x4C, 0xCC, 0xA3, 0xE1, 0xD5, 0xD2, 0x39 }}, + }, + { + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 4 }, { 0 }, 2, { 0 }}, + }, +}; + +/* Omit pubnonces in the test vectors because they're only needed for + * implementations that do not directly accept an aggnonce. */ +struct musig_sig_agg_case { + size_t key_indices_len; + size_t key_indices[2]; + size_t tweak_indices_len; + size_t tweak_indices[3]; + int is_xonly[3]; + unsigned char aggnonce[66]; + size_t psig_indices_len; + size_t psig_indices[2]; + /* if valid case */ + unsigned char expected[64]; + /* if error case */ + int invalid_sig_idx; +}; + +struct musig_sig_agg_vector { + unsigned char pubkeys[4][33]; + unsigned char tweaks[3][32]; + unsigned char psigs[9][32]; + unsigned char msg[32]; + struct musig_sig_agg_case valid_case[4]; + struct musig_sig_agg_case error_case[1]; +}; + +static const struct musig_sig_agg_vector musig_sig_agg_vector = { + { + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 0xD2, 0xDC, 0x6F, 0x5D, 0xF7, 0xC5, 0x6A, 0xCF, 0x38, 0xC7, 0xFA, 0x0A, 0xE7, 0xA7, 0x59, 0xAE, 0x30, 0xE1, 0x9B, 0x37, 0x35, 0x9D, 0xFD, 0xE0, 0x15, 0x87, 0x23, 0x24, 0xC7, 0xEF, 0x6E, 0x05 }, + { 0x03, 0xC7, 0xFB, 0x10, 0x1D, 0x97, 0xFF, 0x93, 0x0A, 0xCD, 0x0C, 0x67, 0x60, 0x85, 0x2E, 0xF6, 0x4E, 0x69, 0x08, 0x3D, 0xE0, 0xB0, 0x6A, 0xC6, 0x33, 0x57, 0x24, 0x75, 0x4B, 0xB4, 0xB0, 0x52, 0x2C }, + { 0x02, 0x35, 0x24, 0x33, 0xB2, 0x1E, 0x7E, 0x05, 0xD3, 0xB4, 0x52, 0xB8, 0x1C, 0xAE, 0x56, 0x6E, 0x06, 0xD2, 0xE0, 0x03, 0xEC, 0xE1, 0x6D, 0x10, 0x74, 0xAA, 0xBA, 0x42, 0x89, 0xE0, 0xE3, 0xD5, 0x81 } + }, + { + { 0xB5, 0x11, 0xDA, 0x49, 0x21, 0x82, 0xA9, 0x1B, 0x0F, 0xFB, 0x9A, 0x98, 0x02, 0x0D, 0x55, 0xF2, 0x60, 0xAE, 0x86, 0xD7, 0xEC, 0xBD, 0x03, 0x99, 0xC7, 0x38, 0x3D, 0x59, 0xA5, 0xF2, 0xAF, 0x7C }, + { 0xA8, 0x15, 0xFE, 0x04, 0x9E, 0xE3, 0xC5, 0xAA, 0xB6, 0x63, 0x10, 0x47, 0x7F, 0xBC, 0x8B, 0xCC, 0xCA, 0xC2, 0xF3, 0x39, 0x5F, 0x59, 0xF9, 0x21, 0xC3, 0x64, 0xAC, 0xD7, 0x8A, 0x2F, 0x48, 0xDC }, + { 0x75, 0x44, 0x8A, 0x87, 0x27, 0x4B, 0x05, 0x64, 0x68, 0xB9, 0x77, 0xBE, 0x06, 0xEB, 0x1E, 0x9F, 0x65, 0x75, 0x77, 0xB7, 0x32, 0x0B, 0x0A, 0x33, 0x76, 0xEA, 0x51, 0xFD, 0x42, 0x0D, 0x18, 0xA8 } + }, + { + { 0xB1, 0x5D, 0x2C, 0xD3, 0xC3, 0xD2, 0x2B, 0x04, 0xDA, 0xE4, 0x38, 0xCE, 0x65, 0x3F, 0x6B, 0x4E, 0xCF, 0x04, 0x2F, 0x42, 0xCF, 0xDE, 0xD7, 0xC4, 0x1B, 0x64, 0xAA, 0xF9, 0xB4, 0xAF, 0x53, 0xFB }, + { 0x61, 0x93, 0xD6, 0xAC, 0x61, 0xB3, 0x54, 0xE9, 0x10, 0x5B, 0xBD, 0xC8, 0x93, 0x7A, 0x34, 0x54, 0xA6, 0xD7, 0x05, 0xB6, 0xD5, 0x73, 0x22, 0xA5, 0xA4, 0x72, 0xA0, 0x2C, 0xE9, 0x9F, 0xCB, 0x64 }, + { 0x9A, 0x87, 0xD3, 0xB7, 0x9E, 0xC6, 0x72, 0x28, 0xCB, 0x97, 0x87, 0x8B, 0x76, 0x04, 0x9B, 0x15, 0xDB, 0xD0, 0x5B, 0x81, 0x58, 0xD1, 0x7B, 0x5B, 0x91, 0x14, 0xD3, 0xC2, 0x26, 0x88, 0x75, 0x05 }, + { 0x66, 0xF8, 0x2E, 0xA9, 0x09, 0x23, 0x68, 0x9B, 0x85, 0x5D, 0x36, 0xC6, 0xB7, 0xE0, 0x32, 0xFB, 0x99, 0x70, 0x30, 0x14, 0x81, 0xB9, 0x9E, 0x01, 0xCD, 0xB4, 0xD6, 0xAC, 0x7C, 0x34, 0x7A, 0x15 }, + { 0x4F, 0x5A, 0xEE, 0x41, 0x51, 0x08, 0x48, 0xA6, 0x44, 0x7D, 0xCD, 0x1B, 0xBC, 0x78, 0x45, 0x7E, 0xF6, 0x90, 0x24, 0x94, 0x4C, 0x87, 0xF4, 0x02, 0x50, 0xD3, 0xEF, 0x2C, 0x25, 0xD3, 0x3E, 0xFE }, + { 0xDD, 0xEF, 0x42, 0x7B, 0xBB, 0x84, 0x7C, 0xC0, 0x27, 0xBE, 0xFF, 0x4E, 0xDB, 0x01, 0x03, 0x81, 0x48, 0x91, 0x78, 0x32, 0x25, 0x3E, 0xBC, 0x35, 0x5F, 0xC3, 0x3F, 0x4A, 0x8E, 0x2F, 0xCC, 0xE4 }, + { 0x97, 0xB8, 0x90, 0xA2, 0x6C, 0x98, 0x1D, 0xA8, 0x10, 0x2D, 0x3B, 0xC2, 0x94, 0x15, 0x9D, 0x17, 0x1D, 0x72, 0x81, 0x0F, 0xDF, 0x7C, 0x6A, 0x69, 0x1D, 0xEF, 0x02, 0xF0, 0xF7, 0xAF, 0x3F, 0xDC }, + { 0x53, 0xFA, 0x9E, 0x08, 0xBA, 0x52, 0x43, 0xCB, 0xCB, 0x0D, 0x79, 0x7C, 0x5E, 0xE8, 0x3B, 0xC6, 0x72, 0x8E, 0x53, 0x9E, 0xB7, 0x6C, 0x2D, 0x0B, 0xF0, 0xF9, 0x71, 0xEE, 0x4E, 0x90, 0x99, 0x71 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 } + }, + { 0x59, 0x9C, 0x67, 0xEA, 0x41, 0x0D, 0x00, 0x5B, 0x9D, 0xA9, 0x08, 0x17, 0xCF, 0x03, 0xED, 0x3B, 0x1C, 0x86, 0x8E, 0x4D, 0xA4, 0xED, 0xF0, 0x0A, 0x58, 0x80, 0xB0, 0x08, 0x2C, 0x23, 0x78, 0x69 }, + { + { 2, { 0, 1 }, 0, { 0 }, { 0 }, { 0x03, 0x41, 0x43, 0x27, 0x22, 0xC5, 0xCD, 0x02, 0x68, 0xD8, 0x29, 0xC7, 0x02, 0xCF, 0x0D, 0x1C, 0xBC, 0xE5, 0x70, 0x33, 0xEE, 0xD2, 0x01, 0xFD, 0x33, 0x51, 0x91, 0x38, 0x52, 0x27, 0xC3, 0x21, 0x0C, 0x03, 0xD3, 0x77, 0xF2, 0xD2, 0x58, 0xB6, 0x4A, 0xAD, 0xC0, 0xE1, 0x6F, 0x26, 0x46, 0x23, 0x23, 0xD7, 0x01, 0xD2, 0x86, 0x04, 0x6A, 0x2E, 0xA9, 0x33, 0x65, 0x65, 0x6A, 0xFD, 0x98, 0x75, 0x98, 0x2B }, 2, { 0, 1 }, { 0x04, 0x1D, 0xA2, 0x22, 0x23, 0xCE, 0x65, 0xC9, 0x2C, 0x9A, 0x0D, 0x6C, 0x2C, 0xAC, 0x82, 0x8A, 0xAF, 0x1E, 0xEE, 0x56, 0x30, 0x4F, 0xEC, 0x37, 0x1D, 0xDF, 0x91, 0xEB, 0xB2, 0xB9, 0xEF, 0x09, 0x12, 0xF1, 0x03, 0x80, 0x25, 0x85, 0x7F, 0xED, 0xEB, 0x3F, 0xF6, 0x96, 0xF8, 0xB9, 0x9F, 0xA4, 0xBB, 0x2C, 0x58, 0x12, 0xF6, 0x09, 0x5A, 0x2E, 0x00, 0x04, 0xEC, 0x99, 0xCE, 0x18, 0xDE, 0x1E }, 0 }, + { 2, { 0, 2 }, 0, { 0 }, { 0 }, { 0x02, 0x24, 0xAF, 0xD3, 0x6C, 0x90, 0x20, 0x84, 0x05, 0x8B, 0x51, 0xB5, 0xD3, 0x66, 0x76, 0xBB, 0xA4, 0xDC, 0x97, 0xC7, 0x75, 0x87, 0x37, 0x68, 0xE5, 0x88, 0x22, 0xF8, 0x7F, 0xE4, 0x37, 0xD7, 0x92, 0x02, 0x8C, 0xB1, 0x59, 0x29, 0x09, 0x9E, 0xEE, 0x2F, 0x5D, 0xAE, 0x40, 0x4C, 0xD3, 0x93, 0x57, 0x59, 0x1B, 0xA3, 0x2E, 0x9A, 0xF4, 0xE1, 0x62, 0xB8, 0xD3, 0xE7, 0xCB, 0x5E, 0xFE, 0x31, 0xCB, 0x20 }, 2, { 2, 3 }, { 0x10, 0x69, 0xB6, 0x7E, 0xC3, 0xD2, 0xF3, 0xC7, 0xC0, 0x82, 0x91, 0xAC, 0xCB, 0x17, 0xA9, 0xC9, 0xB8, 0xF2, 0x81, 0x9A, 0x52, 0xEB, 0x5D, 0xF8, 0x72, 0x6E, 0x17, 0xE7, 0xD6, 0xB5, 0x2E, 0x9F, 0x01, 0x80, 0x02, 0x60, 0xA7, 0xE9, 0xDA, 0xC4, 0x50, 0xF4, 0xBE, 0x52, 0x2D, 0xE4, 0xCE, 0x12, 0xBA, 0x91, 0xAE, 0xAF, 0x2B, 0x42, 0x79, 0x21, 0x9E, 0xF7, 0x4B, 0xE1, 0xD2, 0x86, 0xAD, 0xD9 }, 0 }, + { 2, { 0, 2 }, 1, { 0 }, { 0 }, { 0x02, 0x08, 0xC5, 0xC4, 0x38, 0xC7, 0x10, 0xF4, 0xF9, 0x6A, 0x61, 0xE9, 0xFF, 0x3C, 0x37, 0x75, 0x88, 0x14, 0xB8, 0xC3, 0xAE, 0x12, 0xBF, 0xEA, 0x0E, 0xD2, 0xC8, 0x7F, 0xF6, 0x95, 0x4F, 0xF1, 0x86, 0x02, 0x0B, 0x18, 0x16, 0xEA, 0x10, 0x4B, 0x4F, 0xCA, 0x2D, 0x30, 0x4D, 0x73, 0x3E, 0x0E, 0x19, 0xCE, 0xAD, 0x51, 0x30, 0x3F, 0xF6, 0x42, 0x0B, 0xFD, 0x22, 0x23, 0x35, 0xCA, 0xA4, 0x02, 0x91, 0x6D }, 2, { 4, 5 }, { 0x5C, 0x55, 0x8E, 0x1D, 0xCA, 0xDE, 0x86, 0xDA, 0x0B, 0x2F, 0x02, 0x62, 0x6A, 0x51, 0x2E, 0x30, 0xA2, 0x2C, 0xF5, 0x25, 0x5C, 0xAE, 0xA7, 0xEE, 0x32, 0xC3, 0x8E, 0x9A, 0x71, 0xA0, 0xE9, 0x14, 0x8B, 0xA6, 0xC0, 0xE6, 0xEC, 0x76, 0x83, 0xB6, 0x42, 0x20, 0xF0, 0x29, 0x86, 0x96, 0xF1, 0xB8, 0x78, 0xCD, 0x47, 0xB1, 0x07, 0xB8, 0x1F, 0x71, 0x88, 0x81, 0x2D, 0x59, 0x39, 0x71, 0xE0, 0xCC }, 0 }, + { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 6, 7 }, { 0x83, 0x9B, 0x08, 0x82, 0x0B, 0x68, 0x1D, 0xBA, 0x8D, 0xAF, 0x4C, 0xC7, 0xB1, 0x04, 0xE8, 0xF2, 0x63, 0x8F, 0x93, 0x88, 0xF8, 0xD7, 0xA5, 0x55, 0xDC, 0x17, 0xB6, 0xE6, 0x97, 0x1D, 0x74, 0x26, 0xCE, 0x07, 0xBF, 0x6A, 0xB0, 0x1F, 0x1D, 0xB5, 0x0E, 0x4E, 0x33, 0x71, 0x92, 0x95, 0xF4, 0x09, 0x45, 0x72, 0xB7, 0x98, 0x68, 0xE4, 0x40, 0xFB, 0x3D, 0xEF, 0xD3, 0xFA, 0xC1, 0xDB, 0x58, 0x9E }, 0 }, + }, + { + { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 7, 8 }, { 0 }, 1 }, + }, +}; +enum { MUSIG_VECTORS_MAX_PUBKEYS = 7 }; diff --git a/external/secp256k1/src/modules/recovery/Makefile.am.include b/external/secp256k1/src/modules/recovery/Makefile.am.include new file mode 100644 index 00000000000..156ea690fad --- /dev/null +++ b/external/secp256k1/src/modules/recovery/Makefile.am.include @@ -0,0 +1,5 @@ +include_HEADERS += include/secp256k1_recovery.h +noinst_HEADERS += src/modules/recovery/main_impl.h +noinst_HEADERS += src/modules/recovery/tests_impl.h +noinst_HEADERS += src/modules/recovery/tests_exhaustive_impl.h +noinst_HEADERS += src/modules/recovery/bench_impl.h diff --git a/external/secp256k1/src/modules/recovery/bench_impl.h b/external/secp256k1/src/modules/recovery/bench_impl.h new file mode 100644 index 00000000000..57108d45249 --- /dev/null +++ b/external/secp256k1/src/modules/recovery/bench_impl.h @@ -0,0 +1,62 @@ +/*********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_BENCH_H +#define SECP256K1_MODULE_RECOVERY_BENCH_H + +#include "../../../include/secp256k1_recovery.h" + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + unsigned char sig[64]; +} bench_recover_data; + +static void bench_recover(void* arg, int iters) { + int i; + bench_recover_data *data = (bench_recover_data*)arg; + secp256k1_pubkey pubkey; + unsigned char pubkeyc[33]; + + for (i = 0; i < iters; i++) { + int j; + size_t pubkeylen = 33; + secp256k1_ecdsa_recoverable_signature sig; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); + CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); + for (j = 0; j < 32; j++) { + data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ + data->msg[j] = data->sig[j]; /* Move former R to message. */ + data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + } + } +} + +static void bench_recover_setup(void* arg) { + int i; + bench_recover_data *data = (bench_recover_data*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = 1 + i; + } + for (i = 0; i < 64; i++) { + data->sig[i] = 65 + i; + } +} + +static void run_recovery_bench(int iters, int argc, char** argv) { + bench_recover_data data; + int d = argc == 1; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + + if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters); + + secp256k1_context_destroy(data.ctx); +} + +#endif /* SECP256K1_MODULE_RECOVERY_BENCH_H */ diff --git a/external/secp256k1/src/modules/recovery/main_impl.h b/external/secp256k1/src/modules/recovery/main_impl.h new file mode 100644 index 00000000000..76a005e0177 --- /dev/null +++ b/external/secp256k1/src/modules/recovery/main_impl.h @@ -0,0 +1,159 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H +#define SECP256K1_MODULE_RECOVERY_MAIN_H + +#include "../../../include/secp256k1_recovery.h" + +static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } + *recid = sig->data[64]; +} + +static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } + sig->data[64] = recid; +} + +int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + ARG_CHECK(recid >= 0 && recid <= 3); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(recid != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) { + secp256k1_scalar r, s; + int recid; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; +} + +static int secp256k1_ecdsa_sig_recover(const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { + unsigned char brx[32]; + secp256k1_fe fx; + secp256k1_ge x; + secp256k1_gej xj; + secp256k1_scalar rn, u1, u2; + secp256k1_gej qj; + int r; + + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_scalar_get_b32(brx, sigr); + r = secp256k1_fe_set_b32_limit(&fx, brx); + (void)r; + VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ + if (recid & 2) { + if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + return 0; + } + secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); + } + if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { + return 0; + } + secp256k1_gej_set_ge(&xj, &x); + secp256k1_scalar_inverse_var(&rn, sigr); + secp256k1_scalar_mul(&u1, &rn, message); + secp256k1_scalar_negate(&u1, &u1); + secp256k1_scalar_mul(&u2, &rn, sigs); + secp256k1_ecmult(&qj, &xj, &u2, &u1); + secp256k1_ge_set_gej_var(pubkey, &qj); + return !secp256k1_gej_is_infinity(&qj); +} + +int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar r, s; + int ret, recid; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + + ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msghash32, seckey, noncefp, noncedata); + secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); + return ret; +} + +int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + int recid; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); + VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ + secp256k1_scalar_set_b32(&m, msghash32, NULL); + if (secp256k1_ecdsa_sig_recover(&r, &s, &q, &m, recid)) { + secp256k1_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/external/secp256k1/src/modules/recovery/tests_exhaustive_impl.h b/external/secp256k1/src/modules/recovery/tests_exhaustive_impl.h new file mode 100644 index 00000000000..6bbc02b9a8b --- /dev/null +++ b/external/secp256k1/src/modules/recovery/tests_exhaustive_impl.h @@ -0,0 +1,148 @@ +/*********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H +#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H + +#include "main_impl.h" +#include "../../../include/secp256k1_recovery.h" + +static void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i, j, k; + uint64_t iter = 0; + + /* Loop */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ + if (skip_section(&iter)) continue; + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ + const int starting_k = k; + secp256k1_fe r_dot_y_normalized; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + int expected_recid; + int recid; + int overflow; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + /* Check directly */ + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); + r_from_k(&expected_r, group, k, &overflow); + CHECK(r == expected_r); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); + /* The recid's second bit is for conveying overflow (R.x value >= group order). + * In the actual secp256k1 this is an astronomically unlikely event, but in the + * small group used here, it will almost certainly be the case for all points. + * Note that this isn't actually useful; full recovery would need to convey + * floor(R.x / group_order), but only one bit is used as that is sufficient + * in the real group. */ + expected_recid = overflow ? 2 : 0; + r_dot_y_normalized = group[k].y; + secp256k1_fe_normalize(&r_dot_y_normalized); + /* Also the recovery id is flipped depending if we hit the low-s branch */ + if ((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER) { + expected_recid |= secp256k1_fe_is_odd(&r_dot_y_normalized); + } else { + expected_recid |= !secp256k1_fe_is_odd(&r_dot_y_normalized); + } + CHECK(recid == expected_recid); + + /* Convert to a standard sig then check */ + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k, NULL); + CHECK(r == expected_r); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } +} + +static void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { + /* This is essentially a copy of test_exhaustive_verify, with recovery added */ + int s, r, msg, key; + uint64_t iter = 0; + for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { + for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { + for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { + for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int recid = 0; + int k, should_verify; + unsigned char msg32[32]; + + if (skip_section(&iter)) continue; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + secp256k1_scalar_get_b32(msg32, &msg_s); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k, NULL); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* We would like to try recovering the pubkey and checking that it matches, + * but pubkey recovery is impossible in the exhaustive tests (the reason + * being that there are 12 nonzero r values, 12 nonzero points, and no + * overlap between the sets, so there are no valid signatures). */ + + /* Verify by converting to a standard signature and calling verify */ + secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +static void test_exhaustive_recovery(const secp256k1_context *ctx, const secp256k1_ge *group) { + test_exhaustive_recovery_sign(ctx, group); + test_exhaustive_recovery_verify(ctx, group); +} + +#endif /* SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H */ diff --git a/external/secp256k1/src/modules/recovery/tests_impl.h b/external/secp256k1/src/modules/recovery/tests_impl.h new file mode 100644 index 00000000000..7a28a3ce651 --- /dev/null +++ b/external/secp256k1/src/modules/recovery/tests_impl.h @@ -0,0 +1,338 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H +#define SECP256K1_MODULE_RECOVERY_TESTS_H + +static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + + /* On the first run, return 0 to force a second run */ + if (counter == 0) { + memset(nonce32, 0, 32); + return 1; + } + /* On the second run, return an overflow to force a third run */ + if (counter == 1) { + memset(nonce32, 0xff, 32); + return 1; + } + /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ + memset(nonce32, 1, 32); + return testrand_bits(1); +} + +static void test_ecdsa_recovery_api(void) { + /* Setup contexts that just count errors */ + secp256k1_pubkey pubkey; + secp256k1_pubkey recpubkey; + secp256k1_ecdsa_signature normal_sig; + secp256k1_ecdsa_recoverable_signature recsig; + unsigned char privkey[32] = { 1 }; + unsigned char message[32] = { 2 }; + int recid = 0; + unsigned char sig[74]; + unsigned char zero_privkey[32] = { 0 }; + unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); + + /* Check bad contexts and NULLs for signing */ + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL)); + /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ + secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL); + /* These will all fail, but not in ARG_CHECK way */ + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0); + /* This one will succeed. */ + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); + + /* Check signing with a goofy nonce function */ + + /* Check bad contexts and NULLs for recovery */ + CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, NULL, &recsig, message)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL)); + + /* Check NULLs for conversion */ + CHECK(secp256k1_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL)); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1); + + /* Check NULLs for de/serialization */ + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL)); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1); + + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5)); + /* overflow in signature will not result in calling illegal_callback */ + memcpy(sig, over_privkey, 32); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0); +} + +static void test_ecdsa_recovery_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + secp256k1_ecdsa_signature signature[5]; + secp256k1_ecdsa_recoverable_signature rsignature[5]; + unsigned char sig[74]; + secp256k1_pubkey pubkey; + secp256k1_pubkey recpubkey; + int recid = 0; + + /* Generate a random key and message. */ + { + secp256k1_scalar msg, key; + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); + + /* Serialize/parse compact and verify/recover. */ + extra[0] = 0; + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[3], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1); + memset(&rsignature[4], 0, sizeof(rsignature[4])); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1); + /* Parse compact (with recovery id) and recover. */ + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Serialize/destroy/parse signature and verify again. */ + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1); + sig[testrand_bits(6)] += 1 + testrand_int(255); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 0); + /* Recover again */ + CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 0 || + secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/* Tests several edge cases. */ +static void test_ecdsa_recovery_edge_cases(void) { + const unsigned char msg32[32] = { + 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', + 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', + 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', + 's', 's', 'a', 'g', 'e', '.', '.', '.' + }; + const unsigned char sig64[64] = { + /* Generated by signing the above message with nonce 'This is the nonce we will use...' + * and secret key 0 (which is not valid), resulting in recid 1. */ + 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, + 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, + 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, + 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, + 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, + 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, + 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, + 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 + }; + secp256k1_pubkey pubkey; + /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ + const unsigned char sigb64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + secp256k1_pubkey pubkeyb; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + int recid; + + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 0)); + CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 1)); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 2)); + CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 3)); + CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + + for (recid = 0; recid < 4; recid++) { + int i; + int recid2; + /* (4,4) encoded in DER. */ + unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; + unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; + unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; + unsigned char sigbderalt1[39] = { + 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt2[39] = { + 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + unsigned char sigbderalt3[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt4[40] = { + 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + /* (order + r,4) encoded in DER. */ + unsigned char sigbderlong[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, + 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, + 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 + }; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 1); + for (recid2 = 0; recid2 < 4; recid2++) { + secp256k1_pubkey pubkey2b; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid2) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkey2b, &rsig, msg32) == 1); + /* Verifying with (order + r,4) should always fail. */ + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderlong, sizeof(sigbderlong)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + } + /* DER parsing tests. */ + /* Zero length r/s. */ + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); + /* Leading zeros. */ + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); + sigbderalt3[4] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + sigbderalt4[7] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + /* Damage signature. */ + sigbder[7]++; + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + sigbder[7]--; + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, 6) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder) - 1) == 0); + for(i = 0; i < 8; i++) { + int c; + unsigned char orig = sigbder[i]; + /*Try every single-byte change.*/ + for (c = 0; c < 256; c++) { + if (c == orig ) { + continue; + } + sigbder[i] = c; + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); + } + sigbder[i] = orig; + } + } + + /* Test r/s equal to zero */ + { + /* (1,1) encoded in DER. */ + unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + unsigned char sigc64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + secp256k1_pubkey pubkeyc; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyc, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 1); + sigcder[4] = 0; + sigc64[31] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0); + sigcder[4] = 1; + sigcder[7] = 0; + sigc64[31] = 1; + sigc64[63] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0); + } +} + +static void run_recovery_tests(void) { + int i; + for (i = 0; i < COUNT; i++) { + test_ecdsa_recovery_api(); + } + for (i = 0; i < 64*COUNT; i++) { + test_ecdsa_recovery_end_to_end(); + } + test_ecdsa_recovery_edge_cases(); +} + +#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/external/secp256k1/src/modules/schnorrsig/Makefile.am.include b/external/secp256k1/src/modules/schnorrsig/Makefile.am.include new file mode 100644 index 00000000000..654fa2e5ae5 --- /dev/null +++ b/external/secp256k1/src/modules/schnorrsig/Makefile.am.include @@ -0,0 +1,5 @@ +include_HEADERS += include/secp256k1_schnorrsig.h +noinst_HEADERS += src/modules/schnorrsig/main_impl.h +noinst_HEADERS += src/modules/schnorrsig/tests_impl.h +noinst_HEADERS += src/modules/schnorrsig/tests_exhaustive_impl.h +noinst_HEADERS += src/modules/schnorrsig/bench_impl.h diff --git a/external/secp256k1/src/modules/schnorrsig/bench_impl.h b/external/secp256k1/src/modules/schnorrsig/bench_impl.h new file mode 100644 index 00000000000..93a878ede3e --- /dev/null +++ b/external/secp256k1/src/modules/schnorrsig/bench_impl.h @@ -0,0 +1,104 @@ +/*********************************************************************** + * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORRSIG_BENCH_H +#define SECP256K1_MODULE_SCHNORRSIG_BENCH_H + +#include "../../../include/secp256k1_schnorrsig.h" + +#define MSGLEN 32 + +typedef struct { + secp256k1_context *ctx; + int n; + + const secp256k1_keypair **keypairs; + const unsigned char **pk; + const unsigned char **sigs; + const unsigned char **msgs; +} bench_schnorrsig_data; + +static void bench_schnorrsig_sign(void* arg, int iters) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + int i; + unsigned char msg[MSGLEN] = {0}; + unsigned char sig[64]; + + for (i = 0; i < iters; i++) { + msg[0] = i; + msg[1] = i >> 8; + CHECK(secp256k1_schnorrsig_sign_custom(data->ctx, sig, msg, MSGLEN, data->keypairs[i], NULL)); + } +} + +static void bench_schnorrsig_verify(void* arg, int iters) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + int i; + + for (i = 0; i < iters; i++) { + secp256k1_xonly_pubkey pk; + CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1); + CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], MSGLEN, &pk)); + } +} + +static void run_schnorrsig_bench(int iters, int argc, char** argv) { + int i; + bench_schnorrsig_data data; + int d = argc == 1; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *)); + data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); + data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); + data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); + + CHECK(MSGLEN >= 4); + for (i = 0; i < iters; i++) { + unsigned char sk[32]; + unsigned char *msg = (unsigned char *)malloc(MSGLEN); + unsigned char *sig = (unsigned char *)malloc(64); + secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair)); + unsigned char *pk_char = (unsigned char *)malloc(32); + secp256k1_xonly_pubkey pk; + msg[0] = sk[0] = i; + msg[1] = sk[1] = i >> 8; + msg[2] = sk[2] = i >> 16; + msg[3] = sk[3] = i >> 24; + memset(&msg[4], 'm', MSGLEN - 4); + memset(&sk[4], 's', 28); + + data.keypairs[i] = keypair; + data.pk[i] = pk_char; + data.msgs[i] = msg; + data.sigs[i] = sig; + + CHECK(secp256k1_keypair_create(data.ctx, keypair, sk)); + CHECK(secp256k1_schnorrsig_sign_custom(data.ctx, sig, msg, MSGLEN, keypair, NULL)); + CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair)); + CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1); + } + + if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "schnorrsig_sign")) run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters); + if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "schnorrsig_verify")) run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, iters); + + for (i = 0; i < iters; i++) { + free((void *)data.keypairs[i]); + free((void *)data.pk[i]); + free((void *)data.msgs[i]); + free((void *)data.sigs[i]); + } + + /* Casting to (void *) avoids a stupid warning in MSVC. */ + free((void *)data.keypairs); + free((void *)data.pk); + free((void *)data.msgs); + free((void *)data.sigs); + + secp256k1_context_destroy(data.ctx); +} + +#endif diff --git a/external/secp256k1/src/modules/schnorrsig/main_impl.h b/external/secp256k1/src/modules/schnorrsig/main_impl.h new file mode 100644 index 00000000000..82bba2f5975 --- /dev/null +++ b/external/secp256k1/src/modules/schnorrsig/main_impl.h @@ -0,0 +1,269 @@ +/*********************************************************************** + * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORRSIG_MAIN_H +#define SECP256K1_MODULE_SCHNORRSIG_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_schnorrsig.h" +#include "../../hash.h" + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */ +static void secp256k1_nonce_function_bip340_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x46615b35ul; + sha->s[1] = 0xf4bfbff7ul; + sha->s[2] = 0x9f8dc671ul; + sha->s[3] = 0x83627ab3ul; + sha->s[4] = 0x60217180ul; + sha->s[5] = 0x57358661ul; + sha->s[6] = 0x21a29e54ul; + sha->s[7] = 0x68b07b4cul; + + sha->bytes = 64; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */ +static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x24dd3219ul; + sha->s[1] = 0x4eba7e70ul; + sha->s[2] = 0xca0fabb9ul; + sha->s[3] = 0x0fa3166dul; + sha->s[4] = 0x3afbe4b1ul; + sha->s[5] = 0x4c44df97ul; + sha->s[6] = 0x4aac2739ul; + sha->s[7] = 0x249e850aul; + + sha->bytes = 64; +} + +/* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340 + * by using the correct tagged hash function. */ +static const unsigned char bip340_algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; + +static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC; + +static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + secp256k1_sha256 sha; + unsigned char masked_key[32]; + int i; + + if (algo == NULL) { + return 0; + } + + if (data != NULL) { + secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha); + secp256k1_sha256_write(&sha, data, 32); + secp256k1_sha256_finalize(&sha, masked_key); + for (i = 0; i < 32; i++) { + masked_key[i] ^= key32[i]; + } + } else { + /* Precomputed TaggedHash("BIP0340/aux", 0x0000...00); */ + static const unsigned char ZERO_MASK[32] = { + 84, 241, 105, 207, 201, 226, 229, 114, + 116, 128, 68, 31, 144, 186, 37, 196, + 136, 244, 97, 199, 11, 94, 165, 220, + 170, 247, 175, 105, 39, 10, 165, 20 + }; + for (i = 0; i < 32; i++) { + masked_key[i] = key32[i] ^ ZERO_MASK[i]; + } + } + + /* Tag the hash with algo which is important to avoid nonce reuse across + * algorithms. If this nonce function is used in BIP-340 signing as defined + * in the spec, an optimized tagging implementation is used. */ + if (algolen == sizeof(bip340_algo) + && secp256k1_memcmp_var(algo, bip340_algo, algolen) == 0) { + secp256k1_nonce_function_bip340_sha256_tagged(&sha); + } else { + secp256k1_sha256_initialize_tagged(&sha, algo, algolen); + } + + /* Hash masked-key||pk||msg using the tagged hash as per the spec */ + secp256k1_sha256_write(&sha, masked_key, 32); + secp256k1_sha256_write(&sha, xonly_pk32, 32); + secp256k1_sha256_write(&sha, msg, msglen); + secp256k1_sha256_finalize(&sha, nonce32); + secp256k1_sha256_clear(&sha); + return 1; +} + +const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_function_bip340; + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */ +static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x9cecba11ul; + sha->s[1] = 0x23925381ul; + sha->s[2] = 0x11679112ul; + sha->s[3] = 0xd1627e0ful; + sha->s[4] = 0x97c87550ul; + sha->s[5] = 0x003cc765ul; + sha->s[6] = 0x90f61164ul; + sha->s[7] = 0x33e9b66aul; + sha->bytes = 64; +} + +static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) +{ + unsigned char buf[32]; + secp256k1_sha256 sha; + + /* tagged hash(r.x, pk.x, msg) */ + secp256k1_schnorrsig_sha256_tagged(&sha); + secp256k1_sha256_write(&sha, r32, 32); + secp256k1_sha256_write(&sha, pubkey32, 32); + secp256k1_sha256_write(&sha, msg, msglen); + secp256k1_sha256_finalize(&sha, buf); + /* Set scalar e to the challenge hash modulo the curve order as per + * BIP340. */ + secp256k1_scalar_set_b32(e, buf, NULL); +} + +static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) { + secp256k1_scalar sk; + secp256k1_scalar e; + secp256k1_scalar k; + secp256k1_gej rj; + secp256k1_ge pk; + secp256k1_ge r; + unsigned char buf[32] = { 0 }; + unsigned char pk_buf[32]; + unsigned char seckey[32]; + int ret = 1; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(msg != NULL || msglen == 0); + ARG_CHECK(keypair != NULL); + + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_bip340; + } + + ret &= secp256k1_keypair_load(ctx, &sk, &pk, keypair); + /* Because we are signing for a x-only pubkey, the secret key is negated + * before signing if the point corresponding to the secret key does not + * have an even Y. */ + if (secp256k1_fe_is_odd(&pk.y)) { + secp256k1_scalar_negate(&sk, &sk); + } + + secp256k1_scalar_get_b32(seckey, &sk); + secp256k1_fe_get_b32(pk_buf, &pk.x); + ret &= !!noncefp(buf, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + secp256k1_scalar_set_b32(&k, buf, NULL); + ret &= !secp256k1_scalar_is_zero(&k); + secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret); + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); + secp256k1_ge_set_gej(&r, &rj); + + /* We declassify r to allow using it as a branch point. This is fine + * because r is not a secret. */ + secp256k1_declassify(ctx, &r, sizeof(r)); + secp256k1_fe_normalize_var(&r.y); + if (secp256k1_fe_is_odd(&r.y)) { + secp256k1_scalar_negate(&k, &k); + } + secp256k1_fe_normalize_var(&r.x); + secp256k1_fe_get_b32(&sig64[0], &r.x); + + secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, pk_buf); + secp256k1_scalar_mul(&e, &e, &sk); + secp256k1_scalar_add(&e, &e, &k); + secp256k1_scalar_get_b32(&sig64[32], &e); + + secp256k1_memczero(sig64, 64, !ret); + secp256k1_scalar_clear(&k); + secp256k1_scalar_clear(&sk); + secp256k1_memclear(seckey, sizeof(seckey)); + secp256k1_gej_clear(&rj); + + return ret; +} + +int secp256k1_schnorrsig_sign32(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) { + /* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */ + return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, secp256k1_nonce_function_bip340, (unsigned char*)aux_rand32); +} + +int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) { + return secp256k1_schnorrsig_sign32(ctx, sig64, msg32, keypair, aux_rand32); +} + +int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_schnorrsig_extraparams *extraparams) { + secp256k1_nonce_function_hardened noncefp = NULL; + void *ndata = NULL; + VERIFY_CHECK(ctx != NULL); + + if (extraparams != NULL) { + ARG_CHECK(secp256k1_memcmp_var(extraparams->magic, + schnorrsig_extraparams_magic, + sizeof(extraparams->magic)) == 0); + noncefp = extraparams->noncefp; + ndata = extraparams->ndata; + } + return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg, msglen, keypair, noncefp, ndata); +} + +int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_xonly_pubkey *pubkey) { + secp256k1_scalar s; + secp256k1_scalar e; + secp256k1_gej rj; + secp256k1_ge pk; + secp256k1_gej pkj; + secp256k1_fe rx; + secp256k1_ge r; + unsigned char buf[32]; + int overflow; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(msg != NULL || msglen == 0); + ARG_CHECK(pubkey != NULL); + + if (!secp256k1_fe_set_b32_limit(&rx, &sig64[0])) { + return 0; + } + + secp256k1_scalar_set_b32(&s, &sig64[32], &overflow); + if (overflow) { + return 0; + } + + if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + + /* Compute e. */ + secp256k1_fe_get_b32(buf, &pk.x); + secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, buf); + + /* Compute rj = s*G + (-e)*pkj */ + secp256k1_scalar_negate(&e, &e); + secp256k1_gej_set_ge(&pkj, &pk); + secp256k1_ecmult(&rj, &pkj, &e, &s); + + secp256k1_ge_set_gej_var(&r, &rj); + if (secp256k1_ge_is_infinity(&r)) { + return 0; + } + + secp256k1_fe_normalize_var(&r.y); + return !secp256k1_fe_is_odd(&r.y) && + secp256k1_fe_equal(&rx, &r.x); +} + +#endif diff --git a/external/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h b/external/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h new file mode 100644 index 00000000000..601b54975d0 --- /dev/null +++ b/external/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -0,0 +1,214 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_schnorrsig.h" +#include "main_impl.h" + +static const unsigned char invalid_pubkey_bytes[][32] = { + /* 0 */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* 2 */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 + }, + /* order */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 24) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 16) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 8) & 0xFF, + (EXHAUSTIVE_TEST_ORDER + 0UL) & 0xFF + }, + /* order + 1 */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 24) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 16) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 8) & 0xFF, + (EXHAUSTIVE_TEST_ORDER + 1UL) & 0xFF + }, + /* field size */ + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F + }, + /* field size + 1 (note that 1 is legal) */ + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 + }, + /* 2^256 - 1 */ + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + } +}; + +#define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0])) + +static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg, + size_t msglen, + const unsigned char *key32, const unsigned char *xonly_pk32, + const unsigned char *algo, size_t algolen, + void* data) { + secp256k1_scalar s; + int *idata = data; + (void)msg; + (void)msglen; + (void)key32; + (void)xonly_pk32; + (void)algo; + (void)algolen; + secp256k1_scalar_set_int(&s, *idata); + secp256k1_scalar_get_b32(nonce32, &s); + return 1; +} + +static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, const secp256k1_xonly_pubkey* pubkeys, unsigned char (*xonly_pubkey_bytes)[32], const int* parities) { + int d; + uint64_t iter = 0; + /* Iterate over the possible public keys to verify against (through their corresponding DL d). */ + for (d = 1; d <= EXHAUSTIVE_TEST_ORDER / 2; ++d) { + int actual_d; + unsigned k; + unsigned char pk32[32]; + memcpy(pk32, xonly_pubkey_bytes[d - 1], 32); + actual_d = parities[d - 1] ? EXHAUSTIVE_TEST_ORDER - d : d; + /* Iterate over the possible valid first 32 bytes in the signature, through their corresponding DL k. + Values above EXHAUSTIVE_TEST_ORDER/2 refer to the entries in invalid_pubkey_bytes. */ + for (k = 1; k <= EXHAUSTIVE_TEST_ORDER / 2 + NUM_INVALID_KEYS; ++k) { + unsigned char sig64[64]; + int actual_k = -1; + int e_done[EXHAUSTIVE_TEST_ORDER] = {0}; + int e_count_done = 0; + if (skip_section(&iter)) continue; + if (k <= EXHAUSTIVE_TEST_ORDER / 2) { + memcpy(sig64, xonly_pubkey_bytes[k - 1], 32); + actual_k = parities[k - 1] ? EXHAUSTIVE_TEST_ORDER - k : k; + } else { + memcpy(sig64, invalid_pubkey_bytes[k - 1 - EXHAUSTIVE_TEST_ORDER / 2], 32); + } + /* Randomly generate messages until all challenges have been hit. */ + while (e_count_done < EXHAUSTIVE_TEST_ORDER) { + secp256k1_scalar e; + unsigned char msg32[32]; + testrand256(msg32); + secp256k1_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32); + /* Only do work if we hit a challenge we haven't tried before. */ + if (!e_done[e]) { + /* Iterate over the possible valid last 32 bytes in the signature. + 0..order=that s value; order+1=random bytes */ + int count_valid = 0; + unsigned int s; + for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) { + int expect_valid, valid; + if (s <= EXHAUSTIVE_TEST_ORDER) { + memset(sig64 + 32, 0, 32); + secp256k1_write_be32(sig64 + 60, s); + expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER && + (s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); + } else { + testrand256(sig64 + 32); + expect_valid = 0; + } + valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]); + CHECK(valid == expect_valid); + count_valid += valid; + } + /* Exactly one s value must verify, unless R is illegal. */ + CHECK(count_valid == (actual_k != -1)); + /* Don't retry other messages that result in the same challenge. */ + e_done[e] = 1; + ++e_count_done; + } + } + } + } +} + +static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) { + int d, k; + uint64_t iter = 0; + secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + + /* Loop over keys. */ + for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) { + int actual_d = d; + if (parities[d - 1]) actual_d = EXHAUSTIVE_TEST_ORDER - d; + /* Loop over nonces. */ + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; ++k) { + int e_done[EXHAUSTIVE_TEST_ORDER] = {0}; + int e_count_done = 0; + unsigned char msg32[32]; + unsigned char sig64[64]; + int actual_k = k; + if (skip_section(&iter)) continue; + extraparams.noncefp = secp256k1_hardened_nonce_function_smallint; + extraparams.ndata = &k; + if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k; + /* Generate random messages until all challenges have been tried. */ + while (e_count_done < EXHAUSTIVE_TEST_ORDER) { + secp256k1_scalar e; + testrand256(msg32); + secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); + /* Only do work if we hit a challenge we haven't tried before. */ + if (!e_done[e]) { + secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER; + unsigned char expected_s_bytes[32]; + secp256k1_scalar_get_b32(expected_s_bytes, &expected_s); + /* Invoke the real function to construct a signature. */ + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], &extraparams)); + /* The first 32 bytes must match the xonly pubkey for the specified k. */ + CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0); + /* The last 32 bytes must match the expected s value. */ + CHECK(secp256k1_memcmp_var(sig64 + 32, expected_s_bytes, 32) == 0); + /* Don't retry other messages that result in the same challenge. */ + e_done[e] = 1; + ++e_count_done; + } + } + } + } +} + +static void test_exhaustive_schnorrsig(const secp256k1_context *ctx) { + secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; + secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + int parity[EXHAUSTIVE_TEST_ORDER - 1]; + unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; + unsigned i; + + /* Verify that all invalid_pubkey_bytes are actually invalid. */ + for (i = 0; i < NUM_INVALID_KEYS; ++i) { + secp256k1_xonly_pubkey pk; + CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk, invalid_pubkey_bytes[i])); + } + + /* Construct keypairs and xonly-pubkeys for the entire group. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; ++i) { + secp256k1_scalar scalar_i; + unsigned char buf[32]; + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_scalar_get_b32(buf, &scalar_i); + CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf)); + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parity[i - 1], &keypair[i - 1])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); + } + + test_exhaustive_schnorrsig_sign(ctx, xonly_pubkey_bytes, keypair, parity); + test_exhaustive_schnorrsig_verify(ctx, xonly_pubkey, xonly_pubkey_bytes, parity); +} + +#endif diff --git a/external/secp256k1/src/modules/schnorrsig/tests_impl.h b/external/secp256k1/src/modules/schnorrsig/tests_impl.h new file mode 100644 index 00000000000..2d716a01f89 --- /dev/null +++ b/external/secp256k1/src/modules/schnorrsig/tests_impl.h @@ -0,0 +1,982 @@ +/*********************************************************************** + * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_H +#define SECP256K1_MODULE_SCHNORRSIG_TESTS_H + +#include "../../../include/secp256k1_schnorrsig.h" + +/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many + * bytes) changes the hash function + */ +static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) { + unsigned char nonces[2][32]; + CHECK(nonce_function_bip340(nonces[0], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); + testrand_flip(args[n_flip], n_bytes); + CHECK(nonce_function_bip340(nonces[1], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); + CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0); +} + +static void run_nonce_function_bip340_tests(void) { + unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; + unsigned char aux_tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'a', 'u', 'x'}; + unsigned char algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; + size_t algolen = sizeof(algo); + secp256k1_sha256 sha; + secp256k1_sha256 sha_optimized; + unsigned char nonce[32], nonce_z[32]; + unsigned char msg[32]; + size_t msglen = sizeof(msg); + unsigned char key[32]; + unsigned char pk[32]; + unsigned char aux_rand[32]; + unsigned char *args[5]; + int i; + + /* Check that hash initialized by + * secp256k1_nonce_function_bip340_sha256_tagged has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, tag, sizeof(tag)); + secp256k1_nonce_function_bip340_sha256_tagged(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * secp256k1_nonce_function_bip340_sha256_tagged_aux has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag)); + secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + testrand256(msg); + testrand256(key); + testrand256(pk); + testrand256(aux_rand); + + /* Check that a bitflip in an argument results in different nonces. */ + args[0] = msg; + args[1] = key; + args[2] = pk; + args[3] = algo; + args[4] = aux_rand; + for (i = 0; i < COUNT; i++) { + nonce_function_bip340_bitflip(args, 0, 32, msglen, algolen); + nonce_function_bip340_bitflip(args, 1, 32, msglen, algolen); + nonce_function_bip340_bitflip(args, 2, 32, msglen, algolen); + /* Flip algo special case "BIP0340/nonce" */ + nonce_function_bip340_bitflip(args, 3, algolen, msglen, algolen); + /* Flip algo again */ + nonce_function_bip340_bitflip(args, 3, algolen, msglen, algolen); + nonce_function_bip340_bitflip(args, 4, 32, msglen, algolen); + } + + /* NULL algo is disallowed */ + CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, NULL, 0, NULL) == 0); + CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); + /* Other algo is fine */ + testrand_bytes_test(algo, algolen); + CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); + + for (i = 0; i < COUNT; i++) { + unsigned char nonce2[32]; + uint32_t offset = testrand_int(msglen - 1); + size_t msglen_tmp = (msglen + offset) % msglen; + size_t algolen_tmp; + + /* Different msglen gives different nonce */ + CHECK(nonce_function_bip340(nonce2, msg, msglen_tmp, key, pk, algo, algolen, NULL) == 1); + CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); + + /* Different algolen gives different nonce */ + offset = testrand_int(algolen - 1); + algolen_tmp = (algolen + offset) % algolen; + CHECK(nonce_function_bip340(nonce2, msg, msglen, key, pk, algo, algolen_tmp, NULL) == 1); + CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); + } + + /* NULL aux_rand argument is allowed, and identical to passing all zero aux_rand. */ + memset(aux_rand, 0, 32); + CHECK(nonce_function_bip340(nonce_z, msg, msglen, key, pk, algo, algolen, &aux_rand) == 1); + CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); + CHECK(secp256k1_memcmp_var(nonce_z, nonce, 32) == 0); +} + +static void test_schnorrsig_api(void) { + unsigned char sk1[32]; + unsigned char sk2[32]; + unsigned char sk3[32]; + unsigned char msg[32]; + secp256k1_keypair keypairs[3]; + secp256k1_keypair invalid_keypair = {{ 0 }}; + secp256k1_xonly_pubkey pk[3]; + secp256k1_xonly_pubkey zero_pk; + unsigned char sig[64]; + secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL}; + + testrand256(sk1); + testrand256(sk2); + testrand256(sk3); + testrand256(msg); + CHECK(secp256k1_keypair_create(CTX, &keypairs[0], sk1) == 1); + CHECK(secp256k1_keypair_create(CTX, &keypairs[1], sk2) == 1); + CHECK(secp256k1_keypair_create(CTX, &keypairs[2], sk3) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[0], NULL, &keypairs[0]) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[1], NULL, &keypairs[1]) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[2], NULL, &keypairs[2]) == 1); + memset(&zero_pk, 0, sizeof(zero_pk)); + + /** main test body **/ + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL)); + + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams)); + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, 0, &keypairs[0], &extraparams) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams)); + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams)); + + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk[0]) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0])); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0])); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, 0, &pk[0]) == 0); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk)); +} + +/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the + * expected state. */ +static void test_schnorrsig_sha256_tagged(void) { + unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'c', 'h', 'a', 'l', 'l', 'e', 'n', 'g', 'e'}; + secp256k1_sha256 sha; + secp256k1_sha256 sha_optimized; + + secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); + secp256k1_schnorrsig_sha256_tagged(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); +} + +/* Helper function for schnorrsig_bip_vectors + * Signs the message and checks that it's the same as expected_sig. */ +static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg, size_t msglen, const unsigned char *expected_sig) { + unsigned char sig[64]; + secp256k1_keypair keypair; + secp256k1_xonly_pubkey pk, pk_expected; + + secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + extraparams.ndata = (unsigned char*)aux_rand; + + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, msglen, &keypair, &extraparams)); + CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); + if (msglen == 32) { + memset(sig, 0, 64); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, aux_rand)); + CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); + } + + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized)); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); + CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); +} + +/* Helper function for schnorrsig_bip_vectors + * Checks that both verify and verify_batch (TODO) return the same value as expected. */ +static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg, size_t msglen, const unsigned char *sig, int expected) { + secp256k1_xonly_pubkey pk; + + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk, pk_serialized)); + CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); +} + +/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See + * https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */ +static void test_schnorrsig_bip_vectors(void) { + { + /* Test vector 0 */ + const unsigned char sk[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 + }; + const unsigned char pk[32] = { + 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, + 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, + 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, + 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char msg[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig[64] = { + 0xE9, 0x07, 0x83, 0x1F, 0x80, 0x84, 0x8D, 0x10, + 0x69, 0xA5, 0x37, 0x1B, 0x40, 0x24, 0x10, 0x36, + 0x4B, 0xDF, 0x1C, 0x5F, 0x83, 0x07, 0xB0, 0x08, + 0x4C, 0x55, 0xF1, 0xCE, 0x2D, 0xCA, 0x82, 0x15, + 0x25, 0xF6, 0x6A, 0x4A, 0x85, 0xEA, 0x8B, 0x71, + 0xE4, 0x82, 0xA7, 0x4F, 0x38, 0x2D, 0x2C, 0xE5, + 0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47, + 0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0 + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 1 */ + const unsigned char sk[32] = { + 0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, + 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, + 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, + 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF + }; + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x68, 0x96, 0xBD, 0x60, 0xEE, 0xAE, 0x29, 0x6D, + 0xB4, 0x8A, 0x22, 0x9F, 0xF7, 0x1D, 0xFE, 0x07, + 0x1B, 0xDE, 0x41, 0x3E, 0x6D, 0x43, 0xF9, 0x17, + 0xDC, 0x8D, 0xCF, 0x8C, 0x78, 0xDE, 0x33, 0x41, + 0x89, 0x06, 0xD1, 0x1A, 0xC9, 0x76, 0xAB, 0xCC, + 0xB2, 0x0B, 0x09, 0x12, 0x92, 0xBF, 0xF4, 0xEA, + 0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C, + 0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 2 */ + const unsigned char sk[32] = { + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC9 + }; + const unsigned char pk[32] = { + 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, + 0x12, 0x1F, 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, + 0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9, + 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 + }; + const unsigned char aux_rand[32] = { + 0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE, + 0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC, + 0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C, + 0x4B, 0x0B, 0x62, 0xD7, 0x98, 0xE6, 0xD9, 0x06 + }; + const unsigned char msg[32] = { + 0x7E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, + 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, + 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, + 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C + }; + const unsigned char sig[64] = { + 0x58, 0x31, 0xAA, 0xEE, 0xD7, 0xB4, 0x4B, 0xB7, + 0x4E, 0x5E, 0xAB, 0x94, 0xBA, 0x9D, 0x42, 0x94, + 0xC4, 0x9B, 0xCF, 0x2A, 0x60, 0x72, 0x8D, 0x8B, + 0x4C, 0x20, 0x0F, 0x50, 0xDD, 0x31, 0x3C, 0x1B, + 0xAB, 0x74, 0x58, 0x79, 0xA5, 0xAD, 0x95, 0x4A, + 0x72, 0xC4, 0x5A, 0x91, 0xC3, 0xA5, 0x1D, 0x3C, + 0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E, + 0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7 + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 3 */ + const unsigned char sk[32] = { + 0x0B, 0x43, 0x2B, 0x26, 0x77, 0x93, 0x73, 0x81, + 0xAE, 0xF0, 0x5B, 0xB0, 0x2A, 0x66, 0xEC, 0xD0, + 0x12, 0x77, 0x30, 0x62, 0xCF, 0x3F, 0xA2, 0x54, + 0x9E, 0x44, 0xF5, 0x8E, 0xD2, 0x40, 0x17, 0x10 + }; + const unsigned char pk[32] = { + 0x25, 0xD1, 0xDF, 0xF9, 0x51, 0x05, 0xF5, 0x25, + 0x3C, 0x40, 0x22, 0xF6, 0x28, 0xA9, 0x96, 0xAD, + 0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A, + 0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17 + }; + const unsigned char aux_rand[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + const unsigned char msg[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + const unsigned char sig[64] = { + 0x7E, 0xB0, 0x50, 0x97, 0x57, 0xE2, 0x46, 0xF1, + 0x94, 0x49, 0x88, 0x56, 0x51, 0x61, 0x1C, 0xB9, + 0x65, 0xEC, 0xC1, 0xA1, 0x87, 0xDD, 0x51, 0xB6, + 0x4F, 0xDA, 0x1E, 0xDC, 0x96, 0x37, 0xD5, 0xEC, + 0x97, 0x58, 0x2B, 0x9C, 0xB1, 0x3D, 0xB3, 0x93, + 0x37, 0x05, 0xB3, 0x2B, 0xA9, 0x82, 0xAF, 0x5A, + 0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27, + 0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3 + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 4 */ + const unsigned char pk[32] = { + 0xD6, 0x9C, 0x35, 0x09, 0xBB, 0x99, 0xE4, 0x12, + 0xE6, 0x8B, 0x0F, 0xE8, 0x54, 0x4E, 0x72, 0x83, + 0x7D, 0xFA, 0x30, 0x74, 0x6D, 0x8B, 0xE2, 0xAA, + 0x65, 0x97, 0x5F, 0x29, 0xD2, 0x2D, 0xC7, 0xB9 + }; + const unsigned char msg[32] = { + 0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2, + 0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24, + 0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B, + 0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03 + }; + const unsigned char sig[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F, + 0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28, + 0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63, + 0x76, 0xAF, 0xB1, 0x54, 0x8A, 0xF6, 0x03, 0xB3, + 0xEB, 0x45, 0xC9, 0xF8, 0x20, 0x7D, 0xEE, 0x10, + 0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93, + 0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 5 */ + const unsigned char pk[32] = { + 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, 0x50, + 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, 0x21, + 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, 0x87, + 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, 0x34 + }; + secp256k1_xonly_pubkey pk_parsed; + /* No need to check the signature of the test vector as parsing the pubkey already fails */ + CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk)); + } + { + /* Test vector 6 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0xFF, 0xF9, 0x7B, 0xD5, 0x75, 0x5E, 0xEE, 0xA4, + 0x20, 0x45, 0x3A, 0x14, 0x35, 0x52, 0x35, 0xD3, + 0x82, 0xF6, 0x47, 0x2F, 0x85, 0x68, 0xA1, 0x8B, + 0x2F, 0x05, 0x7A, 0x14, 0x60, 0x29, 0x75, 0x56, + 0x3C, 0xC2, 0x79, 0x44, 0x64, 0x0A, 0xC6, 0x07, + 0xCD, 0x10, 0x7A, 0xE1, 0x09, 0x23, 0xD9, 0xEF, + 0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E, + 0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 7 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x1F, 0xA6, 0x2E, 0x33, 0x1E, 0xDB, 0xC2, 0x1C, + 0x39, 0x47, 0x92, 0xD2, 0xAB, 0x11, 0x00, 0xA7, + 0xB4, 0x32, 0xB0, 0x13, 0xDF, 0x3F, 0x6F, 0xF4, + 0xF9, 0x9F, 0xCB, 0x33, 0xE0, 0xE1, 0x51, 0x5F, + 0x28, 0x89, 0x0B, 0x3E, 0xDB, 0x6E, 0x71, 0x89, + 0xB6, 0x30, 0x44, 0x8B, 0x51, 0x5C, 0xE4, 0xF8, + 0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35, + 0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 8 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA, + 0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F, + 0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96, + 0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69, + 0x96, 0x17, 0x64, 0xB3, 0xAA, 0x9B, 0x2F, 0xFC, + 0xB6, 0xEF, 0x94, 0x7B, 0x68, 0x87, 0xA2, 0x26, + 0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C, + 0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 9 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x3D, 0xDA, 0x83, 0x28, 0xAF, 0x9C, 0x23, + 0xA9, 0x4C, 0x1F, 0xEE, 0xCF, 0xD1, 0x23, 0xBA, + 0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC, + 0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 10 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x76, 0x15, 0xFB, 0xAF, 0x5A, 0xE2, 0x88, 0x64, + 0x01, 0x3C, 0x09, 0x97, 0x42, 0xDE, 0xAD, 0xB4, + 0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9, + 0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 11 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03, + 0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7, + 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, + 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 12 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, + 0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03, + 0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7, + 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, + 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 13 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA, + 0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F, + 0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96, + 0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 14 */ + const unsigned char pk[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 + }; + secp256k1_xonly_pubkey pk_parsed; + /* No need to check the signature of the test vector as parsing the pubkey already fails */ + CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk)); + } + { + /* Test vector 15 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + /* const unsigned char msg[0] = {}; */ + const unsigned char sig[64] = { + 0x71, 0x53, 0x5D, 0xB1, 0x65, 0xEC, 0xD9, 0xFB, + 0xBC, 0x04, 0x6E, 0x5F, 0xFA, 0xEA, 0x61, 0x18, + 0x6B, 0xB6, 0xAD, 0x43, 0x67, 0x32, 0xFC, 0xCC, + 0x25, 0x29, 0x1A, 0x55, 0x89, 0x54, 0x64, 0xCF, + 0x60, 0x69, 0xCE, 0x26, 0xBF, 0x03, 0x46, 0x62, + 0x28, 0xF1, 0x9A, 0x3A, 0x62, 0xDB, 0x8A, 0x64, + 0x9F, 0x2D, 0x56, 0x0F, 0xAC, 0x65, 0x28, 0x27, + 0xD1, 0xAF, 0x05, 0x74, 0xE4, 0x27, 0xAB, 0x63, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, NULL, 0, sig); + test_schnorrsig_bip_vectors_check_verify(pk, NULL, 0, sig, 1); + } + { + /* Test vector 16 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char msg[] = { 0x11 }; + const unsigned char sig[64] = { + 0x08, 0xA2, 0x0A, 0x0A, 0xFE, 0xF6, 0x41, 0x24, + 0x64, 0x92, 0x32, 0xE0, 0x69, 0x3C, 0x58, 0x3A, + 0xB1, 0xB9, 0x93, 0x4A, 0xE6, 0x3B, 0x4C, 0x35, + 0x11, 0xF3, 0xAE, 0x11, 0x34, 0xC6, 0xA3, 0x03, + 0xEA, 0x31, 0x73, 0xBF, 0xEA, 0x66, 0x83, 0xBD, + 0x10, 0x1F, 0xA5, 0xAA, 0x5D, 0xBC, 0x19, 0x96, + 0xFE, 0x7C, 0xAC, 0xFC, 0x5A, 0x57, 0x7D, 0x33, + 0xEC, 0x14, 0x56, 0x4C, 0xEC, 0x2B, 0xAC, 0xBF, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 17 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char msg[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, + }; + const unsigned char sig[64] = { + 0x51, 0x30, 0xF3, 0x9A, 0x40, 0x59, 0xB4, 0x3B, + 0xC7, 0xCA, 0xC0, 0x9A, 0x19, 0xEC, 0xE5, 0x2B, + 0x5D, 0x86, 0x99, 0xD1, 0xA7, 0x1E, 0x3C, 0x52, + 0xDA, 0x9A, 0xFD, 0xB6, 0xB5, 0x0A, 0xC3, 0x70, + 0xC4, 0xA4, 0x82, 0xB7, 0x7B, 0xF9, 0x60, 0xF8, + 0x68, 0x15, 0x40, 0xE2, 0x5B, 0x67, 0x71, 0xEC, + 0xE1, 0xE5, 0xA3, 0x7F, 0xD8, 0x0E, 0x5A, 0x51, + 0x89, 0x7C, 0x55, 0x66, 0xA9, 0x7E, 0xA5, 0xA5, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 18 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char sig[64] = { + 0x40, 0x3B, 0x12, 0xB0, 0xD8, 0x55, 0x5A, 0x34, + 0x41, 0x75, 0xEA, 0x7E, 0xC7, 0x46, 0x56, 0x63, + 0x03, 0x32, 0x1E, 0x5D, 0xBF, 0xA8, 0xBE, 0x6F, + 0x09, 0x16, 0x35, 0x16, 0x3E, 0xCA, 0x79, 0xA8, + 0x58, 0x5E, 0xD3, 0xE3, 0x17, 0x08, 0x07, 0xE7, + 0xC0, 0x3B, 0x72, 0x0F, 0xC5, 0x4C, 0x7B, 0x23, + 0x89, 0x7F, 0xCB, 0xA0, 0xE9, 0xD0, 0xB4, 0xA0, + 0x68, 0x94, 0xCF, 0xD2, 0x49, 0xF2, 0x23, 0x67, + }; + unsigned char msg[100]; + memset(msg, 0x99, sizeof(msg)); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } +} + +/* Nonce function that returns constant 0 */ +static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + (void) msg; + (void) msglen; + (void) key32; + (void) xonly_pk32; + (void) algo; + (void) algolen; + (void) data; + (void) nonce32; + return 0; +} + +/* Nonce function that sets nonce to 0 */ +static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + (void) msg; + (void) msglen; + (void) key32; + (void) xonly_pk32; + (void) algo; + (void) algolen; + (void) data; + + memset(nonce32, 0, 32); + return 1; +} + +/* Nonce function that sets nonce to 0xFF...0xFF */ +static int nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + (void) msg; + (void) msglen; + (void) key32; + (void) xonly_pk32; + (void) algo; + (void) algolen; + (void) data; + + memset(nonce32, 0xFF, 32); + return 1; +} + +static void test_schnorrsig_sign(void) { + unsigned char sk[32]; + secp256k1_xonly_pubkey pk; + secp256k1_keypair keypair; + const unsigned char msg[] = {'t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'm', 's', 'g', ' ', 'f', 'o', 'r', ' ', 'a', ' ', 's', 'c', 'h', 'n', 'o', 'r', 'r', 's', 'i', 'g', '.', '.'}; + unsigned char sig[64]; + unsigned char sig2[64]; + unsigned char zeros64[64] = { 0 }; + secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + unsigned char aux_rand[32]; + + testrand256(sk); + testrand256(aux_rand); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); + /* Check that deprecated alias gives the same result */ + CHECK(secp256k1_schnorrsig_sign(CTX, sig2, msg, &keypair, NULL) == 1); + CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); + + /* Test different nonce functions */ + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); + memset(sig, 1, sizeof(sig)); + extraparams.noncefp = nonce_function_failing; + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); + CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); + memset(&sig, 1, sizeof(sig)); + extraparams.noncefp = nonce_function_0; + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); + CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); + memset(&sig, 1, sizeof(sig)); + extraparams.noncefp = nonce_function_overflowing; + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); + + /* When using the default nonce function, schnorrsig_sign_custom produces + * the same result as schnorrsig_sign with aux_rand = extraparams.ndata */ + extraparams.noncefp = NULL; + extraparams.ndata = aux_rand; + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig2, msg, &keypair, extraparams.ndata) == 1); + CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); +} + +#define N_SIGS 3 +/* Creates N_SIGS valid signatures and verifies them with verify and + * verify_batch (TODO). Then flips some bits and checks that verification now + * fails. */ +static void test_schnorrsig_sign_verify(void) { + unsigned char sk[32]; + unsigned char msg[N_SIGS][32]; + unsigned char sig[N_SIGS][64]; + size_t i; + secp256k1_keypair keypair; + secp256k1_xonly_pubkey pk; + secp256k1_scalar s; + + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); + + for (i = 0; i < N_SIGS; i++) { + testrand256(msg[i]); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig[i], msg[i], &keypair, NULL)); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[i], msg[i], sizeof(msg[i]), &pk)); + } + + { + /* Flip a few bits in the signature and in the message and check that + * verify and verify_batch (TODO) fail */ + size_t sig_idx = testrand_int(N_SIGS); + size_t byte_idx = testrand_bits(5); + unsigned char xorbyte = testrand_int(254)+1; + sig[sig_idx][byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + sig[sig_idx][byte_idx] ^= xorbyte; + + byte_idx = testrand_bits(5); + sig[sig_idx][32+byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + sig[sig_idx][32+byte_idx] ^= xorbyte; + + byte_idx = testrand_bits(5); + msg[sig_idx][byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + msg[sig_idx][byte_idx] ^= xorbyte; + + /* Check that above bitflips have been reversed correctly */ + CHECK(secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + } + + /* Test overflowing s */ + CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL)); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); + memset(&sig[0][32], 0xFF, 32); + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); + + /* Test negative s */ + CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL)); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); + secp256k1_scalar_set_b32(&s, &sig[0][32], NULL); + secp256k1_scalar_negate(&s, &s); + secp256k1_scalar_get_b32(&sig[0][32], &s); + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); + + /* The empty message can be signed & verified */ + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], NULL, 0, &keypair, NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], NULL, 0, &pk) == 1); + + { + /* Test varying message lengths */ + unsigned char msg_large[32 * 8]; + uint32_t msglen = testrand_int(sizeof(msg_large)); + for (i = 0; i < sizeof(msg_large); i += 32) { + testrand256(&msg_large[i]); + } + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], msg_large, msglen, &keypair, NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 1); + /* Verification for a random wrong message length fails */ + msglen = (msglen + (sizeof(msg_large) - 1)) % sizeof(msg_large); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 0); + } +} +#undef N_SIGS + +static void test_schnorrsig_taproot(void) { + unsigned char sk[32]; + secp256k1_keypair keypair; + secp256k1_xonly_pubkey internal_pk; + unsigned char internal_pk_bytes[32]; + secp256k1_xonly_pubkey output_pk; + unsigned char output_pk_bytes[32]; + unsigned char tweak[32]; + int pk_parity; + unsigned char msg[32]; + unsigned char sig[64]; + + /* Create output key */ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); + /* In actual taproot the tweak would be hash of internal_pk */ + CHECK(secp256k1_xonly_pubkey_serialize(CTX, tweak, &internal_pk) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk_bytes, &output_pk) == 1); + + /* Key spend */ + testrand256(msg); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); + /* Verify key spend */ + CHECK(secp256k1_xonly_pubkey_parse(CTX, &output_pk, output_pk_bytes) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &output_pk) == 1); + + /* Script spend */ + CHECK(secp256k1_xonly_pubkey_serialize(CTX, internal_pk_bytes, &internal_pk) == 1); + /* Verify script spend */ + CHECK(secp256k1_xonly_pubkey_parse(CTX, &internal_pk, internal_pk_bytes) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1); +} + +static void run_schnorrsig_tests(void) { + int i; + run_nonce_function_bip340_tests(); + + test_schnorrsig_api(); + test_schnorrsig_sha256_tagged(); + test_schnorrsig_bip_vectors(); + for (i = 0; i < COUNT; i++) { + test_schnorrsig_sign(); + test_schnorrsig_sign_verify(); + } + test_schnorrsig_taproot(); +} + +#endif diff --git a/external/secp256k1/src/precompute_ecmult.c b/external/secp256k1/src/precompute_ecmult.c new file mode 100644 index 00000000000..5ef198a7700 --- /dev/null +++ b/external/secp256k1/src/precompute_ecmult.c @@ -0,0 +1,90 @@ +/***************************************************************************************************** + * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************************************/ + +#include +#include + +#include "../include/secp256k1.h" + +#include "assumptions.h" +#include "util.h" + +#include "field_impl.h" +#include "group_impl.h" +#include "int128_impl.h" +#include "ecmult.h" +#include "ecmult_compute_table_impl.h" + +static void print_table(FILE *fp, const char *name, int window_g, const secp256k1_ge_storage* table) { + int j; + int i; + + fprintf(fp, "const secp256k1_ge_storage %s[ECMULT_TABLE_SIZE(WINDOW_G)] = {\n", name); + fprintf(fp, " S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 + ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n", + SECP256K1_GE_STORAGE_CONST_GET(table[0])); + + j = 1; + for(i = 3; i <= window_g; ++i) { + fprintf(fp, "#if WINDOW_G > %d\n", i-1); + for(;j < ECMULT_TABLE_SIZE(i); ++j) { + fprintf(fp, ",S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 + ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n", + SECP256K1_GE_STORAGE_CONST_GET(table[j])); + } + fprintf(fp, "#endif\n"); + } + fprintf(fp, "};\n"); +} + +static void print_two_tables(FILE *fp, int window_g) { + secp256k1_ge_storage* table = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(secp256k1_ge_storage)); + secp256k1_ge_storage* table_128 = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(secp256k1_ge_storage)); + + secp256k1_ecmult_compute_two_tables(table, table_128, window_g, &secp256k1_ge_const_g); + + print_table(fp, "secp256k1_pre_g", window_g, table); + print_table(fp, "secp256k1_pre_g_128", window_g, table_128); + + free(table); + free(table_128); +} + +int main(void) { + /* Always compute all tables for window sizes up to 15. */ + int window_g = (ECMULT_WINDOW_SIZE < 15) ? 15 : ECMULT_WINDOW_SIZE; + const char outfile[] = "src/precomputed_ecmult.c"; + FILE* fp; + + fp = fopen(outfile, "w"); + if (fp == NULL) { + fprintf(stderr, "Could not open %s for writing!\n", outfile); + return -1; + } + + fprintf(fp, "/* This file was automatically generated by precompute_ecmult. */\n"); + fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n"); + fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n"); + fprintf(fp, " */\n"); + fprintf(fp, "#include \"group.h\"\n"); + fprintf(fp, "#include \"ecmult.h\"\n"); + fprintf(fp, "#include \"precomputed_ecmult.h\"\n"); + fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n"); + fprintf(fp, "#if ECMULT_WINDOW_SIZE > %d\n", window_g); + fprintf(fp, " #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting precomputed_ecmult.c before the build.\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n"); + fprintf(fp, "# error Cannot compile precomputed_ecmult.c in exhaustive test mode\n"); + fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n"); + fprintf(fp, "#define WINDOW_G ECMULT_WINDOW_SIZE\n"); + + print_two_tables(fp, window_g); + + fprintf(fp, "#undef S\n"); + fclose(fp); + + return 0; +} diff --git a/external/secp256k1/src/precompute_ecmult_gen.c b/external/secp256k1/src/precompute_ecmult_gen.c new file mode 100644 index 00000000000..4d153a65744 --- /dev/null +++ b/external/secp256k1/src/precompute_ecmult_gen.c @@ -0,0 +1,100 @@ +/********************************************************************************* + * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *********************************************************************************/ + +#include +#include + +#include "../include/secp256k1.h" + +#include "assumptions.h" +#include "util.h" + +#include "group.h" +#include "int128_impl.h" +#include "ecmult_gen.h" +#include "ecmult_gen_compute_table_impl.h" + +static const int CONFIGS[][2] = { + {2, 5}, + {11, 6}, + {43, 6} +}; + +static void print_table(FILE* fp, int blocks, int teeth) { + int spacing = CEIL_DIV(256, blocks * teeth); + size_t points = ((size_t)1) << (teeth - 1); + int outer; + size_t inner; + + secp256k1_ge_storage* table = checked_malloc(&default_error_callback, blocks * points * sizeof(secp256k1_ge_storage)); + secp256k1_ecmult_gen_compute_table(table, &secp256k1_ge_const_g, blocks, teeth, spacing); + + fprintf(fp, "#elif (COMB_BLOCKS == %d) && (COMB_TEETH == %d) && (COMB_SPACING == %d)\n", blocks, teeth, spacing); + for (outer = 0; outer != blocks; outer++) { + fprintf(fp,"{"); + for (inner = 0; inner != points; inner++) { + fprintf(fp, "S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 + ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")", + SECP256K1_GE_STORAGE_CONST_GET(table[outer * points + inner])); + if (inner != points - 1) { + fprintf(fp,",\n"); + } + } + if (outer != blocks - 1) { + fprintf(fp,"},\n"); + } else { + fprintf(fp,"}\n"); + } + } + free(table); +} + +int main(int argc, char **argv) { + const char outfile[] = "src/precomputed_ecmult_gen.c"; + FILE* fp; + size_t config; + int did_current_config = 0; + + (void)argc; + (void)argv; + + fp = fopen(outfile, "w"); + if (fp == NULL) { + fprintf(stderr, "Could not open %s for writing!\n", outfile); + return -1; + } + + fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n"); + fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n"); + fprintf(fp, "#include \"group.h\"\n"); + fprintf(fp, "#include \"ecmult_gen.h\"\n"); + fprintf(fp, "#include \"precomputed_ecmult_gen.h\"\n"); + fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n"); + fprintf(fp, "# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode\n"); + fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n"); + fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n"); + + fprintf(fp, "const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS] = {\n"); + fprintf(fp, "#if 0\n"); + for (config = 0; config < sizeof(CONFIGS) / sizeof(*CONFIGS); ++config) { + print_table(fp, CONFIGS[config][0], CONFIGS[config][1]); + if (CONFIGS[config][0] == COMB_BLOCKS && CONFIGS[config][1] == COMB_TEETH) { + did_current_config = 1; + } + } + if (!did_current_config) { + print_table(fp, COMB_BLOCKS, COMB_TEETH); + } + fprintf(fp, "#else\n"); + fprintf(fp, "# error Configuration mismatch, invalid COMB_* parameters. Try deleting precomputed_ecmult_gen.c before the build.\n"); + fprintf(fp, "#endif\n"); + + fprintf(fp, "};\n"); + fprintf(fp, "#undef S\n"); + fclose(fp); + + return 0; +} diff --git a/external/secp256k1/src/precomputed_ecmult.c b/external/secp256k1/src/precomputed_ecmult.c new file mode 100644 index 00000000000..cbd030ce506 --- /dev/null +++ b/external/secp256k1/src/precomputed_ecmult.c @@ -0,0 +1,16456 @@ +/* This file was automatically generated by precompute_ecmult. */ +/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and + * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G. + */ +#include "group.h" +#include "ecmult.h" +#include "precomputed_ecmult.h" +#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u) +#if ECMULT_WINDOW_SIZE > 15 + #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting precomputed_ecmult.c before the build. +#endif +#ifdef EXHAUSTIVE_TEST_ORDER +# error Cannot compile precomputed_ecmult.c in exhaustive test mode +#endif /* EXHAUSTIVE_TEST_ORDER */ +#define WINDOW_G ECMULT_WINDOW_SIZE +const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] = { + S(79be667e,f9dcbbac,55a06295,ce870b07,29bfcdb,2dce28d9,59f2815b,16f81798,483ada77,26a3c465,5da4fbfc,e1108a8,fd17b448,a6855419,9c47d08f,fb10d4b8) +#if WINDOW_G > 2 +,S(f9308a01,9258c310,49344f85,f89d5229,b531c845,836f99b0,8601f113,bce036f9,388f7b0f,632de814,fe337e6,2a37f356,6500a999,34c2231b,6cb9fd75,84b8e672) +#endif +#if WINDOW_G > 3 +,S(2f8bde4d,1a072093,55b4a725,a5c5128,e88b84bd,dc619ab7,cba8d569,b240efe4,d8ac2226,36e5e3d6,d4dba9dd,a6c9c426,f788271b,ab0d6840,dca87d3a,a6ac62d6) +,S(5cbdf064,6e5db4ea,a398f365,f2ea7a0e,3d419b7e,330e39c,e92bdded,cac4f9bc,6aebca40,ba255960,a3178d6d,861a54db,a813d0b8,13fde7b5,a5082628,87264da) +#endif +#if WINDOW_G > 4 +,S(acd484e2,f0c7f653,9ad178a,9f559abd,e0979697,4c57e714,c35f110d,fc27ccbe,cc338921,b0a7d9fd,64380971,763b61e9,add888a4,375f8e0f,5cc262a,c64f9c37) +,S(774ae7f8,58a9411e,5ef4246b,70c65aac,5649980b,e5c17891,bbec1789,5da008cb,d984a032,eb6b5e19,243dd56,d7b7b365,372db1e2,dff9d6a8,301d74c9,c953c61b) +,S(f28773c2,d975288b,c7d1d205,c3748651,b075fbc6,610e58cd,deeddf8f,19405aa8,ab0902e,8d880a89,758212eb,65cdaf47,3a1a06da,521fa91f,29b5cb52,db03ed81) +,S(d7924d4f,7d43ea96,5a465ae3,95ff411,31e5946f,3c85f79e,44adbcf8,e27e080e,581e2872,a86c72a6,83842ec2,28cc6def,ea40af2b,d896d3a5,c504dc9f,f6a26b58) +#endif +#if WINDOW_G > 5 +,S(defdea4c,db677750,a420fee8,7eacf21,eb9898ae,79b97687,66e4faa0,4a2d4a34,4211ab06,94635168,e997b0ea,d2a93dae,ced1f4a0,4a95c0f6,cfb199f6,9e56eb77) +,S(2b4ea0a7,97a443d2,93ef5cff,444f4979,f06acfeb,d7e86d27,74756561,38385b6c,85e89bc0,37945d93,b343083b,5a1c8613,1a01f60c,50269763,b570c854,e5c09b7a) +,S(352bbf4a,4cdd1256,4f93fa33,2ce33330,1d9ad402,71f81071,81340aef,25be59d5,321eb407,5348f534,d59c1825,9dda3e1f,4a1b3b2e,71b1039c,67bd3d8b,cf81998c) +,S(2fa2104d,6b38d11b,2300105,59879124,e42ab8df,eff5ff29,dc9cdadd,4ecacc3f,2de1068,295dd865,b6456933,5bd5dd80,181d70ec,fc882648,423ba76b,532b7d67) +,S(9248279b,9b4d68d,ab21a9b0,66edda83,263c3d84,e09572e2,69ca0cd7,f5453714,73016f7b,f234aade,5d1aa71b,dea2b1ff,3fc0de2a,887912ff,e54a32ce,97cb3402) +,S(daed4f2b,e3a8bf27,8e70132f,b0beb752,2f570e14,4bf615c0,7e996d44,3dee8729,a69dce4a,7d6c98e8,d4a1aca8,7ef8d700,3f83c230,f3afa726,ab40e522,90be1c55) +,S(c44d12c7,65d812e,8acf28d7,cbb19f90,11ecd9e9,fdf281b0,e6a3b5e8,7d22e7db,2119a460,ce326cdc,76c45926,c982fdac,e106e86,1edf61c5,a039063f,e0e6482) +,S(6a245bf6,dc698504,c89a20cf,ded60853,152b6953,36c28063,b61c65cb,d269e6b4,e022cf42,c2bd4a70,8b3f5126,f16a24ad,8b33ba48,d0423b6e,fd5e6348,100d8a82) +#endif +#if WINDOW_G > 6 +,S(1697ffa6,fd9de627,c077e3d2,fe541084,ce13300b,bec1146,f95ae57f,d0bd6a5,b9c398f1,86806f5d,27561506,e4557433,a2cf1500,9e498ae7,adee9d63,d01b2396) +,S(605bdb01,9981718b,986d0f07,e834cb0d,9deb8360,ffb7f61d,f982345e,f27a7479,2972d2d,e4f8d206,81a78d93,ec96fe23,c26bfae8,4fb14db4,3b01e1e9,56b8c49) +,S(62d14dab,4150bf49,7402fdc4,5a215e10,dcb01c35,4959b10c,fe31c7e9,d87ff33d,80fc06bd,8cc5b010,98088a19,50eed0db,1aa1329,67ab4722,35f56424,83b25eaf) +,S(80c60ad0,40f27da,de5b4b06,c408e56b,2c50e9f5,6b9b8b42,5e555c2f,86308b6f,1c38303f,1cc5c30f,26e66bad,7fe72f70,a65eed4c,be7024eb,1aa01f56,430bd57a) +,S(7a9375ad,6167ad54,aa74c634,8cc54d34,4cc5dc94,87d84704,9d5eabb0,fa03c8fb,d0e3fa9,eca87269,9559e0d,79269046,bdc59ea1,c70ce2b,2d499ec,224dc7f7) +,S(d528ecd9,b696b54c,907a9ed0,45447a79,bb408ec3,9b68df50,4bb51f45,9bc3ffc9,eecf4125,3136e5f9,9966f218,81fd656e,bc434540,5c520dbc,63465b5,21409933) +,S(49370a4,b5f43412,ea25f514,e8ecdad0,5266115e,4a7ecb13,87231808,f8b45963,758f3f41,afd6ed42,8b3081b0,512fd62a,54c3f3af,bb5b6764,b653052a,12949c9a) +,S(77f23093,6ee88cbb,d73df930,d64702ef,881d811e,e1498e2,f1c13eb1,fc345d74,958ef42a,7886b640,a08266e,9ba1b378,96c95330,d97077cb,be8eb3c7,671c60d6) +,S(f2dac991,cc4ce4b9,ea44887e,5c7c0bce,58c80074,ab9d4dba,eb28531b,7739f530,e0dedc9b,3b2f8dad,4da1f32d,ec2531df,9eb5fbeb,598e4fd,1a117dba,703a3c37) +,S(463b3d9f,662621fb,1b4be8fb,be252012,5a216cdf,c9dae3de,bcba4850,c690d45b,5ed430d7,8c296c35,43114306,dd8622d7,c622e27c,970a1de3,1cb377b0,1af7307e) +,S(f16f8042,44e46e2a,9232d4a,ff3b5997,6b98fac1,4328a2d1,a32496b4,9998f247,cedabd9b,82203f7e,13d206fc,df4e33d9,2a6c53c2,6e5cce26,d6579962,c4e31df6) +,S(caf75427,2dc84563,b0352b7a,14311af5,5d245315,ace27c65,369e15f7,151d41d1,cb474660,ef35f5f2,a41b643f,a5e46057,5f4fa9b7,962232a5,c32f9083,18a04476) +,S(2600ca4b,282cb986,f85d0f17,9979d8b,44a09c07,cb86d7c1,24497bc8,6f082120,4119b887,53c15bd6,a693b03f,cddbb45d,5ac6be74,ab5f0ef4,4b0be947,5a7e4b40) +,S(7635ca72,d7e8432c,338ec53c,d12220bc,1c48685,e24f7dc8,c602a774,6998e435,91b6496,9489d61,3d1d5e59,f78e6d7,4ecfc061,d57048ba,d9e76f30,2c5b9c61) +,S(754e3239,f325570c,dbbf4a87,deee8a66,b7f2b334,79d468fb,c1a50743,bf56cc18,673fb86,e5bda30f,b3cd0ed3,4ea49a0,23ee33d0,197a695d,c5d9809,3c536683) +,S(e3e6bd10,71a1e96a,ff57859c,82d570f0,33080066,1d1c952f,9fe26946,91d9b9e8,59c9e0bb,a394e76f,40c0aa58,379a3cb6,a5a22839,93e90c41,67002af4,920e37f5) +#endif +#if WINDOW_G > 7 +,S(186b483d,56a0338,26ae73d8,8f732985,c4ccb1f3,2ba35f4b,4cc47fdc,f04aa6eb,3b952d32,c67cf77e,2e17446e,204180ab,21fb8090,895138b4,a4a797f8,6e80888b) +,S(df9d70a6,b9876ce5,44c98561,f4be4f72,5442e6d2,b737d9c9,1a832172,4ce0963f,55eb2daf,d84d6ccd,5f862b78,5dc39d4a,b1572227,20ef9da2,17b8c45c,f2ba2417) +,S(5edd5cc2,3c51e87a,497ca815,d5dce0f8,ab52554f,849ed899,5de64c5f,34ce7143,efae9c8d,bc141306,61e8cec0,30c89ad0,c13c66c0,d17a2905,cdc706ab,7399a868) +,S(290798c2,b6476830,da12fe02,287e9e77,7aa3fba1,c355b17a,722d362f,84614fba,e38da76d,cd440621,988d00bc,f79af25d,5b29c094,db2a2314,6d003afd,41943e7a) +,S(af3c423a,95d9f5b3,54754ef,a150ac39,cd29552f,e3602573,62dfdece,f4053b45,f98a3fd8,31eb2b74,9a93b0e6,f35cfb40,c8cd5aa6,67a15581,bc2feded,498fd9c6) +,S(766dbb24,d134e745,cccaa28c,99bf2749,6bb66b2,6dcf98df,8d2fed50,d884249a,744b1152,eacbe5e3,8dcc8879,80da38b8,97584a65,fa06cedd,2c924f97,cbac5996) +,S(59dbf46f,8c94759b,a21277c3,3784f416,45f7b44f,6c596a58,ce92e666,191abe3e,c534ad44,175fbc30,f4ea6ce,648309a0,42ce739a,7919798c,d85e216c,4a307f6e) +,S(f13ada95,103c4537,305e691e,74e9a4a8,dd647e71,1a95e73c,b62dc601,8cfd87b8,e13817b4,4ee14de6,63bf4bc8,8341f32,6949e21a,6a75c257,778419b,daf5733d) +,S(7754b4fa,e8aced0,6d4167a2,c59cca4c,da1869c0,6ebadfb6,48855001,5a88522c,30e93e86,4e669d82,224b967c,3020b8fa,8d1e4e35,b6cbcc5,37a48b57,841163a2) +,S(948dcadf,5990e048,aa3874d4,6abef9d7,1858f95,de8041d2,a6828c99,e2262519,e491a425,37f6e597,d5d28a32,24b1bc25,df9154ef,bd2ef1d2,cbba2cae,5347d57e) +,S(79624144,50c76c16,89c7b48f,8202ec37,fb224cf5,ac0bfa15,70328a8a,3d7c77ab,100b610e,c4ffb476,d5c1fc1,33ef6f6b,12507a05,1f04ac57,60afa5b2,9db83437) +,S(35140878,34964b54,b15b1606,44d91548,5a169772,25b8847b,b0dd0851,37ec47ca,ef0afbb2,5620544,8e1652c4,8e8127fc,6039e77c,15c2378b,7e7d15a0,de293311) +,S(d3cc30ad,6b483e4b,c79ce2c9,dd8bc549,93e947eb,8df787b4,42943d3f,7b527eaf,8b378a22,d827278d,89c5e9be,8f9508ae,3c2ad462,90358630,afb34db0,4eede0a4) +,S(1624d847,80732860,ce1c78fc,bfefe08b,2b29823d,b913f649,3975ba0f,f4847610,68651cf9,b6da903e,914448c,6cd9d4ca,896878f5,282be4c8,cc06e2a4,4078575) +,S(733ce80d,a955a8a2,6902c956,33e62a98,5192474b,5af207da,6df7b4fd,5fc61cd4,f5435a2b,d2badf7d,485a4d8b,8db9fcce,3e1ef8e0,201e4578,c54673bc,1dc5ea1d) +,S(15d94412,54945064,cf1a1c33,bbd3b49f,8966c509,2171e699,ef258dfa,b81c045c,d56eb30b,69463e72,34f5137b,73b84177,434800ba,cebfc685,fc37bbe9,efe4070d) +,S(a1d0fcf2,ec9de675,b612136e,5ce70d27,1c21417c,9d2b8aaa,ac138599,d0717940,edd77f50,bcb5a3ca,b2e90737,309667f2,641462a5,4070f3d5,19212d39,c197a629) +,S(e22fbe15,c0af8ccc,5780c073,5f84dbe9,a790bade,e8245c06,c7ca3733,1cb36980,a855bab,ad5cd60c,88b430a6,9f53a1a7,a3828915,4964799b,e43d06d7,7d31da06) +,S(311091dd,9860e8e2,ee13473,c1155f5f,69635e39,4704eaa7,40094522,46cfa9b3,66db656f,87d1f04f,ffd1f047,88c06830,871ec5a6,4feee685,bd80f0b1,286d8374) +,S(34c1fd04,d301be89,b31c0442,d3e6ac24,883928b4,5a934078,1867d423,2ec2dbdf,9414685,e97b1b59,54bd46f7,30174136,d57f1cee,b487443d,c5321857,ba73abee) +,S(f219ea5d,6b54701c,1c14de5b,557eb42a,8d13f3ab,bcd08aff,cc2a5e6b,49b8d63,4cb95957,e83d40b0,f73af454,4cccf6b1,f4b08d3c,7b27fb8,d8c2962a,400766d1) +,S(d7b8740f,74a8fbaa,b1f683db,8f45de26,543a5490,bca62708,72369124,69a0b448,fa779681,28d9c92e,e1010f33,7ad4717e,ff15db5e,d3c049b3,411e0315,eaa4593b) +,S(32d31c22,2f8f6f0e,f86f7c98,d3a3335e,ad5bcd32,abdd9428,9fe4d309,1aa824bf,5f3032f5,892156e3,9ccd3d79,15b9e1da,2e6dac9e,6f26e961,118d14b8,462e1661) +,S(7461f371,914ab326,71045a15,5d9831ea,8793d77c,d59592c4,340f86cb,c18347b5,8ec0ba23,8b96bec0,cbdddcae,aa44254,2eee1ff5,c986ea6,b39847b3,cc092ff6) +,S(ee079adb,1df18600,74356a25,aa38206a,6d716b2c,3e67453d,287698ba,d7b2b2d6,8dc2412a,afe3be5c,4c5f37e0,ecc5f9f6,a446989a,f04c4e25,ebaac479,ec1c8c1e) +,S(16ec93e4,47ec83f0,467b1830,2ee620f7,e65de331,874c9dc7,2bfd8616,ba9da6b5,5e463115,e62fb40,d0e8c2a7,ca5804a3,9d58186a,50e49713,9626778e,25b0674d) +,S(eaa5f980,c245f6f0,38978290,afa70b6b,d8855897,f98b6aa4,85b96065,d537bd99,f65f5d3e,292c2e08,19a52839,1c994624,d784869d,7e6ea67f,b1804102,4edc07dc) +,S(78c9407,544ac132,692ee191,a024399,58ae0487,7151342e,a96c4b6b,35a49f51,f3e03191,69eb9b85,d5404795,539a5e68,fa1fbd58,3c064d24,62b675f1,94a3ddb4) +,S(494f4be2,19a1a770,16dcd838,431aea00,1cdc8ae,7a6fc688,726578d9,702857a5,42242a96,9283a5f3,39ba7f07,5e36ba2a,f925ce30,d767ed6e,55f4b031,880d562c) +,S(a598a803,da6d86c,6bc7f2f5,144ea549,d28211ea,58faa70e,bf4c1e66,5c1fe9b5,204b5d6f,84822c30,7e4b4a71,40737aec,23fc63b6,5b35f86a,10026dbd,2d864e6b) +,S(c4191636,5abb2b5d,9192f5f,2dbeafec,208f020f,12570a18,4dbadc3e,58595997,4f14351,d0087efa,49d245b3,28984989,d5caf945,f34bfc0,ed16e96b,58fa9913) +,S(841d6063,a586fa47,5a724604,da03bc5b,92a2e0d2,e0a36acf,e4c73a55,14742881,73867f5,9c0659e8,1904f9a1,c7543698,e62562d6,744c169c,e7a36de0,1a8d6154) +#endif +#if WINDOW_G > 8 +,S(5e95bb39,9a6971d3,76026947,f89bde2f,282b3381,928be4d,ed112ac4,d70e20d5,39f23f36,6809085b,eebfc711,81313775,a99c9aed,7d8ba38b,161384c7,46012865) +,S(36e4641a,53948fd4,76c39f8a,99fd974e,5ec07564,b5315d8b,f99471bc,a0ef2f66,d2424b1b,1abe4eb8,164227b0,85c9aa94,56ea1349,3fd563e0,6fd51cf5,694c78fc) +,S(336581e,a7bfbbb2,90c191a2,f507a41c,f5643842,170e914f,aeab27c2,c579f726,ead12168,595fe1be,99252129,b6e56b33,91f7ab14,10cd1e0e,f3dcdcab,d2fda224) +,S(8ab89816,dadfd6b6,a1f2634f,cf00ec84,3781025,ed6890c4,84974270,6bd43ede,6fdcef09,f2f6d0a0,44e654ae,f624136f,503d459c,3e898458,58a47a91,29cdd24e) +,S(1e33f1a7,46c9c577,8133344d,9299fcaa,20b0938e,8acff254,4bb40284,b8c5fb94,6066025,7dd11b3a,a9c8ed61,8d24edff,2306d320,f1d03010,e33a7d20,57f3b3b6) +,S(85b7c1dc,b3cec1b7,ee7f30de,d79dd20a,ed1f4cc,18cbcfcf,a410361f,d8f08f31,3d98a9cd,d026dd43,f39048f2,5a8847f4,fcafad18,95d7a633,c6fed3c3,5e999511) +,S(29df9fbd,8d9e4650,9275f4b1,25d6d45d,7fbe9a3b,878a7af8,72a28006,61ac5f51,b4c4fe9,9c775a60,6e2d8862,179139ff,da61dc86,1c019e55,cd2876eb,2a27d84b) +,S(a0b1cae0,6b0a847a,3fea6e67,1aaf8adf,dfe58ca2,f768105c,8082b2e4,49fce252,ae434102,edde0958,ec4b19d9,17a6a28e,6b72da18,34aff0e6,50f04950,3a296cf2) +,S(4e8ceaf,b9b3e9a1,36dc7ff6,7e840295,b499dfb3,b2133e4b,a113f2e4,c0e121e5,cf217411,8c8b6d7a,4b48f6d5,34ce5c79,422c086a,63460502,b827ce62,a326683c) +,S(d24a44e0,47e19b6f,5afb81c7,ca2f6908,a507668,9a010919,f42725c2,b789a33b,6fb8d559,1b466f8f,c63db50f,1c0f1c69,13f9968,87b8244d,2cdec417,afea8fa3) +,S(ea01606a,7a6c9cdd,249fdfcf,acb99584,1edd28,abbab77b,5104e98e,8e3b35d4,322af490,8c7312b0,cfbfe369,f7a7b3cd,b7d4494b,c2823700,cfd65218,8a3ea98d) +,S(af8addbf,2b661c8a,6c632865,5eb96651,252007d8,c5ea31be,4ad196de,8ce2131f,6749e67c,29b85f5,2a034eaf,d096836b,25208186,80e26ac8,f3dfbcdb,71749700) +,S(e3ae19,74566ca0,6cc516d4,7e0fb165,a674a3da,bcfca15e,722f0e34,50f45889,2aeabe7e,45315101,16217f07,bf4d0730,de97e48,74f81f53,3420a72e,eb0bd6a4) +,S(591ee355,313d9972,1cf6993f,fed1e3e3,1993ff3,ed258802,75ea8ce,d397e246,b0ea558a,113c30be,a60fc477,5460c790,1ff0b053,d25ca2bd,eee98f1a,4be5d196) +,S(11396d55,fda54c49,f19aa973,18d8da61,fa8584e4,7b084945,77cf032,55b52984,998c74a8,cd45ac01,289d5833,a7beb474,4ff536b0,1b257be4,c5767bea,93ea57a4) +,S(3c5d2a1b,a39c5a17,90000738,c9e0c40b,8dcdfd54,68754b64,5540157,e017aa7a,b2284279,995a34e2,f9d4de73,96fc18b8,f9b8b9f,dd270f66,61f79ca4,c81bd257) +,S(cc8704b8,a60a0def,a3a99a72,99f2e9c3,fbc395af,b04ac078,425ef8a1,793cc030,bdd46039,feed1788,1d1e0862,db347f8c,f395b74f,c4bcdc4e,940b74e3,ac1f1b13) +,S(c533e4f7,ea8555aa,cd9777ac,5cad29b9,7dd4defc,cc53ee7e,a204119b,2889b197,6f0a256b,c5efdf42,9a2fb624,2f1a43a2,d9b925bb,4a4b3a26,bb8e0f45,eb596096) +,S(c14f8f2,ccb27d6f,109f6d08,d03cc96a,69ba8c34,eec07bbc,f566d48e,33da6593,c359d692,3bb398f7,fd4473e1,6fe1c284,75b740dd,98075e6,c0e86491,13dc3a38) +,S(a6cbc304,6bc6a450,bac24789,fa17115a,4c9739ed,75f8f21c,e441f72e,b90e6ef,21ae7f4,680e889b,b130619e,2c0f95a3,60ceb573,c7060313,9862afd6,17fa9b9f) +,S(347d6d9a,2c48927,ebfb86c1,359b1caf,130a3c02,67d11ce6,344b39f9,9d43cc38,60ea7f61,a353524d,1c987f6e,cec92f08,6d565ab6,87870cb1,2689ff1e,31c74448) +,S(da6545d2,181db8d9,83f7dcb3,75ef5866,d47c67b1,bf31c8cf,855ef743,7b72656a,49b96715,ab6878a7,9e78f07c,e5680c5d,6673051b,4935bd89,7fea824b,77dc208a) +,S(c40747cc,9d012cb1,a13b8148,309c6de7,ec25d694,5d657146,b9d5994b,8feb1111,5ca56075,3be2a12f,c6de6caf,2cb48956,5db93615,6b9514e1,bb5e8303,7e0fa2d4) +,S(4e42c8ec,82c99798,ccf3a610,be870e78,338c7f71,3348bd34,c8203ef4,37f3502,7571d74e,e5e0fb92,a7a8b33a,7783341,a5492144,cc54bcc4,a944736,93606437) +,S(3775ab70,89bc6af8,23aba2e1,af70b236,d251cadb,c867432,87522a1b,3b0dedea,be52d107,bcfa09d8,bcb9736a,828cfa7f,ac8db17b,f7a76a2c,42ad9614,9018cf7) +,S(cee31cbf,7e34ec37,9d94fb81,4d3d775a,d954595d,1314ba88,46959e3e,82f74e26,8fd64a14,c06b589c,26b947ae,2bcf6bfa,149ef0b,e14ed4d8,f448a01,c43b1c6d) +,S(b4f9eaea,9b69176,19f6ea6a,4eb5464e,fddb58fd,45b1ebef,cdc1a01d,8b47986,39e5c992,5b5a54b0,7433a4f1,8c61726f,8bb131c0,12ca542e,b24a8ac0,7200682a) +,S(d4263dfc,3d2df923,a0179a48,966d30ce,84e2515a,fc3dccc1,b7790779,2ebcc60e,62dfaf07,a0f78feb,30e30d62,95853ce1,89e12776,ad6cf7f,ae164e12,2a208d54) +,S(48457524,820fa65a,4f8d35eb,6930857c,32acc0,a4a2de42,2233eeda,897612c4,25a748ab,367979d9,8733c38a,1fa1c2e7,dc6cc07d,b2d60a9a,e7a76aaa,49bd0f77) +,S(dfeeef18,81101f2c,b11644f3,a2afdfc2,45e1991,9152923f,367a1767,c11cceda,ecfb7056,cf1de042,f9420bab,396793c0,c390bde7,4b4bbdff,16a83ae0,9a9a7517) +,S(6d7ef6b1,7543f837,3c573f44,e1f38983,5d89bcbc,6062ced3,6c82df83,b8fae859,cd450ec3,35438986,dfefa10c,57fea9bc,c521a095,9b2d80bb,f74b190d,ca712d10) +,S(e75605d5,9102a5a2,684500d3,b991f2e3,f3c88b93,22554703,5af25af6,6e04541f,f5c54754,a8f71ee5,40b9b487,28473e31,4f729ac5,308b0693,8360990e,2bfad125) +,S(eb98660f,4c4dfaa0,6a2be453,d5020bc9,9a0c2e60,abe38845,7dd43fef,b1ed620c,6cb9a887,6d9cb852,609af3a,dd26cd20,a0a7cd8a,9411131c,e85f4410,99223e) +,S(13e87b02,7d8514d3,5939f2e6,892b1992,21545969,41888336,dc3563e3,b8dba942,fef5a3c6,8059a6de,c5d62411,4bf1e91a,ac2b9da5,68d6abeb,2570d556,46b8adf1) +,S(ee163026,e9fd6fe0,17c38f06,a5be6fc1,25424b37,1ce2708e,7bf44916,91e5764a,1acb250f,255dd61c,43d94ccc,670d0f58,f49ae3fa,15b96623,e5430da0,ad6c62b2) +,S(b268f5ef,9ad51e4d,78de3a75,c2dc89b,1e626d43,50586799,9932e5db,33af3d80,5f310d4b,3c99b9eb,b19f77d4,1c1dee01,8cf0d34f,d4191614,3e945a,1216e423) +,S(ff07f311,8a9df035,e9fad85e,b6c7bfe4,2b02f01c,a99ceea3,bf7ffdba,93c4750d,438136d6,3e858a3,a5c440c3,8eccbadd,c1d29421,14e2eddd,4740d098,ced1f0d8) +,S(8d8b9855,c7c052a3,4146fd20,ffb658be,a4b9f69e,d825ebe,c16e8c3c,e2b526a1,cdb559ee,dc2d79f9,26baf44f,b84ea4d4,4bcf50fe,e51d7ceb,30e2e7f4,63036758) +,S(52db0b53,84dfbf05,bfa9d472,d7ae26df,e4b851ce,ca91b1eb,a5426318,da32b63,c3b997d,50ee5d4,23ebaf66,a6db9f57,b3180c90,2875679d,e924b69d,84a7b375) +,S(e62f9490,d3d51da6,395efd24,e80919cc,7d0f29c3,f3fa48c6,fff543be,cbd43352,6d89ad7b,a4876b0b,22c2ca28,c682862,f342c859,1f1daf51,70e07bfd,9ccafa7d) +,S(7f30ea24,76b399b4,957509c8,8f77d019,1afa2ff5,cb7b14fd,6d8e7d65,aaab1193,ca5ef7d4,b231c94c,3b15389a,5f6311e9,daff7bb6,7b103e98,80ef4bff,637acaec) +,S(5098ff1e,1d9f14fb,46a210fa,da6c903f,ef0fb7b4,a1dd1d9a,c60a0361,800b7a00,9731141,d81fc8f8,84d37c6,e7542006,b3ee1b40,d60dfe53,62a5b132,fd17ddc0) +,S(32b78c7d,e9ee512a,72895be6,b9cbefa6,e2f3c4cc,ce445c96,b9f2c81e,2778ad58,ee1849f5,13df71e3,2efc3896,ee28260c,73bb8054,7ae2275b,a4972377,94c8753c) +,S(e2cb74fd,dc8e9fbc,d076eef2,a7c72b0c,e37d50f0,8269dfc0,74b58155,547a4f7,d3aa2ed7,1c9dd224,7a62df06,2736eb0b,addea9e3,6122d2be,8641abcb,5cc4a4) +,S(84384475,66d4d7be,dadc2994,96ab3574,26009a35,f235cb14,1be0d99c,d10ae3a8,c4e10209,16980a4d,a5d01ac5,e6ad3307,34ef0d79,6631c4f,2390426b,2edd791f) +,S(4162d488,b8940203,9b584c6f,c6c30887,587d9c4,6f660b87,8ab65c82,c711d67e,67163e90,3236289f,776f22c2,5fb8a3af,c1732f2b,84b4e95d,bda47ae5,a0852649) +,S(3fad3fa8,4caf0f34,f0f89bfd,2dcf54fc,175d767a,ec3e5068,4f3ba4a4,bf5f683d,cd1bc7c,b6cc407b,b2f0ca64,7c718a73,cf71872,e7d0d2a5,3fa20efc,dfe61826) +,S(674f2600,a3007a00,568c1a7c,e05d0816,c1fb84bf,1370798f,1c69532f,aeb1a86b,299d21f9,413f33b3,edf43b25,7004580b,70db57da,b182259,e09eecc6,9e0d38a5) +,S(d32f4da5,4ade74ab,b81b815a,d1fb3b26,3d82d6c6,92714bcf,f87d29bd,5ee9f08f,f9429e73,8b8e53b9,68e99016,c0597077,82e14f45,35359d58,2fc41691,b3eea87) +,S(30e4e670,43538555,6e593657,135845d3,6fbb6931,f72b08cb,1ed954f1,e3ce3ff6,462f9bce,61989863,84993501,13bbc9b1,a878d35,da70740d,c695a559,eb88db7b) +,S(be206200,3c51cc30,4682904,330e4dee,7f3dcd10,b01e580b,f1971b04,d4cad297,62188bc4,9d61e542,8573d48a,74e1c655,b1c61090,905682a0,d5558ed7,2dccb9bc) +,S(93144423,ace3451e,d29e0fb9,ac2af211,cb6e84a6,1df5993,c419859f,ff5df04a,7c10dfb1,64c3425f,5c71a3f9,d7992038,f1065224,f72bb9d1,d902a6d1,3037b47c) +,S(b015f804,4f5fcbdc,f21ca26d,6c34fb81,97829205,c7b7d2a7,cb66418c,157b112c,ab8c1e08,6d04e813,744a655b,2df8d5f8,3b3cdc6f,aa3088c1,d3aea145,4e3a1d5f) +,S(d5e9e1da,649d97d8,9e486811,7a465a3a,4f8a18de,57a140d3,6b3f2af3,41a21b52,4cb04437,f391ed73,111a13cc,1d4dd0db,1693465c,2240480d,8955e859,2f27447a) +,S(d3ae4104,7dd7ca06,5dbf8ed7,7b992439,983005cd,72e16d6f,996a5316,d36966bb,bd1aeb21,ad22ebb2,2a10f030,3417c6d9,64f8cdd7,df0aca61,4b10dc14,d125ac46) +,S(463e2763,d885f958,fc66cdd2,2800f0a4,87197d0a,82e377b4,9f80af87,c897b065,bfefacdb,e5d0fd7,df3a311a,94de062b,26b80c61,fbc97508,b7999267,1ef7ca7f) +,S(7985fdfd,127c0567,c6f53ec1,bb63ec31,58e597c4,bfe747c,83cddfc9,10641917,603c12da,f3d9862e,f2b25fe1,de289aed,24ed291e,ec67087,3a5bd56,7f32ed03) +,S(74a1ad6b,5f76e39d,b2dd2494,10eac7f9,9e74c59c,b83d2d0e,d5ff1543,da7703e9,cc6157ef,18c9c63c,d6193d83,631bbea0,93e0968,942e8c33,d5737fd7,90e0db08) +,S(30682a50,703375f6,2d41666,4ba19b7f,c9bab42c,72747463,a71d0896,b22f6da3,553e04f6,b018b4fa,6c8f39e7,f311d317,6290d0e0,f19ca73f,17714d99,77a22ff8) +,S(9e2158f0,d7c0d5f2,6c3791ef,efa79597,654e7a2b,2464f52b,1ee6c134,7769ef57,712fcdd,1b9053f0,9003a348,1fa7762e,9ffd7c8e,f35a3850,9e2fbf26,29008373) +,S(176e2698,9a43c9cf,eba4029c,202538c2,8172e566,e3c4fce7,322857f3,be327d66,ed8cc9d0,4b29eb87,7d270b48,78dc43c1,9aefd31f,4eee09ee,7b47834c,1fa4b1c3) +,S(75d46efe,a3771e6e,68abb89a,13ad747e,cf189239,3dfc4f1b,7004788c,50374da8,9852390a,99507679,fd0b86fd,2b39a868,d7efc221,51346e1a,3ca47265,86a6bed8) +,S(809a20c6,7d64900f,fb698c4c,825f6d5f,2310fb04,51c86934,5b7319f6,45605721,9e994980,d9917e22,b76b0619,27fa0414,3d096ccc,54963e6a,5ebfa5f3,f8e286c1) +,S(1b38903a,43f7f114,ed4500b4,eac7083f,defece1c,f29c6352,8d563446,f972c180,4036edc9,31a60ae8,89353f77,fd53de4a,2708b26b,6f5da72a,d3394119,daf408f9) +#endif +#if WINDOW_G > 9 +,S(90a80db6,eb294b9e,ab0b4e8d,dfa3efe7,263458ce,2d07566d,f4e6c588,68feef23,753c8b9f,9754f18d,87f21145,d9e2936b,5ee050b2,7bbd9681,442c76e9,2fcf91e6) +,S(c2c80f84,4b705998,12d62546,f60340e,3e6f3605,4a14546e,6dc25d47,376bea9b,86ca160d,68f4d4e7,18b495b8,91d3b1b5,73b871a7,2b4cf61,23abd448,3aa79c64) +,S(9cf60674,4cf4b5f3,fdf989d3,f19fb265,2d00cfe1,d5fcd692,a323ce11,a28e7553,8147cbf7,b973fcc1,5b57b6a3,cfad6863,edd0f30e,3c45b85d,c300c513,c247759d) +,S(57488fa2,8742c6b2,5a493fd6,60d936e,a6280b0c,742005ab,ce98f585,5ad82208,31b3ca45,5073bea5,58adbe56,c27b470b,af949ae6,50213921,dc287844,f1a29574) +,S(f1133cbe,6be8bbc8,dc8df2b8,d75963c2,d40ed616,c758cdc8,4edbc5eb,4899447d,57fc2447,2225b23f,5714626d,8d67d561,10bd3a60,dd7a1687,cbbb893,f652f50f) +,S(95083e75,3301bd78,7f8989c7,9065bb81,3f3d69bf,f3e42505,f4e0417,5bbe89c0,844adb5c,e7d10de9,4617c73c,a77040e4,ee4e92e0,156b3c70,cc593fa4,94b33482) +,S(1a908355,cbb75675,5e576ed2,9c99af63,8668c7b3,63c8d973,62100443,bc5c75c6,d765466c,6e556e35,2f778722,25627d80,a7353807,4b44ff27,57ad22e,2f2454a2) +,S(c5922f74,bd343d5,aa867308,fad97f9f,8a2d1f63,c5f31db4,f04df3be,f349b648,77b1f068,7cfcdbe8,812605e5,d8b752c,da811844,236a4c43,77f53c94,6e7bd648) +,S(64e1b196,9f910297,7691a404,31b0b672,55dcf31,163897d9,96434420,e6c95dc9,c16f60c7,c11fc3c9,eb27fa26,a9035b66,9bfb77d2,1cef371d,dce94e32,9222550c) +,S(33b2e76,687744ed,6c521bad,3333dd37,c602f8a7,549e9ce7,808fb7ea,7ce08de,e1bcfe7f,c8ed8ae9,5cf6c243,7fdd94bf,d742e8ca,a6de7811,4c25112a,86988efd) +,S(20f18f4c,866d8a1c,c2a31033,17b4ac31,89fbf30f,f294a75c,951473be,45e4f294,8d6857c9,d08ef7b4,fd888336,3d37bee7,fe8529f,7173f589,43fcae81,d2d0ea0e) +,S(4d1623c9,44c9c716,a0eb4c68,5e2a8b9d,2df34653,54643bef,d1444176,d7b69a8b,ddf1b9fe,8744ad03,f996bf6b,96ec3496,2b601bd5,ed952f78,54f58388,8917be80) +,S(a901b0db,e8ab292d,280d6b36,85894785,4faad0a4,dd0da7e2,d4ad0ff5,3db079e0,3f27e7e1,834f1a61,af6f04dc,61e7ae64,716bc5e0,a6b063b3,1d0e60e,47298a9d) +,S(7e0af071,30218ffd,50bd66f4,484645b1,2f42a24f,7c80889b,3031c9a6,ebfc9a70,50bc23f3,926cd0c4,9f53fbb2,35eb1e89,d579517,f5bdc3ab,2416db78,5aaedb3f) +,S(7ba8187e,1a7b25a2,c185d335,440a9038,b47f0528,546e9da4,ef82aab0,5aebf20d,6e6aee6c,9625370a,f866c25c,7ca5dd78,527efbc,e7d8b3a3,9ab24930,9a185187) +,S(8c050fc3,4d83b279,b6000816,e18fca38,9767b796,e926772,55b84a39,d93a6807,986314ef,75b68fb2,827c2965,4198139,5d699fcd,81cf23ce,7019bc41,35174870) +,S(53b7849a,78e4df86,25860583,a5249948,9d7201a2,cbf50620,2a7b8b1b,c99c2ec9,4e31ea12,ac607d07,5de4b22d,e1be2c52,e0a44d25,4728d2c5,44d2ddf9,e3e469c0) +,S(9bdf9e67,a5d0c995,6a075a01,fe762be,b6335004,31dee78e,febc527e,53313b33,94264621,a5960e0e,e24c2792,6f16cad2,907f2636,762e8d5a,17e94afd,8e9d2bb0) +,S(7caa72b3,7a8ab3bd,bac031a,47606f89,17d9f42c,6ec2d2fb,429fd990,4a381f34,5b5853ab,7ee5de8d,34e3d6be,b201094f,ff8fbd1e,682f7f1,ef87ddd6,5d7303c9) +,S(2ef29b9f,9827975,79c0295f,c3f48db7,925d62c7,5532493d,de16b97e,3993d81a,496c944d,d9875ba6,a537ef9,6bf4c714,a0afff24,387d95e8,9b42337a,33110753) +,S(df157cad,95b07875,573c1860,ae5d02c6,4029e952,ec354e6a,9e5c34be,97317ff8,f2eccac7,75922b50,899c979a,2b3cc30,b629e62e,85693ba4,70f6ee38,1284c162) +,S(dd55c150,a29ca526,b6182e64,3b9eb544,e651d236,b71920e7,b15a9870,16454b1d,44c757a5,42f4ea2e,b39605d4,268c2510,ac685aab,d77a8f5c,4d95e23f,4c2e9368) +,S(16886cf4,6ed42c79,19147763,63d3256,c4d5d393,87f01723,25b9e4b8,98227f27,7421a220,7ee73299,d46192fc,93ca03de,c824ed8d,e2f48367,ec538317,a17fffb) +,S(6ff180fc,daa30618,8e8b306,d6f0acff,27968c22,484ff45e,56aeaa7b,2b60732f,7d16d654,f0c2aff0,fc254dad,63761a2,6c8d4022,ea85b8cc,22f3ea1e,f69961a9) +,S(3ea4511,a00dc2a0,3eb4f51f,40ee677c,aa912b55,39f685c4,f8bcc8ea,dc395e36,6c9ed1f1,528b0215,93a39839,340ddb53,a2f2e36,5290c498,24b035c6,73c9259d) +,S(b82cd70,dc3de9ea,b38742d8,f32dfb8d,53e4150a,835e54b6,3c7cca20,f253081d,e8bcbfe,1f7f6e75,d32e2049,9329765f,2effc56,a922f268,60d4bc0a,add0e24d) +,S(fe2fc3e0,748745,84ee23bf,105a69a6,6d056f0,17327d49,b7b38b57,a196c77f,3e18941c,c3c6d297,cc9a32f6,95807b1c,7da8561d,e4fde71d,4f9bbdb6,e9bf3916) +,S(4b90176,cdaa3693,47e8778b,12db9d6e,e8b00114,46ea35ec,845dbf57,4bb7858b,f60547ab,6e9c5fd3,eca6e349,b85880c6,1fdad0fc,2f7ab155,295caaec,b973c154) +,S(35f38251,1d34600b,4b8c86a9,f0dbc9ed,defc4272,f59528a0,cd3ec10a,5944c6d2,29a835f6,ef7fa1e5,f6f37a80,cf96ca98,43762bb1,b12a0dae,ae83234b,d0b5ccd5) +,S(1d74b297,311b7ff,a1027e26,587d3f5b,e1d0e9ac,3f0111cd,f3cc2371,722cb94a,5c7bcf8b,57f114e0,b73bcfb8,10f5c60d,35dc99ae,9dc7f0e2,606cc1f7,28c2071e) +,S(50a094f3,9c6f956,b020737,b9ec722e,4f75d1b7,c41593e6,f934a68a,98450428,a286e222,dfe10cfd,9689eaba,6a81f044,89c86db6,869aa1b5,54a90f1e,83778eee) +,S(9b65bb81,2129157c,dfecf12e,275ec38c,282dbcd9,14b48105,99b0a6d6,27c63db7,c582db1a,3f0f2242,1913b2e9,51e98a78,660b4c40,ad08fd65,528593bc,18223188) +,S(8b4544fc,1fdfa06e,456c1115,a1dc831c,85e7f1c5,e620eca5,1c20802d,36a4bc6b,e3e77c41,288f2602,e722af7f,4b70e64d,e4116fb9,955b03b0,6ea8b19f,7a20350d) +,S(6c709880,b959eb7c,5179b29c,c5578fdc,6cb2ae13,ddcede29,d5f81d95,de0ab4aa,c9e33fae,bd8eba42,6736c0c7,6f3deaba,ee2b59c5,953fb43,c2dcc513,9e7c4bdc) +,S(77760b51,37ba6a71,95d891f7,94a087a0,76fc9d67,802b81e7,85b5677,3d537806,f5202cf5,aaeea58b,f4f58c7e,df4417be,1b87ffde,e68e77f0,d7e81abe,158e3a25) +,S(1a8bd783,6a0b0c82,e9a904a8,a8c91a67,e23cd4f8,efd625d0,df4c426e,7e163102,61fe64ca,b0952cae,3c574f28,2f74a87d,c2a96316,b7009f2e,4e9c5fcc,12285844) +,S(fe217db6,59079913,fb1e453e,d24d91d6,a3fb3099,e69471d7,53db5390,864abc30,5dcf9abb,a9625ed6,80b0f20f,b1f047d5,93a0c61c,53969253,8cdf6b03,4d730b58) +,S(2504d637,54afd5eb,c38f58b6,5ead696d,7e3abd7,48cb6c5f,212aed49,f5b33b91,79a6bf43,75f1469c,4f5321c6,c72fbbf4,ba7cec10,5675f437,b5e013ad,7b5d75d4) +,S(b06f702,f47b22d7,89a9bd3f,687105c3,6160abbf,5cc8976b,7fbddcaf,db197b5c,7669bbd4,19a4d491,f592a35b,6aa3dfe4,5bd2fe7f,d179c778,1cd5f918,d732f63d) +,S(803b203b,b31f9cf9,4034eeb9,31b54480,a6f3f99e,bd23d0ac,bc2128a6,d044e23,308abc8d,f271f759,59b20c5c,7fa62baf,bfc9ccbf,49b946a9,54e5381c,1728d1c7) +,S(266a9cb4,c5f5cead,bb50e5bd,a03a7312,e52de1de,8e95a8dc,d57289fe,302749a,9eea970b,a856b2fa,a3e82877,cc84ed4f,3dc0efba,1e7c3baa,8b386ffc,46e0ae7e) +,S(fd8a9d95,d80c7ad5,2599a7ab,98163df3,64c4c141,e9abea35,5d7360bc,f84eba94,a9fb1702,100953b3,59b2e268,8ae7fd33,a30377da,47bfda71,3e2d7d73,dfb1030c) +,S(a7322df3,9f28f23,59fc339a,8b2c80be,6e84acc5,b7b0b8f8,f2cb6f26,f9db0a7d,22f6fe9d,21749501,7fdb7f5b,2f12fa57,95f40e1,31714885,c12a2ea1,6edb6be6) +,S(82a8c10f,336a6649,63a104dd,bf7f0f18,bd4c461a,ea569ffc,82c3c7e4,cb052d36,737ceca2,c0ef7227,8b90501c,cb71b671,5e5c31d4,cd0478c1,18fe1287,95f1dd0c) +,S(9b50d1b6,8e3bf795,7cd12f,5a60c26,6c4ef2b7,5ba5c516,c54784a9,4f15d6df,2afc8d09,b79176d8,d003fd2a,4f18d526,403fff27,2d47e778,7376feb7,cbddd8fd) +,S(3f9083dd,c8b423fe,7de3a822,81d3056a,b8dcb9d7,ee82cb80,6718595f,bae08d32,cb13c152,fd511d91,a9e0ed90,afa021a0,81f77f6d,20cc1376,e2195ffc,f28fa758) +,S(c75c85c1,ee17c1a2,56eff6bd,592666cb,c9231706,59d50bfa,dbd1074e,f2167faf,1ab4eabe,5e09409d,75cca892,2647f48d,bd698a16,d4f7cc85,96daf169,40023a52) +,S(c5341fea,f8a0f5d3,b4d0cf0d,2f7aad7c,60ea8e2b,3d4b7fb9,5c68d576,98656045,95f9f4e9,7e5b9f,a48fa422,a26ab982,dc48a4d5,4d712398,6e6d3ab9,74e88915) +,S(83acda3e,2a8997e0,d52bd4c6,8705dd22,220852b7,752d67fd,8967a032,60c2d89b,dce1bae1,d655ba51,7f5b5580,99711757,a77cd3b,dd4b8e8e,330e9779,1bc31df0) +,S(5b819146,8b299074,5b9c4164,e29d594c,f1c0d571,6c5d3962,5bd279b3,25237b,cc3636a0,3fddddfa,bed88daa,b081f359,1c48d2ca,71ba34fc,f6989f4a,f7625d8e) +,S(64778122,214e38ef,f8041796,166104e7,32f5f664,d38d7721,9b89045e,2c3b0e6c,329cf049,7e15eec7,b8eafc4a,b8a7d1c,d8b63203,8d4aef81,974cf984,4611a32d) +,S(ed4d826a,fe5762f4,79509909,9aee8664,2b475a9d,6da1017c,43d0cb9f,1af12323,8c6f81be,3fafa5ee,c8296f92,8ac7919d,c4d88c9a,59442274,d0531b7b,f7e48e78) +,S(38b42924,419aecc3,acd6f551,346fd61a,4d82ac2b,55f7afe9,7a06eb40,cd109c4a,7f42c096,2feb2f73,b2b0965a,1f359a6a,de49d768,a2ce6b07,b5acb92b,73e05583) +,S(c3cad4a8,d8bb94a7,b434cf70,183e8615,bb2a8f62,24f216e3,446ac2e9,82138911,f649be27,8cad9764,20742ce3,82dce3a1,420e372e,f1b25b27,59a8ed38,7282765e) +,S(2d408ff4,d3d236fd,54fae40d,ce3ea9ec,d9212e57,36591a9e,55588e4a,54bd6538,d596adf0,e8692a06,bc6284bf,299bef6,85e2a171,585aa132,4b9a05b5,ce815b7) +,S(ee7adf6d,247f25fb,76e90cf8,13f888eb,d67423a3,a3c6fdae,bafb7eaa,7a33c854,e077184b,4ae8f705,6c10dd9e,f541689d,143f6871,789e1801,deaefc1d,527a8fb4) +,S(2f9457c8,a9ffaca1,3d91151d,c4c5e89d,dd5d37a3,7c9a864b,7c811f3e,1144b34,eb4c9848,9093d573,a295407e,1d6fc48a,787120ce,b3d3dcfb,b40634e0,e75e221d) +,S(d3f332b8,a0f11582,1ce3478c,efe18de3,60120483,ef531c27,7b30c46e,b7fec294,ea75b9b2,5d717861,d1af1c01,9c372941,c8968b90,ef134f9f,323215e1,bb0b2155) +,S(183408d3,38b05aad,3521fcd8,6ef36dd7,5f3ddb86,66b52f7e,9a4cdf1f,8e152b91,66998520,6edf4ac6,f39be21f,20c98824,210e204c,e4499809,5de35537,1641218c) +,S(283fec5d,b1145e53,ba8f1f0f,f9cf89a7,21faffd6,c2534686,3d395609,5f40374e,70b01237,74af550e,68e68e5f,65ca6e98,8846e03,cf39af77,8511be82,bc32fefe) +,S(ce7570a,4f943cfa,413bd249,d8e7dbfc,ebc73579,770fd6da,f54a0dfb,dd52fa62,e115b14b,ef4695cf,fb85bdf9,8ba3985c,bd5e5b89,83e05390,7c36f9ce,8b75d41d) +,S(7e9c4f19,c8f4ec3f,1269f648,cd919525,df790315,74cbeb15,37794a4c,838fd470,e9d9dbfe,8cf5f5cc,a855d6cc,bd11f480,60fafa8d,ad6bd3e9,c86df5ce,b0fa5270) +,S(e2a9bbe6,d5d5bfe,a7c7f919,df2309f9,ba04f4c,722a3ec2,3bf451b4,64cb001b,e4177ce1,c3cd6ac7,78925bd6,7e72cb77,d1925b91,d06a7f16,98411a47,86393fb0) +,S(504512a4,3e17ef50,e43bf37d,42a94990,f55e641b,1558c265,e7099002,75271012,954a5fd8,57ba3acf,2d4b1f41,e8e1f2cd,1f21c4b9,6899781b,742a49d2,e61ed18b) +,S(81d1f013,a6bb325f,4b2d1d51,ba72c721,859945d8,a17b3411,cd5cbe87,285f850d,2d5d2fb1,f0c30855,3b1fe249,298b2059,259d3d49,d4d7071a,dce4bcc5,dc937193) +,S(5b66c2df,c1d28266,18a87276,7e66c33d,d90dd514,14a3b87c,a733383d,1d895022,9bd0178e,38189569,2217267b,7407e987,27fcaeda,12d8cf54,49eb5472,d554e0ff) +,S(aeb5f70e,98ec5e38,dbd2d544,bdbff8ab,99b583d9,af58c597,afaf8688,20381186,618bd6b0,d25ca70d,f08b7692,9336e421,691b0973,f2f5a05,2e7adc17,3584427b) +,S(b289eff,e841943b,84761e3c,67a9c02a,557679ca,76ad753a,707a9821,2505052e,7a981f0,c21862a8,53b4f895,dc62482c,530ed738,5e5d1e33,cfb9d0f,e879992c) +,S(abae3945,8b12199e,6b0c8360,cfd28288,3f585917,e44e1200,f81bd356,f619291c,adb23bcd,b3d069c5,e83be30b,2469b068,b2a81b7,b667e934,233b75ef,b5753f28) +,S(4a9583a6,485b5a5a,81ac224a,518eb29d,1e0f658c,8d91b013,9419c809,55fbacaa,d8003c9e,e3c842f5,ede375a8,a7768db4,803ecf11,9b7b37de,cea15631,b4e8dbca) +,S(d52f630e,dba6f7cb,65fcf465,44ab0d9e,ea236ac1,460f17ae,3a210102,10ebc169,21155748,9fa93b88,3e5bea50,da005c53,68e21a0c,41bc83d9,145c13e1,370d26d0) +,S(bdc5237,82c75858,f5c50fc0,52e4c1e9,c74a2a63,35bca9bf,8d10e120,9add6a4d,abb1d9f8,74637668,e214efba,fbf529d3,12ff023b,c1d5723e,58540436,6834f189) +,S(44770a33,8bf0aab8,3bb64e47,6eb6167a,88156d16,8f13ce86,26ee0912,e59ad087,5b5930f1,2e9c40bc,b3393a89,5c2d6457,6a3abd23,b7291b99,c965c33d,ef60a55c) +,S(b15e7b32,2e404aee,319ac203,23e36672,6503108d,8ee8e1c8,3e32d924,515e1679,5246a819,bbfb291,5f82ed56,50796f50,5ced5c25,87347d57,a873ceaf,3d997e7a) +,S(a1ed7557,5225cd0,f2c50f75,8a1c1df9,665ae108,d5e04190,27bbd9ae,ddb00f22,3c83145d,ad9f8748,7b97e746,4850ed02,d71dbd04,93281a1,3d212776,6a791ee2) +,S(e8aaf361,6a1bc60f,d9bfc43c,2c60580f,479e9ec9,c23a37a2,3cf8afb3,1d918af5,6ce693b6,4a37c672,7e141041,ab9a0d58,9ab9c303,a5ac3d3e,c89b6f27,9e79827c) +,S(5dc6f8cd,2c855e63,52a4a4ef,6187a6d6,759c043,38a3db76,c5a3aa37,54c20a3,f602c342,8593a9a8,d671d1bc,7c1d8834,fe9f5f5,2e6a7f0f,bb870146,4e6f4838) +,S(63327311,67bed8af,68a063ef,22aa489c,f6563620,461af26a,5f1a07cb,6b42f3a6,b8f7c3b2,20701320,f20ca036,761d3e56,bf94a700,9a919f1a,3ea0cb81,b74424a6) +,S(8a40d925,9a393b38,2305c201,7e8654db,ad66e50a,d798a0d3,535230f9,48080263,afb6a74d,9849454e,dd7f703a,5c6616d1,43f9cbcc,9a9a5d6f,6a7b5d1f,9d9fcaff) +,S(e7147107,27c7420a,f517fd3f,9a05b7de,a6a02c8b,cc20b17d,cdfdeaf8,2078645a,da7d67cb,c1ede9d4,fedd5dcd,c96b04f9,a3561ba0,2581b055,eaa144eb,4217daca) +,S(6131291c,d95fb878,1e42a68,553952c2,9922bce8,91c026c0,cae1f69c,9661c82d,160e1c1c,13342fd4,59d4f989,8ae632b8,42b89479,13733b89,384fc104,2d30bf01) +,S(4bc4f845,b6764692,d0a9bfa8,1788809e,fc5e2aa9,da5003bf,b782bcf1,d1ca4951,87092dcb,b9c3d254,e3b055ff,3a76ec05,64c4a7c5,7fb1783c,efdc40fc,10b751f0) +,S(45a880a2,7bbee9df,29f9bff5,c985f364,52865b5d,582a201f,698e6eca,a2be67df,fe49a6a8,b5e46bf1,ef679714,dabd590e,a831d46b,8ee94eb6,13132ba3,7855fabb) +,S(6a826a38,317c0c86,64d6847a,220145d1,877e5495,b21500d3,f21f1a0d,4af4f2a4,4521954e,fcc98263,df2f14e0,e6e6b47a,f6b83f0b,bc20722c,15445f87,e05f4513) +,S(15356506,f255f7e9,6cc8aa1b,9dce572,8bd860de,7c6cc75f,613e8a34,366a23a9,cd15abbc,d744d485,d5e401f,1f89a5df,122f37b4,e362b4ce,e3e53b1c,110bf3) +,S(f3bc12ae,f53d9f5f,6b865178,2dac2ec,cacff3a5,cca6443a,2b5e1ca0,f2b89b91,cfd4d36b,eb2e11f2,41fd0f36,7a0737ad,303e915f,f247f131,368ca509,18e00957) +,S(7e3c8c6d,fa04a536,f7a26ef1,8b387649,22320bef,58453373,6f728297,335c0fd4,72ea16b5,32a7336d,3332400b,303c0236,b6a1294d,88ce7fe9,15571284,d1f7c189) +,S(198cbfcf,a0575fc2,c161c696,d85155fe,6943ab9b,d6e17223,d8844608,ad0369d8,d5e6268b,30952422,be59fe0e,fe7ba2e7,3215994,827a46c2,f2972b26,153cf7ae) +,S(1e056e89,b68cf35a,22183c08,9089b90d,5a147caa,780b1fd6,3aeb1350,afb0e5e8,b8241453,abc44c57,ddad6ff3,86d416f4,3e258a39,c6f8837,9f80472b,943f32b9) +,S(dc7ff974,8d827e7e,a6173b2f,1a646d47,d8108144,ce7f98fb,3fac729e,72faaa21,c1fdac5a,ef4c6f0f,fcb8e1c5,c4417c71,3e3d5f07,146daa1a,aaf2e7fe,e70c4914) +,S(71b95efc,c4981e07,5354bc1,1cdfbc48,36b2eff0,bf8f8ec2,9a99da1b,2fd28e79,fd5a3197,6fad6aee,c304752c,c3ebbc51,1f3695b0,9a737fa3,af42cc6,efd684cc) +,S(43854caf,29dc2bd6,c9f3e8ff,a25bba83,f6b96121,897044ae,6876883a,de542b3a,56365176,897632f,8dde3167,7a24f558,34c5c9a5,5c1cbf36,fd8b4480,3c9c6c81) +,S(2adfe17,90e9f9c,708c9b73,d5fd084,b6eff990,fb877961,45c2ecf2,d427b222,b5ce3160,5d6dd9c6,22cae425,ccd28912,c4439820,c06950cd,4c86d9b4,53abd7ed) +,S(a123452c,2b7eaf31,15b3a534,3b3ff31a,9f70c54,ae33c620,471e3e82,27a9d6f9,933d3483,78a71f44,3788194a,afc545e7,f53e37a6,f779f96e,8fa14ccd,ede3b4eb) +,S(9b89a3c2,ca995a81,86c15217,61348737,aab166ae,7decca60,3d06e32c,cec0a6ab,2a7d3701,a8724b12,bd7c4830,224ac083,cbea83d0,543b5414,80ba8c8a,e7731232) +,S(64dd7457,e7d9d739,8e2b9a0,dc45272b,384b0433,9ed8b2ed,c9079646,11e9e9b2,ea90f8aa,e214ee16,ed608a72,36699899,4e311dc7,780ef885,b29290c3,823c470e) +,S(59227431,be607c6b,d327fd71,4eb71c87,20abba42,1c7f550a,6b35767d,6fa2176c,cb7571c4,71c5527,65bd289e,a3cf3f38,796da2b1,2c953d0b,8705125c,4861d598) +,S(53d765cd,adb26e9e,1c80ddf1,99374363,843b7d08,a7237bdc,8c5106ef,795fe2c2,7bbbb198,eb39973b,76d87f81,94d45150,a66d4f3b,128a40be,c989a405,ad7c287b) +,S(e507de9e,c16b3bf3,523a989c,f5ff6c1,452ee90,9b66ffc1,6d7b519a,57bb66af,a2f2f02a,8272de6e,3dc8b395,8959ad2,51b6d3d0,4c81952,59a501e2,8ff7892a) +,S(16f48c6,eb84fb2,81903b8c,b9f60b7a,65601d76,e2a57983,5569c983,39b4a6f2,8613bb84,8398681d,66f1e75d,5b6ef44f,d827b629,f4956a4,41d8f503,dd32b289) +,S(650471ae,774265e3,270b5132,33d12d85,bb98e38,2a3b3af9,cab6339,e1446056,838e7793,34aa6fe6,cae90a62,d359c339,187b4032,15d97cda,4e62724a,a5a50306) +,S(15dea416,fa34584f,cc90e19d,69825fae,348d1ba1,fd7ac821,559aac2a,bc21dda8,1fcabf2,1e19ce68,ee12a3d2,84bd1304,10fa5f5,d45f9c15,d4070243,a8433047) +,S(b42b2495,4f1f70ed,3db90087,8357ba46,ee9d6a07,b4f7c751,dc5cba07,b05b46e2,e15723eb,e0bdbe6,d6f28d6d,a0443c63,4851f5b4,c551bec6,9f9196a0,969ed71) +,S(8e9e4f5,c6aeac31,1dab1125,dec9b460,6ab10b7e,8e250960,a17fc57f,c0230f83,ffb0e211,c79fbb79,78bd4e53,a05a267f,f1e32c34,d6287dee,64576d31,ab959ab2) +,S(87be7323,73bd4b73,8627fb63,bd4d50bf,d6f2bb81,f804b528,29549fe9,3fe1ac2e,f6a9186f,f147b9b5,ffc844b2,ec0e255a,1ae5537d,75624288,ce8421f8,7e94e1a4) +,S(43601d61,c8363874,85e9514a,b5c8924d,d2cfd466,af34ac95,2727e1,659d60f7,8791c000,7c09c94d,b328034b,88c5bbbc,11333536,6679eb09,9a5e75b5,83bc2c2a) +,S(341b1580,f83071c5,365f0bcb,ba66af96,6902e394,2a2560ac,a0daafa3,2ab49d0d,4b985b13,c5499026,7ff564d2,d4649c6f,7e8fdbe1,ba101d94,1c034e14,64877b20) +,S(175e7cb3,ce4a3a43,7c7181e2,c79fb154,33ac1aa8,e56492eb,57627171,f14dad95,31ce61a8,7834f52e,fcf8703f,93696f42,58130155,63ca5d9c,e92d8fc2,81135b0d) +,S(5ad430cc,64e61c61,e3b3c848,2ca3ecac,89c1e495,4c80ba98,249e45c1,307165ad,bea2a060,505c13bc,317ca083,c5a8b85c,9ead5f6e,1ac23fbe,ac7cecea,9251c791) +,S(41dce0d9,6dace318,988602df,7fa84c1,80f0ce3,dd7d09f2,8aefefa6,db8b837,74962c3f,ed9a6e9c,896635ea,855323b6,8850091,f84dee33,3cdff8d0,d2827928) +,S(a5ef4498,87104dda,103c1dc2,52067643,9aed2d5e,432fe5b,a23cc142,39961bcc,1cbcf83e,a363e0d9,3e6ecc32,8653ba7a,a165c526,765b09f0,696b0d61,f122db3a) +,S(4da26ece,9ad46003,38bdf68b,852a2cbe,18225f2e,2d6d5e62,6db57235,fb3a9d45,d10b5a63,7ab546bf,cc610e2d,1c3d61f4,61b0a806,e7ba29c7,3d3de909,e9fae659) +,S(6e621e6f,53d2408e,488d8eb1,6a19a4f7,e9d95585,11e69111,29dedc69,f98f4763,7b148ef2,73e1b131,341ad477,9342c7bc,7b945a2c,b52c448e,4bb5fd50,3cea1a19) +,S(ebaf5764,5bed7469,9b57ea75,8a395a90,66bae20a,8f082ab6,da4554d5,278be83b,5847f4e0,6c653033,5e29ea94,389ee3e6,d916314a,60126028,650ab9e0,bfcfbba7) +,S(c0f88a71,711b632d,24b55dbf,52b15d2,faa38ca1,1438c17a,6a6ff635,3310182f,2cbfad4d,16c07021,86611eec,408082fb,fb2e9898,141a5248,1c59e44e,cd0676ff) +,S(5d9b6c18,84b79498,c6244fbf,262922c6,dc1cddb7,3cf70ae0,1b5287b0,5b5c6350,328e831d,2f2b162c,4abe1644,bb54cc85,18db178c,5b6ae97e,5e85110c,7d7fdf1d) +,S(d1d1360f,37ed6e69,d4f214c6,323a53b7,e57d7595,55904016,654c49f0,4e02e21c,627eea93,c6c9b53f,94559414,40a8b100,6eba68d4,6c922b6a,1521f394,6dd15e4e) +,S(efc987cb,f1023af5,58acfa18,97b1b2b2,ace29a83,65674703,e4969ccb,ee411731,195a6a65,d3790bec,71642986,3bcef432,e38242fc,9f565dbb,e159bc42,f5740c69) +,S(f3026b97,163df3bd,61b88b78,73864480,968d1d7b,83ef6b01,31090faa,18284ff0,177c3a61,682363ab,bf281615,d59f06ff,5f87644c,84d670e9,a6c56ac1,b611509b) +,S(5d34ff5f,123b5b69,92ac92c6,8c9cff46,deeecf9,68ff830b,5622090d,682c5873,2d1a0b9c,8eaba065,43204df1,48eb1618,25443efa,80f8aff3,d49b6626,c5955ac8) +,S(cbf9ba17,94a95247,c39da065,84308cc8,e0ee591d,31a9b0bb,dac67280,468447f4,549b18c3,10feaea1,225fade,934112d3,4058101d,74f00538,1b82796a,d0461736) +,S(920975ba,9e2261b,bf5982a6,b57a7344,8e7747b8,368d7a53,79acacd4,c7dcd31f,e95e0508,81af550d,9221f5a,e9541031,6367d24b,d545bdcb,434e7638,acb46dbd) +,S(815b2ae4,6fdcb55d,926cdce8,2b4f25d0,39132312,3bc180ff,33fcf132,7eeca64,62f637c6,7d886374,8f1e2e26,865118b9,99285b87,55f25512,c968b4fe,49b8c971) +,S(1bb9a6c2,8e28d4ba,30ea8639,7a4d387e,27ca8025,da231926,de3c454,f7e0b16e,a0cbc016,5e32171c,8184265e,ac7e0147,206349d5,41035a94,f56efc49,dcd7ab93) +,S(6f0153fe,dffd83ea,b099d29d,dde278f1,9c05a4ba,78eb4c3d,34d337c6,da68bc22,a532d00d,35013f85,9f4041d3,aa231f2b,9fc49967,e0e2f82,4d5051f9,e7f0c626) +,S(3454f73b,3bee77a4,d00d384,71bf555a,ed23e5e6,c6dae855,2e9cb7a9,1b20258a,92c20846,cfdf1e8f,3fe5bcaa,6bdedc3,9926833a,3f40d28f,23a8f952,d8d18dde) +,S(367807c9,a3606b4e,1b8c2616,ad528030,1dfcf686,40eddf02,fc59317c,230e9a86,1f023f2f,a2bbece7,3dba14c,124095cb,fdc4f92f,281a14,8304a412,c16ecae6) +,S(8ec4fdc3,9891f6af,1374e06f,c44b815,1b82541,75fc4909,acba5941,201af62b,2dc6cae5,cac2d887,83dca0e5,3c798f8,fe067bcf,5fc29751,13756cf7,ef4e5f1b) +#endif +#if WINDOW_G > 10 +,S(5cc24a6d,4c5b24f9,14542f91,e5fa937f,ffa08551,51b8b842,8729b06a,9178a263,b1da8635,81531a1f,bfb38a4e,419fa1fe,ca8d55a8,3ddbcb98,da19d5cf,fb7da472) +,S(83905926,c03905c3,a9644a6c,da810dd2,92602a50,50c52a21,9134fc4d,e3599e9f,4293260f,e8af6792,a20b115e,aa837638,9094298b,21d9de16,cf20e0c5,7a46089a) +,S(944b097e,4721e9dd,f8204ac3,d3878fa,e8fa6c14,34ae4822,481b2985,6589b6c7,5fc47565,30e9b095,f8b79643,1e745b99,1525bd4c,4764e8e,e8af4b96,9bd6ddf6) +,S(ab0b4a3f,cfb7c134,e1caaf04,a63a7331,17327a1e,5fa90301,7b5ebbf,3423b73d,e1e79263,a5bbba8a,cd78c92c,faeccd3a,b84944d3,785c0781,3763bf1a,ce96c9da) +,S(57a344b5,220f2b0e,f7bf7fbf,5a2e4e7,1aa2c3d8,7bf090bc,f803dfee,fe8b85f,f82b7d0e,8ef9620,e48c9f13,53a72a95,a9e11a3c,1678cf10,576e639b,b1a7d04e) +,S(6e053e1a,800b7c4c,51f8c4c9,5cf0f4ff,3608e396,ec46188d,a1a9263f,c8d81ac5,86389e98,e3c823c9,e1b5384f,fce428c3,62e36579,7202fdba,dc3d8c49,395e7473) +,S(62d76406,1804717f,b30d4a7c,7567b545,48a289ec,7f083f1c,59deae25,ce485cb7,f1d6314b,661d1f8d,8531d57b,9470fb53,d1509b2d,a626a0fc,4cafc941,b668be84) +,S(e5db28f2,219fb2aa,830cf108,bd2449a,5c4d0800,82d34658,9e347f31,dd29250f,c296e646,32f97dd5,ba3b7012,ead44b6f,324fcfd2,f35f8b24,8e58fe68,888bd453) +,S(4725b3e9,a3d00de4,8a53177c,9fff831f,733ec89b,c2994ab2,3fe815f1,9b32729,ac3b7747,de38c00f,145fdb74,1482bb52,324127cd,2979ee12,d4a9e689,b9f8e778) +,S(d0d3afb6,492c72e7,394ed918,7013e347,b036b65e,a76e0569,bbe9e346,41d72b3e,2dd3a45b,94aafe07,53061caa,a28560,bd952b0b,2f63f13,96f42fb7,8e02fef3) +,S(7853e735,d717c857,97b85654,a24acff3,104143ed,cf4b4b4c,7869068f,c304632c,a873d9,e70fd14a,c2777a8f,b5a02922,bae3a31a,14938e69,cb535355,de1efadd) +,S(6db26b3,7d4fdc59,13a1a01a,14c92356,ee44e2c9,7f9d72ca,7789de33,8ee904a4,14fe2225,bf2ba0cc,28c1c409,e9849c4a,d8adf792,63869b68,54a28ae9,631941fb) +,S(b52f0869,bb98af3c,b2f7f5c,669fa43e,538e400f,63a9cce6,99aa2ef8,eb2848df,24566b24,55bc454a,e7b378cc,a0e57b6a,8b821c8c,a76fb858,bb616e17,8907be5a) +,S(8614dde1,1ee6af03,eb34a9e9,970fa7c3,234152c0,1384f7e4,c1e1f93a,197b448,2a1125a2,ac996870,2ba22b5a,d230c40e,4e5c7e55,d8ba6ba1,5e54d3cc,7b72f3cc) +,S(982a37ae,625f6e5b,78e71c18,f20bdd0,8b3308eb,59d0cab2,dbc20937,938c1cfa,671fe16f,a65128,591249e2,b5070bf,2a689e2b,dd6c57dc,18e5309a,b6a40d0c) +,S(6bea9305,26b4829c,ec99742f,c9231c00,627a09af,22ca9d9b,4081a2fd,4c3e703a,aec5402a,54517b4c,1f344d14,b1943e69,d7541f10,c45bd483,2b02b059,499a6cc1) +,S(b5724781,8694487e,7cc188b3,36d116b0,54016a99,20731920,ba7bd29,96583edb,5cbbd186,1f80a4bd,3d58262d,ebc58ffd,1d278fb3,b4d7fec6,208f6286,77845cdc) +,S(de1ade62,7ba00e91,786f4f53,18ac5392,4df5a534,704edbb6,2e0e9e2d,997c5412,7ef486c5,bf23bfb,fc6dc15a,41c0673f,a9d003e6,e1d09a8e,4bffee9d,ae2021e0) +,S(3738a57c,b1721c41,9f9e465d,fb80e1d7,33720398,bc01166d,d476d36f,3398c0a0,e1f25bb2,1662b16d,6d28a629,ad84385a,43df566c,52924bfd,11854a78,b70c22f5) +,S(4cae21c1,6b2a1239,a85575f1,2ddf6daa,1955feb8,b7502e37,6940006e,7a81885d,2affe855,388660d8,27671e89,c82832b2,25fa2c9b,29d559e2,37af565c,b4dc99c3) +,S(4c511a1f,ba8a0be3,6e37cf55,85bcc3a7,97bfa7ee,1baa6039,5732faf8,dcc2bd7b,ea69f794,5c6babff,23400fd4,a95d6833,abb27269,887c372d,8a6a45ca,b25651af) +,S(d811d8c4,323b4370,2607c25a,de936c0a,c2e4a44b,2ba51f83,20c5179e,745a7e29,6ff970a2,17bf47f8,da0aeab,cb490e3b,46c6df3f,69f9e93c,3c4dd94a,e7c05345) +,S(101eb5d3,b5e5aaff,e39bbafd,f13b5ffa,33db68ae,1fb09b0b,1cae25e6,16c43eee,9d6a5514,9867725a,607a1c96,eb03120c,a4970939,34e0cf4a,1631a63a,bac5ddb3) +,S(89eb1152,b8dde45f,e141f21f,62fead1,ecdc7f70,eff8f968,de21cf8b,72480519,f8a337c4,3181e3d5,69ec99d7,f2bc4770,cb6703a8,63fbd95b,41fdb07c,b697b447) +,S(53d633f3,f48ea44d,273d8f1e,455019a9,49d95eeb,68de70cd,bd1e964d,9ad0dc16,1b26ed76,964dcf1b,3f7fe6f3,2e6db7e6,8e8ff4ee,48fe63af,48ffd33b,cd1645fe) +,S(de106910,49891106,59a94d26,b9cedb64,6ce3db4b,8398ad1a,92f8f95f,d8d9be6a,87640b41,dbd99d16,578a3d06,d23d4088,8768a4e6,dcf83e7b,5b9d9133,5eb43d32) +,S(40ed1e6f,b9ee245,ac189a9a,7809da10,cc6daa7b,41a163ca,f761773c,6af5bea2,ffed1501,7298fb9a,78eb7bdf,1430ac04,82bae82e,a7197adb,50bcc1e1,fc217b2e) +,S(55faaaee,59a20b9a,3784d171,9ea529cc,1b7ab3a3,29f26dfa,a3b11bd6,67ba15c1,a9f8939b,52ac53e3,5ed4771d,8e47065c,d7f2805,a7e5475c,37353ddf,182f4a65) +,S(b51de64e,21cf88af,2180ca17,24956d10,a95ac607,f034fccb,a53bd02b,fa8af3fb,175d9b70,1c652ebf,46b99f1f,6e66c4a6,9b840019,a48b1ac4,878b386c,3b7f81e) +,S(5156b0dc,bcd91e82,4bb235be,9367cf40,7b8927e8,cd874171,556f997b,7b07b143,1d457c0f,a29d4c3f,e65ded19,1127016d,d40ada90,cbb0d8de,c2af4bf8,20cc91dc) +,S(3bf51d72,60b4973,161fac55,88e441a7,f1993c06,791b6bcd,e11d8e,96dd63d,7bc6b470,90a7afdb,fc63905d,df698499,73e1e4e2,af74f126,63eae8a4,f4722d49) +,S(d2971091,20088102,1154f4d3,ba6f2da1,22fa74c6,4faae05a,d76db7b0,9ad61fe5,7350ebaa,f2ccf3c8,f940cc14,151c23c2,bc33cb73,65528156,92648f6b,628e3fc8) +,S(c2ee47ca,8e17112f,a255a520,21ffd30b,6d7a3b7e,2341526c,559b60a9,c768013d,2e6e8b6b,d83b7f5b,1dc8e83b,edb3b23a,80d9ff08,2029831a,45305016,2bece448) +,S(559998d6,9ddcce0d,9e0da39e,96cc4c00,c5ef444b,561dbaaa,e475adbd,3e70b6cf,c49c2a00,95aeee5b,8deb5e8c,db4d21e4,cf0f3173,1af2fac5,25c534c2,34ffb328) +,S(4b4b02c3,e4c8badd,e45305c3,9721a98d,7c1955dd,90dcb2f9,e9d54901,6bbaf363,a0b67b7e,be8f59b3,c25d546e,3dc304d,d22a6a64,615bcfb9,25b685e3,18d43468) +,S(fbafe7fd,7836b427,51cf897c,5d42897c,7650ade8,ee1ed01f,e0d7dd2c,aac549c5,2f511943,52d07e51,7b7841f5,8eda5225,229a7e28,9a453aeb,5e70110e,12668436) +,S(ccd306f9,c65b8a0,7884e620,b73ac4e6,81b21bd0,2a4b219f,954de1b6,7076c06c,823fa47f,a7b0b50c,907056dc,73e04574,3f68a7,5a4c8566,8ab5f5b1,5657510b) +,S(bafbd838,995a691d,3b5a870a,7847452d,9124155d,d89a9980,820b8d56,18195a3b,8df4c9fa,c94829ee,fb0e7f52,1020b5b0,4f05f4d5,839c8687,4e893e7d,8ad92a3) +,S(d125cc3a,8073156e,a166af8,ff940a64,713d8f37,b86919fb,157cc380,224f458f,a030e8b6,ac4e37a7,df01054a,ea23a78e,1bb7a22e,f26052a3,a034ecbc,bc35abde) +,S(7d491f28,1b5ddaba,ef2c6433,be22e42d,f2d1bbfd,8a7e8866,8cbf278e,cb8187c2,ca18161d,70360966,ca381ea3,f760b2fe,28b040c7,ebc82af9,bea27ba6,f4dfe8ed) +,S(31ccda33,9f29123a,86c2995c,6a9f4979,6d70a595,5079b961,6015f07b,cdf8c39e,aeb27d0b,edf61fac,99528a9f,f060d1f2,376626b0,bc807a19,561c2e4f,e8b49f65) +,S(79e64c7,f45f9189,6c92073e,71b76fb1,e5ec912f,de11ba7,d7439f4a,297807ba,57d93436,b354963c,5891abe3,825d89b4,d17685bc,c9632e7e,fe85ded7,5823c921) +,S(d6232edf,fccb3868,71ef057b,60bda43f,69f422d2,debce06c,78a31f6a,8c42274e,13daefa0,b2e2e09d,36f472f2,29b5f7d1,58a18f63,ac3dc4d6,d62cc7d7,ec0ef826) +,S(21c0f298,b2d6e3a5,3738fc00,c8289458,722d78d2,48a33ea6,a7ebb667,446e368e,867553ec,17d2fd95,b895eede,15da569e,cbb3f25a,e5f334a2,b20660df,df062383) +,S(1d1a3d01,dcbf799,d551621c,54f74720,eaa2311c,3fd9b1d0,f4f2caee,4c3196c8,d5a7a115,9900f90c,879b1a30,13945d8c,5453bf1c,7e5e33d,6f8faeae,439734eb) +,S(57488680,8fa99ede,ca97d1,8582a151,62e26d5c,7753a561,4f4bb1dc,28e76735,debda859,7117ede0,dcc0ecc5,4ec1a494,b3bbee34,95db2b1e,ebaa1db9,2fc17c6f) +,S(b6dd34d3,4ce1dffa,4e1e820c,4c8bde9f,607194d3,1c1ce07c,9f6fadc8,9791715a,8bf48868,e405d533,2adc0ec9,49bc7cf,1487e554,3a043200,71786521,8a39cc9d) +,S(90f9ded5,69088772,ca2bc887,1522df9b,5821df6c,9e20b160,f3504bd,4a91d0de,d17e64a,dd534a6e,fdd0af26,b4494339,f76b3c1b,126397f9,a2beba76,eaf902ac) +,S(c55f34e8,58d19353,9106e4a0,c3002873,db07b239,9b10299d,260acc65,6b2cfa59,7d9f38d4,74b5a22e,72949f7f,e2cefb34,9a8fe1fb,c16b8dda,11f162de,30e50f5b) +,S(6ae44192,d38981c5,9b3f8452,c4a2b627,f39c16d2,b6f52575,c5f1722,56b8ecad,9bbba8dd,7c49204a,9edc4b91,e38e4973,fa61de1c,eda6ad61,603d9715,7f0b099d) +,S(33a7d639,423e1b36,6a93ad99,eab6444c,bd0c251f,6cd8b79a,e0344eef,6fdcffbc,c26112cc,6dca2a,fa52684f,c9ed22d3,2f067891,d5bac2c0,2bb86e3b,9411c61e) +,S(48471331,eac48670,28fa6642,a76ca6c5,3380c1d9,f52a4b2,ea640d47,f159af0a,b4ea8546,93fde01c,fb903a31,18bb61f5,c5047b94,705a714d,5b586d47,a0142704) +,S(565ac39,9ae731c0,4cffaab7,43d24b71,72defd79,beb8ce86,d46012a5,c2587917,deb56aa5,d45031ea,fc411fec,e09a9646,14664989,fd4f40d7,79c02981,98bbab48) +,S(964838b5,3b6c2b7d,6a8d017d,c5a32fc,99549094,6dcbf773,eaa7085c,98314c0b,2daf9f3c,ec44034f,c8a71ee0,ee76bd77,ac6fdc9e,fa042a2f,6caf9c5e,fd130b97) +,S(bc00da90,7b8d078b,9d83522d,ae548b14,6f9bff0d,2ef887c,4aae2f1e,c4eb88d5,6bd0fd11,f9e2db73,65f21dd1,34cb29f6,fef4d7f,b419abef,eafe15a4,20ddb152) +,S(1a59f855,f89f0c,f13dd8ae,9f5e550c,a2082bb3,27fb111d,75455ab,dba7bea4,7ea2fb40,d460adff,c9e25c53,a65c508,e77e6e76,e2e435c2,150c870a,7600c823) +,S(7a3b611b,d3bffc6a,d4508162,45695024,452706a3,279a6fda,d88598a5,4eccc764,16e09589,68066e52,c873d6ef,e549d3aa,83d30bd6,a1d730d3,68aa1ad2,32233145) +,S(2fed5577,9cbe0a5a,786fa95b,5c56e27a,a0a1cc28,51112bef,4cd5e1b7,15d6d91,7eeacc27,b2297fb5,63d691fa,36dc650a,f66fd3e6,6fe5e637,9959d46e,2d4bddfa) +,S(267ad217,952edf65,673efaea,6bebb44b,18326dd,f1b36d02,f0154a0d,774a9558,77593cc0,7e9d5e5e,688a7b33,bf54a01,703cc9b7,a0485e6d,907515bb,11a13fef) +,S(eb6ed62c,239b99c8,6978ccec,a5f32145,e0d341b,ca7eab10,6fa05ee1,7f6687e8,ad899e22,50f6a8e8,ce29b225,83ad8755,2a6e6ab8,9061d33b,6629fbfc,52c0a241) +,S(ca5cf17c,e03d214f,b4ef33c,41686c4f,5087a59b,f88ca7b1,891094d,430a9e5b,17e44eeb,473f75ba,cffae683,c8ea0299,e1935180,7257803e,f9963ad3,d0989ce9) +,S(4c7bc29c,acf0642e,63f035ec,a93e6b6c,c82f21cf,46623a2f,e4c7215e,51e82f7c,7c55e76e,8756796c,143f64e7,e40a402b,eb537be4,f1f5322,e59d2be2,82776875) +,S(57cab8e9,b42289f0,503e5013,acf4dd7,79783184,2389fd20,80b61bc3,671058e3,78225318,6671273d,a7b0b884,e72e9bee,2b048c45,9430d2ca,7c398aaa,9fd9e2bc) +,S(3c2bf23d,f1120c34,de813a82,a56843f5,abf3d272,ed2e6c27,53ff6310,9bc4823e,1759db63,88aed233,ce0c5b47,ec9dcb88,76740928,e12fe9d0,d08eb759,2d3f1990) +,S(c010a9ac,83e0742a,d3348dc,3dcfddd2,34170aa2,28d36856,d8581b1a,eab38d2,634c97ed,644a68f,e1f1da1f,190cf920,2b2dc810,446b78ea,9cd27684,3c76aafd) +,S(a4abd9ee,548ba468,e4cb632,b3d9c8a9,4f1b773f,ba3a9660,5504593a,92071994,3a14266a,ba263297,fc6ab00a,8403565d,c9390b48,ebffcb61,11b5e8ef,c8f87182) +,S(dc02c852,efc115f1,c5c08540,deceffe5,d68b82e5,99b78711,5a7a333d,e8dda172,e4e6593a,8e1ae842,ca7f4eae,d8cccaa2,8a35f8dc,cb8549ba,2367faf5,5f6c29c6) +,S(ee4769e8,223822ff,c28a5a4b,5f29fd7c,a54fc81,72175cac,1b6db5a2,91ec57c8,fca2c6bc,4076c8eb,a0978b9a,2b0158c4,33890514,28094619,38413fe6,c020385f) +,S(f3006c1d,34910c0f,d435a6de,cf088c38,2cf990cf,3124f2ab,b11d2727,d93ef066,7629f5,aa367f51,a29ebaf1,235cf267,f8016a6c,88dfcd9b,82d36904,c949eae2) +,S(7cfb203d,7bf5669,129f0a3e,325c3fd6,b1b9c804,4932f0f3,794b9357,1e7313b7,4f76b9fd,24339c38,c88c4217,387b016d,e4ae08fe,67182d39,82a45bb4,e82bc60f) +,S(cca3ce0,36e00993,9d30be8,e70455ad,efeabe71,83aeb206,a324d0eb,32312c0a,9674ae58,fe947c6d,34c63725,2058c88c,91b437dd,98da58b2,efd7e8d,1615b9e5) +,S(9fb64148,81cd5c27,82da071c,1f98d71,d9815fd2,2389d212,c66ace66,ab0d9c8,4c25454,1a513742,5f75e515,c04f1c73,d11d5047,9c76b09b,ce23c13e,d1813251) +,S(1dbbebf,3e3d459,10d39de2,32560b4d,eb5d2ad8,6aa1542,c2c070b6,51558b25,ec68e71c,2e94e490,4194753f,d7484ca1,940eae51,69831876,877b9ce7,2d0b9db1) +,S(7751d219,92f47421,7742856b,4c84d41,5a890ee9,24185e21,5a210a3f,a46bb5f7,2915a9c5,b770c86c,edd32749,3f698c17,6371f6a1,4cac5a22,73a3c648,1b237fef) +,S(39a849a0,5b189c3e,20782983,ecf664b1,e7b89c96,4e11d737,70797fca,ecf36a2d,d3e6f8f1,6191db06,be2274d1,56685895,48e69253,54f41114,f43b5ed1,13690c5) +,S(67e56125,b29ced20,f9f95522,d412d67c,80e3d628,b8bfddea,768117cb,e79b25bb,608dfc15,7e3c23f4,4aa0fd88,3d02d293,3c83edcf,66ea57f,9167b712,8d03da21) +,S(a51aeda,2f7d59d,d31eec20,e95839f6,ecdd01ef,529327bb,5cb229b7,b78f1525,704967df,93fb862b,3d38b18f,4c6818ab,6621c7d0,80d92cdd,1f0092c0,d7847903) +,S(c980693e,73a1cb46,f5eb71b7,73b00389,f8bcb36f,fb489e7a,aae64c23,6ac1745d,bf3b808e,fe6b7efb,771853e5,6fbba6e8,b3b21fef,706bd4,274cc058,b6fae474) +,S(c78df930,bcf54c1c,28e27aab,2975e9f3,94167bd2,948d4713,6b17a374,a1391a9,9a424f36,6d3a79be,55bb5e9a,283be1e0,163bfe22,1bc65e5e,318f0de,304d9ae7) +,S(9a75f7bc,c6d2f3a9,e6168ebc,8f7f1e50,a998b1e4,e67316e5,fb242fc4,6d284089,cb478e6,dff8b9aa,3ad06c6e,8fc7e35a,39bf6ec3,787977bf,d40f3159,bf169e01) +,S(76b2131a,db0bb3e7,db48277d,95ce73e4,7eba1e7c,b6f801c0,d20b71a3,8b6e6224,32e3cda,ef60e55b,a9e36e6,cd287737,196c5af8,120c47b2,f79d2492,9979263a) +,S(21898361,4ec5971d,f55f96c9,3da89483,cdcc4c46,deb8de68,f32a42b3,5c1384e1,2c396c50,44a4953a,b22a2d22,47769741,c5eda54a,d9c9ac97,d6486b5f,126dac3e) +,S(ac0b0a49,4e9d180d,101dbe1c,a528fecb,a08449a6,cf5d82a9,aa14f875,e3db8adc,26d1d412,25a1b583,2dd53b9c,56a6a8e8,371dd19f,31462dd9,b2aefe3e,70412554) +,S(f869b58c,851a65f,bd6d3329,75f596a2,9d1a78cd,bbf04a1b,6dca6c27,30e04625,40dee344,fc6f5c72,c18b1603,e149949c,a0cfb31b,b8b91b09,c3cbabb0,c6a5bff0) +,S(f74f02db,2406250f,8984a5f2,273c63ed,a640a43a,8e7d72aa,ecf78d6e,b9544c3a,882e3a6d,cacc1e92,8a3c1a61,85f2bcf1,5e364f7a,1eeeaaea,1c0af593,cf86185b) +,S(c0613eb6,1d6755eb,2ebc9284,a0aa69d2,88c39050,4b7e869f,f3d943aa,67ea65d,72f61ae5,27b5c82e,4afa8966,55d9289d,29931c1b,f0d36c09,fe4213c5,27848cba) +,S(eb66ff98,60ba08a6,3c0fd8c4,7117aeb0,ae0dbf63,524307a7,eb739f08,f31285db,c3142ca,54bcf2ae,8b05dfb9,4e40f4ba,7d3662f3,774e616,55c7515a,87ddc5d5) +,S(3a7108e6,a1256061,fc25d58b,ca534602,e41c6b15,156c15b8,71a516f0,ec4a861d,daae2d02,41cabb2,191b5be,c17e7e88,957bfcd7,66df1226,a183064e,3c4393a6) +,S(d17e3a58,c83169d1,33ee7371,7b205f2c,ea1a2ff3,4e744958,949e9403,b8f89d5f,98c35f7d,69e5d98b,920ffafa,6d15d349,2d75fcb9,81ca5022,5ac7ff32,618b1a20) +,S(d6e32892,cefbb8ed,14350cbf,2618e2fe,98caf6d4,f7679385,fff36bab,bf6541c,7175462e,be0f5ec0,7872b55,356f2498,976196bc,edbe021e,8081ebd,b2636298) +,S(318d49ff,60e900ae,6e8e2182,f38ec006,82ddc8ae,93aa6291,86d5ddf8,affef75,6e97ec27,dd7d614d,c1ed4fd8,fdf6aa70,8dcc3eb,be288831,a9888166,66333b2) +,S(fd6f9e30,1772db8b,a68ea5ae,b585abbd,c075e72b,68d6f67c,5a2f8144,98cf6346,dadd16e7,64775bd5,ca5c5f51,35843556,d7608230,aaff4125,4d4eab38,1d28d2c0) +,S(8fe25b38,a2c74761,a90ed08d,4bce768c,f074282a,e9560d31,566ae43a,182ddd36,6ee1e84a,77c6ab78,a2cda1b3,2fbdfe2e,51d66843,271d15c7,3f8e1a82,1e4c23a2) +,S(37cf0ed2,88ed8fef,4ae17bcf,f6bfb815,3e12bab2,a46d7e5d,2e6feb99,9793bef8,92e7a57,18eb0751,c99254f4,ddb5c278,e17a417b,21793339,119a146d,bbe3e0d3) +,S(688c2061,6b9d0c8,76deb812,b60000e8,eca0e04f,531ed1e0,9158442,7bf403c,bab4b2ba,41ba4d53,df512e76,32200bdc,11d8583,f2ceb5bd,a8b7eb14,5ccc01fe) +,S(4b4caaaa,f5399535,d822371d,63965216,d1b53584,d89a84e9,d868395a,70b3d804,3ddd27af,cd18049a,3b01d043,7761e4ea,652fbd91,115c470a,e4c7bd40,51ee73d2) +,S(6f5acbc4,4135da60,758ed9a5,18b39b5f,47cca398,24e20e56,1444dd52,e2fa1d2e,5dc9d46,e5f6d94d,48af2efc,2f197a2,f729f1d7,335fa569,524d37c,4acd58c4) +,S(79d2d449,3dffcb91,6fda527b,f8b6b622,661d6f23,738288c6,ce94313d,c267fc42,b2683bf1,3fa8f7fc,be302823,dfbc9153,8d902791,d5d6dde1,d2805f37,a0c08db) +,S(33a8e87e,246b7b9c,9c77a6b0,7cc67d41,f3915dbc,2180118,c0800b33,f9f95524,baa8244c,584fd05f,2655e36b,e2e5c459,207d30ef,dcdb2294,70b34333,9d16ff8f) +,S(9a169132,f3887df8,20561a7a,e4bd5461,3235ddb2,fba7a19,3f4daaba,79868e95,686fc317,995446c4,42945216,1a96595a,a233b100,e5f8bbc0,71990229,44630bcd) +,S(790b74f4,8405ce3f,9abdc7e9,439f2f5,c859989e,2ca5e6fc,29046104,8783ac42,8961c913,562385ca,990593a3,77111a5d,1dc6762b,b1a928a6,6ebb304b,8a24a701) +,S(e2a3d0cf,ae1fc2d9,87caaeb6,9f32fcd6,95471785,f524e438,b5487aa3,72f9e49c,9cc24205,ecf2708c,357edb54,308ce452,11f7dc03,98fb48db,4982d337,14c93046) +,S(cb30c43,5992c195,76d372b1,96f2ae68,cfd2653e,63e3ba7a,2b3c21ec,960bcbea,f65735b9,708338c9,acc9cba1,4b491b8a,fb683058,266a483d,4987cdd3,89ccd0b4) +,S(1faedc95,d6310bee,6298ffb1,6fb3e6a3,296ca66b,7c995d2d,fe924381,10e8b46a,35039e3f,8201e904,e5378d03,2bd8b766,26d9f0ce,4425d2ce,e7bbd24f,b8725089) +,S(a646cf5a,2be8c1d1,3f05410c,ed51b3f5,8e93ea53,1e28bf31,8f6c750b,52b3e8f9,58c58ecb,7727a920,b47a7e78,e1e51d11,e427d7e4,465429bd,a01f4650,a4c102bb) +,S(32734727,18537d38,e9b8c397,a5cc322d,1c77c0c6,15eded39,dcebc020,debe2205,c2debc89,58c3f60b,d4c7b072,d475a7d5,c1ea784b,c3e532bb,72c02490,9a42d65) +,S(16a1a718,855a212,c068c095,d930a270,9906dd22,e7db3f4d,4ce2f393,d572827e,d389d64b,b30ba9eb,6ce80335,cbe8f7dd,b1ef3016,a8b74660,2196b724,d115605c) +,S(b4bf4d14,5de25571,33694b86,76166e90,eeb1ebf8,4a7402e9,a61af4cf,23687596,49db20a4,d82397e5,6318640a,6b605e96,37d38961,a58ae3db,fac2fc11,bbd11242) +,S(d4ed67a9,ccf4665e,418a0de0,8d9380cb,fc311413,e90a964b,bf367b9b,b892630,8ff7e57c,e79a0883,1fe8a972,92493764,7472b77,61b055fa,37105d18,b51df131) +,S(8ad256f1,9f413ef2,eae906f,c1c2ca4,44d5dfdc,f916d366,b32f1f47,f54fe70d,bdeeeb41,8d2c4dc5,82547f65,91c97219,34778f5e,d25eff4,94e243ed,a6d34da7) +,S(8dd3e2fa,fe55b5f1,f13723e0,1a5587b9,c67d22ee,21f1f62f,7f62a15,31f17f8e,aa23d2a4,7d6b717e,55d7c6b6,5d9c46c6,8f2db41c,ba66960b,4b4bf93f,5fc88cb0) +,S(44fd9e28,2a8e30af,ac34db01,a7b0e939,3c13917,554d9a67,8e577a5d,4b3d0f6,cb079061,353319b3,a1669d59,295bdbe2,18927d06,ccb1290e,4840cc16,911a61d0) +,S(5d249a02,4464ed65,831d2aa9,c9645f46,2db7c9f4,e5a46477,746b1a71,88b7aa42,2bff7386,527d6b5c,2c595f80,e08b4d20,23bb8dfb,f294da12,b54f8b14,77281d0) +,S(d98eb458,1edcd51d,465e123c,d891c481,ddd18b54,b9408ca,85ac47c8,e10fb23,15bfd3be,d3756ac6,f2f1f9e6,f254c9b,2b153717,1b265081,6a2cc21b,78b4dcf2) +,S(2f12c369,19a2aeb6,2132134d,2e85150f,6edb486e,9d672eb5,876804d6,44db6082,c0111edd,3b4d28c4,edd264b8,dc2bd0e3,20834dc7,bda82dd0,827133c5,7f8cf73b) +,S(4d949684,7099c9f8,421d35df,ebce57aa,71326034,8f07e3e6,f03017c3,144b4624,9afb5a57,d71369c7,28db308f,b8b07da0,b91f954d,b182eadb,126b1fff,ddb673da) +,S(cf1db910,5e95f1c8,e360b39a,752ab17e,fca8f24,d9ddc8b2,a9768700,e2af2466,e7c99f66,c49c8674,a6c1b94b,4b964019,5e645ca7,b3d2e004,ad8dc73,f647ca5f) +,S(e71eb425,7d2ffa8a,b79d63a2,42c67585,d4b1747f,5b27f22,a9ee4284,6aa62b85,a906aeec,f901a376,7d721f45,da53e342,3bc0a779,870e33c3,d10f6426,6a2c8865) +,S(bcd987d3,b2575f4,3bc5c3e1,b4a299bf,21c58b6c,a27ebb21,8f9882ab,30559887,403804c9,4339ae27,2bafd894,e63a4eb4,690c1b4c,9289db00,761e9b3a,1d483f65) +,S(b74d5cf7,48af7162,395d2d5e,8a69f740,7a2bebba,69564042,ea9c7e34,b1f8cab0,b5c5fddb,332bfb59,835e9a23,4afa4543,5728dfaa,7dcfca3e,a3c57deb,e849b336) +,S(46f3def5,9835c9ae,1a7b3b13,a920bea9,e9bc12ee,633b3edc,57251b72,3560837d,587b2e1f,2e8eb9cb,37aa6977,870214ec,818fb71c,1035eeca,91d53e68,150ce67b) +,S(8d3418fd,eb3f0968,de51f4d7,cbb60299,a50ceba4,1915d8b6,5774cfb7,7667d572,cee79910,16a28462,aa9da7c0,f67b4c7,e8b3dd38,f4b2203,9d05115a,ac661db8) +,S(98cb0f09,4510695d,78a0a672,eb67253a,30f4327b,7864fbcf,529cf212,ad6f7c10,25952dac,4e1b5035,9b47e9b5,52852d1f,300fde75,a6bd532f,9fd56af,2a0ab333) +,S(96045e4c,ca075fc,4a5383f3,f03de105,a34c7c4c,b030ceff,b58b98e1,2b39a3cf,f527b8fd,92234151,ba11f24f,7bd5dfed,6ebd03e3,a5048c6e,8f2d5231,7201bafe) +,S(f262e891,42addef8,cba26a9c,ad779761,c3f4b3e5,5990a93e,703bf56a,99cc6030,275cc764,86c86a90,f597dd6,7092ecff,5382c7b7,33939ca1,d1f3218d,6f0b594b) +,S(cd79c02,ee175336,5f9f7900,be51bb2b,ad75ef81,3c6c5634,7cc717db,156d17fe,b5ebe8ff,b30de5bd,a5326044,16abbae1,4ff9198e,b491794a,c4500031,947a985d) +,S(28b4bf22,5b1d40dd,e0122e03,e630830a,d9ba4629,cc51c9d2,80a225f9,48f858f4,24756189,98bb414d,4a534c6b,e300297b,aadf4ffc,b10e6795,4ea36e25,2cf3cac0) +,S(f018f206,7dd55df3,9c53344b,c6128a5f,cc765c36,c7b0bea0,16c8465c,c6ed2ff7,d9fc5ab2,cd619d4a,c66c1cd2,251504cc,cda34a76,86c5661a,960a00f8,e4aa7e66) +,S(496968cf,8086d02,9a5dd5c7,4f47cbda,7f661ef1,488b3942,18ed886c,424a7a13,d7d8df98,442060e0,f17a363,579c6600,360b5124,2774e2df,c8d4b787,1e1874e7) +,S(242d4c59,e9113b77,68e48574,93600da7,b984355c,a1d07949,8921016b,22efedab,470dcfd7,b0c8c2ed,63a28074,a505573b,42f50920,6b0ae577,27a8b796,7a0f42b1) +,S(b6b804cc,1a1a59d3,84c4afac,c5e5050f,466280bc,d5ab1586,1d20f4dd,1385e8c7,2f789346,2a636a9,9ba2a1d2,32829f41,39b57967,bb26d0c,898798bb,6521d439) +,S(dc30a3d0,7ecc5fdd,38b8048a,f281024b,46904b2d,2a4c51ca,d1b49b7,1d918a4e,326409b0,70550e97,58f53698,7936a54a,b701f7b6,78a7d10f,ebb511a6,c18cc917) +,S(e1fe434d,345bf330,83abb628,f4f44ac,5fb22934,977813c2,c015f2b,43d3fab8,1b251ca5,2af897ac,4c08df48,ce3d1607,d3b31b2c,2dcd7f7a,59a95b07,774c4d83) +,S(a8ed88da,e08ac5e2,afbe4a40,ee775645,82c2f513,cfd72060,bd1fd5d1,76fb8d08,f4fb60b0,74419630,fbaf5b53,717b2a6f,5cc2d98f,1d29481b,77b1f9f3,84175729) +,S(b52cf828,de1e9cd7,c95c083e,ec50d228,8e770713,a0e2543f,76fa5790,2c7c6481,635a3953,46fbbf,903dc729,d3e3b52b,43eebdc5,3748ed83,3c95eaf7,1b75790f) +,S(702079ae,f76d9bfd,ccb957a9,4aad93fc,b1297c54,d634978e,4dc78292,161d5e83,4983c08b,f2d81c52,d3b3a202,e0c6ddb9,32a43a45,c4b95f82,c8c10642,5a783b52) +,S(4638d4d1,8e9de1ce,ef4fe8cb,db4378e2,3ed3dcb9,513cc9a0,dd73ee2e,be57bbf5,561ee032,45cc3066,968853f7,51fa36be,cb50740,a5951e87,cf77ef20,cb27e110) +,S(eeb34eb7,5facadde,d561dc5e,e3d0a039,d98e4880,910439cb,ecfb22d9,3b386bfc,f2b23cff,5ebdc8c,558db8c,1c311a94,e9d8f63a,d1cf4af4,c21c2349,a6e57c4c) +,S(7f2c6e5,becf3213,c1d07df0,cfbe8e39,f70a8c64,3df7575e,5c56859e,c52c45ca,950499c0,19719dae,fda0424,8d851e52,cf9d66ee,b211d89a,77be40de,22b6c89d) +,S(6ec76722,1ec5d27c,f7e11064,d4f8b016,3cea090f,6a950f81,85623303,23e53647,9b03c757,9704e839,c8eec7d0,f063c4fd,d0aa7ba0,5ad75254,984b1703,ae69a3d6) +,S(98f6f69d,320d5eca,1f184b0,378f67cd,b44a707a,c5b2af54,99e9f8a4,524dea7e,26ef6b3d,7b037663,979333fe,56bc33a,ca54a3dd,78c9244d,79ef5426,f2b69a02) +,S(cf1ef445,58b82c76,5d77ac99,8c0170c9,2d308668,2d9ed7af,2961cf05,5b47e390,8bcc1d05,fb880ec7,8762d8f3,f5afefe8,f4345bd8,36397d23,befdf446,498511c3) +,S(10e01651,efa26f2e,f88cc5c1,594f378,9ab62b82,5a0875aa,37c280a1,8c6f07e8,2e6a15e1,1f776335,30fb2cdb,788aaa98,83105da3,7e28c0a,8fad503e,b9779df2) +,S(b94e2fe0,41ce209b,6efd77d7,44983130,af90945,120b9a58,5427966,e93eee4a,8f7abf1,103e92f5,5dcb1dde,746df10d,a86bfb8d,2776a0f0,1d07142d,c9bca443) +,S(cf9e7d02,c671a9ea,145d233e,244d8af6,6d71cc34,e17f2ccc,1225d2b3,16d41154,82eeb8a1,f0b966f,bbc3858a,3878f969,a853e2bb,e1b60c4e,e13eff85,d2d2ca7) +,S(da3a3c29,94ad3b91,319d18eb,dcf4b934,df8e4f2b,e052f436,6d539aff,4bd48bb2,28f9d653,c4042478,831ccfe7,bec86663,5e0d32ed,f6db4f54,25669a91,d1dc0193) +,S(ab812818,2b80378b,d914c9fc,d2831f30,a0a095c9,d0e52450,d4ba27b0,f1eec101,5abc582,274876d6,3dce366a,fbb1d80a,2286dc2a,dc0c078f,1424d45e,26666b3) +,S(ea5b82a2,bf02caa5,d5d64391,c0965c53,f0edd967,f8df94ab,831408f7,e5c4977a,81fe8299,f320837,acddd504,7b888e6,2518d53e,897dacac,5d28bce8,ff3d9339) +,S(50605c0b,ab201d7d,3dd618b,e3da2d29,318aeac1,7df58d2c,a95b8fbc,fbe70fa2,e50b1e,7b5693,c4ecc160,d928cd6e,d4c978fc,6c2a68af,c03f397d,72a60383) +,S(f76c50b6,6d7dcace,f45409d8,854f79b6,51356661,108b7168,31b58b25,ea1191dd,7d055b74,b0195140,bc0e2e93,a97f07b3,a3040148,7720df86,d3bd1810,6df3cc72) +,S(de5053ba,d716047c,cc2367db,272e4e11,41312690,2bd79b32,f6d3d959,93260e7d,1c54a2d3,9c34b0db,deb61b5,b5f46033,b1e4c581,5113bf3,d3f38de1,c97cc7e2) +,S(ad3e719f,180e946b,1b98a332,bde18e54,437f1a24,949d712,1aff7c8d,fa06499d,b458d7f1,390fa4d7,d2473863,abedc063,ef310adf,7ca2f2c8,82bcad3e,2f1b554) +,S(270a0234,5560af6b,6310c867,332f8b79,839a3ae7,6e2666ec,b46c840c,c36bae4b,8daab84b,92157d16,ca0f160,99877a1,ef7ef072,1bdb5bc6,89d16a19,4ebedeaf) +,S(eb5ed17e,3027c9c4,c87ffdb2,94a84ff7,25ba2b5b,2bf72d30,f98334ee,68624621,39fffcb3,8f74d471,9be8d1a2,14c61ad3,df4a91bf,d599c3ae,3b54b4ec,860a942) +,S(b9c11df2,8a0b98cc,623f4e80,75acd469,fb1f6621,a7572d6a,7bac135c,2ce0a5dd,5bfa8a78,d42b95ef,327eb0c3,692b3ba9,5eb506a2,4e2fca1e,391ec545,40a76278) +,S(eed17043,80abe259,fe661106,6eda0408,f60f1399,3c49a21c,a8a6310c,ebe74b5c,6dcb6276,cbe37b91,162a243f,57afcd9a,8cc2c661,652c324a,567d5db7,22a0d750) +,S(8e4b0f6f,5f5b9cf4,68e5524a,4adf62b6,8c68e310,5ee374c2,5265000c,53aa97a7,d1f880ae,c18d0191,b74578c1,6d0418f6,c7e59f2d,157c0d56,e25137ec,c1b7f74a) +,S(77ae21bd,fc6596b9,ae85ce9c,93112b1d,a7f393da,1238d76e,90cf59c8,caa5ebbe,f4484581,1e3266cd,f4625390,e729154f,51694717,3206ef9b,9106c547,ff4a21d1) +,S(1d379ca8,71c02ef4,59a8bd35,f5066265,92922533,f0503999,e16d6b07,dbd2346f,c0550b9a,72899a7b,42197cfe,d195c704,a6333d5e,178d91c1,d50b772,4140cad0) +,S(625017f3,28fc16ae,99367199,5f02772a,5c7ea721,7d47c296,cbad670c,3fef1ccc,1b44e253,af3b214f,edbeb4ac,50110df6,d7056d06,617c2bf3,6189a74d,64450603) +,S(c7a4fe49,6bdc3509,3ae3f508,d43877e8,d1019d16,740a5eb7,8eaa72b8,638412d,1b5b12a8,95fb7130,e8792406,74b8f735,6730938b,675996fb,a30a9744,960febef) +,S(cff9f83c,e8f9c4ef,3e80102c,bc48c409,b65c6166,b74f052f,a5628348,b2441d3f,4cc418f8,2180207e,fc846a41,ed6973f2,814ceb07,a8bd252e,338e32cd,e352ee6f) +,S(84027710,45b8c295,c938ae98,a9ea11dc,2fd23ae5,7ade6ef8,2c604721,66700541,72946592,d3c11404,881b972c,eba81d4f,f3f80dcd,40b15da5,f56e0723,841e4f99) +,S(f7ab1330,e00cb9ec,61a346b,d8f5522d,5e304a4e,a94f84af,b5c70614,d2e0d2c,5d4ac851,89350a54,af58def4,6f3f3d69,2ef0f6a3,9dd4ef86,6bb1101b,df5e6144) +,S(a7c84e19,2303b778,8c1a4d5b,786c9829,d0da4ddc,c13f692c,7851884c,6fd4e618,56e32e5b,8fc2db2f,21d64bad,35e3f115,65928533,a829d744,939ba456,bb1774fe) +,S(b8b0c884,a680dac0,363bc55a,fa677a72,c65f4139,7f5cdcc,f199d80d,ac98c43a,43e4188a,c92606c1,cd6bec5b,a4edb045,6569f87a,625db932,d0f8e71e,516b8127) +,S(816ec443,d0576135,5a3bc33c,1db4a179,c5bef98e,943af8dd,ac250482,a65e0df6,89a7b2c9,e9f3588d,990f6fa1,96e366b6,54f9a30,1218a2a9,c9b87c48,55f0b360) +,S(8ded2103,823d07d5,33fba24f,7fccc47c,b101960f,3b717fd2,af39d49a,a91e28a0,3f03ed1f,be1a661e,f43ef9f7,d753eaad,e3e1a391,2a682ad4,fb19526c,c0011728) +,S(b1c4b39c,e874d478,bfbdf9e3,ce8c3165,ff4f7c4,bee20c87,4849aeaa,d0d6260b,38af8b61,30701881,fbbfe724,5396adc9,32c25b84,dfbc4dbd,a54bd236,c04b4fde) +,S(7d5bce3b,e5953eb3,a17f657c,fabc8209,f011bcf2,7e10b90d,e75dad9,fab2c971,7380d686,5f5fd782,b0708b3b,62c39e49,864b2ba7,4066167c,bbcede2a,b0f84787) +,S(2af5111a,422af2cd,14e7717f,bc7171c4,96af178,8b229497,a54d2b87,4c00f285,4468bf1b,ee43f100,7e800b68,b7b3b243,2f3445c5,c8aca59f,7534beae,bb771f41) +,S(b46e29c0,6dc8ddef,f8bdfb65,f4043b61,fe010dae,a2d0955d,c81a7b49,637af766,62777495,ae16314f,d7d0cef8,24a27a9f,748c5c9b,9c51645,9c1ec9dd,9d7b59f5) +,S(105786d3,f44ea40f,71eb3bd5,339cd514,aef6d8fa,5923b4a5,89b219c,fba6b1ea,2a4ea7da,c87522cb,7d92c450,8e86d0b9,39fad024,9fc2cf15,1ba005cd,b743d0bc) +,S(1f3c0c81,be856e30,18934573,892ceb22,d2d2d8ef,f08b7857,5c624f48,16adb23f,7321690,de24499c,f52f4840,89c4d7b4,11158d52,d32731c9,faaea567,8bf6072b) +,S(16dcbae3,a95a95fa,912484f,f833ba0e,e437876b,f16f9c9f,5abf46aa,468bd2b3,56727c07,247b12d6,c1ade473,3c691700,30e5582a,cde14034,3449f241,59ffa44d) +,S(114be56c,d6723c8f,924ff3c0,f5edabc6,e42314a6,49edbfff,1c794438,dae70726,984dd72,855cdeae,7c580046,b32cfa7a,45b61b75,944735e1,d5fd9065,268ac521) +,S(8d0cb2e6,1f98472,e169dbac,7f5babff,51766b3a,8d74e17d,747b7eac,d903fdaf,d1593bf5,b9e793f7,25cea368,2ceabb11,f06b36ab,899e160a,f1f736a,80bc9b92) +,S(5b420754,188c82e4,db72f3a2,c8049691,34e3b43e,484b45ca,ab4727f5,31714db3,4a89307d,27d7f360,7acd1643,719be148,1c7eed5c,77598883,8bf6cc13,a4723d9f) +,S(91e3761d,95761d96,8d856a72,800fe0b5,9f01c62e,1cc446ed,18c1b58f,88cbf74b,b5ab61e3,96f88376,28f3389e,9999ef55,b73a58c0,d33debc7,25812530,2b96c772) +,S(31380b83,dc77e5f2,9c2f5548,abe052a,16e0f1f,2d8aad3,5b05d29c,5c1a4655,23ccafae,cc84ea72,3c434342,b839cd0a,b42173bc,1aa1db20,1073fe26,6593403d) +,S(ae40198c,bcd54264,904b44c7,c9019553,8f3f3727,a0c9639a,764cda80,b21edd27,3a57f08,ffecccfc,cd9a0e7c,827d98a2,ffceea9a,6c39d200,5cfae623,34eeba8f) +,S(f4729787,abeac0f1,249b1d3a,c19bb025,5764a854,727b415f,73e24c88,a8a981c8,e31161a5,68d81328,c7f9783f,de146d07,b51aae15,bfe719d,ab4e9e,ae65d172) +,S(f92f02b8,34148934,f7059b61,7e84d0a6,f52d3b8c,a7d7b69,ce4c8175,7ed5884a,faed7ef8,82733020,888eb530,5c6dea4b,cacd208f,fbb66b7,6f3cf41,a8864080) +,S(a2bed8aa,e93bd682,be8cc4d,d1f84fc2,9efe4022,b2b0dec4,9ed3ce17,7cc93363,287ab9c9,62126fb7,e0340f29,9edeb89e,7bf235b3,b3f08213,d630c9df,198ada1d) +,S(5a42cfcd,3d1811d1,99b09dc8,9308134,cf6219e2,e029598e,899418f9,b7af4724,95ce721c,39929d76,b0ea83b1,80bf25c2,e301413d,60fb8717,2e0ee8f0,593f8423) +,S(1d27ab05,67e8bf19,323f1eca,44175085,2e768a6b,a1436789,40ba2b94,5b0e530f,18439939,496d29a1,58a532be,76b04932,a23e3ddd,d51a1b07,c6c33e6a,11e1afa8) +,S(592bf859,22c05bf4,4b42fcf6,e4cdf3fd,bbbf8088,b7263d31,9bc74914,6eab4326,84cbd8c3,8dccf0ef,de3946f3,ba2eac25,3aaab976,8f7f601e,7d95bc74,4c7f65) +,S(66730a70,5ae3dab8,bfc01f4a,deeadc41,d4df156,d03c4fcf,1dd9e16f,9359d5,c04c7cc4,4ea1d8b2,273b9170,19b9efb3,6e8f422c,4863f718,582f57a0,778273ee) +,S(3d002600,532420ac,9fb246d,84e48560,1ce6897b,979491ae,7c5914e,dbb7fe83,5bd73264,2f16d4e7,7bcc4855,72494523,c221fa1d,321c552a,53241dd7,94c7d98e) +,S(d42ae36,2b5dd22f,d2089d37,d22e2c2a,750395ad,710aa1c0,61ed4275,43a24487,84439e00,1571e1ea,53bcc24b,a11b6f7c,ded0a649,b2a12fc9,c2a618fe,cb39ada7) +,S(37c761ca,486fabfd,b306d,c18e9074,409e101e,5bdd1670,edef1253,aa253743,e53840e3,1110db1,89ec241a,e7b2cb89,29669da9,5c07f3d0,6277f667,b90cad12) +,S(4e672ef8,bbafbc8e,eb819f37,15ac0d6c,2afa9781,a197345b,2889ed0a,f3b0e788,9c10f0db,bb16d807,4680133f,e62e0eab,130cb0b9,51937852,4afcf4c,38814061) +,S(c1f2943b,23c07929,e9c635ae,66f62949,8e1df12,f35aba68,ed8791d6,8fd51fec,3376b6c8,93ad5ec5,991f7ef9,6a6b1105,2f2262c6,680045fd,fc4d4bfe,ea64ae75) +,S(3df2461e,739cd984,72cf10cd,f663e651,351e826d,7afdcffc,e17602ae,c0370be6,5e48fcb3,3ed9c0ec,3594eeb0,81adaaa,bd5ec5a5,7eeaf01f,c9f00d02,c692cb06) +,S(d4d3d528,f98b92d5,f4c4ecfb,ab60fd85,50f12327,5b63b3fd,5518c1f3,d62a82b7,64496d50,85435de6,991a838e,d984bc09,2554053b,54b05a2e,490d2ce,da7d5b76) +,S(ecd8399b,4aa3368f,1a7a4113,63ff03a7,ad644847,e225108,b3ee7d02,1209236b,2e1209fb,a7921c29,e351e61,73c02cb5,c629d88f,4ca51af,30f37123,75355213) +,S(d5990be5,7e6a0da9,333354a,fb344d59,416d1a70,785cdae3,8c332e09,cdf78722,b2a2cd8b,73f76f3d,1079198d,34441008,278f73c8,93979ece,eefc5911,7ba17814) +,S(7598ab65,1d8ced00,af3d5978,661d801e,b57e9089,287bd74f,85ef042a,90374b1b,589fc426,9466b1ff,b9c0cbd4,b022e9ee,7edaae87,8f4cc240,b60db60d,6c28f04f) +,S(fd071417,b12d2d31,852048b7,61c5301b,be088cfd,98ebce7d,7e0922cf,41f694e7,2d9c53f1,ee63b93,2adf679d,96b548d8,d47d8f74,58ef8b45,9664da23,be32c363) +,S(5a5b4990,e290868a,d1d571ac,8e9347f2,b1e513bf,cbc2b8d1,5e56ce01,2b72ca0e,c76852f5,7159524,541569f6,3c4c9c7d,424285e7,e83145d5,e5161998,efebf968) +,S(93deec24,3cd4f146,42f5a415,f6ea6f36,25c90081,5f3d20f5,9728c056,fde7f2bd,88f919be,b9993a16,61f78145,f54149f4,6abfa859,1907736d,d5e85f25,bf2dc7cb) +,S(9224d17b,a65ad967,969104c9,3068d439,9c9bec7e,7613a602,f5c9917e,46df82b6,346c98e3,2bc2a4e8,c7689e54,eeb1064c,1b5691fb,cf5a4710,55cefbcf,18a32f65) +,S(851acc91,24ddff9c,14cf054b,87347a71,cfc91637,6e559189,f055143,3b79c38e,d959bdf0,58d21cc3,430527e8,cc49dc56,2dd20bf1,30f0e13a,55cc69cc,1e116f35) +,S(ff6c1303,b7c111c5,87e01ef,44829510,eff0a612,931f9212,2b71075f,2cea4d96,24f09bbf,7bcf50aa,ca239be,b925505e,7e99d0ff,5a959574,5370eea1,7b4841f6) +,S(f23bd9f0,55e7bd1d,433fb51e,c8b6ecb6,fd5014f,4f4ca9d0,6a4bc636,435fdac0,9652b458,9d269ad9,68ee7012,aee47447,25ba917d,f120bda6,9d2194ee,a56d7b60) +,S(9d622c56,ea6d5d19,7b823e60,1bbd4af0,1fe070f9,391bb564,2a05527a,49f46ff7,8061bb94,d6485fe,d9fbd557,66db3dca,c648c7c4,2e025494,e6c3a91c,fd5c609e) +,S(9494efe4,cff5d5e7,6394b67c,407b9961,2915afde,56933b80,370d0adf,2f020c13,ab0c7e38,c85ee1cc,27964b2,de42372f,fd86ecb8,fd3f0a81,84f5af38,58a7e4ea) +,S(a8e4d7ba,ffbc52fc,a8cb6c,2938a01c,e028c259,97403268,dbe1600a,952e1a86,8d5b83d,dc3022c,4f79723,c6f16722,cc7eeeb9,c964496f,c9f67c29,351a0bed) +,S(83841f64,938e460f,eff191ad,4d72d7a5,203c01af,1519cdf1,f17c3bb5,e4927ac5,f5868f2,c2e87249,21373397,40415c4a,ecb1f30d,b204fe41,80e01d79,eb536800) +,S(ee8974d9,5ef03f8a,860dcba6,7b597fb2,af2a2df6,950aeacb,d623c883,20612f6,5cf10d74,3085dd7,cc695145,3f9f763d,6596abfa,eb7cf216,34ee07f8,a4f141ac) +,S(68e88d8c,23616ca3,b136e5fa,3427628d,a92dde6b,2691d857,b2d01a60,b6579606,5a9090,3766d6eb,c58c5d60,9b6a5675,e5ec7b73,86a17c41,2574d179,a0fd5450) +,S(fe34dd8a,c62ec8b6,20dbea79,44ccca40,cfe6ab5a,ce3b2e7c,50ac589a,9522345b,88cf0055,adf1e122,535611d7,bd3e00a7,30c9edd5,898d25bf,f0abb9bf,6bd6c8c0) +,S(423a7a9c,c0f81489,aaa62479,c1317368,9989366,fd18bff7,f6a5f235,8251bc1f,c926b3dd,519241d,2e776ea,16112e41,259ce896,472ce71f,de4261bd,29c678ee) +,S(7fa60bf9,7cbf54ff,e61bb840,b2e08d91,ffb0eb4,727c0e73,ed4f157,ad0b98f4,d5b1aadf,84d387b8,fddc7b26,a7f736a6,7e296fed,7978e81f,6e7b3b09,e94d733) +,S(9e53cb0e,f1eddebc,77edf8a6,6917f915,8294815d,eef898c,f1e77433,60153a66,5358daf2,60fea2a1,b9a4c6f1,b8bebe09,4983499c,fe5577a2,ed8f817f,46b41ccf) +,S(adf93641,c616c677,99b44ad5,354332c0,1404718e,8ec91e96,31e69552,3ad6f119,da3c66af,e4cfb3df,f55f6761,5c6ac42a,8dc17241,5ad38619,dfe2a13b,7e42ff9e) +,S(701e3ec,485db367,b0687ddb,2be15f4b,5b6242c4,396f6f0c,9726ecb6,474e4ca8,1098fa76,13dce1c5,29f7fea,30740377,691aa3cf,3d13cf94,6f2d8191,2d3b9e83) +,S(d8fc5ba5,d3ecaa05,9e9a7e04,2c52500a,d513645e,6149e84,aac0d910,f8ccfefc,72724b4d,eec94da,7494b4d9,83a2df06,df96ee83,e578d920,c2597089,7b4b3d8a) +,S(7bc88f9a,8279ffb7,658a186,faaa5f0c,c900cb9d,4a33b8dc,c9eea83e,ff71398e,cdcd21df,e5ed8151,1a2d8c77,e08b76f7,4939d39f,1f5581b0,aa956066,fa14a7c) +,S(8578d531,bc79e1f,6e219bc7,7f2172a3,e5fb92a5,efbf9919,f46ea11,6f5ef0e5,fcd1b2ac,39c262c6,94eef5e0,52338f9c,cac2d04d,ed17c290,768759cd,13b7d550) +,S(98bc22d7,3ea2661b,545eb5f4,37e1cc0a,d4124020,44bb9093,5cdde758,a8020a62,143c7dde,d33ba5b,c2ac8d83,cc462f94,2607bff2,a1aa32d9,f32e14c2,82232226) +,S(7fcf821e,95d2176d,d088106c,a5bf0855,9980f265,ea3c401a,aca44b0a,d5e8ee10,27c341ae,87e7afee,f8af4598,e8e27cab,c127b054,1b389cfb,266ec9d2,fe400284) +,S(898a39b9,d440ef05,f87e195b,6a334f93,67acd67a,1fc76ca8,316292ea,216a5f1,eb642fbb,fe3274e5,2fd1cae9,744fabfa,c0db80e6,2bd4f7c3,fc2ca43b,18ce52ef) +,S(3ee974a2,8918c216,a962480,1f18bf9a,87d6a627,83323e3c,bf138bf4,3f2192a4,f5b386df,ac71eb35,499d5b2a,960fd20e,fde39fc,10dd5c63,dc50b55b,cd660d9c) +,S(bdd10d2f,de76df34,9ab753ee,d06c1251,9766bbf4,2fb610a5,7ddc3f36,4047c14a,504532ed,34f97eb9,b8b27664,ab440032,2b8b47f6,9c403bbd,6bc74330,16923dec) +,S(2c179437,39784124,4ff9a4a0,eb9ff292,477a5148,c4176b23,c000a1ce,3bedd63d,a367b584,4f9b7b2b,a82fccca,b9a12a8c,2c1ca5f7,3e630173,e37e600f,f2fcfb6) +,S(282ef30e,f2d61d13,6f71e6df,6ee97ebd,a83036a3,2d3cd841,36289798,b3e71580,90b0cd33,c350ea2e,54c25264,7a3fc91f,5b4f9dc3,1f58e86f,c47825dc,e3d0f43a) +,S(a42b4d55,42acfa7c,b54ab3d5,ee0bebd,85bf6ea,db138ef7,1ea38c73,899eff23,17e38880,f10b9927,764c4997,326b0b9f,63d0e03a,fd2f0bd,b1ff3cca,1f566bb7) +,S(b23acc64,c5b00c8f,4b580d47,49589559,a06fcea5,75f3d38b,1a02251e,ff7ef00e,66bb180a,7eaa64d8,4bfe6a17,d457f5e7,73964ac,ff908729,3bc540aa,1cb6464f) +,S(942dce6,96aeb063,4681ce7a,407516e9,89df029c,ecc77023,411a628f,75885ea7,e208be8a,88be7b3f,6b6b06ce,a3aafb45,c439f0ba,d517a784,ba13f80b,707caf14) +,S(b8a6a2b9,52194ec0,8238e4db,e71eb948,23e64a94,e10ea0e1,610465ab,88392d16,f8029f31,b8e5ee3f,77a758ae,343be258,34c7bef4,c1b555c7,4cb63d51,cba5fec1) +,S(a36d3369,a1ee05f7,b1fdb083,ea614cb6,f15feac4,17a416d9,cc83fc2,868fc20,e4abd7f9,fe40f27d,5b7b7651,6a9fd714,aacd2ae0,5f0a1f10,e94327e3,76f0af52) +,S(4ea30108,3d711ae6,ffccc89b,9d6fd4d5,6f03bd68,f4508cc0,ebef5e43,88dda1d,81e9997a,8b1c5949,6554bcf,154166d3,40f9ea5f,ce55ec83,eed793d5,5ca3e513) +,S(20228716,1c1c89c7,64742e62,e427b712,fee118f,406a175e,ce2f424e,2affdc55,7837965e,cf26a7f3,428d2864,41e1d09a,91eaff0c,5ecd2c28,bc817766,67fa35b1) +,S(d3c072fc,8e4bf160,5790d429,61206123,95be9092,f166784c,f5adb7e8,6070d20c,72688262,594c75bb,bb55c0fa,af7991c8,f412e0eb,afd1c0c,f5bcab82,d8daf31a) +,S(294dac7c,e307fa7c,cf0e8f34,28a354d2,94003dbd,ca763dad,3e6df60e,530ec82,479fc222,a7bcaa62,aee807c4,ba6309e6,cfbcc783,afd49ecc,fb9b45f,cf84673d) +,S(3956ca5c,c09fe8d9,e4042a8d,67b276fe,225de609,ea24575c,7075d9ac,4e732fae,1c965fe7,a8219052,9d25ee0c,e1fd62f3,7196431d,7bd78302,e287a26a,2eeaa23e) +,S(24d2e396,da144b48,e736eb06,84940175,4f4109d6,6d87a9e6,97ee82bf,91fb3def,bb79e772,24b02fcf,dd1e3c9c,edbad212,ea875c75,1fe7c81e,76d7d0d9,a372236e) +,S(638d4042,f16e5c07,fcbf9619,dd9c2f91,18852889,3e12cd3a,b49e2b9b,99a2aa5e,d0d97842,4f0010a4,df9eb8b,8e5d8147,f618da43,74b8a4db,222e4ab2,b32b3d92) +,S(f91ad5b,a99972ba,bb323a1f,d3032e1d,94202d88,63680c5c,d7d67828,8f0d866c,60b66d45,a693175a,3a38bb4f,efb32dac,1cb558e1,b0d13571,e24a14d5,9452bdc0) +,S(3154137d,779c25f1,4ff1fb88,a6d0370b,9e6af48d,88e7fc39,c6417272,eaa69b7c,eb3bd91e,9c09178a,398e112a,9264484e,c1980c19,b1993b13,560d39fb,92295f7a) +,S(f8821e1f,dfdf9fc8,1e3acb3c,1d1d7a65,f710be2d,94a19355,721cb93,61549597,bb507868,c1e05282,51b635b9,dcf28e5a,c5770c05,c7afc2a3,f4b4c45b,7d8993ec) +,S(8409463a,521404a5,a2d8aa90,50e3ad8,ec5d6faf,870333b0,6dd4f63e,8354a655,cc99452b,85092ca5,39cc1b66,83b7ab37,1b8a6525,269a1ecf,91b857be,e1db3bd4) +,S(96802411,12d370b5,6da22eb5,35745d9e,314380e5,68229e09,f7241066,3bc471,ddac2d37,7f03c201,ffa0419d,6596d103,27d6c703,13bb492f,f495f946,285d8f38) +,S(9d1abaec,9f5715a1,5c762824,4170951e,f85e87f,68ca5393,d3f9fc3f,a23a69c8,f21ee700,50dbb61c,238c89e6,29423538,71b010e7,98867bdd,149ad28b,3f28cadf) +,S(1fb96691,8db3af46,c37234b6,a4b04371,9886d6a0,5859ba32,f72742d6,141f7ae6,8bc13ecc,207efd91,f7f4c442,6e9a425a,a17b5578,20404eca,b09d5582,d41f7379) +,S(22d9e364,b9274dab,98bcb23,e0428e8a,416d54f0,5a781281,ee221db6,9e1ec7b8,5dc23258,f93d7db5,e5799195,b74e9519,4c300a91,28f924c1,c1e4865e,2d8407d) +,S(625fa450,aed083fb,30166766,d5874131,adb168c0,247cbff8,3987297b,f873e45d,720a8104,473dc904,65585ed2,1a0244f0,fbb5a286,5b8e5117,5a21f644,8776bb7b) +,S(24acb1c1,9b6dfc25,defb01c2,e2681ae8,2deacc0f,f21ae8ff,1f82f37,a6a2147f,f729d335,210e8061,8a8abdcd,b71aabe1,93f50ada,dfaf7d52,783991dd,d3ca5d4b) +,S(d2856803,a99d30d4,f3a328e3,bbf7db3b,6c6d1896,ba5b339f,33c1302c,f75ab555,9649994d,64705b87,62c98bbf,1b41b725,2b814a89,3e780fdf,5689c9da,692d6ff) +,S(80529e65,9d196884,b15e95ef,871e5fd8,8fb5298f,3bc7831b,50a0bc98,4cb5fe0a,868b3e4f,9ae4bea8,efde50bf,c5a5b268,b74b4a8,74e86de6,e9ae476f,10b3b778) +,S(7f9199aa,3b8201ed,5d288e49,49c43277,e0bb316,953f1dde,d0674d7e,8728e183,1aba673,d0372029,546c174a,3a72268c,ee9d7e41,dd97de2f,fcbe1f9f,1a5288b9) +,S(7d32c885,8e959f6,48c4674c,dcccb191,29b4566d,644d2fb7,6d0c8966,2c29ecbc,d90e94ec,b50bfee8,c951afb8,e65c7386,875ea99e,31f553e8,66e00342,6d39698) +,S(f2b961c0,9291ecc8,576ce67e,bbd1bf01,1f1727ff,ad9eb74c,bf8819e3,2d1abfbf,ebfe5849,5a1e6a36,46c38220,8656f638,ed0aec0a,d40c0524,1707102,3126f795) +,S(d9a0c689,95283291,972d6a72,897181b2,6b4ae317,4e98a676,f75bbfbf,81be876e,d36ae886,a0acbc9a,d1564d97,4d3f0309,e9039b93,bb350d92,2b7f8c7a,c6bfa042) +,S(c7a36324,6aeb7c8c,991b2aa7,10abdf5c,fff29912,30b3a69f,be2dd481,7c7c3e0a,1298fdd7,e448d2d,79986302,6b4b2d49,2b32148,d6d1e5f8,15f5b0c0,5c9e21f) +#endif +#if WINDOW_G > 11 +,S(635cd7a0,5064d3bc,66535a0,4dbf563a,640d2464,c7fe0ac4,8304214f,e4985a86,e40265,913e77f6,46735cfc,af9e2f30,e8d5f047,f3281a4c,e0453e27,e9e3ae1f) +,S(5da624f,38edea25,37f5b632,695b481a,eca54bb7,2169cadc,c5b91e10,989ee5f5,d3ea6dba,a1080300,fffaeeb2,43a5256e,48c28822,37b16505,a220d771,ca721779) +,S(aa4f64a2,b19775ec,92c1f687,1fe4b6d5,ce05278c,2976c80e,fe19284f,e87d4d5e,f39f117e,95fce0fb,6976e949,9583a66c,224ea028,8396518e,293793dc,3ed4f240) +,S(9b6518ea,99ff1b42,22a93f26,62e05551,d60969ec,ebe378c1,477b5c36,427e0641,2e9f1655,8650fb3b,43aea9dd,30532ff9,bebdf7c5,1d421656,27b7487d,8f93165a) +,S(6c9b9aa2,b5972e0f,a1e01138,1ddcbeb8,6547f47f,fb101159,4b193d00,ae97b562,af09d91c,8d4c71d2,be523d0f,9d205bda,a6e78eb2,67476d3b,1624a038,6275e27d) +,S(a2a1c880,3cdc95c5,5e636541,c7112a0,cf80aec6,a37e5f71,f5366612,db467cbe,c4cf570f,3638f040,ffe5410d,50d4b175,802e2e1a,c422fc2,73eb9b2d,4e23fc09) +,S(63d3750,c961ccd6,34a5af10,48897366,13102bae,20f2c8a9,ca8437e5,ab650427,87415332,74b39a76,72de90dc,698742a1,f21125f0,71393fa0,6d670045,8e339248) +,S(8d070e66,e4428255,a53e8fb,5845d14c,bcc97dbf,19b6930e,1f5160b2,52bdd04a,4bc98c82,4f2b4f04,c9884099,f173cd22,48cdef90,ceef4bb2,497da8dd,99487ecd) +,S(f1fe56a7,2e5f008b,b5014395,cc1658f,e3f3d4df,7b361456,175bfd2b,4a91c8bd,be5ffebe,e57a7da5,d01e302a,d3688567,a19caa5f,fe8a57b2,be2c866e,f5f275f2) +,S(802c9adb,d2eb969e,9ba71a95,675bcc7,b412399d,5aecd635,7476a1fe,73554b21,42132026,f547ce69,66e6527d,370f9c0e,cc3344c9,be1047ef,b7422e13,6772bc5e) +,S(95b1b6c0,9d6ced22,f0a5cd,abc7a594,9d24cda4,f178a745,c718204b,1493db56,bc143681,53033d16,ac8ce5e9,a6cf240d,27b2331d,36cb23dd,f69009d4,b6adb01d) +,S(eaed529,1f94eae,183b2aa4,e17022f1,7b79a06e,d76b169d,2d6483a6,a6ede35d,53d5b276,91c5899c,ddac1efa,3ad6baf0,bc6e377c,99ac7f8f,9cb27fb9,5dd559b3) +,S(77c44fe5,9f6f448c,72eb485b,6ef3f7f3,906d690e,367beabe,ac7b7359,9c27d770,bcd75022,6c440f80,2ccf0360,4e3d6b38,e6629c9f,facc49d3,83322eeb,fb1102fd) +,S(e863b2e2,f00f0a46,b6752002,cd936a88,11b6279,5411944e,fadae5fb,e40a0306,b5c79ba3,6da29f17,5b9caff,631e8ead,c2ed937d,66008358,b36fe044,67243a5f) +,S(226f5bef,93df71d0,b2feedda,4ada3098,3883adb4,f3dcedec,2721e72e,eef8f191,a09204b5,2bcebc14,8a0a08fb,e8458618,f966078b,d75ccfbc,c13233ce,741707c3) +,S(aa222fb0,8c1e7c53,9f3a82b3,9c6f08de,c33beda4,aff7c46e,3a4e9036,83467184,41105cf,21cafd39,821a7c3a,a6dff931,c1653d29,906b5d4a,c5dd6431,7c1c3765) +,S(1879c2cd,26ef4ed3,dc5220bb,397b1501,f94482cc,1236da82,239754f1,e1fec96a,912d5f35,75eade14,91fb1609,21d63042,4fc68951,cb73d351,464725b7,71f0d67d) +,S(be39e4a4,e7eed88b,f4a4cfc5,970d4b7e,6df6211e,bdc2bb76,7657ecb1,ac9902e0,d8b1e4f1,13fca7b7,6306d9a2,b4cf5a49,32ae54a4,5615c899,f94cc476,7e27cb4e) +,S(1ea72fce,33378c3d,d0302836,86c3f8a8,1c2912e4,7cf44631,d3fbdc2f,752d5786,e20f4558,fe1cdd14,ccff261a,fe506b78,cb6e2b0,807fc7c9,aed0b888,3748906e) +,S(56e33dd,67bff57d,e8c638e6,f32bc396,2d0ca011,b74db242,3ac662fa,da036806,4039c0cc,165e7130,9317d4e,41de57bf,50d78ecf,3e14ee2e,fbb3b93f,c393f461) +,S(51981691,a5f1d8df,1cafb95a,738b9e3e,d036ce54,f10a7447,c470cc2,e80f37ad,9fb9047,67cf2a99,766e3c2,6e97f045,d03fabdc,471ef664,d31aa662,c5972261) +,S(ef3a5685,77a59783,6b0be7f9,5f927996,b90db9b9,bcd57f30,16ec5979,98869dbd,51cfe457,ff22749e,949782c6,ae1f4783,fabe1136,4bb524d3,72ac3d8c,1b7c5e07) +,S(efc652a1,8c3a85ba,7ee9e0b1,6e3c6433,79a66882,5304a22,523c060d,af196415,8a656c14,cef91af3,1db2498,f5987083,8fcee71c,98c09d49,737447b3,54f7b2a5) +,S(cdda1fef,f4d5ce2c,d9802198,389880f1,8adc7962,c04a95de,f07370a1,884bbf82,8bc26ffc,b0c9dc05,d799174b,4a478162,4417f9ab,8536235a,e55c9b0,49e31d6c) +,S(6f3f3985,3454aa13,134b76d7,77dedd40,d46bb6ac,dc3a3a3f,93886847,b96cf0d4,a8ba499c,4f7ca1b5,ae7e5192,ea408344,b6e32491,e5649637,e4eec5c9,2cadba81) +,S(e52d11af,91abfb83,ea842065,ed8d804f,a2a3627d,85149ee8,61cd5df,e54b13e4,59f3106d,619e5672,cb21f6ed,4e73285d,2e132a3d,e3ed069,46838e12,a9cfff97) +,S(89fec736,f0de1cb6,45654d13,b32b3cab,8fb91869,c30e2ac0,66c0cfa3,9e7256ff,f9417ae8,4d3e1a6d,b6ab938d,9dfde62d,73e708db,b58f5ded,46b455ae,7e44274) +,S(5140f56,91b10553,ce86ce73,3028749f,52261520,a8903f75,31bdac09,22b70b29,91a1962b,9e02c23d,61f4ce,21c0ce90,ad0acf0b,fa250afd,dd67d72,aa2dc024) +,S(3c16130,93109917,1075e199,ed32f94b,579d0eb,85520d09,c0f90fc8,7d267b5c,d50d04df,e4040db9,3aa0010,7693ac01,e9f156ca,5e800e51,a5f7d36b,78ac64c3) +,S(fd87690e,63a50237,258b8a58,f0240552,a2d0b952,911d1fa8,be13eeb8,9be8bac9,406dc1ac,ccb968f5,6fa3ee35,247fc66b,b40f04e3,ac512474,58e4fea4,8a1b9225) +,S(8e4d1de,17e78f3,2ce8ad59,973b328e,99005ce0,6a8d9347,ebc7434b,d5a12a81,c6348f3e,744ca65d,744c843b,4bbf0d8a,992bafa8,8c31b6da,42919401,b1a2a8ae) +,S(382c7bcf,ea62c678,173b6eeb,ba58caaa,f4988104,1677bff6,ea739a0c,6c7743c2,190a5da,77e64243,53df7f27,e01c0f6a,67e9addc,afcd3523,7cf5539a,69c5eb7d) +,S(f56a8b4e,74b84807,539fa471,bea50795,25b0dac9,53bf5d29,e87d90d5,f914ed0f,5456d908,da57e612,3ab881c6,56a6ea24,8f9f201c,13915a48,c50151fb,c096db8b) +,S(908e9ffb,6a5e557a,1fef8ea2,b16b80c4,3af3652c,55f12a04,4ecfdb06,17965b80,beae28c9,d1b14cf0,f8182ca0,7ebc3137,b9c01094,ed6b6043,562de75a,878bc2ce) +,S(a6c30718,433381fd,16b22533,52934eb,3fad254b,99d41e78,7ef2e6e9,bec86ef4,47a9a286,a60d5102,4d129e4,e0309c72,9e266f82,5ee26f4,4bf90057,623fb818) +,S(948bad86,6c3e2c26,2d46163,52be20ae,30a652e3,4a299361,4766eb7,98b3e903,30d30622,ad478a2b,99c43b0f,915de0c,4321da4a,76a18d33,95b4c484,d9c35164) +,S(d6c92b9d,cb8a17ae,77788125,18782d36,9d536edc,f96d2c9f,c9e84d2,1cf6a3f2,dd9367a0,93518377,97b0ae88,1aec5d4b,ed68624,8ec2207b,9e0104af,2ade09b9) +,S(f9ff3d7b,7d8b13d6,46c641ca,64df802f,7b082209,a75ae328,54cef0fd,65566abd,ac58619e,1f192095,f7223022,43d811d1,b9269d28,a18711c8,c84e5960,32deec98) +,S(3dae1dba,3a70e0f7,209a920,42837ed5,7f4e767f,834d14e1,c3528f6e,92c8d5e0,7ae2468d,6ea1f2cf,e1fcdfad,3ffe87c9,5c7816d9,ea99332e,8b4d055,280f797f) +,S(27045105,6fcc937c,9cbffe13,f2aaeb0,8ffd227e,dbbc7ca,d0b4b01d,19b49937,11766a54,6c24fdfe,220d3724,661d6c75,bbd801f5,c4286ad4,d08a698f,1ffa4397) +,S(f9d95ff9,6c3260ee,cd434075,262fba81,2024c556,649c4865,bb90d65e,20defd22,37cbf7fd,8f741411,80a632ba,8304730b,a89d54a,1a5b1dda,24b026bc,17a13c2d) +,S(4e8df18,f90f67e9,fed8c6d5,b66cfbe6,ff0a86bb,db990214,48ab57c5,c5a7021f,7e69f8c5,ccf56413,453a2b1b,3b34843c,e9badfd,3a83729e,a2293fda,f2a621f5) +,S(8c2a4d2a,710a7fb2,1ba78383,63c66458,ab3d32bd,3be35821,c8a5b779,d2ffef9f,d532447d,27e42583,46171515,71bd6577,f82d8f91,ff39d205,caa5aac6,365511d6) +,S(28b7f3a0,19749cce,6fc677af,a8fae72e,c10e811e,d4b04e19,63143cef,87654b75,30471eb,3245ab39,1597c881,e71f4a1d,e241ba31,a678fe39,2ced5a63,845ec782) +,S(cb474d0f,fcb8e72c,257b5acb,999ec8e,d89f6494,cf4b008,8f6d7db,59be416b,ff7cd0ce,fc293cbb,8ab9a950,8759f856,9a0e59b3,effc00c7,e3a3051a,a16622fd) +,S(c33e6982,5dbebc40,265567fb,ede2a4a5,1a180034,2e9963f5,bd57b35f,4055b36c,22ff3ff5,7ce265ce,253b5061,599ab066,82c0cb5,91a51e0d,b798ec2c,c546be18) +,S(84bfc106,44d37123,71a441a8,4444a9ab,257e0745,b3d0ca0e,ee341838,19bd2237,7cbe56d5,7b7af706,c33d13ff,b3e4197b,afd7f421,1ece235a,e1c2187b,289ef6f1) +,S(9c312ec,d53b244e,fd40f003,f7e0835f,6063028a,5b0488dc,73599653,f97b713a,11bcbd0f,58fc77ef,854d0b16,188b4e8,59698ba5,fee41fe6,165449b1,4eb76d14) +,S(5c06af59,a22d6f2d,cd83bf4,e3bbcf21,d474f61a,e01d0433,2d0a82dc,af15cefc,476b4be9,f1c265fd,a8c6d70d,6c669aaf,41fbefb1,425e2be2,9048165a,4322aae8) +,S(777259c6,81a3ed43,b4c0eb54,7af39ebb,f44f0d71,c84602bf,2d6d45b3,f1b6bdcf,8a9d3753,5481858a,eec44851,4c834667,d6742b9c,f563ebba,22fde187,fb3bf754) +,S(b370601e,ae1fc1d3,14e4328b,4d0244de,174b8c4,766283c,e3820c50,41266842,8ef05079,2174c3b0,752a9abc,8d980ee3,eda7b5aa,4042a932,3e136834,bc125ac0) +,S(5af94ac0,7f8d6492,a472ad40,67097206,78086856,b01528bf,8248ac8e,dafe6584,8a54c7ce,57eade51,1d5f32ef,cef5f56c,b40dffd7,8cfe5655,2a9c3966,e62daf1a) +,S(8fe3c19c,e2e87055,385d4f23,c5832f37,4f84b41f,3f945945,81acb8e7,5b0586c6,f923099f,d16f44c3,a4314d49,1af193c9,2f5e2017,156f860,674f5ac,91728c28) +,S(d580961d,2642bd1e,5f9211b3,9b65eb5,e531d17f,a37bafc3,b5f288fc,13ac9a71,500c0554,337e8b43,36e50a6e,b12fa86,d9678cdc,5b38f650,e4f897e9,1b4185cb) +,S(255dced,529fa623,49e46033,86790c32,234e7967,5a9c5405,256cfbf1,4295e82b,7eeda9c4,7f3e1c7b,fc3253d3,faa46317,5dfba7cd,94f6cb10,c8f4b4a,7d799815) +,S(4b7ebfa7,9240451f,ab8476a4,ae48e55f,1a27c338,a8dd8458,bdbe422,ec891557,dfb260e9,f89135f6,fca23cf,ad7ed812,c12622d7,e4285284,8c63d83e,85b59085) +,S(919d0780,9e6092a9,a3b5819e,c67719d,3119569d,3bd14c7d,8f47f555,1f2fbf28,ca0b6af8,76d70f2c,ecbb2fa5,98d6118,c204d3d4,a30e24fd,cbcaf283,843d8094) +,S(466867a9,de89a944,5bed73bd,5ae342a4,9b8c896b,59eebf42,393dd536,8c70ee78,2a5d9707,b3e15823,79bd6ca,e8b7ed09,9cbb9f93,4ee96029,385d5678,aae042e1) +,S(71274d08,c8784517,8921526f,cf71258d,fc740d5b,be655f3c,d985cba2,c1db3f7b,e0af0130,a5be1434,f8d652bc,4406177b,3cdd2ca6,6abe7f56,d848def,fb4b25e0) +,S(a46e9048,2d25241d,13c693c1,f4e6068f,b6e8256d,1fb3111f,a0ae0e37,7ebe2bcd,7567700c,f22aab69,8126e7ac,961726ad,fdd708bf,d5ae5111,40f921be,94474eda) +,S(f7590b91,f2431126,85873b0f,77be6851,10ea918b,a26d3b5b,aec02bfa,a5e84abd,481848f8,594c94d0,c9b5d6cc,858dcbc8,2d25128d,5ea28e2e,ded935a4,62708999) +,S(2d7aa8e5,1282e1da,dad39d64,398f0790,4f966edf,aff5e3bc,9a22edde,428c2edf,12b2133c,42032099,eb33ea24,f1755f9d,a30b4da1,708cdfb5,7635b61a,335d9d79) +,S(91313f40,3302c47f,d9f113a5,581f135c,82280927,5f658607,99550fa9,7236d0e3,f8b6ec07,5e7804bf,461daee9,1f21285b,aa9e96c2,2e0cff27,c323f627,90838a77) +,S(da248119,9d385a7,8468e86e,1b146fbd,e0be031c,3a19d0de,2f44a1d5,6c6743cb,c07c897b,5f76f6ee,f2c62511,19b37c47,5d418b6,1d2cda66,6d39ef67,40348cbf) +,S(95e36a24,b1bc2e3,fb5e6082,de9ed432,760ec3f9,6f01dbd6,2e820268,dde82220,be6990d7,3abc4a3a,8f03b209,dcb4202b,52a74a87,1e1e3d01,7665e9d1,1ce1cb63) +,S(8b05b060,3abd75b0,c57489e4,51f811e1,afe54a87,15045cdf,4888333f,3ebc6e8b,1d10f881,45db40fb,889e2ddc,e81bda7c,27f5b615,acd6179d,bb30f4fe,7f40fb39) +,S(ffabca3b,764a327a,750bbb2b,a1cb8329,d43ec0b7,dcd8f728,55a9d30c,f3020f54,93970a65,c90ba260,5b2fb393,a4e994b4,c791965c,b60a1302,cf585443,6dd0f05a) +,S(b3a85aef,ef35e4a9,8f0f05fa,9752998a,d3514868,b133e7c0,a18fb053,b866c72,30115ee1,c21e5b9e,3d6b36c,54e700e8,9ee78c7,e88a2752,38f46d1f,5b6005e2) +,S(a4f1fd5f,4c233cf2,b9c5659,f666d51,5b78fc32,ebcb52d5,d155250c,c95b7ab5,91d19f85,726a1258,444419fe,c5219c7,33754325,89d92d52,c363d61c,81faa0da) +,S(97b84b4b,7baecf13,94bf3923,2b58b5ed,9eb14637,d29b3c98,bec3e624,15bbb0a,497db4af,be8e7b3a,13493d73,ca92b4b6,5eac7f30,d86dbbf4,8b86f495,2d162435) +,S(2ceba0d9,203e3666,75e78e96,51b5b57b,a9de5f82,3cc8569a,1c274d19,946312b3,d4c2fe86,f042cfde,41f0a88a,6d77c188,b7805db6,c6ab440a,488a75c3,8ed2b437) +,S(ab8b1930,6cddaca2,8be57b78,b4836998,912391cb,c6a41e10,e91b86a2,3f2b7009,fdbbabdc,79fba1ae,9d8472a1,7a648206,7abed651,36892a03,35128650,374172cf) +,S(2763029,1ff140b1,57eac2b5,9938f26b,c149705d,aa2dacd,6bb0d305,1a15b394,c2b6b32a,38dcb9e2,f4640838,c52f5ca0,55359479,86ecd875,a91504ac,49374ee6) +,S(22d1edbd,1cc1514c,7f91d793,3e9dd124,9e703fd0,8c65ed8e,6cc79eb5,cafc78c5,7453e7ee,a53ae741,13024fca,208a3816,a93942c1,2378ff7a,5e65678,c0a85efe) +,S(70d869c0,c5729e94,270fa559,bdb3fb8,b6146527,5ecedb7c,c8e7c9bd,acffe222,4bfcad32,8ce78fb4,617baec8,48c2c3a8,f8d41474,9c131657,115dcbb8,f6ec30c5) +,S(a25b45de,da8d5782,64f60dcc,da97bd28,ed9039c0,6bb7c97d,d4a24eb8,791b1647,8fd84983,fd2ad956,32376555,4c43a664,f306f11e,2f030c7d,fe1c68d8,aa43db8f) +,S(823fcd6c,9b237c0d,5aa38336,6737066f,3e77fa14,b975a5cf,39ca8a74,3b1024b8,e691a44d,29a4f2dd,e99c2ba3,bb6d4345,d1433e4b,d1c65d72,198f16b5,4424dde0) +,S(39a5a63,8244aef6,432b1247,d394d305,ee594bd2,6ed2433a,3a96c4ce,5a158d0c,147ced39,dd8b8494,d57ff37e,a24cb108,ee4b9f43,50c556cd,32df8b27,626a8023) +,S(8f9febb5,b85bb2dc,74aaf7b,81b27796,2a18f6bb,4879f5f8,de94aa56,b3206487,48daebd6,d4175a00,e37dbde,c2b57b3d,dc7474f2,ab6a093c,32a86acb,f610c2a2) +,S(fc16fb14,2f500856,4509158a,5f6b4e35,6a08db53,36e9d3f8,4f7a03d,9143f60c,8e9326f2,7e02b73a,10f4ada5,9db85fe7,4027584e,6b32aeaf,58bcf804,dc1f7a36) +,S(7db09ea7,17446f6e,9115d8f0,987eba83,eaecae01,f4201d78,8e292486,85c5a281,b4469cee,426d455d,f736b2ad,c12fd17e,79fd2167,c5a6f864,2733e327,c215742b) +,S(d45d1bf5,28baef1c,3ea56fda,b1f8d3c6,3df7caf5,c7ecb0b8,564fbc94,a4d9a57e,91e26984,64830e89,1cd21d3d,81ad7000,ad0c84d1,3c05a191,c1a172e1,16aeccc1) +,S(3faf0b75,1b6f85d8,550a9ffa,a7a26bb1,6a4d9c99,ae97678a,d43a1a91,75f03901,8a5d062a,a4e43cf6,5caaa39f,6386311c,be775d14,3b8d9368,b555c436,1844328f) +,S(54608cbe,8e08a472,79cc5e39,c65e1ec0,1eefdba3,3b127107,4926b06c,76efd121,a7695bc,40def81e,48ec5f91,cc98fc2b,9bdc2776,71d05afd,cb789e20,c540f038) +,S(559a0d89,50dfcd4,364e6955,23b56972,e8a201da,4e196d46,64dd580d,909823ec,7bf8e1ad,d6528b90,cedb8d5c,87f5953,5641e32b,6a6a7b4,c46e8052,e8dc71c3) +,S(166e8858,b5e2b9f2,b1648c34,41e5fc28,bb305ea9,b0679c3,1a996b94,acf467a8,9c9b306d,ff82fb42,acd8a6b9,108f9994,dc1b7c37,dd0c9d2a,f64205a3,92e5bdb2) +,S(40e29e8c,e66e83ba,a94ec5fc,3ae438ee,e5284f94,c5efe5a8,d41da738,38fe1941,7c71f71c,c01e7868,1cf154e2,73a23d0b,84ae684f,b0e709c3,9551884d,39acb2dc) +,S(6829c8f9,eb659ce6,7f87fc76,4661b400,6aeb8b3d,bf674408,1a844380,72d4ee7e,1d35530a,8332dc05,54e82522,5e9ff30b,6647fcb3,304fd908,ea506945,ca22913b) +,S(4a3fe05a,322e9fd3,93393b13,6e2af237,e25a2540,42d10e7a,dbb35d41,13658196,859a41f8,d4527641,a93c40d9,ef0ab175,78dbdc45,7edeaea1,f147018c,7901574c) +,S(de5817c9,a675eb2e,c1567ad5,a6467cc2,9e9ddec2,177f382,25a5e101,9aa44f94,4050ebd0,5413311c,df17e625,6d4bf102,71b45e17,4c8fcaf5,ec36567a,ccf723a4) +,S(fde29245,4f07f411,abdf1a2,6f3d8f38,daa7b9b3,1b51fe7a,155da5eb,5662a108,f2a4e6d3,7b39e929,ccf347a3,ac6c719f,f09d1756,e407371e,d98dfdc8,b727808a) +,S(f28d3cfb,6eb98ba1,76fc536d,6a772861,b0917415,d08c22e8,a43a90ed,eff42436,4508be2b,b328250d,e043dc82,d8894aa4,1971fe8c,42e6cb61,e9d02735,1279d1bf) +,S(c7655c30,4d1cb5b7,d0992afb,119a6df7,7bb65496,420f78c7,117b951,7f16e3ee,898162c2,cdb730dc,4b986b1c,b0de79c1,a348b0be,51b9070d,2e427e2d,e71dfdfd) +,S(e57d97c7,2fa3ee66,71d67936,eb62f4d8,53ffba74,f2158d0d,7ae3eca0,7b4b147,b1e3012c,a3d92975,91ab80b9,a668ca13,1ed42660,47c34958,c07c720f,e1fecd64) +,S(eada8642,155025bf,c0644f92,fe014ccb,6cd3d37b,76686a44,bccdf8c1,e22b0c01,89035d7d,71d71bb0,117c37c5,540f82a5,7152aac,af79fe91,6aed7d2,9dfeeed) +,S(3e76267e,3f172198,9f9d7e8e,11fa3ff,62dbf8f9,77503e27,5567ec84,e60d0e25,a1835790,9631c6db,a453001e,c7e3973a,416f8bc7,e2fe0871,82d8a236,6e1160b6) +,S(a11d97d8,9c262f35,2279e69,2d66be7e,5de7235,18e6750c,6972d250,91a3df70,d18df8a3,dd6fb016,df2e48fe,ab889165,44768d77,e9488b71,fd31c6db,d52a69dd) +,S(b16e3f75,cefec06e,edd54bf8,dae7cc29,a5ab5208,fd58d787,922f4221,f5f20651,57fbfeb4,5a6e32ed,74fc1989,16909891,233ae90,c539b81d,a758761a,a6d0eb2d) +,S(37de800a,3f73ea6e,9eb564c2,faf147a4,837339b3,44a33d9f,beb25784,c74628b2,59339259,9da55803,196b7e5,3596aad7,e33fc96c,fa2ae0a0,2f41ec13,e6254050) +,S(6f68412d,65b3abaf,6fcb781d,8b6e6baa,4ae57fb0,9325a1f1,9beec438,cbd68055,884fd59d,406171bc,b31042,21abb5d,27dc1433,ef49af08,ec031543,2f8d3bcc) +,S(91479a9e,6bc5e261,24cf0ce2,b52f070f,980f1f9a,f60bca79,572902d6,cb6e4366,2304f70a,22de4435,99f6025d,4b13be27,47932524,112f64a,ef935d1a,9c2f5288) +,S(8ba6b0df,36ac8708,8c1e7c1e,4177dcc9,4cceabc7,4a6c7701,8358c194,4d19bd8a,e96b720e,e9d515e2,922abe8a,177ac755,989dff1b,789a85ba,ad17f859,62ab9ed4) +,S(ab152195,871f3fcc,58f59a8c,a35514f0,f11b8a69,54e4ec9e,f4aacb7b,29d567cc,c1ddad48,623ebda1,42899ad1,75f88ff1,965ec1ca,651b419c,3c8ea037,f267fb4) +,S(7eb23f48,5eb92bd0,1c0e6448,e19adc22,6ca45c46,d4d5c756,e552ce7d,551600c5,953e9b12,4278b939,7b3de07,63e30c55,a300ef97,a8587328,b3dc27b1,a7c57ac5) +,S(b23f4c2b,a4b2700d,c7520a92,25890491,e0212fb7,eeb1f0a,2f624905,4e21ee17,a38b6772,9e95b3af,2cc7d5a5,c10386c2,8a2c287e,6349f811,457ae0dd,8b598530) +,S(85d2e723,387e55b6,a2c1a02b,96cfad64,67a6c12e,b75424a9,a10ab77,2769c2a4,727abdac,223898af,1b077fb,7d481434,ded380cf,21a131d0,db845150,c8e4d303) +,S(27c1715e,8dba4cc,41383d59,e669f66a,54ae6901,88a794be,9fd8da6c,9b09273d,2767ca54,306e6ca2,3517d884,1e7f30f3,e16e22c5,cf2bbf9d,998d5cd4,b5b1a266) +,S(e70b8cd3,7f9a5e8e,9e0c4fb5,6f85a6ab,42cf4042,4080350f,4465cf8b,95eed89,2e3d8c58,94788d1b,9734e93c,7508cad,faacdf06,319854fe,5ec4b0fe,6b0cb31a) +,S(e23dd455,24058396,98c81a39,f3f076ae,93932c61,d0e7f65e,e2c2013c,dde956b9,6c53cbd0,cd8ab8,bf5cef85,a8aa0b64,52b57e79,cb53315b,1dcdb68b,78cf77c9) +,S(5e923f81,ccc49813,11a09f2c,47677cbb,9aaf0832,10c683b7,d7a07399,4d919c9f,604d7112,e64cad06,fe0e64a8,af7054fe,7059667c,fb5159f7,738b97f4,38306873) +,S(23d9f253,1a9fa278,e02b71d7,113fde6b,1380e543,633286a5,60037ab7,70142507,55dc8247,b6eb6119,a6ef49f6,bb4e85e3,a9fd201,4f696564,42d3372b,fe44a9ac) +,S(eeb23095,ad2551ef,15dbb281,5ef6d252,886c79ef,12c7318a,50f5d89,d73b8f24,d1a71b94,b9810ce8,eb0c3896,3e7cfb90,56a80f82,9d384eac,67d9859b,11ba1ddb) +,S(64a6de7b,57bdf7e2,54beee53,6efeea9b,899a8436,e421e3c0,e7a2682b,54b7c21b,6427936e,2e344fca,c402e2d,2902fc6f,181ad190,e3f0d537,cf40c96f,27b4755b) +,S(9e4676ce,d76daf3f,1c1aad5e,51e700b8,8207fd45,3cec846d,779f02c2,cc270073,5685c781,1d7610ad,4655019,5d8a844b,6ffc4acc,eb458c38,d9d74f4b,cbdc9e42) +,S(95ee1228,80616ba1,76e0ee23,14428c7b,1d83c635,6ec843e5,d134b359,8d645473,7be34c64,41914c07,58081278,9b254c71,49a60d13,c6ee3a3,7d12e29e,a3bf4054) +,S(e53ffeef,d92081a2,f91df506,6453cbdf,d0b1089a,c598da9,94fe4c03,fc6516ad,560f02c1,4a600d02,a2e70b28,5164618f,5dcd1b67,ac071929,ecc1d891,e4c59c2f) +,S(9c332744,7c75488c,5a14f1ad,fa3d9974,90d4eb10,63afba83,fafcc3ea,62a7b68,9cc759fb,9a7fc3b,4d0ff7d2,24d0cc54,cacfb78f,5590eb8a,d689b6ee,19791c63) +,S(e826d500,2f4315ff,77eb22b0,c8b74142,f1d1037e,81e3c58e,4ea39430,973d3c45,3a466e58,82f971f4,3ab9316d,fc7d53a4,e8ab16e0,2ae75045,5d8d1999,bc8b65de) +,S(ced4df0e,af93b5c4,8dcf196c,6e9b16bc,dd38a87b,3fd67512,d387b388,115e13c7,fe08a63b,dd149dca,b4f2c930,99cd11e1,8c754271,cedd597e,910462c6,d68b74cc) +,S(b056ed27,88ea50df,2b220182,df38f54f,8065e36d,e0218b27,ee8c5416,db7eb33d,97338375,cef457f9,ebe43aa8,28e9a1e9,8d514d9f,fc300a6b,a1a83db,dacf6409) +,S(35dec74,2fef94a,7fe60b66,7341f6a3,eba030c0,4061d156,1c9ee288,5b7830df,2599121,39c810fd,e7f02fe6,eb6e9221,3eb8be6e,4d8f045c,aba1f058,789b933e) +,S(3f23cc8,7733213f,d2e15cb9,942af44f,d7981e97,37c5af1f,81addfb,324e020b,24e8ccc0,d43ccde3,4e392455,dcdec100,7ffc0c61,3b5f865a,c8afc051,756e8f83) +,S(9ba96c76,c0805cea,d7ecfa43,dba0d86f,c8471dcc,8bce9bc1,e06537ef,2bbabbdb,c1a3c433,1c2ae04d,be2f8e3a,8f4f07b1,622d9820,607ee3ae,e93bc37,f943def3) +,S(83c1479a,31475395,8d510396,5decc9ce,1d414f41,610e2ac5,c2e887d7,d16a3815,84d4d018,1354cd46,e5f39bbf,f9fffbba,c123d470,d07c292c,7f085740,289b5b7a) +,S(bacf627a,2db11d88,76e6714a,2857db8,a8d7010d,7b349ab1,fcb5ebc7,efe0a32d,a287dc0d,a44c448e,68b777b7,36ace20a,14b3e586,bab7ef5e,d57ae303,e8c83129) +,S(73063c55,30129f79,10bfd2d3,a0147167,4ca888d1,d64d24d4,619c5cff,2776ebd7,d57941d9,44ccf8c8,2fab0362,b14986c5,9d71906c,d28584ea,368c4bb2,2c159489) +,S(4ee8632,df55ad15,12ba4ce3,4ddb403e,a3f51a12,d445a011,4d08a00b,3b5d6637,c29f7199,dc30275a,39ff01a3,19723d19,91687901,9616fd81,88ae6c45,92b14820) +,S(fc46e66d,68bbd41f,98b18a16,a23efaca,8f5345ef,b567786c,cd42afe7,d7e7ef28,8b42a2df,abf8849d,53daf38a,4a4c28b9,a0238231,ec8f69d5,d702715,a643c18a) +,S(a71ad1b0,158d7978,7eece5e,2a3907b1,3f9b6b98,aefc7963,8a9de618,b3a7dc13,6fd7e86d,a956c464,e538a864,41b9b7d2,ccfc5c44,e80a66ea,4375e6a1,ef08bf90) +,S(602185f3,6075a67f,d7bb9957,60c6af59,61a7c553,d51d828d,ed37768,f1860a3a,90d312db,706b835e,647a027c,e7a89d39,2265cd4,dd52e802,165c32bd,4d10b2e7) +,S(db0fca83,76729191,b9d9976d,37dc62c3,36b4437f,943706b5,98e7b7df,607a77ca,23dedd6e,8eba7ebf,e0c9f0b3,2a1802fa,78699a68,99507dd9,c4f4841d,82efc29d) +,S(6919b861,598d4f09,2a159909,fff8de82,237d0aec,339d884,7618f257,a4a54939,ab9f82fe,1fa53aa3,b85c0784,59a4e191,27a1a214,392c3ff2,f3e1cbdb,6f34b90c) +,S(f4a7d2e9,f1f51ba7,c3cf0a5d,5d53a00e,877ec118,f7e39e39,299efb2e,8074bd59,9f050900,6aa6ace2,da4e6380,cbce7983,c9bea9d,99741be0,ef17e190,2c5bd257) +,S(8a5d7210,d4f1de13,1091ae23,2fffbd96,3927317e,54197656,366b2e35,cd453da3,9aff8a1b,5b71da0e,a6558a05,a9306adb,4cae1004,e532aa98,abcd1644,b0580a54) +,S(99eb23dc,e40d7159,b0a0406b,ea04b87a,2c9195c2,2afd79f3,f938018e,b8e86f16,2ef21938,a66efdec,7ff6cdda,a79fcabf,b1f17fde,9e80db37,82b47d41,64ecff66) +,S(3bf16e84,1a874418,ac7f0d0b,9abbe781,611ad0e4,7acbe904,a99ba65a,b4d37472,1d3cb9f4,e1948cb2,fc88c0f1,9277437c,7d1138b2,8aef4355,1fb35121,a3e714ad) +,S(a3ef83ff,19eb394e,b87c133,36388a86,561811ce,5449895a,f459fe4f,e7f01f3e,1955dd39,8bdcaccb,cdc7ddb4,711d08e1,9d687ccd,d335a4a1,45d13a4,8178cbab) +,S(26816f51,da9b4e81,3edc024c,223dd6b4,5a344d11,f5ade552,63ef17e,70b1af90,46278e1d,1d6b67a3,57280967,6604e897,65611b7f,bbccfd30,22007a60,294aabd6) +,S(5e1653c0,d640f148,ecbb14f6,97940b0f,1d47dcc9,48e7525a,909e8444,afdea823,9b8b81ed,e7cb8350,ecfaef22,92bdc528,8e499cc9,6feedc86,cd45cccf,4cb092c7) +,S(1bd88e45,b0d3694,56348c23,125b12b6,b7725d6f,addc08f2,47fe9dbd,e828de9e,182939e3,2d8bddda,577dae7c,a1d40164,9f6faf68,69808fe2,98dba2f,b8a95db0) +,S(4b03fe06,3adc4e40,315e754f,bebb7802,b80ab716,d4201fbd,31b12c5f,d9b73c02,a864d0a8,e2c5e519,ced537,e03f98e3,a5623c31,ea4a430e,73e8cf54,1c80fb06) +,S(e20a515,7818f33,1ed927f1,3c46f3b5,2146860f,d085e68c,5884f1e8,45d35f61,a1c12002,1a79d6c5,89e466c4,3fd48f66,a924e9a0,a3d20db0,484875e6,96bcf328) +,S(e3d11a4e,74a1e1cd,8be24d87,4885e1eb,4aaecea1,c802ba73,2db925c7,f81e37be,8f1ec01e,a1ef01f,63806787,b8831d4b,22b0a9c,7b44bc7f,73d2a3b6,861645f5) +,S(8a233215,57fe0dbe,e8e92b58,4729b163,da71fa32,f400617,d1e2a081,3e37f6e5,af5e471a,bb8c7505,aea1ed74,bd7798cb,267dbd29,61c35f5e,93889056,aecce950) +,S(3bbc0a2c,b43f4683,151070e0,7015cd6,997e8dfa,99685cbe,99f9a76d,6851d20d,9a1dfb8e,a5f14c40,b9968e88,b6083111,fd140843,96fa8278,bb0e351b,7cb4f97d) +,S(8c04d781,82d83ab,e8c59dac,9407b4b9,65380f38,39431184,811e133c,911d1deb,4d74e493,fdb22316,fcf21340,88039534,c0a3e098,7198ceab,4a65260b,4c0a3db4) +,S(467d4d0e,72312cde,df0aa7c4,62e03644,1ed9f915,c9e7e8c8,5770a4d6,d6a0291f,83db40a9,d7c2954a,30c624dd,f11d565a,f117e240,183a81fc,d4dda1d,70a1ce32) +,S(b62f60cd,8e55a101,ab060186,941cbd52,ce73ae2d,e19ac195,d55f498c,45a3dc8c,59da48b0,7c6d2562,eeb0ed09,158cd20b,4a5108b8,fbf6fcef,428cc301,b314ef41) +,S(6b5d6210,f98aee61,df36d7f1,9546efe9,166e88cc,6492183,379dd1b5,cb9e681f,dbfb1748,59c88a6b,72c8afca,830045c2,7c6de87a,c47228e7,7f246e6f,698a0d76) +,S(88744d04,e8c7842b,68d2cc9e,f58977cc,548768db,48d3c286,49ecd0a,22300c97,84573aa5,1ea3c51e,5a0b0e42,5c7c90b6,149d2993,91085bc0,393f58a2,8fb9c38c) +,S(fdf2c824,40f2ac58,19b06571,216ad938,d0218ba5,be4d3d4b,ada80e32,c32e37c8,c2abc4b5,9e961ffb,e48c6f20,58602dfd,9172031a,740668b5,5876d5aa,5d538f74) +,S(4d2fdf64,1f5a883b,322273bd,24755405,15178ce0,9b4ce8a9,36648957,ef777559,22ba1d01,210bf31c,6421b89b,9b3217ae,b2837f01,c344a9fa,bed0b385,4aa41b11) +,S(ec7cbca1,e743bfdf,81af3fae,a5c64a8f,5a54dccc,2afca269,9c461592,34ddc633,9f193da9,ea76a050,7b528c05,e5a10107,dc5263e4,98fcee29,5f57816e,4eab0917) +,S(ff2fa113,771998b8,b801e779,3cb804c,da9cd6df,9d371943,c7fabbc0,44b44fdf,962127f2,1ac57670,c79d966d,b8cd6f0a,2aec6824,22cac54,23746bcb,2df6093c) +,S(6d1b406b,2dfb02d2,34ec21be,c436d6af,4fd418c9,29f175ee,6475e77a,8a57580,b8945668,9dba8e2f,8f0693d6,d3e7b602,f157efe5,38b9ef07,b2dea23d,bce895eb) +,S(4abb9dfb,449e00ce,46476727,dc6b96,317bff7,74c21df5,87bef539,644d7963,6086f2b7,c016c69b,2ad80786,89af1c98,4d6dbba8,7545d8e4,9c2c58bd,f86e6407) +,S(db0c51cc,634a4096,374b0b89,5584a3ca,2fb3bea4,fd0ee236,1f8db63a,650fcee6,7ec0bd2b,aea1ae18,4bd16fd3,97b0e64d,5d28257f,85836486,367fe33c,c5b6e6a0) +,S(ae6f6dbc,d0664919,a65e02ed,646de704,6996a382,21aa8e74,4954d22c,37fdb287,abe70eae,f8ae7404,11931379,19f9102e,c5bbb2f5,f5fefd1b,b76fb6a1,c3f2f201) +,S(aea3eb97,cb321f30,bd0771a9,17fc9770,f4079a62,fac51fda,63dd3ac8,d35f6227,b6a53416,398515c5,e9133704,a287dfdf,878145a1,4416b525,6f1ae46,6abf39b6) +,S(90c9f8cf,711d50de,81f7234e,f6c13af8,39355c06,3e891ded,51bca1c,852233be,8d95778,18f19649,f2d3d452,81358783,17d2c32e,aa01551e,d7fe21c8,3421bff5) +,S(5ad7ece5,ab1d0344,5528dcde,34b48efe,fd954aab,920260e2,1495ed8c,86d976e0,2df2163b,2c3c63ab,bef274e9,3c46b6e0,62ac9444,b17843d8,70014b03,f78569b0) +,S(b6ba2e2c,8e942ef0,16e6d3ee,13ab0cac,1d80ae7d,588a831c,b7844e8e,3bd28d9a,41180a35,f923dfdf,501b6b06,7d241160,a2ebf453,d00b501d,855ddb7,1bef7fb4) +,S(7e409bc9,bba26c7d,fabdd450,bc84589c,799555a9,c6809cc4,13a4c674,7ff5f37d,c518961,9cc5afe2,e41c4260,481d8fdf,6066b034,19fe030c,e423dee7,79c9e6b1) +,S(9486cd14,70b2f2ee,28d01060,6c7c4c22,2c72636a,a50b64e0,3008516e,de4f602c,886ccb8c,fc5b006f,df931785,f732367e,c062e9a3,49f452ce,aacfb74b,deb467af) +,S(e7c11d7b,c8b07205,1e1af6d8,745ba05e,94b1ee9c,5482d83b,1af9ed8b,21338d2a,fdc4d293,828cab1e,fc9062aa,192f35a9,6ad4683d,797fcf79,c74852de,d75c8e50) +,S(dfe627b,ff315cb0,1b1b67b2,776ded35,19b1a85d,8e802217,c98000f0,93d50bcd,993c55eb,bb65087b,6fdd2480,c9d68e6b,ea0f69d1,b95efc28,5f32a8ee,55f9e773) +,S(a0f0cc17,fd00a2cb,5fc7c981,860f02f3,eb31c26d,54841dde,189eac65,a446f516,bfae884c,31d58a3b,f11077a7,d3edd37e,14bbe4ea,bd30fa74,ff5c295e,4b3b8969) +,S(c1dbb6bc,bc14286e,d6eef926,c946b52b,d37e7f53,91fe1dd9,dd7b72ba,a3e37338,67b02d87,bd336882,f4b6fdc8,1a3a88d7,aa5e2735,139e1bd0,e793e6a6,12df7bf0) +,S(20b9065b,c7d495c4,c92cb1f0,6eedf5ef,7025511,10343eeb,e82505bc,bb4bebb2,a6987316,5c231d92,bd21a4f9,60242d9,4fec71a7,4b24fbd,55d51246,10756835) +,S(7bedfdd0,c4d8c38,dda9544d,38fc8786,55ab9a66,4f8dbf2e,3c54810,eda69190,9994f0b0,d4f52de,6ead0049,172fee05,365556e5,3c9d4591,690715a6,f8af77a1) +,S(26762eaf,997983f6,ac63815b,720e97cb,5adcadd2,419d368,df4d385e,6b5918e0,81f5448c,e11b4dbc,24be2e9,be5620fd,25f0c0d6,76aae549,2792188d,5a27e6be) +,S(7148cae7,ee18e152,c3354ff5,dda86e13,ea14f175,92d0d3d9,a944f4cd,f387bb79,bdb35fa,f6f86e90,41465efe,dac6bc0e,ffd42a0b,eee83365,93dcb4de,2310b18d) +,S(27e45dd9,33ae2c33,a69ae00b,156845b5,bb4d8f06,593c2723,5038ce17,87bdbc90,a2bce33f,a93579a3,f8d9c75c,9271a2b1,7dfe36a0,590f2db1,f7cabfd6,51801ac9) +,S(af0c7215,5b28ae8c,2a2d79c7,d81e603c,d0539c11,fed2aa98,fa2bf2b2,d7d6b7d7,ae6bdfcf,a25109c0,b80bfc,71cfac3e,3b5b26e1,e4f2c856,40d2c69a,a7ac41f9) +,S(7b63c408,d4f8d34f,314e609b,21e8e372,de0f5a19,1accabec,7ecfe02a,63cbabf4,aa08009a,78fa96bd,8ceb6f65,e88859b6,236925d0,bccba7c,e0db29be,94f16327) +,S(ab768853,14f3e88b,d63cffb6,8f4f3232,4f4b4801,41aeff93,94d58f9b,85c6890c,1a71c833,d6d96bc1,c33610e,d7ff1481,c9ff9841,157c59e0,5d3a036f,cf7f192c) +,S(641437f0,7ad75112,f8375487,cc0ed859,ccd308da,4b25e5a9,953e351c,9e3bd32e,3c58f7e6,b255346a,f50f1ba8,3f008662,7d2ec950,84c326b0,ccc3a388,81a9b131) +,S(f532fd2d,600ed478,c1dcceaf,fd01ae87,60f7ecc8,7739580b,9b4a7649,67a082cb,7393514c,71117d7f,7cdbb4d6,c803c9f3,221847ad,697c945e,440bcfa1,1285fa96) +,S(33679959,2c4bab44,d89e6f60,8f882938,db73dbd4,75f0dc3e,e1fbd075,b1c7631,4c1f8004,6fe89cf3,6d078251,5ff57cde,17125d62,5cf675aa,1fd70163,49694fbc) +,S(e184c16d,2a34ca57,b06b5396,28cac285,6f18b7e0,32970a5b,e2221a07,be56c9cb,7dffc17b,51ef9c4d,f16ab068,8c66df57,d646cd34,46b509c7,7f85e03d,e2c5bf73) +,S(f8a97d16,2fb49d55,bb8de990,9a20c1e3,4f6ce6d6,efb8c68f,e26c884,6415d419,3cd3cc53,4dbfca01,9492e161,61f2e86c,5f20a83a,866874a7,ded4c2e4,42061146) +,S(9eb6aa2f,6c6ad821,d46dd612,38d3dc53,28cfc406,ad71964e,b32de0ea,12475781,14501a83,79d32e09,3664ce34,1a419b28,53dfe3e8,fbc204af,cb33e347,6c45c299) +,S(ebc2566a,68e68955,e1e42740,323fd401,7c40315f,ceba7642,5f887a3c,3602668a,75e8109,96ff56e2,655f9f85,ae9ec9a5,fab3bdc1,42ef063a,a06931e4,d4c7ea39) +,S(55646438,a966ce5c,2fa5b29d,ba4840cb,ab9c5e4b,4074a9fd,674b7eb2,f52bc392,34631a86,76034a89,cfc3f68a,45cd52e6,2987d80c,e9a8e28f,a37020f,981c8d66) +,S(b87f8309,befb81f3,313257b8,c7dd914c,82eff5d,6729f2e7,eceb0337,7b16575e,bea66832,59e4002d,6fbdf03f,b80bec1b,eda5e1c2,cc55c630,deedb7fd,a96ea298) +,S(45957585,b440d63e,acf598b2,16e435e,24b6cf15,2892c8d7,953471df,70a0a93e,f4cb6260,776a4f4f,23ac366a,565067fb,b29739fc,233493a0,b3eaaea,c4b71427) +,S(2c90f64c,8d9c42bb,1824c821,8f9cc057,3fe8d648,b960ee11,1487bbe4,9648ca87,829bcd57,ac643cb6,9f000a9,f22fcf57,69bebf7d,6b1d8ab4,da21be41,d3c25a8a) +,S(eb327ac7,779c9abd,9546a3fc,c7731729,2e753912,2ba9f7be,36db0548,144b5efe,21ac2c85,8d2fcd38,8c32c594,d6e74803,2cbbf365,238565a0,8c439190,518c9435) +,S(95ec7e2,272ccca7,aa2b07fd,d37d0f08,daa35418,1ae30e6a,dba0cb1d,2c6d007d,733786ef,59df6050,552ac913,c10b8890,2d589e7e,4f740f33,75f78fc5,2ba12b5f) +,S(4b7a6698,8b4fa080,f27c845d,7ff17371,91104a29,2c6195f5,fc367c69,fc0cbbd1,8b043bd0,a3605612,87b38fd4,d99b29e4,8e52494d,8241207c,9284581b,63a85b8f) +,S(89b2c58b,6df581df,352ab28a,619027c0,a9233792,fc6525e7,47dabd31,a342e6b2,300b1b34,d459e65b,e265edea,203b74bc,9b053feb,888e81f4,10045a10,d7f53a2b) +,S(41099b5d,9f6a28d0,e4a7ff0d,b75ec487,1c926327,89f0c800,7ada8114,9bc43cf1,2a0aba96,2e2b92b6,e949253b,e06588d1,3e07919a,3594b26,995c15b7,7a62cae5) +,S(bcb0fc64,9ec508c3,507396b2,9a663555,8825ea9c,1389c817,af7fd616,7229be4,168c7992,cf3bf5ab,6c3a12ae,922e647,13664db9,2d7bfe5c,2c746933,3a07d606) +,S(7a3fc958,5a6256af,9e314ca7,55a8096,9cd3b3d6,f70349a5,ec719cd,ed8b762e,fe8b280c,29cd0716,35288526,b7179d90,dadecd78,39128f22,17d445cb,d3df1346) +,S(377093e1,b968a35e,e0f229e1,e656da9a,7583c1e6,d06fe1,c89e3f06,61a8176a,e7c0860d,f6c9f461,7e6a4dd0,b8c0d800,6aba8e88,20aeb82,e6e0f8a0,c2c601d9) +,S(c5eff3da,f4a5cccc,f1f27a93,361301a1,919b1dd2,5a98ea37,5ba63f14,4aafecd8,34e11634,26f983dc,18c8a02c,2222c2fd,a94129f,4e3f1d67,f424964c,dcb97a1c) +,S(fc7919,eb560d33,44230f72,8368afcb,3c0fa6f1,52ec54e9,84ea9ccb,e63ffb27,1c7d3782,af766ff9,bc1cb838,8e4a7dd0,a04bc4ce,adad3fa9,4132842a,9859a6b3) +,S(2783d7fb,49386d72,54434cd6,edc6f46f,b3118322,43d381c6,287d8b24,861ca5bd,a3aaf271,b806ac0,e3c45026,28f89c79,e4c68574,81710111,a9316e38,c7fa5c70) +,S(7407a478,68d4e0d0,f77f8949,5e5bbf95,88f54a6f,fd35d229,8ad4b30f,2d8a02f3,1250d562,96e18cb0,aa5b393e,a933297e,debf3d94,59ac1ce,24cc11b5,87fdec9c) +,S(c2d2cce3,2940ecda,77ac108e,71544079,c5899fa4,f8461df6,cc54dd21,a861a321,f0beb1fa,40bb8071,928b05e3,ecc8545b,a919eaa,e830db72,9e6de85b,f05a1909) +,S(8cf6b189,c5051956,6a94e1f5,ab5e9530,d459a935,4cb13eb,349fac3e,ade8a56f,bf6a9d70,32e52886,ce6d06d3,b22d47a8,327aa788,1621338c,1606054b,cfcf9c96) +,S(d6b07586,ed9f8471,f96ac5f,53277d1e,2deeaa2b,7fd09d51,ece6766d,29a94968,dab4d4b4,ce5655cf,4aef0d0d,5e3fa292,2f79041e,d2e23c9c,75be83f5,f09c5326) +,S(a720b733,60a03edf,f33a0921,90795834,9e661d33,44da800f,b857227b,ef4d647,1f213c6a,721c2d82,6037e3a5,a0f4867f,13d79dff,bd44f5b1,1bb5c0b5,4884ea63) +,S(558a5698,3b03c6c6,717db862,e59dd075,b39f9ba2,ca01b0ac,95a69cec,1f3a5ff7,7e07c752,db21b68b,21738458,a045fc60,fe3ae869,887fd557,92ecc6c7,d4ffb1a4) +,S(b927dfc3,278668a8,c5329941,f11d0e0a,a7c2d9d7,f8d6c263,9cab5550,10e14ca4,3ce83725,9954227b,b420e35f,77705225,72f4d854,999af552,4b8795c2,b723388c) +,S(2b70d499,1085aff5,88e23ed5,ab55a374,3c35f71c,651c0165,13f98ecc,4f0e6da8,df413b4d,aa1e5c9c,a2398469,7d82762f,a701413,1cae25cd,1a94f02a,506a8b06) +,S(b8836cdc,f72f6e00,99a9181d,94ba77e9,e1368e54,a62e1144,1421f2ef,2daefe56,9ad452f,e31f26d,cad7014b,68ceaeb6,1beecaa,5394c359,afa52209,e50427ce) +,S(252b297b,65f0e23a,9788b48,f33809a,ec66b445,cd90db00,4dcb6a80,c4af93a7,8cc4e0c4,3c346211,736a3bcf,c24a58bf,9f77c7d0,c53350e8,6cb0de2,60916838) +,S(9f3d30ca,1c15cc66,8efd5fa0,3d6b7bdb,d34f2704,cd729892,aad9171c,debe6330,448b6434,f95ee7a,bc056974,f1476171,353d9b98,4e22057b,38662327,b23211b0) +,S(8225e16e,5bc9add9,ff8a771b,5bc7bce1,653b545e,4e54b9e6,6e2d2985,2fd35e49,6254c5e3,aaefa2c1,6ca4e1de,87f09d94,df836b9d,d100612c,7174aa75,7d0570fa) +,S(a7dcee48,4d6e99b1,b72a80b7,4de255b1,74f4767,4d3c5799,4669ca6,aad02ebe,1d6f0cfa,76a2901f,4861f541,bef7a948,78586178,8c7c42a4,2db583ba,1c170a7) +,S(a91445a8,5d4ce90e,98d3372f,d2c664b8,9a6baa2b,a396fd1e,210e315e,809976b4,adc4c68b,99b072b1,b51d1512,cd94007c,72deacf9,4e7c5449,f1d83876,78b1d100) +,S(7462c9ce,907c9655,75c41096,3510e00f,6f6ea6ad,886cdc79,ed685ee2,2a7ce1f1,4ffa41c5,f02c2299,c42df5ac,79cc4140,47a854e8,332f8f2a,e67ffa20,bb71c7df) +,S(d42895f3,dea495bd,af8e36bb,6a79f234,dfd85544,965a8506,5d38ca86,28cd4f40,2fedeb18,13a11c42,e7869b20,7bb8486c,9821710f,a80d9bbd,59c92ae0,b50d9cf5) +,S(ef9b6b62,ce85588a,f13434b2,7ef53d12,e8291e6d,76a65669,c29d99a1,4d388adc,159f5fcf,9af0c962,ed907955,e91407ca,80261255,45b6938a,db18aee0,9bbf912f) +,S(4003f1a0,bc659daf,df5fb7bd,bc96afff,92877c7e,2a693f39,2afb06c8,fdbc9f32,ebffcaa1,7458f0b0,28ff1dcb,74be865d,7faeafa6,c2707cc9,ea685eb5,7961fef9) +,S(4390488b,6b03d851,648786f0,7486f5cd,aa9ae1d9,4867de,bed7036a,6ac09a8b,78329de5,a10db56b,1c35b88a,21ddf393,452001c1,29a0bd6e,5dd76a63,8682f07a) +,S(ae6da0d2,9ea3fb66,b6006c56,5dff8b41,6074ee16,f9ff86b9,60574067,abfadea1,74caaa63,dd012a63,e76f0916,f370614e,29e3f01e,b88b49c0,5ca33234,c11cdac7) +,S(78f879df,98614721,b7c65652,4e806f6,35942e0,950514fb,2fad8a86,bbcfc72a,4194e58c,478ae80b,fab661b7,ffb85cc7,2318aad3,88d61c68,a755296d,38281ac6) +,S(80684365,4f41b0c6,d6cd51cc,838355dc,352e028,7b1c1d1d,edd2f96e,5fc97e01,8b0c223f,13c61b4e,1e141a0d,35f29a7,7546bc7e,3b1e5c45,262033eb,92b62461) +,S(29509d9f,4fd975f4,6efd1169,1d97d0aa,f83b5934,9c797010,5cb3908,4b87466c,1477eb75,69a0af96,c9cfccbe,135e3c86,a33de585,2ead38da,8a0eba6a,6d0da81) +,S(191d1443,3d9c722f,c1532fe,33c63a9c,4e3d5741,6ebf799c,2d8ffeae,df1dfa4a,5bd00409,b6b571ad,745ecf83,91884eed,a5e3c7b6,65ec9706,eae4b4dd,703a2cd8) +,S(2843d42e,d2738168,5eed65af,eea82bf2,a50f0e1e,3db201e1,ebf8b159,1b0155a8,807cea66,c0fa9f53,b47e6e2c,232cb225,77edafb8,99a6f98,ff87d091,bbc63ee8) +,S(5568b7b0,9656d36f,5347514b,8e8212f8,e96ed02d,4516c018,4d653bd1,2bc8f644,5b44eba6,54836dc4,3fbda30d,7ea36406,4960459b,a4128911,8b2d8638,50e60d87) +,S(5b84e0e0,809e44a6,9e8d81ab,595b32f8,4a7dd421,c073fd6e,5f38ec5e,b145e803,1a65a2d0,fa791ced,72fa1522,ae431155,7e6109c0,fe934243,cb43d3ef,ad13d398) +,S(ef42c56b,dd241071,47e1519a,18d32910,675ba842,92cc8ede,900a64ea,bedfa672,70151747,33359977,611e0c25,4addbf6b,26a618a2,31474e3c,c9e7bcd3,8bff75ac) +,S(48dff2dc,b50d4a56,4be6ed00,3b1415b4,adc653ec,87eae94c,92b7c129,5656eb63,a9be97fb,53afecf6,f0bc59e9,8bfad542,fa29e63d,f701f6b5,f0f66081,8d643928) +,S(672e90f5,246ad174,10c9a2df,c22b098c,d1923bd4,19fdc337,f881e4fb,4ae938d4,73fd3380,1fda6db6,883e678b,31e5f09e,f331b624,5617ec9e,97aa28b9,a1781f19) +,S(59cdb9b1,71fb819c,909e094a,95dc15de,dbfe5521,4a7cb723,ee7cb761,4b315cde,55ac212,670b4a63,ecf3f8e7,3082009d,7f2d38d9,e490ca18,7a6db01b,e88351a2) +,S(5ce38d0a,357a58ab,134db879,b99994c4,6b827f82,8e1ce8f0,43108de,ad2ddb18,5e816202,d9c1d86e,c2f84b33,ddbcc51b,94748c67,1089c9c1,745a14d9,3b97f716) +,S(c982196a,7466fbbb,b0e27a94,b6af926,c1a74d5a,d07128c8,2824a11b,5398afda,7a91f9ea,e64438af,b9ce6448,a1c133db,2d8fb925,4e4546b6,f001637d,50901f55) +,S(383cb084,79e61bec,dca81d29,7796d00f,60bfbcc2,83c83d31,725f5329,839ec818,26e26fa2,49008933,8bde0498,15f34d9,bbc3426,ad8644ff,db1a190f,79dec91e) +,S(e6945731,2ad4f14a,71917b52,448011df,28b88c9b,6ac84550,248ca4fd,102f612b,30ed2082,51fc701e,5ebeddda,c9eb0b44,c81cc86f,9706889c,1b1c3386,4d76f53d) +,S(2d0071ba,8f799352,212168d2,1262a729,250809f2,24fa58a7,f283c4c6,bb9976f7,cdca6901,4e4873f1,16945544,800079d,ccc118f1,a5709b03,c872b017,5f1dfd8b) +,S(c82b9457,65b74fbf,91cf35f0,679877b9,da35c2b0,8437d789,8d748f22,1e927e,2e504dd1,bb06bfc,7e057dae,9aac8f07,b57a0f2a,39b1533d,9313d9f2,45fd6a2) +,S(9c1a4c2e,7eac21a9,fed135ed,e737dd19,2654eda2,fb3a4227,63cb6328,75bbf0a6,f3134b6c,12f71c58,226c9128,9b7b5a06,80eb6646,e9da2e60,20008efe,10e9197f) +,S(971d3d9b,bc693222,ed8bd645,e80b7cf9,9b170a36,2d57753b,6a2ac27e,8d6c9b28,d63d49a,e296dc2c,6c4a73af,7fc5e86d,e2039433,f3858980,80a36f7f,91d22e2e) +,S(f5493a73,86bc1151,23f29f2a,e0619e05,660a317a,bf5ac23f,a67802fa,8b917d2b,e6adbccb,8b780530,2b305157,b427b8b5,38455e02,80133e23,9642306e,65e0f1d7) +,S(831f123e,500e0a0a,e497a321,5ebde2ad,763244fd,40b386da,dde05537,99b6e014,35616862,2ff588ac,552fa508,ceef5ef9,ac04af0a,9db6b950,f44719c8,cb221d6c) +,S(9b8ce06d,18474c,3394c334,2ef385d6,7a338c22,98e92975,f1728c87,897cfb35,76940220,b8dc3e04,7cda50c4,c1f53747,7ce8757,a4a3731d,712cea05,42a40d72) +,S(f70a916b,a98d2bc9,60172410,42bf3e14,14f06cad,dffa7cb,1e8137a7,3fc5b855,f1b8c1f4,70d7896f,f39a3fbe,997a88f3,b5426d84,43c4023f,ff98fffb,280275a2) +,S(2d2ab7bb,c44e7fe4,ab283661,2f621d05,a64d6909,fd94e599,92d52afa,c0763d56,53450e00,2a6991c8,68fe044e,8b61c2d3,c5fec8af,3605728a,e57d32cc,c55328e8) +,S(8178deb8,c516978c,ea25423f,3a913157,321ff7c5,5d8058f3,dc9b9d46,f4d10005,16a71b2b,46c9d303,f4ae6a28,235249bd,f9c00146,a26b6bfb,5983bfb6,8d6ff4bc) +,S(b470bb76,d012ba7e,67ef9c32,add59940,1f700ca,16003011,26e6a692,36b56a64,f7d093e0,7d179861,871f36f1,58d26987,1775f082,a2fbfa69,27cc2272,614fd95c) +,S(164f2aba,837cac12,19b48eb3,30f02141,d3a89921,1cdb3f78,fe17133f,e2de29ce,3bc05608,95f7d034,4a9ec79e,b821c06,c2837c50,66925197,2c076374,871d28dc) +,S(c77a3a04,2a86d2e,f512268b,35cbb89d,e6a210ea,883e2283,ec59fec5,12e725f4,2ebcd56b,edf1a07f,e587e592,8ed602b3,6d1db4e2,5b49e914,8dc9eedc,131cfba2) +,S(e2defa1,f714cf71,557a3f1d,71c6abe8,11df5504,da38e9f,60ad335,3b11349,5ed64303,7a53bbc7,2f41912e,a657d944,c5107da,3b9ab54b,d88b545a,e045f229) +,S(ee2d12cb,b4cd9e4c,163fca1e,5a4330af,35280ce9,cc1d57b2,d2112443,b6313e3c,e28b1dc1,a4377c65,838ecafa,bfffb696,4057fb6f,dd4baf08,49f9223a,ee153262) +,S(4392c96,73e6deca,f3c39c34,f5be7c3d,a2109b45,2271467c,78f256d6,7d9e28bd,7fe4c183,ae352533,b049edd5,343a6bb4,747d63d7,d0f406fd,5902a886,110c50) +,S(5972e2ee,167374ad,93a655f1,6008f49a,f5586b2,f81197a6,712ff31c,a0d6960,6d70fc55,d0a57c74,8a2e485a,d903bd72,779343fc,7c090847,bc3dec1a,6f7c71d6) +,S(a85d800a,fc2c0315,889f1faa,29e5766a,a180f31a,400e3c19,85589af0,302c78aa,7429d7f4,903c76a0,a4437b41,92865b7a,ff5aca7a,52dd32a5,8f8b00d,b97ec85e) +,S(c9836b0f,d594fcc,9a89e85d,7d506386,ccee3f38,72759cdc,9548569f,a5f1c245,9f0b1926,93b7fed6,2f1a7d06,fd716727,bed1c2c5,9bb431ed,943b7082,d094fac0) +,S(ca2184fd,b2b84654,d0348e5f,6d963193,75f2c441,ae64622b,588cae7f,d202bd3b,d1222820,3d657aac,493dbb2,fe9729b9,e2563cc8,1f671626,83c4f0fd,726a4de9) +,S(9e0515c6,3c9b9664,8762704,80605d56,b5dea0cc,c7a4c66b,44a2e605,36941fd8,29de3224,a2eb2d86,afef789e,2dba061e,95f0b762,117ede50,6d4b21c9,54be831a) +,S(42042c25,33203a7f,c22cf7a,fa5f3d79,8a3447da,51d66f60,53a8f000,af5dc1cc,f075a67a,6d6c3872,315420d5,bc13d13,c54f3c1d,61f73d9d,ff688da7,f5e6c05a) +,S(6645a1bd,4eab02be,45884ffd,288955fe,3f5a68ca,9ae431bc,cd3967c7,12295b96,231f79f9,1d264ed4,28ed4b30,f0e92c4c,bf902865,24050b67,30cccd12,bb84cfad) +,S(4e281e6d,2c316e88,231482ab,1587de37,6898f3a8,870f475f,30bd1ee8,d4b32f9f,f48cadc8,1c119edd,e5f78062,cddc3416,c3f708d5,f37e4910,11ef7581,c065602c) +,S(77236414,96e41e9f,f13c7ffb,c7a66203,4fbaf7d3,e432ce02,fcd54ef0,4aaf5136,222e0174,d6cc01e,fb4b4bf2,9000f697,98bec7a0,657f328c,80083074,242dd218) +,S(3f2b704c,8d467859,ada6070c,b1221840,18ab009f,f7b5ebdd,af31d977,dd45860,a47167a5,146aeb5e,8c38dd21,5d61a2df,e2b6ab8b,fd05ea9f,b59faea8,3b4dd88a) +,S(794ec130,d243d811,2ebb70f0,35f983db,84b3acd0,ae4c5b51,640b9e92,ecad4146,49edecbe,95c25c7c,eeca537f,937aef5c,658f2dd5,d8c0de71,c80777aa,d07be84d) +,S(750ff9ec,e363e12b,79b04cf4,a7b1c0b1,49c554cd,6e9fe3ba,808c9614,95a96aa3,5a28269d,d1c5a3ed,f4e70f14,9a060b42,2d4474bf,1e4c6dfb,2de1502f,7a1d59a9) +,S(d65c05d7,df6668ec,b96c9ec1,fd129462,263b082c,9b7f4169,6335fb2a,b66272cf,d7728c5,1c10d42d,242cc5b7,fc77fdad,7e48be06,6b2f7c37,891ba4f0,de188839) +,S(d3804cb6,8cb2e9e9,b5b9d270,db9a172,aecffe39,72a3d2f6,1225bef5,595190c3,11fb350c,9568648b,30af4131,46053428,2879023e,6ff0d613,482c2471,b5e30d5e) +,S(f762de26,35c6349f,6cc95c61,9ecf8d37,6a938241,1106db3d,b34e9e84,70351bf6,dc67f9e0,c8a50f9e,e753352d,a99112e4,ccfe22d,3e88410b,1cadc0ba,bc9fd814) +,S(ab18b4bf,a827ff4b,17ee163e,d17e3927,d7dcecee,ba87ce7d,ac5e5767,53b87a71,6db83bd5,73e40926,c882bc09,c4d07f72,29706d1c,d2b1ded5,b57ea9b9,2b0da919) +,S(f754c248,fec21ae8,da343a87,459622a,b12478ad,8f63ad8b,f5c66695,198c95e,2cfb76a2,5f9c8776,b848d8e6,7f544774,e056ca7a,32bbae52,93b27992,6052b1bd) +,S(f8d9473e,3c3f0798,f893ecdb,716bca16,103516c3,1341c8e2,c2462d4f,9a46c51c,55f0065f,a422fe3a,26b314da,c7547835,5c53bd3b,e11b4686,9e05be92,d7924e02) +,S(8639942,d294cbc8,9a75fa22,5b29fda9,2f7c5ab4,bfbc4395,352d050d,754eb741,3913ea2a,445de35a,36d79abd,db3ed7cf,741da883,4cb81c29,6779d8a9,e7d11e4d) +,S(2a588c6c,706a388b,f1719230,b5a71b4a,6857282,83aec61,794d1a78,bb95d5c2,af25ed77,1a56f6d9,6407f07e,a7e11f97,61f458ae,bfbb1b00,96842c4b,6cc47592) +,S(137bd1ee,8931b9a8,b26dba4a,d9a5edb0,a5459717,22e1fe3,37ee8d54,20a0cb6,cde9fb7b,8197c77d,273e9f0e,e87d76a1,eaea105e,21154b7f,f5848a30,17ceea62) +,S(46580345,c686313c,97152371,13af2c2a,f9b5fea,a1e0bb48,d21bbe32,d2de2bbf,75bc5d7b,b6329ffb,2bfbc79d,b66f4c2a,7edade8e,a16bb051,a3a8ee9,ec92ef64) +,S(4a149252,afaf5acd,982fc491,c26af545,2ef93d6,1b282a85,56d5ef64,391bd233,fbc100bc,10b55b60,96656ea3,863f5d4b,bb9e83fc,5a25e59a,3b53d78f,60cfe285) +,S(894ebda6,fc0bcf8f,e025131,3475d64b,95bdf089,7d9753fa,ad0f92f2,15a01f18,b25f3150,155772cf,c69d0251,97d37ae0,1e4ede02,e2994377,9fae26cf,5f5ec056) +,S(e70d8a93,a91b891,30def1b2,bfd720ac,2deedca6,f9e5a85a,3c2a6eae,45eb032e,bd3aee53,a3b0ff6b,45fb96ea,4911cb02,fe102681,878a1b0a,693fdf11,4cd9f9cc) +,S(7cb1fdc3,e5ccb1dd,4a16765b,f9546b6a,1189883f,135d447e,eb245fbb,4eb36852,90ee0d6,becf5ff7,b80edbe1,75dbf258,d1889008,a8fed4e0,1968e2ca,8fca582d) +,S(51278ad8,331da17,8fc90a21,432b9058,b39f57d0,31210685,bf9bfbc2,87b9bfc1,5aaf547,f39ce678,8c3ad759,b25db3e5,7bc1f9e1,f75bc040,536ddce9,d3a66b6f) +,S(f0eeaa1f,c52b3068,48b56308,22fcf0f3,fee5008,54e276ce,e9fe9904,54f59cdd,90ff89b,944d70bd,eb5e5e01,6afbeb30,d51cf7fa,81182e63,ab3bb2c9,f2124f02) +,S(36fc9bf2,8bf90fd2,613670c2,27b51c00,df5b4caf,252b5df6,648ddb6b,3aeea71,887c3876,f1ac6c28,606c8161,4ddbbbe7,d975ecc6,9fd9075e,13d0e3a3,e7836683) +,S(6e31e26b,cf9436c,e14d2d04,1c29f62e,135c549d,5e65bacd,ba4df2a8,9b91b68b,2389684,9e63bdaa,b5f7d9f7,7a778b31,94c1af87,d09a9a85,85896188,acd0e7ae) +,S(c5044649,a4b1c2bf,ac6a8a1c,ead33aa0,3da9fad8,4f742eac,35792672,1d98e864,6d2602d2,83e696bb,717d1327,cc1143b,45fdc84d,b8d400af,537b201d,a7a1027b) +,S(a933e71,f13c44d5,bda8e963,b5a007bb,b9b2e84c,c45211e6,eca804ec,6a99ca28,931bf3bc,ec45e2f6,e6571207,31d42fdc,c3ce0279,542114f5,c1c0f659,f6200faa) +,S(9003f61d,840c2d62,1ba98884,e117038b,b8559d0,b132a1aa,83adf65d,f8e4a58b,50c75124,f72b3952,9feb7ece,cba26854,1388a1ac,73631532,b67f56dc,e8d30895) +,S(fc807c18,3cb370cc,8638abdf,c17281a6,914e21a9,e9f3e2c5,33fb7c37,caa0a886,3ac79d3e,75ac1d5b,a9af7263,9d564256,1ccf6fd0,6b8d2cde,e9d24a1b,e8af00ba) +,S(3d072ae4,aca4ac23,b43b608f,150bcd4b,cd780dae,7e4073c1,86293cce,dfee9cbd,6d9e443,f721c9f8,a98fc563,8d7627,f9c60414,67da3857,92fd55d2,7e65d9b6) +,S(d0cb8594,7061b4a7,d2bc5eed,522faf8b,ba6e26bc,7acb1d3d,106aabd9,a7f80dc0,fbfd0f26,e9d0dcc1,a0107b82,d1a9876b,8d7562f1,41f0892c,9b739e47,7b012e0a) +,S(e4edc0ab,6416c644,1e59f46c,c7221cc0,267aadac,242cee32,41a6d25b,635bc9fd,f41c3ae9,cea7b4c4,4834482,980807d1,c496fd4e,bb06964,b84c1fc3,4fcdc71e) +,S(6233b50b,2d3d9101,8f5a83c8,84be0f5e,ffb80641,1b0b5271,557d32ab,dd7eb4b2,8dfaad24,ffdd2ac2,5770f21e,328588b1,34a3a2b,dda40399,7911ef19,855dbcc5) +,S(6ca00162,e27265e2,27b4e544,7e981f6b,c427e65e,bde295df,9434b7dc,52a19ab5,d33f5f63,a8f227e0,a43fe297,babb3a07,223e8916,e153a5c,e0f57e65,1154cce1) +,S(c01205aa,5d2a8d5d,c0d328ae,7ce7cb16,d6c9d992,8b6105b3,cd68666e,36fefcfc,b65e5f99,c4f48095,e1bd6f6f,6af8ba7e,cf2988ab,ffa9bb45,3ad01859,e831d3e) +,S(e3965393,e6268cb,61d6fb19,58050f39,7b8a597,4a6c4abb,4e0b78d2,dae0e155,1f78ad46,2ed6e1d9,18004892,85383b2c,3f971fa5,cda0c828,a2f289bf,80731737) +,S(27bfd0f3,702a9d43,50c1a6,9fd990fd,3dc03af8,50bd84f8,1248222,6cb099ce,22e16b60,e8caaebd,19b0c0bc,e40be7c0,c49fd3f0,d9094f39,fec1b1c,bc643de8) +,S(8210fbc0,23319565,9eec1777,12997a89,2a37172c,6f75e3c6,cbf080a0,6f96a2f0,1ddd7792,101166cb,bb11d552,85e1eeb3,bfacbb25,6d1a5097,16dea91e,46afee8d) +,S(15cc66b6,5fcbbd80,df15298a,25e2ff80,ae4d5065,f8befab0,89cd21a7,4e347b5e,944b47e9,35748296,deb324c9,f5616d28,7b225b34,488fb34b,6ddacd32,7937c97) +,S(eb7b7aa2,45960169,1ea1a482,a9e6c35e,c7bb08fc,726c2c4b,ff801ae0,94c97976,4d2e9570,cc187791,fcbd20e9,3f0656a,f5596f4e,104c3f2,27c23f82,2ed1b1f6) +,S(4598fafc,ed29e844,c22436e0,996a8469,18e7c106,b40a5ea1,5fb0e7df,5e9ba12c,e73d96b6,d292ea2c,39779dfe,7f716609,978a8555,e5b09629,7dce228f,f35e6093) +,S(49835a86,3612e594,572a2591,76f90e18,e57d4dfc,1910c705,8e37eeb3,1a8600f7,3b7613a,fbd2cc1,cc23b147,e0e80d36,464c08a2,e488d7b9,8250ed37,dfcfa531) +,S(3a6d6fed,1fcc8067,32a3177b,4dbdc33,3cbfe0b7,d19305b9,965916f7,ce335351,cc3f3d8a,314d617f,148a6706,d7f10641,11eb2b56,1bd1dd0d,f2986925,5a6624ea) +,S(21208586,6860fe30,ce92d2ef,b2035b74,f672a024,ee7baa78,fb0d6c7b,3ad7a9f5,aaf145be,51b1ec,3fee8be1,1f6e9d73,96ff0ce3,41f25d7c,e1074a09,78bebbb7) +,S(f819132a,c9bb2f09,663d609c,51cb11b9,833ac082,6ceffcc8,67cda04d,266e4e06,b1fde638,ec6a305c,aaffd1a0,6404aeec,c52f48ef,7646abb3,7e227239,4c891de5) +,S(536c05d8,8786640c,43734d72,aed62d9,168385a1,213c4428,423a9437,c2ec009d,7f4be100,d827de18,68bc2b43,c83a08c5,fd84ddee,1fa9ef13,4b489325,db6df0d5) +,S(4328123e,c4c6db76,37ee3ed3,42c8a859,9de2fb1,a39a24bd,650b73ba,a1df722b,81c002ea,1277753,e6a22fa7,1b4f86f5,4ee11f10,f5d5b15,94c9d7e9,63a40857) +,S(f3e156fe,f8529951,86a9e536,f985c1,6a85fc32,d50e9a08,1550da68,112a5f17,91ffd66b,56ff0e6f,65d67e83,c362b853,a2f441ce,7418d091,5d5dd09a,b48892d2) +,S(32ba7359,84e13f42,d2e8a716,a54c40ac,6645a1af,eaf030e6,8242a8d8,8b456cc9,67ffcf1e,1c32b150,a82ab317,8ef24c93,f055765c,9e7e6200,f868b183,bcb4c6f5) +,S(cb9c2b3a,43d105e,518674cf,64d8b4aa,9c868b93,18abbddd,ccabc0ac,59829311,1fc67ef2,233f076b,ded3ac47,99c859d1,834bea5f,bd2bd5db,242607ee,842b691f) +,S(e14f2858,b7bf7070,32349695,e09bcd3b,5effa957,abc19e85,6efa31bd,2e9234f0,3e04e49d,d3f3fd39,883cbc25,80d5ff06,cf8cbf0d,4a895761,f3cd15e4,dce08bdb) +,S(156beb7b,1c27b8e3,cc78113,c97ff026,74810dec,58409e01,d7b7388,87550d82,c711730a,80216ec8,352adf2f,d5939991,3a8e92c6,c16c17b,16e27a91,90bc5371) +,S(de5ea7e6,b9b46864,4b80e495,9a2ddaa1,a24a3399,f8039355,7b798b5b,2c55d600,8901a027,e6a823d2,dc0a9d24,e182cd52,b9b1de67,22b7f7d5,3a03c615,8cd48ee8) +,S(8eddd368,8bfaed46,25b7312e,7b2bf0ec,aea07414,a1281ade,b79b9e3f,ec17c3c7,2db43af9,26171d34,d5ca48a8,9223e57b,59b885b1,5c4f7231,6d8edb6c,7955da7b) +,S(5c971b6a,665ad1de,8fa489ae,22237ed9,87872e0f,ef95eb85,fb2ad3d7,f0b1d4e3,4d71f598,37c2af6f,af32ff7,42ba01d9,aa8d4d7b,302d39a6,c4fc693a,5f8b1f66) +,S(edfb253c,28212b6a,d5b66589,a2a8f1cd,bd3586ef,34254768,85cfb70a,46b9e228,3e5b6608,b7e81f69,b8cb26b8,4f306292,594e42e0,25134c1d,7f7b2a24,b2616c00) +,S(4395f24a,e127772c,db163dd4,e22574bb,d2373cc6,b2c67384,737c56b7,dd525c13,bac6e725,4c800c2c,64896913,df739574,676581dc,1b4447a,819be64c,10103526) +,S(81100ad5,73a766b7,f8913b64,b5f5a87f,8c782353,5f62a3eb,182f0ff1,946866f5,52cac16e,325b0899,9d068f7d,51dd9d5,c6afb8ba,9870a9c9,d28b4170,e9a00c73) +,S(fd3a0551,41168146,6ae358c3,aa14216d,dee3a05e,e5ddee40,7f72347b,eb95120f,2af2f30d,45ceb12a,b89b7b88,b7e04b20,11a3c607,58ce7250,e4c7bcd3,da8ee5b7) +,S(17a55b58,a7eceefa,3ff05b6d,fa17d6c2,76d1a032,abd198fa,4e3fc3ef,e6435ff9,d7273958,a3ad67c1,fdcee72,e71f0536,418f35a4,57e06240,bc99bf71,b9574d4f) +,S(870cb7b8,e2ca5ea0,8c5c73ae,e15e8b22,793fd005,5ed7003b,c49b4089,3b789b6d,c33c8b40,7b701caf,26d7a9bc,e22644a9,4badbec,ad509cc6,a7b0ee04,1be67aa3) +,S(f951c5fc,dc46ef00,adc53c89,a50ca0a7,ffbf7c36,d80e4897,5452cc1b,4e71f8a7,6ae2f821,7849cc24,30864d7d,24df9e59,c1705b92,5792e648,75120738,c792c95f) +,S(aeb8077f,3b92c676,ae11bb06,a18ada3f,6cbd832a,1637ed61,31e4902c,96a0caf1,29f41d1d,f5d4a430,94e75fb9,8bf317ff,6c8a6d7d,b37ccfd,e0232e1e,afcc1e35) +,S(d46f4d97,5d2f2e58,6d18a7e,5d8587c3,8482b78b,595de60c,b9d2035f,313b78f9,95d781aa,3bdc1176,396154ef,31fee42,f704e199,4316e33c,1053491a,e86392f0) +,S(6afb44,4b4bd89f,2e21b54a,c49b9ec3,af810b97,73c76eaf,4f3a5f1c,7a29b201,3502901f,d7d3b4ce,134ed90d,1388ab37,64db460d,bed334e,af061822,6ebf932f) +,S(5f02e582,a38b1703,a7bf6086,9587af5d,e6634954,cfaf8394,932f7ed,ebd86976,a0487cde,92f3a796,b24b06bf,740b8fe2,ccfa5d0c,a2b68a7d,ef46a005,2d7afec2) +,S(26427482,60432ced,5a07b885,f354667f,ad70eb75,9c556e33,c6652d3a,a0599fe,119238fe,2560382f,d76ea737,9340453b,a63867cf,6e044c62,949f858e,b828ce85) +,S(6b2a3e5a,d327adda,52b19a7d,d5e837ed,4f03a5a7,e1e5b7ff,2cd66660,469f91dc,2f9f4526,6b482fa,f336560,1da9e945,354ed265,e8d7e57a,22f04bce,8a54c6d9) +,S(2588b88b,7e214fba,ab10934d,def13e8a,e5fbaf77,d7497dc4,fcc0345c,435daa79,3e5cf90b,d3ba6d4c,8d7f142c,ef1a51da,61ca644f,acba35e1,51ebc114,c5435bbf) +,S(d9484146,92852eef,fa8178b4,a01404a,e4e3d846,c20c3fcb,cff5cff9,de551a93,d5b0fd7f,e628c427,434a1219,6ad99862,13ea0abd,969864cc,dbb8258b,96a6d5a4) +,S(5cf81fdc,3a2f2087,cb64b1c,9b6f4754,5ccc1e78,67cee5eb,9fe9c4ea,3b0de2ff,e0b0ab1c,f6bb8e5d,f7ddc700,5ec73471,e7ff3125,daf113,1b78fb8c,15bc0d7d) +,S(41b4ef7e,b719fdb5,704b3f17,4132c694,f8ed2471,1677a320,3b866660,dbe879a7,a6fe65b1,cbae2235,cda8b459,eeac19a4,9f44c2aa,1c8a881a,e12093b8,3621c85f) +,S(43ed572c,41f691e2,a8dd1691,86404ec8,7a4c0a3f,406f3bdc,5c2709a9,bb117af7,b7b9e1b8,90b40334,6bacbbab,7be4d477,90a2b093,dafbac3,fd4d2073,fa481da3) +,S(4e010a19,223086a6,314bb526,2f1955e,81722b41,e85fae42,1c338e46,1b397de3,f0d3f11c,3475ed8,44876e7b,3bd0bb8c,283b44e3,70c46ec4,a6159a27,eba65fa2) +,S(b3609cbb,7fc86bcc,4dbc385e,81edcd84,45e15d2a,7d355e22,41dd442f,ee11f36b,8607e5ac,a3df34ff,804017dc,977bba88,c308911a,aa1698e2,e6190c8,dc9c5f68) +,S(445e60b2,543fbd3,7bd68cdf,6db1125e,d1bdd6b6,b27249d1,df96e43e,df965b4e,a5fa458a,8c4ab47a,bebfdc7c,f922e713,c65f8b52,287a65b0,b5dcf0b,c7715fd1) +,S(709f8227,9264c99f,86b59a7b,ef14c189,be875b49,e00cb64c,f9dbb643,10f50fc9,168027f0,cd28d2be,8a69064b,468e4de5,3d4903ff,faaaf628,83f15031,58960d10) +,S(62aa200d,cbd1240b,a252e725,a333f21c,8a2e9d5e,fbf18cdb,e1567ff9,29fb4ba3,19aafd6c,7017bdbc,4b906b46,843e41ac,1ec3282b,12dee1b7,b18e3f28,9e0a1347) +,S(2ba73958,8ed54646,fa9f2389,802e2ab9,e123987f,c881ae11,f38f10ac,b882c09e,f37daa1c,9c0a98ae,f86cc45d,34801353,d8f8a193,77518423,721f3e12,375a25a6) +,S(8672b9cc,e8fbb69a,ae5c0f54,9b59dfe1,e266e9e0,3592a397,7314e6f,79005de8,20d8476a,efb61c79,adcaac68,fbf9eae,c411e875,a66b5aa3,99a97a86,9b05af65) +,S(334cb002,84202999,79fdbac1,5ee5c17,1f32bee6,133300ed,a26571e8,bdab6ab5,8827d99f,3da7878f,46b45bfd,579c5cb8,e4e972b6,49d6438d,96e5a188,5aa574d4) +,S(32b30e07,d260ec07,354cad6a,2f64f81c,e9f25f4e,47bf1afe,602f229a,35ac6d4d,71ffcf0d,64ee9078,6f290418,1126c44e,5c5e3688,f3063941,85660874,3c3c0427) +,S(e5099658,7a4b4e63,43e401ff,299e9bfb,3b5ce402,5c38fa05,761e600,a39a8451,7b0382a8,65429a86,94eacccf,5c6b3380,683a3916,70fc7241,f132c465,b3bb2ece) +,S(b3872c4c,2bf539bc,e0aea035,3b3d786d,ca684121,29db66ab,d316e930,e5d6477d,7ce04af,e4c8c86f,3b37ed1f,a9dd4161,59391c71,22d0f4f9,2424d090,901e285) +,S(d2b56fdf,9156e3ab,2e414d96,49f4c418,6095e74,a2df8908,f3b406de,9935d07b,443c2c1b,67668c56,a84b4925,946a8e5f,b06a33af,371552aa,adc3b500,efe3b23f) +,S(f69867e,1074c765,923f32e1,ec9f41b3,4e8288fd,62b0a081,15db15a9,f37fbacb,fd6c6e25,2a11a516,9ce04c6e,d719c22b,68709be7,6fdd0e58,cd0505c6,413fca16) +,S(bc1830b4,a9ab11c1,ad8778c8,688fccec,cae23898,555b6579,62670d8a,b9e64988,b6244089,f3c46133,1979a0fa,f3d0c8f2,8e95cdcb,12db9ea5,b6d95ac4,c22e3c81) +,S(fabaae21,dc729fda,98c4bbe8,3cd5fb92,126cfa1e,a21f43b7,445e4b47,f38dbafc,1b569775,64465832,c73513b3,ed6aed9f,177ce1ba,b2c09fbc,c4c33600,582d8cdc) +,S(93386101,4d5d4c3d,f912497e,a248d8e3,bcd3fc03,216dd57b,5473d96d,791f8bd4,3d8fc96a,c141163c,4ff3add5,44a6ad71,9e57f22b,8e806d95,1d630fa3,6c936725) +,S(c5312d5f,85c42820,59546b8e,ec6b186e,da0a4324,d30147f2,94a83fe,a6fd07f8,f8ae6e2a,79ba0756,523be12c,8d544734,332898e8,b35b651b,edaf806c,45d2992f) +,S(a08f2496,52c52f40,6db75c4d,da022f41,b73b1128,11aa7388,558480b5,f203b057,a396c7de,9ab5e1d9,5e9aa925,1ecfe3ca,191d7a25,37c4cccc,845dc745,2f3eb2e5) +,S(93d5330f,e8df6fa6,a74b34f,a251a6,a036e0b5,89b8a05b,c525e4bd,40f634df,ca15faea,10f424e5,5d6774f7,7c87da28,c4df567,7d153a08,f5ac560b,71838756) +,S(4622bcc,dfcab72b,e850a994,1f652110,5c35b813,f05a4f6,17055f92,aab51fa2,d960702d,31eeb256,d25cd245,695b53c8,e883d2a4,60965a8c,d29b41e9,d7ca2d4f) +,S(a326036c,7dd885d9,94ba5872,8138c30d,fb6c83e,d17c8d88,7aee086,e0ef9fe5,b465ce69,3719a155,31caafcd,e7689a17,456a6ce1,c75e5a53,4893cd67,32cb9bf7) +,S(2354417e,19637e79,71b0c887,bfa5c553,f3d5e7a9,84a6c946,b1d20b5a,7eef77a5,815a9721,b6ead3cb,b254fbf9,9f34f409,ea740053,3cf4ed4d,2169f48b,29f4bd4b) +,S(9d346d6d,fc53174f,5cda746b,23810d7,3a407819,ddd5df9f,2b07cc8b,b7ce6fca,9b6cc06b,64293e5c,a55a8ff9,f1e90551,4a199b03,df08e9b9,8512b357,9776c806) +,S(73c82b8e,c643a7b7,f95f000a,debe210f,bba638b4,5508564,bb5a3330,fd48dd01,fff15699,a0885c61,fe35f61b,84cb2bda,7d2acf5c,df0d6f07,5fff1369,805b614) +,S(902469d5,a0b2d5d1,cf931672,88506b95,f2d29bf,6ca291af,c9b39cbf,fc798ac8,356d011,d71c769d,342378bf,fcafe4ff,cd78addb,abe8b0d4,fa63de89,1fc3ade4) +,S(e670a0fb,3a0c86f0,53523afb,819b8944,dc4013e9,fd500371,b1efe23e,1f110637,869136b,cd13dcb2,157db5a3,d07e59ef,272557e0,9dcb250a,9bf659df,260b31b8) +,S(f3fef06d,526581e6,b0f68e27,cfb9cc9,b57f11e5,849545fc,b9ad3d5b,8a05c395,32b2e997,144420ec,c4c45176,efa5fbbd,570752d1,4b092f4,ff375544,19b8f553) +,S(72a37663,3958d844,560fc28a,8cc19d88,f942c09c,471d2cac,70ca5d39,396a05bd,de9b1b0e,6e121070,f684b3b8,402e8d8d,729ce846,d2f7ba8,503f4548,735ee1ad) +,S(38b78ad9,c43b7def,4119c3a8,190cde68,4172894f,a84cdae2,2b637bd8,805300b0,a181567,6c4f5f51,87204f17,5bff32e9,de7cc69,dc851c84,23de74a8,b3d01e6f) +,S(db968ac8,1d2e7c53,6c66fac9,e194fb23,540e2e89,8cbd3af,68e158ff,2b34752e,4d5c57ab,79d9972b,ac6b4af0,a6347271,4179e8e,fd14c769,a24e5a73,aab48a0a) +,S(2ace1679,2d3a4d83,71114f28,c1ed35b2,505dd4f9,97c72435,a145d367,a8aad318,5314312a,246874e4,cec63b87,f685f6d1,405b0ef,a1ae3539,cc88e73f,3626f625) +,S(32d80e69,c390ded,db8a4600,862727c4,bb1fda18,2563277e,852f93af,3dbae108,3c7d96f,ea89d06a,6d3cb3f8,181f7cdb,bc1c3e12,3d9f1d08,cbd557a9,60dc7c07) +,S(3ef49e8a,e7fe6b40,628e61a2,945db3cb,f1bf050d,e525d521,d8e8a408,76ee3908,4381c75c,62f45fb2,4d431b54,d63115af,3ff72d27,58c3c92b,d3d1de08,1a123f2) +,S(853808d5,cdb82cd0,39b517d4,1c88d7b0,e280ee6,59e5c640,5aa27542,3c9722da,c1677c44,9b2a9626,698a652f,81722242,3ed18d03,92d4200f,b4dc229f,5f7e8f5e) +,S(572fd483,490c05fe,857520bd,8861fccb,306ee4f3,29adef49,58c1db78,1fc8584f,82acc906,10392302,cf0107c0,6b3b6194,d38e9155,b31ebca0,be300036,3413f4a5) +,S(b1cbabb2,9aa8ca31,75aa9a2d,d4d956e4,fa771344,d4592481,38c93583,376e1386,888cc0f1,7f9afdf0,6ba1de03,41409c1,265cb2f6,c015fc,bc58d2dd,66292ec9) +,S(f856cb92,42393134,7580a65a,149a6e81,2c5c960d,670701a1,6ddbbb98,2f6bab20,c33511ba,192c00e9,991f580f,65c111df,77d9d6c2,d5d63869,c5595011,48536674) +,S(e1601cd4,773e129e,2c042887,b56bbb3b,9eed92fb,6c128e23,fffc3a7,ee73920e,180748c8,a38c7796,ee247c71,49ba1fcc,a78648c,a0508ec9,6f4a016f,301054ca) +,S(98ee20d4,5ffb6177,5ca206a5,b0cbf1d8,e8b37cab,97489534,a98928e3,367c7e72,2df4ace1,ea42db51,68ab5e6e,88fc405d,854b70e0,4521bc30,6978e465,6273c610) +,S(4796ca57,acde905a,31dcfe95,bedd1e13,5417bc41,f5acc246,ec0ad4ee,ddfe179f,7413f522,395a3802,b37637e5,9564c239,5bc565a3,463f815f,8ff962a1,f0a367a8) +,S(b367c864,38adb0b8,d5b627fd,56c7df9f,cfd55536,9abbdd40,6c68bdd,1a341200,c0364744,b99e816,7982f365,72268702,b4986cf5,c9c5749d,fd22499e,2e8fba51) +,S(db36884b,723ddecf,7e2244c0,20de844,e740760a,4f27d386,a747f4a7,88914d29,8ae487cc,2a743a3c,2a1e0750,7def0f2b,fef90e24,fda0e3b4,e5f3333,7d79e023) +,S(65971818,f71c212b,a8e45821,31eef4f9,76b4732e,6c6c3123,ccf5c6a0,99a316c4,415f6791,353350d3,3b087f39,13761119,526a2831,c70375db,4cd07754,e13604db) +,S(f2f4eb3a,13a8f4b2,42182a63,97eb6cd9,9053903f,961a1338,fcbccac7,60ebd65a,a575d67b,667e94d7,20adc8b7,4eab8ebc,18811b3f,3a3bcb6e,7950cafe,8ef9ca8) +,S(a24e7a0d,a058f0c6,3328fa51,fd3c927f,884b3f77,cc068a47,e8c6b4d3,1d113a49,be8db830,79aca569,9eb2fe3f,829719d5,bcee615,645e4c81,a9a7212f,450ef78b) +,S(e59a3ccb,77e11797,7db6cc32,5ebd5981,42212da7,48f0a4b8,981db72,41efad5a,a8e07545,fdda2668,cc0a10a2,2389a2d8,d6903416,a4a05299,9d4c2d4e,4a800d9) +,S(3191b263,a3c70be5,bec721f9,3dabe9c9,fc6c1a75,aaa94e9f,daf6060,fe4b8f32,339192cc,1c7a9bc7,2a9a87c4,ea3cbab0,c7af7b27,53e74491,717b1f99,5df38a96) +,S(63dd5fc6,4f9ddb0,8fd47e27,5e839b20,12f408e5,3c139463,8b97874f,9187023a,1af048b4,2e8b7e6,d456cccf,d12ef7ef,67e0910,4162239b,84f35cbc,8504bd9a) +,S(a92e457,cd8312ec,cb87229b,7f751c4b,2e1d8640,c2b8e5c1,2d3dbf4b,671bcf13,d7aedb56,5447eb5d,18449241,3a07d672,be46ab4f,3d5b4b3f,551f292e,5ffba768) +,S(1ee6b970,b9e09d22,2b20f02,14f00bb4,4789f55e,585f35ba,6c0dd6f8,39b10495,7c910fec,eff9eef5,d1a3c8a0,46252885,9dcf73bb,d4a0b2be,3f8d10e0,dc9e9462) +,S(b19c23b9,c2ac1957,5328d7c,43d04870,1abe9e97,30285ceb,e4fd1659,8f06a76a,79a811be,c07c8b70,6f380f8c,fe369e45,c605607c,d08c8a49,2745b283,37a38398) +,S(3c20db9f,9ed35fc2,7c0888f5,e266a455,4f3fbf98,b8b2a016,b1e9aef3,14f49a5,bb3ac294,3f29e63a,f610815a,4a1e5a12,9327c1b5,ccf489ea,7d8950e3,5bfbc4d5) +,S(fd1ccdba,b4746e9e,44eb5904,d338244,efa29ffc,8ce8014,f6b922c5,2eea4389,e1065546,52146f90,fa52439f,c43ce4eb,73961a52,10f6c040,97a82032,9a8df06e) +,S(e30fd18e,abdeb8a6,ef252dc7,3c2b0d75,83641a29,8db37ab5,1e2da099,9b64020c,49663672,1824f481,962bcab8,6716eb41,8e195d29,6afe9704,cfbc24c1,28dce88b) +,S(4bc1f789,26ddf930,e1aea784,83a9dc09,5cd72300,5540548,e6e217e7,515bda37,966b32b6,95dc1b00,8dcbfa2e,734bd9ab,36d8a26c,2a52c471,63a4cfcd,d200ca69) +,S(23d3e27b,9c864b8b,40f0f7d2,6ece9bc4,9004f98e,d46b539a,affffea1,54f036d4,be4617eb,f680a27c,cc4143d6,ac150d51,b3dfefbb,2892a6c7,1b36c794,8ac0b05d) +,S(28adcbd0,14cd3b70,f46e0a89,477b5cc0,4a513091,cb6c1aab,56de4894,3e6009c0,7c49a838,75204cca,38f250b4,608cfe4c,25040dc7,3ded4fda,f4a92cce,fce31601) +,S(776084b8,a86f0823,a5044ab8,70d84f60,ea52ec7b,a545ea0c,c86f219f,1ca29d08,60bbbecb,1048d250,b410bc38,49e567db,def17272,58570b2c,d0834532,581c60db) +,S(45df2e0f,fd32ef48,95d9667b,c6044951,e3db94b9,ed6af5fb,d4fe1e7d,228f2350,a732464b,1a8cfe06,69e4076e,d4164b98,4de155cb,68bb3994,73fd7918,63eaf095) +,S(6904976b,46a5fd1f,a74bff80,c493a2fc,8ae9bbe8,783cfebe,7f69f0e1,be7dd7ea,19d071b8,df9d1436,6241a22,1a00b340,30f1df45,5e66fcfd,5ad621ae,ca2c3e64) +,S(849d8728,f977d075,a8de805c,8e80980f,e01def35,1ee80f0b,ef528e85,29aef659,d84955c4,6c886283,b9d7adad,bc069d0d,8042dd9a,ec7246ff,edf31594,ae5bf428) +,S(e3d64b4c,234506e6,e7facec,8d7534ac,54588dc7,ea685281,e27c6746,472d58eb,4a32ad3c,cf822a84,74447baf,68aea598,11a9c839,4c9970ef,bc61f363,ae5a36eb) +,S(f41c7928,57d15a31,19b6f132,3b67639a,889877aa,e9213ece,c787d53,5463bbaa,73cfcd0e,c84c55,4d007594,152d9ddc,630c458e,7ea456d0,7cc60503,794d9328) +,S(e1d21747,47ab84c,e47a4a02,caed939f,e0cba1c,41e7b21d,67f52fd7,79186079,17b0b628,aa4bc0a3,ed9728a3,e24a8101,fb26da66,9ac92f63,af81aafe,7db2b668) +,S(a8a0018a,f8f86795,3189da2d,d52b4db0,5d7ddb4b,8d290c80,95a8e7dc,d86ef1d8,8bb9606c,84b88a1e,df980c7e,9360823e,25b927d7,9cab4c17,fc8aba7d,6826518b) +,S(7383c671,6ee05e44,daba57c0,50ebda60,e4e0c0e1,3df338f4,cd8d627f,736fffed,3bdcb946,5f164a74,638cb973,fc77daaf,38eafd48,9521cba0,4ad896c,8e89f0e0) +,S(61fa7e1c,8bc8ac97,96be6431,20858063,1ca36af4,520cc1e,858f90b,ad372dfd,3f0d6768,36c3e694,32287909,c8841de0,a5f646b0,94b0c207,8d634486,c3eba33d) +,S(86029e2b,ca0ac601,99092def,cf4882a8,b4f14349,43bf116d,3cb310a3,b2c4a740,b8be906e,cd9056f0,f3261cff,d12216c8,ef5f1553,dd708480,15463b7d,241c2f7c) +,S(e172f7e5,912aa487,589d6c4c,d0d6b9ab,48c4a6b0,5fc5f90e,2f6474c0,4fad95cc,edbd23c1,2b0a0ed3,b899920c,e8b64d7d,d7bfd79,5009c290,ea0673dc,8acc401) +,S(7986ba8d,322efc24,8b7b22ab,f838de93,2d931c78,cd6a8616,d1f37dbe,32873494,693eab22,4c750592,319b7544,d29fe0c,2420a5d3,d3b7e01e,e6ebc968,12a13634) +,S(ba594138,4a727673,7600a6d8,8d36b133,400bb5d3,6a8a9d46,3e8c65c,e1e00383,746f4e28,bc1b812b,227fc953,531058bf,d9c68545,2f6219bd,86799dbf,3c2ce557) +,S(45ff41c9,92d6b117,c86eeb77,bb17789f,6bf96cd7,2cf0c6b9,802af869,20476c8f,9324f5bf,6422e3ae,2010c9e1,27167d8,4f522e86,87fc95cb,ec3d6972,2002b59f) +,S(bad79e35,487a4da0,7171c282,e8666ed4,d00bada4,d9576a7d,9a93ecc3,c16ed68f,19397a2e,efb184a4,31a02e12,91db0cd4,5b153517,9038a920,7a6d50dc,787b57d2) +,S(ddfe2107,2d8875ec,60c4d583,59755bfc,22cf890d,d3665b79,cfa403bc,9e3c8a41,c62bd917,491d0a8a,9215674c,28c28872,8dbe0d3f,87c10d90,ce22b608,473f62e7) +,S(925f6a53,c07f923f,968ccadf,bef9d95c,d7594269,a3d9fa64,b1180edb,667eb299,1080e8ff,1f918e6,6f08b26b,7f9cee48,58f00038,b8ca50b7,b2939960,b1e7809c) +,S(c28e49dd,a75f0283,38e5d2c7,d1f03af0,12768bd0,6b0e0d0d,87878ba8,2720dd80,670f8989,c941a49b,cc512c5b,4987e167,ec5ae6b4,d7f68a98,331845ab,5d0db12b) +,S(7a9053e,95035be8,8188c196,d5e8e05a,b21dae48,d59406f3,7b9f86ca,2c837cbb,40ee088e,8e7694b7,994774e7,9d097d76,6de026f6,f7fbe352,e7f2bd0f,443a7e1c) +,S(33af78ea,bfbb00c5,4d88ef81,e9661b16,e0b32c85,a1b61b95,6c6a79fd,e036aa2,713e7aaf,537a796,c4d79644,c855d0b,15331988,5ef4629,d8048c69,d3cfd3c0) +,S(c588d014,5a3f3d33,29695573,96d674c3,1326dfa4,797d63d,f9a0c720,49583bd0,b5c0cfd1,6c67cdad,ababaa8f,cfd2cd76,7f747024,8caf60d7,37531c66,ac53cdfa) +,S(96b3d5ed,b93742c6,7c48ef12,c649341b,97223f22,1f0edd5a,2f2ab523,8038d29e,db475caa,38a3a05d,3719a2e6,4ce7b4ed,bf25fe57,4b28d6aa,9961ec0c,b0e44c4e) +,S(412f4b6e,3d894ee6,fb0cb00b,14662a9c,1eea3a42,5a286782,a62da77f,5644f0c7,a84ef636,ab9bc805,bffde813,93874429,a8503e89,8c03f1d6,f139af86,f6a676fe) +,S(25f0a785,c7b43028,52f1421d,a32c418d,32fdfdc4,89c39049,3794e1fa,e4563252,efeb090d,457190b5,89c953a3,aebef406,da716af5,1dc6e334,a0226883,6004e4bc) +,S(50fd4ab7,f367faf4,acb4403a,49ea3e7f,f02fed58,4327acfd,e0bd58a4,ed741c6f,78abc1a7,3c9dcd48,6520cb52,adb1c3a,2d08abcf,a079607e,a56307c6,3d46dd5f) +,S(157583d4,cfaf7f79,33b8fa66,430f107e,c357621f,4b94f313,bbcfbed1,46a477a,9aa6b235,ce8cd1fe,60cd4355,c46d4859,fe35ed8d,659d2aaf,fc09cdea,297e8db5) +,S(3c44bb62,5d262603,e44affc1,65b35976,f2edcedf,8be6b494,f4b3bc4a,5b3300be,88b1c561,67973ab8,5ecd4594,90598152,1ef0e8c7,1ff707b9,79ec2bf,3cbc2535) +,S(31d4264d,e1606b97,f2f71d19,33f23cc4,8fc5d9c6,e087dd93,5ee25b8f,ba298958,460609c0,a3aa1d26,2865180c,98555b98,c8e41db6,2e62b2c4,4ae01190,718251cb) +,S(1f551f0a,8ff14724,60ab206d,3dc1834b,352d1d1d,80a8fb78,a87247ae,5d03ad2f,24253c06,a4c8b148,db944f81,802bee34,fcb97ab6,50957b32,eccea33e,c116a6e3) +,S(de2c4e1d,27f08407,31334311,9ff5a8c4,206a1f73,2aaec3a8,7aab6bb5,c1cf333e,dc813ba1,40fecd3a,31ff4a8e,41fa498d,9226ca2a,cb2d5a71,c5a5cfe2,8195170d) +,S(6fdc5db2,adf54ac8,132c4a22,c382c2f0,c1f54bd1,8aed5620,a54bc4c1,18a95612,db3fa4e5,f318e94d,c0c11053,61d21643,cf60b0ca,a6dc4d26,944e8915,970e221e) +,S(c7eb76c6,ea0e1c51,a3aea6f4,dd7eba10,bb76650d,85df0fc,7fd77b73,53680603,5ae1c1d7,b788092a,3c41c3d,7bc32ef2,a4f4a39,a82b53e0,e6f47712,df5bf655) +,S(c81505a2,b7e78b5b,64ce048e,6312bfba,1a52c7b7,8219d857,b4813a98,c8aa89ed,46db2842,6d6ce211,5e1e49be,459f033d,c222be7f,96b247fa,87d5dfc0,df096806) +,S(cad75255,15f9c3d5,8705ff0d,83ac3508,f7dec312,bdc71c9,a17eb9e,78503bf8,32b36a02,76cfdb97,ecd2ddc7,638e4d61,6231be5,25b6b4c5,2d19c12c,6e6bd719) +,S(94d22144,e22b7e30,56eca8a4,7d6b15d8,f17f3c65,82533fab,c70e900d,be4cdd25,12c0760d,5fef2f85,d89dfbbd,bd0124cb,828bf72d,79b4ae5f,6121a84d,47d93bf9) +,S(325c5c23,ef00601f,ddf52040,7721bde2,13cba19f,c0f2e225,3b112b8b,916731a3,59d3cb98,c09c1643,993f3dd3,64c7d29,5cb38cb2,45d8f70e,9628e5ee,d62498e0) +,S(9c907089,544b8316,4a251516,81bdfda6,7d187438,3e7f4a7c,da96d861,91ee2318,f639dee7,e7010630,364539eb,5c225059,547117de,9fbe4911,d9718e6f,8372d20d) +,S(34f14807,ede9c06c,4cb2a1d8,97a4fb81,ec5544dc,eac1bfc0,f32f9835,302b7a82,78437a8c,ec6aa228,f5f18813,a68bde68,3c54c367,5d6be482,8d01f2a4,96d9c57) +,S(9498d30b,3f080828,e03d459a,fcb81fdd,490b47ff,c344d75,3887b600,1639788b,7a5c8305,b97abe3e,b241627d,c5187a9c,677865b3,567cfd2e,ce136852,e42522f7) +,S(eba08f6f,efd36e37,aa53ec32,d3cef88e,5d4f36ff,ebb978c8,76d452f5,7754f226,fe0e66b5,43aa54ca,7afeade9,b38cbe0b,39e17178,4d029470,608c7e38,bd2015c1) +,S(555d4bc2,bd21729,f6119b77,ae8c9bce,c8ef49bd,992cde50,4c794484,7240091b,cccebdb8,69521e33,2ca86941,593eb4a7,6c9052ff,a54f8315,d30119cc,7f437b54) +,S(33729b9c,19da3474,42f33833,d1723d45,3f3060ec,c692d823,679f087b,ffe8872,a94b6a4f,283af604,eb885405,6bfb8044,fac2f007,d7ebc800,b4abd64c,5c34fc30) +,S(2a1a889f,afe64678,647b060a,73ab92cf,78124ee0,d44c7c32,d8ae15e0,df1dc11,626f963d,3bf11f8e,686ba46b,e6dbbf0e,75aba0d0,7ef91218,98605ff3,fc8b75d8) +,S(4702854c,a303e6fc,ffc62f70,258bb2f5,639148b3,4e3927ff,f2dbcb0b,7c197d6f,7da261b2,8513257c,d1475c2d,e059372e,2da76eb3,f3b2c51,95c44447,d71e1156) +,S(7002edc5,a0cc23a0,65015cae,6e49e7b,51d90cfd,7da04e03,4857c596,cd319c5b,6f2845bd,6b7aa58,7ad2d2ae,19fd6115,78c47b56,84fc6975,db63e230,c3db73bb) +,S(273294d4,483d610d,b2169f05,71d5450f,f4cc5bc8,725d8ae6,7c1adf0b,6f48d485,99b241a2,ffec9e0,a039a003,18239aa2,a71e3cc1,1cfbb6d3,7268874b,67d942b1) +,S(1beccf82,3055b440,fad26a53,5a852a5d,710c72a,c4d28e83,b0335e8f,e98c9a69,f3ab566,ac0eee20,7c8ce0a4,d471eac,2c5db716,5e24b489,e2fde03f,7b8aecfc) +,S(dbe4eecf,4f033d53,5d949cae,c8fe672c,a1902323,77892197,fae8e192,53128160,b3f50bc7,927f0e5b,56241c72,24960fc5,896fc806,1c0a8a1f,5fd3d47c,d5aa566f) +,S(6643fc75,bed80c69,4591887a,5dc573ff,caf7f484,b0ae2631,133ecf4a,39bd1e20,4701285,f7ac7c93,bac1875f,dc4a26e3,8ec1e69c,293c3b7a,1f8b5c5f,878d58e5) +,S(99f90bde,cf1dcd5e,7158280,53f820e7,ef19d936,bca63f14,516342fe,5422a21,a04dfd30,6dfc615b,5390a86,8bebead6,5cfd7719,33f91e2a,180d2d79,b99cd4fd) +,S(54e7ce48,3184b7fe,45fb4e35,192b5678,bcf71f7e,49c033e,aad1dd32,86e33433,cac2833b,65ba9cb7,83a8b85c,b7f4e4e2,4d4f8546,3c6a2c3c,4decec88,14c0e8ef) +,S(cf864a4f,fb60993e,444f4e7b,8f4a9973,4705aa16,295627d3,1f7686b8,4bf02e08,7a98d20f,b736eb4d,465db874,ce98bdf1,6b8a1951,7744aa51,af276c7c,db6f1bde) +,S(6ff160d6,516fff91,5ae2cd45,7a98afe2,a2569345,60a7f26,c9e07212,6d59d1ae,5d1f1355,bf1410ac,e4f8b415,350f9c75,7db5d5ed,1f34de,aff5c197,b4eedc4a) +,S(9adba62,aefd2690,1d77f2a2,c6287da9,a56fe35b,3702da46,f231fe4c,9f5dfcc9,ba58ec45,cb4a359b,7126af,fd2c4bdd,2e708d43,41d96e7e,4825f153,abb04161) +,S(204ea41e,bbdcdc48,cd4ea945,72c10dfe,b5d90060,e9dcf5d6,52c0e2aa,14a2402d,7b2889ac,a1952f3c,b2c5db8a,9924a6fa,fb0b9e32,3ec09809,789f780b,ac36ae38) +,S(f7d6c669,364d3114,225a6826,c20d26ba,a4b4f190,e842696a,82aace97,5fc8ba22,15abb177,b42538c5,67d160,cb3c761b,1ff47cf4,4b0cbd16,36f67a5c,879d3470) +,S(7bc4d30a,87dd28c7,8b066e00,c02bd221,e50a7e64,45b57f0d,cb466f27,7d352587,f4ed4854,2e7e0164,da66e0c9,fcb04a1e,6efbc9c1,206b552e,c68cab96,d0c294d4) +,S(55442584,b046bee6,c245dfb9,59f20629,c200eb21,b42509d7,8564943b,1e316ef1,2e2aa971,c8111ed9,6666353a,103f2e4e,a29c4162,d19da280,905031a9,48580d82) +,S(8e7df8c0,de88903e,71224c97,3a8ca65a,923f872,841f2dcc,bcd69e64,b1dce1eb,e4153083,9ae86d51,e7147873,f1fba8db,c31205e2,34c94662,52ae43c1,25d2a0cc) +,S(672321dc,69d8aa18,25569d06,65fae079,b84a9bc9,35bda491,5d546f51,c651de8f,8ad6430b,8708897d,be809ab1,803a6eee,f977b1f1,6b34c188,d333d6f6,e7ef005f) +,S(f4e2bbc1,43e99b00,52032718,285d7698,1b8beb9a,f693dbfc,2d20f472,89ac3abc,e54990f5,dc330eab,2e722b7f,70cd426f,6d80e93e,205eba89,7eabf0b1,5d651a2a) +,S(5aa3aa5f,c6d2258c,907c7275,805c160a,72694f46,6b5fdad8,9134f1,d39ffff,22d72170,617eafa5,b843e82b,5f670cc2,3146aa98,cb07644a,7f4c0600,48ea9531) +,S(34752ff9,d2bf499a,c6b3acbd,1b78633c,9e9a31ea,45c34383,be3eb008,7be2e7ef,b53ea374,2cf3d886,51f7d076,3f67c8bb,39d73ca9,8306bedd,91a6db47,2c1104f8) +,S(d6502624,2ea44f7,d9b4c9b,5069e1c5,88977062,db2bad6b,51735366,27047327,52f5c99a,f2f2a8be,c034db3f,b573757e,d8014321,86db2c28,8c7151fc,4ab16f2d) +,S(52b3aec6,553d025f,d164a0e0,b1f39abd,915d4a9,ed5db2ac,b4593c30,11f4cc9,51547402,1c17b2bb,9d401683,931b25d7,77af18bc,e0e7bba2,432a7717,f4e2f8c9) +,S(8cbb677e,f7979224,12728418,68b79c12,eaa0ec6e,ba4f9b17,4d99547e,827ef9ca,a32809b8,b07e1312,b6a40ec6,411b60be,92974f98,bfedce19,ae590f98,40183f2) +,S(d8f55de0,e2eef17d,e94b1564,d74734b9,3f89f2d6,c317a248,7f1724e3,d531d47b,e9fd46f5,da576370,e0416f71,f271e64c,fa7dc64c,5e086930,523e92c,9ab7d770) +,S(fa6fc9bb,faa2b31f,f9d57301,4777169f,a4ddb8ed,ed4bab79,d0f4cf62,356b6fdb,b6ff57cd,dfdd790c,7aefd1e4,d4b111d8,43a2adcf,9f781b33,1b4420e0,f57d494) +,S(239f028c,e748edd9,69f752d9,abad0498,f9359017,653e6ae6,bb93f09d,61b58e9a,17dffeb7,8831f6ba,7ba463b7,bb7b142d,d55c8aa2,91bdaf7c,644e8ec,14f8b516) +,S(2ef6cbfb,728d976f,99c71db0,5389bba4,ecad3c14,8f2597bd,99af8f74,965e4f3b,19a27ba7,a382078c,3f1ebe8c,1d93a37b,deeef542,cf174273,b411b60f,79b0fd00) +,S(972d732b,9af8315e,88f042f1,3377871e,1a429247,d8537436,98b975d9,33064a0e,308153ba,ba4c3b87,40a380fe,e4bcbba2,a5c2ae3f,25fde1d4,f40af4db,aa4fd28b) +,S(3d378b34,ba4998f1,833aa295,185414be,e788bced,af422ed3,3c4f2747,6e062a4c,46a4559c,9217f919,80887b50,29f75c01,3c3d5238,d3758170,93eda1a8,f2c4c8a3) +,S(fbb2003b,1fc1b3aa,fd32b289,abe3b362,b13d70f2,7d6451e3,76bf882d,395c3087,97c866a5,c462362a,4ceb96bb,9c17db03,f28e5b1d,4e418a81,653a315c,4dfdabd) +,S(28fa94e,8eeab1fa,bd27a9,258e26c4,295efdb7,afb5a47e,6e14de8f,877a0471,f7619d0a,f2eee8f3,c0c7b5e2,8ce9d0f,62221919,4d1762a5,5145a909,9d23276) +,S(4708a285,7eb9c115,71627ede,6fa8fe29,4be27233,8798f25,c12cca0e,f9308ae9,f35f9964,2e773990,b2e0ab60,1a92cf56,85403466,87a8c35,50e36b91,ca4fa449) +,S(93408097,6ff4b874,d88903dc,b3ceed6e,a82427cb,36b62c6a,6364f2f8,9848a62f,e25a6962,d4e26764,9ab2d4fe,a0babf7,daf64d48,98bc60ae,ff3cfb63,e95f3c6f) +,S(f4a42ba0,818201ca,e3195da9,3a566623,9e0d24dd,256cbcac,3959dbc,720ddf9a,8fd26fcc,be3eff0,75d194af,e7391285,10bd4c8e,7230f96a,60fd27e0,a000f86) +,S(c5ada616,e65bcd40,cf39ef6,197e0a97,791cacef,b41b0991,9c51b166,e3a6240c,e4c65d68,fe41c62d,c85b0b32,39106ae9,cc26787a,60d351a0,4a7008a7,f96eb8c3) +,S(7c193ec3,d3f1d91b,cbd7c62e,5061a5a5,e8b1fa48,561102ba,ca2ae100,80c640e7,cc7cf895,511408f3,e400ff31,8a53685,3b8e068,1d4b333a,26b59cad,97873ccd) +,S(77542543,8e7cf128,32165629,3e6a1c19,22b76355,1ec716f1,d96002b0,ad1bd3c3,3747169d,212c37be,1906eec2,8860af9,edf7d932,c187c4,debbf800,8bd2137f) +,S(92dd5399,fa75e786,fa5c0f7f,90abd1a8,bb48ff43,e54dac5a,3b9990f6,27d90992,5cb1be8e,f93783e0,c2e5c824,ac6c5348,ee493231,9932e9a4,6e54921,3f11b7ba) +,S(c1770828,468eeb90,10b55053,2a532fe0,4f66e7a7,b7a1cb37,6eb6ddef,d693157d,da5643d,a0147d47,fd29e262,f61ae4a2,70e5e9a,77a76bc2,d2e7d24a,819a2e11) +,S(1372e116,e90ae522,4649a534,111392fd,a8baabe5,be8a8ad5,33cfddcc,af6378c8,5efbd4a2,695775bb,dc38c2aa,f8da6f45,1d0a1cf3,2bc584d6,e9b2b6e5,c8346af9) +,S(2bbdf21e,9fa1a2b2,bcd52009,7f30929d,5e2b7fa,e1038c00,8f32d86a,65dda936,51b78998,6008bddc,616c0dcd,2a883361,1806ebcc,5843b64c,b0ba02c9,339d45ec) +,S(36694ca4,d0495ed7,78230d49,e6f21217,9b63cc7c,26ee3f7f,6a7438bd,753005e1,2e49e3f3,bbdcb133,3ff1e17d,b18d5267,a87f48b6,95b5f907,5f5aa0d1,70bc0af8) +,S(243d84b1,dc9ce143,a6913bf8,d13c4aaf,6fbc1373,6bb8a7e8,5e648958,32013b8,39317ad,b6bec71d,ffe3c2dc,6dec5e10,21a3dd83,2dffeb91,108abd5b,6e7f28bf) +,S(1d888387,5255f3f6,838eab82,1a12a8fe,ba6dfde,f190585d,e039542b,2d91ec92,a9d38be2,e919f815,5d633538,d2f0aef3,9ccabdad,dbd912bc,46c2037f,3324b489) +,S(39a21f75,4c0d3376,f7560e2a,a743751d,5512d628,7a480955,6456f9ac,b1be3765,3cf324a5,2a7fd79e,3bc188c4,d55bb449,ef4950b1,3a4531bd,e0b2ea9d,4035e005) +,S(a10ff60c,d8e25df2,a1d394a9,52c67f6d,18ab0a1f,a56569e9,48d9278e,b42e21c8,b45f2d63,3ce82ef8,1dc0c0bd,4f891473,89fd2b35,f02cb237,bfd4f502,df9e991) +,S(bc269792,d5042f7,1051f7a6,46b971f9,bb801acd,dc24a2b2,5bbc459e,b7bcbcb1,b70445fc,1c032061,61b01530,c9205d7e,c7fab6de,1d83f1f4,78b35bd7,71235665) +,S(3d7279fe,fd5a3682,a82a7f95,d1db4442,5f0ef448,f6bccda9,9a61c240,9037cb95,df5226ca,e6365b7e,22b42cca,2ba2494d,9a2ea193,cd92162,2de6602f,70159740) +,S(e0c56d30,ef92af00,b936c2bd,951b3d51,bc439ad0,e4216e2f,d552c2d5,e8dbe588,c2bd177d,2a75c44,40dbd186,27669a0f,f35189c7,a4873e0f,6484b3b,68555fee) +,S(9bf960e5,2b7bbf52,fd839830,634baf1c,f0d6e332,4272bc15,d9999ae2,7873315b,b28719d,20e01dcc,b0016cb1,6a453739,551862f7,d9cc81c9,6662387,1d8d0405) +,S(20df196b,e60ba71a,e617a6b1,44757e0e,87fffb45,d447d9dc,d5480a0,34351198,9c722d43,c0d071b,a07d4953,9ad0abaa,f12ba358,42fee0ae,9960ce1f,26eb07d8) +,S(843c136,208b40b,9459693d,8154980,455a5f71,23b5f633,a26661d,ca9bac17,d5b5bd8d,9095fc40,d2d1820d,31dba542,d0c74f23,86770ede,c9b4df46,f2f12078) +,S(9109b4df,702c1ea0,dea4ee0c,ab46d6ef,708a3fcb,72f9dc03,e05bc722,408d11a0,75baa2c1,8be5801c,b5315195,4c2c3024,7348e9c7,913bb242,cf4ecc8b,96dc507a) +,S(f10cd1f5,c960a9bb,12adff03,c203c59d,8e51552e,3727edb2,329eef3c,5991113c,a84ac8e1,6f65daa6,16574689,8fee662c,9d2e03c6,4796151b,8f3f0bf1,5e8c465a) +,S(9f07713c,ffd3602f,ad077b69,a8a5f539,ae0d6d0,df58ba07,1eafe6ad,10e747a8,adfcc873,42b59083,cdc3d735,782f8ec1,cbb4ea3a,57970afe,58cd5e5c,8fee867b) +,S(6d1d9d0e,32905734,13b2b870,fff8978c,5ce9ec6c,b120d9f3,64063342,cd95801a,650be4a8,95d3b602,4d745f7c,23bbdce3,25a3f597,922e50ef,ba154f8c,6831018f) +,S(497185a5,6b3acc94,7a27791c,7e1fb149,5c649f99,dc767fa7,12820cc6,6cdcbd82,7d511b7c,11dae1b1,7e4078b2,fe7565a0,f33ce5bf,74181c3d,f5b6a951,fe6568c) +,S(fff738f9,848eeb9c,4ddb8bc7,52cd87c1,9a35f7be,14a470a2,c3154ff3,100a743f,106b8a55,cd913c97,76837cdc,f45c58a0,211b979a,17085df5,7bdff373,2f2c38ec) +,S(320391a4,8d3546cb,4466876a,37d60015,41899ef4,5dfc8e38,ccb9021b,981b4830,46f63030,b4559411,e742f303,25707b4b,23fa2d7d,e633800f,9c71205,6651b102) +,S(be44ce40,a925e88d,26937f7f,b7631f18,55879106,122813f9,adf16e00,5d85fe9e,1755ade7,d22e6dc6,7e6806d4,bf44b6e2,ca6948ca,9a418893,24db0266,2b6e1dc4) +,S(8d3f06b1,58ddd609,f83b0531,466fc2a3,da6aa80b,433a92dd,eeb20435,cf33ddae,2d554a99,efde513b,b8b6e5f4,dbd2e942,f1d0a641,98c3df2c,4c74705d,4b37af63) +,S(f814a79c,f258f553,255c1cb3,a054fcc0,d0c71d74,742b6627,210ea846,91596729,119fc95,be48b4b2,23c80c42,fd1f3d45,271ce8a,edeb82dc,31813f75,a32d867d) +,S(95e8fd46,1c37f1db,5da62bfb,ee2ad305,d77e57fb,ef917ec8,109e6425,e942fb60,ddc28b1e,dfdbcda1,aa5ace31,60b458b9,d3d5b1fe,306b4d09,a030302a,8e2db93) +,S(c06543fc,47e18816,bc720604,cfc20826,6f4e5cc0,f436e149,e2dab0e8,a7981e77,22070465,f3a4a7c2,1134819a,c194cc9d,28185431,17ec634e,e6634831,97021441) +,S(4983d95b,3716aefa,4a14d116,bded84e1,fd5b050,bd6001ca,a2b97086,b4d5c68e,1373426d,a2efcd14,333d47bc,ebd3befc,f5e609a6,6fac1b02,80cdae2c,7f0a279) +,S(a2bd5cc6,92e84b97,3ba2cd09,25e0850f,ad8054ed,e6b73ef6,1fdcc958,3eafe6ab,cca6e78a,f9141b1e,6159011b,99f8024d,33d8d797,9795aa4e,4f0b2767,e6a5ce2b) +,S(61c99231,a18f4e73,95076281,b367d084,b8f85226,3117ab60,bf698d4f,6b6d741a,82314b97,9e7f1d30,64861609,a08c019,af886db0,67d49929,9d340814,6e6cbfe5) +,S(4a5acfef,32c55299,3a7114fc,7913321a,d4072a2f,6c6bcdb7,3ed60bfd,6ab34304,7295a29,c06859b2,69bf9f29,64b26dbf,1323e89,4affa4da,9f61b056,9a0c03c9) +,S(e0467755,866f494c,2b36dcb6,c65ecac6,604e5013,4216ad48,7d4f5b68,bb7f4023,dead03c5,974dfa1b,f532f955,826189ad,ae945975,28ece029,d9e5a42c,30b336b3) +,S(686fdf05,c9265fdf,5b54ca74,b5b1e231,c4e8be60,20844596,40dc0d2b,bb215ea7,f4d43e1c,edf9b974,aef950e,bff3677b,c93723f2,c5901710,b6561e53,d57ea7da) +,S(12476985,f9b20c,ea62b7d7,b0d96d2f,e2bcd924,d1f15cb9,fce5ecbb,8bd21253,d3437cb3,9e904fc6,43a7b356,b4389c0b,3f1950f2,43dd7842,e32de16d,2b522004) +,S(656bdcec,9a87c9b2,e5b32291,9f657b,b5eb1e1e,d2fa724e,45388026,2ad17b1b,c7748d0c,47b6e4f7,f63f704b,3fdc08ff,cdfc830,d17c1d11,6aa3dce2,f92fa64d) +,S(5b7f710e,f721612,ca79b24,483ced12,7a3d403e,60ebc04c,3aebeb96,b483e4b5,1b5157a7,f0688aee,634196e8,de5a9eec,11db4b72,bd96b86b,698f7284,bfb08080) +,S(bfca66d0,552ba6f5,5795bf18,40f90d85,2545213d,81d2cdea,bc8d3d04,a1e6b4da,4910b0cc,290d4257,c04c4638,30cb3a10,223043a0,bddd8690,84b6dd1a,f1754e75) +,S(663fa68f,b79dcbbe,4798f8ef,2057bd14,1447c11b,cec70924,7f566032,88496f16,3ace2efa,1f3bbd23,d885598a,91d1f420,a42597a2,ab30f951,f2b27aa6,83c41786) +,S(27cce333,8a3db8f2,1fef2f86,ede68a25,7c1675ae,80cf004,6085f1de,495c4321,7156bd8c,8babe472,eb144a00,263d4fdf,7aefa69f,da2a9c29,4b16a82b,24d373ae) +,S(d49c06c4,52ec5c09,be27940e,13c575ef,b727be4b,1c0e8ce3,5aa5bc4d,64bd9560,2c653518,b298100a,72a66469,f9a03635,5d7ad789,546df3c2,f5175238,e78d18b0) +,S(6960807e,bd028026,d3cecd25,140d3bd6,3d7bf4fd,10afd129,cfa017f7,544ad08a,a785044f,28befae7,2b7cb546,5bda6bdf,6f9a6383,aa9abf4c,f7baeac0,920e7c7c) +,S(8382bf36,54b63a71,a3b75abe,ba57dbae,fc9263c5,5a54faa1,edeb5325,3df8faa1,e05eb9dc,c319cb53,4461da26,9627661e,dc9bef3d,945766dc,b6d0fcf1,849b011) +,S(803b9379,30ec876e,78c8cca9,fa932f22,b7e7059a,f605379a,cc45a3d1,4ab0bffb,7db2341c,5202d1c2,c6fec7d0,b7869471,cb90d1dd,17cd1152,b52af046,55e5790f) +,S(cb4db129,ab6ae9f,11165ff4,f73fab02,cb78fb0e,89647e08,f998ba11,d2c5292c,ccaef9a,1776384b,b5a80ad6,5bb366fe,745c2408,d754ee9e,f6154188,d7d1c9c2) +,S(fab28757,50e9f672,3838be8a,fc070fc7,8fd6af7b,84c9579a,a8152acd,ecd115a2,d59fe028,89cd562d,5397d3b8,3ae85303,764ee931,d9c6e495,6c311490,c0b3f065) +,S(dd879eba,f870ee3d,f6e3f03,60833e12,fbdf844c,d6a5b76c,19802485,6649bbc1,e7bb04c3,a99a5c11,dd7a324c,1d5696c8,b041a12a,c6a538f7,3094716c,9943c55a) +,S(7aa4afbe,29b06a1e,da9319d5,72572b13,1df68f74,1b5f8d8e,d00ccc04,80f8016e,15f79a9f,b77b8587,7f02e3c1,3202b972,423fd00d,937c0d2d,c9d94b17,53fe7130) +#endif +#if WINDOW_G > 12 +,S(9145f3f5,876a3265,5d7fee64,f2d6e660,c34354e9,1571d68b,a19e4cc5,8c39f890,45e0a95d,cf369fd0,5bc9ba7f,da108d6f,37650c1d,5766b6c9,98ecda28,b285d8ff) +,S(5450b752,36fb010d,1ef37afa,2077f3dc,a5a7f6c8,91a21317,13df740f,4511ac9e,a7c7ed57,62bef86d,4de1084d,3ded2d7b,13ff563a,67109ef0,8b6f0180,fe6ba175) +,S(ba6c0d72,5e48de2c,cb8256d6,7417d075,bbf2766f,d13501b8,4c32cf88,c0666a0f,cd2a9132,7137299f,50eda669,3a599032,bdecd64b,91bcc640,5ed186f3,e525e442) +,S(b94821ff,1feeebb4,6fd1006b,798fbdf5,d25a649d,aad58b05,53adb7b3,9605c921,21589ba0,79bb92a2,c7c3d950,c574afcd,f45ccfae,eec4365a,72dc58ab,f9077c05) +,S(46436446,497f7c76,b70e0d7a,5a963cc8,432f14de,93d61f81,98f8879f,da0681d,29344a4e,90c4d810,10da8aab,5ea25e5f,48c367e5,b3ec9239,8a3e608d,49c83a5f) +,S(bd8e5ac6,a2e210be,4959185b,7bcb0cf1,bd3be917,5baa0d08,2bb0b38,e4c1ae1d,6b381be4,6dcc9755,da7773a5,eec888a6,69c6f71a,7c3ec0a9,4edf08aa,2db1fa19) +,S(c27c1e1a,c428a7a5,f4c3405,58ace76d,7fb64593,b3942319,74cd18ff,99f22493,fc95d661,c12f7b3a,1cb1884c,fa9f5994,25108af3,c05e04a4,9544f919,c59cf57c) +,S(a1765561,837e4ca5,5268168e,ed90466c,44c17c01,4040fc02,9e53af22,77eb30d5,8a2dede2,b8d488bf,cd655d0b,30e6e2f7,3032c775,d0fa15ae,cfc8b66c,b6c28eb5) +,S(2bf6930d,35cacc91,87e9279f,678ba368,e9eea737,8300ef93,b03e98c1,81ddbea9,8a2d4d43,3aaa8bb0,3ffee538,38ca8e16,d0f3f930,c35d0db4,6e2fa069,e625209d) +,S(766a7725,9cc5aefd,90f005f4,d6755924,a36d085a,3a5856a,6a066a70,6877c8d7,db3fac97,4fd9e2e7,f05bfad1,5e938ef0,90b46d04,bf40bdc4,171c1e33,48049190) +,S(d25a60cd,953f21d4,5fcc333c,97329da,134196e3,9a913242,88792ff9,18461268,89bf2be8,bd04835f,dbb874e7,12352980,a07ad598,9035270f,397f24ce,790c7863) +,S(c7b28e9e,8b7125b2,6721f467,b665eafd,9bf56986,8ca180b3,60dfe429,cad95d68,ac28d58,b3a7b61a,71f947ed,8bca4768,9ec7bf34,7646a167,b37c3aa7,9e95c398) +,S(e2a5208a,c61f8c29,ada2d7a7,4cfce985,20c29160,f1f7a97,ce8b34dd,7c59bc24,de8ba14,49708a04,ccb4483b,4e90e383,a152ce27,777fce4a,880d9f5b,3dc70830) +,S(e1e8e4cd,2e8df95,d3b2b152,a540967d,6976e001,88287ca5,3e844adf,12e205b1,a5dbc6f9,cdc7547b,cb3f0091,8233723e,d34aa97,f546a491,a77d8cef,43bfc9e2) +,S(b20f0a51,4a684e55,2b228480,3f3b1c2a,3c3143b3,b895f75b,ea454bf0,9d2b6512,bc3db380,676d0d14,9c0b0c3,1941a07c,f7c95585,cd44ec31,e0edda96,e80d02c9) +,S(b71a6923,b1adbf77,94cd9d8d,407ac96f,9582cbc9,b9748949,9cfa696a,c29d3ec,75182389,9d59558f,b93113c8,d38c72d2,7b6d75ee,7679fb1c,89bfce1a,64b4f151) +,S(ca47adac,68ba38d1,8ccef76c,7565788,a82f415f,d9dda65,2004d5c6,a7d3bb3f,bd598ab,1b783382,44035385,e165fd5a,ccd8454c,3969d378,42fad050,4a8701df) +,S(5fade148,aceee9ee,9fb4eeec,edd5e4c9,4fb989c4,d99f65ee,a45f99d0,2d40e441,ba6fca3a,e82e5581,ac5104ca,c8dd2c00,15afd1cb,3943f1cb,5e61dd4c,d73831f0) +,S(767dc9d2,14fccf00,900ba01,a1cf30fa,e834c851,e633849e,8adada63,fe5f84e9,8c650911,aca30e56,2d6b97a5,2fd7cbfd,1a5bcd1,9ae197d6,9ee3215e,64404639) +,S(27f8f961,445e2a20,5daa7648,fc3c06d9,523544d7,477e686b,91d7178b,7e4f06d9,39110b27,82cd7be9,75596bce,6b79e5de,37933242,21be8172,427cdfd,82a73a60) +,S(8de0485b,343b5e4b,ada4070b,f79dde48,8a1b2889,839735bc,6a403165,3f3de668,90305767,6f43e0f7,d7d1c1a4,4c59124a,12fbba72,8302e143,1c2cfae2,ed5729d) +,S(5e43db6c,8770e8ae,8ab8d318,8e700c28,5b6af8a1,eec95fe1,b68e5cc5,952df0ff,6882628d,d85fbcfe,3a2a1091,15e59c78,9aeebb3d,37075f90,ae02a439,506c7aa6) +,S(7db2baab,4bf4300d,e7caf4e3,52df1423,6102863c,edfeb7a0,89311f42,59a4ed54,387561a2,fbbb44be,303fbbcd,685909cd,e553a84c,a3d4c0cb,d33026fe,178e8a84) +,S(96da8525,39106887,d1fdf9e8,232db3e4,cdbefdcc,abb90bbe,fc04d10d,b996c6f1,65271a31,49127341,9fb5d651,3dc33287,45948c92,b7fcc509,4023d300,9bf9edcc) +,S(84eff1cb,14eb1284,f5ba51fa,838b485e,64cd4c0f,acb97b00,81ba7848,add50613,926c9c8,a6540a8d,7b1e602b,6ce818c7,609f4511,32f284fc,7f578c52,a6febd9e) +,S(1eb96371,8e2a2a0f,f5ee6000,7bf94a00,416e6a92,25d59705,7fe19941,e2adfbbe,4870aad8,9635ddfa,dc3d4011,500639aa,d3cf0523,cff0dbb0,9c9f6a1,3005b855) +,S(2994a36a,6ea3f307,1bda8696,baf193df,c75fd4a1,f7683fd8,d454dcb8,77bdc098,e465e8ee,a7273d4c,d786bd0b,e96fd3e8,9969bf03,1b76aeb3,fc82c4c4,bf856766) +,S(25e7fb70,f3d357a2,c29b115b,5e2d97d9,d2b68fcb,b7f2fc00,237758d5,9d26c414,4959a370,a3bb895e,bf530fa0,13a86ab8,206b7330,efaca631,fed26773,f356c4f2) +,S(fc387f98,80bf6bbe,19f0481a,2d66bc5b,c3945c52,588860ea,dfd5893,347c0623,89d7b80e,83caf032,9c9d07af,734604aa,7ba33274,c1081ff,16e663eb,b49d67c4) +,S(c50af368,c25fc9fe,10220fa8,2f177720,ef5c00b4,85fa99,e2f03294,fe01e1d4,c3777b26,41983094,912b80d,9e94af7b,27d9f10f,978c931b,a4294cb6,b97579fb) +,S(a0f9d109,d524d9ba,a2e00362,941a5f20,d7015c48,554f5bea,7c97617e,10041f94,28c51c02,daa5e108,3e77ff2,c64560e1,2eae923a,3a699f1,daf3c62a,710e9ad0) +,S(41d12627,58b708,58727138,908004b3,2138bc23,cbcdfa28,5da862a3,48316de1,6277029,153bcec9,5c95f451,3d515d90,341d90a4,90eb2999,d29df4f0,7c1b9673) +,S(944c58ce,fe6cf543,d93afb77,e33adb3a,5774448c,d61d621c,fb80f856,6e99ca87,c071ec1c,9b7fc717,ca91c557,66bcb222,3294958a,b7d7b056,e7473170,284d66b5) +,S(3307ab12,e06d71ce,9c029bf1,88eebb58,9a27be59,17290635,f2babebf,be437145,889c3cb9,28cf9091,4748dd9b,f89e9809,4a6966d0,97d854c3,c6b6a949,c861d213) +,S(42baf011,1eb2224e,4ca03abd,24307b6,72b74572,2db6a8ac,dee1b7f3,45cb9ae6,bf32e128,d608dea2,4b564bec,38d22c5e,879515d2,7379cb11,25695faa,2e12ee06) +,S(856baabb,be7b4bd0,49fbe898,110d1175,166c69c0,a2bc86bf,e734c854,c402c621,24a323c9,b6d31fd3,cd424161,be229e89,1f825197,9ed4721b,943d7418,4912ac0c) +,S(38dbc18e,d998143d,874c224e,de83834d,95aeeadc,805cac1c,3216d830,d24a9cd4,273ec126,f7e85778,ea38e2ea,a90ab5c5,271c6eee,7f934a03,570891e5,167eae4a) +,S(359dc85b,ffcd2329,3166bb20,c8374af1,5e24c065,a5f48d92,c981eb81,4988dc59,de5dedf7,deef588b,90237d06,e437bdfe,c4a05703,f77b584a,e58162fa,bfbf39c6) +,S(e1068065,e2e91c88,3de2f73a,6a5f3da7,1d872a74,9d7f283b,b1ca35b7,c63666ea,810c3a52,b5df0851,87928afa,a7685035,a7e155fa,c8dd4523,c5ed1f01,73752cd9) +,S(50767f71,37e7c9a6,6e317183,cddfdfc,b564956d,cbd5f3c7,fd8506d,dbb19d83,e1c2dd5f,5e9d5fed,807d24dd,3f2e0ae2,393b6167,563db9fa,5e338664,a0d4fff8) +,S(44cecbf0,cdf88355,f1216d0d,efcea137,5e01275f,f53d8a72,5a0b5980,e6e65864,469568e,5094e9b9,ee290550,e67bc636,e8e3f022,f15c8d2e,25c3ad6,f51cd40e) +,S(1830c8ea,43cbb07e,fa2fe597,6afca2bb,87ed8a92,602e05e8,86ce3447,96aa18b3,df551328,e064aee7,67f56203,7fa31c11,3c8ce2fa,b5445d65,8bf1dd84,2f1da49d) +,S(58d54b7a,473a7ab2,51c33417,a41f4ee4,708245ea,c4f8eb79,9bf90aa4,bd9326c6,a191f338,15e2e07c,ca4c331b,fb1cb2ca,a1692093,faf5e789,1ce45a2e,c49b2a85) +,S(f0dce604,9507812e,603af104,42fc9861,70a18b6e,44e81af7,ba192b55,12c6792c,c221a221,b5e86ed6,23e48df5,5cf0f560,4cc60eb4,c54d95ce,3ada7b09,bbb966e4) +,S(42fb09e5,72c0302b,286aaa04,644b26ae,e4b958cf,ae5293d4,d7ba505,59dd2ab5,79c10573,a00e6888,fbc7ec76,983e7d17,f46e1ba8,27494099,43781bd5,19f2299f) +,S(7adf1551,ddae0c9a,8628db25,e0dad10c,935465bc,88b005de,ea2d0412,f3502ecb,657c0ba2,143cea92,c9ef5c3,69d110a1,2e031e67,9d945a9b,b3c5886f,29acfd20) +,S(dd5a48b9,56fdf6a6,d6271310,afc2f5bd,3a7bfdc9,28125345,4dffd91c,282c7a5a,7390d037,2e067f36,fab52107,29590464,2ac6b0cd,91a161e3,85df7cc1,7ca52657) +,S(631850b5,15374594,be1c783b,104d2ce0,13ac763b,1d36301d,2936c2d8,8a1466fe,2490ce1e,a9b67e44,a9241416,c5729ace,2016d202,b77efa85,78bf3228,c590882e) +,S(332e39e4,d6732229,aed85cd5,83a3ccc4,24466869,bdc6a8e0,741b0e06,f3a0bca5,90840f03,60db52ae,a58b1b4,74ad65c,b66ac30d,f4d465aa,60244d48,5d7578e7) +,S(de019556,f0c7e1c1,6567224e,826532f1,d72c0eb2,91e70980,de7513a4,362f0c97,39a3d79d,1cc98840,4162227a,66382529,d75fa5bd,64977e47,9af0aed8,68411ea3) +,S(4c44c0c8,e675da80,c6ffbf2,61b82e46,4f81b76c,a3f902a6,8094a2cb,24ed859f,59e1ee88,1ecc45de,d8ff2800,243ab8ac,c5497897,1a3a2246,63b2b593,e45ac34) +,S(e60339b8,481e19e,5c1f4d1a,85ddcec6,a4e0dcbe,113e7d28,2793654f,309286a2,9a1eeacc,a607941f,b51c7998,ed2a5a98,bc58e3f9,4737f72d,1b08a706,a49d9d59) +,S(10f42ee3,e7292f3,9f4bc472,708ffec5,c6ad955,c5285be0,d44d02c3,d8a25e66,6f365f0,53ebe28f,db9d5f2b,c967cf14,183e130d,f01a5106,34a975c,ec916a25) +,S(7e0931ca,d1286687,7d2fb0f3,1c58d74b,703af3ae,593a9548,b6d53d86,6729c445,5e4b9fc,75eab41d,663caf7e,8056f4c8,a9c34af9,22773ffb,f5a12174,1f6b0b0b) +,S(36313f7e,f9613c6c,ff14cd1a,78362f7d,b7f1acc0,db278f1c,6a011435,57963f22,1e6946ab,2a94231,4ac6627f,5494205c,33960a91,ba663a69,8641bab4,43d7edc2) +,S(223eeed8,8eedc265,b2e18a63,ceaa2e9e,83f9ba59,2fc8f3bb,55cec574,2869fe01,72122173,4ae29bfc,f3632cc8,92d72d10,5593f7b8,d687e5ff,eff21095,c1bbd71c) +,S(b6bd5ec9,33302c5e,3fb9b32,18795a11,60dbb2bc,f9a9b5fc,31b7a5a6,28b3ec20,fb9f87f2,98a8e5fe,b15f051d,63b48bac,34f373f3,9b42a42c,d0f1d2d9,c99dd495) +,S(a365a760,3b1c24fb,157f69ce,8fd57ae,5a802dbf,3b8f92c9,8f0a8b01,4ce24668,73e6422b,7746abda,2a38cc7,298180e6,578005b4,1b0d3760,6f2bec3f,5c0a89f9) +,S(e86f8fac,43e436f6,f4adba30,9d446a07,e24bac1e,d379e13a,a235ca1e,d7cebe6e,1e7bb4ef,aa75a9bd,713a592c,42a01134,930b7402,77cc1cd4,a913d6db,f4a166af) +,S(f5a57dfa,d2b25571,dad09304,cfde1da2,5cab3e2,e85895cc,9933e868,eb9bd5ac,d265de5e,8fc90e41,d518dad2,68997a24,8eb90906,becba9b0,c768c5e9,877c1ff6) +,S(e1dcd17a,7259374,7e6fd8ca,b2464a9d,6656607c,a2bf10f1,45c45947,75f76c7b,efa2c310,23f86d2,6489feb6,1232bd44,dff819ce,6b95678a,130de640,4af9a20e) +,S(83f8abdd,84996ad,1be74b80,a05da9ab,cb3774fd,cca40c3b,afd386cd,cfa801ff,267ebd64,329fb10e,56ee792d,966868d8,1c85ff37,6aa24287,3d37c63a,4bc3f63d) +,S(54cc9d79,6ca85a90,27487c71,6511485b,ca324b1a,f34fe454,ea9ba54b,4f259fae,18c39071,ef0b861d,7d016e9e,deb6e83a,3c6ce8c1,517ce0f2,e201da0b,fab2da2a) +,S(9d12a52a,e0091654,e2875ac1,b11f8744,1c3f65ac,940e6a51,6351c219,31402ba4,5ffbb334,276219af,418d17f3,9f5fad63,c6d7e42d,d53f6e52,bbee2f01,38e81d2e) +,S(659bfdb7,66821a91,cd030917,ff21aea4,488007f0,b7ef3824,4f23b665,e6496998,2ad708bc,4506e85a,341ef96b,78bc247f,d7321a8e,bc21f9db,8444e7ca,254784e0) +,S(e2cc4e33,d4a08374,4866a253,81549a6a,76ba1b4f,57312413,d601296e,5eb4670b,528b2b25,347e7f34,7b79780e,a64c3718,80497f0b,a3b28e18,79714089,a4672476) +,S(529c0b9c,9e21c36c,9b2164c0,fa505601,e8dbbac4,cfcac131,e248e103,e6edec68,7fa44821,72a0ca01,33669e6a,bd2e0386,6cb74f5f,9cbb7e4,96770129,567125f4) +,S(289d6baf,be6a7d1c,154d6532,a80fb65b,3d89e57b,eb2f1dda,654d3553,683b63a1,801f4863,d3ce8d61,60e2c62c,55267877,db149ff0,c3cdbb53,38893168,7d005400) +,S(d16a84c9,e3b36660,7c005bb3,425ab432,2eab9b58,58d1899e,51f2ecf0,790f14a1,2c6f5dab,10715328,f9ffc5ea,4ad6e0f1,46ec79cf,19cb2313,79bb5198,5156dd07) +,S(d03cac39,4fdabfbf,440a6893,e410dab2,a7062df3,ecbe1aff,d30703b1,6b6348f1,152313ce,f530b317,70d85c08,7de95b1b,5dc4a86d,38e4040a,e5d1ba34,449d19f9) +,S(b66b3c6c,a673c4a9,77ca7d85,1f969858,d4c4b604,bc497101,c89207b5,a863379b,54ba2563,771c6aac,482c63cb,7156961c,4b00faff,187f0560,9a470b06,31624da4) +,S(be684644,11c47cd7,dfd3127f,4e7d7308,2a43fb68,79c5e86,236e4516,a98c8c45,79290f83,c61d368c,2e395aae,b9cc50e9,7d78ddc2,fdee9f19,a15fae85,826733da) +,S(478ac3a0,9f34f463,4d61de70,9ee01878,4ca421f,91d20e0c,5c62bfb7,afcbde9b,f752f3b2,ccbc1096,1ae7526f,5574b5f6,e4bc7d4b,f77edc34,f6e37655,7b0988bf) +,S(745f355a,f2ed71a9,9d4d7de9,c9bd4a13,7271a2a0,c077c796,e7064179,8f3dcfc8,18ea61f4,6b0c87f0,9ed05816,c31e1992,d4fe8826,630c5f6e,67242063,86e288b9) +,S(54e7bd6f,9878a8b0,909aede5,9286427c,a3157a8e,38ab94b2,18db520e,86760ce0,d7b7d80d,c1eab448,d1f3c638,675dc0b4,e04bdba5,340d3f2d,dc1d24f3,dfb8e49) +,S(ff56afb6,55eb431e,f3c6f5c7,fcc6febf,99b018ae,3dc95208,27e4a01f,a07d510e,9bfabdb8,42d7b1c7,9f4388b4,49a28d6,ec723210,ea27509,655e9b44,2591e371) +,S(c2bcc099,ed298fc8,679d0250,6d8ea790,ea511b41,5ff3ebe3,82d39d21,fe9cda72,6c7bf2c4,35ecf773,5b6c31a5,82fd38c4,825de4f0,58efb070,aa1ecb58,530f971f) +,S(2383f144,9811331e,6c54b9a1,19c681fe,c8549e36,890b80f5,99a80187,8e2ec4e,13ab411f,d846b6b5,938a999a,704470f0,d8fff03e,9dd35cb1,44860a0e,3533a1f9) +,S(2f2271c0,d4fa1d8b,f8a44584,ba4f5266,9953f72,89de16b8,17d6bf0c,6e096048,646ef05d,b40e50e8,b6f32c22,63ef553f,a957173d,a6f14ab5,7cd60b60,2fb42fc4) +,S(b7b49b1b,f067a27,eedbe55c,bb011eeb,809e7ada,ada5d08,9bf1f26a,25e951c7,fec760ac,a8160525,ad6ec95c,7cb0329,4a9b7f20,45907331,5b2dee2c,7f7c33ed) +,S(36c8e1ca,d9933e5c,971866eb,12daf81e,7765d4cb,9f0af557,94181aa5,e5409223,895eb6d0,a0252282,d71cc730,9116ea95,22f2e35f,52498853,e291932a,dc8b8fdf) +,S(3cbe9127,63283592,13173e01,8cc2b0e0,fa5b8a11,5684cd6a,6ee7bde3,bc1ed523,7b2d3dc9,22f96c9b,9970aa9d,c75f1e15,c5149ab3,d0993055,e4df30cf,ce44dc81) +,S(76e94d41,c4639419,23448d38,8b239e6,fe0aec99,314ed16,4e67e97b,6247213c,8ee4a6c3,2f010749,103460bf,d75fa38f,f9efe4e4,bf283cb5,a3bc186b,21fa1278) +,S(493925cb,12c0e7e7,a15749e0,7fe9dba,5b265d27,8eec0c08,506f3433,4b1851ec,70900c6b,3960a465,6cab318f,9f730a66,e4a2400e,d819da9a,1f5b16bc,4c62b193) +,S(b37fdaba,d1a1393d,79820eb4,a4823d38,3873306a,a9f5e6b7,51173aed,c43cdcbf,8506f0de,57fad139,e20df67b,e30a75a7,dfd325f2,9e35652f,28fec608,f27030a) +,S(4451960c,48e95c49,32b0c90e,9f90724,8f2b7023,9c6c703,3c29f4a5,b0a5e8c1,83553a18,d9ce9f66,961c9e1a,47766a4e,28bc404f,bef524de,53b1b687,d4d7490c) +,S(9b0ac1a8,697c69b9,80cab20e,b3f98718,7857721b,c869c704,caf63b80,dfea3449,210e4c53,bf1bbf3f,71e32a58,22809853,61b61723,72e845d,65b5661d,fa7e60e9) +,S(e6697355,ccae4f7e,122d62de,1c00dcc5,32eca4fa,7dbd1ceb,e92684b4,781e0851,1f122cff,dbe5ef3c,944353f7,18806a82,9d3ded91,427bdda1,736ba236,e9bdc3cb) +,S(ffa890f1,1a1aa4ca,1f26f86,1288bac7,ad480a4e,1cc47f2a,fe39f260,f167201e,1688dfc4,1716fc3d,473c4149,77d0ee8c,ac569cda,b01ab5d,69d449ca,85439cb4) +,S(9088d4f2,6ce238cf,63eb09b1,5c04a04c,c41fcc57,946c6c14,cd3b1b4f,54b6bf47,9e380417,bc61004e,3d5c9943,b3d359db,2ae4ec81,2b70e909,bfe265d5,e4d2c2b9) +,S(a3395dda,c1e760e0,fe7f7e5f,e3296bc2,99949ca2,2c034707,67c08ffc,d9576a91,4f8a879a,54036d17,16f07016,23dfcfba,3141850c,de003870,6ee940e7,452393d3) +,S(11e54d64,54aac1e0,58cef234,51f686a9,1a77300d,75330ecb,d208678b,2b8ad651,749b2960,5a8419f9,c5521dfe,f552a24d,aaa53f45,908d2679,6e08b396,c9c020f2) +,S(c8f13cdf,7b41e822,ab6d5a70,7c701d29,98f5f0da,8e4c9746,75e808fc,64327f30,489a69df,17c09c1c,dec329d6,a1f34f60,445d7aad,d609d94d,44168947,c3199404) +,S(9175e6dc,cf674838,a94c628c,3e1a9dc2,9487f394,8a25e50c,d463cf6e,92d84442,8705713f,ed377125,51e37e51,78ca7a7,c13e193b,1b83c729,8cb08186,8fde1c22) +,S(8eed492f,b6d5f0e9,ee78f6b8,953ac0a0,5df8b9ec,db17a09d,22863bf4,3620099b,23a45742,17672e98,d9cf8b94,62439ec8,82e1acfd,40db9d9,9ece889d,1e0ff1bf) +,S(cb95ce23,dbac06ef,79793f54,3105f5d7,5cde90bc,651b7756,bebfa367,d5c2dd9,9612a6ba,c023b0c0,73b5ed99,271ddeb4,57d22d74,f7ecea4f,c618be5e,164a9a48) +,S(667218c8,bbd3ff37,d42a8ebf,8b5a7791,d8fdd493,9ce447c9,15dac906,67a3c980,dd401179,9e19afdd,46b44aab,1055b554,452a21e7,6750f2a,ce98083c,8cec26c0) +,S(884799c6,ded4851,ce53e855,dc429698,c7627b5,a0ed3852,19b59af8,32f76e5f,238d75ed,84e6408c,79cd2d37,152cde78,22e34377,fccf05ac,3afda662,c21c4a6b) +,S(8d98f36b,5fc0082c,597a05ba,e24ea6d2,2cc8bb90,3a6bf96a,256eeead,6911d143,26e8ad1a,fc902a6d,505b2fcf,80168177,de7df931,b1dc1516,f2ad7b38,e0ab3cd3) +,S(ba9062ca,c0ddc6d3,27f2cbc2,8d2efb1f,d1db2388,c86741ae,7403f4b8,3fd70ad2,473b335b,3036e754,d9d71ccd,53814455,674539fd,7b73d9f7,8f24bb0a,668b38c2) +,S(4a2d36d7,3bf0e609,7a69be67,55621051,7453ca53,11e288f0,1ff1dc03,acdca29,ff691e7,a90331cd,44e83ac6,c298f5fa,9d694a81,48db01d8,595a4386,b2ca8f83) +,S(e868f28f,d99c4b16,b64fb0d9,32c325c8,6b365136,e0055c4f,cd362e1d,cf37d0c4,ad3346c1,83401034,8e8e0440,e889109a,40e5fa11,37d94bca,2742adec,4cd4a9eb) +,S(6c5e8689,830a6ca5,12d77e56,62239833,ea77e696,da40feea,99da3519,2babbf3b,c29e05f1,5fd00b60,7bdc333d,d753647f,56b9830d,46a597c1,2bee9465,ad779540) +,S(b3a172a5,6ebf2dff,aeb91cc8,6b9d5a91,c317adc6,250ae210,e1a25bec,1c046344,28f6dd79,9ae40d6d,bd31fff9,9a4c2fa,f06401c0,de7a5d11,9fc5faf8,3b4ac3d5) +,S(198f05d2,e2f9d779,a50aed67,39468a8c,ac4a22ec,71a3ab80,91a94e2,100d8f47,cc6a183f,c9813173,caee3baa,f3fcb223,39708968,360c02b3,cbf899e0,b7cd0414) +,S(78b2178f,a943a791,4bc7703a,e850b07b,41ae77db,79fc39d8,9f0f50aa,b077f48e,85fd3e34,f2cbb092,8bb89004,e1801be1,d78fceec,c29eabeb,11b9cb15,625274e7) +,S(6f70df00,1d4c5175,f997a795,170e28a4,23828ef9,d5f72dcc,cec43fb8,d9943f3e,26315213,b77183e4,5979c34b,e730e2a6,956a66c2,a8dfbee5,f0f1eedc,ce8315ce) +,S(ab813144,3c946d29,d05509e3,b45b5926,e3964b2d,1cd0fbd0,9cfc359d,b5a9dccc,aebdf315,c1273af,a0c5e587,6c6c6132,16b7710b,3f505062,6336ca9,4f5c5ac) +,S(e72b3791,dd751127,23723e62,77e5e6ed,6b94569e,ba3321a2,a3e883e,5473ad3,131b3074,2dbcaaa0,fd3109ab,5e3a2847,9c2091ac,8830b19f,d4df4c82,9b28a3d8) +,S(ca5a3296,ecdd5e50,38fdf77a,fcc507da,bb525d7c,56b50c74,61928432,ce3ded63,8bdb6794,b7e177ba,9027258e,42b365bc,5a14209d,2bdce54b,3f865fc6,ffc4ab9e) +,S(eaa3be9f,26ae8cff,cedbe59d,cc03b202,e7d2e815,a7269819,c881a700,e31a9222,1b5a2cd7,a367d34c,60ef8026,51df2d3b,36ac2816,7cd7eacc,735e45c1,9524ec1c) +,S(ebba882d,3ab4ff6a,e162076d,56791554,35a011e6,74872206,582b03de,e8e97728,94222a05,3d8dd2cd,cdaf2ac7,69ed8c65,8a004c58,7bdfd0ed,355be474,65be16ac) +,S(ca0d97ea,537a5dd1,147cb784,eda20601,ba88e0d1,68e8df44,6d8923c8,353aba86,874ac858,89eb86f1,88ebb979,a4490e65,96c97892,874b5b68,167ca99,f68fba1f) +,S(51de2965,34807454,7e798f98,c5fc19c5,84a90a0b,e1dda24,7718cfb3,ebb797e1,81374e3a,ad04e6b9,55c1952b,fcdf9a7,ace0ee4b,99e487bf,87ceff58,3f7c54d) +,S(69d611f,3136be2,cce39bd,a1d48fb6,87b52135,365b8df5,151c6ec8,c1387509,75e2d820,563b64ca,c4d127e1,a5c29720,fb84c0aa,6b271fa7,e9da2c22,3195bde0) +,S(31163083,558660f,23220456,1dcde218,6fa4a4c0,de450a9c,b2f57de1,3a8aa135,25d6d496,b1341688,3008c636,ae1d8b76,29e14207,e5fbb817,539ddbf6,ff46eae2) +,S(84e342aa,efa9cd4d,4d82e5b4,4d0ad9a9,11f4623d,8684c274,cc3cd561,2c7ac334,fb90dbff,260f9997,c84f0a32,4fe5d2f6,f552affb,50aed654,fb8f660,2a92a70e) +,S(95efc402,969db115,22446814,3d4e3aa0,fa812aac,8867a5bc,64d66692,67bf6562,315bcc31,6149252c,56f3f00d,445255fa,e4567d9f,d77ab4b3,e82c1359,9f371883) +,S(5223623c,f87e9da0,bd289993,a55bb9be,55b40149,bb501507,e3d5c9e8,d78d07fe,6bfd0a21,dd2df437,9b1c16,b0076f88,832e921,db3cbdef,fa5808fc,ac613b56) +,S(f212d199,a6b707e,61d87ab3,109e1178,ea180f19,66b0a55d,f5f4cb97,c0cb0a4f,3280446c,7edbb64e,e47c3142,7c0ea113,7f511422,19ec3824,12f6b069,a0f7c84b) +,S(6b55063f,f25d76f8,2154431b,20058f96,e1e19ce2,210e1b50,835cf58c,31cfe8c9,5427dd62,36450762,46e99707,6f60ffed,558a82a3,dd7e31c6,492088da,9069f8bf) +,S(2539e5cf,a09690c0,12ae0c12,9e6f8b27,c9388d41,a82e1e96,47219d57,9b23045,94cb83f6,1e26a4dc,d1b93000,e5113347,31d804b4,a259e24a,77c457ad,d9021ac3) +,S(aa9b6ad3,4aaf1c30,71aed31e,8f28c3f7,9106421e,f0e53fb6,297fae54,a47d51d,dc0958e4,9fe4ae00,98b4e7db,10ab4d99,58cbd87e,ca443d3e,d1c9de77,83544c47) +,S(a850a313,aad224fb,f5ed6e63,5a3f6b0f,e08964e5,e9ca262f,780532f6,13487ad,7e476ad5,4cbc55c2,3b9708ca,eef3479,d9a5e570,26f15a4c,43b83363,ed4ccbe7) +,S(314fec33,f4fd0c96,d04889fa,b18e29d2,5da44132,6477b28c,7418d4ae,5fa09c1a,a2c9513,a98ffb7,9b5dd4f5,49534fdc,d9b4b8d3,1aa6a4a9,76b7b94f,ebd25f42) +,S(6e7dc3c8,9ec57e79,ae1581ae,1afbdcef,183998b8,cf52dc85,329afa35,4f3d0963,6b636805,6d5a8e9f,9651e3a8,2598ab1b,8f057830,fccac964,a83515f8,9d9f87d8) +,S(596df693,fc4ba2d5,20497a50,7d1841c4,38b6cfc0,58c274ad,9557d400,573337c5,6609ede9,1c97b09b,3a171723,e9ec5cfe,74b75c33,d5ccb3c6,bd03fd04,b37f4ff5) +,S(235f8dd4,10de7800,58550e8e,77bd42d4,ee3ba259,97bcb4ee,13cf0a12,14e8afb7,bf6e0ccd,b8e8e136,800f8d59,510a4455,53b72c33,824b71bd,189e158b,6cfa6712) +,S(a9d8ba97,b259e91f,125fbb28,c80e81f0,3f03906a,ef692279,4c9cc23,13db8b47,e668b954,19b580f2,67472afe,221f5895,5e6ce6f6,45ba737b,f14754ac,ec048656) +,S(53b44dc6,4f74c170,142bc629,51349b88,c4e2cc35,b7d9a7f4,827b07e8,4a288e5c,4aff13e1,404562c4,d8f006ea,dfee7b5a,32216187,d8c96c7e,5896e157,97075d4) +,S(76e6e038,a6baf9f7,1acb56ca,1494486a,a9187279,486f62f,947b5a02,580af1a0,51a5d110,66884076,44c18348,be045910,3b57e0d7,2266ffd4,465e6b4d,e1f0f0fa) +,S(7761ff19,2fc70129,10eda284,dde864bc,1c45b4c7,1bec7870,2bcf53bf,9bc1e6b5,80980f70,a82f7196,61f7e1fd,fc3e7d37,e0bb75cb,b1ab47c1,d947dac4,296e11b2) +,S(8199c9d6,1224f51f,e6dcdc33,3869d860,95c0bd8e,210d2d7f,8fed2804,a89aadf9,be89724f,5cbd2384,ae9bbd73,f030dc74,a158ee7d,2a9d292d,daae3057,4b1ec89b) +,S(15c279fc,760a2556,bbd62680,3bd779d8,8bd4dcb,e508b3b7,99d27405,91c55c0e,fd5038bf,ed80c963,4915d352,bca040fd,ea0b9b0,67215dee,3373e4d3,53390c39) +,S(fb3f8d06,b2804047,6f7b46a3,ecc2e7ed,9724ace4,14831a8,3c111615,f8a39b46,f9250cb6,ff851b61,3b3fd70c,63c1bd72,3177ed50,ac991185,4fbfb3cf,6bd2154e) +,S(39b2b547,3c964125,da2723e3,97c3fde,f9faf415,db0b389b,5eac9a6e,ba012edb,8ac1c2a5,a586f413,bd68aedf,1f65f231,6bce7bae,ddf9564,2882f2,1bfb7547) +,S(42d5dffa,e476151a,1d3f6d0b,bb24e8cd,bf72d73e,ac87e848,20cff44a,47f1552b,631d9645,d941c001,627ebe3a,f403bcf6,663f6e46,17d86ee2,922fadb4,b8847ee4) +,S(84dc96c6,24ecabf0,a5edd071,1e922d9a,630a0bd2,6d9c6158,e311fb7a,e6e0bd8f,40af318a,16b7324d,2acff10a,8bd2fc25,c795cc71,c0aa5a8,2cc8eae3,ef8703c6) +,S(636e760a,797bceee,11b812af,37bf7cbb,4663ba02,c36d93bf,1873983,4bbf505e,ed5c5e4b,6cc8cf76,436dab98,104b9458,69924f40,57d92ff,d74f703a,65f724d2) +,S(137fd025,4bb5ee78,669ca6f4,ae278064,7d32bc0f,f6175090,d4ff7580,98d06ae4,282d6aa2,25eaaaa0,e9b186a3,36e92e7,e07ec23d,e9ce4bc8,8fb7f09,328d0fd4) +,S(218ab848,39e49256,b55bc7a5,cb250fc0,df781f60,17abcb61,1b6734d2,12459e92,7eb14f56,b53fb0dc,430c49c8,d32f39f0,1a7212fc,701ca444,c994b3ce,4d0e1599) +,S(6b3f7ba0,106f22f8,df69e3a7,8f137605,1b2f0a99,ebb4f4fb,61915495,5f8eda65,c5788c4,4c946bef,86d9a4ab,481e8873,6c831000,5d36d3b7,aaafb7b7,2330d299) +,S(9b414ecb,a2de1195,196fdf19,62eb5b86,131ad1ca,f7fefd08,c5de31fd,d9e8ceca,38e6f31f,9550df40,80db0626,9da9f4e6,51e94e85,95e74797,639225e,a725a637) +,S(436b07a1,857425e1,86933af0,d1d444d6,156a4a8e,f3f2df8e,cbaf661b,26940653,94a52f35,f124ebde,ca642713,724fcc63,c6822dd1,bce4c53a,ce155b31,443f2d44) +,S(cc0a9338,9b25f82,33419bd1,87b5e290,b8d76f28,2099b4d1,fff32cd5,128fbc6b,cc7e86d,ec7ac7a9,448cb627,875500e0,e713ad7a,430ee9ec,220bfe87,6e3f458e) +,S(5a1b316e,aaf877af,cc7b1907,eaf8dcab,7ea684ea,72fbf888,8f21fe83,c3a19858,4af0339a,da08846a,6b6b3466,da69412e,74411094,22dbc450,cf7424ce,cd81e7e1) +,S(faf89165,74444bb2,1fe1e411,40398b25,ac4a5725,2f9ff274,e7d409,6d6c53ee,cfa7795f,af75547f,5dcb6426,3b16c9c5,d87984ac,81083cb3,99714f6c,99a43100) +,S(39e5fd8a,ca141623,1840c68c,6c6cb028,c94cd22d,49619e33,aa9e4dea,d174f248,f8121f65,7083da65,74013e78,88f66276,a8d3686,528aa105,61d10a6f,8c3c1ff1) +,S(20a135ec,147d0cf2,ccd3cddf,6fbe1356,a64b8ed4,219bc0e9,25743098,325cbc1,b17514ab,ea1a3725,4c101fd2,675d30a9,fa1d170a,811f06a7,15622ae6,ee82c013) +,S(a181a1b8,af48f73f,a13d69e2,ac75b13b,9903ca11,8a8851fa,b461c2b4,2c72320a,c96c8467,3f487e62,3d72c432,ad5887a0,a66fbd3a,c43aa5a,219c84b2,97a6df20) +,S(395fc031,720a5da2,faf5d76a,9516de8d,eb462695,5eb87fc2,752462c7,7db3ee4f,4aebc86b,53783895,ab4e14e7,c3ec449c,962ac869,9b340523,1288bf41,c759ad6a) +,S(a36de9ec,f6df2b96,87d632a6,1bb6337d,3fffce5,71b9fd17,4246b33d,1b64fa6f,784e4c4f,a133d140,1b212e14,77deb40d,620fe29f,d0f05ea9,cdbdc862,651999f4) +,S(8cb5a899,ecee4430,f7381820,4535f57,e55a3ab8,3dbdc359,d04746e2,9840ba8c,12a7282a,e9c3a3c1,2c1df0ec,c3d28b4d,731dedb1,ef02cb2c,b92da5de,17ff59a) +,S(de441e1,4d9c9ba1,90e37201,22fd1fbc,4cee72d8,b26b1f29,9c450b66,60b60985,add1a30e,d12ddd33,d4f740d4,427fbeb6,2927b3c6,75032110,508e2114,271b63e) +,S(88e38b56,b5e5544a,f2f3c1b,7128d118,520646c3,97295067,4078207a,9b9fbab7,8833208e,d44e9656,e5bac529,cbdaf184,dc8ea020,a2d8f4b7,8101d8e6,1000e5e3) +,S(a4f0f992,f5616420,b9ffa3d1,58d2d729,3ee217c9,60f5266c,6c5f3374,f4640a7,da6741a8,437a86bc,40ec9188,a1af42fd,b131a8e,81289e71,3d80e201,f82e6ddb) +,S(5f00a8cf,f2d1aaae,604a40be,e451d8d2,86899fbf,37f96ad7,efe52407,1c5c945b,135fc8b6,9ea76d6e,39d1549f,b4692d5b,b48ead3,ae6c662a,424b63d2,b59deb12) +,S(59351a0e,bfd6fca2,ee04c799,838ddb8f,9d168967,a9e6cda0,b416ce31,88f99218,6e01a267,3184f4a8,28e27b6d,4291e7c8,fc4159d,73a465b6,4fe3d4e9,d50fdb34) +,S(175ee35,f5c533b3,de87387a,5f263d0c,6705ef73,e77f39f7,2c796f91,2cb1aecf,a3792715,4540e426,1e0d40fc,4c5fbd60,5fca3b63,3cd7b506,a80d0280,b9d9513f) +,S(75189b41,597b18ac,9ab6362f,a7905ad4,5655951d,fad033b0,2047dfbb,f347b8fe,f536fd21,ffa10ea,57c023de,256a59ed,aa246842,845afed5,b0177b77,21b2527e) +,S(91af9ec3,2522d65c,70bd2a31,57efd23a,43885573,6b5a1c72,49a414,a19bd4ae,312007c3,8462b858,6b44898e,d0b4419b,31c9cc19,a2ca6d6e,6436bb08,741a32de) +,S(ddb2fc8d,41fad5d0,5d109443,2f283c5c,732273a4,1a14db04,712a1d84,a4565c27,4f7e30c5,2cec6f4,201673a0,9893d092,8f6ac9b6,d7f2da38,d63ba2fa,d69c1d0a) +,S(9ce65d22,d7240dc3,50144936,ea412539,ad40a907,f2b04f96,f7ddc1df,f63641a6,af93e587,7f25bc64,2460b425,76062f54,c3037e43,80542340,cf927609,79d97c8c) +,S(7dc0d0d4,1fedec58,91c3932e,b0bf492d,5489f1b0,1e7f95f5,4936d76f,776e9a2b,d55a279e,760c3c13,bfa1c7a4,93831a14,1e9bbcf5,a535934f,a5269995,b107c47a) +,S(d01215c,b6b4d728,9dd8d351,f3e4aa7e,f190d40f,3281c8c1,63d03a95,4c0e5ead,ef98344b,ccbd7eee,723ce7fe,641854d,c68be6c6,99eea25,48b2c881,b0fdc662) +,S(d4d1c31,a9faef8f,5991b0d2,9bdff3d4,bb6498c6,2933eaf3,e1d06767,8d7cb92f,98f3a848,ac6b91fa,85bccd42,f2185e46,715faedb,a4f6590a,4df5f862,ae6a4831) +,S(cc659ecf,42abf24c,3da2d83c,84b1e32,3d718f0c,41a1b5a4,9fad2f24,c6080839,7bbdfd55,4d843399,b6edf249,ae795758,c7aef094,3f84ccbb,f0f2761a,c81f963c) +,S(19ba1567,d5cff385,9d074e94,478bef34,f0eb4775,6708d04e,594d1641,71ea4b04,34ea281b,d536b02e,da858311,4e59c110,30555c91,c8b90ed5,d4f53485,4a820f9a) +,S(3f0f02e3,1a6e5907,631960e5,fd52d2da,e825d8e7,529586a5,437798f5,d7bbc30f,b93e27c3,3aecd4da,59079ddc,be2cd6a5,62a3bf29,7b40519a,3509061,e3e63c3b) +,S(9884c48f,35f63fd9,5a9dd895,b0f382b4,8d0fb096,e5fab23e,df07924,149ab12,5688c266,7070437c,3d5e321f,58b6f41b,e011545e,989feaa0,13f241fb,4180eb44) +,S(940f2a93,79bc9c55,3082e85a,c2f83e5a,bb4a6fe0,2b23cb47,4489bb7c,c46c7b4d,b4b82380,77ba9d8f,51e7c735,cbc6a784,2aa7429d,2cae2284,700c0e2c,7f21fd9d) +,S(a9a7699c,e5353d9f,41afeccb,b5343ea4,5f4beb03,42f9001c,e0742eb,58b782f0,3c759eaa,b3e18cf1,a4341f77,8a601ac9,b0536fbc,5fb498b4,c7ca9597,9587c994) +,S(a21e348a,9cdb00,56e36cc2,82d0112a,93f4da1d,23f274af,b1522263,b218913,141543fa,652f9506,6ecb8e28,a701e663,c70b1873,b1e778da,588c1f4c,7ebe89ed) +,S(d6d54d95,1121e118,52b298d6,18ce738,e8142906,306a5ca4,1f048fb3,5a5fd383,897dccb8,de891fe2,304fe9d0,38d8eed2,8f76c8f3,535a2912,41253445,828a7a83) +,S(7e0a635d,c937eafb,488c7f7b,5efb12fa,6232b464,a3a47ebe,21cc0f1d,c31e6cda,d2d1d4a,75525e1d,2ce5b34e,3adcbf36,74489c86,ced61e82,2d63ac63,8de921e2) +,S(4ce2080f,66a21c68,428870e8,36b3fae9,55bafa14,fac200d3,afea00b8,d451a659,29e1fa26,565b02fd,318d0f3e,f0df93ae,f0ca1b92,73e31b1d,891f055f,6c7da4c4) +,S(dab86b87,b633bf65,59cd5caf,1b89e815,e6d4b7b4,d8f58f7f,c091f542,712bad2e,8e49b109,d79a55f3,8d8159d7,f55bd930,4506a634,7e57bbdf,8fd15eb3,53c85b5e) +,S(c6a14ac2,90fa32e4,e8b5386e,a7672d39,ba16224a,152897a5,6ae29001,b365aca9,42aadcd6,dcc588fe,2421967a,42ff615e,45cd5f2d,fa258164,b2c0eac7,735dbc67) +,S(2599fa40,880b108f,28f24400,4f3458f6,63510bac,c8a1041d,e694e214,ea450a27,54792ad,4ae1cdf4,6a7a973a,1a02bfd2,a424c46e,548c13e6,951d94c8,7ba57a01) +,S(f6ab0cb4,a6afa8f7,aaed8fe9,e79ec43d,31265533,6fa4553b,bf3d7476,8ed9f9ff,4ea12589,c4ba0090,48c1a476,1907fcd6,82e913bc,57af13f9,73fd9746,845026ef) +,S(f51bd48b,ab8f020e,2d97ecdb,d3ff4da7,72738ff2,bc71dbeb,dfdd48b2,707f1dfc,6b168ba0,947f47fa,8a7fe7bc,e7ef90f9,b361c752,248bde43,8c93f3f,4a697c40) +,S(b601f114,6c9ca90c,af798f2b,1d0bf7d2,a50b286,53521362,5c898f0a,4a2a3443,a6ca3041,36b6b675,5f317a11,59f0f110,6877fed0,fcc167ed,f0cf2391,c61f87dd) +,S(792dd67a,e5957c04,76f0511f,c5b7191,5be6a158,f2871ccb,37e90651,f85f974b,9b7f5cb9,bec59f69,3a44774d,d2f463e1,1a4c1c5c,84ac3bcb,94175809,4b1dd44b) +,S(7d884669,33b6f4ad,b3700eb4,f02514ac,4c29c420,33c34377,93101302,8bb093f9,2fc8c35e,674500db,5287ead3,5e46c306,2ebeb5f8,a5134885,a2f9461f,b5e2cb3b) +,S(9c76eb91,6d0f860b,21b82038,77089435,ead4bc41,df82c249,10edb80,692a5351,72badbf3,38800156,1e235a6d,a8c7769f,e51d1e0,d6de06b0,d9998290,f5c88b62) +,S(a49b5638,3d8a93e1,55e52a2a,a1e47c33,8fef18d8,2dafc24e,cf5bb0f3,1fd807f9,1bc271b3,9bf34c4c,ee4b0760,bc934646,9dc392e6,1fce976d,bee58e8d,901d3ae0) +,S(4d3135a,675bb0b0,ca9d5cc9,68f1c72e,a704c9fe,77aea9e0,a4d6247c,dc634460,ae5d7cbe,72f5f4bc,f2f1ffea,cf02b13a,cb74bcef,68cced38,395a76ee,280cfc4e) +,S(59572fbe,17dd6e38,fc0421b9,b42f192c,eff95583,a9204e37,11f33089,9e53f588,57134640,a8cb3f9e,6a1ab805,1d60a047,a01c8f2f,9b72782a,39c45421,de1c7c24) +,S(73cccc6d,49b4780e,caaa1c61,228d2e9a,a5fff08,f5605a5,cb5ea1e6,712d9511,463a8d74,f986c8f1,1c12ea8b,59b158d3,6a52c06d,6a85b08e,dbb2cd4f,e3752cf4) +,S(b6c8ebfd,db620aa9,476f7280,e8fdcf6e,ae3885f1,87683d1e,e503c2a3,8c4c1e46,9a6faed9,f0210048,be575c2a,c8194a5e,76a25d55,f3215dde,b4091060,e7d39802) +,S(b4162e0f,92de5493,da996c53,93067de3,b9cc4a8d,4c21df7e,b507fc9c,4c5e392e,ccce10d0,c9211d36,46397873,3060d982,eecf2217,7b8ed120,a4052561,6a3b385b) +,S(46bf2566,ca4235d7,abe91955,2a0b8d40,a581008d,6544d9b7,a2a469d7,8d2b33a2,6f66fd6b,b8278841,92d82e39,cd0bc9d5,285b5cf0,2171ef1,b77c87f,c6785040) +,S(78446da4,e869a9cf,8badfcd1,b89c135d,b5422a68,2a9ef6b7,419a914e,3d59ab2f,4215b131,db7e46c1,9e03c051,f33bebde,3f5f31bf,2d428983,27d2b586,5a8c9ce3) +,S(86886a05,511080cd,42bdc762,95eb8edb,fa2b01ca,5cbd1d1f,4bebf001,5605f3b7,c71b69f3,5579c0dc,7078854a,83add404,f9b753ed,597a77d7,67507e77,f7914466) +,S(a02e675e,37f8fc43,fd38675a,744406e0,36d5fafc,b28a7371,e16d94bc,83713388,d6f9a541,835c80d4,eae16251,277e9eac,4ee66bd5,a1899c36,de3173de,fc41239e) +,S(a16b6aa8,432c6ced,cd110096,697bc04c,9b299777,ee287f14,ea4cc889,8492bf26,5c11a70,ef9e42ac,d0ed644,6ea7e14e,1e734da1,89ef1ace,d2fd7241,4e0db298) +,S(66a3f2fe,775fe5e5,d0ba1205,f7b81fca,12d7fc2b,f8685c5c,97114b98,e0f45b5a,5059bd14,a49ad49d,550daad0,30b4eb21,e626e2,95ed01c8,c1823050,5e5e3eaf) +,S(9a47a3ce,bf9a04c6,755c6321,61150ba,a1f09460,ea855785,96213784,5314b3a1,22da5ece,8f387e6a,f37c7045,b9296927,efd3a3f2,2b95eacb,c6cefc0e,ec40a80a) +,S(1c014014,9027b9a1,e3ce3c28,8f18fa87,12b25a53,49f9ac6f,97af6273,5b6628c5,672190fc,d048d3d6,b78bc34f,f160f978,87b49934,5753bd35,3a456c96,e448a4f) +,S(c2d9670a,1de5e876,5ac965cd,497e0765,8d137400,9e4ea31d,57effe5,2e8d84cc,ff818647,a6ddfbb1,3ab56b58,52956d08,b97a2e8c,f852379,cc7a7271,f13ccdf1) +,S(1a9fec47,16fd6a69,70ce094c,4141d68f,d21339e5,5396a691,e01b1e5,c996ec1d,e38eb2eb,6c8373fe,94f7639b,595de291,d29b8738,11f5d40c,24006d8b,93f8557e) +,S(b7df52ed,15e91a6d,40e9e500,6b1ab26c,53a51466,98d63bae,77856afb,1d8c464,ea60f1bf,d915fd8f,99d0706f,ff180d51,705c360d,a5fdac1,162ec530,b6e21254) +,S(2f95cca,bd092e2f,bdc86a53,40353350,918ba7f8,8488b9d1,295f9959,d7db6b5f,31456814,fe6ced86,59ea9c3d,f09bf38d,d5b0f893,8db1ea7b,5234648d,a1693ad2) +,S(763926c8,64dfe4db,6a1a432c,a37e4022,3b6ae1a3,7def3fea,883a6612,bd8a7c1c,f34d5b72,4378d10e,bb4b3e63,d80f1f98,a3e741e5,b9e4fa41,bd3f0a5,c361bd1f) +,S(2e43be7a,12916cf6,f312a513,fcb6c98b,708ce2dd,18dc4ebf,72a807c9,c8a31b0d,db919224,ce1b7e57,16e57b6c,ed514cd0,a3a9dc09,8cb59c5,971e99d0,dc24acfa) +,S(7d65e48f,1a867d28,76731984,afc6873c,2d1acdfb,13a5adf9,a56960c1,cd4a5561,9c73b955,f0957ad2,ff0e2d4b,caf795d8,bc992436,be7e69da,7b97ccbe,d983ebfc) +,S(1c6becc0,3131b772,cae166f0,4d715390,6b132c87,c5c76b7c,10b94a71,7819d725,2c3c64ff,94998533,97dd26c,dafdf608,41b84a22,cfb4906e,318c4d24,b23280ad) +,S(f5042a5d,5d118102,32ac83c7,d7edf079,aff339b0,7e9d20f8,198b2a64,13347675,19c10fbc,e644fc6d,2f238802,a045052,b2723f57,5a8bdd20,b597dffd,79a3e4c8) +,S(7c387866,c2c0353e,6e00c887,240e084f,e0ee9f0,2de12539,b4833588,bd4be300,ccc66f94,587fc58d,42fc49c6,d074800f,56f08855,6caf4ab4,c37b43,ef2b8f79) +,S(ece8ad23,d33adc2b,6ce38194,58ba2ede,104b35d1,1691f4e0,b7b206e4,eab3c140,eec976c0,7fa1d3f5,f3c245a1,2c9b728f,1c7e672f,53665e7c,5c6a408f,7c0c0a88) +,S(822b0926,a274dc38,c9eefecc,7d021774,b951cf19,3e2cbc56,a1baf58f,19d12b9d,48bcb10a,f9cac375,8314d2c4,9fcf0512,3638f008,510fe63f,1be0c2de,44118313) +,S(d26a3a03,6ef5f428,fa058d25,7ce62fe3,401dfe47,80c468a8,5cd2e77b,f85b8c3,98c39762,3a644329,7d5c6759,a308c2db,62f1bbcf,9bae4ba0,10fb1175,126a6fa7) +,S(7febb81d,8aa0cbbd,3002ab6,ca247d1d,24c8fcdf,bb1664be,b5b3c346,93019090,ee625bcb,12ca6da7,544ca6c0,2a84b9bf,966dc923,d8b23b44,6cfa4604,a6c3ec26) +,S(839e44e7,2d43b6bb,e6f63a75,cc3644ba,b7aa002a,6de2c087,33df2b0e,51d3473c,8368f635,26f41422,a563806,d775bf68,2d876d98,542b3da4,3e591e31,340fb9a9) +,S(52e947da,1c96e07c,9e2c84f3,23f2eed9,7e049b97,86d21135,ea958eac,db0d7afe,6bcfdec9,e0c70d3d,39de19a9,9fa72ba,bdbbe50e,dc44897d,9fa670e6,d473a831) +,S(72ec5426,5e4a743,1d7f6dd7,1c8e9e4c,c8b22074,cfcb00ce,db18c6b4,c67f3603,ddb9360b,7f9def94,f5ea6d71,51eed4ba,49455cf8,15bc9023,6156d4fa,786b5ee5) +,S(370a3f15,59a55689,16bf9ba,f2863d11,2ac051e9,d6a90f36,af39add3,1406c849,854cbda6,8517cee6,95ab5d3,20b1067b,ee80d993,235d1dda,ba3a0ec6,1f005840) +,S(12e57888,60d2fbdb,cb3af527,577ef6a1,41d1cf0c,f719ac6a,714f9a39,9bef5dc2,f5af7aca,5dd8126f,7dbb79ea,d5a4b475,a094969c,64adc821,ab46c5c1,86bd9ea2) +,S(b494abcd,b2fa5de,17b1abad,757bf9d2,8b7905c8,aca0a5bd,fe2ad8c3,30a2b722,c397ffd6,dad8619d,9ff8d8ae,e401a4f8,cbacf710,c6409adf,bf991d72,9294cb87) +,S(2957692d,900d0b94,b208245c,f71bdcb,118ea6e4,499dea83,1064605e,8ab9d89c,a3c55447,9284afea,37e94,fc24d50,f129342b,7ebbaa91,857d655a,40444a7b) +,S(61101879,f325e072,bca13642,dc14a5e7,1969aed3,2e49ccda,39cbf723,a1bd20eb,4e199c82,4816e4bb,d5b67269,e9d8eb0b,e5c2483e,d66757a9,c1d59847,e443b3) +,S(9eea48b2,99f3474f,8aa8c648,c2721fbe,c65f6ad4,990ab4e4,29a9c41a,ba55ab18,13954697,35ced1bc,7e857049,7f2b5a1f,b6802892,fbee0654,c1d7d89c,1f234443) +,S(dbb054d7,8ba7b707,ca475982,6a36808d,3fff42b6,31f1bc5c,c9df403b,518bd97a,396ef6c0,96343a55,dd404885,427e781f,a55a1f8,1ab95d4a,89d87975,611b923a) +,S(dba95bd5,7fdd2ef4,9dbcc0ea,35c14dc9,b2f62541,5b08e75c,d70f3caa,b61bbcf1,2af0965e,b7a17e46,18b6dba8,415159ba,b8f76ac,ae9384cc,64a90e32,d20a3d) +,S(6c312c9,7979bb0f,e72d8feb,c3c755db,bf1a132,722f6ef5,297beafb,8ad0e5be,36366388,db74739d,df78d5ea,3d8fab54,6c435961,71f78643,8be00718,8202c6ea) +,S(65eb7057,a494bc8f,549b8638,e18cd717,ad987030,aa3161e5,b9fe31b6,dc8825cd,458202a1,67f285e0,9196b4ac,f87068e2,160b7b42,2095bc92,7656694c,2fa80312) +,S(a0696917,b0e868da,ed5db7cb,d2aebd1e,c1117426,d842c0d6,b567e2b9,4effa7f6,c874d20d,a1bb4dc8,f01cb828,be8bda8b,c797ec3e,37feb0f5,ba55675c,41ecba78) +,S(4191bb82,19372a13,2dd37830,1086b64d,10874479,1d3b7879,3b27c65,782cced2,c74907c9,8ce4d218,d1ee52bf,82e130bc,49335279,2497b4a,34892fca,67dc3f2c) +,S(75f37d33,721293ee,5923b9b2,b95c958f,945e3f2,909c38f,3c3e7f5c,79b218c3,ac041f8e,c6b222a7,a2f28e18,1cf11aa2,a7d2fda1,1f402a33,9afdeace,a5928be7) +,S(cbc3173a,b58b2f29,20b3bef,6f18a84a,6004d1f7,1dd6c65,78571afb,96fb154e,c413a0b7,6f264414,2d3c166d,e9577ee1,b8f36ec9,618e8892,26de4de0,f9fd5c37) +,S(64e56b09,a139fa59,69688832,419cd1bd,64f212f4,5bf4cdd9,2a5e4370,dae226cc,a9194eee,f2429016,4b41eb3d,b429415,d10915a8,62a02fa7,671bc19e,50fbbbe) +,S(e33795c5,e2886cf2,9a22c2fb,8e02f913,34e13350,9cfc14f,73bcfb49,355285a6,7890fd21,f33d48c7,24e580cb,7b4bb065,f7c575d0,c6cdf5e1,5c2d6423,1afb304) +,S(7975e6b,7a73d0a0,d1543d2c,76c79233,6e6a0994,35eb7699,8f25ce75,a6b0b6dc,10b160ae,c68993ed,d5e48d5f,7562bc24,8f16eb10,a27f7115,121ce2f,f63eb06f) +,S(6d0d13cb,f9c13967,92e093d0,801f441b,c1ca4484,92ce3ce0,2ad71cdd,d1580f6f,17ae4238,84caf022,bbddcfe3,37a44309,4bdb25d4,71da56f1,bae4bf2c,ebb45746) +,S(2195f14a,23af2b59,c9fd3f90,42608037,60d39867,3fbd0856,a974a20,1bdf0154,fc05b38c,9a44ef01,f4db3a10,b500a372,5ff1aa58,86ff6111,da53ee14,f8136a8d) +,S(47679c73,60acf8b9,d1b54e16,7d1dd1a2,1f558288,3844fc4d,ac2a7fdf,8b713628,82a02225,f3b8e81d,e4d4bbde,94f7cd97,7ca0180a,ff3a4751,a93f6ca,17803ea7) +,S(b0bd02f5,1636a69b,23ffe514,cc2166bf,8cb4ff2e,2f7c8655,ac9aa7c9,de30831a,73fad62,48bacbc5,2a7ffc51,fbeba3d8,f4843b3f,ba6c8814,48add0d0,8fd5f518) +,S(dfaeffd6,bfe9f81f,ed3f81af,adbec5b8,aab5f15,23cb7452,c689b01,a3660158,3f54d105,c3ef4814,e6ca4bf9,ccb5b54f,30c4bf80,10d7b24d,f3b5f3da,c9240583) +,S(eb016abb,da661e49,8f53d2e7,96fd6be4,80dffae3,eb7e4ba7,46ae06b,f40d42ed,310d6dbb,aa7659a9,6cd4d50a,dc2e5e85,10f005ed,6d29d1f5,18bf83a2,7af895be) +,S(989e1bc4,3c0880b3,6d35b5eb,137f8e61,7263784c,d2f35173,e517afb0,c99fb2ed,4c4ceb5f,110cccc5,3a35963d,11df77d8,999b3bb4,c2cd92fe,b53b7476,9dfaa1d8) +,S(beb0170,be4a7bbf,1f65bd40,776d5efc,dd801d6f,909250bb,fbee1198,c2033811,1356b98a,1d329a38,57a99820,26d3ce6c,f52349d,fcc59644,ff4dcc13,8486461f) +,S(2d90bc1,986f9a4d,6f75e596,96c4296a,ea9bc55d,5b60d12e,337cb42a,ffc0b145,7d57cf64,734d1997,bf84b721,e67eafb6,b377ccbe,d2ef3b5b,48dc9f06,f71a0c4c) +,S(6b7a6a54,c9608062,de196848,dc3673bd,59fd53f3,fee72481,e829ca77,789f51bf,6a9ee208,157b8a69,f0879f30,c58afbe3,dd4dc42b,43cbf21a,5795224e,6c09af23) +,S(c99244c7,32cbdfe7,68df8fa8,7b7e7eeb,16faf0e8,8870fa8b,f4abcb68,368e8393,20ad1b55,53ba2ad2,40563453,b2dae2e8,58cc9b8c,c6a49951,bc0c0fc2,875620ae) +,S(553fc07b,402a8dc5,5f1cf4fc,609a01fd,350fef26,9c1f93f6,d2871f94,70f01b6b,3b518c75,39616def,fa7cd0dc,7d7d53ab,9b310217,7e470290,9c199137,34e5a824) +,S(c5930378,6ed8a7c,b3cdfc80,a34c85bb,721fa927,9492e369,a4e4bec0,c0fe2f69,3699e469,8a3e9129,3796dea6,213fd702,d7580e67,9f446300,1e1c7a53,3717c149) +,S(cb6f1118,f4d59964,b8f4613d,8c349d74,8cda0e7f,f1d11c6a,79dbecc8,911e7eb5,62b0ae88,98b0d5cf,723cc88f,48257c47,ca0fe3d,7de676f4,cf4835c8,fdde20ee) +,S(da2cab8f,8c26668d,d9722ae6,1decb99c,78b5d48c,966889a9,46fc522a,31a26db9,6a03377e,234f949,4a614cb7,c93b131,1808496b,12485ad8,fc21e1a7,6d0c7e98) +,S(fc6a4d42,3f9be3c7,fe337411,f03eef,fa595b83,9a6eca82,b228d5e6,b43b7d86,6c089544,eb8fbe1a,3dc78fdd,ac253fa8,27dfbd6e,269196f5,bb476865,a298beff) +,S(73c9a91a,b9c6e0d0,773258e8,3ca9460c,3d09fb49,9426fe09,db73756d,e3dee882,8b314327,efc0508a,d5a90259,c9ed876b,52040a10,45d06224,78cd635f,e571d2b3) +,S(a69f061,45b8cd1c,343e6127,14b80996,2bc02848,ae976762,933744ca,3b4516d3,87518d90,b4503741,ec16caf0,18615e27,96b6d91b,47f649ae,a86da209,d70ebe3d) +,S(1cbe4a25,70df40b7,1cddfb2a,c15ba441,376a430f,446a2572,fc95235f,28ed9691,12554ecc,f262e1aa,cf2a2d10,ab3953ee,c8ac69f3,99c5380b,6ef5d202,5613de85) +,S(8dea49c7,406dccfb,4305ac85,ba08b191,4ee2f11a,8827852f,d13c837d,b788e27d,c73d61a8,3b517c3e,bab8b15a,b7a0506c,2b6071e5,697b4056,d902957b,cfe9d9b0) +,S(de926377,b175cc3b,1ecab5af,81d38d6a,5e4b717d,55bc94f,6e4c43a4,86d0ade5,29d5f3e7,9169d974,d4289115,d8d4b8b1,6be387ac,e60d1cb9,73c387d5,17d0e11f) +,S(6e76eaa7,aeb37ab4,ab455a2f,3d525140,f6e8a9cc,5eb18fa3,8a9a25b0,d3b41497,7e3cc5a,78909d15,bbffb936,a47aabd9,44c40a3c,d690908a,89f193e4,95e066fa) +,S(37131ecf,22d57f0d,a662b03f,c9891f99,4678539d,37f5ff8f,9eed0f8,bc607574,c03b2d21,69d42968,f611d596,e173d4b9,281323aa,6abae6ac,c177a1c9,1249f3b3) +,S(72088814,82c89957,28e76633,bcdf0ebb,65155c8f,4979a4e7,66713f37,4a5d8152,6783c59f,8c0adc8b,da8e26f8,1990a00c,588a7974,b48aee92,d2a762e5,c974eedc) +,S(1b8263df,baca44b2,a7fa7a7a,dbf9d3ce,d4567fcd,144d9e8a,db712365,d3241864,1fc7e3e,24f01143,1944b98d,b2dac036,edf36680,80196785,783a41be,d788606d) +,S(7a372de,27ca7f2b,8199714d,bd583edf,ea41bae0,5a1313df,f1a8c260,cef5fd43,a0e3216b,b32c5785,b5c60f22,f5e4ed5,a5d3ab64,ba0eb2e2,916f1b9,b6281142) +,S(71815daa,55254491,c8bb9432,755ac1f0,c30f22fd,79d4232a,72bec0ea,8cd02300,8b341392,8de15c16,5fafcc68,84ebe3c0,3ade0918,4c463804,876f1600,c76471b4) +,S(1a54b7a,d3cfcc64,b62d866a,9f2056e,5535d4c,12c89c78,5d1c5c53,ff654d2b,b7c77ae3,9f4b87bd,22c77395,a91ec307,e9f5aef9,dd2892e8,41d8390b,47a12f19) +,S(85cb4457,1fc973e5,dcb0b695,3d75a2ec,22cd2820,74039987,7262b7ed,999c44a6,efdd1df3,bd13fe66,c0d4ef02,8e142093,58037a7a,bd06ed53,280d3318,9d0f6aa5) +,S(98e8649c,64a010c9,424b305a,2407a36a,cd72df8e,138df962,c35bdf75,fcfd4e4e,a804c569,34395d7c,549f7770,4c3faed1,624a8cf6,fcce08ef,cd3aa486,d5a6c60b) +,S(1eac47e6,a297e5a8,8f433895,874fac8b,5019a164,69c6a881,7e500b94,74a5a72b,8b7daa6b,784ddeae,f380bb1f,fe64b9ed,43a10a2,95c30325,f519e4ae,da11105) +,S(f079ac65,91f27363,17e9e0ab,6a723e25,e29950c7,a02a66bc,96c4ae68,44f42f5,ea87d1bf,c99f4374,4acc3ca0,214a1ef7,490186d0,3d924562,24981469,c432dfc5) +,S(d6d09d79,bf1f30e0,f011c3ad,a077b1d8,fa0d94e8,8683186e,ba471caa,32539643,8770bc64,fac8f541,f730494d,cdad2d48,ef510037,466bc049,876f5cc9,7caa8adf) +,S(376e4bd9,f8963368,7059565,68313f89,d6416ca6,b1e4e91e,3aff3ba0,b8351f65,ba436de5,67248f1d,5e99e8b9,6447cb28,497deea,47fae95b,78a5378d,e65f13f1) +,S(270f3a18,4b42c799,a2193dae,c96f834c,b17cb53,bba1610c,6578c741,b9f20d7,ccceb12b,9ab98bbb,a0fb0d0,1673377e,3a7054a9,f4a3b000,21b67328,57e7e5bc) +,S(ae271b64,1a1e5348,29e47a8a,93b496d0,b055d2b7,fa98ade2,f505a5d,ec1a599,14e9552f,39b481f2,522a9a23,f87afa9d,5847908a,53c1581e,45dfb244,7fc2bdd3) +,S(569eacfb,177d8a74,a9288ad6,4ee5390e,db36a93a,943fd6a2,5ec869b5,a7f28c8c,1cf62c32,9127642b,99a7508a,a6f4f136,bfda9af5,45f52844,cb9c71b,5f732f7c) +,S(77c7f27f,fdc4e7ba,a326a246,89790f8c,41bfb5ed,6d365e46,f277cf81,5f15b558,4d3440dc,138be5d9,566a6828,852c2ec0,e0f970eb,4501a43,25af933b,821c3007) +,S(d66292db,f1730306,a87f67e9,b044fef9,7d46761e,7b8301ed,132ed7d8,94adbb25,ceef7755,8ceca4ed,92145f23,8bfcb32b,3d36db14,6fc50209,cb0e58f6,2c8b83c5) +,S(1c42832e,12ea6f44,b77927ef,7ebb1f3,8769e3bb,f5507a49,25e8565e,a77ed0d6,8b9383a4,b31b4f5d,a717917d,9e1e41da,786a62a3,327be11e,280e538a,9c29d5ee) +,S(63e57eff,942262a8,cc362911,fb98cf30,60832435,3cd394cc,5d6abf77,b21f7968,9e3c1e2d,fb9083f2,4c344e7d,322ea530,146062e2,a25fb6b0,4502ea35,59b009be) +,S(be233fa1,86f38a5c,72c88e59,19094ea8,cf3ed3a9,b4ea3f9b,2a51489,97b83c90,402eb2b3,362fadb2,6e389ef9,edc537bd,40bd48ea,6296956f,efd19d0d,eddba564) +,S(636ddb80,4e7c74fa,9c5f4d06,5a730fce,f2cc6956,4a24b579,aaa0c3f1,61844b78,6a4a3569,583212c6,22feb59,897eac8a,6aa31ffb,916262e7,deef47eb,e6a2496c) +,S(d251c1d1,7250d87f,f7b5af1e,ee2f2566,215ae7c2,b6e69e60,5bdd6c2c,dee1c5e7,245accf5,7df52fa8,cab5c986,2b96658c,5de60d06,c84584cb,f554b518,7fb4ae78) +,S(405d4cb8,c62f133b,7051cbe0,54b06f42,9055f917,3ba8248c,c3bdc744,198ed407,8463df10,a8963cb4,298e8031,bd2bc3ed,523553fc,60746720,1a9abba7,305deb54) +,S(97f05aee,9ab33a07,e14a0314,4fda5be4,ab329394,1ce8f003,546ed8e3,9be983b8,59e62a26,7fd9138b,c4c70b15,533782cb,d321f120,1e3d1a7c,3be4ad5b,eb849261) +,S(3388161,18e125c0,6a9060f2,6b9ad691,c99fdf8d,4309553d,ea160749,eb91ac8,583e918b,5b8e1a68,c053af0d,245a9902,a571788f,dbdc0c88,7281767d,9404384b) +,S(ddd20c46,6bbe6a25,9f706b1a,ddc3b607,8cf65366,3369fc31,dc8f7fd3,3d17a9f9,b2df7b29,b4ea9868,bbaadcf4,6621ccf1,7833e159,acb43daa,7cf78e89,c1de5a99) +,S(923c6d2f,71ae0ee5,596c26bc,31389cbc,eecd0712,e8df91cf,dfe00172,3bdfc9f7,6fdb28ad,27c41243,6a41ae96,99a03d40,5ff2ed87,3207f082,414a4370,34be948) +,S(6d42a6bd,28d57e87,66a12461,b8a7d111,a448876c,149071a7,fde9df18,dca09e65,4df07ab8,1dbe97c,3585554d,f0226234,dcdd2826,747f2775,640bed6b,95fd28bf) +,S(7fd42961,59f9f259,d3c3610d,8539ece1,70efe104,31c9a3f0,4b9630ec,21d761ae,fd695441,b8ce2bf5,1037d00c,4d50e640,e85b6001,6d5d26dc,787f1df1,25d7e280) +,S(48c1050b,128d97df,e7900a01,70559990,944045dd,f408d8a7,5b59bb25,ea6770b5,8f7ceda0,4b6e319c,1cc61b31,53538a09,d450e49f,8863061e,f9b017c1,6cf66559) +,S(54462d9d,a12d62dc,96abaa1b,4883c67c,b3214c40,de5a4a09,689658f7,dee2a686,7673ad6f,916011d7,fd33bb5,eee819e,6a3f0016,d51ae37,bcfec2e,59ccd957) +,S(698534c4,e4e11d89,82a5a46e,44b771f0,95c5fe47,54d7a261,44373982,1e6435e8,36d602ac,b2720c71,8d619a8a,5e7d6873,9faba099,f71c1137,6a8f41d4,e1cbba18) +,S(4493f759,51c681c3,bb376b0d,7c88ecd9,d0bc2a21,26fd341a,d8c4832a,be77ecc,e553e21d,d4d99aad,97f15857,4bfd54be,df7143f4,e829c12a,39109892,c120351e) +,S(b054daa9,330080e1,89784cf5,f917c024,6c06325e,687e6ec8,cf8be248,ccf8313b,51f04715,5c9ce55a,c755f2a4,602420d,4ed52a5a,1dee9a83,b0688b1d,b767d866) +,S(4b4272a4,fa996b1f,9ffe6796,e6519db2,c1f8cfc9,606fbc57,1fe03713,c029583e,9526f2d0,dce7c53d,5cb36f8c,fcbc517b,cecde833,4384d10c,f5fc80a6,ff0edb83) +,S(d61eb681,c69de82e,caed8e64,7d1a3948,6cf63f83,f1f04bff,46a04aa3,63e29604,9b5a92fb,156d7b8f,37c6d9a4,30ae28eb,f62fdf5d,5bf441df,aa386259,721f08b8) +,S(bf8f002,57f979c0,9f973c8f,3dc15eb8,8349e340,efd8d57d,5763e4e0,c2bf507f,561d862f,1041e670,fdc265a8,36d363a3,43346739,f4f177d9,f66414a0,820614fe) +,S(63b254e2,a7a6fad6,4d9ca03f,7293a86f,b471fd45,51ec72d5,eb03e289,774cb498,f4145111,3a4ce922,dc7b3819,a2de49cd,f5be7d53,6befd880,837bbe7,51948c8b) +,S(bae6facd,e1da6ed8,63491f33,c4c9efe7,50fdd908,6b93c09a,e0418a29,d3968725,7c7dc955,e483176,f6bdf74c,6654e6a2,e4ca46c5,2526349b,b4d66090,6ea30533) +,S(f56285f8,ea15aa08,f3ed8139,59c660b0,d30a6317,5380429b,59584623,aceb34af,110033c1,a202194a,40703c9d,ea2dcb9a,d9a0f6da,7b99b8ee,31eb1ce9,55a9eb9) +,S(876c7c95,3de3d451,edb9191c,60e8e36a,eafbad2,198ec6a5,40d72633,8151d87a,95efff74,72ce0c6c,4010d17,7e52a859,cf55011d,1005bd27,df54e25e,972279b8) +,S(e956c7ed,77c7bd5,68096902,4ab1c758,a024d86d,ba3f30e3,fbfd83ac,940a6d30,1b5dfca6,f0d19ab7,7a57a9da,259a564a,5aa5759,ce6826b,45c71771,7aad9da) +,S(f53fde61,abdb4543,1456e9c0,65048cd7,ab743b5a,81a468bd,8fe2ffaa,99dd3f16,1d28b539,47ea22b5,178e86b,ab3561bd,a65ac78e,e0e2a6bc,1a26b64e,d790222f) +,S(b91a8681,52eb435d,475b9103,936a7c62,5e49b0b4,f7bcc3b5,f5d36449,c8043ad9,c758d17,56939bc0,61696f3d,11dd1bd5,722dc90d,1e8be88b,b3430062,a13aaa75) +,S(5a87bc70,23e32927,db4c55d0,abc97536,61f5adcb,b24c2897,b16f08cf,8d8f8cc7,9ceaae4b,aa6a0d5c,46d2120,fbff74b4,9d1ac32d,88a89b2c,3d2aa6e0,6f731e54) +,S(ac0b1b43,e54eb354,3bca80b9,efc5cdb1,215622a8,66b66e80,de979f79,71ceb034,a891575e,5731e152,17bc2b87,197da9b5,439477fb,d2bf07f6,9bd13f3,f4638d8d) +,S(d3c41ebc,2017cd82,76f4d6f3,f6ba2370,e84f1949,df3abdc1,45073467,e85ca915,52ab1d52,8be55945,1f6b1e91,610fcf35,bc1e9576,3ba3ece6,9da5e4d,8cdcf7b7) +,S(68cffc57,f4c82cc6,f7900d00,fe1b0f36,ab842e4f,49ee9063,4d1ebe95,47923b02,729955bf,aac10741,c3fda281,c18a306b,367ba904,baed26b2,6fe6a485,9ab1d8e2) +,S(7e0f58e1,246299ee,e08566b3,35324a66,579dc765,343f874c,d30f2553,8c177d9c,39652583,587293f0,809af7b,5d366740,86b9015,6a05928d,cd340196,8821447c) +,S(c72abbdb,d1816498,eb53d4bf,1b325fd6,5dc45086,73257bbb,97a15eb8,e4c9b542,3c8fafa5,5df5f3d2,88441ed3,e46cd318,841a068c,b681b782,88e77afb,2b25a7b9) +,S(74747f5d,3eb09144,1f64d76c,ef690378,943654ca,73fe15a1,b720abb5,d2363d0d,12c6724,bc7e8f7,321f993a,5caf0547,bf54c1a6,41f959b9,746fad7c,1c443649) +,S(f2a702d1,ab1de7c4,34cb5d71,dad689a9,29db862c,d1fb06e1,212ffc8f,91b67067,5b91e2c,c730ac9a,cb7452bc,7fb4dcfb,1d5ec11a,bd146429,62c7bd16,37afd854) +,S(a92d4f08,14e76b46,5fda87b6,201c46e8,c2535b3d,4be91e1b,530b5634,d00d9340,4d829a8f,3c02fb40,569fd9bf,e754dad8,38d96dbc,2350f0be,6f4ba065,5cd0277) +,S(79e30cb1,ac06c3b3,f90ea320,60a80fba,df5ea142,84a15746,2aaf917a,26f205a1,ad220a0a,81459495,5ac8a79e,d0cba974,7f17364a,9f6168d5,3521f276,c8d5c82f) +,S(6d55dc53,d412577f,463252b,e240fa32,88c8d6a3,babd6ff3,20231b6,8c9401d1,83a41c96,aa3b32c0,59155345,2679f056,c98e17c8,a0a5e154,d732fd3,7b006eb3) +,S(cf9c9f1f,604eb909,b37ea5eb,4cb8a0c2,11ef14e2,d3e2f48,7c83b56a,49b3f20a,2b90b9f6,4e649988,77260b5b,ecb441de,da24eaf9,df56ff93,dd3d1c8b,a247dff8) +,S(60d4299f,29ed994a,b3367780,9ef6fcac,e30f435b,ba9a8346,a2fd925e,186b35dd,df69b88,b8aab4c5,8ff86ddd,2d8e424b,40d51a4,9d189437,37b23695,4760331e) +,S(d93a6edd,1b674a60,6b6bbb85,4114a3bf,7de3be59,82cd2122,887c5376,d9493540,87da37d7,dc79197b,c0159006,4f921ae7,acfdb08c,447ed230,423c51bf,f9e5f7ff) +,S(cf8c3d37,7e108d98,b72bb6b3,1cb7b5f5,fd5869da,1a06fc60,25d9191a,bd652962,6f5cd02,bb96ad02,db42b034,321b3cae,fc54271a,879edc93,afc9c8b1,34128fbb) +,S(6ca99247,4637ecf9,827ab65a,c7b9ca0c,715b9048,f24c42a6,90847e68,8cdf29eb,51378da5,fefa454e,d96a446e,dab57c3e,8bb6160d,d015c1f6,d93983e4,feb55439) +,S(6f7d2c04,3cb813d5,dea67758,cacf2e3f,3cc3064d,7b9f08c5,58ed686d,28d17afd,4794e278,13ecec48,33f9106c,17c5e161,b590a5f2,ac293c8,c65a6cc6,5233bc6f) +,S(f8aee0d0,bc9883f,ab6a82b0,184e9199,e818d01a,7d99f475,d2ca8a24,e924f3e1,acf9cb2b,69135df0,9426bfa,c6b1b3de,44f1055e,5cd21b8a,b526f34a,839442b5) +,S(8b00fcbf,c1a203f4,4bf123fc,7f4c91c1,a85c8ea,e9187f9d,22242b46,ce781c,61e9e58a,3e81e690,ec026428,ee5442a,a8de699,dadfbcac,478985cc,89d35bc9) +,S(fbacbb07,8e84a2b2,c201ebbc,1cc3212c,a7278523,e984bc1a,b0eb7fa1,39d6dd4d,2c6c9dd6,f5eb0899,797df675,ccbbaa25,4e557d5f,d16c6083,3aa84a7e,4c3a0f52) +,S(1556875c,2f32f053,8d28f993,53ba2804,5ba601bb,3df8a175,bfa33dac,ac5c0611,53623050,c3da9464,8e9fb540,5888e387,d2eb783a,10e45cf8,ebaafe84,a4e240b7) +,S(b602b095,7f5b5e98,ce3e690e,c683f803,49a8ced0,5985f79e,2e972bb0,2d93d77,78868390,ddd6b821,e30046ac,b1bb7b31,ff358838,af5b89d9,60d39b4e,85435227) +,S(2a110165,23a5244e,89d66f8,a06f0553,7a846216,75fe4377,24f51501,da2dd17a,24d3b525,e1ca62e9,b02de498,30737f3a,b881d078,7d2c2bff,938c53a1,b8825159) +,S(7314759,1148f9a9,ce326a8e,4f43d2d9,a13edb92,56fc9d38,35a35da6,457efce0,b195cc94,80d0aa04,d3ac7cfa,45766472,1ad5adf0,3060b790,c7fb0ff7,77b2d8b3) +,S(a36e4fe4,c7e23d7,16362979,c5a9d8e0,525d864,37d96e3d,b2f45edd,b36206fc,56ace785,a428db4,a8a70de8,708339a4,346699f,697a6707,c745635e,66844751) +,S(97864be7,a2c54118,5d61b61d,5a2494f4,85b877d7,e8864402,3444d778,f43cac9a,43332a78,a85b8391,551dcd90,e93e71c,3a6c5428,71b980ab,138eda2,b9f2ff69) +,S(34a52dbf,2449eea6,da2c92c8,45dcd47f,daa7ca41,5ff02458,b74eb996,8519893e,add41829,900f26c9,f7ba8d55,21f3bb23,b3545a35,699d41b9,4270547f,e303ece4) +,S(e250aba9,94eea617,5fb7b2b4,8631f5bb,d8bdbbb,799f6fcf,5afde8a6,2ff3d629,803f34f5,9db0fa86,bcb6fae,689530fa,2e92c4ec,bff1757,409bd836,8143b0ea) +,S(18356a6d,b5946e2,1149347a,4558e116,7953042e,e3b2a372,869ae29,b871ae00,56ef0971,6b176f81,e1f98ec8,dca127c4,ba6de23,ba8c1f08,f19e9abb,995385cb) +,S(35a8ebf5,e5306084,365ef3f,30c29e56,ca5932d6,f73d688e,ed3cf2a9,10205533,9eae5d95,42954de,23d41032,5ada759e,20d30fd5,c2d058c4,53a18520,7f259958) +,S(37e06f5,25ea8fe9,ea862b92,53a965f,7b3dbe90,9ca487bd,a705041f,e6a4e1b9,83919fd3,5e489bea,23f13b60,41a19940,3f2f6568,fdcf60d7,3f57fb6,1fceb97c) +,S(abbbe697,ac6c002f,11062947,6e4a6ffd,48316646,718d8713,1a4dec19,5e131c27,b2c926cb,9d5122ff,7f8d8a24,a20eaf4e,fd704944,9aa48300,92971572,b12f9dcb) +,S(4df36acb,1484dcc3,f7c29c8b,78915315,5a1a3636,aeaca043,68a585a4,69b05878,fe16fe6f,c08af026,3fc417fb,19564534,aa059f4b,b7fced09,d4fc20de,6a41c41d) +,S(5ff14ee3,10256a0a,889570e5,ebdaf6af,c8f49c60,dc7c4731,23a7d29b,e799d0d7,96ff1538,55eb2fac,8f2a923e,ead9851a,95382d6c,56cfd0d8,9891d2bc,f7e65d7b) +,S(16a12c52,c1d422f4,791281a1,b7ab7186,a24dbac8,36af6810,4f62dea2,855d119a,7a6ef272,f67356de,46996cb3,8bbaaba9,d36a4bf4,60e3b2a,b3a81723,24c17478) +,S(8f4c9c33,83688920,a48b3d15,4fd567e4,5fcdbac,bea44eda,60600ffa,a1489ef5,2bb5bc4d,e06444c7,b2bc0082,d629e2e5,a4b0abd4,8cbb9b4e,37d564ca,db885717) +,S(498bf39b,7547010,854ca399,e50399ca,19236d2f,d05f5777,6abd6d2a,aab83310,8e2debff,cb58e36,bcc7beb5,8a45d4ba,b5edcd46,2c355d0c,4dde51a6,6afd691c) +,S(78147e0a,2978d396,b22247d1,74958336,2ba51d90,11e89c11,71e6e136,eefb5996,a66b7b0c,a73b661b,e71bf0fb,2eb4410c,4c75bff5,b8b05fd4,1d830d27,ff85989) +,S(351298d9,fb236c7e,5477aea1,d2df0048,47e112a2,e16adf66,3f4d77dd,828d4927,6c9c91af,8b6f23a9,d15c3884,e618ae51,241094d4,5878ff20,67f2ac81,dcfe00f9) +,S(fb5ffc0c,88fb609c,24cffc14,848549ad,c1814668,9e5f8a67,a342bcbe,16399d10,a995e13f,9ced94cb,90feff32,8e92e978,88cf5791,c885ca09,46f46e5f,b8229ab3) +,S(8352b7c4,4cc09c5d,717bd197,40dcaaa0,89565e94,77cd76b3,6c7a4fa0,4832097b,9507c998,fa25d9,758ca78,6774ae68,f91c8fab,694c5e23,6f8af6c7,7d0fe6bc) +,S(1be65c0f,273a2746,d6d014d7,6bb1c595,5d5ed1db,62ad940b,d8204115,85919f4a,dac98f30,2a38f839,a3d470a8,3ef83ae8,f044e93c,80b23552,da3da359,5c09a3f2) +,S(7107f3a5,2f4be227,eeb65037,ae800f64,8de14d89,ebf743a7,ed65f98c,b58418e,bfcf1c09,bd1af327,d14e429d,18eeae45,927b2df2,aa15ce60,69f6a74a,69fca7a4) +,S(117284b,e8edae5b,1ce54a13,3b1f9d98,983389cc,a4ccff,9dd04973,97312e3e,91e48c1e,724fed49,8bf51999,4c84d0b8,84e3af77,86e61539,638b45c3,8212b03d) +,S(a08d86de,b1ff9ab4,651f1cd0,d89b6714,41c243b6,c7e655de,d31b44a7,b00de54e,4d0fe7f6,344d39d1,57764fee,f74cc949,a72ed8d4,c2dbc12c,ec2629c,830f0d2f) +,S(9c44c1ce,df67418a,eef2cbf3,68d48a08,98cfc633,de711550,3f78ecb5,a4e8c25f,3cda2020,86d3f096,31da959b,9f9870c3,de3d3c6d,e4c1b35f,81f64dbe,31e743fa) +,S(d933e475,5215c065,bab118da,6f24d714,f8597949,a52ae319,250338b2,2339f149,5fb0f28e,313af04d,de3abfa6,4981287,e277e39,d2f19dcb,547d6fc,88baec45) +,S(7fe1f197,ddd0532c,a2010528,9f243bc6,4c2f9e53,65aad5ff,63c0f1d3,188a42cb,813b133f,a1869218,ee361828,6561e75d,a9ec6bac,6ba2ac7c,d3f5678f,fe472af7) +,S(e3568521,89612102,7ad0789c,72dc6d57,7ba412ae,b3d7551a,96aab952,c507f79c,7645c505,8e2ca8ac,ae5fe225,eddf4d45,7d820114,cd5e69a8,4966465a,423e3a30) +,S(c56afd46,8a5644a2,abebcefc,3b6a9da0,c667a183,b822780d,146ecf82,b6ebece4,9e41c655,a80e2844,89fc587c,b686549a,2915ba14,1c691e75,cc635f9,54f1a8d4) +,S(b242eb39,60e6a8f0,73b6042e,1095f0e1,440f9f8f,d1abed56,ad1f26,a1589345,944da76d,f063f0a0,3602decb,696f2a34,378579ad,e8469ca4,bb5041e5,876dfde0) +,S(3a52fd66,6d2e2e2e,888a43f2,fce68703,78f835a6,b5c3bd42,af57b107,323bb827,12e51177,a7b37a46,2755cea0,18f4f29e,96c7d6,d0e434cc,4874da99,a7af91c7) +,S(b77d5615,c8831ad1,147072d2,598a8c6b,4a71c0fe,967a6cf,70877aea,24d28f53,25d5b7cf,a068a665,deadf83d,5f793605,f5cff2c3,36a8d176,d18c634,9ebf3132) +,S(e4420c3b,61e435a8,53784728,8426aa27,f23d224f,4ff7a14d,79898369,c08530dc,422b04b4,857984b9,9bebd74e,1588ad96,9b3c67a9,89b119a7,f7cd2c84,ecca8572) +,S(888bfdbf,c6ab299e,3ba0fadd,a614fb01,236e3c44,98ad07ce,cae08105,630aaaea,86e7253d,58cfe580,628fb94a,a1a8f40b,7ada97c9,d8713453,f06f4773,3770eb3c) +,S(f74d258b,f7d78b30,ddbde398,a1398164,d850f2d,48616cce,8ef4c436,10ef419c,d13d49af,1e6dadfc,94332213,cbb12d32,5d60eb6,d48cec9d,fcaa7ff2,53029204) +,S(a8b33e90,98d60483,a7009786,11b92257,65cea0d4,b7ac0ae0,67914110,5cda6df0,58cc238c,c08d957b,1172598e,96ff4762,1182b6c0,652c9ddc,650f3b51,3521c553) +,S(5af8b154,7477fad9,8e5dbbe3,d4a1a15e,7a4a6cb6,5ae13cb8,9699470a,1a3ef1ff,525ed201,d0c61832,36c8fac1,366e8173,3c0a8c15,b6ef7672,cc84b1a3,7d6f25bf) +,S(155c454,6d4c5c4a,21d14383,3df8662a,fa71e665,ab7ff0bc,8119f29e,3bec21c,20e99f67,2f641185,cdceaefe,8fd7247f,63842282,edeff6d0,378966bf,50411aae) +,S(53918586,ee182d66,e7c22aea,5a663770,c8fd7f0c,6738d473,1010660c,7425a56e,c7fea092,3052ec1d,7e2564a1,e70b8924,cdbf727a,7212052f,abc58d9d,1856152e) +,S(f7964dd9,a0fab716,74804abb,a7740f4d,cc52d7f2,8d5acd4f,67998bba,3bad6414,6a989f64,aba0f60c,e7bdc5c2,aec11de6,d469a122,f1bbfccb,31cac834,89f62c59) +,S(741c8c8a,f514f2de,7880a909,b327c6ee,ffd72ee2,b5b1658e,72059edb,cd663183,f35d276d,e5de1460,dc53532d,48afe736,e40b6b31,fb6fdb49,1224544,a487b2ae) +,S(de8c69bf,6cc2a28a,fc6ea9f1,26ef4f22,606e55f1,312177e9,b2ef8835,8b47945a,8de62853,6900d614,780e2fec,b4ff7066,70d84742,3b1c852c,8b85ca4b,40a48a02) +,S(81e16f39,619bb41c,d8a523b2,d3dd0135,d6a8d5fd,9a8446af,cd058ea3,6f57c537,6786fc73,7cd2ecca,d146de9b,951deec4,375c434d,7dbac32f,2395c265,bbf4b31e) +,S(459e9589,d079b22e,8c5625b8,a725b30a,e70f7f04,8ab21a20,f0123aae,7a6f988d,a56ede93,5b71a292,c4ad26ac,cc3506cc,915de21a,4557512e,e767e8c4,33f38e08) +,S(b079d755,4faba7ff,20818806,a70b4ead,f2e5bb51,d1abb758,2284f385,868ebddd,495ddc2d,552f174b,210f6577,3e434fa9,20b6c0c4,574601dc,fcf5b701,fe74dffe) +,S(75391bbb,5983fb21,41580de1,dd5b10b4,bb30af17,3f05c100,569abd2c,674f288b,57c7a6ba,c9154ab9,eb66032f,2135a52a,b319f534,d1f1c80d,b58a4af7,de958d67) +,S(71436957,f2848f75,fc461069,e4fc691f,5bda94f7,32fcbe7d,5a89e136,41524db4,1287f852,ef4fadd5,65a2813c,51b93c81,95658a5a,5cef224f,e92511db,df3f0007) +,S(b9038b33,fa75d097,dcc74c9,e25970ec,94ad076b,7279f785,3b7c98f1,41543f9c,a28c3169,69295ed0,3fbc1bf4,8e39c8d6,af59cef3,d6f66660,73470ab0,dbcf838e) +,S(b2c63c28,a9fbd900,fbc664e6,36dbe0cb,f259bdb9,d67c34b0,83b8af17,a5f86196,a8f050fc,69c63c4,67308421,89510ca5,b7920723,6f5c12b0,ee7103ee,cd49ebdd) +,S(cdd2a5be,a32b2195,f4a7edfa,dfb7c785,d06bf346,f38e928a,5c92cc7a,2417f39c,ab66e78,ac421c36,3203ee7,22b380ae,2133864c,83829f04,d2daddd6,b7fa621b) +,S(825d0864,b079a737,acef03a8,28838ec5,a27d740c,724f9c39,780cfa61,9f3db80f,bf3ee8b7,749e44a6,7f27e427,fe05eba5,c2154fad,bc2e2b43,a877219b,461071d3) +,S(37b79e3c,bf6bf402,c96930a8,79f4ce3d,d0c36477,f0b0e218,608b890f,bf5e24c7,d97142c7,cec5630b,a090ff4c,9213c2f0,c32a5bb2,f7b0ee29,2045ad03,10f66f1d) +,S(fba64ad0,678ea75d,409105bf,5b452ebf,89560b0e,fbb079d8,aed22c33,552b6135,e665362d,e4e637a8,a85dd844,1a806ad7,5c628f19,7d6dbe3b,df63c0b2,d1f938c) +,S(76787b8e,77ed36f,9d84897d,e84c476f,d3bd490d,184327a8,59ea3f97,ecd9cf72,cf79f14,1a3f38c3,cc126011,d1d78dfc,e3ba228b,33d64158,210cd942,3980a9b3) +,S(26babdd0,ffb3a334,85e6ba1c,5661a551,f16a129e,42f9fe8a,3691a50d,157b31,1b3a4ae2,b1cf1a46,fb666e33,a20370b2,e66a6c71,27edc8ee,e4c4072d,8c2c530d) +,S(15aedbb7,7a2fa1e9,7a6aa864,7729f28,7ca4d3f2,36046008,c1b031d6,9f76307a,3342a142,bf8b2360,6a574643,9c05f36b,f9408878,5354c788,a6dcfd96,ff073649) +,S(98ece0a3,9bb7cd4f,df4d5767,c6ef4cc1,c2b072a0,dfde5fb3,de100f57,466fe467,c4e924a8,218c93e7,eb829d0f,839556c6,1e679d29,6a0a6bba,6f4f463e,ab227e28) +,S(7d867505,fc213eed,4cdffafa,b067bb71,8a48cda2,fb323304,1989b6a8,3ff373a9,5df51ff0,3c212078,197c417e,f4a4014c,96e167f8,8cea0c1b,9199ef75,7c97d47c) +,S(f24f19d7,43578e1f,be3ece8b,7b00d5e2,bf269a48,9d76d17f,410b73a2,95b3001f,644a43ff,55448b66,7b048bbb,b34f4c79,16d2b547,5148020d,53e53627,623631f) +,S(93853304,5c22296e,1e911281,ed4bea22,1fd1061d,2039a27b,923dd3bc,800efd59,22988cf6,cd2d15,f799bbf,e4cc905e,2607da21,e9fad162,8c2fe699,8beb7040) +,S(f090c705,39834f16,253b14ee,8e4d2685,b91ff4ec,9897df0d,af1531c9,46319743,c1171885,1d30271d,a8a08391,f53a02b6,28c59c8c,9af3ad2a,bf158341,280bd522) +,S(e8fc8ec,ab5bf3b7,4a0234ae,b2a8eafc,df9bb08,a90078e6,7fb6cd3e,fea78c6e,b08165,34ce9bb7,46efcd71,362e0a75,a8397c0b,490e75c2,9b007b28,26ddabe5) +,S(46258cd1,87cb43e7,3003cef6,94af37e3,c7426dba,c8033aa0,9b0a0d71,9f126785,846141a7,5f060822,764dd82e,2c369821,75576ebf,7082c6d4,601ad237,55ad4fc4) +,S(e7f38b3b,db3887ef,529d27c3,f433410b,94109bf3,45f9b7a1,e65bee6a,cca3e430,f52440f1,5eaec702,90adec0c,b07e8ac,ab1fafb7,adbc8f81,9fac349,2acd589f) +,S(2d29e833,1472798d,75fd5b75,1f569da,fa9a0167,f73fc62e,da5b03a5,2f537aec,52d3dd1a,b117b9fa,a17c58cf,c0593603,d9e2f55f,5a230001,d18976e9,792d2be6) +,S(a3b2ec9c,abf7a7b7,77fb44c9,c7552dd8,f47609a4,6f943c7c,8ac97d1c,3891ffb6,6ce38c70,f091381f,53093385,22a5ad66,4d528061,5b01b417,d559cbbf,3cfc19de) +,S(afcb3c1e,7582a56c,e6504dd,ab3d1a8e,6cefe762,58543015,a21f65d3,3100f473,6baf1f9d,fbeb8499,8a6afc61,8e193103,67edbd87,57b2c4a3,8e5a76c6,8b171af8) +,S(88b2f212,dc899567,bf62bbea,9466a8c2,6650f74a,490b86ec,cdd35625,d90e2ac8,73fd757b,def6153f,d7f6d4f5,da1723e2,6ecd6c42,d994a08e,7e458a64,d18c30a5) +,S(bfdea9f,4ca32916,651c971d,7da6a2a7,395c5945,5c4940d4,93d991be,1dadef3c,82747044,7ef3f684,4200adea,5b8077cc,4166bc65,1f6d4a17,578b64d8,21bc20d8) +,S(5d45cb81,aa765d69,ca52e386,9491ecf0,e8fdf6a6,3d64e65b,5213647e,e4973ae5,a4a4a32b,51a76d77,773517e7,c103a7dc,fdab36fe,3cafa2bd,b17f82b1,2fd019db) +,S(f3a503ce,e14e9994,aa34fa53,1c43e5db,6d6fe092,45d2f3ae,87d06753,7ae7109d,2b1714c0,a24d50b4,20722daa,d1951b63,568aa5ba,7325785,ac555e55,f3ec49e8) +,S(94c3a76d,6f812ed2,454c225e,ab8e6b8a,4261953,37d1d2d9,b666ade3,88cbeeb5,bb89cee6,aa406746,dd4893b9,5bf1818a,3d1351fa,d66e104c,bc8d63a1,efa953e3) +,S(23dbfe81,5232403,39d5a662,51fda5bd,b9a2d3d1,181dea3c,c0c908c8,f0f4c050,caef3a71,229f10ef,488f8385,c79ed0e4,b5c16899,d40ab679,4e45b84b,4deae6b2) +,S(3907e3d1,20ef8619,c11dc69d,c57935f5,d2dcbeca,1b4bbb88,e4629ec6,acbbf1d2,438f96b7,d74e2b9d,cc17b0a6,c936844,e6aad1bc,58a20055,ba298446,1415e853) +,S(c140b19,3eeb04fd,80aa6a37,3407f591,651c944b,33788b71,e6f05e1,672b7d9c,949bfd15,59e24543,9d5fef6b,70763b63,899450ef,430d2e64,1f7077b9,29e44072) +,S(977cf05b,c96a39c8,1dd2fe26,930f75e4,2563c3b6,b06e28d1,740a547e,f2ea56c,3802e3a,8508164c,36e95e23,46ca468b,7e15878,36a9edc0,e70c0e6b,9aa10d52) +,S(1069c0d6,3995e0d4,cad51e5a,9e4e57f6,795a7bb3,9ee3c376,1e827b20,d8a034e3,e1aa1487,9c0e4c65,581d89c4,7abb5e48,47963aac,788fe804,1d2c194c,5a7fe33b) +,S(ff78c680,c3414181,ff3ab10c,74e2a755,42419af5,3527a45b,ba3825b3,c93e3682,eeb70adb,f05390f3,76b2382e,20b2dbed,86c8c574,df2f256e,1fc4a376,24d3615e) +,S(5ec9eb03,3acd3d6a,9c04c3ff,5838a6a0,2b0cb26b,d5c37d05,9056afd9,86bcddc7,92a287f6,eed0df0,17c0bed1,ed9445c3,e39d92b4,8c3a9c8b,9ae26749,732aff03) +,S(eaa206ba,792dd34b,7ee67e14,d8dbc7e8,bef0a54d,a7dc7ee9,339d8ec8,471b37d1,5577e65e,be719ca0,7fef2530,c40c1617,55e00d21,1d78e5e2,695107c6,8d1ee92e) +,S(26d062f5,6034012a,3d76789d,455cefa2,689ef08e,d3d87f54,af952afd,ceb3ed7,5eff1dac,ef6f5877,99c340c5,f0d1f6dd,dbe6faa2,5ace9109,4e7b5836,d1323424) +,S(800d415a,e50db62a,4f49e449,d11eda8e,1a2413f9,c341bbd1,492f2271,1e602d48,569cad6d,5d19b5d,2299ec5c,fd12d9f3,d5c8cb0e,756036fb,dc5957f5,7c02eb50) +,S(6c01a352,bc16dc19,973aaca5,f1a21676,e1531fbe,f8586bb,9853c627,9c9a1c90,833dd742,c9596a0f,2767226a,b2548139,a39a17d2,d64d6765,4c073b18,f8cc04e7) +,S(3accc922,f1b3ff0c,504e7c4d,4738d1ad,f0b914b8,d08ef8e8,a54e431,37742c26,aa9cd483,27d60b34,304dee26,c52b2979,52a2d118,82e10b17,86a09acb,3cb0ad7) +,S(a0df5c72,828b73f2,a380f75,3f8e6352,f8d978c1,ee6ebedf,2ec70ff1,d0f8ec72,b230adbe,f1e0bd13,1e622689,379e7232,b1327db6,eb0ee306,80d7a89f,a4ac6670) +,S(9d5f0d94,9776ec98,607a8dbb,d54865c6,d4bbc970,d3ff85a4,49d57b97,33b52c73,ff08efba,f4893add,54b8a056,ff60d345,ad7faf15,7d11acf2,2cea0f2,afc1a8) +,S(def5d92d,9ea1822e,dea5b293,58a51ec8,228f54b5,a6738917,fb7f2108,6dd3d84e,b6c740d,b94aebc3,138d3ad0,202bff37,9d5bc20a,d7c0307a,479599ee,8b3129) +,S(fa90b105,cdc8d74e,3f87136c,f4d075f,643fb0f1,ba6eb832,73642e65,84df33de,3e6b28c3,73f58eba,49e9e852,f0f0e244,3a180d92,52624c27,3c079dea,50bba36d) +,S(8212e821,ff2f7b90,c01c8461,3d4d9df9,ce077cb2,9706a349,575b8cd1,a3d0eb52,d59c05db,2fa3e756,fda56e8f,33540639,d24bb5ed,2c8aeb5b,8f8e43ff,703185f0) +,S(ee340cc8,1d1f71d7,4b1a641e,101d15e5,24f155b7,2afb4e49,f9cd8b20,ec61220d,915d833f,25355fd7,f1efa796,4a8e8b04,86f8141e,f5811438,f0083382,ae286f37) +,S(2c535525,dd2e3d83,740b257f,bb7223e2,302b5009,7f8366b5,aa26f65,442afee1,1cd4514e,f945b668,4f38f966,2f3b5402,92d43a79,7f73f947,67272713,b61cf765) +,S(df7763cf,8b57a288,cf4a9083,a2a5f977,404b9e1d,6e814f2b,aae9ad45,fa67d94d,4f7dc336,31fdb48c,612276bd,d388ee9d,bf05295c,1a92709c,b4fc33ac,b1580ce2) +,S(3514c240,d6d0f218,11374b92,8cd6d063,8ff99b8f,4d5e4da1,8fd126a0,ecdcee60,2a0d1f4a,1a1baf80,3c98421c,7777ed1a,ac17abb2,720975ce,e530a5c6,4197fca2) +,S(3de75d9,e58bcb81,94dde551,ab541d54,237a1b58,d935f60a,b54bd3c,6ae40a27,9ada14db,be2db058,c6bad8c4,86f25037,3ec422da,fdd5bddc,455b2b8d,25d97c75) +,S(a728ce0b,1804355b,c5c144f8,1d5eb1c2,90ad3d52,f502c5dd,ae28a08a,6de0420f,4387cca8,f72b51a0,cfb4893f,a85491fd,42cce3b9,ec3344f7,ac93d001,47ddad3d) +,S(ec3c9a8a,5b844c0,947b22e0,2503a815,1d8234ab,aa94032e,16c1d874,5551c39b,7b08bcef,45f0fa93,660845ca,44edfae8,c8ac51ce,e836b043,3825e410,8ebd7fa6) +,S(b0173d56,24945acb,3bab7e6c,617532cf,e619e7cc,e9872e93,26a8ec55,a24761db,78d27b5f,3e9a0761,d0feff12,198dcb11,72a81df3,1320f10d,44591ae3,5f1b381) +,S(d9eb3bf3,cd43dc8b,977c3890,ed3a4b8f,4e04bd11,f95963a7,970d9600,40cd73f6,98196b5c,c42e808a,3f1db718,98c50048,510b9e4,c9b69c41,e7f5b2fd,63b23044) +,S(fbda51af,8a40230a,c7602606,21f92b38,29bbf1b0,1c027f10,7ca54c08,65a84e74,64833994,aa453bd5,4c8729e4,e9010fcb,8fd427ba,3bbe7c71,e812513b,fcd6ccf5) +,S(ae4b9a7,51be1966,f564661,61262faf,472b14c5,f0532cf8,8af872f,ba583f9d,8b2c248b,aa9d7e5a,6f0c6eed,9ad3ab5f,e2bd4078,da4fa281,f4b672e4,9695ee5e) +,S(58040152,6088026,1668c6a2,e462845c,f29764e0,31edf6dd,a40b6e0c,4ccf6ff5,d2f96ae6,4a83c04d,a072f9a4,e39976d8,a2e5f88f,fed070cd,5fb1a701,db329485) +,S(4c28d686,57380f81,639abbd9,fafcf47f,cf477e26,1c46a03b,57ca7326,4c7e029e,694b8a9c,4fa75e14,56a67e8,acfac16,3122a941,150da022,59fb024e,ced8a70) +,S(de205ab3,9e005587,f23b51a7,3d806f81,6984fc77,7179a6b9,465a92c,ff25c9a4,ed84325e,12efc1c2,db42cf1f,eacc12c,48f68e42,9aec9135,5af5c327,c5273d83) +,S(5ea82868,c2cb0a7,4b658dd5,721e6571,b968f589,6d22a5f1,b3ec6b69,594273f4,88d10eb0,8db264f8,13adecce,636f6c58,e1828539,1e538ad,6e2237d2,384a9499) +,S(189cf7c8,64497416,420bd98a,3e3db4e7,c3b0dd46,d7b9bc9c,37f2d036,324998ba,bb3409ce,d46dff28,36601b1c,f7dd606d,7422118d,723f7da2,4d25802,1edaa083) +,S(70a17187,38f50d43,8868026,58100245,3c3c41d7,8ee5e14d,3cf536f9,bc82789f,15c95120,e112537e,41f33870,18f09d1e,101dc445,a9f36296,2b9462d7,bc27c1d6) +,S(578ac0ff,622adb6e,8c20eed,f3011085,8e4271aa,46833865,cff46b9b,fb3a368,f711a1dd,f5f3172d,2b9b2f7d,9d50818a,6b0ceaf5,1d67e15f,1f01ca5b,bbd7f851) +,S(dc9fbc03,476aa747,d64738ba,ddce8a5b,5887f177,fa6cdaea,3e3b05e2,8d840071,c0f6752c,8087dd25,f8d94a19,d294e550,8bd26774,cf4e7ab9,515f0a4e,89eee1b4) +,S(9749acff,a348cd5f,2e84dec0,b3d73151,4bb817dc,4596d78f,e0295215,47b0294d,df667dea,35e54810,daeec20b,e0e7d203,d89856c9,94501167,23de84e0,5781a1c6) +,S(e39fbdcf,2fd2730d,c3359f21,fa815478,ae8e7a98,d6b132e8,e92d343e,32657d85,bafe9881,70a78596,76a6ae3e,364885a2,62441578,8c31c283,20a06b0b,e5b5e01c) +,S(6009014e,27f13712,c00bda4,dc913516,e04b692a,ea32b89,e0fab8bf,91402c09,34910894,f6bd1cd2,cb796f58,8ddba661,eb4006a8,6cec32e5,7086099d,42359f6b) +,S(bf04f247,d02e46d8,2fb9bec4,f76b3eef,b644c92d,43622162,d419488e,87f2f773,d646f4e8,bb3c2e4c,f19ab00,4674e354,302e125b,c1ed684d,32b1cebc,7c2172f6) +,S(9609f7ec,b122b353,85871efd,915c6d99,3e5468ab,c30e9acf,f5b4dfaa,31e5e3c3,106bc52e,b933f0b8,71578ac7,74e2ad89,ebb4d9f9,eeb95592,5d6b50dd,988f9a27) +,S(b690cc3a,e1ebe25,a07440fb,5cbdf56f,f5ae581d,4dec7366,8da2ad62,bab9abe,83cd0023,fd3a3ddb,2cda9603,2b6c1657,35e5f9f6,249a535f,b9666a97,e049dbd1) +,S(72da508c,ed507744,1aa2bc11,4a9098d8,2c947948,395bf38d,6cd00977,91d326d4,165baa93,3433ea2b,e978036,4fec922e,e5d743db,b8117e09,5eafb467,3f668457) +,S(e0fd116e,540a3009,2954322f,5125a72d,1133201b,985d1017,29b1c9b7,a9851c37,c6bc7276,48aa707e,549e899d,630d3155,a516a06b,777997ac,8509045e,e5b88a92) +,S(9d4b8bea,85d4e412,ee0d6389,e883f9db,297f01c,d0695c13,abe2b682,94c10af1,5e2280d7,3f7c0832,d9ae62fd,6a884973,5bb66ebb,e68a38d3,8a95258a,97556181) +,S(eef84395,aa4b6e04,ddc56123,cd5eb31d,69f1255,1c216d25,5057a2d4,388e08ff,45098aa4,34e14364,40d8b26c,73179c48,87797e6d,59963928,b1d6b61,d62d2376) +,S(66fe5c7d,56e38e48,6134371e,76ef427,b4652daf,6e60cde7,39aa1165,c90d7654,2d72926b,b6edc93b,7e40ad43,3cbb6c4d,96d4c384,966ca582,a108a84d,c11a2fba) +,S(5135f9cc,1818caec,cc55a304,aa983c98,82f9e1c2,939f27af,dc2c6df2,c08ea2ed,5a526dd2,7dfe1750,4f8baf4e,115ae1b4,2619b5e1,47986954,27ca3621,e03f22d6) +,S(1a37c089,af7f4a9c,2ffa2bc,c22a3e29,82e3318a,ce1ae29c,3fdf9b62,3e6487ca,d389c033,8522230b,a96b33d2,373672cf,509b0312,35d2ec18,3c955ff0,3d2464a5) +,S(49f7a5ff,15daaf40,913c68df,c9016f95,ed1edb22,22fb1576,e4a11848,47a248a0,f9b55b01,3d637bc9,e9794246,fa6bbef4,d5ebec82,1a5d7f61,1a18c7a7,b9abd8fd) +,S(8247845e,5d9ef839,207f0f1e,26eb0470,3b87f835,ac3af130,253aaf88,1e641ed7,577d790c,1a23984e,7f1b1947,4cb42ad7,b4409c8f,23f391de,3e2440a9,e53c5f1e) +,S(8295984e,cd160241,ace92ef6,10853e8e,57b7823e,25eea4fb,8f118593,d90e0749,635321a6,6798d5f7,39a450e7,67b1c38a,2c5dac96,780c83c1,4c38dbc8,c0ac8353) +,S(d4c32bf6,d8fcf5ff,be0ba34e,770c68b5,fb5db412,b1341537,7b2e9c80,3dd75461,b3c73602,e23845b3,2c44272b,4eda70b9,a1a71e51,66d13353,74153f66,4485f93d) +,S(1a08e32d,4a968e6,a44703af,6b526a32,3babe7ca,6882cd84,9fd3f769,6cc897ff,46ed98bd,b77bed4a,25c2e19b,e2b14a8d,3fdc8209,70344b39,9a6b2a8e,afad4141) +,S(8559be0e,96723f04,4b05965,da8c9777,6b40e1ee,ce49de82,e7cfdc34,354f4af7,63e24b88,854e20d1,2c3f049b,2dd0906a,ba4db6de,aba42dc0,5af03dd4,91333ef6) +,S(e0e0b223,fc7a478a,849c0ee3,f2ef2a6,edd0f08d,e8ccc8c5,5e28bdc6,5e211e8,ca38832c,3aaffac1,206d38e1,25b8847a,6609a5e,d1288d1a,511d6037,9fca60fc) +,S(a237be98,2d8ed250,75801eaa,5917582c,265c3424,5679b4e2,34539ce,68e40a19,f4cd227,976a3780,454d5de4,7026d668,dc1bfc32,9003c87c,f48982a5,5a231318) +,S(28a84882,1eb08d07,f03fe770,5a16f2bc,5edbd0d6,b4367ef2,474f9b60,1205ccf2,9067d3e9,e7d77628,ba0526b1,71d23da9,162551bd,f00fa301,eecb5fc3,f856a17c) +,S(142fe8d5,42bd6b5d,325b8fdc,3820de5b,cc83e2ee,13d59d16,f4c69adc,98c1d5e8,2973f278,32533b9,559d1421,38d7fa60,1b66d106,1bf9c453,9c8310a1,dc75b150) +,S(5b3b611c,5d20649d,19bb00a,11b4b928,8f3d5ffb,700fb6b9,9c97b012,98ad87d2,849059c8,cde0e12,cdfa7621,9ed70bb4,192ead87,5a22c58f,8ebcb58a,f2519182) +,S(248a2249,5d4905a3,f61f74c3,5f35f6f5,2edbdc63,9454cf6b,192c7ce,50beb8af,b5a6f3ff,b707c108,1cd97b24,38867a1d,61eaf73e,9b89b5c3,b1136ac7,bbfd4c83) +,S(8a474a2a,292b50e9,d4d1fa99,a229023e,31ea2093,2d3a5d2,875384d3,dbff075c,7745285c,7d5341b1,e5c39289,16cf8fd2,45b5f045,d30d5dc8,721d6b65,ef804dd9) +,S(3fa01255,7fc042ea,67cbe4ea,86637313,826d10d2,48d5bb22,8ca8d113,5015ffec,10b9d325,f59b4b8e,ecbdca5a,58c48e18,162d436c,a3228b25,e3f75f27,26a937b3) +,S(b77b5c0e,7b94f1a4,dd88f007,1af049b3,6b778d5f,c8a828c0,46ac2195,9fd65648,31246bc0,6722bbea,8c9d5722,26edd609,e2b65d2e,9df6c21a,d54cb157,faaeccc5) +,S(2635f482,67e82b97,6c2ccad7,89bd4bb4,5671846e,d5d1d8e0,8f2c41ff,8535b44a,7edc804e,956091fb,667f9e4d,47b7353d,d2ce39c,b53234d,afb6d5a7,a72b8def) +,S(2306b52d,ae0952c9,c6b6f39b,6d1ea36b,ed0012da,18d77238,4a4e0866,361b474d,438250b8,8d7b8f6b,9a63688b,b2cefcf4,bd767472,bcd21221,582b56cf,325486c0) +,S(caa866b8,dde8284,8f586f9e,ed5a1d1f,aa5604ee,a8c0016e,248d897b,a9f74b4c,2818f140,349f78c4,572834ce,b805a424,e33746a7,d58fb8f2,9954a55f,dc09c341) +,S(818def5a,a0793d50,5f5e9cc4,29c01ed3,fb5e577b,b25277cb,b74c70fe,88bb1641,da9eee80,f7621031,80e2d54d,796367d1,f48ea2b4,93a1445f,bddb3ee2,ee4f276d) +,S(2c62cdfa,568d412f,cd764ed0,1bcac5bb,c36e11c3,5a295bf0,8b12df92,447bf736,e8b8e025,58117062,705ef985,9aba6418,ee73eabf,195325a8,f82c051a,3ec31979) +,S(28ab54d9,9db06e8c,d4a2f7cd,517d049,4e477f1a,b6eb3416,59bce807,e1f04adb,993b5319,a5cb9602,be656276,bf3e7d84,4fb00304,1ecbfb08,72aa29e6,7494541c) +,S(493e7c16,2254a40c,54b4eca4,223a8241,d6c2abf5,f15ebbb6,3ea4814c,512b6061,56387f7b,588d9d4c,fee36b59,7ae8f21e,5fcf817b,f097ec89,7def80ba,3ceed628) +,S(672e11be,e7439165,4fe118dd,a2c5d389,8922a68e,222c9bce,902d2062,b9c51d4f,3555134a,2382a9d,b4bcfbca,45e9d62b,db6bbfa,bfce7c5f,c5102dc3,23dc36e1) +,S(8f8d0f6e,e3b86889,8de86c06,b59f8e5c,27524b2c,2959e701,38b2c3,8eda550a,e7def281,9e27abc5,9940fed6,687bcb3b,f364296c,26bf1fd4,5d417103,49212f34) +,S(da8c5783,4a11f0a5,797cf4c7,9179f30b,118f2802,1205d495,e8213fb5,78b293e3,6ecfe35c,6f663975,86bb1c3,ab5dc518,7c7a0ce1,b6338d28,a2c01df3,89c35f91) +,S(4953e0f5,3b1965ff,3efec2d6,fa99ba0c,fbce09b3,83e20ef4,2657faa1,49681955,c210c78d,9d1635b2,3e468324,7980766,3c28fa97,18d0ca39,fc09b541,975541c6) +,S(5491fdaf,48a0e1e1,be21f7fd,be910bd6,5cd3e0c8,16da38db,6c742042,3775f293,65273688,5d1c5338,a3be9b29,9b51f4f3,9c82de96,318643e,3d34ecd2,fc7ffae7) +,S(b9c4afa8,42363b9,fb583885,8f17d1b6,b0a8529,43c907f0,af3ec9b5,abc168d1,ebd3106b,1b75ebed,5d013aa1,eca7d8d5,e24d511b,6d4178e,514fe156,4b550d9a) +,S(918da36c,444847a1,b5f9826d,eab809d5,d6802e73,3abca386,24237683,92d2bd62,6e6237af,d7cc87e6,15e14113,ab38989e,889d5e6e,6166eeca,abf1ddc,8a53e218) +,S(777d2994,da1f514a,800240e,59b743cc,748eb42f,4572ac93,a2e42e37,1d3392a,6193d7,e9eb3195,2cab96f4,14e1d24f,9d92505a,9d21f864,5e6dd3a3,8a9680c6) +,S(108e6ea0,9a08c5c5,e27b8b3e,af24ef55,3988c650,34ef954c,4d17f232,5723bf3d,1a8b974b,86db6bb4,7c314ebf,f811937a,b8a0dd76,e824dbe2,88fde1bf,fc13b2eb) +,S(36d9dadb,65a54d49,1198a486,8deae1fd,3c2dcef4,4a682839,b5dac54a,456bf185,25e84356,d93b5d86,25eec306,565bef19,1edd9bf8,347dcd8d,785024b,2147bbf7) +,S(3e0ebab1,43ece776,729d8a9e,302726ce,aab89654,23292fe3,ab2e71d3,66531fa7,6e7b2608,556d6236,8948f32b,2fb04b34,8e38eae1,3d9abd5c,691383d9,958d41cd) +,S(923dc76a,f315f31a,a1de9521,a13ee9ab,ab08ab42,157f483,2babdb5c,18fa3728,7a8f17b6,7439857b,3141bfca,6d89e649,7facf685,6331003e,f6bee07c,ed3ae47) +,S(f87fff32,2dfeae3,4ce9cb81,51ce2e17,6bee02a9,37baac6d,e85c4ea0,3d6a6618,74e49037,aa726e0a,357ace25,603cdbfe,7c14a4cc,2e1e4e13,c7176121,585a03e0) +,S(1388065d,dd7f69a0,11dec106,b539f7e9,e00b5aff,7568820,e33f9c1,18881ed,acab1d8f,140661dd,422f72a5,5ab4242c,65d1a932,23fe732c,92b32317,4d13408e) +,S(e5476b1e,a99b6a08,83731542,7a3751b8,3d685b34,acc5201e,59e9b623,ac4b6941,57d5b2f1,c4dd795a,323c794c,aa8fa754,bc86dd67,3cc8577b,b418b2e9,5f3b4e21) +,S(f938ff60,f1e8ebea,4c229d89,4c98418e,90c14981,4ed7909c,3dd47cb0,15cd1f15,d7172212,1a0cc646,a0576e29,372bfbd6,37fe2c5,b6ed6821,4da50318,eebb13e1) +,S(b31bd410,7c4a5108,1795544d,5854f9bd,180b494f,a08878ad,8ad5a3bd,98a30aa3,94261097,6bd58962,5e941aff,a007eab3,d33828f0,e12b31c1,8fb6f5c0,50519e82) +,S(b3ed87ba,83210d01,1a2df141,b9a6c6d3,33abd692,55da3af7,b4447d03,f4c1cb2f,949dd379,29c757e1,a970273c,b6341e66,b90be71b,347e747a,be0914aa,4dd632b3) +,S(60e6c240,1ea790d8,4bb95e78,731bca08,89a57c0e,38b87f46,668ee16d,31221e17,f247bf35,c722098f,2a5c800a,571eaf0,36738704,4050d98c,c03bd146,ca9465c2) +,S(2ae806b0,4cc8d047,e7dd8d37,713cd71,eaf3e16a,f74c3b87,994afaf1,c3750a80,a8d978ac,b29771b5,1a87fafe,605ca0ee,6facf6a2,41aa135a,e38de4eb,b2e2e954) +,S(9af178a4,bbba2d29,e7a0bb15,51f6f3a9,d2384386,3779f439,58a424c2,29bb5c47,c1031fba,a0238857,a487ac85,72fbb3d1,4052a4ba,adcdf259,78101a21,ae79abd3) +,S(9dd6a721,e9cb27af,2e7da097,c9e8a250,fd78a531,330ecb2c,3a116d99,6008f523,e6837b7d,647309c9,4712adb1,4bc65787,fc4e975d,f4e82173,57dc9d3f,e7f36080) +,S(cf5f16be,d7a1a1e5,3b3e3f1d,e44efbb7,fcb717b6,9a28bf0f,e31a1da,a5e91c52,9549ebd5,4d87207b,c63912c9,99920cf4,b0c80a0d,8a69d4b1,4852834a,c4487497) +,S(c6794890,810954d0,782466a3,c52a0149,de577cfb,3a2001af,d45e905e,dfa64722,4a4fdf51,deb64031,bfca5fbd,5c827829,8621b625,1be69187,fcc2460d,f75ca468) +,S(a25fffcb,bee9e0ff,1659c1ea,41406aa,b03b4920,fe1a63e4,442d5241,30599713,176b9e06,5a821189,ac3fc28a,fb72a1ba,40fab791,4de987e2,1236f244,bf41486a) +,S(6079a722,fd5d923b,16acfafc,7248e329,128cab6a,cae9e5ec,dca49774,e0c5bf71,c09972de,99ca5a45,c4f6f1d9,10337efe,23f5292,bd5ecc45,df0f7aeb,d18c4bcc) +,S(188cb43d,9d4078e7,18fffc42,8b16723e,f64b950f,cab7582c,8139dcb9,2b66b403,a038fa37,ec9ea240,9a2879,9556916d,fcc8c2f3,358ab14c,140f7f1a,23af5404) +,S(e310fc40,cb575c68,f5792506,65567ec8,c445ca34,68cfd02c,d781b27e,f819bb30,31328a65,5ba312ee,5e901def,66e7b946,e0c18336,a0f1784d,df66b89e,2abe625e) +,S(dd86485d,1c8245dd,d940bdeb,1f462cc8,f15693df,246c3c8e,52b574bf,77dea4ac,cd6bb7c2,56c9a270,4c690175,ba298a09,8963a8b4,7e743b48,33fc09c6,9966ce2) +,S(1b7ed20c,f81567b8,6f7dc67c,ab69e197,dba77399,9b36097b,de85d02a,7019aef,f814e92a,d1cb4386,550d89b5,9a4bc378,df428d54,d314d531,be6fc35e,f0e3d1bb) +,S(a15587b,2d528338,ed146a03,670b3f1d,9b41cd0c,a0645897,a0f719a7,b5ded284,2aefe34b,5aba1a4e,e30d225c,c4023ee7,12fc1522,ad6b452b,fe6ea727,122e925d) +,S(57bb9f9,c99da691,98cfcf20,9a0940ce,8d19463,9e4d1054,484953e,936a5484,63d0fba8,d90226e8,2c7be5e4,1d77bf0f,700dc57b,d8d3079e,9a6a47c8,331660e4) +,S(224295b3,7fa1b4a0,d7d7f7a1,2113b21,291f84fb,8fa4b746,bab925d5,93bd262c,d60ac40,b1e4b0da,7563eb74,c222660a,46ed388e,c4517ddc,ea2962b9,38195796) +,S(2434eae6,a34ec53e,7c031b2,9e74354e,d6101ca0,f228055e,53b39a6b,5453b0e3,2ff5ed61,d57a04bb,138f3956,33a20e60,8b04f775,6476d0ed,6ce7a382,743ce23d) +,S(448de592,907c1113,bdb04c64,9fb22b05,ef2e6ab6,36d0a03b,700a5871,89885ce9,d7aacffd,6ab35068,debe6dea,25b02930,63af8b10,d4592880,3d0421cc,a879eabc) +,S(8405cf73,5aef7674,7feb92e7,1aa3ba0,defc0a1c,c1da698f,7c2a3718,6393dd76,5795d006,49cd10a0,4a661c78,3f4a8711,89c9ef2f,ba86853f,c7955258,e6c407f2) +,S(698974c1,e5c1487d,fe9349aa,371eb86,9318accd,72c66d5,581211cd,6e08efc9,37c2238c,dc8f4bf5,1f76536c,2ab9af61,bcec872a,bb84ce15,90bc1c0f,ef84509c) +,S(8a37857a,be3cabc6,7197781d,f315f78b,e6548c61,1b846d8d,ce2e5732,643fee05,29882f68,9154cd0,7e455e4d,9e3866d4,5e28e99b,21dde0b7,8b87698b,4cf674ed) +,S(a871b34f,5cdd39fe,13104c96,87a8a717,25ec8cdf,fa60846,793bce03,2397eaef,84f96417,9de103c0,9f7e2dc6,86c9213c,642312de,8de6cc5d,f3ffd7a2,c387cb28) +,S(49bcafb8,9f78a7f5,a8857905,e99e74ac,9ec66ec7,aeab8fb4,fd964ce6,8286f44a,e7db8ccb,5641ab74,a791d2ca,7bd193ea,71124a61,2716d94f,4eae407c,ed9eff6f) +,S(d5c7d92f,2f05c9e5,8f586289,dffe8499,40d9b84b,79feb686,c3f71300,f68b6df6,a68b2a5c,219ea38e,a04b272c,e1cf42bb,6fcb2b2b,fce36043,4f1802af,1d51c08e) +,S(2ac2fe3c,fea4cd7b,9c74a249,cb0c8ed0,6a825cbe,2826c56c,fe4a8db5,3b286696,7d90a659,b008a51e,ca2f6031,c6ca6078,505bb46c,f00a3834,a67e7804,b60f43f) +,S(7c09acbc,62827ecf,4f63a85f,5a0eda7a,5b0069ef,b03b51d9,2f61c5aa,10a39234,e07d2539,c29128c5,685f8641,45fdc318,854b56f2,962b001,5a96c688,69624836) +,S(e886dd56,7e1b42e7,69941ae7,13b2fad3,3bb4ff02,34a27a7f,2c496bbf,6ffbf9f0,d4b2277b,abeef80f,371c097f,df4e5de,5a4666f3,c630b010,81d1172d,c667a877) +,S(edf65cc8,e83983,c5a178f0,ff60bb1b,8ca8a6e5,85344464,73a199d,59c2dc,a2426713,f0c5309f,84a4710a,2de1cdfb,118a4db,1070d23a,92c76244,89ab2d5e) +,S(29c12f04,b78a6ebb,9356dbbe,5b152323,435ad7bb,a3d2d036,a746af6e,d26d17f8,8399275,bf6211aa,78ea211f,39ec451a,b3336d27,fa059935,8b7fcece,216eae4a) +,S(d5db8b8c,280e9914,f0a034ac,3e0f9fcf,169f2046,4a618789,994f8a79,6663c3e2,41163c3a,85a0039,f5e5635a,819941f7,98f27078,aa65ecbb,eb60d577,c263412b) +,S(990a4fa5,630eb00d,958e57ac,8bb4f7fe,10e1055a,c547d165,7000a17c,d9135f8d,f25ee025,491fa289,446a0364,68c71217,eb252414,f8fcf291,2ecb23d7,4bc9653b) +,S(d784ecf0,1c7849dc,ec901c3b,3315cf53,4e3049ec,c68d71b7,41637b57,9e9c0935,5de98d22,cc382aed,d8c82a84,1ec6fd46,30672008,8567dde,6b2d64fb,6b4205ce) +,S(6576cd0,58850cbb,aaf53b67,bdf3c19d,9b4d38e5,19c99338,3204cd35,6ce38193,a329993e,92d1e56e,31c1fbeb,27648fe3,d984960e,30bf3420,658f74c6,5710eaca) +,S(957788e5,f675c0c6,4649a808,1c4549ff,20ccb177,3d26e4d8,bb94844e,bc35efce,7ea4431c,dc4bee37,d95c3948,615e17cf,1d32906,9bc10a8c,515aa0e,521d9b5b) +,S(8af7ca80,5053b537,ec501abd,78c13ff0,da5549f3,b045096b,1452c05,e39e4a2e,25e86225,aac042e4,cfb235e6,da40543,6a436206,e9d67fb8,e1b5836a,2d7e8402) +,S(49bf0393,e16e634e,202ff642,ad79c179,e6eb7456,637b2ba2,623937d0,e215236c,8590613f,401de0d4,1cc0ce1e,e9a13441,41e5f80c,179ac722,d603e697,a431a85d) +,S(c82e2a25,2572863,527b6858,18c9b6dd,df3653ed,a264b5af,dc5ebd19,d4192063,3b86f800,cd87c1bd,3d70af04,47f9e939,c2717ff7,376f91c7,b2675e3e,39a6de8c) +,S(9ce43920,2b9a8f7c,3aefc9c3,fe4d227d,42ec1355,158b2041,a3712dfd,d8eedbf3,dbbb5b05,859aedd3,faef15d5,9a939ff9,53a54bb3,dc2ee6e2,6d5a20c9,ff5b52f6) +,S(e07009e,49de05ca,52d20221,3ecab4b8,baa707ad,96ef24a,168bdb6b,16fe6227,6a35b0bf,e752ba26,81b865b0,ade8d4eb,2583833c,a1523b2e,4178f9ce,6cbc33c9) +,S(eb4dcdb4,7e09af61,e4694814,79612715,d588615f,f4c23fab,65015bd,821da888,63e38168,584602fa,1e06536a,d4c8115c,86305c,41040083,4a55d153,e9661b8f) +,S(be5f8681,2bf20113,1d257015,dd29dacf,a2c65907,26078f7b,f864f339,10e49db6,d0f420e4,56174aff,5995a92d,a73fa511,43c4f1b8,c40e9f30,8f04011d,956d9da7) +,S(3b32dc39,10e75f9d,98fa1318,edd7e8ef,db214a5c,b31d5ed7,4a61f881,355b99a8,1a12de86,19c2e9e5,9fddf756,e752e54b,6e4e0aac,572fbc42,18baf1a2,a3a18bc5) +,S(95ac5dce,5c06e885,65d2922e,a3f386b7,dde10735,169729d0,a3c3e7a4,86e04db1,1a22cd87,ab1b1821,e3c49e85,616b7b49,680edb77,251969fd,e77b5b27,3ef39838) +,S(6e4ed0fb,a4b0f13e,335d1b74,a5ed295e,7dad591e,a8dc5cc,d301836d,7ce708eb,9056166a,c61c4e09,ed988e6e,59cd9ab0,16a2ef99,e99c1a54,ac37f152,a34b931) +,S(8b7c3394,208e0ee1,374925e1,7827d849,ea8d9a79,91d2d859,898eba2c,23a42e10,b6ab9237,96720bcc,910e6440,75ef3ff,2c8bebf6,2f21ad0d,3abeb2,7043d193) +,S(fda7b47,f6690d73,884965b9,8b6f5dca,dd48ab4d,8f96edcc,8e20584b,b0f871c6,9b402435,a272cc6d,28b487e8,b54b473c,30929222,55e47560,e18b8e6b,ca926c5d) +,S(f15da0f5,395a5a1a,ef8beb53,4c0e9aa3,6e63018b,cc91a55d,ad6106a3,3dbcb217,28cf69ea,bb3b0151,917571ac,48609723,80be252f,bcf98f6d,db6ebf76,578a8f1c) +,S(c6e266dd,2c7817e0,c92378e6,38709a97,d9a208b8,7fa832f4,abfd881b,bcaf9253,2af100c1,fa9bb3a3,c8e95e3,5d0bef58,5ffa7adc,93232082,84291ee7,cb769626) +,S(4bf8aa02,fdd201e,488c21a8,33925687,7f5a727a,4fdab13f,d133d08,b6e28753,58812658,ad9c4d59,a15c6bd7,9e6c622,d8fe5f05,95cbdd88,f39be9d3,cd5fc8b8) +,S(aa985f28,6dd485a,5589fc39,da77fb95,5cda673,db61e48b,972fc129,7cd0a6d3,abb0f897,2f1163b3,29a5a92d,a1ff02e0,7c277710,10e24a04,e1e5f60d,1e4b75b2) +,S(8174d101,ec13a1cf,4eb9f88d,88c14121,6c2fa04b,ced197c,8e1732ec,61c41c9d,c6765dc2,31b02e7f,eaf7a662,5a639b00,c6e5d94b,1a791bbb,46f6a758,8fd79aa7) +,S(f9f64ea9,d6039297,b728fe09,85a9a3a2,92573aac,fdbe6cbb,8702f04f,6df3d876,4146c7c1,406067d0,160950f2,1172e879,188069fb,d87eef9b,1a67d2c9,9a4ca01a) +,S(3e643a70,5a6885eb,3d34454a,2a5de925,f8067cbc,1ca92951,d8865ecc,a8f1b3b4,2deca704,5525534e,de9d54d1,d777a996,8b5e5882,7162ef11,b0fe08b7,e2fb0355) +,S(444df411,fcc3ac07,7e95d200,d6f76d03,caae45d2,b87a882e,4c0966f3,376c63c5,b4566598,643d964a,a7cd1a4d,f2decf3d,ec520c93,ac6e32bc,64350aa5,5416cc23) +,S(12a2f61f,58be35fe,314a7beb,1a6810a4,19cdaa6a,8424d465,bbb7a87a,646946a0,9a7bdf44,94c2cc8f,f1953946,1a69fbca,48410b31,95d79069,8dfd535d,290ba47d) +,S(bdd72692,462573c7,3d48af94,b687bd22,511b2b7a,93f48793,3d52b2b7,e264cb9f,56e6c4e,b794fab0,bd5ac992,3f7469aa,858e6df7,dc40f4ed,955c0df7,a2123874) +,S(e1bd5558,77c3f55d,12b4f156,ea4da9ef,c974bd29,d7d043d6,ec7fe56,a4066bdd,8dcd9b99,fbe7436a,2382bea5,6c5a32f7,789cbf1b,1c44433f,f5a95075,c3233170) +,S(a7c68de4,781c8294,bea46609,f4a1f550,fc064eb8,b071985d,804351d2,60132ad9,a08278b6,3d9efeb5,1062b240,d45989ba,6f6bbf9b,ebfa0766,8428862b,adb42c32) +,S(4f3a8769,b4c6e369,cbdeb90f,5137d07a,5fa0d66,3d8ca79a,56b3c70d,2a9aa855,f6c051c,5f701e15,348ed9f2,c4707584,b9d6db2c,b62bf93e,35b6486e,ea6ea169) +,S(deaabc1c,8089ebfd,841cac66,d8a6bb58,36fd047f,cb435a8d,74463dde,f444f232,fb7cc4ba,49c26e7a,a826e654,7c8a6d64,ccd14a49,62a6d4f9,f50c293,c228e8a1) +,S(c411af61,547b1b38,12551e1f,4ef2b32e,fd7f33ab,7cfce378,8b5b8f93,319c0695,d2bee7d7,3d50f82a,e9266d21,2fcfbb76,294ace4e,f6222ab4,797bbf88,558cb66b) +,S(d0ff6a94,485bdda8,d0c28494,5b9dddc4,4a35f101,d0a89637,8210bdea,909ec5e7,ab3f60fd,2923a8f2,d02b7e83,d8f953c4,cb1910ff,83a92a65,e2121f22,364f620f) +,S(a0d05cc,9555ed92,2851baea,35ad6cb1,6f2744,b3fe424,98235aa7,1f08c0f1,843b1105,237158a7,bd7e67c,a20b2705,50afe2ad,318077dc,4714c7c9,d6339948) +,S(bea08445,eb295fba,5c83ef6,7d909978,7d599642,893fb9d0,568e5920,1e3f5d32,2a81a7ff,b3f7f453,d78bb2bb,41d12ed1,e26594d6,bd4f5cc7,908f322a,6cce10e3) +,S(e8ebcc4c,431be689,9eb5aea6,f6ab9700,551c3098,c5acece3,e822c7de,e6f0d5f0,ef99a461,760ae4f5,8fbd511f,59a2ae79,6d65db64,eaa0d61e,97d0a3b,31fa902e) +,S(4948606c,dd73dc44,ecf1db77,c796d8b6,806bab5,85877cd1,d9630bce,966e8fd2,3c67333f,786c8c67,841630aa,639446a8,cb8c13ed,f3db9123,bc64b925,beb95f80) +,S(4f259b32,40d9efba,4e3e40cc,a66cd494,fb5a19a6,5b5c8a16,5c18792e,9ea778c2,fdd88087,78c26999,c4a00605,49f4ea2c,b1590f7f,4748cefb,1b68eaae,4d17446d) +,S(f303a493,e14d7f52,f276e2b4,3e118eeb,1e7e918d,e7aa7f33,7e350fa4,7adfcc29,c49fa46d,befe53f,5f5bc49d,aa6ad265,453f7977,c5fe4163,cfa1bd4b,69141b57) +,S(e00c4b17,f4c0800e,c1b11859,c40a560d,58b9fdfc,29df5a41,ea4b2f53,c1df595d,62441a66,c3ec4d29,d18d0d95,7b4ccd18,a72a1003,d34832fb,8c81fb75,9763b99d) +,S(484b8486,1af6af52,a47603bd,2b754be7,ca16bef2,21581171,4cfb2301,db72ce70,36f84ff5,a0ac79a3,fe696865,2a0a6759,cf72e5c5,8c76359,d477e72c,4d32fbc7) +,S(88be58ea,d8b51f44,a1be6a8a,7cbc149b,ca07fece,11a7adab,210467b8,4cd93f14,94c10caf,7037fbc1,71cd6cd6,a0697b19,8ebbebf4,9f00c67d,4d46ebca,92687fdc) +,S(abf6ceaf,9fddd7ef,44a75e11,b10119b7,7372a3d4,7c163b77,384de944,47da781b,5cadb30c,6320c67a,e9dfe2f3,b9bb4ef5,41718392,81c4a59a,7960eccc,6795d290) +,S(e8c26522,9ef665b2,67fcf10a,17c6c3cd,4e221e0d,95663deb,74f8384e,b89d173a,9a69fbad,f9b050ef,d231965b,30d91646,bec7ba26,9fcd0934,35ae11f,ca2aeeb3) +,S(66652bd8,bf72ecb9,5e670a24,e8683155,e031f3ea,91fff58d,f60fa4ff,d9c6c23e,4844ec08,3f182b73,22c2fbb6,6f6630a6,5fa6901,52dcfb3b,4b65a3a9,30be994e) +,S(207880c2,d8421040,dc8202c4,45bf6d58,75cac841,532aaf0b,adf252dd,4c2c0964,2b1819d7,3eb24de1,ae4ef316,7c92a7b1,a562d93,80fdc54,e916d1f0,c1860cfd) +,S(46b9bde4,53d0692e,ec933485,ed0dff68,7e8f262c,7d9270cc,763fd959,2013f581,58af9be6,3ae599c0,f499b0d6,3085b7d5,394cc786,9f2fe225,6ecabd2c,a14f9bf7) +,S(5d9b2574,dbebe5d0,9756e2f,29af3aa,a2fa2555,d629a78b,82b1d679,75ea3e11,ed9f40ac,aa6ac68f,cee3dd50,7629758f,f3a64190,1658f0f0,2b87b645,ee59263) +,S(ecb5ad82,8b986425,9a76a649,1774338b,dc598fd7,77cfec52,d086c172,6e590e4f,2b78936,73c6d87e,a954b5bf,52f8212f,65d33ea7,ccc4b4e3,1d98df2,c9887886) +,S(b32b64c1,5e711b8a,1d174725,de55c,ddd62e99,fc90e96e,8f3ca532,3924ea67,af5d61d3,6dceadf2,34a7a94d,e7e4be1a,4d81b84d,e0fe16a5,403b0c24,a6ac2083) +,S(5137f71b,71582334,a6d57aa1,5cf6ab3c,8b7f6842,a800b4ab,1c308fc5,820cd364,f7ea5fec,c9b17dab,c6a248d,49757711,e4a3b38,95658381,efa652a4,4df1eab4) +,S(b9bb0e1a,390b5889,3e113a89,801c3f5c,25f94e65,63161539,e7c56297,ce9ea866,d8db3c90,3c3d35fb,ae4e14ec,e81e4e31,247f60a8,2539880e,6b66951f,8324a11) +,S(3f091967,6da40ec2,4691c21,1c42f47b,88cc1192,ec1827d3,17beb468,924fe9af,f1b44826,3e882c1f,18ae6a81,238d0724,ba4c04bd,d3fcd395,8775df5c,16bb8de9) +,S(b5fa25f1,dad4600e,8d55e7af,c70a1b2c,3767da47,d625ced8,d55ac88,d893b4fe,7575f661,f2ba296c,7ed3a190,8a49d099,83e49503,ba17a70e,1d6939b2,8ad22347) +,S(a0371ce2,dc6a025b,78db797e,90373069,e4ca06ea,6b1cc018,3d4c6f7d,680d17b0,92b5a8a8,9a5005ce,e851c521,4599b774,24f0ff74,5c4af6bc,6937c432,e859919d) +,S(5aae6e90,a49107,78863967,d7d42020,cd0a9828,da25ac8c,7b19942a,1ee2f210,ed9cc20,82a54f3f,fd7218f7,b79ec399,7e82fdc4,cd783957,5760e4f7,b7ee8fd7) +,S(54e7daec,f4a9b6f4,b100f964,850deb65,64efddb2,e6ce7b05,3fed2a28,1a0841a0,d9ada32a,54773a81,d5a857ad,8b34d96,70d46785,70943dae,cc83deca,97c9c63d) +,S(e9b29910,d8bcef46,b48d8be0,c7649b84,383ed752,391ecd7a,bdb454c8,8fbf44e8,eb268094,f669e91f,a5173965,50e4c40b,d7a26792,9a8df3de,b84c703c,261d6b69) +,S(43f95222,f254a513,1977c589,577d1d9d,3f537a1c,9fe14ef6,384e1779,da546a97,d7d3c653,43345c47,f245b305,b662a2df,eef80b3,97b3f5e1,4b0eceb5,71cb18cc) +,S(9fb45fd5,3999fb92,830bc090,216ae485,6723385c,7224b1d,cc91294b,a6c3b103,5b47081b,dbfd82d3,90d7bf7f,39a494bb,6731b506,b827213a,277f7ac9,febdf451) +,S(dd92282b,835529cd,3295919b,2eb466f5,9ca840e,20ad87f2,3cbc824b,b71dcce9,ec45f6e7,bc59d668,b1ef4a29,d1e23bcd,f3796268,3b58fb7a,d58a9e1c,5f726371) +,S(7482f012,9fbdd7,bf99def4,f3de23c5,fe29036f,c1ad5c38,686c05da,dc16348d,a43c4a0d,5497f6f0,bf2b2a20,b65bad11,73fc0dba,c24e65f8,db1663a6,b840abd1) +,S(fa4cfd95,97fd6278,1dd2f587,a5b03195,537fca30,f7a9a377,a69a6869,70ebd9a5,4568b6c9,9ddbf778,bd31d269,be18a8fd,e2a35031,a30505c,1b8ebe1d,c7ae823a) +,S(51e0d3da,e7763e8e,81905e1b,4f1ffebe,2f1078d3,27944c53,d9b7d110,3fa60b9e,118da0c4,ab572fac,cf9f20b9,2108ed0,1da673a5,2395f3f7,bfa2ff2a,36da6740) +,S(7d8e567c,c0552335,38c3b857,289e96f4,502fc674,f40ebf86,c482a668,dbc9530,76c3fc46,c6446a,4b9fe552,ba8b2614,7484581c,585c8ad7,600c2ea6,8eb37571) +,S(d924c6d3,b400196f,dd1f216f,dfa18c79,1c316d67,9ef4c0ed,8d12b94a,cd1dfb1f,ec33cee,881c04b8,b11eb3f2,88dd9b92,90b9d119,26c692e5,9d82aa80,4febcea8) +,S(8dcb330b,6f629c8,d18d28b9,7a99d82b,3965cb1a,bf953b8f,33074457,5e93c0db,3d8a2d19,8323902d,1b129b57,313f81a8,b58b7340,f6f7c97a,b6d74f37,a46857a3) +,S(dd1c4a3b,94b06378,8cf86797,ddaeb671,57910f1d,35a32e80,d3f749f6,bea5d2b5,efbec0c7,5a69583d,643e5be9,ab78cb78,3d2afebc,73d7c64c,869bede,b3230777) +,S(2b03de34,1dfad7f7,395f6ec4,84d292c1,ec0275f2,bc762dab,7658a885,37f5e772,3235e8fb,3818582c,55bd48bb,49f78e5e,803d7d1,ae49bbdf,97166a76,c3c0d0e3) +,S(3a795b0f,ba145bc9,7e7a80ef,a6b77132,677f06bd,4c3e7f39,47978c83,1428dde2,f4125b9d,df038a26,37cbc9e1,eed40aec,81af644e,a3f1352b,526df579,44914691) +,S(ecf813b,a133d6cb,9c46c081,b0a851db,121f5c21,788d1e59,ef8c0588,684fcbbf,69e0daf2,a7b7b473,7f2becd0,789529c2,597e3915,ebe12093,ecd7738,13e53560) +,S(637c4982,c14163e4,1037191d,d4e09d3f,74383245,5368cc33,57669186,d6217d5a,da5a2ab8,fd83d2e3,25baaa5c,a378318,f6fb3747,5ac64b77,a74da573,deecb410) +,S(19fe73a2,d8875b57,dcff5fac,20530da0,54255658,1251f7c6,b198b3e3,71b90e87,3b03ac18,2ccc2518,c367a77a,1fe5e8b9,a3264681,28fc1ad3,5a39f7a0,d8151ca0) +,S(16ea62a,d4cdc00,9d151b3,b6680b0,c68b4cbd,f144c234,71d55b7f,3bb7ebb2,8cac4a1c,53672e59,338612a8,995980c1,35f02060,2e3b9f6a,8fffce9d,e53fa629) +,S(6b9d68b5,454c6d21,678e5413,279f9a28,e1eed485,fbf512e8,49f35394,22a40970,b63f5044,98ebe37d,af9e6969,da888eb7,907f8565,4b05d472,fa4b1b27,ae365482) +,S(1fa20c8c,8f0812c,2e7dc948,afb7ec92,32c3c27d,23165d05,868dd127,b5ed3e6,c5257f4d,82133642,7df68606,2c229fea,6cd16857,280a60cf,ed84deb6,29838076) +,S(73a83c92,7daeb4de,1cf1df6b,31d8f536,af15bb38,be506263,e8e8a6a1,bf6acc86,a08acbe4,cd6c30b,82b4e24d,e8c9b891,26a21dab,e4df40ab,2fb7ad6a,82eb8adc) +,S(3a995664,924e2dee,ca278cf9,3ce265e2,85ba90ce,fd2a55a4,8e1761ee,7588bdbe,f3221adc,99eb33d3,52465d93,91caf18e,d011a1bd,3b7cf39,dd48d45c,44cbbb0e) +,S(7c65ee19,b032f5cc,1d45cd9b,9c160e86,5ca516fa,b4f88596,5e07f269,3d429c26,47c7faf9,e3df277,d31076ae,4be2224d,8cc54a5e,3743e287,ff9572a4,23704c5) +,S(c010694c,6750dbbd,bd953118,dccb8d03,2f05e6d9,65db8fb0,3dc00b22,e4d397dc,3b4914c6,dd6c5441,59dfde10,a196f132,5a5e6101,52d41be2,39583b80,6c8e730c) +,S(e255848e,d28d8b6d,6f95a12b,92136131,a33dcb2c,a723fae7,5e317cf6,62519d57,62f7d5aa,1757dad7,98207dcd,18183b24,377c9ac0,1e106fe4,d36d9264,3fcfb7b6) +,S(f31418e5,73232992,3a878dfb,f1de30d1,a9669da7,76effc45,bd1a56d0,2c236ed9,e62ab884,dce0d946,55e34c8a,630b5aef,16a1eff6,1f889552,af7234b8,ae56b84c) +,S(9adb945,b876313b,ac9c290d,47c1e6aa,1f3f3c9a,e8c67770,61512c2b,bd703181,b21fc142,b4632616,4820b82b,edddf2b2,51531d0e,df0f0f86,50f74d1e,9f0908fd) +,S(c4682b2b,9d4a63a1,855132e9,b35b390b,ca04b846,b83bf36,1726c3c5,808da322,f25a906a,7100ba32,1b659762,23e36f04,14e9075a,835ce5a2,6eeb5d03,d35f6972) +,S(ebb0fd6d,60f49c47,8167c405,597c765e,559159f3,ae04003d,a99a1066,ea80d63a,eb37d160,667ac862,1da2ffcf,28b431c8,c4202f67,706f4350,afdc868e,6aa0b0f7) +,S(78f12d20,70d8bcb4,267cbb,bff637f1,65ffb098,95f5734e,3551bcbc,9a5597a,42976ab3,36621756,1bb574d2,c87d99cb,7419a3e3,39973740,7de17090,2bbb78f8) +,S(3dffc4a,f6214b63,9839fbc2,b949621a,35ae41bb,e7679eee,5798afbe,85919f69,58174b6b,1b4021ae,22dd15a4,29d97502,a13480fe,902860e9,36fead8,57f2c456) +,S(410c9393,a4ed42ca,2115198f,4db76eb8,bd16bf0d,324528bf,55d5d745,b55a15cc,404ff4b1,df71b89b,c14c2cf9,bca25176,83c2981a,731fc3d7,59faa0a,5ed58306) +,S(6b4d5156,87d6b079,3df36632,6fe6977c,b93e6569,66797196,6c16c495,be4e3649,647a4894,bbac207f,5d2a0315,2db1760c,1a25560a,95511c81,5d6c11a5,e969f4e3) +,S(58ffad7a,e87d5986,f0bccfd8,5005d9c1,6f0d8724,6be4dfd9,4a771c5b,a5f34247,ad8b7ad8,f9ab15fa,f50d6f93,ec8629c3,b33fba6b,ee36ace5,e505cf00,f0069817) +,S(e6d3e41d,1835fade,af27738,23e883b4,adb95669,72892c72,b310eacf,a6a757fd,a136c88c,b580ece7,cef03e42,5dbdb8ef,d6395cab,b427ae61,45a0ef0,21359c15) +,S(fc47c62b,43aaa030,ac104479,21bc1026,3b561b42,a2d32a5,573ae947,d953b35,5d318d1d,65fc7806,732b5810,40a1f511,62723626,b393b29,50230600,246224f0) +,S(ceae2867,cbcb37bb,8e78da9,3553866,d0a1b8a2,933cb1ca,36bacb7c,6fdb251b,48bf2c7e,c163aa95,79417b37,343727b7,956cc629,3a188c16,d4c2d1dd,abb3dfd) +,S(abb12378,c84735b5,c23408d8,2516d887,9195fb74,c8972d78,daa8243e,1befeab0,5a0bf64b,da5a465,d9d0be91,3c8a56d9,ce901c36,67041a02,abb591b3,3f66698e) +,S(d7781e39,8330c7c9,2185302b,e116316,1a576ce9,43a4824f,274ea700,3159eeaf,6341a432,4e07c5c7,3ee7398d,d1be3d7d,261aed99,96f6f310,fbb464af,d06651a) +,S(a6918dcd,46ec2045,72d71646,d2a21df1,6f3ad133,dfd41a6d,be5b7684,7e4c760c,c0e51aba,378d498d,9a70e4b5,3521397c,1d6c7cfb,2f6634e5,1f056e7d,932fa9c) +,S(413a4ee4,fbb5de60,392b340a,65fd9706,7785e2e0,248d2770,6ef044ca,83d1a204,a0362506,c18a8f34,3bebc668,d1b08fd1,6595a674,51db27c3,43af172f,8a3dd197) +,S(e1a7bc24,de8b0920,f6c4aa08,2fbd1126,87fd8766,237311a8,9681581c,5e04001c,3e3ba9fd,d0a2873d,149aeea2,61a55c65,3a3d90b1,efa8e49b,29bab100,1a6bed16) +,S(ff9292a0,a147ccc4,b5ae077f,8a337e05,ab1dde9b,1795942d,8a9a0fc3,dd333a75,e50f027c,5f7a3463,7654b412,25ad5dfe,b555ea2b,8305c7a4,3b6f5b78,7a23a166) +,S(eae56623,437c9dd3,9dc7a36b,45c2d3,afe849c6,1980140d,900039d4,4ccb9c0c,f1b8c9e9,92847436,dcab5a9b,22fe7e78,55e62e40,372d77be,39f68974,dd32e043) +,S(7dd20cbe,3467a3df,e1eda0f3,48c39e5,7f9c6004,bcc89227,3d002cb5,54bd5282,ec4d2f23,f035d2d5,4cf4c3f8,31772a46,ee922582,8ddfd4c6,4eb6a689,7c1485d0) +,S(359811cc,5acf1291,547b8870,33bda3c3,e4e245eb,db0dbfc7,3a02da3f,12a877eb,ed2f5087,8b97a3de,6ff916f,511c3a27,7702d1be,2b683a59,bb6acd98,e908a792) +,S(fb33e89c,f2bcca4e,4ead57ea,1a24d1b,5a6c76ca,bc605a2,c031102e,49a71c24,c75e02f5,ca602705,7ab5b958,42a9272f,d7fca940,c26e980e,192861d,2f1c9f45) +,S(a1cd33e,5eed74a0,1534f836,b05a5129,b7b2970e,f293b606,9d1ebb56,e5f687aa,f90d1ab9,ccfc345,3b2b60cc,1e4380e9,bdefc37a,896a1abc,c9978d08,1ec4a6b0) +,S(461696b9,3643b7a,bfb383cf,ced8ac92,5d9f169e,1db30999,b8553504,c4213614,674f5c77,5f300fa0,c8f40a85,9aebffd3,ee91c4ce,695998d6,de0d59a,3033bc72) +,S(6c6aaa22,1b589f6b,ccc885ae,93f7e8aa,1fd5cdf2,27471727,f390d5bd,e14ab025,a77c5e03,40e1b90d,1ad64483,fb50fa76,aeb84417,88ca415c,9f8d2cbb,aa077538) +,S(c918d391,927f3310,d032c7ee,6e729e6d,792eff1a,72acc268,3874fcd7,4e61c38b,58fd746c,346048f8,eda1bed0,e5b6cb58,fce24a72,6e27f965,74243c80,780dfb5b) +,S(48679e16,1ca0a3f5,e4ac2654,213c494d,9240c3f0,33fbe2c2,142ec589,6dea5918,556f93fe,300cafe3,e93a2966,767840e3,b2a19fe7,9cf204a9,a30d1f1e,3e1d1a41) +,S(c68c05a9,e46b6440,a72d6eed,eaac085a,5e945659,ac46a584,69968a30,c6e7b858,b8b4b5dc,35d4ff80,be3d64a1,d036a117,c768746a,4d2bf2b6,1b126460,15de450d) +,S(d133ef10,6358489f,8f976dc4,b6c54699,21e3dfe3,6f326dc9,f0538757,9d444e6a,2c66abc4,db690d2c,272b0f57,afd66a6e,327ec3eb,e32b45be,cbf3c502,baf968cb) +,S(53544f59,8d759dea,b10766dc,48a7e2da,61ca0a60,a201d193,92dad05b,3df976ae,449a205e,61cb7aef,204e3f0,3a199ad7,993d711,537e17e8,79a42bfe,2869cd47) +,S(3108a074,fda5133,39e26385,14b6b7c0,9254c65d,ee374a62,2fe34acb,83b8b331,42edc90d,54263fea,8b1a473d,ac2f2244,d6fc05d1,f59e115b,5d930132,268b6243) +,S(1666c40d,52c1c04,d9e95099,aeb55861,2ee58ac0,6b22f962,154cd8ca,7cb4b23c,5065bb41,ae046638,aab55923,e0752954,abafc247,d201e84f,b6c444b1,93a82fb9) +,S(c96d07eb,d3eee6a8,f001290d,f76b2d82,ed80fa90,bbd5ead5,3a572457,ee47722e,d3d69c04,447fb7e9,a3416af1,798b749d,13ba06e4,78a432c8,d00dc2cc,7e20baf3) +,S(a9ffc39,b11b5b05,78769a9e,8ce7542c,647fa7bd,7b2c3479,fce84d91,1d81b49d,bec21248,82e928f7,e98894dc,25840712,80a64449,38e53747,375d2122,68bcbee7) +,S(52ca128c,cd4c9380,8e55d3f5,29320fd3,e825787f,1a600f27,37fc5fbb,f7af0632,846e8a80,95a98cb7,b4ebab01,4d9dbfb9,37ffa493,83676ec3,70f42cde,3135f7c4) +,S(ff92aac1,77fd9927,7b8abc41,e49f7c94,698525,2329b9ae,8e0fa34e,a9407c20,af0d8cdd,5aaf5273,ebbbf2a9,b7230373,dafd9a93,42a47331,a3379f45,8ffdcfb5) +,S(a692a73e,d3c10a3c,38163c97,314d02fa,5fb653b1,d729ff09,a541d01b,27991e0c,722f55a,3e5bd3e8,d863d00,6b82415a,aa05c949,9a537809,cff9be69,e468b905) +,S(d9e59c3f,7a629a93,e32fc4cd,2c98d480,6b813ba6,315ce4e2,e2fc7fed,4120aefd,24ce2594,23073119,4f5bf658,909a47fd,3234be39,13aa8d30,eb08e14f,af0214bb) +,S(74e5270f,7771b109,64991ef7,9abcf05b,4dde8d5a,605ab587,14b8e534,4a0f6ff,2ad861a3,a4a83f09,687a285f,1356b1e3,71ced066,69154887,14bb0461,b3b1670f) +,S(b9169230,1c43f7e7,61a85615,7957c3a2,744668a4,8587ff58,7a201f59,31d4420c,bd36065b,c1268280,4cd818e0,c6515a5b,659ea423,f5b23e5b,ebe1f74e,5819536f) +,S(37faf253,864568da,972d7211,505b7fb2,cd01fdc9,5953bcd8,79239d90,364d51ee,b69ae2ce,749db3e7,e6aea736,a3bc961,d8c12523,6f7be823,65749ead,3bc15f85) +,S(e194114c,4a1c138b,34882477,f0dcd065,1c379f98,c198614b,43b087bb,a20cf8d2,7a3afb4b,b90ae22e,3b182cf0,6514a998,889f2ad3,d71d4d67,89e3758a,e898a93b) +,S(2ce2db01,d3fb451,7388e4b3,c81588d1,1c8b13ef,917333c,ca054379,fa17ddaa,9232da9d,af0e76a9,85e1529a,ed1a5568,74285cb3,8010c922,e2c30d77,367bbbc0) +,S(c292ec48,4bdb7045,3dce2e82,1fea7688,bd66c6e,59635f49,98618f9f,3d6f051f,210a74f0,6b81e69c,4d0af49b,fd153247,12b77736,126f4887,2b119ec8,97b57d6d) +,S(15bcc9c0,97618aef,697b423c,cd83ad3e,933db83,d77b42ad,3e132036,a5acfeee,e9fc7ef1,1bb996fd,bfb3c490,14912ca1,a1bb98a9,e9611c,1a83a806,b88a7a33) +,S(46119caf,50f13bd7,97be45fe,55f2d298,848639c6,99d5b113,fd24cb24,6e1e7785,6a203f91,f4c56eb9,7762cf8f,9ef932b4,ba301501,5aeb1215,b1327a93,842ea3b) +,S(f3a17794,3e4df182,a9549a3d,2da1f9fd,cf141094,5e6b3a64,9d9df885,b6f9ecf4,b34eb7cc,5e82ad39,fc2b6619,859f8328,444a1dff,c82ee115,c80cec10,6ecf7e8f) +,S(cef90a74,84a7f468,db9cbd45,f5b9a0c5,fa98bdfa,50297d67,536075c6,b7913fe4,d090eead,2a43fbc2,86702946,52507875,fb79a555,e5c55737,30fa40a2,6a301815) +,S(21d8a214,987aa938,ec4b88b2,4bfa5661,26c528b6,b9060b06,833c6ed2,a35702ce,c354340d,5b65a23b,c628167c,8a2830,f736dfe9,a501fc8e,94b66f26,d84579e4) +,S(6b18ff27,9049be4a,62a04f6c,f82dbd24,e19196fa,46e0761d,5d139518,3a1ca53e,ef806f0c,52c01367,8f81e9b2,6698fa32,6343f0d7,2522f8d8,6cacfdb2,c5ffa3b7) +,S(7d8ef4f2,452cc04,d5332afb,ea3e673c,bab07c36,c081a0ee,850ae31d,cb466e6f,32461667,55a2ceef,273367d0,df10f6c9,d224da47,f19117bc,137a6244,2cfa0c0d) +,S(c7de1821,55d15649,f5bb6327,65ac74a2,3413560,b1d31afd,6994b488,20d12cab,d9965856,c5fb2c0f,c93b8659,5c3240d8,7fbe0136,11d7e844,48252ce7,96eaa23a) +,S(4cecb33a,915e2c3b,189eb6ee,45fa4eb3,eddeff09,729945c6,f893bd,4381b294,cf17f112,b5e61cb8,44625035,7b700cd7,3534d6e1,3310b6ff,d1bbbd8e,1ea3aeb1) +,S(826cf464,bfce606b,b4c3ab5d,4cf00fe4,1c9bc72b,285c8c10,204aa658,66255749,6ba3b431,527d285b,5156fabf,b150aa2f,6d7ca564,b18011cb,b878e235,7b6849c4) +,S(c812dac6,f497d245,5192ba92,2d6fc10d,de51d608,d82e828e,b2187e7,648f8f62,d02e8c7,73630680,8126ee1a,efaf53fc,2be94dd8,7773e8f6,1ba6b4ab,b08b317e) +,S(5269550e,bd967f47,e45eaa8b,c9f14ebb,aa45926b,6e38cd1e,3c6d5d3f,e0ff8851,a1597d20,26e3eced,443422ff,cd1b3fd1,b45963d0,3086a95a,38b8661f,99a7455b) +,S(7fcfcb29,80e652cf,bc42721f,cdc40ba8,c7c2ae6d,54a51e9b,af1afee7,e84d7676,abf72d90,4a408e34,ec6bcbaa,ac8f19d6,a4d044f5,66a9cce9,f95debf8,882cfcdd) +,S(85f01aa0,4597e104,848e18a2,132a6a07,3d5f25eb,8baa857c,79dc4b6,64a9f451,f7463ceb,8a058187,7bbb71ab,35bcf456,5398cec1,cb4e0132,4b4ec47,e5f081af) +,S(95b4a1a,7dcd860f,ac3fee1d,10febeec,dc1a5fbc,224035fd,a01f8dff,92885628,2a0cdf9c,5bd94467,efa9dfa6,94c6ee3e,1f80bced,23738d97,f70406ec,bef7f772) +,S(4f624a6,24dddd0b,b254b38c,e37753d8,8cd95cac,ec4709f0,49b90ecd,7f6c51c5,874a9a83,2efecd9,2a20dcd,8ccfd454,668de4eb,1b976bd0,70ce584b,c77a4fa5) +,S(39e06912,e18b537b,ce440f58,545e9c6e,a2914d85,698d4043,437dd66d,7506b48d,eff20e0a,16e93096,abc80153,c128aa12,f06c6d,4695bef1,8db7a167,6f352e0) +,S(52edc132,66d67831,74ff4f59,cadb979,4c1d41b6,5efb9310,7a717b46,78f1ace9,e569e202,c6781e3f,e32c0bf4,9684d7d3,cb07cf55,8f46927c,3af6bbc1,c4d402d1) +,S(e3764b48,964b8107,3e287f07,c915fc8d,e4e9458d,6f2a8d3a,1dfa43f3,4328465f,bde2a64b,fb13e0ba,351b460f,6d0d7574,5b7261aa,53a79b6c,3ad5c8f3,4cfdb023) +,S(80efe507,7c77698e,3ec38768,ef81732b,e1c81aad,9c42cebe,75627eff,bcf513e6,690c671b,c54391e9,695e6059,953d3d9e,a9df2e17,5aed4bc3,483f104a,388b709) +,S(484ac7d5,ebcc497,a2f2bcac,87cd23ef,19b0bf7e,93f8e728,5173f70f,c908b641,1d9570e6,f3b17236,9f2b8551,653f3271,5bc8c995,14c2aeb6,1b44ea5e,90ef371e) +,S(9c989e3f,bf1fbdd8,4dfca53e,4415cdfa,adf26c26,3801ff65,36b8fb5f,77e3d124,a34ae61f,5755163b,964b3b80,28fee3ac,2993c442,d7f16dd4,c79aab0c,88212a38) +,S(8b8fb0f,601afe7f,6456570f,19e37f80,32846dd2,97b0d8e0,9308c57d,75a5066b,7858afe,ffc4e6c9,b2e32f10,fd67a1,d6166c72,26f03b3c,240b29e0,e848c9e7) +,S(e37d0e74,ee1d79a,981baa79,e0a5d807,bce0953a,211c00ef,451d9d60,7ee78177,d28a1285,2ad25f4,df1b5625,bfe59875,a07d0593,aab4ee6f,4bd23ebf,b09f8f9c) +,S(80c8577e,9a003683,ad658e75,47657b1f,281052d5,54cd0e19,4b2a9e70,1325c147,b3fd0cd,7ca3a2ea,ec7ba8a0,d7297347,fe2baf99,bcfbbfe4,32a6346f,564d945c) +,S(e7045d6d,34121e5,536f7902,67ae01a9,50f6ba8d,2d05349a,ddeb3833,3ea8c6a1,7306a8db,326994df,e15571d9,c2a5dd24,60b37c2f,e97559e4,e7d88ab8,8a181fba) +,S(55d2da4b,850a47fb,6b3af0b1,3c03889a,d87554f7,cb346980,4f2978c8,652e0d71,6ac0f982,c861d0f6,cd20b7b4,f22eee5d,189a56d,5cc46780,72361e79,dfe16e7c) +,S(ce562e09,55a22f7f,c83a5ff2,11500c03,a1e86d1c,404019f5,5bd1cdb0,b1a38d2f,91de004d,b4aac47b,c6b0a165,edc5f82e,47407032,6f1ced31,4bd6d96b,521bb865) +,S(74e00e1f,596af05,7f91bd64,53107f1d,cd0eb8,6b93b6fe,cc7592e3,7854773b,11ca88a3,38e52a53,eb311867,b10a146d,6fa9f015,11791374,e13fb749,d8e1d217) +,S(ae8f0b6b,c194f6c9,1d83e400,ac92ed97,68214d39,95868530,a2e99f9e,2104eb48,e973fc42,dc0a930,36127de9,eb57cbf8,d4aa8f73,14646362,c855ceec,d7ce4cf2) +,S(40a8c06c,8df83675,e108e0c0,565f33d3,7854e722,6f76b674,1582fdcd,ef891ae7,16ba7850,b5116afd,3d29e0b0,40faabed,b8ff9c09,83af624e,a100555d,887bf7ed) +,S(61ea9e54,5c57f6fa,a2ab410f,861f1fff,926795b0,4d240e48,7f6df1bc,6df83b33,c69ec12a,e0b217c3,72e1791f,7d4529f2,b9063e67,38a8c03c,49071581,da79ed15) +,S(1c889cd4,440caaa4,fcdf55f7,2145fc17,d73e25ec,264831cc,30a0cb5e,c1d37632,41b5246,131fa67c,7314a223,7db5e4b0,574f5b86,11560166,ee55bc94,22d72fdf) +,S(ff295890,791d87e7,982a99d3,ab50bfa5,c58e0d06,25392abb,4ab166a1,8e49525d,a09664de,19951364,19649baf,88806fbe,c370879f,efbe4a58,e619a01a,19454570) +,S(5eb2eabf,cfca1fd0,7c939e5,b8f890cd,74e399ae,d9bdf785,7bca8767,84e95f99,4c42e970,1c9a783c,201aff12,16265d8,1f46f25,fe110f63,31fb8fb,f72c9871) +,S(43e5508c,dbccc93b,5b3f8ce1,7a071c1b,3b17bf4d,8153f61f,cfc7b6b4,f6cbaf91,b5ed8f78,438ba71e,509ec388,d09a5307,c853bb73,db240638,15a07343,9bdfdcfc) +,S(f5d16930,23cb20df,c8607261,cafe533c,eb513f87,7f6e2c99,5b0c0f75,fdb56f53,e539b168,1528332,f7fc4bf8,73e2965c,2557dd40,6eb2c8f4,92ce0dc2,126ece68) +,S(db9d66d1,5dc5a918,46180a62,d662a2eb,72313c6f,ba511eb6,c7fe0c0f,78aba2a1,c96de8a3,61f0dc5a,9e2762d9,2257857c,3cfb46b5,81c3f0b1,f89a20f2,a1517227) +,S(e760d3d8,46fd63bc,4f565bfe,7bf5133b,56ffce08,27b99ab6,833a64b8,868ecdf2,60ee6685,8be2eb4,1821cc82,54062e01,2c1c1e12,285c8381,e60e5d4,12f102ce) +,S(2bdb2299,caca7ab,d22533e7,12e37004,e3a956b0,31da4d99,1351d790,5c33e026,64675cdf,c2738105,dac3e877,e27d00e7,80193286,24cbbf82,a784713f,b6e44731) +,S(1cce0bfd,5992134,b7813773,9fd6c844,7be48d20,e001bbbf,c3c87b9a,8166bee4,2d4a8ee5,1ed7fe30,c3a1253c,4cd9e83e,b5eeb73e,c166f4cc,42788bbd,cad37057) +,S(6d6be3c3,7f5dae7b,ff5b5bd8,ec6b8c65,ec8405c5,bb6575bd,6ebf89a5,77641075,4fd3cc1f,5c6fd3bc,6011507f,7c4eaf4b,24d1938d,35159b80,39246ccf,ac9c2c7f) +,S(d82c180,d96e781d,783fb1ca,8758fa1d,b3c67f2f,143e836c,c6007d8b,bdb22351,3802f669,952aada8,93b3e9a9,74a43218,37415af6,7964b1e1,51a7b8e2,7ad0c7d9) +,S(4ec61edd,7e03fd34,f91dfed1,b546f1b8,fbf9fcee,8c73e343,b228ce18,3db3cd71,e1199709,b5b2e2ec,8af90340,de9ec3c6,db7d948f,aa941cff,b1984856,b03ba9a9) +,S(31aad469,73aea11b,a54744d7,bead13ee,a8df7a8f,8e735643,add781e9,e17a034b,64676f41,3e49f606,3f68bdf5,7ced7486,a94680f8,e60e2913,f13b674f,84b37adb) +,S(a9842189,2fccdb8e,f6515903,b589ea62,1f946bd,97e2931a,5eb1ce4d,4d173e02,50be76ac,3b2dd7a3,a3370e13,3cd6fb37,7ea266d,a566049,abe488a4,89a3908b) +,S(822b54f3,3ec00433,7a6cfa09,277540ce,fee79b08,a50695e3,f8fe0ece,b7bef099,393623c6,20d3f604,7343ddce,d8805bf0,7405d336,fda8c712,8d044851,236bf7f6) +,S(100f6b55,fe3d7000,c5f8de14,ebfc5d7e,15793d10,e99dea3d,33adf25c,15065e0b,d1bb44f7,58c4dde2,7c928267,6d6c1114,a352ffd0,dcec8e51,9b2cd74a,4eecb4c2) +,S(ca5d8318,6a09c227,481aa6ec,d195d094,6a54257c,5adb71bb,2d4e8836,d6142f7f,d890847f,b9747a0a,f3ba0c38,84ae057f,878d8d31,fc73933d,e014f4d9,2677b42d) +,S(e91c25f4,2234d20e,2931a352,f98ff610,e8ffe53f,101b56ca,fa5da12e,24bfbf14,b1ec15e5,441ec52b,c71740f6,d60e99a7,7a26bcf5,143ceb41,872b4a22,964dbb86) +,S(57a8c8dc,310902d8,8569b290,22e99ae7,acb54547,2ccf7065,9e9d42c,1ae34445,85224541,442e09d,f4e92db5,64866aee,50e7cc3f,b8c20acc,b9c6161e,30ab1fb7) +,S(232b8c67,2502d16d,badd0d41,28c02b6f,55a8531d,a6fe87d9,581045b0,7104500f,38110a0e,9e7d8587,227c476f,6549492f,4f5255d9,e618cf39,9a7a40f5,85f93fb9) +,S(7d0be68a,d71f69b3,4f5d4876,319f7e7a,750d5c7,e3dc876,187627fe,77004fec,3e72a050,7d0af3e6,1d6f5402,8a5b971e,a12b1d18,2ca45e67,ca09efcd,45124633) +,S(4dd85f0b,77c2a271,c95fa436,90c43485,b70b02c4,9a46cd83,6ba7a2d2,7af93292,843642e5,c9554d98,48ab6ff8,5dada7a0,f139e64d,2081978e,8c9e3bf5,1c11d597) +,S(537a93f5,88f02004,70b531a1,74ba9a7a,3eb2e5c1,eb767214,9e264e2f,712e52f8,b0d9b3a0,dc009266,8e25f06,71895af3,94efa1f9,78257ebb,3f839b61,340e161f) +,S(13faf471,325b1e57,98ce60a4,6f82bfd1,ab346590,82588ae8,b972b331,9ee48684,a6720384,e84eb529,e22f2585,79b2201a,dce7ba18,845b8bfa,49a21ade,7634f743) +,S(691e24ed,5861b344,e015dbea,809dede7,ca17c482,22d9e06b,e1be4405,cfe8acb8,e3564adc,c197b0f,cc520d90,9d9c6347,5ad00294,3d0f3f96,6f49b76b,91c529ab) +,S(36543b91,aaaea850,15aa394f,fb334923,b754b3f8,9047f73f,423c15dc,7d3d7ea2,73b4693,b79b800e,8e48c838,9218094b,9dff44fe,5a1fafd5,2d68a2f1,bbbe5799) +,S(ff25abe0,394180cb,1e045045,5320ea80,e007bb0,fe3bc8a2,24f20b07,8433f05b,a512b109,26dfe650,e6dbd678,ad9db412,938f69e0,8aee6c2,f903631e,530b7e51) +,S(1dec07b,5faafdaf,51051f57,cd0247ac,cc607bc1,70c53222,72d389a1,7d87e443,7e77e937,382b2bc0,5a2207a9,2598dad4,d870ce67,d0e138d3,bb35094b,9fa9a325) +,S(2f10f776,f62f8632,ea20147e,d14e0919,485ab78d,fc636236,29c2994,9f413c32,3b2c5fc6,e760462e,b9d8c8b,5aa6b1f6,35c23668,33e7ef5a,d25269ec,68d2184a) +,S(7974f394,e61c2cdb,acf09681,4bcafb4a,ade31943,cc180188,31160022,dabd73ca,e1b34da0,3bc1aa66,87df854e,813ba451,2be4cde8,310e4056,73c83600,89e98309) +,S(54c5f39,3c5cc416,56577469,84aa3695,32af1ede,3a51b14,436748cf,1701c332,3dc67b49,49769cc5,22b0626a,eeab6ba,ddbde8ac,ef78a0cd,800c1b6a,5043e4e) +,S(199aa296,f047c7eb,1d8a972a,318585ae,8092e905,e555915d,81c1a3b,425f3783,f5823679,64d17a96,b4ca7946,dfd3a266,585154e1,cee02e2,b87e8fc7,eb46c262) +,S(d15d39d6,fb616dfa,6c292a3b,a1fc58e7,cbcdf0be,7976be87,9a7f088a,9bb7f299,4c8ae97c,4e37f837,bdbd4912,f43bfc79,679dd418,b57d061,f705ba60,2bd7a900) +,S(76d65134,880e7dfc,81a332c6,a04b82bd,bff26eca,9a5aedf5,a6f6683f,364ef58b,b71ae708,bbd22d83,a1ec9048,6975b9a2,7b4aa5bc,5bf1246a,6464406b,401507e7) +,S(1eb4d2a5,d4dffe36,30ae9ead,792ffa9b,452ef0e1,94c06a02,a0308143,dcae51b7,88d978c1,e6ab8e79,9a286af4,58cb3eda,7cc94b67,589b144c,9a55cdbd,6ff47b0b) +,S(dee03251,35708790,361c3451,6710623d,e474bdd2,4513562f,95512f0c,dddf571d,d22dbcfd,cbf6d809,2c68a28d,c118ffec,496d9623,b20667c3,7fc487a,1690f565) +,S(2eb0272d,c98ac6bd,ff68f0d5,5f13f509,bf1dbd9d,f36385ae,ef02356e,56d4760a,f80d4355,4aaf4eba,27aa1832,90573687,5c69ad44,7211f746,111ca02b,26a04277) +,S(eaf62e69,7509672d,8ff6ff7f,c7788822,b75853ea,27636b5,c39b0321,ab0eabf3,442e56aa,1c8fe22d,71b88b96,90733f1c,8614e160,35070095,6effdedb,2e0a3b7c) +,S(2059070a,13d96fd9,6bdc442c,236ef463,cbc70185,b8799d3b,15ef72ae,4592858,bc9042e8,3f259ae8,f6221d7f,46ae56d8,f426fbfe,901b94a2,80da34bd,14961ec8) +,S(ff2ef7fd,9e7f3e7e,6f7b4cee,a44ec281,4b8b4a44,208c462a,f925d27,ad2f52fe,6ace74fb,fa6f72b4,8156cb52,a67f5137,956a447,6b69fe3b,233ce4f3,df0a5e24) +,S(e3e5cef6,fc4553fb,d337a7b0,4357ff1d,d8fd0de6,4df17bf6,20f7f9d8,9d14d83,acddfda1,baa7b60f,d0d1863f,769a475f,e667b6fe,8a047365,1b84f44d,238f0460) +,S(97a8726a,41c02880,e9942341,a66b9c21,a0c64577,bde3c54e,c11119cd,bf57a6c3,b5f37cae,27023d07,78cc5c7,26d845e1,fe160aff,3459d164,681cc38d,8b67b4e8) +,S(ab01e6e9,4862f943,8639484a,119eadb4,12fd9002,1d7781c4,1b020450,9dcc81e6,6ae50c32,101b5c3a,51fab05,2ed79e5,48853cf4,15a30043,6b11ee05,7483b14b) +,S(c464410,da2dcf6b,2e6ba5a,c8d8479e,58ed9a4c,a8c2b0d,5a2ea15f,7673668f,3698c590,62392c7d,e597f333,cd3ce45b,eadee944,5209d361,adbbc386,b499945) +,S(17eacc68,5f721f3e,2013b0e6,76c10795,ee49d524,26edbd86,48f098f4,17867534,cc3116e9,cb19f49,bbf7214b,b3ab76fb,fec0f856,e994a01b,d6b63ece,189ef300) +,S(c040dd40,2908ef17,539b77bd,5befd53d,3ed2e8bc,d7d3608f,2b114dea,d4c00d73,7a6384ae,55ec2580,4d1403d8,45113dce,b2053ecb,6ce0d3d7,427835b4,15279c00) +,S(a5963498,3658f70c,2ec25fed,6659a290,41bf2ba2,ba92db93,41b03e39,2ebddb42,dc114caf,260ec4a7,a8e8bf4,1695785d,1ce7c2d2,82359600,a950ade4,d79f4872) +,S(44fe22d4,51dcf63f,c7e33d09,533836c7,66382372,339de279,9897cea1,1b29aa0d,1718c4e7,3d4bd434,929e9ffa,e2496f79,4f3bf80f,ae805a9e,53b577cc,4c4279b3) +,S(8bd718aa,1358c15e,fa3b246d,e244bfd8,4fc6b5f3,ed5ec91c,ff466a11,2c71647b,172f1a88,ba6c11f0,1b7deb8d,e4002793,65a0a3c8,443b2fa5,f406dfe8,4bd737fa) +,S(8ebdcc25,bbe6aa23,809aa53c,3ff3a7a5,d7ad4cd5,5dcf3cfc,d9ff8ce1,738680d1,5c563b26,af86adfa,c3728c,f886d83c,5be64766,78ac5872,cd798875,45e5641a) +,S(5cf54e1f,688faabc,99742fb8,be896cfa,b469e5d2,feb72f4e,9dbc67e0,e91713d2,d82d6590,d06330d8,2f86393e,190155b3,4920e8a8,86324b18,5694786b,e4fd09c5) +,S(6c0d96e4,3f01a1a7,2ec16ff4,e04571ed,387185c1,4c8a2f8c,db4c187a,85845f1a,f399a14b,763ec2ec,f3415c1b,b9bb6f70,abcf013a,3117ddd6,e55a96a6,b0798c08) +,S(eae928fe,fb6a2fdc,d05f1515,5726a133,9a15ef0b,ea716ad6,90d32dc3,92b74046,bdf87ad9,f086339d,cbfda797,8d6ed40e,f6fd4626,60d6db09,84ecc577,14c76bc) +,S(e5e5e30c,bbe72fde,d9f0dbbd,e08dda,b61d5cb3,1aa688f0,d572008e,447b3a21,9fb4adb8,f80b6e67,47c6ec03,d5171ce8,5de65682,a105435c,5610065a,85b248ae) +,S(711212ac,c9e26bb7,c5ace176,26b300bc,78df6b0c,a79a0b79,7dbcca,138223ee,dc68858,4ef44ddd,9e6b343b,c4c73fe3,6b873239,18e11cbb,dc3aa72a,ef027757) +,S(3b52ebb3,531aa4f6,ddbb9ea3,fb5e5784,c4cf11b2,a4c67d50,6b6340f0,21c5e22c,3da3eebd,dc0046a1,3facf02e,46818640,b698c8a6,3c5fb9de,55a9996b,b190938a) +,S(30f28481,110345e2,7dee7292,fe1c7a56,45294a17,e96cadf9,1eb76bdc,cf56b78b,70c610fc,26ece34b,f047864d,25116fac,3c149164,a1deb08,8e6d702b,77abb049) +,S(4a844a8,12c55b6,4e4d37b6,1ca4a1f1,5cfef527,699d5ab5,edf1564d,e930ff58,49874548,508de6e4,dbbe6bd3,8d0a9ff6,5826f9c0,63274cd3,f3189d59,683dfa3c) +,S(a5ca561e,a7c8484a,642e0fd9,a999e14c,5ce2b5d,edc51026,4519e6c6,7868b06f,cc917942,a5e2eeea,ac09b00e,affa7f6b,7abe386a,241de5a4,7a7c43a3,85afa7ed) +,S(f61b7ed3,1e16c456,c3851a68,e10f614a,1fa547c6,456e57ef,3c1f8ee4,dfd6e72c,cb26d0b7,fc401865,91f5fbdb,4d17bfa6,a0c5a811,4d099a54,734a3280,5f622f2b) +,S(f8e4d462,889700c4,b52859f9,e766fbe6,55976866,a22207fc,aee56185,15f678b2,30bb039f,c1b16fb0,aa09c271,bfbb76b1,6791e95,9dd51ae,6f01aa4e,bac77554) +,S(89cafc1a,5d25915,b2f6f71,71814a2f,d5d97a06,a717a91c,a392909d,332ab653,1a24a0ab,b4e4858,d29c0055,714f34e1,5eac02da,60e87ce1,6fe2f144,257ab76e) +,S(d285370b,d04f5dcf,caa01dca,7a2ad510,33c5b555,6aea60bb,4a48d97d,477c4f20,d4b427b7,32e885d0,13a2adf8,ec705145,c61386b2,c6981b41,6c44d202,4693b9d4) +,S(3c532f2,d9bdbfb3,219dc90d,17aba269,fd335066,e1fd4974,9026f66a,4df217c0,86fd5e7c,a6c97fd0,2c33c7b4,28413977,2791a6f9,f8c80576,75b3e306,66ac5d59) +,S(24d1950b,fc35706a,21b17a16,53037226,2984453e,37e26924,b730314c,cc8ac1ee,4d22a45d,6a31a90,bb247c68,59ae9a75,b05bb9e0,8b57ded8,4b9c1ea9,c9f918ac) +,S(cc6ab0f3,6227b1ab,149f8ace,ea036fc2,d8505341,ab67d44,59582b36,4e7615a9,f9ad93cc,40b1258,67c806b1,20fa6f21,bac918af,54a0f7d7,107680a3,83761cb8) +,S(de24a954,f36e94b6,ca816bcf,f730b99d,6320f20d,9b141cde,f08ff71b,25318cf,3e34b1d9,1ac24a49,b982d235,44afd62f,8475c35e,a48394d9,67904a41,db899933) +,S(77ab04c3,4900aba9,d83a12c,7953cfbd,5f8243db,48fab618,f83ff252,5a1ffec7,6265ac27,3bcd77ff,496265af,75a8db31,231c871a,30a32bd,ae873efe,bcac2f00) +,S(a47af706,5f4699e5,e0079885,d19580a2,51ff8dee,1dab741e,ce84ad51,16e78209,393cbbfd,f1b1f78b,a563f7cb,3465ab97,5b786088,3daffabf,bb8f34b9,7a257440) +,S(a9f5f9fd,c55c7b7,4dd170fb,d0322026,93d709e1,d52a37ea,8a545e9e,9cd7016d,98717925,4badf22e,8fd847b2,e9e80ab2,54f0d327,f6b6162b,8734b105,f1d5e0e1) +,S(d57e9ebc,96b938a2,8fa200c4,e586e7e1,ba866864,a947b71,6cc7cd63,4e18ec38,9aa0d2ef,68239110,5b4c8b7c,b412df87,25de16ea,f28596a3,62a6aac,d1b6bd36) +,S(7463a8d8,fb4dc14d,5618e66c,aa85d73a,e27ccc1c,ab820611,9f506829,faa58e9,82fd6ab2,275af504,aa0645a2,8438db86,ae7990c4,b4c389f,569aad0,68d4829f) +,S(2e7a708a,29c44831,9a02d03e,4eb331b1,3927ae64,534db2fc,a3c6e7cf,d53bf412,84f3f199,73500cdc,aeae0073,f39b3b2b,ebdf6824,ec018160,fd2e3b3d,4b1e11d1) +,S(8707b0bf,540bc058,faf2f3c2,e8ba304e,180d094b,b7fa8dda,414d30c4,d9dd5e03,70b61175,fb791033,50c6bd25,aa0594d7,18db5ee9,9667c25d,fbb49c20,f100b915) +,S(3fdb370c,3ce6cd02,886070a7,28e66749,22f67dce,1b6c08b9,613aa2d6,53ca842d,163518f2,474a0344,a5c4c5ec,10b1efef,5d3a5ef9,94010063,17a486b0,c8e0dafc) +,S(c37da302,412cd549,a01411e7,6f58d4b,33077960,94b31af,2a283d89,48472f62,aa08f287,16c642f4,8702d1da,aa0a82bd,ca849000,b8ad1d26,801c6fe1,3a21f92a) +,S(3eba0550,381ab0f9,251f923b,5c7a339,60ade9ec,2b0b47cf,25726fc7,a5e08a1c,1427b0eb,b681dd3a,88639652,5afc4e00,492a1ad9,a0c5a396,55741a5f,cf0fa7d9) +,S(96723ea1,8ce5d5d4,bf64628f,7754fa0e,e43f20a7,85356e01,94eaf8e6,bb50cee8,5ad09fbb,b9bbbf10,e86eef51,2d448aed,6cf51b5b,b28c8e8a,713066a5,81f49bdd) +,S(d7645211,7ecfb6cd,3a09d346,55d5c58,ab822892,67910f13,29f8d604,a3663748,ab7cc104,d20fde08,2c889dbe,2baaa9cf,bf2c9b10,c225da46,eebb8031,c28540f7) +,S(1f6b23dc,7e0ab136,20d907af,ad4bc944,8c866065,b4ac7e43,4dca8906,d0ada5e6,8c37b25d,6bc639da,ad092040,5daa9eb1,56041440,e48f6602,398ec256,763e247c) +,S(46ff04bb,aa06a168,79479e64,bc0e8ed7,6abb5a12,8afd1f9d,9bd80d50,75459945,b1104ec2,6af2ba0e,39133bb9,e47a61ab,e7e9d229,41d71764,91ef9da4,f51bcd4a) +,S(ca1b3c25,38888069,3b076e54,58bb0451,3bcdffb3,d824af86,f3f4a883,2a597ce2,f02916fb,dd1b6dc4,76109d11,bd9e81ed,dfc9d6f5,79847622,51bfe2,a1e0285a) +,S(c961e9a,adb69ec4,8efec7fe,dcdbdfb0,5fad1277,2b801763,ee747a10,99ece6b4,469a6c33,e0b253e5,270bb70a,d16c4b70,56bb9b3c,35f0a2a9,84e2f269,9d8fb6e4) +,S(3a2ea279,1418cc94,d3f81708,9d44e777,7b3132f5,b9b67393,ea4f28bf,939d99dc,15805143,c035d921,be217dc7,18d13e2e,b981bf8e,6525f88,31a96c65,6bf164be) +,S(416dcdf,b3a1f0be,1a3fd6ad,52fb1c03,4e24d48c,cf34d189,e7dedea6,b65a7a4a,76909ec2,bbc93359,ac177781,2132db31,47e90a0a,3c6ca35b,ebadd113,60c204c3) +,S(b397c245,9aefc175,8ba5177,2d4b3ed3,2ed9d1c4,85d2a2b1,7318545b,93c63eb3,a106a360,30763676,ab418ffc,692043ee,22813574,e3117a7e,4471ccb6,f5e71748) +,S(75c5589b,efd61646,329dbb75,5e809b2a,c1bdb8c0,d29a3065,32ef3909,d40637df,26f3e1e5,1492105c,90ea19dd,81fce6bb,95e60295,a1fe347d,cba27adf,a3e6f631) +,S(2eeecd12,a3517432,17d5158c,439a9046,e4b0dc80,119e58b6,620e6f08,969135a5,e1deebd0,48c58ed3,1b53d753,9c4c5791,13606467,14147707,806f491d,2daaba4c) +,S(a981f091,5d39d650,66b1d52e,5addda67,8cab860a,c75ac124,aa100593,9cbe65d1,4cb09fcb,7ab60293,2d98b23c,96e5109,88d4f149,4f334e7b,66c60040,7d3ed069) +,S(1a19fae3,a7e81d02,a1260c9,a759e79e,545cd869,2666b31a,9aa4c0a0,9bd4ef62,2807d657,8af25c69,e29bf7bf,d877dc7b,79714df0,68ae0707,89c5b72a,b0937902) +,S(cff8696c,1ee7d196,d76f139,2662e776,9b0f4314,99d30567,1952813d,2420c61a,8497e013,8a399690,25c04b1a,136bb816,3581f122,b62b70c1,47fc52c5,e6d16df8) +,S(6817a420,4a8b3479,caaa9582,4d48eb04,9669115a,9e5a5cd6,6cc905e2,1e27ce8c,9585468b,c3377a5c,98725465,35c8385e,8182a0c2,763226fd,95e72937,7b3052ad) +,S(9ceffc84,6e0ecc26,af13eb99,579478f3,7d114b19,59253233,bcd33d6c,8dd9d58e,e01aca1a,5cf8fa1b,67c4d4a,fef1c7ec,51060234,3ea64426,856d0aa8,fa5d2582) +,S(6a6e1dc6,f203f7fd,d9796589,2301e5fb,995a3731,8c410543,835f0edc,d3456c49,2a072b98,98b93e9e,b05f9ad8,6a97546d,83b579bf,6efd3482,f93baca1,3784496b) +,S(7e7bae1a,588d761b,5158b4f0,fb9186e8,8ba3a521,89ac36d2,4dd31d7c,d2a9129b,5198f63b,37995cc7,289e60e5,7d0f8738,17e6bbbc,d40d29d,cc4856fa,ab3dbdd6) +,S(13fc3a8,63deab2b,ed54966f,fa85e553,ffa15863,ee12f9f8,5dc5b35,6bd253,e31c3245,91275056,ffca59e7,6e76a957,a8b77c82,702e5d58,b3b5b577,73821459) +,S(ffe28deb,3f39d917,f6b6dbed,ae89ea4b,e5650326,d148ccb,becbc6d1,16e9c167,8d8a52b3,b878444d,e5385760,4e02b3fd,383c4be1,128c5b2c,262aaed6,9dbb988a) +,S(28ed423,9bf26de7,d0379a88,30fa0ecc,481c4354,1dcbc3cd,44483b0f,5cc57be,192122e2,ea018e67,4520d860,b4b8d859,2d560872,19bd0ac3,7bc0405b,10ce126e) +,S(7bf3827c,7be8c484,52acc00,eee769da,5aa4ca38,2f806d72,76c72c8b,bf8a708,925f3eee,e505529b,45c601fa,1d71d706,24a75d07,1ad29172,6bb243e8,a559eebe) +,S(cf1a7e99,21a01c3,f8ede862,71f7b6bd,2acb5aab,330a17a4,a7be1380,6fce7000,21365a83,7b3ba611,16a3e740,33a3463,5f1e70a3,f38a878a,7c3a155d,59d3d673) +,S(e779ea37,d1517cc4,e36c812,1bd0a986,af3bdd67,52626944,afcbcae9,11bb29c7,32c635ac,4b19775a,a04e2c6c,29c6f42,6472bb6d,45c1bf81,e8ac8015,d78a8a2f) +,S(10309d2b,76b54210,1599785d,6c381d52,f9697728,8e0182a1,638b7f68,f26c2a92,21edf83,4c859870,efb9b37,7f931316,f3abceac,c19b6a1a,438d020,658265a9) +,S(79927b09,701e46d4,2eb2240d,e9132036,f2b6b311,a7140701,813e721a,533a27f9,fb7c6513,a81886c1,a4c75640,36136104,8a0f47ee,b8d2b905,3b3d84ed,3b58920f) +,S(743b4e33,77da3429,9f593e68,3ce24e3f,85b1de0,4a3dd37e,fdd8c73,1528849e,37900069,b5ee63ec,7b3f178c,aae73281,fbba7de6,849e14f1,8164d6b6,742f3216) +,S(d73cd2e1,ce1bb7f,1aacd9b4,9951fe6a,e46064fb,a73acbf,49868605,c4f04da,e6a762e4,4cc6e71f,f5887fcd,6a33ff1c,cae7f84e,2f22a096,14b7f4ad,b253dde8) +,S(3e1c00d3,f563246b,3ff318a1,77b3ebf1,ba632481,47c073e8,ed32d697,95f6fa68,df2b60cf,87d5c129,1036aecb,80e381d,18ce2e00,c23fcef6,b4a72f0d,2d0776d3) +,S(96e07f90,92da1653,e5cf10e6,87526db4,ed90c2e4,c629b221,a32fdc6c,d968053c,d65c1c3b,b8a2ea6b,9ee20ea5,bfad3b9a,1f8517fe,2e5e3616,4ab20787,4dc2bd66) +,S(6d230440,26b1ee02,531cc124,b2e0796a,d27a7652,33862854,d8e177aa,afe1debb,f3a8f995,faa14689,50fbde47,1e4ec008,e3dc6228,a8cfd2c2,5983bc09,ed79bbd3) +,S(8dda9f5c,1f949dc0,314e43c4,9e716138,ad7d4511,a4b06d9d,c76fcef1,e5707781,d0563faa,7585b0a5,12b674f5,db737435,ad9d9bef,ae5ba77,5c78a582,6801310d) +,S(5070613f,98667363,f5eda369,fffda417,b4bf17fa,b4c276c4,e5aa357b,bbde97cd,b20eff,4fe77ea3,4185751f,9b16db86,eb40e47e,486a4817,8a0cf09b,dc34ebc2) +,S(3a4a70f0,bfab1456,b9b8838e,ac1aa188,4986d74,6a9b3a8e,fc792eb0,af16bce7,e4524a93,19168eda,a1832980,c04e8423,843b3e89,82381e24,8bdf5a3c,adc4f3e5) +,S(2cdcf892,183159a9,da9a82f5,4630773e,db5fba99,3bcdda38,b5291230,aab33532,c88ea6ea,c9113f32,85e299e7,42abce8d,fd95692,32292044,e0a35870,757677b9) +,S(1a85928d,f8f15f61,12e0cd6,f33199ea,2b7fed02,98c203d,781a2dde,28955c99,1b3986b2,821c76a3,fe13a6b0,30725c29,534a124,51ebe945,5682ce39,74db4299) +,S(86d14da1,d6b03065,a1520663,41b9f010,dde01966,3e622c1a,6b66b84f,1da1d388,679514ec,764f5cc9,e884a6f9,f38042cd,cfe5683e,1f6e5055,fd1380c2,8399b2de) +,S(e41f754f,bdfc879,43334341,5a5078e3,30045999,7c245441,565d0357,16201cc2,dd059641,c21d191e,dfef119f,492ee9b4,743f5e0,bb3cee47,dcbb0fdd,790e8e8e) +,S(b7ec9268,45b5bec4,79668d8f,4e444643,2946e17a,8338e2fc,756996d3,4475cae4,ab4a18b,b7539e90,10e210f5,779476b4,d945e350,978ec2cb,7cc62e71,4fdda53b) +,S(240fd9dc,f1eade19,1662554a,a25850b,bf3ecfbc,83249d4,56b769d4,b7518912,af03fa5e,e0ba3908,853a3a62,eaa6a804,5318a897,31352207,76a06b08,d104515b) +,S(353c4ec,ee7d3114,979e39d2,88cc3faa,2b88aadf,8f1cc129,a5c57237,875bb769,9fa7ec40,90af4e12,e940118b,ad70ab8e,28e607b8,5ae33cf0,2a0da4fc,d12d147e) +,S(f4eed58a,a8556688,11606ae1,1628fd1b,89340988,cbe0482d,39e80376,2bd933de,4278cf64,fe74e070,d071969c,a8ceb40d,18b40bfa,52d7feb9,1606f0f8,df3b3d44) +,S(698ffae2,e2d02660,434c17d5,b5552d4,b284f0a,736bc0fa,1a1290e,266ef1ce,1966cc8d,7845b74,1da7e53a,496fc12f,8bd50cff,b0bd143f,ab608198,e1ffc970) +,S(b53b596d,5c88c140,d6e0587d,417c8945,22d884a0,4fb596b,5957121a,65314098,ddff60b9,9befe76,c87de485,76c32eec,25deeb70,4cc19a56,77197ae8,8f2c745a) +,S(97604b21,d4393bf9,d6e4cba6,7e9f2768,79151865,9f626d65,52712fb7,1a13066a,e7aef384,e1cf7f7c,65c5b0d1,7357f266,7d871c54,fa027616,36062623,4a8d17f8) +,S(7a35c9ba,6edaee60,312b234c,1062f7bd,3b38760e,da1d47ed,b63484e9,51bb8623,33897a7b,a4546761,6ae92b58,6ef704a0,769f3a57,86ef8245,7ebd6a42,4d84a5b1) +,S(86d40c75,f989115d,ca26e0cc,9263010e,c9638b17,86707e01,b6a20d95,d1e2804,759bd762,4ffd8c1e,e71dcc8,a846b5c9,dddf2842,c4170410,c0f38742,ec315ca3) +,S(603bff47,9a4bb79f,663ddea4,93b90e5d,fc77f6e9,b2a401ce,3e8deb31,609badb7,62879fc,65281aaa,6aeeefff,cd33a02f,358c86dd,dc03720e,e1e23998,9da4f4b4) +,S(5c8b8f3,c7dc7a7d,721e0bbf,8a75a36c,fa13ebdc,14987d7b,5dee68b1,32203ed,6b601f38,2bc4c6bd,7d9d304d,88fcd6e5,3faa43ca,141bd90c,e7749340,ce08e7d3) +,S(313c1ec5,a91694c2,41e7a55f,f83b7378,25a6f27e,90090505,a7963ce8,7544fb05,9c3153ff,9a4365fa,fb644699,bc4462c5,1ed858e,24752e59,82566037,103c6384) +,S(51aca51,4616aefb,30268cb2,968e0fa0,150b4bd5,a79746bf,98b01543,a9d923bd,7c51f9b4,73a7747,bfd63ca4,f4e2b361,a0a66ec4,31df41cc,203457a7,4ee028b4) +,S(4ae8d399,27ea0648,4936d3f9,2bbe97a9,353071d6,7743ca12,2ab7b6c3,2619677d,f9dc519b,c251bce8,38ea332b,9110538,f350f5e,4352e7c9,19e677d4,3c8a47a3) +,S(6bd1c95d,3f9cb5a0,8c1a054a,884d4bbf,b100c289,c4af257b,aa0784de,a256dcca,7936283b,de39b12f,6f71fc40,1b07de78,80192357,a8887e71,39654ef8,6b803b5b) +,S(e2278a29,4642caad,ae370a62,e07fbbcb,5737f700,9ef9e8ce,19bdd283,aa49480e,43122fcd,f3943ce7,35b570b7,ed82f61d,87bc8b5,83d64f77,b36f143b,4837dd01) +,S(68537cd5,9f9469fd,d104bb01,93335830,8d24fb2c,b22471f,feef4ac4,fe96c644,765360ef,41107a51,dbf99ff3,26e3b19c,4003ab45,979de4a7,32063c81,8400050e) +,S(5ec9ffc6,69c99f9f,8f8a0735,fc088824,70be08ef,3f81bb54,b1290a07,765af330,abb54008,e76f8716,78c3229,56b47c0,1f4f1cdc,dd1cbb38,1a421397,1163b222) +,S(4e00188e,5d4930fb,a9471aba,465154a1,1a330f6,15cae31d,b2399874,704dfae9,7e76f30,282436aa,73f656dd,35b40209,5ed3fe29,d2086bba,57fbb81d,4d317868) +,S(4ae347a4,d480152e,ffd39ede,b4c2f3fb,a2659ce4,bd3b6e3c,8aaddfd5,f15ed984,383e2f46,d44cfdf,4fab8ba7,ba72c635,65bb6ac1,f35c7307,ca2c5c3,62d4e523) +,S(32cade24,a8d3ac0e,f96d90fc,86509a5e,35fd09c4,d8f7719c,603ce1b8,9c6665ef,87273873,5c63b137,5b63c5aa,6ca89f9a,266939f2,e0c936af,55c10d0a,fb8bea36) +,S(8e4ef195,60147576,6ace6891,f87c22f,20c703c3,d4f7204f,5f422444,51cfcbee,2fa72e3,89d97c1b,79eda0af,c00fbcfe,cd5b9d0c,c949c666,459706e,6ed47af) +,S(35fd575c,4adc03f6,c4d54991,18607a01,559d7316,9efc2509,aae7e7ff,a4a2c30a,f9a5779d,274881e7,cb700926,dcd10ac7,dbf3eecd,9c948aa1,3474add1,ca48e000) +,S(932e4c50,7fd02595,148929a5,2c4126c7,efc12f5f,5f5db287,3c635fed,c90a9cf6,ce6bca21,bbaca19c,29f6b1b2,4d1982c0,9e84effb,cdbf1f28,75f61ef9,ba8ba783) +,S(cad8de44,22a051c1,be36a37f,2f459707,55d3e2ad,35debfb2,11a45d73,49fbea11,48b0df1d,4f6669f2,80a41c90,34f86f11,308eebd7,8a9fd3e0,53323a66,f01c347a) +,S(9fc7d304,c847fae7,d016aa64,6cb36383,1919ffc8,fceb757b,462fbe90,6c9594d6,dd17c0e1,3bc6a187,cda9dd38,a7afdca4,1963676c,e4d4bc9e,516e3a45,d9860ff) +,S(41ba6cdf,10d4a05d,c6865453,894debb8,8300e4f7,4c17c0b4,c8935761,988b5849,7eb62b15,8c3f0965,e571e278,b2833321,ece57e84,cf153ac5,9309841f,e47ad4c5) +,S(1ff9fe5a,aef36ae6,a2d74248,cefb8693,d5bbf30d,f057e884,b227ba44,11c7377b,6ba24b6c,585c0038,49c9cf41,fcb55f09,50690850,5be64692,16520575,f1e74278) +,S(299d7c44,d706d29,e6d9d070,4856c272,6d134814,1f8f7ebd,893f38c6,cbf5d660,e4a74f3,4d0374e0,ca9b4887,76de9acc,62f7d1ff,9b494040,fc85eea,2d03ff32) +,S(a0333ed9,ec1c987,6e318ceb,83d6e93a,b607c2d,cea512d6,9f7b2bfd,72e3a67d,da7dd365,5f51769d,35b37393,21fe7b50,19f83e3b,b6b8941e,d685919,fba0539e) +,S(5a4412a2,2e52a330,534093d0,ba96865f,2821cf01,564ea0d2,e75b84fa,404251e0,6a4788e0,7e6c570e,8390bc0a,b06d293b,3675ab27,54eb700c,7cd4078d,8f0e4313) +,S(d772ec4c,3b141dc6,e534ea6,a69f9b65,783351d,c2fe7cdc,3e823cf6,32b7b0b5,bd93400d,1036487e,7090979d,ddab3821,c9ccd92f,db89bcfd,da929be6,689ac0df) +,S(949782d2,c7694c3b,ffb3e1cd,6e40f807,d4452fa4,eca1321c,d04a2367,6df89336,e7c5e67f,b8ba22b5,4372e5db,bcd63c55,9f4e2c14,c97bc930,b68d459c,bad436dc) +,S(7ee7d5f5,75e6f59f,3e0a9e4d,4c49c71f,6d9ca0c8,6177470e,2334f616,a457e6de,4462da9c,76123e66,c9074add,76fa310a,9cbbbe02,d6a07d01,97e732ee,d7d9f3ee) +,S(7a4b630a,e08d47b5,b785ba7c,15417951,8a554847,bb8320b,50faebb7,b13f843e,ca24e44f,b86801e9,7163a524,db4980de,69a3b219,7f9e5dc,6b5d7076,9d937c00) +,S(d2d90a42,428ac40a,40aa5503,2bb623c1,3a18eef3,2994f793,9c31c6cb,1aa82b96,75852e33,2367d59f,30039e06,40b1e0e1,394a3b6e,582dfb66,7464d5a3,f234972a) +,S(d92499ab,6206dfb3,da1b5606,62ed4f2f,a4809b5c,48349b91,340e0b16,e95d13e0,423544ed,26a4fe1a,8f940074,993aba60,fa4dfc64,be002941,11f29b2a,b271be38) +,S(ec0c1ec2,58875e66,d24e2d31,5b7ff87a,bba6f2be,6c6bf4dc,8d5830f5,c5d09a23,e526a7f1,648abd18,1c49a237,e608bf79,8b798c98,75804d7a,ee8ba416,28591421) +,S(69380968,835b5989,885b4805,290ea050,3a6ae508,17798c2e,f30e1009,6bba8863,71bea39d,80f0ba63,45297137,a14d07c7,7522df75,8192f345,a6170f5e,2f11e5f4) +,S(d66b1da1,9fd1637e,44cfe8d2,e1ff2fed,15a40a5d,f596c62b,ebbadc8d,fca9ab23,68cf64eb,bd2b4bb7,1ca17c4e,607b3315,5cc5d91d,26583b68,78a69476,586b9946) +,S(9dd98ca2,c6fa62cb,92750d70,c9931641,5036475c,a6b59695,a510dc88,3298c95f,55a88bb8,53b99cd6,f8d278b7,e63b31db,40750905,d98ffc81,87a0e07d,acfbe821) +,S(1b66bc2c,842cf1bb,ea4ecccd,c1e2d71,4efd848c,db7a9b92,5b9a9ade,d141bfa2,fe0b4701,55fe82b8,af43d88b,68423cb6,402b3501,8831ca89,ddb9a70,83673bea) +,S(b280dc4,8a9231de,d396a61c,2922e003,c7d2d5c9,f0e8312,c1c075ca,c8eb688a,81b745a6,a2f8be66,b32cb3ad,62babaf0,498c8261,531cfff7,da9ce306,d2738a74) +,S(7bc5951c,9eb3ba1c,828125ad,510e2e92,413e906c,f015680f,8cf1cdc5,f18a6b5d,41b905d8,480ba8bd,b8a6fc7f,49adc6d4,fbda2f0,ee229a1c,d43af5a6,98352a07) +,S(69ff74d1,2318548d,76a53095,25ca8695,11647908,dc4f2ea3,4ed2c53b,f6eabfc1,f3a3e628,8eb99f78,12eaca1e,b3adf5fd,1d617397,dcc95bde,d4be775,afde2419) +,S(5fe6dd3f,1f6d3a5,9fa8f8cd,de7f689a,ffa46098,aa0f03b9,2c552e1a,c84af209,9eeae901,acb8d022,4ed197a9,15510eaf,f356cc16,274a1aac,d6dbc74f,60dbfb55) +,S(469e9122,cb0475db,7469fafe,9c53f911,d3b52bc7,8cce23b1,21d22e59,c505f5f0,fe7487a8,38b2ba6b,f5a5825f,a4d22c26,80d8a580,9db637e,cb84e2fc,1058d812) +,S(1f4a3ebf,6b62923,b2df816e,8b30f8e4,72a5e718,70c1cc1c,6d63b4d,9160e6ab,98da1295,7602ae19,89938bd4,298a67d,1ebeebde,88706d39,b77c6a61,4dc89e2f) +,S(d8ea95fe,1c12ff0c,cec226ac,26f510a0,4117222d,d0fa4773,c2f78ebd,53b86b0f,155bef9e,dde6f293,b88bebb3,ce92c249,f154b59b,a01d7f5b,25fef472,8c6288d9) +,S(1ad8a3c7,97b38071,2214b2cf,87045300,2bb36f5d,dc7f2527,1797bd4f,1227cac6,680a77aa,3755237f,15418957,6fcf51ed,58398c5d,4d56a1c,cfa3c05f,4857814c) +,S(ffea7104,5d1d26e,d942646,9f0b0f88,355540b2,c32aa92a,3fdec318,24fa7d66,eca244e2,2d8da06c,44ec8db7,5702edd4,81f67af,2ca64ed4,cb5d04c2,2434eac8) +,S(4ac55ba3,f7fc8898,54a141c8,cfd6f675,d3abe9ba,55d90f3f,c1764ac8,b959d8ab,9c7b2b91,f135fb7b,fd252d14,118b104b,714821b4,1bd879ce,15bbc93b,f8be2bd2) +,S(5f814467,7aa9a4ce,f29de0eb,865b8a02,bc7061a9,ca525536,fe27af50,bb718ac4,bda965dc,4062b26f,e6434071,6301fb02,2b8cb894,73e39b36,69acf101,90d9c042) +,S(f372cb04,37917498,4b29f213,5981f32,da5f96a4,d1acb903,88beb154,75dd88bb,82d68f5c,1e62d500,1a0a0ea0,7694194c,7ceda2ec,e32c4efc,b2a0ab46,1a367d89) +,S(fb12bc5,45760478,36313375,3fbfa4b2,878ec6f2,243e2692,7a3c5320,bb59b128,3f820118,67dae1b5,bb5ac0cb,a24ca681,96193077,fd7bfe17,a926be5c,4953aef5) +,S(3d9759ac,918a4a34,f4307560,17a9747f,4adafea1,b0a92447,316ff819,60c0ea07,cd9dbcf,6d6a330a,b671d5dd,aa96497c,caa317a6,77bebecc,6fca559a,56018aaa) +,S(eae0aab3,699c521c,3fb49be4,669bc7dd,9f476fdf,58e42909,84455c82,fe3e00ce,badce8dd,450ee7c2,99b77b56,25e808a3,62c7ef1e,11e30bdd,9777fae1,4f17259e) +,S(fed252ee,c2c0ceaa,57625d0e,925ee5d3,43718a7d,24ca3384,55e0abed,451eb851,66bbb6ae,56ceefcc,21d66b27,70756f64,dd07211c,5cf0bb4c,457a5a8a,e82c648f) +,S(da639ebd,22ac3c1,417fb04d,3bab0b22,2362af2f,9d3013c9,bc08793a,2d7f9dbd,83f27620,55f1e9f2,fa74ed0d,536bbe54,3627aaea,3e7a031c,10aa7b4e,822466d5) +,S(524d24de,d77345af,4d4d3ac6,7c71df91,32ced2a6,acae682c,e097cfc2,7eab90dd,e4cf5cf7,c6927c5c,31b6f55c,90fe7cff,2d010a00,887b3b01,b2f7a074,fab7f5c2) +,S(7dac2ed5,fb52b60c,35c7cde0,c28617b4,28672da4,5fbc21c4,b24c5268,54ae4f94,cc6acc7a,e9168866,70b5c4a2,bd2466c2,f6cc11b6,d282b09e,a578ee0f,e7794038) +,S(5f46b64d,da61f59f,6b99d10d,e9291a,887e5d9c,a3893ea6,f7c51cbe,e56083ae,6043d055,da252655,506dcfb9,c5572929,9bfa6ba,7e1b582e,5ee1f3d9,e283a8ae) +,S(8863ec33,b6a25f21,6e641ec2,b8c5df0f,48ef0fc2,38a7f635,175961a1,7de14aa3,9d6618f3,1e52581c,2f829277,7490655b,45b2a583,da0ff7a1,17dcb12b,eb42541) +,S(85403446,3ac459ce,6d8184c7,ef26f91f,b377f3f7,3e92ea03,a1bd6a68,33a2f9f4,2d1f1296,8ac56499,b252a5b1,8313fe35,8f7719f2,3b0c9430,438f7278,c5b399cb) +,S(bf6b3f6,217e412b,fe651dbc,362266b4,6a325d27,5eb7f201,379cadd6,5e223c7f,a1160954,c14aa455,fb041e7d,ceee3ded,ebfad90d,6af1beaf,a9b1aef,97ba748b) +,S(4b20202d,3c186135,4aa079ea,409aa4cf,860ca219,8ba1bffc,77124e5a,bed9e59d,9f684503,c107c0b0,ba5d858f,2f11d904,7703eb45,510602ba,b555e8a9,f5b8873) +,S(4087f880,6d679a4b,3a24f533,127b5931,99c050f2,627cbe28,2686a5aa,6421dd2,4838ad84,b3d9d488,33c8c883,698f5a59,69880041,589f921b,5a5707d2,bd88e8b9) +,S(15a79287,cb2e7406,a2db91e0,5a4fc34,53877504,c790eac7,66d9131a,fe97b79c,9f4ef322,76572e3,d3fce497,c2c6160f,1bd597cf,b96a83fa,df2a41a6,b94a238a) +,S(1c4fa063,c0524bc4,ff233d61,bcb3d40a,404fb10a,7e222812,2739b343,e3bcecbe,2a8561ec,a2d82eeb,97209e9e,bd730b2b,d39c90b2,bf4d0353,3aa8c73d,62d48bd6) +,S(a0708ba7,43c1b2c5,267936c1,85312f2a,bb50b8a6,d4886c26,56d163b5,adf2a636,958f45f1,916988cc,6c9b8155,12e1d2c,7dc66a62,359a4324,5845e94d,371a20ea) +,S(d7960b4d,f01a42e6,e109d71f,2e33ffd,9b79754,b129a858,c213793c,e8acad7d,8caf19aa,5a841d2b,61c3d0e1,dc65730a,33566193,63118707,d81c1e19,dbdeb920) +,S(7a03dc6b,f8ba70d5,96e25ba3,8fca1b32,a7c4506e,6e8a3789,daac3240,bf8ba611,70f19e22,292d6856,5a63e378,b773e170,48a3681,d096b881,fcb84a4f,7f7d9028) +,S(53a9a662,a8fa3411,c3989850,c6c83aa5,da516ca0,726fddba,c2f38f25,c7443b97,5deac250,6179c31b,f313279e,844d1e5e,2adcfdc5,b803036e,140ff59e,3945e25) +,S(86b946b6,3dbb0d86,ffe69af6,3c1bbaa9,b7ee99b2,876836f2,a450d9c,feb2cdf7,44407783,d3d0e2a6,cb18ea1b,a1e4f133,7cbc39c0,19997a62,ed74b598,f74b1fa) +,S(ce81cf5,cb884b46,f6956726,20d2423f,6b28c8ff,ba71d9ba,bef152e6,ef752d8e,75afd973,8120644c,349bf924,c04c1aaa,979177ff,2890c926,2d0b5404,5ea9248c) +,S(41106e41,3a464d2d,9f86cb9e,47d57d47,7b791d43,133a2b8f,bc6ce92d,e1172ed9,e2ca44c2,30e920b8,5601a2,773a0f88,2ce4e42a,7379b374,d2ec6fa1,f76741c6) +,S(e9c1f2a0,4e830a12,e546541e,c7ac6f6b,bca3f1ca,2052c152,4e141b4a,20b49777,51df3843,8dd12c2,29973fcd,516712c8,5ca73721,f5d50308,86b91f9b,32a58124) +,S(8bb9e12d,c5e8ff3e,4ba25775,f1552e3b,9be21f27,4250d511,fce5cf15,e73bbf2c,8a822b7a,273c3730,1c24fcf5,c19c4de,b4d0968a,bc23962f,91ef11a8,d00d1152) +,S(b0058ef1,da227791,e4694c3e,ef66e031,697f3f3e,297d139,9ad597a7,acb6bd0f,7f5bab4a,5793814,d8c0bee6,8ffe8025,e5deb644,7d2ba978,c805b2f0,be205a2a) +,S(1dedd42d,8df5fdd6,52e02b78,4dfcab0,6dfc3557,4b8725c8,db95368c,ac2522a5,3055a449,23730d25,18ff4a8f,983b61b8,24b918de,f357654f,5b46559e,b6bca540) +,S(761a5248,c6794ba9,3f45b0b5,12bc39db,e471813d,9d5c5f7d,a46f2ef4,380ea544,185ded30,c4f5ceac,5e18d0a3,95ba8ed6,9f703408,5fad1fc5,c60d10b0,832c1292) +,S(f1d5b60,e515d0cc,8dc20982,a13c1b5b,a1749687,501a4f2f,fefab898,e3aa5caf,55fd766c,395fd8c2,173a9e4,8eb63f07,ee6f9ab7,54994708,e42ed9cf,78a0d91d) +,S(569cb44c,9b7900aa,576ba0bf,61c4455a,fb09ff4b,c30242d7,fba993fd,bb37425f,dfdeb8d2,ff1ae3d4,1e78f646,ac7dda3d,c1131de8,e2566d0,d3340272,cc350b1) +,S(3e59b69a,d99839e8,51947a78,7d8f850b,9c2dda11,7dcd0776,d22c787c,ba1851eb,732cd2a4,8bfeb030,6bdd9358,37ec4f27,7050745e,b2c9f6d4,34cd8834,592e20b3) +,S(a46d6621,7b45682,98250240,3fc0886d,81acec57,32c3087b,e6ea4c4,95296967,140cccf4,29a5b062,24097a73,f9a8208d,46147884,e6127464,51acef,b9763d33) +,S(b920e59c,f25c53ba,7c00c427,d1575c9c,4ad70efe,daeb7927,74d16c46,5079ab1c,606160f1,d4ba888d,1d5435a6,1656b937,9201ec5f,37f585c9,d43197c1,f045b67f) +,S(12cf1ae1,e7d837b9,eafda1ef,db270db6,3b88b6d9,8d05c713,896e06b7,f8bfa8c5,e0d66613,181b934b,9f23d7b,e9cfd8b3,c4c1d66d,485075d9,1e8cca69,39c99c0f) +,S(6aad27ae,a4eaca2,e60620e5,a328154e,eb93a900,be13a302,87ff39d3,8dc0ec1f,932155c5,caa21539,e27e8cd2,dc57fd7a,d4681474,342c0811,2fe626bb,94a1f46a) +,S(134cd94e,7cb166be,82b48916,6c06c1b8,8d168bf9,21f75c36,ce9343ec,acf870a0,42a673c5,e956fd45,e82a51cf,ff09a399,2f7c8fe7,e73d14c0,fab88c3b,9453236) +,S(d5dcd58c,7b7cc786,8c42971f,a1c85cee,429b1d18,dca68e2c,56d9f5b5,5a3989ee,e0ca4130,ef1bcae4,ecda0529,7a338bc7,45bedd0a,f0bb75c5,e316624e,21208100) +,S(951d6534,c344908b,905fa4cd,b691f33b,3e3567bd,1538a861,f66ac9d0,e0d8c8e,eef35922,eb847928,6681a990,345255f6,95a5f691,9a7d79f9,d575f306,ed7046f1) +,S(cedba44b,25f7964d,76d84c9c,9b521156,690af0ba,966ede27,b33665cf,c1cdd0fc,806a9049,cb8e9af1,d187b6b6,493316b6,187e7124,91a8f7d9,4c21b79a,87c79e7e) +,S(4ff03660,d1306bee,29abd39d,32beca15,d1c7d2d1,14492a20,49c6f4aa,d8a10b54,c2c75e69,8fd89951,e36e8bc8,be71f689,4990f25d,d2ff1893,d99e2773,6d1e574) +,S(c08bd508,8dbd6465,e87b7702,dfb7200,c78061a2,683b9824,389042ce,ce2e0ca7,562019d6,1343497a,b1640884,23a9f171,1db329b6,8c63e78,41793255,f88d7307) +,S(48dfdcaa,6fd2ceb2,3b85cdd2,28bac318,955bdda8,274a1e3a,7afd5db,4bf9857d,2a46622e,896167ba,5154e76f,ce429554,af60f4b5,1431d171,d55ffa2,ea0287ce) +,S(40420900,d81af883,cbf76b47,17025382,802c1479,a33a3cee,bbfacff3,16a1f236,866044e0,dbbcb53b,308f50fa,2b54255c,7831e96e,f19e1b4b,e4168d1b,7b85e3f7) +,S(96a3747b,23b667c7,70ec2018,4e99208e,ec1e3142,3b1156f,8b12f37e,322bdc42,67b0b3c8,df8c4647,3310b04b,ad325d6f,dc7545f4,a4a07af7,98c7cd86,3cf22ab2) +,S(cf07017d,e4037969,24361f0c,b151484b,f1db3e91,a8d16784,5039132b,c8460182,b7a1b107,62f29e30,d0f6e762,f6940638,e2eb60c9,e65ad067,99b1bb39,3797939d) +,S(12b5b8b2,5b0bb6f7,ad1b90de,d75fdd5b,93507aa3,dd7276dc,805cf5a,218beb15,5d3d4767,8cefa19b,80ed6368,d40ca199,5a5bc165,b3609ae,e89b56ed,b78933da) +,S(879b449c,e866e6d9,3998b9ac,e18b6f19,77ecd299,bd9b727d,cd99c37a,13a46765,b0c480eb,758cfb12,acf50c4e,91a8d9e5,f0c45215,f03e6bae,c6c13a83,63781c63) +,S(2ec48783,e9d3a01d,d1fa401d,d3fef249,e502280c,cb36d21d,d2b7b90a,cc7dead,fb029124,78f9e2ca,1a5e6150,5eb469a2,83fd8f81,6798703,ca2f0c7e,85a67fce) +,S(79cca258,27bedb07,39fe8fcd,2145956a,5b7878fb,bd873a83,aee22093,437c3ce7,ff488a93,d82e8750,14cb7c48,3eb74b30,bee990b2,2c1915a8,d3381cea,9cac467e) +,S(c444a4ca,3d2b8b7a,826b9eed,40616aa6,8e146a80,d49a9cd9,3e93cdd5,5adbd207,4d1368a9,63d504c2,541ae338,1ded0684,ac00ad0f,b8fc3231,9d1fc273,92d0f18) +,S(3ee47c50,cc0e44b2,5864e205,835e8d6,dbed328a,60493c26,7ee5529b,cff3e7a8,fa555339,56ea87b,c3249640,145e243c,b6229a30,3d1b91f,84e1ca9e,90a5f095) +,S(e963c987,3036bb7f,422251a2,9f9b0f47,8e69e2d9,2d1920a8,1c012d7d,c809980c,ff95bb0,779bbf2f,1242bfa4,880b173e,140f92d6,c7f8e5e6,18027a3c,55c52fd6) +,S(aaf6075b,b6a1b8b9,afe4b747,a46fa394,23738e50,e686c8bd,3f711cc6,548fc07d,4cdb0aec,6d11ca1c,1e85bd16,2eb411ea,53ab326e,bbdf898b,1bbd5219,aaf2b0cb) +,S(691e4817,d8e9756d,8e174a18,d5d708aa,842b44d5,ea921298,6e4c7585,4157ac0f,9eaeba0b,3bfa7ad7,80d0eb15,72f92873,4bb9a8df,29f508c2,d1ff4076,a0c0c222) +,S(c3e6fdbb,45af4a48,941c9d4c,583dad8c,c77dbfb3,1caf3fd8,1d9e087f,e744996a,ca998d1e,65ab29b8,fee07bfd,1ac4e979,b869474,b5498a73,e642bc9,608366f2) +,S(edbd6320,a55d25cf,21f2630b,e7c5c996,923eadf8,333d386,8cec00b3,940701f,d65192e7,afcef5e4,c88cd12b,fe28f94a,5e3d3d50,f6b2c3e3,f7a14243,4de4889e) +,S(c959ed83,a80ae0b8,ac2fd249,43c37412,b29684ed,9d4d85da,d7cb4c34,ea95d336,80c1dabb,8dccf252,ad8b0e97,25970c1,4de5f58e,12f7e5f,8b59a2e1,a72b168b) +,S(778cc574,471004e9,d88c9022,4d2d5cfa,2c5bc6ed,da64a312,74e3df83,3eed9237,eea23d31,6b2a1c02,7b92e502,db921d9d,675720fe,51cc3609,46b2dc93,92916c17) +,S(a1f87438,8c3656af,43f299f8,1d98d2c0,173e7e46,d3fbed9a,5c2afc96,63b42055,10bc8443,820d6c5,b3150e79,b9936785,5d874afe,dc72a84e,abb987a7,d56f4afc) +,S(c8ad7f0b,2d5f8b8a,cd9a1839,c3d043ee,8f7fa583,7540f6a3,d002091f,68224a5d,3018b580,eebe5b9a,2d1507cf,18a7fe4a,2a1cd4b5,1157dec3,8e65f191,c7aebf8b) +,S(c25d5264,b93fd7b,b7e4e426,1ae767f7,1ecf3840,a2a7ad20,bea810db,4820055f,fa15c8c7,6e3f2b0f,a29fffbc,eb48ed32,bf331aec,3a147524,c349e8e2,465ad684) +,S(d0b972eb,7e4cbfad,baf224dc,cb2d873b,28316877,88b5f2f2,ccc62bf5,e978f92b,ef5d3ca1,606a5852,aafbcb4c,f23e787a,75610b31,8420bf56,e94e420d,f7ab8e3b) +,S(f8b44c83,58564479,6448791a,b98132b6,d393e851,bbc294ab,56c8042b,1b0a2d07,c28242bf,42040be,e9851362,fc8e764e,2dbe0c01,d5bb0ed0,b8e1edfe,e870a27c) +,S(e7cb8901,6f72aade,39410adc,12fd1234,5d942419,51a6d36,8acb7c83,da5666b7,de367522,46b6d9d7,efd4ee6c,53a1656f,f0c87e80,cb0f8f63,95341c35,d6b21697) +,S(8b2128f,14e3f4aa,92e89478,64c5eaf5,f40f93e4,95cce167,fb2c7424,c279d87f,e7ed384a,f469b4b1,1812068,a830303e,699926d5,b8304c11,cbeb0e49,cf5d246) +,S(f34db5db,3cbcd586,38b6a5f3,ab5b31f4,1f3f631d,785e8317,658408f5,93b4afb,dfce7372,bb2c8466,fa31a1c7,4ffc1ac4,5bf11263,4c98ef2d,56e30fd5,c3dd3d9) +,S(c3689e09,a445d685,daca48ea,bca533b9,10b4fee4,dd251c86,a965d5c2,ecaabdb8,7804d05a,6a263fbb,c33efbe4,f4075d1f,d62e187e,3a5917a1,55c1f22f,1679e3f4) +,S(7ff995ec,f776a10d,7a66d62,6095892f,f1e47d4a,2b47ca78,d708a0cb,3f005cbc,edcdc774,5f17e430,cdca4d11,56d08288,e3911d0,e92999f5,cd5c5eac,ca6ea90d) +,S(3662a262,62234bf9,69b18351,2423ebb5,db78bd6,1cfca8e4,1c0253ec,427d4d27,88a62042,f07e69c,f40f671,ccaca36b,d550ef9b,79b4999f,c41cabac,1c2e1b09) +,S(2c127c2e,6d9c42e,970e66ee,24a07388,b6b4ebe9,1614b951,1763b414,3f54e8d1,a4773eb8,dacbadfa,afa26c8f,f4adae30,856be023,6022d93a,aae59c9d,fdd6629) +,S(c420ffa6,116f161f,fd94863a,9fe30b7e,b7dfcb0b,8cf9acb3,7f6d6515,4ac17802,e6cc469c,25c68f6c,8499e9cf,95eda8c1,7fd76d97,2ee8fbc0,79b143b,e50a028c) +,S(77896743,220343dd,58c2f06f,d3217468,34d386a7,e7fc969b,50c77847,eae3de0d,4350d59e,4408dcd9,710bcd7d,629e92a8,cd906759,627921f8,57054a4d,21fd9369) +,S(cf7ea42c,1a14dcb4,3334f9b,636ff0f7,7147688f,19133c83,dc127139,349f5827,b9c02c80,166bf9dd,139c2846,895e4aa6,ad1a689,66460a29,f8e951dd,d99e6d9d) +,S(d1793439,ab1fabdd,ada8ab1b,33c9f96e,417b1c84,7f753630,9d815fa5,a673a91f,ac13d659,3b5941b2,3b19f6f7,f9a67d0f,b429add2,5a40d05f,9bc0d1cf,ced3b3e0) +,S(bb1568d6,727dde70,c52f5863,133dc9e,54722577,4a74026b,e9864f02,9e92b420,b5654756,268d74c6,cc6adf80,ceee29c0,9e137d2b,e15aafe7,b170c95,22af3992) +,S(732912d7,83e8a5a3,a7468177,231ba93f,ce07c42d,778dc205,35cdea7a,db877dcc,d34b8388,1b128d23,e68ffd7c,29c7a945,1664f5d3,fed3dbab,6f78c8e,77df80a2) +,S(c74f0f71,fb8532e8,2c3e1865,1684d3b7,4927b6dd,22504afa,9084688c,7297074c,9da5ea61,c0bd178e,8bfe5a92,dd040c6e,35984bd4,1102806a,53a9f1a7,bd006ac1) +,S(bd4fa939,8bda5a0c,5a4e9e49,43060d9b,1785a613,3c970aac,91fcbc68,9e3283b0,631d4fed,b6614b49,459be1ca,ccbac0d6,e79cfdbb,f14de95c,5d2a5cda,30e433a) +,S(9fa65462,733f13d3,2483e0c8,15cb6bd3,e9bc2d79,7b89ba72,f2465c64,a341cc8f,7051fc5b,afc5b18d,748ada32,c4a27151,443505fc,2f14f130,10fa02e2,6a12db04) +,S(eaea6f7d,ab3dbf1e,816434a9,ddbe53bf,715168fe,2c1ebd4a,6cd40744,c35e31aa,b96962c2,4f202b96,c2080619,ff4ba905,a594b9b0,1f709e6a,76a1a7ab,9784d61d) +,S(b3df7ab6,3b947504,f33e6d5b,7b8e2553,9a117c8a,497f8751,6b97bfc5,3b17a2fc,72df7500,a35ae6ce,d6fa6265,1a759dd,f11f00ea,9152a5b5,ec51bbc4,9d758b9b) +,S(ef875ecc,46da48ae,45619be9,950e294f,4341df09,726417fa,3a8d1ac6,c3281bbf,7ab9e204,af4c05b6,d6d0eb6e,8306c987,51ced2c2,b9e8dbc2,8a642bb3,7f1c72f5) +,S(74c3c446,576a8a3a,5082f234,afca508b,3d748757,4cbf14e7,fc26f36c,70024fdc,73d57916,4ddb6fa8,72dd2afb,f9d8a307,b6ccac9c,94a4eae8,8c4fe8e1,dc136506) +,S(959c4b2c,409f2e3e,6c020493,33ba2f18,c06b7182,5a664e1a,cf33846d,cf39274,17cab35c,7401629f,b73cd398,dc5bedd,d319919f,1a3995d9,45f42f68,2c9aad47) +,S(404f0dd6,94195313,1953b53c,67fdfab7,f67c24bc,92fb4d69,a9479a9b,6c9175fb,857c75e7,f40a48d3,ab156085,1d42b037,7e7d3e79,86efd570,147917bd,f24d87b3) +,S(3e040511,233b0f5a,53df4d5a,b0854137,2db4ecef,170b566,807c4923,6ce82075,f9337271,dd443843,77a35ebf,56753b22,1fda08e0,1b790e02,b9603827,600df3d3) +,S(942ea853,10dfdc3e,1f7993e7,47bdac04,ecc8692b,94847bd3,e044cdf2,2cd77e6e,bbf2f7c8,e688b6e9,b4510bbe,58c41b1d,f33e9afa,5428ce51,e02e624b,9ea155e5) +,S(1e577a74,9883a5fb,85593809,7d0180a1,dce21791,e10b2c0a,3fe6cea1,cd03b532,a147662f,856f5e15,dba53000,7278e878,7b575612,d5dcd790,19417ec3,ac41c003) +,S(ebc9d95a,8a237b64,212e9dfa,607fe4a3,7a05fbfe,7c5594c8,ae472c4f,6ffeaa5a,39406dc0,e311a47c,cf15fb45,8f8b48d3,8fec2fd8,6b4afc05,b1747957,e7f1162a) +,S(c78eaf60,1afdfc20,2123d228,8496189,b9081637,1fb2c475,2773faf0,63cac063,95325b1,e0c22dc5,df6e84c5,16d396f9,bacb42cf,6c1fe9c7,6df83b3f,3eb42de7) +,S(b5918719,a1d504d2,b44a3d0e,117c2798,4f2e536a,3571db8,752685cf,df6d34a0,9b01e8cb,585cb7c8,fa29828a,ac899050,16beacb2,5e62ea35,6d54e9a6,18184abe) +,S(8706a73e,b59fc9d1,92907dfd,cc6f75b6,454f1045,4a5e9584,bdac978e,8e0042cd,8b1b5f56,6f1f78d6,f528405a,2b6a87e8,4265e2dd,1e34c1ce,7109286d,5bdc3a49) +,S(93e9256e,4ddb4bfb,6f4a9289,6e2ad04,793e5642,3a22230a,e645529d,712d6ca,83b242db,d9b3dfec,3640ea62,f0e3989b,d874f247,90a75cd6,9756a8ed,6eafdcea) +,S(2dad49af,8702f39b,cb353956,a1d5601b,a24fffbf,58ab527f,e9ac6ff9,ea2ac295,b5af68b8,e6040762,55c0704e,2cace8c0,ed403611,40dc02fe,2773a625,27e4675b) +,S(5ffc1899,4da42fa4,54962719,5ebe332c,86a2c364,f43b14f7,59710c54,4f6950a0,22eac0a8,79815faa,220e6141,9db053cd,4542ad2f,9ba9f63f,4331ad5,c2c9bb88) +,S(71be09bb,1832a799,c4e21bb8,a2bb5ad0,324c639c,e6e62b6e,69fa60bf,d41c51ba,c5227fc5,719a5b8f,28c40767,b54eb249,950588dc,c15e1656,e4ff238d,54dda472) +,S(4f94305,f92799f0,a64a3cb3,7df2bac4,56d661d6,44568277,bac0ed6,6a587212,4c48691f,bd8683d6,b94ddc7c,ad8d1d7e,6baf796d,6d00f344,511fc13,13c054ab) +,S(55ef868b,6fc2923e,e624fc09,65f61852,b3aeb38c,e2c6b3bc,54b86b3a,60f0ab81,ec198aea,ab16b4cc,5354d0ad,c66051fb,76cff6df,22dc1a0e,72ce6e79,1622efab) +,S(26ad5590,46e19dbf,e60953e,d40a3958,a357f6bc,23642279,cbcc355,74fdab68,af6fc5ef,906721c0,553c6a74,60bc6894,e5bb77e7,4dbc25e2,184fb3f0,fa795508) +,S(739fb43a,b1b07155,39c0b0ae,43901bf2,bc051a69,8ee8d503,84fcc1f0,ec37312a,c1223704,3c882226,2d4abe33,1de6ab4d,ff90d6b8,4c0b59e7,a193e763,6c6b7e28) +,S(2144649d,508cf5da,a7b422f8,22e9125f,d5a10965,a9d32c6c,c299bad4,6616771d,1153178c,e33c445,f03ef96b,35067ceb,76ddeaca,d9ddba1a,74acd229,d01ca76e) +,S(62cc463c,16ee8e8f,16ea8517,5508278d,4d5577e3,556d3580,ec8d90e3,bbb97072,cd294843,e299c500,846a6c91,c913395b,56b48efa,2f9ab3fc,b81863fe,8a6a891e) +,S(1196301,33edf190,d14fdb00,640f74cc,4317e1dd,b9dff1c9,707eac33,53ef9c21,f16ab4e5,e3a3ee6d,74385187,6da07034,caa4f519,6106a0c8,3136d21,5420494c) +,S(b250bf86,3fdaf93f,28f15bae,d9555287,777d4e34,2673c16,2b4a6319,2289adcd,295c05be,de343d28,87d3543f,6b40d5f9,da1e06ef,39fad6f8,28ad5ac1,39b3d2c1) +,S(93a40bbc,ae584739,9f10945a,72c199b1,27ef008,14e87e69,6f4f46f6,483e7c6c,81ed70c0,29809674,f5f289a4,5926864b,f088e2e0,af66173,89fe8cbc,aa858a09) +,S(b9e6761b,4e909d75,b17e76b3,4e9825e0,19ff7ddd,4faa9f90,eff8c0c0,f60978cc,640c1503,5fb91270,8881b70f,bf2c8575,65c75e3b,c98d211b,76279090,7b5aa117) +,S(4dc22812,fe3d9ba4,687e260c,f5b2dc08,ae454751,b022b9be,ebf4360d,10cfec24,9c35ef4a,56858135,552e986d,a4d68056,27f0822e,43031c43,5b2df5f,7f9a90d1) +,S(431276b3,1127f9c2,406b94ba,683d2d3b,e198e225,23663540,9348286c,4c9deadf,2265ed84,c7f1df86,4b46280d,ddc8cbee,c26d39c8,ddd5b743,13938c4a,e01efb3e) +,S(75c5b6c3,c99058f4,2b4b81d7,6cfaa917,328f1736,b8788360,aa810acb,3683632a,549f009f,def17b7f,70a309ef,49a890f1,4a5aaa1b,a80f0464,affdb5c5,a8f719d) +,S(3c900027,205af742,976b1a37,7a4801df,26d4d4e9,12ea757c,815ef99d,cea827d7,e28cff3,37eca7de,2387fa7c,339dab2,7a2446,fe7184c,83c578b1,8649cc0) +,S(5660f31a,3676b95f,9fa8ab0,d5c23f30,c89637bd,3a8ea97f,3a87aeab,3310d9ff,d6069cd6,6bc4ca0a,7d892ff3,e4d9aff3,955bb76c,2ba3f839,efbd786c,b11c568b) +,S(2b8b68a4,1b45dc86,7f7979ce,5b71d778,e6733cd4,79af6f61,8cd786ff,5f3babe9,7c831244,d5441b33,c20923f6,3ad9a093,840f89c4,6c1421ab,40ac52c5,8de4097a) +,S(8635004d,b817bcdc,4b357886,96b3fca0,1d369d4b,303e9290,44229cea,89c18610,2472da40,2bd46e6b,e2f84cc0,5158da1c,7e9f3512,1fc4b00c,4c3ec329,6eb909e2) +,S(6c991a6b,6eeb4f97,9b7afbde,46e1eccd,b0d39d03,dc64fb69,3a56a234,88cb28d0,1e5df74f,c2cd6350,50277188,d3eb4473,e0b753e,4cd41372,2bc119ef,65c95620) +,S(acdac19d,4283cc91,b9698ed7,e92288b8,554569a4,962ffa0c,a52a197e,9f41570c,fa536d87,523c8541,f530c6bf,e71742ba,451d41a6,f97d9afe,ea03a520,c6d7b66e) +,S(b1496ba3,f696cbb9,548b107c,3d28a7cb,85bba7f0,aeb50abb,a3e2a596,465fc6c0,77fb6cd5,727a4a6e,e0fc8f8e,ae807827,487740bb,ff5cc57a,8572ef3d,c86318ad) +,S(3fd97db5,6098e9ca,fccab31,d6d128e6,c2c9f878,adb07ec9,4d854034,d9b09126,1bd77c36,1494e374,fc45127,38b246f7,24e37d4b,27e14a2,2c0401f3,222b4578) +,S(5e8df855,f2a468ed,5476d5c4,409c7cfa,eb174cff,ad793338,8982ae2e,c2aefce9,52e73a82,3bb8ca88,a0977184,38701841,d50da8ec,c46f357a,17eb8cb1,36a6845f) +,S(99f106eb,1417cb69,e95e6fb0,a0fb932c,62021a1d,b940c661,3f814086,c64672bd,9e7fb038,e1e70011,6a926e6,a1c27fe5,e484d843,d184d533,7e9825ff,f7a6501d) +,S(686fc498,5526d87f,fd11d686,4ff0e208,68bb14fd,4a5c71f7,ac43063a,7e51ef8c,1d28f532,d793af85,bc96dd6b,2e0f23fe,4137dc5f,5b3d6244,22f60919,44588e5b) +,S(cfa5df56,cc450bca,914f3a85,b370f864,e4c83600,560bfb20,93df96bc,bff6b83d,cefb9a46,bab7ffc9,1b1d96c7,48f81706,61cf56f0,264e203f,78b05f3b,8d37604b) +,S(991b6b4c,3fbb9693,f7641eed,534e7cbe,8937606a,962a83e8,b39089e4,713e404e,3ffeba6b,be556688,d3b8a0a2,f4b92b8a,98dab79,d5847c71,13bb60ee,be3f8d3e) +,S(d104c5d3,b9b0121c,58a1fa14,f226c513,2955c4e3,56938bcd,6891bb92,13c8c0d7,8c8399a,814d7cfd,32cea21,85c77738,91ddb00,a091196a,3d90d056,b0caa6e9) +,S(76192853,a45c3648,749c9a40,719424eb,415a06f7,c74b31bc,ad93194b,e355dfce,31139287,3cbb5012,d7ebc934,52613c62,b5517b37,91475ecf,84ef3745,324ad2fc) +,S(173304a8,509c1f4,c05b1de5,c51093b2,10c7f9b9,81a7d6c8,8059fb1a,e5070725,43bfbd98,c8e08394,543db2e9,c692297a,800cdc8b,398c13d5,f9e21f89,341d353e) +,S(aca057e1,d28c5514,107f5b6a,9e46fc95,9eaccaa8,b14d4c4,6b7ae515,bda104a,e17f1717,70bd76ff,18095be9,a4b72b8c,cb00e6cd,23f6d702,4dcba433,e6bf6ce8) +,S(fb202550,e0098fb1,c30a7385,900a7dc3,85b2945f,60e6eb04,b7e8489d,3476dbaa,1aaf8420,3f72c68d,bd3bc98c,77f473cf,cedda922,dfc3c996,45e4f565,ef9a0f28) +,S(e95b710c,a0227ab8,e5b66c66,c2958be3,af1aa298,422c501c,8f879bc,e11ae7ac,e645f4e1,ab5cf4b7,da909022,cedd01f8,c745a968,d9ca30a2,c5525d50,9f97cf19) +,S(6db4525c,3589bff9,605cf203,cced45ff,ab136c6c,ce77ea15,14766f3d,e844770a,e6b7f403,f5f7584b,2331d295,82c0698b,799cd7bb,3c59c903,eb5d6848,72658c81) +,S(8893aa9e,49daeae7,15fc2959,e4db9c45,1690438a,6964a2c8,fbe73133,35085eb3,70fbd83e,ae803f3b,6377a4b0,265f62c9,bd15cec5,baec8c10,d01c7094,e5987cdd) +,S(be57f6cf,ac6e8cda,871e3ece,8aa78bc9,2cd9e2c4,8f3adfd5,6e39414d,8e0207a0,78170872,99abf89c,fdcd141d,899aa7ba,8893eedd,36bb3aa1,58120f2b,ee93d5f2) +,S(77fa6d2,85a01129,c5e05ddd,8d02b5d4,a2f69bf4,5a9e7562,6718cb54,20b34925,315bb23c,13a3d218,ce886288,ec0edfeb,37a2da99,e017b97,ce04db45,326455cc) +,S(2fed7bfe,8414dc33,62c834ca,767ffb0e,61094ad,978ddd00,b2ea09b8,d1f4dc03,14e5e8f7,aa0b3d31,565e434f,11c61b,63332a60,b6c4cff2,a6de2c5,98117e01) +,S(9f4c2cd0,5a871ba1,fcb43df2,bf03ee3f,7f8af242,ce8ee6a1,1aeac89,b4d66c6,eb421f52,f2427887,8ff8a2ab,dc384e23,d0fd7df5,fc341acf,83bc5940,be922920) +,S(53c0e0b6,824a04cc,b7203ef6,e37383f0,15f0a48b,bbc1d3ce,7c8fa7ca,5dbea647,6a9b598d,9246ca1a,539729f9,be809397,13c59d5e,105a8e91,836fd3a1,4d618cf9) +,S(dbc0cc82,d7906b84,b6b7bba5,433d68eb,bb20fdbf,7b4eefd5,c0a3ad8a,ad17d714,5ebc1f86,23ff2c3a,6f81b090,4e5e6338,8aee42e2,85306e37,a4fc7676,2dcd7211) +,S(7862af32,a3c08e04,7b1a8cbb,8131d55e,ca93a478,40c52165,af20aa6d,248f5f0b,bb5f6607,6b10353c,8a367a64,587b3bf9,7e8c272e,8da92684,f1efdc33,8bfc15d8) +,S(d3571fc,800158b7,6ed2bad8,15c93b1,f8238fc9,b8753752,4e44c0ca,931049ee,162dc9e8,3e6630aa,9d0872fa,915af449,70a9e6f9,526bf15f,4d26bc74,82a44bc3) +,S(a851c894,cebbc758,642b98e5,5df3584f,b9f531da,88faea26,e908b0b7,88589d9b,74702d5c,adfac1ef,71df3898,3ae433ad,1e1af1f9,b5fae0e1,151258e3,b375b422) +,S(a92e43f4,12effaa,e0978a08,cdb2e885,2d9af1f9,1f0931e,972016ce,da58012d,d8f5a09d,5560170e,b35d7bd1,28252096,535c687b,23bc13c6,bb903b95,d02fb668) +,S(75cafe44,8b4369c8,42e658c6,4760ecda,bb29e129,d283c24c,9007fb5,f3cff6bb,ca0e12e2,43c73553,1e2affab,51d4738a,db1ea5a2,fba215f5,3c9477b1,b55dc39) +,S(ab0066,4db959ec,2f17a233,78023b5a,c48c4177,7b6e6b56,a2148453,8c41d006,8cf9e2fc,35545169,f46762fb,940758ad,e3d3387d,eb72e9b7,b5d37175,9f5d8b31) +,S(27510ef8,2e4b2134,180855bf,469d1f0,f89b9afd,573f2781,4a1bea50,9db7ecb7,20fe00e8,86b54c06,1fe07355,5be99fd3,b0a1b20c,dec68aeb,90055c34,acfb87e1) +,S(773ff5a8,d388277b,7921405c,99c9c207,f4a6c2ee,3b59ac1d,7452c8ca,4db16d3a,cf45e631,f51cc65b,afc806bd,87318e3a,f75caf,3e734284,8d7435be,f8a52f8e) +,S(2f8f2c98,e69ebfc3,b7277e35,9da1a8ef,4293fc37,2e24386f,e14cc455,1ef45746,f85d23ec,c4dcaba0,23c3e406,604aaae8,8150a6c8,feea2c36,42ccad40,9968ec06) +,S(1878acda,ab8dd0e2,a0884952,26356ce5,74575678,64da41c0,61a83de9,6277f67f,412c868d,64e092c,ade96f05,bfa48af3,ecbcc128,e6d09bb,9684565a,d5477020) +,S(8cf281a,eac4e4e2,7ec4f3cd,d1373f62,c5a17b0f,49cf69c4,cad8c4bc,4f5618c1,2f17f995,29c9ea27,cda3911e,de33029a,7dbf09db,64ffa625,cd9fd86f,29ed5973) +,S(3a597c9f,f165369e,5d90d191,3dc2aefe,a0957936,717f1ec3,9ea20698,d08939f9,8c2203b2,90c9a2de,5b464b0,988e07,a7b48c86,f5891926,da462b4e,b00a14d4) +,S(cbe3205,96f10ff,5de9c861,55290393,b9ceec90,bbac68ac,5054facb,950ca15e,446cb06a,b76aba12,c32b4855,716001cb,9bf7c72c,ade16bd0,5472b947,4fee27f4) +,S(4313c9cf,8224e70,18413b09,e6544731,1cde7100,5ee60bd5,3a8db041,56fed594,dfaf359d,d3045a8c,b181021f,9a025208,e80bbd4,abc4a331,7ab9d735,1b329a96) +,S(cead2b51,f8d8adec,2d89651b,2da5ffa5,1f5cbfab,19fb7688,2bdf0faa,bf73c60e,ab2a2480,6992f0e8,c73e7932,2bf144ae,6dd3bda7,ed2d221b,f8451ca4,56a25897) +,S(9ce75c8d,848762f,645164b8,45ee6eee,98e34dad,9f8be0e5,2d8f27ae,4a7b79a0,e0556d4f,e11ba906,6b97c04c,8b742a26,9f627559,b9163571,d0a29dbc,9aa30a05) +,S(6024489c,621de255,f92106bf,8c23847b,10214b83,1d653a9,6ba00889,326741d7,950eb24,80a90200,ec932621,6b82e5e,abf63e08,6626faa9,b1fd8e2e,104ea858) +,S(d3c746f0,108f6bcd,406c2638,c07255fd,1f55e1a3,c6845e11,546d22ed,5f08e51d,d124dbe5,d349c739,e641a776,c57ef3db,35ed4e1a,6ffc165e,25d0bcce,438dfab6) +,S(a1eb5f5c,d85dc222,f97b9e11,e08594dd,a69c69f9,bcfa4c63,52cf2717,136514b8,46ed3d35,a393e017,76247ddd,7dda3ba0,ff5e3f76,30253b68,750a7c,f8a15fff) +,S(2b24a357,fa3ac2cb,faa5f1c6,1c14147c,e4406556,b82c7639,721f7561,485a8736,d67219bd,707aad55,1a8fd7ae,d5721d45,ad192a5f,5d0b643c,18330cd,1bd73ade) +,S(9901a1ab,9dc60159,63cc9cfb,42ecb41a,ab6a623e,62e9f306,126a4f6c,fd87b2ec,8f766594,17cd7f2,fff7a3df,6cb414e7,eb5950c1,ee265730,633ccd8f,f0339317) +,S(311e8445,5890e2f1,e1d8e600,37d58c83,28a2a4e1,b21c3763,4aeb9965,8477e8da,cf593f67,6cc75762,a1b0dd00,f6703bc1,e017e927,1e61c829,a0459056,ecce030c) +,S(905f72e3,97140f6e,298ad8b8,c8faf66f,122d27e4,6fee88b3,67a8ecc7,9e83bb77,c03f155d,bde9c265,d90b94fc,1b5b253a,2d98528a,a12e19b4,698714a6,f1b65257) +,S(61df77a5,d5940001,2fcc2f02,199cbb4c,39eafd33,27dc85e,4a3f55b,a339350c,27c88b7d,de9b3f,73b0603f,2d6e40f5,f3664020,8d6dc05f,684626a2,d9049161) +,S(e1f8e199,886d4b1d,5dd6af90,6eec06c7,de36dd4,ef026129,5bc42bac,5df18c28,502c12e9,b956eaf1,2865bc4b,ae7e6348,56a98db5,4c65a5e2,9ecf8ab7,51ca45a8) +,S(ade2f5b8,3804a21c,7dfe6a7,7044cf96,9180e154,79a4aac1,9b686076,fbb8565a,d0d65e1d,7c8168c,308985d6,f5d267e5,98a9e6f6,45715eee,3751bc26,ef066aca) +,S(c55820bb,154f972,ac345dd5,c62880b8,9f7f6b85,a1755b88,ea5821de,6f268187,911b0fea,1e6ca659,263b698c,8a17488d,4dc35f5a,d817e7a2,1241e56b,cc613086) +,S(ea20966e,321020f4,53964352,b8ccc2d2,1285888c,152ddd08,9f7039c6,6c7778b5,c942f591,cdc81e52,6abdc9bd,643429c1,66f5476c,dde18d39,59e29f26,9f4fc18c) +,S(3c57552d,9c2dfe5a,67301bbd,3e1ef84a,220c908a,8e80c707,9f9f4df4,607e2bf5,d49fa0ff,bc4a6397,3e71a0a1,7265ff65,6fd34754,ed508522,b9f0200b,e71f39e3) +,S(f188ccc6,e1043ec0,59e8e133,94ada165,a3fd5c0b,cf7f071f,eb5a0951,9bd4e1c3,5f1f371f,e53e79d0,2d6fb190,8207649b,db045c41,a2fe1cf,94486053,7bfdbe4) +,S(a0145fd2,7e72232e,8055a146,aa7bfb49,447112a2,d1ca53ca,d4835e42,c11c8c6a,7bc018a0,e5e70ccc,c4bb675,f0709cb0,ceb874bf,22c7ecc5,243e49c,3de679cc) +,S(53400de8,c221153,1fb85706,b558185,c17b7bd8,b17416bd,9c93df80,f16ff48e,e1228e47,3ba565f1,e50840b6,a36ea970,2df87320,8a66a44c,89cd33da,41a6cc6f) +,S(82115d2d,9d37e3,50ce3482,1d59af85,cc8960b4,52b99904,8c6c6674,ce64b1ac,98deaa09,659a0c24,4aadab0,3b9d1881,bffc1b3d,e9226f05,e75fb9ef,b61eb048) +,S(273d8c18,53d86f1c,c49e6e9d,450dce26,8669cb7c,3083968,1fc17894,59fe7c3c,6c5531aa,8ad026c8,174c25a2,51efbadb,14974e1f,7f7f88af,2e16d101,c2ea00) +,S(616e16,a7e38191,70e33f4f,bf428fcc,41e68ccb,5b059bfe,4036751b,ba5ee319,7dbcad21,182a3efd,b99173f5,cca99374,7c7dc3c7,3e8af2ea,ba84b0e4,f506748a) +,S(6761896a,76a39812,1f773402,d033f210,dc566610,275f6774,52c37c01,60b82812,7fdd01cf,1b40939f,8091184c,8e2c8ce5,11848df1,a23607eb,e760782e,67302c9b) +,S(77f7abaa,e97605da,12535bd9,e177b6b0,bd6eb020,92345fe6,dd4a6d4f,89e508b9,fb04996c,cc7b830d,fcf5fd19,bb7c9332,dbf20fa,10d61231,889e4b65,cc7f0b9e) +,S(c12f6717,3a2e2bba,3da97378,501f9cf1,bc4b4a8a,67b0c5a4,a0d8caa3,98bce311,de930986,44d31401,510012aa,3b6cb541,97cd133,6e583853,a330319f,779a47a8) +,S(6553a2de,19c7552c,8db9d268,ddf3a034,4afe8ffa,a76bb304,ee77ef95,c18e66aa,91a72010,7c180bb7,2af4dbb7,752d374d,69f95bce,c9bbb7f5,37377060,70edb93c) +,S(f54b4be,353f4185,22e2e936,3400caa9,bba98023,e6a3d3ee,c1fc5046,b7b834e3,96be786c,bdd5f1f0,a835afde,219745ab,ab6f78b4,577d3a5,1246437c,8e96f17e) +,S(c2d317c2,a0fa6522,bbc806e,45b4dc8b,f86be37c,4b677c64,c0d5b4b4,eadbb2a,c5710969,bd68cabb,718cb16d,fc9994a7,100f078d,4a3aeaf5,8e8eb35e,d313ab6a) +,S(52a567c6,a5b8a64f,dc74b9c9,57f5d472,cc43e143,4136fcce,fe1ff313,1b89f384,332631bf,a314298a,dd45f7d6,b8192956,d7de27e9,7d835d48,5c16f7a2,9c9e8f53) +,S(f7dc086c,891a4412,88543527,831247bd,3530f0f1,99b4c5e9,8d24a207,1dba4e20,734ed712,452e59ae,b0ef5f75,10485860,da055003,ff1067e7,b82de345,b74444aa) +,S(954f9fa9,7bb6dbc0,cbed8d8c,de6f8f75,b3f2ae51,e512cd3e,90520d8b,22ec06c6,b65b43bb,8bd9660f,4bdb3017,bb4f8214,5426f614,8f04378b,f65c39db,185dd9bb) +,S(20e69b98,41416588,20b66947,f775cd96,6def2dbe,416b545e,8188db14,2604e87e,e6514659,bd12b9b,35ae45a3,d43f6023,dcce04d,87df1f51,caa67f89,28632539) +,S(5cde5b82,2dc42f04,44187fb5,33029577,71bed484,2ab39dc3,709e7c57,c72ed1c,a0f7bad8,64e405b5,94416e7,53fd6137,cea3dcbe,7625fe41,b4929299,a9a0ea9f) +,S(b586cb4c,6ba6b0dc,2aafd03f,49d4d6e8,45b20460,5de71c34,6e73b131,fb26421f,ced613e7,c26ea3b2,a31de623,506afb86,6767b469,98bb116d,2b4ac9ab,58948744) +,S(7d3f6170,35803a82,c8e13dbf,a8d601c5,4e192a54,377e4a8b,2a2a5de6,90ba6ede,138e810e,62f413c2,fb56477,80c0bcbd,77eaf84b,e78e900f,1969f4d5,2ec6cb15) +,S(e7a314be,fc4af863,e7fe6713,5304ab81,c9fa32dd,80fa9b41,d8577ec2,8f7eb925,cd978600,f0e04acf,fa99b6d0,7da970c1,13ec94ce,c50808fb,91a44f4,80f3eb1f) +,S(179c3be4,9f41902e,e21cd8e8,10f0dfc8,ba5fc0ad,9e454231,ec090263,d3c6a577,75f9f60e,fb9b9aa0,29eb03f5,a50b7e4e,64021689,a4e889dc,5b9ff0cb,4c9cf184) +,S(10a55871,464bc182,b957808e,25754fa5,8d76269,5cf8c6f,e50610b0,91e6401f,d36493b9,6d2bda2c,e305c679,f906ba9e,99a787f2,aa8cb8b3,29516a3,41b56ff4) +,S(4a903722,5e858c84,15508d45,b31ec7f6,585827a2,f3a9c99f,96af3e9a,e88e555e,da4d45a7,fb9e44d0,cc52463f,20fcde14,31c9a477,d02c464c,70c7d132,3247d145) +,S(6d109d8c,2505808f,7b4052d6,b170ec80,c68373bb,e02f2b62,1cd29773,a96acb3e,c8dea0de,511f6e40,5141088e,cb023bff,200c870b,9cb952ad,c5038b28,eadc9a57) +,S(9c219898,6d202467,c055c734,73557505,6105b3e,2874dbf2,8f7f0c39,66e1af88,8637496c,8eddff12,f9dd4146,36565e0f,efddf5cd,52d48455,ec9fb2d,8dd0914a) +#endif +#if WINDOW_G > 13 +,S(22ca5039,e660f60,1036dd75,2bb973b,dcd104b5,dcb8f2e7,4de8edc6,c292b03a,86fd4471,1ef6b81e,4416449a,708fa0c9,cb6731ba,c403e58e,da5e915f,646b11e8) +,S(cfc18f02,cc004640,f2116fdd,1f6ca202,2e39be25,df75e27c,80bde842,e6b6f938,d62b58df,4f79d0e5,97ba2923,f708cbe5,c09236a4,d9d01398,6451d684,6290df7d) +,S(3388bcc2,3425458e,991f46ca,6235c50a,57490556,becbaf25,9d3c14f9,9a80a087,7d4aa2f8,6f65783,1c22316,6958fbf3,6c3dca5,d4ac413b,3102e13e,a645c016) +,S(d26bd013,1b8c12de,3dd8fefc,136d9f95,44ac963d,4cbcbaa8,2ba941e,f0b46a19,66f89ea3,31b6795c,6b694872,4cab492a,d045a7d,a6780653,cb10ac25,b68d3a99) +,S(dcd3370c,db67e8f2,163960ed,fef5f66b,465a03d4,d447f5ca,1d99d29e,57d1fdb9,8b93747a,320abf87,2cf8d448,393bf732,8a9eb4bd,9b64ded9,922616a7,347084ef) +,S(74074d05,e602ad56,337105af,59c63819,21d449bb,3fe0806f,80589f3f,4f8d8e7a,1a4d4bd4,adee80ad,44fd515,a1dd5236,bf0dd8f6,c44782cf,e19b8414,b03d574d) +,S(a89cc81,f3a23ebb,6a8df438,a78092a9,97120394,d6bb4dd,732373a8,2f05c174,4b6f83dd,676df063,4e5ddc9f,db979dec,326a9ce7,5707fd77,873a9644,a3c4fda4) +,S(8f1a10ba,fa913f0e,1902ae36,b07f964a,6443c540,b60ace03,7dda380f,6616424c,1028d644,45c177c3,24416ad4,e740f31d,14e3a462,d5a0326e,86998555,5de5525f) +,S(ad8fda79,14f9a236,a7957268,ada499ad,9154a2f8,478fa6d6,f4c74048,89e27b51,9ca1d2ab,1f7da6c6,f76deffc,5c3c933,703b74f0,26063834,6174e4be,320e82ae) +,S(6c6e990a,797b2970,4408cc24,6f238e2f,2192700f,e4fb3c87,4d15e32c,fd67fbe7,1ffc1798,f355659,9fa5b32c,c040da31,39811b87,93d4d9e1,be83061a,3f91dac1) +,S(202b13ea,31ad2abd,9635351d,e09f237b,9f86f75c,a340a47c,edc1f9a3,25118969,c52fb505,a14e37f4,d5111184,ebc81873,868a4521,700004c0,fe3cc535,181bcba0) +,S(5355f0a1,25142fa,b0dc7c7c,f9855953,34053c6,12326f5f,d2284291,d7b748a5,75bbe36a,553501f6,c1c8ff9d,e60ee3ef,9cddd36a,781c518f,4b1ccf17,7e281949) +,S(b8852d78,eacbdec9,d1cf1664,4a83aec2,79a39ab1,34706235,f913aeac,c29829d7,763bab50,52b3c61f,ae42735d,2e89ec3b,8d51eed0,f729e0fa,eb431613,df183156) +,S(cab2e44b,294df78e,1c17d4d6,a09ecd0d,696d18e8,b0f188b,eecced5b,7057ae2,f351b09a,501a499a,ced49607,c55b506e,de28bfad,5b20ed5,4059a068,19ff2f43) +,S(1400b9c9,9c6d555a,2bd2355e,b54b756b,b16f9f36,b9b86658,9d46853c,57056b31,8b290816,62f41167,a0a6993b,3d4211df,5709b91f,96f24436,e569c32a,dfa077a8) +,S(52ae372e,973e9c1c,687ae7a9,a111446b,b3d31b19,5588d8a5,fbec6e6,bfd9141e,f982b40d,e6d0e42d,b9638721,a4590db4,1f87cfcc,d8ece56b,71ebfe0d,82351ccb) +,S(3d14ffbd,40824625,be241e14,850dc030,1139b708,b937f2e0,fe5f65db,61899c24,b10a64fa,477ee047,4d9cf16b,8d2213a2,799882ef,d3766872,981fc761,88a1dfb7) +,S(c6f52adf,54e0c197,a8bbc270,d4c987b,e7ab3fd1,a95fe46e,82415ecd,baa48930,7524c06f,b53873b4,9050281c,99fa44b,b9ef9193,2adeba8f,77e5afd9,3856811d) +,S(90089264,bdc47cb6,7a3c838a,4c79c1c0,5f2d1dd8,6d18f55,9fe60a3e,c944c1aa,18963846,d70b3226,6a9d582c,c430e4b6,ca140bcb,91de7064,eea0fb39,d2ee04de) +,S(e27c24ea,478b37c1,6275b2d4,ce8212a5,2db74166,96f3c6eb,c1bf7091,efda0662,27ec5279,c3a267cb,fad532bb,5031791b,bb99f4da,fc3b7b7d,8537cf09,12783de3) +,S(ca5daa12,9cf1d6eb,70025d85,7955d3bf,2549b8ee,6064092b,917eff84,c40a3eb2,682d4905,500f6f7d,33e7c7c2,7d420b4b,7c4aa5f2,77b89e9e,f6a84259,de7a9811) +,S(9069ec0f,2b2ac688,46623fb5,c89d1424,6c98ac5b,4250c170,4871699e,fc877f55,cc500ec4,eff83712,16c0617e,e2407dfe,a6c3c3a8,c8b80266,975d3a56,e71fb05e) +,S(5fe1feeb,bd5ee1b,6ba742d3,c5e8aba0,536393c,592650f,b8cb1391,c3bda16c,db11b327,1ac64ed,3425ba06,8072f76f,ea02ae6a,4375daf5,3bf942b7,9865a34b) +,S(a4a91a5,f168f883,49035b6c,f90e4e0a,6bf2602a,85e0ccb8,31866c4a,ac1b2c34,5bfeea8,fe36ed1d,18af2ff8,e2b898aa,ff7265a9,c08f4857,ce082030,7f837596) +,S(f4135f36,f0c35b52,4a870505,4eaabe4d,43f5366e,d3c7d9e3,5f06f746,fa884849,1c6707f1,b8b6c078,b4d9d0ea,43075d75,ba1a5d30,c3a9c52d,d55fc4b2,650c526b) +,S(d5a8998a,9363fbae,d2b44992,883e84b8,14a504d,92b41e0f,dcc3a9f3,94380203,96016b03,6fddc805,8bb8ae7c,6d46cd7f,2f20c5af,a62abd4b,bf9b3da,ea60e9fb) +,S(8804ca34,4b30dbd,a07fb62,210c1938,d50297e7,9910dfa8,cc38b9be,4bf3d176,5b64bee5,79927c63,7788c55f,f3871631,eb65db50,b11cac91,24caede7,57d37b0d) +,S(8691c1fc,440c21b6,bc48e78e,78bda5a5,c947c74,7d098e74,ac5dbf6,2b811021,fd8ec1c5,35f51181,556c330a,f02a7110,682f4539,f66c1c09,3d48bca,d7b1787e) +,S(445fc1f6,343be2e1,fdebfe3f,894e9293,c3ee5fab,b0ed01eb,58a40637,ef093229,857f17fe,6737f853,d04aa1b7,3eded13b,c3c087f3,48da90af,32907bdb,7d85b605) +,S(5c397fde,a657d1b0,b2e3aaf9,5b88c4d6,af1a5555,a1dcf966,7d1c5001,a76493b4,9ce74820,7b6f3c75,2d736aee,6a9fc54f,ce5cb52c,f487fd32,de79a06f,df0aff0a) +,S(9b5565cb,28d7e028,361d2bc5,bdfe1912,d9f53584,372d30c1,d7e36fa4,c7fc1b7e,7d5cfa8d,2de2a832,58a57f05,4e3f6c6d,a23af075,d98b062d,82799b11,63879eea) +,S(afbdec63,1bbf870d,3971b165,71bb195a,a5229a9f,1012bb4b,89654da3,c9194f1d,cfcba749,b9492525,f9874ad1,bbb0a267,83fe5714,1f54316a,773c2453,8f27e296) +,S(7712abcb,ca3a5347,5cbc6160,5e9e9ec7,a7cc11c6,2c4b3f4d,e01d688,acad916b,7b91c9bc,eb12555,ad2b43af,8c3bd332,b57cbbfd,1ffefead,c68f0a2,6a4b82fb) +,S(3c452346,f2935e41,2e5fe506,fdf5066b,11b43a11,66e75c9f,7a2d38b,1ca2b7e2,fd3f6de1,27f96829,3af532f8,d4811fd9,e02038a,352b6696,2c608c7f,f59cd800) +,S(bd8582f,b4dbda3f,c7da53d6,70c994b8,e04eda44,ddf0b054,7d182db0,aa48b7be,799e2769,c18268bb,8c16b282,ee7d0828,ef0dc4b7,9767033a,d6de8c63,45285c68) +,S(c41010a7,8dd9dd40,62bfb71c,1691338f,befe03ea,d99eb719,74dce6cf,b2c84112,5008c39d,e71ebc22,3b1c5dbc,f824a63c,f270f807,3143e08d,29b162da,42a2ff83) +,S(e89e807e,6cf4ba27,6586a6,a509bc8f,f786bc5d,dedb5f4a,1b6253cc,2521d311,aadecb79,7c4948de,9379fcfc,4c040029,2228f9c1,c099117a,ad6d9949,f2fea2cc) +,S(363df1b3,be2dbf90,64137919,51218c34,84091f73,866f3fdb,dca1b90f,dcb08577,aefd04e,5634e36c,49621493,f7e76f20,f9ea5b64,6309a605,7e3bdf0f,75848bae) +,S(5c8d1638,83d2824e,48121322,85cc44bb,ca8fe33a,34d5c3be,cd4a3c8b,c78ea16e,f66f91d9,c7ce66c0,89500591,49f7525a,355347df,8f31a685,872aebae,1ac0456f) +,S(10ac6676,83583ed,d837789e,ed9254da,4181dd58,be75dff4,8085e87,eacbe126,6d3eaade,23f3e7bb,7465acb,c6b25af,72e0dba0,1815ea1a,1f57ebe,bb17d22d) +,S(1e79a1ea,7bb65540,44567796,2208ea3e,974c4c0f,9b61f7da,8dba697a,8c153048,b63e3d79,20a34888,68987406,4a8008eb,e07d35be,33a055dd,394ef2a5,f0787fc4) +,S(db0d1c73,97b0a23f,508df2ab,b00ff13e,11699118,11d6476a,7bebcd09,53fa9a5b,1c9d0877,3ca74f1e,d1972431,2b5c8eef,2f85fd41,6629cdc9,d0b9e328,4900dfe8) +,S(e1fdd7b3,481ece8d,266bdc22,92e775bf,96904223,e620f622,3a03ed,cb385f27,3cfab39f,28953ff7,d6dee65,83fdc6a7,d9b31f93,e2103e6d,9e4066a,970a4c77) +,S(96797134,2b69bb8f,3d6701c9,22130c8f,9ed85fe5,bf189880,3b2df11a,a223ffd3,2d43343f,630b6f9f,7c4b6d93,cd29a3e6,632c0dc6,c095794e,5997e47,e631d31) +,S(dfb40218,6e27d494,c69d2a0f,399dd480,ec0a776d,9a99fba8,cba81417,d9c33efc,332d91dc,e9f93273,15e45bcb,79603050,9bd8501c,17820f48,61f7b12b,5d37796e) +,S(6b65c5eb,ed13dca4,51608da7,b5c1a331,171de004,7fbe35e5,189b8468,c27681ec,afd0ee8,e0aebc0b,2f246b51,f6fd4f85,3e71fc4d,f5bb9f43,e2679c8e,89a34f62) +,S(bc1c3da1,60b03965,e26396aa,5d426df3,21e5c22,fdfcd004,80a390f5,28c4b619,fd657174,65e4fea9,ad7862c,422c11b,86ad94cd,35acbbc8,76ed464,aca31640) +,S(589b1d17,96d6ca35,53f8a6a8,cbc587e1,9026406,c2c6f8e2,de613dfa,8c05913a,e655d5ec,ac254f46,e279365d,e3bba2a4,3c7b6469,da45ec87,9742cbae,503fb3e0) +,S(9e726385,6d1e6c2a,94dc2ef5,c92d94bd,6ada63cf,cea75677,6125bf98,78ae4ed5,8c238df5,1e5b38f8,b628a48e,dc7aa2b,a83bc40,43c91896,69f5341,60e304dd) +,S(12269d78,14e0f74f,ba40c551,b2080e00,4f9bd3af,255218d5,7eab5dbd,c6764263,f0f70bd,6584975c,106febcd,bbd16920,daee58c7,c22dda70,4a95f864,e385b3d6) +,S(d3212f2f,cc509014,e0c48cdd,6273effc,5c73fdbf,1676faa3,15e9173b,573088a6,39af39f1,673f51f,362618c8,49c6934c,ff59b6ea,853fafc0,9db64084,4832df82) +,S(c535f72b,9bcc0bad,44014e72,4f649623,4ef288fd,9f42adcc,dae45a20,84250052,3f79985b,6fb7631b,62814a17,f7ce829a,88447302,293000a7,4655c7ee,4a271022) +,S(4f5b7126,9b169fa5,8602bb18,60ed0df7,271e3912,ec0d7c12,1c80fad3,93399605,b60fc104,7f2a58ea,9102c6cd,b97c932a,576f63f2,6204fb5,dbe41363,cdcfd0a7) +,S(cb459b3b,244c38b1,af2c2863,e0029c14,ec70e7d,737a7851,de9c8f1b,b7d5d065,7b67b15d,3c0376c8,2f646241,1e890b3a,a888bd15,692c90ea,53a74a4f,1957fbd0) +,S(787d61c7,ebde0c5,18f121bb,7f434196,d389f563,d1a46597,ea72a1fa,4e19054e,5baf56f2,5fcf8cb8,c271cf39,6b3d150b,f42e9ebb,d72b54ba,4b93bcbe,ae72a658) +,S(c38afc2a,31d0b0c9,4b77d97c,bd639082,3373538a,602352ba,cc93b6eb,c5f6115c,b925dfca,b138fcc2,4b9a26a4,c645f8d5,875e098b,d2e58469,d842688,43ee529f) +,S(37661e3b,8e606e95,b9dc6ad5,e5b9b25f,39a5dd0b,8ab7a82a,d6ec879a,ff406d0a,ab735e5d,430d8fce,1317e07b,d6cf9441,60d8bc39,132382a4,df1b1638,a7e9b977) +,S(e5127851,b8c22b47,c3d8e934,8dc0c677,88ea5ad9,f64e6062,abd68a16,51e256ba,5847f77e,349eb7,90b4b7dc,5537ffa,5b1e7d4d,b87044b3,f947f387,270405c6) +,S(f3c7f45d,a6b8a8a1,3713e7cb,7380fe06,127a3698,520bb41,955647b9,ad7382e9,2acf9a11,eb1b9d31,f71decd0,90093677,4b469301,719d4a51,ddfe5fbd,f63e7c87) +,S(86de4047,e8d5b252,523733a1,848a990a,79125f95,3bb0e4de,ff4b2f0,84d745ba,71e6a472,dac005d,2b284cf7,d5de92d3,56921105,1a9ee007,4279a746,71bc969a) +,S(c6115c30,72259d66,d960cd96,3f3aa16a,3029d9ca,c0c5ec63,5e2875c2,f3f57504,18d690d0,b33fdd78,d797f56c,23c821a1,ced02401,3443c770,50d12850,9f7a712f) +,S(cb545099,8b43473b,91838cbd,76929b05,8bfae0f1,e2bfbc6a,c61d3674,42f53c5b,4119d74d,79e34f08,cd7684b4,f9b9df55,c00ba8ba,7bfb4ddf,de38db78,91572bbf) +,S(d0dce704,b9362bb4,fb1771e2,660a98a2,a333b73,c6d09372,5a752f28,52922d2a,f92c3b70,7947ce0d,f1f3891a,259cc2ee,124d3f54,a4c518ff,de5a3915,96e37e47) +,S(db93e238,e5aa5986,38eab857,655cc53,d4270259,e7d73a96,249a19bf,216b20a4,8d19dc8b,670e8eb6,50b4f60c,d26ef657,3ab17895,c62fc94c,815d7eb5,fbbcc7c5) +,S(c387c37f,d8cebef8,29e07e54,b0796129,4d6c6cfc,bbf11835,ba85d4ef,68c3f486,852580d9,ae7eb300,6ca0f7d7,f12d7fe7,c8e3ae0d,b6258897,994fe78e,11ddeda9) +,S(ebb58d34,f04de551,37c01b5b,192bb4b6,4d3b22dd,23ad9092,f943749c,7606c232,1b979d05,9c99f9d4,db1d3e82,905abc9b,d92ae72c,509c912b,c59488fc,ddd1ae16) +,S(7891cc66,acfda29b,765810b1,730cad13,2f13178a,fbf238d8,2525ce42,96e38e6b,22193729,20188c6c,462987ad,7ecaec3,a21ff6e7,db00adb9,72facf65,367caaf1) +,S(c0b02542,e4bc1e8d,2c2578a5,3793fd8c,acec800,c0a311f4,72c50de3,5814d081,24bdc71,f5917c0,1ae6bb5,71c09197,76b1a884,ebffd673,13698bc1,b57f8371) +,S(ea15d574,b8704507,f12fd9a3,e40ea603,c2000cf4,4eb3d4b2,f07a36b5,c426d2dd,b6596d4f,4d8ca39f,4e0faf58,ab7e3894,c5cdc16c,589a524b,6ca25a51,8a30944e) +,S(77d387df,c35a6af7,b88d5726,a249d34e,70877698,1358c672,6e51b779,cf9604de,e5daeecd,2d70a962,d2d3c235,14fa2b1d,45916506,de017249,93fcd9a4,f08b4a87) +,S(a92742cb,7d1a24fb,c1a4dc2f,9d6fefbb,1064f9d4,c3152db8,3296a9dc,9dccd7ec,665a9cf9,8cdaf0a4,ec346df6,823f3c6,66d4f163,b3e7225a,d9d18e42,31679f76) +,S(253e54f7,9f0c393d,5d34053d,37b55304,f62de9da,29e0eb6f,36cb105f,a6316a46,54e168cd,ed78ec0c,32a9417a,c5b27ef0,67c8577f,8fe0bfd7,b2ae33eb,ce7155e0) +,S(d13048e0,e9c38720,6179586f,9e38029a,55fc01c7,b33d8443,4ee45cc0,3fbf2,7c4466db,94502477,85490689,7b251c39,af257840,b9bc61e3,64075080,84743f37) +,S(e9234110,387c2122,2887d079,7bdbc9aa,a632b237,2a5632c8,8e604653,70a284a2,2b98b08c,4ca3521b,4ffb3afe,66f98ed9,839a2651,f740f63a,e80b0cfb,6f6523c4) +,S(302e03a7,ab6978ef,73891a5a,7bb25764,7428341c,94f8a713,32ba9dad,83a29be5,4abe0adb,210c35be,b2ee850d,2e56bb3f,e8430db,644082ee,a98a2f83,5710120b) +,S(53701389,44400f30,dca0571e,eb0f8c7a,4fea8bdc,31d68859,8d7cd156,11665368,ca345664,39c1f221,a5731bbe,5a9a36e1,a712e2db,f16a6d19,71b1a74f,eaa97cbe) +,S(8c0e8186,645d7cb8,fad2b6f7,a5a2d399,656aaadd,5423cff4,9579529a,f28383cd,2ef275ea,14c44981,9307319d,18fbb482,63c6d24e,c94e18ff,cdcd7757,4c48d27f) +,S(64a70831,26baa3c9,a11615c4,5ff8ca99,adddc512,c697901d,afc43d7a,5fad8af5,ba43c48b,59a65f6a,c3a45c35,4bb17968,148efe4a,288f742c,43253e70,aafe29d5) +,S(fdbd066e,82ff8e24,b2f785e2,e166245f,63559acf,b4f56680,51db47aa,5d438e06,60dadcf,a19ed8c2,376a5d38,28b9499e,875731d5,b2417def,144e2a84,12973d63) +,S(b287ccb8,1ff90731,19ddba01,d9461512,82cf15cf,2dcb3e0a,f1b26f41,eead174f,6ff15339,7a9a0bee,4b38a463,5db66ed2,36d1beab,c0039bd1,acfbdc09,fb74e090) +,S(18047a48,b65234a4,fa5f2188,8b3032fb,3b3f8457,1bdec3c,962d5cd7,fd068116,13627669,18198832,306c5444,6cea5681,80134209,101a117b,1f34e15a,624574b) +,S(f1d3b54f,be4e2ce5,88a2dd32,8a41e136,6b74ffe9,5bd4aaae,ce7e7a8,235f914,37c25d41,300e817e,b4ae1471,e8486232,c0c21165,97efe33b,e86d6277,a8a3981a) +,S(9b0da9e9,5046dfab,7ff509a6,10ad56d,9770da36,c5e22a83,9ce3a36d,853bec4a,27d60345,30c25a36,e80bbc3f,f43829cf,df757c19,1a2924d9,6da77503,38135faa) +,S(d0833bd9,5155d18b,be55d40,3717568e,2d3e4d24,f2eb65f9,f13d8d65,d899c5cc,e509aec3,b5044ab5,11fb1e4c,56db7146,ffeefb82,ec4e9de1,3c473bc9,964741e8) +,S(8c41627c,185f17e4,28a01b40,27980e6b,ed62ad62,17c9f8a6,26c329e2,2fc37117,75ca226c,3316a552,37e8a1e7,483f73ee,a36da441,c732dca7,7d95b7b9,3a3662f7) +,S(371f0105,e43aaa30,5cc7099e,9a13b97c,2d75c26e,5b50b11e,7cc6283b,27728d27,c969dbe7,d0976d68,8cc64312,4538ead,b1194426,cedf149b,293b80c,6ab3ce99) +,S(5102f59a,4238a358,f8b4d3a1,85d864c2,d94aeb83,7a8f3e03,541ffbdc,2ccb1710,9e14c4f9,adb63c3f,4cd30606,cd41cabd,bbffdc3,89e996ce,91522093,85ef1445) +,S(ca21b6c,fd40403c,78353c7,836162f0,a7f57eaf,bd4a8cc2,6df2baa7,1ff08beb,108a3c46,47eba55b,3fd9f2ef,751edb0f,d6b68482,1424bffe,e6ae3e58,1f7f12f9) +,S(d9cd44b3,ff40d19c,e8368bc8,200e3dc9,7ec3642c,acc40769,7c94e68a,31d775d9,b6b6fb6c,683ef701,d4cf7101,79de4af,fd7c4a1b,5babf3cb,85c95eb,485f0901) +,S(9a1354b2,cbcb6888,bb564426,71bd4904,510da508,3fcc61e1,4fbdf44,15a10360,3f5f5291,707c48b4,4da3a2a8,93e24037,bc4927f3,81dd9b9b,710e8b82,874f953a) +,S(c5e55e0f,271a81c4,ae7deb0b,ceb0fdbe,20fc60c5,38692941,bd50ab9d,ad0fdf79,138a0f35,eab49301,7a53e7c,c62ae93a,85ed9e7d,708a00ae,cb10776f,fdc83a63) +,S(5ebc2f64,7f66bd3d,2290e4dc,6cc5f662,7c67ea72,599d2c6,9a004aed,9060f919,68f7dbce,df2085e2,27cf7920,65369637,3ec1e860,b10c8f1e,56e996d6,854659c) +,S(4f28eb9c,7d060dd0,5051a5a7,9a79c960,161d7081,d3a58b2d,a421075c,cf966e03,ec378861,5434741,bb2aeb8e,4a2afe78,44849f3d,2cf12a6c,2eff3e05,d267fafc) +,S(f50e20d1,ce113e09,850c7a9a,10b347c9,9fa039ee,57ec85c0,efe15b4a,1a83fe8f,4db7c231,90df41a2,8218595f,61407f20,cee46478,27d54aa9,4db9bfc3,fae975be) +,S(cce6b2d0,1adeab95,dd78cdf2,b55882bc,79de945c,d4249e76,ab2841a3,abeff5ef,1d690674,1312140a,fdf764bb,560b1bd5,bab1dbaf,9fa26bd5,604427e5,34626e52) +,S(55a65174,fb10557d,2ecc7312,15afcec1,e4830be5,2d34bbbf,bc80ed6e,9f2d8475,c69795f1,de1e537a,970dd412,65493806,3f0623d4,e7353eec,611c8917,278012c0) +,S(78221cfa,7b4db3dc,7e22779e,97ac8d46,d0c1d819,76594ab0,267ed28a,6127f290,8ddcd5ed,fd8e8c62,4883a158,2eab5652,ace0660c,2e358b66,3ad53e90,cbc46a54) +,S(9b985039,441ee434,ed4da39d,6010782c,9006cce2,8f92ff96,2b2d6fa,986ed178,e1cf85c8,7b537b2b,78bf67d2,2d9388c2,8a50dae1,73f003bb,85fe5f9c,12c6cfa4) +,S(9aa2ffb1,4a9e48de,57db9d78,d9b6757a,6c27e7b0,291dc4f3,8ae9f204,f7edf20,771c7be3,78e0f794,fe0066ef,8592952d,8f80d7d5,2772ca11,5ff8b7f6,377d1040) +,S(d1059083,66a0b463,17c510cb,40922a0c,949de251,6d80ec02,1e359a89,c6937e1f,84053a25,c9ea4414,a897155c,c45e0da,e5e6f2f,aec780ac,99c41545,fac8630e) +,S(1f3ecacf,7456984a,fedc2d81,2a81f7f,1ac58ad9,c70ba7c2,3e7a2ff1,f9c5d066,c6add8fa,2bfd24f1,73f4539e,f21681f8,15f1f362,e0f98d94,cd435d80,71a23e54) +,S(a312c709,a16d0cad,25551ece,86c8f947,5e504d06,eb3524fe,569cdca0,da2c4371,865ecc2a,ea04c5da,2089ea2c,66b5bb84,8c1fc29,ac7bf969,c778039,b3ae7b03) +,S(f21c4675,e829ba78,fbcf6410,9c2eed38,8c3493db,1017d69d,953f32f6,744197af,fd2c673e,43377caf,5db0ee06,1a37b03d,43d9373,482d3ef2,b37f74ad,98b2f57) +,S(116174ea,2a029a02,fbcb2eb6,1851ab31,f4836933,a73bd426,8feed7c0,18865692,2123d027,e1cead9d,b5fca2a2,d6f5d1d5,25cf3855,44b64352,ee772d4d,d70aaefd) +,S(358e77d0,919e4c6c,f64a2117,357e72d6,2334fcd0,f5e7e60a,962335fa,73f9d663,7ef8d620,6f99f403,10781985,988ac7cf,dcf5cdaf,a086a0cb,8b5b6eb6,7837bc08) +,S(509f7e0d,9e81f146,39157e20,3165faac,8056deb3,a813460d,b86c6daa,baa33fa9,55148e1a,340eb6c4,e6a8645f,93f1ad3b,fd12165f,c3bff090,a095b8d2,a0db6ea9) +,S(358e325c,185f0e26,1e9e30c4,9346f21c,a15c95bd,438020b9,ad9c7e6a,d2a4ed09,5fcc074,c97715b2,812ef690,3b3d6185,54aa11bd,34789b3d,97f9b65f,2d18c4b8) +,S(1e1c712d,bc00af2d,37f37e4e,a2589e02,e314c310,47890d26,8d36be3,dda2fc4c,4898f9a,e3136bbe,36798cf5,ad30b38b,974e7e75,42d4c14,5bfb1f6a,490655dc) +,S(a6516f9a,aa3f79b0,ff3b794d,c80a9590,64e31720,7361b918,bd797b57,23ffcd1d,c5934c6b,59f3b830,53f77b07,47c7c312,812373dc,ebdbcf9b,ed550300,3a54f5d4) +,S(e46b48d8,8b1e1b84,b9fab824,3044469,50cb5633,da599b79,295011b8,b1098155,43e9ba24,4a339976,e342e551,25974350,3e7c8a80,cd950a80,a5d79365,b0c94f51) +,S(ca7a5099,97a9c2e0,625105b,1df9e714,e1cc2d40,1227400,e583370d,3f65aa0b,dd8ca4e4,d2eecd1a,20d994fc,ef7cb0ef,19c61844,cd2ce039,b7a1eafe,66e1f071) +,S(326b5ec0,d29b576f,111352d4,b7786c40,8486599e,ec01ed0d,a390d586,96313f08,f4a3f171,a4ac654b,e7aa6063,3d5b2a0d,c2d5d3a0,3da4d264,95e828a8,1011d384) +,S(b762982,54f5c75a,a557038d,bfe9bad9,7c5bf8ee,e512fe2b,39293228,e70d306d,8b808f9f,b36e3e86,2c75bb2d,d7de8be,cc85c75,398496fb,f92db3db,143606c5) +,S(8bd624e1,2b1d36ff,dde50a09,6f1a811b,ae66f1a5,790654f5,ef79a21b,872286ca,6687ea2e,f4538961,b6731c74,744234af,8bf6a2a2,170544d0,fe9b8057,ad1f02df) +,S(ed25eac7,2a9f9290,bd414cc,cf846c65,509d1c33,d5573da4,2d78d25d,5de48a9,556fa9ed,2710fd03,b6d1583c,682cd7bd,8705a9d0,1f73a8b9,8f3a1eb5,d89eaa) +,S(f1943b6c,9ed76a84,9c67bc94,c755fb30,e8facc1,de280060,df4b9e7,8bc02bf,98c7ba08,85dc4e0f,6acbb646,42cb876f,a3156232,df1f84b0,4818ca56,882a40a7) +,S(c5b60b14,2de3ab8f,b0c24276,dcedae7b,83422821,6ac8ef39,1d351832,a5e9e5d3,ce86e4da,1174e609,f55e10d9,14d4a5e,33259578,e07c1260,e912acdf,9eb5cd69) +,S(b06638e,706cfe63,3359647b,253f99e1,c7778200,c168d4f5,92e2c409,493755ab,e6401fab,1b4d5229,136e2493,39f95357,e16dd37b,87e7f69d,3e88a383,cb44bbd5) +,S(cef8c1b5,486dacfd,29650ea5,432fa563,f0ec5fe4,6814bcd8,9f539b7d,264b14cf,80cc2c1,8d0b0be3,939ea,761d7281,5ed4fd2a,b252d66c,9316aac1,1a5a2fcf) +,S(f616904d,f868f2a1,5fcdccac,4198b1c1,62defb40,269754f3,8e546da2,4b85d7ce,fb971012,344024c9,f0bb93e0,b73b31cf,de8b4d37,aaeae3e4,7f62633a,7b8255b3) +,S(97386144,bc7e4a7b,33a51697,902fef4d,1613d8e5,ed80a599,a59f62c3,f98632e3,bd12d584,58429939,2dd834a9,5431af27,8e56065,ba79bb6a,5a806d36,cfc16b4) +,S(946f130c,7a70fa00,f403a56f,6656b279,1eb08ddc,561311b,551ce437,bb0200c8,acd698f6,a5037e60,7f5a923f,3af05784,186d9794,a7bf7105,7a66949,e1945b8d) +,S(ee0cf184,72c453b0,c38c064,fc0d2589,d5f1afc3,3423687d,91740bdc,c3929230,d817775a,7fecd397,e954db12,fca24990,8c773c28,b36e991f,79c78264,9fff8dc8) +,S(f335f7fe,9542a587,9d48b4f,4ab1287f,ef007289,4d93bc21,23463a77,7d535d7b,336e49a3,2465d29,35389c06,d8eafb4d,7639dae9,a6b19bf7,45518502,e3350283) +,S(55bf8179,4fb37f8d,dcc200d7,b76a9040,b1326d6c,559d7f06,f0eb0e0f,c97e7739,ca33cf00,79155cc1,e902ade6,f7d703ed,3053f6a4,f49d0866,32e930a2,afe69bfc) +,S(dffccf81,6143da46,5ee2195f,abb6d943,1033b901,2fe0c623,49b7d6f6,29de29b0,9bfdf3f6,e1dc4ae7,dc29fc06,f85e1588,c04bc39d,5fded90b,bfe75b9c,74f0aff7) +,S(b9748c94,25fc6fa2,fe5c1395,b556bb12,c435bc11,2e8f577f,3c5e7d82,3539dec3,f5238bb2,b995d23b,5e96b233,6d5141ec,f76d31bc,63aa96e3,dfaca8a8,c94007a2) +,S(92c43c54,e951b157,38f29e33,5f52ad9a,2c5349e5,fa6a39a3,fb615878,ae97f7ca,7c7a6b73,dedd1bca,308924fc,6364b62a,bdc4ae79,d68a62bf,71bb0195,612b4a17) +,S(b1937ea,25995e55,ee1ef139,d7a58923,5677afe9,f4726d96,40b66b0,d21eb272,d0f95a57,544ac7cf,e6c3e0ca,5e44494c,5585c503,a8ea9919,5a993180,cf043dd6) +,S(2c1cd64d,bd7ee24b,2bc5a6b7,2009b788,e2a5047a,8d10dfc9,4a46d807,c133f457,fe8a63df,ce7d7a4b,e7c31a1f,5e68826,7a9449fa,9e9ce30c,fd8684b7,660aabe3) +,S(4ff10a78,be6ea8a2,b6830649,b0a403d6,6d544368,6cc854ed,447f53fc,45004834,b3cb30c3,56d50596,2e81cf5b,f4e2db0d,e43384d7,28f5d8bd,b362d287,e58765d8) +,S(33f55b66,6c90665a,b60a7c2a,c714591,f877e8c8,517344d,9da03558,f43d28de,399848ab,6aa95ed5,8ae0ea80,c93931a2,af146754,385edce0,8c2a4f64,2d5163f6) +,S(b9712359,5a7237eb,18b7cc15,ff2d6be,408da66d,5885a636,20887ab,340d3e04,a283a3bd,643ac5a4,1b3f0ab8,fc693146,dd125f88,fa87cead,817788b3,be72363a) +,S(d20f9067,6efa9435,f602c1e9,fff7338f,5a4204a5,4d984dcc,f0ba5fc1,60a1035b,ac3a3c7a,452003f8,7244406c,ea315175,ca1af26f,6645486f,3faae77b,8f404139) +,S(322d6ea3,157c9f0d,444b2d0b,d072e192,81d8b3e0,3ee2ef5,4e294b53,fef41f2d,838147f1,9dc12dde,676a9e67,6a638c42,6e096df6,ea62ba97,ec359b4d,f92936b3) +,S(95925c08,68341b6,b7564ea7,bae00b0d,1d2bfacb,94aae4cf,8f29ed9e,fa0c26d5,c63edb9,13152232,c255557b,2207c2ec,edf14cfc,bdd246d0,2b46f7f8,76b92130) +,S(7592aab5,d43618dd,a13fba71,e3993cd7,517a712d,3da49664,c06ee1bd,3d1f70af,554ee877,af74284d,5ac0aef1,ccfa8ab2,7a9222ae,977a1b45,7d79d386,16eaa410) +,S(ed9d298b,e13eb71f,8631ad31,1b391680,8062574a,6053f503,671d9a59,1209e0eb,97a9abc0,dab8886d,9a07caa3,f40d87d,7b479efc,d500eb6f,e54ba1b8,9d85c3cb) +,S(cdfef636,a5900bc3,bd28daf3,308d469b,78ae69a2,ffc39fcb,9f8e4942,fa355fad,f8338fcc,54c0ef4e,a46a1c25,591607aa,f4f6c7c5,378f2d51,79f80e46,520db6d7) +,S(f638cf22,ca3bd6a,ca7a8fc4,26d9f5db,dbc0943d,6a587584,8ca52e6a,7949db49,56a267dd,8309eab7,90b49003,9d595141,653a7926,9fd1f732,f3691e0a,41675295) +,S(4340fef2,9b1e43f5,3c76cab,163920b3,7a66163a,bc942e1e,6387a2b1,8f14bd1c,2d5a782d,6889d353,c6c908f0,b6f7a9dd,59ff2f15,8bbb9eb6,ad62bc2b,832210a0) +,S(78af8680,5e3db13,cd2c01f,beeb826c,1aa83296,c6ed1a30,bf2822f1,a9b80991,19c7ca36,37a6ce91,2680d95b,6b94f835,ec458cdd,86206a2a,49d41af6,248c3725) +,S(d87e590f,e6a4bef7,54a831c0,13b3d561,72064279,38b96d49,58a2ae11,c9c41ef4,3928a93a,c9b43489,f1fff97f,f8ed4ebf,53b97aa1,b50896b3,e30b40b9,be1d1dc6) +,S(b59d19f3,69c547e9,4155cfd0,a0b9076e,85ea8569,195b8a7f,630a8446,ddc54c32,b8f5588a,ffe7abe0,e2b83d55,28162c5f,2d50827e,c44a4357,f81ff085,da661865) +,S(34f643da,7cd59b00,3aa64cd,81c143ab,662726bd,5eaf543a,6d83d30c,60f3ee78,41574cf2,91a7f573,5a0bd29b,3ee5a36,91906c1e,3fa47b22,d5204446,f4501ee8) +,S(56ef37d0,583e9de4,33f78757,dc31c968,fd007bf5,6b05db4e,cac395d6,233dbbf3,a140e01a,b5c898f9,10ae2807,53ba14ea,ba8cb5df,b9e9629a,92c14b9a,df5c9286) +,S(1e43f34,815b568b,1139ca5c,b3a5dd42,fc54dd76,78454fc8,7e3dd00a,edc957d7,5cc38274,ac96ee20,78a82d9e,64dc2bdc,8e947afa,d043302c,85d724f7,7e334cc8) +,S(ce79e49,35d2db7c,d9a9046d,3d81b7dd,f8b06c82,98f78eab,ad93062f,c339a952,fc2f6eee,1b90626a,5ad8c494,3bc3cf5b,8765c8f5,fdc05dc7,fffa08a1,b84f9686) +,S(b4144804,ca862c26,70cc3365,e1a00cf8,f6766cc3,4b3dce2c,76c40c31,86fe4fd9,e4368a1f,ca9b6e00,a3f752f0,3a00fd4,29cbdaab,5e2a04b8,7175b9ad,51b2219c) +,S(eaa29724,7406f824,8e79cf65,ced49d39,5416341e,c1bc46a7,b71d422,1f4fd39f,68e7f81b,e3b75cc3,de4d9932,85e21842,d0d4b6cf,38a1d46,248dd28b,a97c14a6) +,S(4e2d10ff,1f7288bc,3b8c6caa,3dcbfc72,eb7371c9,f42c6999,e7a2ec50,30f5b6a5,68da3c5c,df2a4fb0,a93515ca,3e417d00,6ba793f5,eb678f82,be88200f,a5a8774) +,S(834f21e1,114dec96,2a8a4b45,c67c2894,7d073b94,457c1adc,e009dda2,230659f1,e9fa61b6,edb5a0a0,2f7acb27,d04a67c3,39263adb,6320ca6e,f78ac7fb,25adc89c) +,S(a84b44ac,a0a64455,a97268d7,cd3d68fd,c43caed9,f9bdc381,ece7139e,30c7d0c7,2f903f3b,74e702bb,d2fbde43,f919af7b,d1267879,3882cd6d,a05af259,bbf6b74) +,S(21219e06,98bcb977,47b1df66,f9e0fa6e,600cbe7c,bb432cbd,d413481f,241d6789,7a4388d3,c8961874,a897d968,8b5d3266,2e6970be,324bb736,aefd1892,70954055) +,S(fa514e1f,93bfccf6,88b4bbdb,e4f49879,7b946549,82a27562,6867b22f,9baeafd4,ccd48215,52572b4a,9e087b51,8c930e09,2c2f6156,c26a730a,478f257d,a4f91b74) +,S(b60afbf1,643099f0,c0533a4a,99bd8c2d,2204d4f5,3f2fdffa,4cafa02c,79451ffb,fed8f90,1a029926,cd4b3bd2,76bda6e9,d321e006,3eef3f43,886eef8b,4b21294b) +,S(f29cf9a3,196ce34a,86efcca6,554694e8,17c2b765,39c6cdef,c74850e8,a7ed76cd,5130863a,f7c333cf,b37f1bf6,2db5bacc,994b2977,9951e8f6,2471129f,88c9c5f7) +,S(9cd9e23a,cb00bfc5,1a3af34b,3e23f1d,d8fe314a,322254ed,563b9275,c5084e4d,ecf0235c,c66ea710,151d6c1a,17b31705,4f31bd4c,f8d2a77d,4d36fc4e,1298e1d5) +,S(56f889b0,2cfa048a,f96d99a6,be56a282,18ed6691,ab2b25bf,f3d3b6f5,f6e5d65c,352b20ea,4a2372af,f674f824,8dc8fca1,bb8ecc29,ea0c8d92,1b7ea07b,241fe4bc) +,S(de32beb7,f8fad8fc,16d69a7d,d3def556,8e2366e5,246bfdea,16c936ab,5dff2a08,d731f11c,93a71c22,46c2bd06,fe265fab,eaa216cc,b0de1acb,a7c004d4,249e145f) +,S(85ec7dc1,dc1729d8,c03dfa58,fefaacdb,7d12dc3a,f984a693,968895e,2a6ba256,523038af,8e9aabcb,f98c73b5,afba31dd,89e4b9f2,ba1a841b,194b0b45,9a4a747c) +,S(f7948995,60528ec1,ed7f5efe,42db8bf6,e223280e,2b26d4ab,e23a5caf,41e2e141,9f7594e2,96ed1f98,86837e9f,da8d6d9e,58871e56,16cdd2fc,dd6fcb7b,80c6ff98) +,S(588d6fd3,b4208825,3d76e8ee,f01a93be,866bd53a,e228c137,62199ce0,f3454f10,a5fc9653,3e41208b,ba3f29ad,e31b7e32,6320b81,ad0ded2c,6d922a4b,b42af573) +,S(186fe08d,bbe5c8a7,56f87d4e,8976777b,b01db294,e834659c,bf423de,1ccc7443,d99ded39,a46f7820,3437a93a,435fd0ca,29f12e26,a6449bdc,a256f99e,9bdfbdc0) +,S(e549cb08,3055abf3,3b7eac38,cee13336,2af22e98,2f576bb,5a06d5de,59bd3d25,cdf37f20,e7b51483,6641c7f7,afc35ae5,5ababde4,34a945fd,4fe0325c,7d332381) +,S(a4e42afb,fd7f5158,5c86108f,cfe84b58,b930df79,f53a86e1,8ac93389,224422b,e9f8e1b,3963102,b58d6177,f915d7ac,541e551c,bbea3e2f,1ea47960,ce1e30) +,S(5f7ed844,42022f42,6b09e9cf,b7750fa4,4755fba9,7199fd4e,d09efdca,d803dadb,91d5ded,d06a8eb0,9c9592fc,c9096f1c,e852d9c3,9bfcdadd,ccbe1bdd,2b76ffad) +,S(3fac4743,32f064e1,b33fa22,3f67bd15,91dcf7f9,afa38f1,868e180e,c2938d66,45744e67,6b203799,3386d10a,b11730bb,eebf270f,9ea65920,6f93da61,e2aabe5c) +,S(5fb983ff,f058d214,2e4d13df,97d8e784,d4b10e0f,6a18c6b1,90e64bdf,fb7a7aa9,33394601,8dc540cd,eb73f73,a9733d74,ec581181,8a6d58e8,3460f1a6,8ddabd6f) +,S(baf35c3,fa939a2,db15eec1,ab083664,9c6e941e,19d3e0e0,43e0f5e6,df41f88a,42583cd3,e53fa1bc,4eebdc3f,e3b8b069,9de41445,54fed966,214108d2,f68e9201) +,S(97641f5a,a51e7ff0,f1d86183,a3fb3d60,4266c4d9,acdb9f9a,c704a05,809a8602,134ffa32,aa9fbdbe,d8d82fc9,1cfa78f,1ab169fd,459da39b,5b0d3287,ad9517dd) +,S(96a3711e,acdaf6dc,5adaa8fb,4be05c37,f59febca,1a876a5e,e23c6b55,2727292e,8fb0cfb9,681ebb7b,5e1fce0e,67ad5d81,34be9123,56100e96,b82ecd3f,a5da4392) +,S(ae64428b,8e540c6d,28d38892,6136320a,9f9f16b0,3e9d5e2a,14faadef,4f154b0a,db202e5e,b9bf73cd,b9ed5193,b0ff59e7,cc68aded,6fe6c2e4,d5b79493,fc118aeb) +,S(2c5932df,65c0c2c1,14b532cf,15b48433,e16424ff,ba87438d,42229075,6cc984fb,161ef8c4,b908a056,d395deec,38b9ff4d,1c643628,2ceb1e47,f59a2c24,c7d29130) +,S(76e21c78,6937ba69,18252d56,3ebfcbfe,2415389d,bc692071,f9c48f55,7aecca3e,de7786fe,9db47d61,e3b61d0d,49309fe9,ca634d28,8d71aa77,a3fa4efd,4533c8e6) +,S(7170dcef,ca8a138d,1d20b346,6afc6a46,99df363,fc964a36,eaa70805,b267900f,196bfd39,476f1455,98f89f7b,f870f8f8,440562e4,623fb203,3b36d5d,d8c0bb8d) +,S(98eddeb0,75bdd245,aa1fb466,ed1e89f7,61a95662,e35836f2,e6907c5b,691b6ccd,af3fb5f6,b59124b8,c9c2ddc2,108a3a2c,bdbcdc99,ab296814,731a841f,570c91be) +,S(bf42f806,59ae606f,a5e36fc5,c58379c1,8dd1c34e,fa98e67,68bf6da8,ba8e8849,d343fb70,6e4adb94,46f49578,26bae8c4,ca74a0d1,21cee98f,26be68f8,7555b8af) +,S(40c1c4a5,891e8dc6,29075c36,56249fc2,c42fd65c,8c338a0,d82df955,4662e1cd,667223d0,e68ef6c3,7195d819,2bcc12b3,f2025327,3a05703a,e5aa10e9,cc689ec3) +,S(162dd310,c8e3fe4,8384cf1b,1a0a2d6f,bfd3ef3c,5492fc92,b921133e,8f883dc1,1f2311d5,c82f02b9,f7197685,cf490e1c,3d0ebf4e,86ea0e21,a653c8e0,db5cff0) +,S(ff0f8146,89eaae3c,f3f302e5,1089ec58,5d63c4fd,5157bb3d,bdfc7e40,cc6331cb,4dc1fdb9,4eb529e3,bae54973,778d1daa,f8814cdf,5a3b0c2d,ac2b5647,551bf2e) +,S(143ae674,b011b557,2f472b22,44c6d9ab,14b3e641,54f4a033,c3ea3917,4607b78e,1528d582,faefba2,6018820c,a03dfd7,ca20298a,e199c99f,db9cb421,3601c35c) +,S(f3adce28,8fffd45f,96fa0efd,32974d98,4115a80e,cd6b86f3,5e17b017,8d9009a3,20202f00,96329bb0,69a0915e,494a586b,805580a4,eabd4ba7,2d20665b,4916a20e) +,S(d2270829,e2730d0e,2c8e6bc6,fa4c2247,4904ad22,f44fb2f8,5ad07558,c4d8cccf,d5a6b4ac,9d5bf669,5989741d,f262e412,27c66c7a,ae067a93,c6302f5e,8879a3bc) +,S(26d17eb6,7d9bf2a8,45c57a94,82bb2f3d,8347538a,65c9f567,56ecadf4,352964a6,954af3d4,7d67c345,bcfc4a52,a49aa70,b8703d1a,fcd21c6b,7f7719c1,e2068fb2) +,S(e4437f8b,e104c899,5cd1618c,e5ee7d10,36a52d99,31346476,bf68f21,e7fac74b,d6c156d5,b8256e6c,1a820dbe,3b56fc8c,f9b015bd,b81c756e,27b70db8,d995cb81) +,S(8932e04e,96db6079,662b63ed,29b5a39d,ac5bb51c,d1ec70,851474ef,a2d3c1d4,5437e77f,e030225d,53f5166,8c3551c9,fc912a0d,a3bd336e,c0587544,77e58541) +,S(fe776976,465b86c0,5b2003c7,36c8141c,933ed0e4,5c6dfd0,c7c82517,16617b26,b279dc5f,d576d506,d302b0af,359ddd50,94364d3e,255102aa,472e6d9c,c52aac39) +,S(6c60a4ff,b2a29224,5c84ecbe,1633817d,f69eb73c,a6b9f72c,b86fc91c,535b45f1,278dee6f,814bcc1c,70301a51,f9c7853,6489af2b,d23d6223,1b55cd29,2a2a0a2c) +,S(3132e58f,625f902a,98d556c5,ec9e8617,a955beb4,6e9c2a81,e121e473,9c9af04d,a5880964,a2443c5e,14db9220,446904c5,cf0a957c,945c5006,9438d869,45a9e461) +,S(b05cee36,361a9bf6,eb9003fd,c8d38587,640e180a,9de822dc,57e5012e,34903f6f,fb473886,29519a28,b745ce16,d625d85d,26fe21a2,30d798c5,305d8e82,545c9a5a) +,S(e202120f,5659e580,7a14e68d,e3aad7cc,23cd2f6c,abd86739,3a05f16,12005e83,49928b05,b66af992,d937cb4d,c05fbaf2,a70e8fac,7c081544,849d55e,fada136) +,S(57a91d89,2e5409e0,b07e68f0,450614cb,9a9bf0cd,8c5b3459,2f198633,c7a796b,47905cce,59018fa8,baa612c3,124b1192,1dbf7706,c5d8d16b,bd5c1e9f,8498e7fc) +,S(e092c40a,3ba465c2,d59e7c5,8265ddde,91c0468d,67428ee1,dd153b64,a5a7e8da,83f4e2b4,bdfc4248,2d4ab1d3,13b097f7,baa51411,134eb042,feb26f71,5bffd39b) +,S(73a3306e,7baa4fc4,a081a9c2,c335d3df,7c1ee84f,f5a46554,f78a6009,1de0ab38,1f68c8f9,2022c326,e37a7043,9552191a,3d93f684,3af0a235,bce893d,eda1f938) +,S(7c7a79f8,6e904961,73552caf,4a1401db,e99883c5,a39e493a,6a6eabbe,5f3a4434,85ceb252,e4883931,96c8ce8a,c0b596cc,a2670981,2c293554,15e17f8e,26e869bb) +,S(6a9df561,ce4ff772,b37054fa,e513657f,19f03086,eda93918,623a1c47,84a37788,bcf0274a,d9b3bf58,331ba398,a6611fed,fe719867,106eadb4,2b25b623,fdb65280) +,S(fe7bb24d,47b3adff,1c545d2d,ad2c6aff,81934cb5,bf2299ee,f3f8c53b,ff91c950,7fe65f86,9d2623c,930c27d6,f0a292cf,a881738b,4af0c5b,efde5c40,8a574e7f) +,S(26d1d2f2,7944b77c,290ba60e,17d05347,82ce2b64,ae815453,1da42907,30407d3d,ec3c5024,3106000b,d0b2372,53581384,51b768d1,d5aa206f,4d1055b4,b4f0f495) +,S(f00e51f9,38f91573,4ac563ff,8ea44de3,fb85cf4d,8f034806,e6c096d,8e73e2b8,7b7bffed,3a39a491,d3ab6a13,6fd88e0a,5854081d,21380c70,3c596771,a22c727b) +,S(73e15472,f42f8750,93abe811,a4d4bca8,8bd179d1,4e3e3b30,9e011e27,37cfc4d8,392ef4ae,58321768,1106426c,9b00b4a9,c53c826b,84bcda34,b5d0609,f85b9231) +,S(ed4667a9,aff30464,c851d86e,479df8e4,d29d2348,edaf8333,a7faf560,a9568092,77367875,6892d42d,469a9ab5,ff577e0,6d9f4fda,679882e4,3dadc7e6,3d49bb0c) +,S(d6ec16ab,10811cbd,dcc346a2,64dbfe0f,51066f2c,79034d74,af5b0ef2,541dde26,981f1cab,7ac7be22,9a91b733,6c0b89bf,4763b01e,4a1b715e,f4857e9e,4ad0527e) +,S(284ef47e,691931ac,8241d92d,2ee5b717,3f762ef2,bd1f48e6,8dca4b53,ab4c593f,ab739ee1,e6a7be47,83e1288,7ffe1b6b,b53a4d2e,3bfad3e1,c7ac5415,1bcf5e82) +,S(530f9e7,5a267d0a,fc3ba53a,c49018ef,44b490bc,835774f6,c6cc3f87,8d505c3,630c481e,44e5e9cb,cf6d7fba,8f7fded4,bee9fa70,4b88a8d3,6e2b3bc3,4e85e3f1) +,S(66a9b4fd,81d0165b,6737a4b3,8025d2da,ef9c4d20,3c49a2bc,1ba4d59c,eaa905f8,2770c44e,6a4dead9,7dd7311c,195d3051,12c86bca,257955f1,21b7b1cd,4e525e8c) +,S(25812e7e,dca47b64,9b18d739,7474de25,39bb7898,96ddb94f,60192135,23a289be,4bba3d83,72aa76e,6ba76f7f,18cb8644,788d3ab8,b58d0e5c,795c6213,6f17e2da) +,S(3c81be70,af162448,170f88b5,8fbf587e,df1a0e8a,3576cfd7,24acba77,dfb29608,ab16e48e,da59f480,7a0b5250,7102e9ba,ed9dc9fa,e0de8700,27bd5ff4,2aee13d4) +,S(ab626dcd,a5142933,ece82c8d,125aada8,39626e90,85c57525,2fb24f76,e0d6e39d,8add774b,34fa4b1b,d571f2a3,4d8ebfc2,bb7be73d,dab73cf,e7eedc01,764abff6) +,S(47f25106,120720ff,8cad6532,1a3e2873,aaaaed57,98e3933d,e1ccfe0b,f36bd85d,f6d472e,729512e4,ecb74ea3,f96583ac,cb44e013,ecd0bc60,c38b16f9,20585b60) +,S(6fd30299,f7398f1b,3c538d59,71b8bb0,e1640926,752d0842,36148b9f,23c26b1b,3b8d6166,a79ce235,1a2e9c4d,c5c89ff5,7810bef0,277f3d33,372e05bb,ba6799da) +,S(dd5b07c,784e1cd6,58c51ab7,45c4a09d,49db1287,dd7871e3,f449bd66,4a02e040,b26dad8a,62a491b8,dcced2a7,c0feed9b,6a04597c,d8a0f857,a4731078,d68d8659) +,S(3cf5836,104b4227,aa275e5f,16b84bca,15b61a8a,700b56b7,dff2adf2,167fcdad,1cc6f65a,2cb579fd,f6812340,88018dc9,445af726,2db43b5c,e9e49e4a,ce00c9fb) +,S(683b5455,8b9421c,c3aea163,d74c043d,d4cd804d,23857f41,3e01d28d,4919bb58,1bbe4576,2cd5c056,8add6943,8111cfed,691e2369,55022da,17cfddbe,79a11f0a) +,S(d78661b7,897a40dc,5f42f7ec,4202ae53,e83ff0e0,d73ce7d2,19503279,e43b724c,465299b0,e3f478ec,fc3db82a,61d5f290,aeead2fe,d0ec4a02,6652b29d,cad20b21) +,S(1258c664,fc15e794,e64dbb87,b4eebf1b,32e89e7d,50ec114a,1afa5506,19e15a21,327c4a92,81a73880,70d1a7de,c2a0e5c7,28c5997,bbc21571,94b0521a,141be0b1) +,S(f2d04fb5,1cffe2bd,c6e43cdf,ae7314c5,387f4dd2,4bf7fbb1,a6ccd627,86e8be00,89af3f8d,435f2152,8d32ee47,a86a2ae1,78d3a7da,c27ceb37,93250a8c,27061c9e) +,S(b67bbec1,4ab23ad8,e52cc402,def0083b,d21551a1,92a9df6b,b335481e,3f0dfb08,d6ca6bd1,93838993,5284528,56587554,3757cc13,fee01fe6,698b30f8,10a64a23) +,S(1baef1b9,fa401fd6,a053ce90,f2d661b8,8a466584,83a8489d,90d48312,2b79235e,28a19a14,a2f7817d,922b3872,cba558ad,bc1a69c6,c0b65ee8,3352494,a31699d7) +,S(6c0f066b,23623a48,b2b6a746,801baa85,f58de56c,e5287c79,c3c10ff1,b851aa8e,ec837256,84cb0f8,e528bd94,e1c86327,2347a479,2059f357,4ccdbb93,15ff0868) +,S(fbd5bb09,65bb9d22,bea6d6cb,7aebcf28,a0c815d6,18b79c0d,94913dd9,f63619d7,3303574d,5e605e5b,fe298f77,e20f3f6c,60ccc063,37a29c7e,6612dfca,3f00b924) +,S(2246042a,c4b22334,af6c81ac,8106bd1a,f8bd5f2,8dad88fe,7e568fa0,b35b1739,1da0d8eb,9c10116f,ce29bd9,61f92e36,9e538282,345a4f79,7cdabc70,5aff6e7c) +,S(470a914f,2fff2d37,835b3caf,542cf50b,9606cf6d,fd294c51,5632d9f3,4182bc4a,6b3805a8,d2c74856,a5be3cc9,e9c6a8eb,4398c606,81ce12db,b3a58660,1d426e) +,S(4e03f50b,ffb6d933,4282153b,a3f909d0,44bb7a11,50300c1e,cc8027b0,321b4be0,596c58ae,963e71ec,f1fe8f9c,b4de8cbc,9149b125,31e83e0,95f6e5a,b08c504c) +,S(5a6c4fea,b806bb76,191567e9,139dde28,188a26b4,a1803b7,d999278,fc57455e,6e81d07c,6505366b,c28ea476,a718e5f7,353d73c4,2f551459,d59a7d7,82e6ce49) +,S(ed73c9b2,9adf52e2,1280bb1b,ef63dd4d,74f4e09d,1be56c3,a246dc37,9b29bd5f,e9917b6,19ebe0ac,c7d1fa5b,7c4b7c52,e272ad9f,2df62161,59dc87b3,f913828b) +,S(68c6145b,38cbf9ed,4af10608,503ca13f,710dd34c,2386fa99,bdf93b69,c01c04bd,c963585e,607d9eac,5016f884,df535a9e,e7cb74d2,2e0c1e9d,e928d7ca,3fedc73a) +,S(1b651863,927317bc,1dc6094c,3f5c91cc,92269a12,59879b6,a8439a77,b0454126,31c6125f,8ac3d09b,d8c1fe92,c31bf13,c42b1915,e7147cf9,1371dc01,e8f5009f) +,S(45593ccc,dadbde3d,456b74f7,a3b705de,7229ff20,90a0df0d,38166d4e,6a09c52c,13d6657d,89fd0205,3c2b9a31,1ee964cd,e14634dd,20d85866,a43a4ea9,bc0bd737) +,S(1409c06e,d6f2fa2f,cd532983,d28c2109,e4dd7c1a,4ce77960,566d3eb4,37927da5,dc05f98d,4206fdba,e3b69836,e694b71e,fbeda304,537bc623,90edcad1,460984e4) +,S(d9e08c6b,c307b056,d4323921,5426febe,5d6e5cc8,4eb73707,4e2f00dc,e85f4580,a23c1647,c6b47a43,a3ab52ad,da32605d,172f4de4,201834f9,15d5a4b6,292c632d) +,S(7df319f3,d3c2b6b7,3533a916,64d5fa26,5ac0f18b,bbd5e8ee,1aa15dba,bd62fb32,9120f6af,e023bb98,1d6d8d96,31de0814,a9bd169b,a91af0b7,9c3db58d,2bc9f8c0) +,S(1a94e587,38b9fd1f,93146232,e2165798,11d74244,9bad3711,a373445,6986d7a5,332a27b3,17eee7ae,fb4604b,197f2db2,fc32549,ad86765a,74820428,abe4352e) +,S(dfa2cb4d,6db266db,2a82ef8d,fc0cf871,4aefff41,895ff691,fa0781f9,1b619a47,c5e5dbab,3a28a6c1,8cf20fef,4cba62f9,d2a1a0f7,6ea7056e,45acfe4c,49ad8b19) +,S(c2201007,be6bf76b,5e82c135,2a6e053b,acf4e2eb,c10a417b,f35e4c79,3a876730,92408aec,b9ae4d74,3af97c15,9c387343,9a735de8,90d1abe7,c8d14dd,fbefa581) +,S(d45632d2,ab087f0f,9d0d4d85,26730742,2f25c794,efa3815e,33e8285a,1bd7edc3,b7ce3697,c4994fa8,2479e99f,9c9e4b1d,814e7258,da7ba569,5543d6ef,8d5ff44f) +,S(8cef362b,cdc292b4,885f34ca,923a171a,df6c25b8,f6b7cded,c9003b71,cf5df93f,b3910f34,ed8b7fa2,bfa4f1c1,9d41d99a,d702e13b,5dab6bdf,2608186d,d09aaf5e) +,S(247f7be1,874c2831,17d60431,8184878d,3a415ae5,59595bfc,7f17583b,3cbf9838,90e235e6,a779b4fc,f9521da,65f65091,efd513e8,df338464,2f8a7cc8,f1f30eb8) +,S(b8c0cef1,c8703adf,411dd0b0,acaa2b82,f2609348,e36aac56,b0148ad8,981cf568,a0419411,47019aa1,4b8e74a8,1d49a97b,45e7aaa4,54c0f916,a33472ae,1275f14) +,S(8e55776e,6e1c791,2aa6b43a,4dd1bd17,a35ab0d,aad792c0,ab51bd86,8208cf09,dfe4ccc3,a025abbf,c2d12bc,6d462e6a,cec7307f,6daa9c01,2c8a7ad8,70822d56) +,S(f1cf6d3,fc9d9824,4e122790,de390241,db813b70,c48b667c,5f05846a,c3ad1ad,4925c6ab,3952d1b2,35ef1ec7,7ae7a84d,75006993,b173a6f6,c8b969af,c3984799) +,S(b49dbf88,dce5ee49,2b4495ab,9db762c3,81164147,cacbc00a,9e56670a,edb9ea31,c0f92f17,ab5797c7,758d703e,fd288a46,8971f7c2,de8923fe,b8b7acfa,ffa9ef2a) +,S(d6afe2ad,257b57ed,15573c50,a25f7dcc,399e2643,9e64acab,9a8c9f75,d8ca362,5df236b8,6919b56b,17140249,16282b11,38d355a3,561c5b42,b47ac6f3,8d35749d) +,S(bb0284c5,f23365fa,5972a439,fcee4b4b,45b48a9e,6844a44b,53e12004,1ae8e89f,684bcc0d,e09e5932,79018fb2,aed55329,53221dca,6f14f493,6ae76099,ba265300) +,S(57e95714,8a409697,1b8be621,98a04177,c4779627,ab5a77e4,6e82d847,e64467ec,714bd1b1,14ce2580,7c6d3a8,f12a5375,fd8e7cd2,5e854c12,6bb519f2,cd443f13) +,S(b0c82f60,b33c3b47,523ef2a3,de804521,a1e14478,eb637757,d17526d9,1e713094,cfc8d1b9,d763f52e,6522f70a,c93f7fd9,23d163d6,5a82b2ee,ac1af994,a2cea63c) +,S(2ba76170,404785bd,5932c185,c6d98ed0,667d8324,ff7f85a3,5c24a4bd,553e1ee3,1810790,74262af5,607167d6,b55164d1,e56aef19,f3e2f307,205d5603,eeea35b9) +,S(5bd54e13,d508b920,fb1d15c8,27e0ca59,3eb1c85,a7228895,b5c9235c,6ed3e88c,d65d35fd,5607e193,ea70ab1e,4ac7d822,878017ac,ef3bd6fc,2b1933af,660cf0c9) +,S(b0bbc2d2,753bd89a,b2bf1664,e6cf212c,a590d65f,5664e694,7ccdf977,3ea8d09a,9057b6c1,a1078bab,a1419065,4cc67052,7225741,1f34d47e,47f09bdc,8f993c23) +,S(c1701203,3cca38ac,ddc0fe41,95452129,b38b4630,20e8c459,224e9dc6,cd3133a8,c495d87b,1cfb6f67,46c07188,86c08616,624f78b5,ebf4fb14,fb6b636a,f5557e9a) +,S(1e0bd20e,5f1e49ff,32287961,7fbc28c4,7c9fa4dd,d93532ea,74930a24,5fa21bda,2d407400,e98f15d,e5da681b,2472fa11,b2a5869c,66be1cd5,7038e160,43dd6177) +,S(5cfc223f,ec4c6618,ff12a974,8533a70,f39defa3,bc05f88b,3a1b158,317ec15f,7d928bd4,89e3719e,6386ec22,6c738b09,eb4468f7,b6718cf9,3da33544,aff21411) +,S(f506560a,bebd668e,57e514e,bad47a84,5da345ce,50ac0e88,1cccc2c,81efa67d,e2ff0bf7,c9c2a99a,bc3580ad,17f64a26,63111fd8,15bdcd63,9d9a7d3a,ca0fc7e9) +,S(8448fe98,ec887485,45a46e4c,449d0168,1d00dcae,5bf96ef8,306e7bd8,26c54f45,d0f07229,17500322,2dda8271,33481376,85b20045,f69d656a,66aeedab,ea6f0407) +,S(c9a6857f,db037c2e,36d5ca71,32942f34,2480cf28,a98644f5,6bc455ba,97cffc55,a69e08b9,8f678e61,6c0b8326,ced6f97d,f742d974,b68cd1c6,b798e367,8faa149f) +,S(b5d13f5,c611eb3b,c82f7db2,d89ab19f,b8fc286d,8e4699d5,3dc664d,bac4011d,27eb1650,7cdc0fdf,5b92493f,f2487d0a,ef2692d8,9c702bb6,259808b1,324b7adc) +,S(bf9ec5f3,2e0ed4ac,c001b887,18c29c6e,90218471,d7f1afad,75abb34e,da35ce44,13846488,892b4065,b79224ed,368c47a4,a1734f68,7386546b,dd837a80,467ef2d1) +,S(2c3812be,4d3b1c13,aed1f6bd,1ca6f5b8,893c5a87,ad6a8f2e,d6d92ac1,3a526e19,366b82f1,45d551e0,b7bcf877,db340bcb,1b11edad,1466baf3,24a94cef,3433aece) +,S(77bdef28,dc8ef6c8,7fcd0a13,c08a26e5,9fd17253,8d8bd3a6,f21c5c86,ca33f572,da66b0c7,bf3bd49b,ec1fec,aa580a51,6977ba8a,83f957ef,8167f69,ea3c3a1b) +,S(bc4a799d,3185877b,cd86503e,3f34c606,8693bac0,654eeb15,4effd116,8b71afe5,53fcd7f8,99a8190e,a7159c99,e261525b,f59abf6b,d331be66,4f7f7757,7255569e) +,S(301fd884,733dce05,6190e4c7,d0375078,6fccdb6f,2e13f9dc,e275c188,2efcd040,79e4f9d5,185b9f51,fd835cef,64be607c,312c910c,e25cb73,5de2c88a,51e25cb6) +,S(241b4a9b,be5e7e54,214d0bda,13719c42,133f8377,e50db2f3,87b6018a,814adb70,c66edc08,fa4fd22e,1f76bca2,7fcc00cb,a8ce2100,248b3959,3c164847,b410bdb0) +,S(be6f1639,68191289,3c5c1351,d633d51d,dcd28c16,f3294981,56ea1602,d8c79585,6f674a7e,1a65539e,a7f8a966,8f5fe5e6,1ade5da0,a543335a,5f7a71e5,fbafff21) +,S(c8b5008f,79c69e2a,7e209ef6,a2d14b9,b3f7bfba,b7fcb285,e237cb31,3dd3a283,1dc79348,6c3cf7e0,bc36dd7,46efcb36,3cea15ca,a63008f5,2d83ec0a,6bb54bb9) +,S(5014af9e,aad5ed62,4e997ec3,a796ad1e,b038edac,77cf27d4,eeda7ff4,c06c0998,e01d786f,b8faa1c5,2d44a77a,987b4b6d,91143953,34977151,1a488602,3189dd7d) +,S(6ffefde6,2c40643e,da2d4f28,4f28fcdd,b0845ec0,8d882d2b,45dadd8c,a7bb989a,8e2b183c,782d3a9e,2229e4bd,9a2becbd,ff0a5480,6a6f4471,7fb6fe5c,8411cc0e) +,S(ac762bbf,190e1374,d32a7e5d,b4c0c36,ad0140f,c1e92290,4aaff1f1,487d463f,ccd79f18,31016b40,a381bfec,5db6b12f,bc34d850,ed81aa7e,435a513e,5f3adefe) +,S(973496d6,3ec05c75,93244e7,b737b1db,d791a5cd,e828f342,7968eae0,e811cb24,4b2c9bc0,44e3351,f637ff52,5c3f34f3,d7420b65,2f57bb7a,bf573e67,25647533) +,S(a9d89166,5f77bc30,74357753,9ea39e36,c39ce300,6fa03429,1a799b34,84a15d32,d09c3a17,fdedb8fc,f4f9ce98,20635a50,56dd884f,ccfaa96b,8d0813b8,4b80e213) +,S(108a8ffd,aa2b544d,8b8a7419,f2421bae,cbab636f,60d6ef76,9eca9a20,a0c5710b,ad3e9fc,ab04ad58,a265776a,75f0e389,cebbb273,9df328d7,b125665c,d4e0249d) +,S(ef969d7b,c8843c57,bfc0ac6d,f5e4495f,9543878d,95120a36,de8c5bed,727c5fb5,5ab81bb2,26738036,b145d81a,1deaada5,d1d4d653,7b80b02a,fc1cf85c,361f16fb) +,S(ab825bc2,4d505453,f12dafb2,8f70b245,d74200f2,410f5162,b0ba3096,43c39b62,789e7df2,23774415,da7e31da,277a81c9,708098b8,d455594c,6f9cb065,b1281a1d) +,S(4984a4e5,2c173c02,ec79198c,f8496972,eeed4e39,9933bac0,59856bb0,48bf2622,4596b67b,79be2e61,a0887a9c,2cc3ccf6,f199e924,3991f434,8e7cf897,acc5df3f) +,S(285c6ff4,93c1be13,f4f60d0d,8aa7cb24,4bf0f76a,23f3efbc,cfa4a132,625f7272,39dfe9a5,cf9cef28,d5cfd998,49db9b23,c4caace5,e8a27c12,12d7b3d9,d3ed49d3) +,S(1e14b1d1,7e721971,e9266717,13100aa9,9bc6e506,c278ac7b,348b708f,843db340,63a239d,d705f627,347fe464,c4d4143c,394d7dfc,5f79ea11,64d05f04,4ce41cee) +,S(b8f73b9,ed71cd1e,f61dcf30,9cd48587,3b1394c0,4cf318fc,10140bb5,be17c8aa,8af5dae0,bd66ec85,2ff4823a,a1be65ed,745676a,5ac42ec5,827107e6,776f665c) +,S(7e0c7297,e878fcf6,cb636776,d15afd0,49c995d3,1cd49d15,e624bf6e,8714540a,df5795f7,4c512043,f48b7568,bb271a00,ffd59530,a0280e5,8aaaf0fd,aeddd658) +,S(9f0ed1d,465bed9f,a2b51133,fcddfe48,10999011,b754acba,de5fd027,6b798545,7005ec9c,73bb0e00,64badde0,12aa99d9,d85b6c38,e63256e9,21799990,14a8459f) +,S(2d556f5e,b5c5af0,160608d,80e23cef,cc8e4000,b1e35b12,5a0a51aa,9c8e12bf,7600144,25bc3baf,1dc7f6fc,1fd86f41,d24d4488,f80ab8a9,4e4422ca,15f12000) +,S(2617667d,7637e02c,b479524,d9c7dcc1,2cc14ce5,4149928e,e8d81bcc,835ed3f2,521573ba,2cd809eb,8f5496be,478ca639,7a2c4e16,1b299ba,bc6ae419,4780884b) +,S(6247916c,5b519a64,7b76e10f,8810a3f3,4cae40cf,ed05a492,ba1b061f,d9aac10,ffd02570,535ba978,906a193c,500da1d4,602b0969,c3e9f4ca,f2d33026,eee7f098) +,S(c40b27e0,8ed50a88,60017e78,ececfb9,ea14c64a,95137db4,fa55d4cf,9a3c52af,2415cb8c,7d025b84,fd9d1e97,7105aa54,c4149fb8,30ea801b,a86f1acd,e07b6493) +,S(ba5aec8a,54a3a56f,cd1bf17b,ceba9c4f,ad7103ab,f0666974,8b66578d,3e0de12,348dab11,abecc4bf,3c7474d2,8ea5ba60,a705de60,39f9b70d,c49d58b0,6d57ffbd) +,S(ba14e658,f8dd294e,1331262c,ffb3f31a,c1e9e504,e55c7f67,5c002248,94076268,ced74905,fc43e55e,c70cb36c,66dd9a10,c221b0e3,a326e365,9b96de4a,c81aa1dd) +,S(3375af69,8880c7fa,29e718cb,4139ab30,f9c1d00e,a1c22d4,cfbdfa16,a7f4aff4,cfa8b491,a83be5b1,b66fa0b8,5e26c68e,8d27db79,ce55d726,ddde67ee,ce295a27) +,S(68d2614b,306cfdfa,e9fa109a,2c4b276f,5b9a8ee2,f7d502d5,efc94aa4,bd9f01fe,148c36bc,f04365ed,7ddf54e8,4d40fb59,ef9e1d48,8408c8f3,661386c8,5f48550e) +,S(93facea5,597703b0,ad2990d7,1d63387b,900ece6b,6c3677b,7fc47b7f,1c533edd,3c801bfa,8fa114e8,b5c19985,39a1f6c1,c20bbe44,d8ee7179,7454797c,942ad5f4) +,S(f11dd4a6,72f73118,95775ae1,76c90b2a,5a0a61f1,6ca205d6,eef6c275,75054277,bc06a16d,2ef2ac0f,7ea2083c,ac18d0d0,6c307d45,51e0a0e8,3f59b568,b9556ef6) +,S(42ebcc5d,710ba454,fd29a94e,f83c8004,b71fe85,9725c010,f10ca39c,864204f7,f8aa84eb,643101ed,4c7d5cdb,271d067c,e633c17c,dc698e40,279064d2,d65f223b) +,S(d40877dc,d96d5a94,87b6fbc,e89d19a0,549e96da,13f1fb2e,67e9e3e1,85c80e52,be9bb9b3,85f20fcb,8e57b59a,ffc01442,c0be8306,f5d9087c,837e234c,5e789444) +,S(c18b2c98,cd2110ab,888ec934,239240a7,aa40c1bb,ab8d7e39,8fa74358,2562931f,d9621034,9147d74c,75df18cd,1066c40b,b83f189c,937c01cb,24c2ce97,155773f8) +,S(154d6b22,1a44f841,1cf4fa0c,4bb4debf,6fe94658,c648f9e4,d14f88e3,e05c0bd1,df0bc307,c705332f,328bbb6a,dd94e63f,7c1074f3,ebc55976,de552a59,5875559a) +,S(a38259e5,629f93b1,a397d228,59842dbc,24485d59,c3ab86e0,a9326a35,e1a26f15,69b5accc,2fe52a63,b3874932,e8a79b8c,1713274f,f435d892,367bb9ea,91f783fb) +,S(9d729eee,e91e3493,9925a7d5,2eeded18,14827029,6f822013,d4db2a3c,763fcd19,6d832154,3cc8621,166f731f,2d874fb0,9cadc09e,4e330339,657aa2f0,e3e89a1f) +,S(2674f008,86307c7e,576cede7,944a9f9b,46398c93,8a0f8b39,b25701b3,67751e3a,3e9eb42,6ac9d1ef,837638d0,7b0f1f4e,e31bdec7,a9d22fa2,12a666b8,193f83cf) +,S(b2a06d5e,adb1b856,dd28e9fd,bb626c0f,b7c1642c,6f70c2c2,743f3451,4e237f41,5d4caf8b,8673b268,227baed4,481ad60b,de579a98,4d005f5f,f3bcead6,3bf664d3) +,S(20b27d64,d61debdc,ec3e4ec9,2040f05d,2b278c0f,1415ba60,f0bf23e1,222d713d,481d85e7,ff5c2df3,5cd26488,6056750e,c8c5c809,bb3afffb,41e447b7,a4e516a3) +,S(4f4a610c,450eaa25,f60d7c15,20c551f7,5270930f,45a7c51b,fc7cd5c5,3ce3f2e5,df1e8e11,db416228,672d8d8e,f9d68ed,e824234e,fd7de39c,2b32fd90,3a47f328) +,S(9b375ed8,504358,25570b4b,e359bc07,bc06c989,14659e9e,776fba36,a8aceaa9,3d056593,385c0069,915de5b1,f59c3483,22683440,86dcdf26,d1e6ae22,35e90927) +,S(43640804,5d432c87,31f865e7,2390b7ff,c13aff87,37fcfba4,60c0192,2ec9d1be,e2338eaf,6fc73fe1,e3df2aac,54bb4fbe,5aff2a92,5b8b16eb,2346b220,6070cbeb) +,S(a6e59c4f,24461172,4161f35c,fbe88d4e,59287f2e,f2b9ea39,4c476127,f41e0b66,75c70747,f5dd75f9,41cfa470,c4cf718a,57a8ae2b,2e7ab277,5f5ec5fe,7d9f334d) +,S(ff639617,ae7351fd,977bf1e8,46a6d33a,5293a959,74b296ed,7c9a007b,25322d51,e6123dab,fa2355f7,653f81ff,ee798353,e21dca71,ef40639f,79d73116,53dac457) +,S(77914840,1710d8e6,8a37cbc,5ad5e284,c254dfee,1c8b043,5f8ddbe9,4ef4faf3,d97f44e9,9ef3d4c7,4075dc3,894d2a6a,623be446,32c98eca,a54b8ed8,e0611414) +,S(f68910aa,29254aa,10551c00,adc135c4,947cf1fc,6dd8ee5,d42579fb,79484aad,40bdfbdb,33a56d63,ad587ea,fc9784de,69f9f5c4,3f5c7c94,1b9b59e4,c052c1fc) +,S(15be8f81,473d4cef,719c7501,1d560d84,f2d4d8d2,def1d696,29f62464,1b6e0fd3,7e66f926,fc991b41,c451ead0,6d93267,64b85ea8,849047bb,1d28eeee,70fd9a2a) +,S(e113d5a,2e22302e,f4327297,7c41c8b,d0c5c26f,9a0bd9db,9091abdd,8a84e9ca,2e4862d8,34c6dc45,17a6b70b,2f1b2c5b,b54941d1,cb803530,26a257ca,f5574dc0) +,S(96b10770,485bba67,7f620d9d,ec0d1be2,2c94dab0,57d6d595,aa78dfe7,47bea688,e060aaae,222726a,c1a1bd58,fc779d9a,ff854ac2,4a4996a5,2259e9f1,bbdbf30b) +,S(81742f00,5555954e,17e5e899,d2cfd8c,57f6f7c7,5a38e183,de878934,2405545d,a1763fc2,e5f705f2,e6f2fbb0,73578fb0,a8d742c6,8f92236e,df1ee03d,2ed2fc0e) +,S(17c19f13,96988f62,77cb72ea,f90d37bb,86bc7a0b,e16c1c17,fcc481ff,bb78a480,cb1290d5,210164eb,621c2642,ae3e51b9,3f430e60,718f9fd9,c5ec3bb6,53c78833) +,S(7b0f06,e8746ec9,c6648b2b,bb861548,bfeee507,63c01c3f,40319beb,a2497a3c,c6949378,84297d8e,308b318f,1caa0c7b,1634b758,9d6e8c6a,2fdb778e,d6a70020) +,S(715c2b06,2414183f,9a67d8c2,8a89b754,55a80517,cb1b8134,5f56e91,12c5e8b3,f89b89c8,9a795dc7,1e2d4cca,7f84b4d5,23167f03,97787b33,9205773f,2520370b) +,S(e0d0ce00,f974fc78,76777662,efe5dbf5,57aed09,dd89a4c7,8f1f40dc,8f74d3b6,acc5be65,ed704847,94bc7f05,c4c5511f,c253befe,7cb3c0d3,e85704e2,e3e3eb56) +,S(37553289,76fbb8b7,9a5aaf75,ecd9d2a1,bdba9a87,5bad6222,e770ab1f,d26432a2,6dbbe233,1b7e064b,d80bc7d0,12b2a088,1087e7c,2c5c1d77,eb016108,c2ced92d) +,S(2e95c3ef,51ea9036,8683f6b0,8b2afb04,f46ca651,2abdc699,446ab3a0,6fe3d3ff,905ea87,b1d8dfe0,48463b94,c61dbc62,1556c66,b2b498,39cb40c3,299b554a) +,S(25310e1e,721f3245,7f35c67f,b73553f6,6467580d,b5916cf4,fe7d75a,c4ff8eb5,9c5e52f9,be42eeb5,425a359b,87dcab1d,46ecd662,c17eb041,16b5430,786b4ace) +,S(25932b1b,2b24fc2d,d7877911,7d7cb506,27a23b7d,7faf53b0,cf707f51,b7830b7b,7e8e23b4,acdb26b0,1d7969a6,ddf3a2ae,2215e206,109cf3e,4e32d91,df536765) +,S(7d232af6,251f7667,ba69ba44,397f5b8a,892e135e,b09b684e,22b16a44,73c5ed3e,a3e8f638,c8a589b5,8cfdea61,d9824f1c,131b9045,9509b92c,1cd26571,a6d8356e) +,S(4d56caa0,1b65ea87,ba3e05b0,a4495606,6afc8645,4847633,cb9e9755,c8c720f9,14c34678,36e65197,ca3f1ada,936f0348,7c1eaee1,977ae08f,50f41771,77537330) +,S(71abd165,ca6ff8bb,775c81f4,2c722ed7,2615b503,3727dc2c,122efbd9,c500a88b,79ba2467,7284f86,2fb1c46a,e11ac4b9,a5969352,64224eb9,c39ab884,492620f1) +,S(8462fccc,c3810519,cc449634,5c5d9e56,30215e74,c41179f4,2002e906,56a48965,535a966,cd7fb998,bc548a7e,29fc4640,f0eb75a7,5c3c05cb,64d09048,a7787d4b) +,S(f68eac93,fed751d0,b578b5c,665684a8,b9c2b104,6fe45ae3,286e9351,36c09826,98e0c32b,98b0a8a2,8f119ff2,fa50e54b,66f7d8d5,732a1831,7334fc45,fd48bff5) +,S(61447250,9a8d935,9c0e4014,f6ff569a,43467dc7,e4940b16,15f442b2,d9f72041,fb7177f,c7f57ee7,deea7108,dfbea888,fa58f209,2aeb2d2e,b2f33141,7ac8f807) +,S(ea69ee11,4ffa1bd2,e2259a26,e2d88cf1,c9846ac9,379a1497,fc28ecc5,4b15614f,589b81b5,1dd6d750,91014108,3dd6cf3d,63183d1b,809b62c9,b17b768c,5ce4e2de) +,S(34727b24,3404de96,641a1ce0,d7ff150b,38e6aa15,c51fab78,1464c660,4e5d5263,9198326b,cf56ca77,35b9baad,dc0069d3,1920bff2,d5bbf804,435289d4,d827d4f2) +,S(952452ae,613778dc,29e2d275,6e98b4f0,eeebf4d9,526cead9,52f8d0d9,9e217461,c08b3a28,c195fb5a,f9a50eb1,1b1411b,c17f6582,dc14b5ff,797175b,2ad486a8) +,S(fbca3f18,dc4a8bc7,7e9afeba,66610306,401b8342,bde2dbfd,2d4a156a,e78e49ff,2b829d6d,6027b2de,eda0db7b,c76b924f,4cf75573,bb9329b6,c7b7e443,f94129c9) +,S(c7ddf11d,7ddc643a,957dff64,a08a4a70,5302bfff,b940882b,57bc4c15,5bd8c141,e9ca11f1,ac93b018,3fe8146,839be79b,b3711ee1,8a3daa88,89d55669,6e708e20) +,S(71043a30,86e3063e,b831f7e4,4e682181,1b3f2353,9cb6efa2,cd0ee4a6,70ce31b8,4db3f338,ef9fd273,4aa9cc92,55e2984d,9334c164,5320b411,ebcb7cb4,89322c9d) +,S(6de4ea40,15347cbb,d9349d36,80fa375c,5d70f044,799134c3,dbb6a776,48602585,3b76588,65ab52db,eea8d839,47025cf2,458a3243,38c73d70,f1d77df2,7f960418) +,S(29faa79f,467cecb7,ea17e23b,6f7ba03d,db9a0cc0,e1fa6215,bc425696,ba4fecbe,e5aa691f,c42fbc29,c1f027d0,46bdf106,64a2245e,d2ff1154,e50ffa1b,48f34838) +,S(ff880bfc,25ae5b22,78e5f15a,2bf8f5b,d750f8b8,74910f79,c8c42f93,16aafc99,9535f70a,728f79,37825bd8,1bb502db,60e7a166,bc8a0b10,5eeeee82,3a5747df) +,S(b781b6a0,3837f6f5,8520c566,352e8c09,60eff0b2,42524eee,f6a6bd2f,a4a2a378,acd7b7d4,6c683dd9,43722ee7,3c12b69d,cbf8389e,62755e4f,c44fffbf,4cdbbb62) +,S(6d976593,e8bac5d0,da732c64,82e4ac2b,b3f19062,59045990,ee540a3b,467406db,30c353e4,af6d8161,6c0bb9c0,f2a4aaed,6cbc1825,9a8b9658,3bd7e9c1,2f2a8b6b) +,S(18ed676a,4dd3e0db,46212112,9fad1e13,683ec782,2a6d9401,5d0866bd,6cdc3032,c86b06e1,5dbfa82a,5f7b9762,65e03670,6f9a6e7,7ee319bb,8ef26b16,a51bd5) +,S(3138e38,e9440ffc,c2cbce4d,aefd4b8d,d1e859d3,b951d18c,eb3540ca,db5ce2a1,df8ab1b2,a11a8667,dd660a13,490c6e6f,fef4bc40,94efa9a3,430e28c9,6895c241) +,S(757df4ac,2025c9aa,b8ab1e76,149a9762,163ce608,f4903c3a,91571cf,e8b00c95,ff0af5fe,ab36c5d8,47d15ab7,65000765,c56bd7cb,4d0fd8c4,a37d4ecc,dfa03430) +,S(8a697a52,7156589b,d13319a0,81e3b2f2,ce09de8,450b95cc,9aa70409,884c27e1,9eeb93c,b6029e9e,37f2815a,d332d5d9,5a5edde6,bbf03ca1,3df09f86,ad51f39d) +,S(b0bb6987,36f9e0b1,6cfc2198,e37a84d5,d35eb89b,d4f4c0b1,650d60e3,e58c721b,33d5b200,ce25b501,6f09808f,b38e82d,b855615,2f48c1eb,b3b6363b,ed6e00dc) +,S(1ca0edde,5dde4634,2637882a,d2f8ff7,ef6d6f5e,906ae2d8,d9f1b545,c837efed,19efb5ae,4cff683d,a7d5d4c0,f5eb9f3e,4c4d3a4f,ac58ee41,acb9ebda,a82863bc) +,S(780e5b0e,b9a4e57d,66a84931,1e1b765,d59ad11a,de4e921e,d90fc422,4d474aa7,5ebd9ccc,58cc5f21,2da579f4,c79aa3a4,1d8f34ff,418516a3,d339320c,133ab811) +,S(f7e92ce9,39808505,2d2af620,cdf210a7,30ec079a,54bf1468,edf686da,34eb4c9d,2c559dcf,e113a961,58fd54c0,32f14ada,57c23496,7a88b585,7b1f7ab9,78f93666) +,S(3c3afa20,75bb20a7,8f9ff809,20d80d61,3a5688a4,269336f5,4bc7da5c,4a89f938,7ef38308,1dd235d6,e563a9f5,46435f22,3bd836d9,3f1d132b,978f3f9c,7b888c8d) +,S(71d6f01d,ee60f9b5,75dec59e,7e56123,89fb9edc,3019115,af4fb155,f22097ee,e1ccc245,4a31a35c,52854091,fb414321,38da4fd2,eaf1680,2ef0470e,1c80bfee) +,S(9726660f,5705ec80,908a77b2,8e6257de,b107fc31,c58ab6ea,1f5f75b9,38c4fa2d,94cc07ae,3102d1e9,6118c213,b6db0c65,d3636fe7,8ea40c6,90c86949,b48cd4c1) +,S(ace5d0c7,54b2a1af,691a1a2,97e8b632,297fad12,ec1fc4b8,7fd02ac2,b2802719,924f9f24,8d3e725c,eba491f0,5f188d6a,7fc843ca,d24d0858,1f4c9485,8b9f85eb) +,S(fa51306b,34800ff0,ccd778f2,838a4a2a,8200eafd,622e98b8,8fa566b3,85943f64,b60ee616,6b144873,a1cee030,fc92b50d,4b67757,ad34d5c8,5f05c871,4296e293) +,S(85df9018,329d25a6,79c097ee,458eafcc,b716a59,611730f1,7c19d584,2dbea60a,c555d5b6,46d211c,e99ad7c0,9e787774,b7bc64c6,f2f6980a,e62e8911,897ab0fa) +,S(2f77c00d,c2024467,ab461b52,ae634a99,337ff5f4,780637f3,efb989ce,24af5e3a,c7f4a678,ebcbfabd,870c52b0,be7efba6,c5d28e7,aef2b253,3f0e7fa,905e3e39) +,S(52d8a23a,720050d6,ff6a499,7b802bf5,1f238df5,b0ef6001,58fc48c2,228bb34e,98ae81a7,861b8e1a,162d29b5,1c30c786,cebb1812,c91780f2,ccd302db,803d9136) +,S(a7f3e479,eaca0049,22fb8320,47555b5c,701daf22,407462fd,37b0edb1,7212b211,80f6190c,8c4ca7c1,7ba68498,d1bac039,3e33767c,c476fae8,e926500b,9fbdaada) +,S(31ef3150,e67bd326,61bbf4d7,942382af,73db5799,8f4880,ea04607c,a2356103,7db8f5d6,655d28d1,93b50bb5,14b16ed5,bc03c46a,e3d2c954,631834b1,a8a9a8ee) +,S(ee82f155,469c0299,39ad1ee3,52edea30,599b0cd3,868131fc,eabee245,3b8b058d,fd0c0d4e,2d77c2c4,2add9ed6,cadb898c,32de9398,f0394400,eed2ff30,5092b10c) +,S(dec7c7a,bfcedd6f,a9f7d45,8a071575,27354990,b456873e,206d1f7e,556b4586,af841ab4,cad597f4,186f0912,b79fe320,2c7626c7,b85cb276,73c18010,747200c4) +,S(c28e3370,48cd6fe9,7591ba40,5519bd80,2bf34f12,ee48762e,526b34d1,f4d2369d,e00abdd,da456731,7f486dba,6976ba13,b8640f52,39325a64,7d50eb17,f0636e8b) +,S(47157ca9,2c275f65,c29e9d,b0f23531,37027731,1cf05a93,7145123,df222195,648b17fa,c911fd25,af87e9ed,441cc874,9fefeb72,b34f8dc4,f430e0ce,89cbef6e) +,S(84d11702,745c53ce,d81b5503,79ff1947,9a0a9253,a7ab3868,f5471a64,6ca73241,4f16b6a2,c3c087a,4efb1353,644e64cd,fc593ec1,d8d656b6,2c0e0bc2,25f858c5) +,S(3bba3022,196060b8,6b2b2f28,ea8811c7,c74e8128,8e91adcc,b7fbe2d7,97d63fc9,7f34054a,f0945373,a77c5aa1,2ea4f54c,879d3f98,b6e7ef3a,9d73d2a2,a734e286) +,S(85637f4,7a2c6143,2437485a,b3d40e70,b9f74606,aa8538f4,425e8a06,98651c6b,bc6a95d5,6fb42b1e,67b07576,83a5036,f76e8531,a30d0096,c3500ad9,93396054) +,S(25302e98,5e75019a,21ed1605,dd3c543e,e8021a42,a40a967d,8ea6ed31,4dbbd123,849ccbe0,23097591,d46f9b4b,a13713f9,c0220639,11fdd0f3,267a4d8e,66797a83) +,S(e59a30bf,88e393e3,c08d73da,ba720ae3,485fde0f,b6b85f8e,4117f5e4,f43bea40,6fd7824f,e222cb37,1a0fa6bd,33e4bf83,83ebbb64,87872fb4,42284498,6197dfd5) +,S(c5902df6,97981a60,589e9bc3,b935de2e,de05331d,2c1365bd,a83f8183,f6247e4e,c67eb14f,5af551ef,1ab5ecb5,8feb7ce1,21d0736e,b93dac91,f865ac7d,2d75fe3c) +,S(df8bdac7,fe27127e,c679a9b4,74e3c809,b8b6409c,2e6c4c1b,277ab4e6,d5e66ad,3ff26fe4,9f0b3896,54d802ed,72eb4708,2738256f,c0266dc7,645b1027,717d43e1) +,S(1d55404e,9c7cb8ca,c39c7c02,b810d5f0,9eff9125,9166cf3,f1e8cf76,2c65a82c,c1787023,f6a1c8a3,5c499f64,a2fc4d23,e5a760ea,9a04707,c24bb9bd,b2a7632f) +,S(35f390c9,b035fdfb,68506073,d585e450,2d040e96,67a1b4ef,804ee088,df43b44,6a85cd88,86aad8b7,7dc36fec,50eb9754,4c3cad2a,da43d038,3c55da38,bff512a2) +,S(fbb0840d,ee888fa6,f26d7005,b2449cfd,1d22786e,d43d06d5,88f744c4,c5e059b0,6460514f,d89a70f2,3a4ffa21,9f651bae,203b05f4,bd3d45a6,508d2b25,cdb8d3bf) +,S(24056cf0,1c2275dc,44608ac4,66931e91,61fa0ae1,3353cac9,ce481271,a34d78d7,43ebd3c6,7e7381d1,bf03088f,434a5275,965a3fa0,d86a51bf,7dda1b63,cbc7751f) +,S(3b1043df,e8447c78,8e07c938,cd72f6b3,54f9f745,d7e71297,e7791972,70f9cd78,28e028c4,abf0d511,126c29d4,b2b185c7,b67ba361,e16c50c,34af129a,5e40d6fc) +,S(aef909d1,41793638,80d75b23,6635805c,8088b08f,5c577a81,a5bedd20,69a040e6,cbb4c6f,de26b6c,5d0c2b43,df40a3fa,93350cc0,1c497382,d8a1bb7c,8600dc51) +,S(c8d494f7,386331cb,6ff59aef,5f229bc7,913367b8,10f407ac,2c9f9d3,ca833f28,cb2c76f9,4b6285d4,d39afdac,bd3ef114,c7b85027,8d62da67,e70aa74b,b10de4d2) +,S(25afcff7,af14ca32,3dc74443,71de7b5f,c1b52e17,6fe5f3f5,f4f39139,34f75b28,d867a4a4,7f9d7e97,6cb1f57f,8d505a66,5010cdfb,4af4b781,75271722,6942b789) +,S(2436c86,f773930d,872c220d,c8bd72e5,d407682d,7708e2f8,19ad9632,3d32e2c7,6e396dea,92af663c,c44de690,24e1407f,20a95887,37f01662,bc89cdea,88ab67a5) +,S(61ceebd5,9e5733c7,910bcb86,e19159ee,57638bb8,7f3cc56b,d0f4d25,147f349d,2a850545,e9b0ed08,fb63082e,741a30ea,7d85218f,86282aef,3e74b15c,f2fadb9e) +,S(5a1133b5,d45d0071,42b91a73,79e2a46f,dcbfee6,e102d16d,d77e817e,b4b6c187,2ffd96ae,afd6d9c4,3c9c0517,133a4b7d,34c1c2e8,f398f81f,f6f0305,28d492e1) +,S(b74a3849,8b701b41,29eb5abe,8dcb13b9,fff0f191,314dd293,9c38d0f,4563c8ac,9d844e57,e50a20fd,864d6f7c,5a677855,689be528,f8431186,ffa96679,9cb9014f) +,S(c35c9cd0,4afb20b4,3fd1c337,5a952ad4,8e9a806c,a64aa4b7,52fcb204,5f89d26c,b041c6aa,4a83efcb,dee79d84,19e195b2,48c765c3,f069d5a4,b7e87792,79a9c65a) +,S(9a85aa58,753868b3,f04b2af4,479141d7,11703dde,e5b6e5e8,fea8ad37,d0b82b96,465c70ab,aa16f03b,d24b8075,233ec626,4e062041,3bf485f2,551d9952,7bd75d27) +,S(3ec71bcc,e051f3e5,12d83c14,cbd23f49,b3e825a3,cfa4c61b,d12eb057,5c86fe14,f198c21d,e2daa56a,55294c5a,b033f1aa,45caba3a,9a950007,db35f05e,e9915bdc) +,S(ee1cbe22,939e1ede,9010e23,535bf33f,6b09e579,3737db45,aea48f00,b359ae63,bf604026,d4444df6,27f7d297,1dab6a91,acecb6d9,de53228d,47178017,921b90a5) +,S(ebcbf3e1,71de3a62,ef47677d,1ff4d027,5a8cd92b,bc889ee7,8dcf0c99,6746073e,878d63c7,bc9c7224,914a3f3,2dadeb9,95c6d890,a3823f98,5c3f574,9ef6ebe8) +,S(e4e92ee4,ce72ef15,b87c57d5,259520d9,b6066430,c090dae5,6e81b2fd,ab9db797,3faac465,4a03a753,559f47db,f5877452,6d21838c,9c1f8217,ebef6965,655f944c) +,S(fc1ce758,8e292b03,7b4ef743,12eb1f67,cf275fc6,7c1e3d63,5bc42dd0,deac1cc1,176b79bf,44f7d9af,7f7c791e,8cafcb7a,495bc392,c23899b4,2fe7963d,e65186d7) +,S(f1f5bfff,179e6a6c,692a86b2,1c95ef85,49482b3a,b97a491f,9e9c7056,ba94fc56,389257a8,a2cd3bc3,fb4f0620,5c2aae70,67041512,10c62093,13a2584f,8a39e143) +,S(980e7414,61c3e001,ba6bfef8,d175a141,2c7aaa2e,748c3323,ac744fd6,ab793eb9,6e37ddae,29e05e83,b3cdde28,d4286005,34cbb33a,636c4259,c7fa7625,1b31826c) +,S(f519cff7,686a5257,71986dc,7e6c1955,adb7faa6,a6f7a07f,66a257ed,a1b1c179,3e803eb0,8c765c98,7941d008,a93b8503,174ed4ed,1c31e97f,9eeb8f2,a55a807) +,S(2dd8d9ea,3851fea9,1ba9bafd,bcc5cc0,9011d939,10edceee,144e2755,ba8f8061,6147f1af,d4224689,37cd058b,4ef52618,7adfdea9,ce970dc1,365fe04d,1da52ae3) +,S(860c4262,9483537,47ac0c41,5aa00f63,2854f88c,d7d09b35,edefd780,1454a4ae,a2a7a22a,7d826d25,8e7dfc56,1eef0d85,d15378a2,80535cef,95ce6e2e,d73392f4) +,S(e76b20ec,17d82c3d,987d4ea,20535209,e0697f90,2c964b28,ae97ad0b,aed732a6,c97844b6,85f6613b,fdb7cec9,cc47f701,32bc1137,d997f8f4,ad182492,67f54bf0) +,S(26731d0d,12fba582,636862b1,62a417b7,718ec9cd,e3d047a6,50455efd,910ab88,3c10efb3,b464a61,6e2023b,b0736d6e,8d298609,47ba5714,3b1a71fc,9b542192) +,S(50cb4878,52db811a,87fe46f5,ed014db0,3fc4570e,8b2d8ea8,9865df9d,a224dcde,bb8488a8,7937ae89,88f572a0,c100e450,c69db48d,303d06f9,5d54bd83,8b39621d) +,S(fb69453b,1d67ffdb,670f9fb9,2b3fae5f,64b0c4d,cb28ba0e,7ebeeb21,ffb02a60,b0fdef36,92d881b6,3ebb1387,984120f8,d1ba17af,477364ca,41e303ee,a4fd2c39) +,S(a8f1280b,4b720226,19faec4f,ea3f784d,3f4061a,56dbbb99,38c7706d,8bb249b4,ebb3b571,ac505913,4572e501,4be7be33,a97e12b9,bc1fd9d4,484703f4,6e39b8cc) +,S(4292ce09,df305790,f17cb3be,30996016,420f83c1,bc19abb8,78b49027,6eacaa98,1b14d94c,bf2b1d1d,82cf1873,3461b76c,f32c8d5b,6746e2f9,aa2aa248,1c745d36) +,S(ac241177,f16f747f,b796750,49c83f8f,8e1a062c,9796b05b,8c5a5587,a4c9464f,dd057503,8261d044,ec84eb03,73065687,266b695c,ef5cb41d,1cba3b5d,9176cf58) +,S(692eca73,26bf2da5,7fd9d640,acf7f846,78e75c9b,86b18e7d,d7fd2545,751823d3,17d6d462,548ea78a,18557320,289d61da,14c3850,4ff03347,8f17fdd3,71c8e97f) +,S(d01b1a44,55ef5011,e4ecf946,ec02e6f5,d0e129d4,d2f59889,e823cc5b,6f10e216,84a4d89e,55e33edd,d54f38f2,1649f5fd,807879e3,388df988,34556ae6,57f91a0f) +,S(1eba61f2,96a788d8,9273a67,18f2a0cf,fb0798c2,393330f1,2f890bc7,9bfc1e9b,89f298cb,e8471046,2df0a6a6,b6c4b6af,505da2c0,9ee13266,bc47cd5d,2ddc9661) +,S(26dff8da,94603121,4649fe1f,721edcc1,a2300ca,b1a6d548,9c9b68d7,415980ea,d8264a21,55e1bbdf,c3b65862,efb9548f,3c4a0a5f,97f5b713,9d3da15c,90004e60) +,S(4e642b51,425e1822,1275f64f,283e9eb1,a3116adc,a6e25047,cee3bc0f,323fe676,f28b7d65,9125468c,4951db0a,bc35d4dd,65b9c5a0,ed27d742,47a68a23,89eafbb2) +,S(354aff5c,ee9a27db,37e7c97b,4cea476b,b4f3700c,e9c26b21,e94d2e1a,78f448a2,8d6907d1,624b79e5,6392d008,2f6a794e,99b4c4d1,6ca78dd5,97709c86,2930fcdb) +,S(5286d074,949369fe,8f69f020,c0b65f75,e76995ee,5f49b9dc,d570b956,8ffbdc3d,255ef2e5,3dd2c40c,1e462a45,27e6ee00,e0a23d3e,b16b05e2,2781de6,879703ab) +,S(b84a8346,c86e2299,9acc8ff9,1a893592,6bddeeb8,6fde121c,266d5f60,3268add7,31179a8c,79f40238,e1b80c87,81e46597,29f5c8d3,d8bea0a3,f65b403b,ef20789f) +,S(1e7bd5e6,63fc9a50,2258b9f1,14fc51c3,1b9dfc27,9022c67e,fde7872,dd12bb94,6287a9b4,555b146,7d250f11,e77ee8b5,7accefe,6d91cb6b,927611f2,c2c1b84) +,S(7ee68a21,37289ebe,7a5cfde6,be672ca6,9d28acc4,54d6b8da,9c96b2ad,37d2bc81,3ec34064,a6c3ca,f2a8aeee,9b24e023,3d7dcbe,b7acddcc,8a53db84,c570c83e) +,S(29d4b10c,f4be3bfa,a9d07fdd,da6ba7ae,f3adef75,67c3c33f,8d4d914c,f8ce570e,b6a74385,96a4f40a,40d03c25,2c7070da,2ec79e08,dbef71f2,422392ce,1058bf4c) +,S(7907c5d9,5c5cd647,e312a43b,42c3f053,50218f10,da6279c9,895516d7,328c359e,6c65a9e1,ec062a1b,f2abca52,fdeeac18,26888378,58f985d4,c8f1c987,64d6a625) +,S(cc436eae,ce11bbc3,36014fe7,bc68fcfa,e5bc2c55,c53430ad,fc994b8d,959d31b1,16160de7,d6ffbf64,d644e608,96052985,6b2bd539,66d7edb3,a50c924b,fa9706a2) +,S(cf023d5d,278d4201,ae659d55,6239dfa2,1b5fb30b,14adbea,7351b620,150ec1f0,d6007395,ffcec07a,6e71c26e,7575cdb4,34c473b7,57d4574,9e5154e4,d4990741) +,S(1a2a093,f718c59b,d4d35b73,2c547b61,12b6a257,e807a38d,71b04125,e7746a21,2674b542,652fa39a,1a2cadcc,3924796e,16c0f8b0,5d83f919,f8b93547,98fd4c95) +,S(534ed420,4b8ac51,7518fdff,224ffae,f712e4c7,6a84215,fac925b7,eeb799d7,35e5852,3ea6199f,b9fe497f,576dfae8,fa30782f,d24cd439,c0708118,dbd82155) +,S(8d31e4ad,9e6f30ae,6c78ff18,8f4b0457,e9ba646b,3a26138c,f11d84c1,4a00d08e,f0dbefc1,909396c1,3a1e36a4,844b2a87,e4b0b1cd,4b30e996,47839bcd,4dd5feb2) +,S(81748452,267405a,bf664379,16ff7f73,c418439f,86b73159,54c15fd2,2d2b3412,13d1209b,435b50b,1409389,9961f5ae,9f6f95fd,280beba7,cb3f3f5d,a0f19bbc) +,S(bca87f72,e604e885,64552b,edf380ca,45842270,57efe12a,6cc23847,658aaa3,ee508af5,28b77125,72c123c6,276ba23f,af26538d,5752d84b,54ee82ba,df9e3d0e) +,S(de2baa9,a19652f6,c0c0365c,d6e78cb9,d527e546,1240fc52,e8c59183,7fcd3fb2,aeb418ef,466c32fd,4cb5f2be,571672dd,86573941,a9cf9bd,73377aca,1ed38905) +,S(7b8ce1e9,14df7919,b54a0591,c077135e,556f6cab,c7665e5a,c0004390,22acca9e,a60a3ff3,9cd8ad49,c100b72,4338a54,d06a96a9,f3fdc7c2,fb8ae598,c0b40628) +,S(cd71c179,13fe7443,19bc80f8,205d7617,4d6d44fd,a6ac3d1b,402279b,eca50e75,9f1e73bf,cf3438d0,1f01d1a9,3f633929,ae385812,528ad211,967bf38c,71419064) +,S(42cad02e,32dc8dc3,4ba36161,d0816af1,619b70e,117da444,f4f1e454,73ca8fe4,97cb2134,5a259cff,8870823d,fe11031a,79e59d7e,dd2593c6,65128a8c,36e75568) +,S(98a89130,4f0652c6,2986644a,62a1dfab,48331756,c8b9e1f6,d473c03c,b98ff8c7,c130f2ce,cc506903,9ca49b3e,534ad484,b277e0ad,7b2a8733,98864000,e9a824e8) +,S(23c45c76,84762aa,7bfd39ff,284403b0,d7a4a128,6bd7b455,22c09d2e,df8a4328,f4ab7317,95c46f47,c3d46dc7,cb0d43de,d57cb274,ff0c350a,f0d79548,bb303cde) +,S(8b700037,d584c4f2,f65416f2,dbd37c35,9e6a7b83,108dad34,3a6c4d0c,6a21d856,8371ec03,9ed0066d,4e8e7d86,69169f9a,5a172cf6,c324c2b,ecdfc76a,c365ca35) +,S(da6164a8,d0fb4111,ca1d78f2,83e8180,4f4ae8,50ae8596,cdb97d9a,a30f8a7b,f9a8463,717e4f17,a77caf4e,10c11101,1cc0b5a1,c788307f,c7aba482,2a9a342d) +,S(49f37d65,a9d1a54d,1929b9c2,6db7d7e,c45924e2,9e6010fa,2202d47d,eb5fd6b7,f9b9b785,28f62629,7bd0dbba,9340c142,1e64895,b1befa94,ca677de7,686aa51e) +,S(8755f088,e26859a0,1a56b78,ba1898ab,12d80837,308677cc,b38e9c53,e36efa10,5d67013d,1eec7a88,215b4768,f55f83f6,434906a9,f2f6a9a9,de5df75f,6ef7e478) +,S(35321796,b7aba6dd,873550fc,5a35e081,a4e6d134,a127c534,69ff777,c609045c,47ff0f43,efa93f4e,f197a680,4f1e1133,c5c8301c,b49de8ba,6fe10167,f0a1e832) +,S(3abedd2b,644bd2bb,e77ab5ea,2823b42,83479fec,df2b3421,56fe9ace,612559b3,4269b08e,6c13b818,131824ba,11e3369a,87bbccfa,330e408f,17985b21,e5e32b06) +,S(e30112a2,2c23462a,a803dc53,e3277d7,c14b62cc,92787f77,5be98ffc,7c956de8,d0c7e3d0,dbb10e8b,7a9f4e0f,f93e7581,99d90f6d,d869368a,8d2ad369,4898da40) +,S(6250858,439c4b4f,30d47f6c,b9259103,bcdf497b,f09d3762,f1073f5b,973cd06b,3437f5e4,84ce4258,5584407a,fb0e4383,87e4c930,2fcc902e,cd26b721,5075328e) +,S(77ad4485,b8c94cfa,4e904bc3,90e93e3f,66838d50,fb16e09b,dcb39ad6,88f826ea,4dbc505a,9798879e,137c8444,750ec3c3,34c2ecb5,485bab73,6b0b9bbf,806001d4) +,S(5dcd3e92,e413601d,b9dce337,7a8e67e4,3852b8cf,ac41066c,ad579199,3ac0b7db,acccd081,35efb43a,306760ed,ec278f7f,36996ed0,d6367f85,417754cb,a4e997c9) +,S(3a26663b,adce051f,c41d2e6b,9b931851,e65ca385,15f59737,fc8c27f5,caff788d,2d647eab,af01d846,70110e,7272cb4,9b9db0b8,88a8113,bab5f89b,90abc2bb) +,S(f57cceb9,51dc98fc,712fe9c2,c024031f,4e3b0f02,5067ac4,b8bb0096,e4b1aec0,696093eb,7a8aebed,a751455,782f99fb,ddb2c66d,438a7bca,9c4df301,b7a1ea25) +,S(a89a4778,bca06e14,bdbd46c,948ccd36,df47c83a,2dbba9b0,93589406,be9b4a0c,f4224dd6,9d08262d,22b98e2e,4e781e6e,939d69ed,d59f30d1,d23f9ea1,6ef366cf) +,S(64738381,84fe8247,2b463f4c,7ff04a6f,6a3be92f,ba295d72,adf065b8,10b962a9,bcd100c0,d09f6e93,4fe9d58d,d58004d0,9ba164fa,324010bb,c973709a,2ce32de) +,S(4a683a38,21261e28,2e0196ba,d9f8727a,f7bcaa4c,afd5e686,6c7cffaa,3adc7774,b5aba4d0,ec3d9aa4,39b37f0b,15f40fed,913af371,b1b94f20,2cc93378,954ff3b0) +,S(1025e16e,fdaeccd4,436cfd9e,b8ee1614,53fee046,e420296f,53cc2e5a,bb5cb3c7,f806b96b,67ce92a3,e159b807,58f38f73,704e4d8,3bd611c2,25314400,f0c48f3b) +,S(6149d809,675a5353,6fe2217b,7f6777c7,60039cb3,5a0840e4,552e2ac6,db6650d2,e4ae636c,9a9808aa,4f49b03f,bd12f786,c72f07f2,9e397a11,68154505,b1a96ca9) +,S(ba24112,43888342,54ee8327,4bb03dd3,2fff3edb,4d607047,d8c141d4,c3fec47f,8a6bf123,29c3fcdd,38e6a18d,ed28c8a1,3717e997,9d0c366d,aa640dd,bad5c35e) +,S(c20df096,3c7cac7e,9dbaa259,538af550,35c00550,94ad4993,2190688e,7856a961,491e995d,16cf7ae9,85b8dd8d,6a5890b8,fb4f2c42,aea7c33b,ad84835f,b245d40a) +,S(6f53d8ca,4dbb4d72,d9ef3dcb,93dd2ec1,aac9f38b,1b4cb2a5,c76449d,4faf0c50,6784a02d,f449beb7,24156de2,486753c0,77bbecc3,27caee12,f7888687,4e7ae24a) +,S(e57e78bd,71a08f60,51c8a046,184757eb,6364ae0f,8eca86b3,51317712,737bdda3,a0623c7e,8a535f66,57116c82,da77554e,31a1d263,28ec0e8f,116976d0,f4385342) +,S(f52f6f29,aad496ab,9e0abd0e,a7cb53a7,7853e8e1,a6e5ffff,285e97c4,f7ab099a,3df7c1fc,6d5c5e81,8b5de4b7,66f2995d,c361511c,198a68e0,b7196204,559d55a3) +,S(da74f5fb,5c0a6d09,6fb26268,b33d9c86,ec5cf08d,8bd65fe2,59f836a7,3efb0dc3,7e50e989,de5e2847,7e31c816,42a51edd,8d0ea031,35423f3e,ffea07a9,48a62c47) +,S(2a2c9aa8,7bd45217,f341d35,9a9d2de8,35d14414,cfd3eed8,a2337a64,e051f4ff,bf9efdeb,99335f68,a01fd7e5,d8aec9f9,49688221,59d18bf8,a466c6ef,9648a1ce) +,S(2a3440b1,91dc5314,c6d0da7d,b07e2cf3,7d13bcef,1ebfd23b,492ad632,92022266,bdec24f5,c993a020,2f2fda24,e8707947,e4c1e9f2,2c34efc6,dd1e62d3,e2ae2b40) +,S(a3a9bd74,3d1d36ad,fad36e8b,d5544500,e0accea,d53d081c,28740109,e10942a2,cc33decf,f8cae7d8,dedab1fc,ea1b4c16,2cb71104,ff75c16b,66db334f,ec794ca0) +,S(5b83d48f,70a2f212,93dc724,77f4d87f,80db7eac,2b08d70d,308953d1,88804950,f78c0488,a10c66c2,e11368d7,690fcc4d,982ecdb4,7ed539c3,30d4b14,4248b545) +,S(dd5b46a5,6e3e4a22,39e210,a871db8e,d901ab96,3c6fec29,4140d77b,be9736a,d9b76eba,ebdd45ac,35c52268,ccd35df8,9e7136ef,879848ce,ae647c13,d421d46b) +,S(2f74db5a,25486127,6236bc5b,22214097,d1ff781f,3798f64,62cc6dcb,3f61a6d3,b6d635ed,256f6d2f,a91b868e,a3014db3,64647147,ac89248e,ca983c09,53149c1c) +,S(32adc0c4,1f7c939a,58640b8b,fde1c8ba,119bff26,dfe4b0be,c5058ddf,23ab2e09,cf317248,7f0bb297,d7d7772d,2a01d917,40beed83,3a35a293,66bbb0dd,3946ae3f) +,S(4fe53ca7,172da8,272a152e,d74c07ed,4e336cb5,85cb2ae9,36f9f301,87c6cdce,81f6d1c4,bd711c16,21cc2986,916578c6,baf42870,58b84843,27e46e98,81e3a8ce) +,S(601934f5,577fa2a6,702f316e,b4dfed9a,3b08dc06,5d3e58ae,63f8548d,9fb2569f,6df7d882,4360fd7f,b5f96f68,93b1f1de,55e19690,f6acf954,362074d0,30f714cc) +,S(79da708,8ff4806c,64492ee5,2e9dda2f,e1bec3c6,79fa3129,8173c0f7,aa79d321,2b1eca29,76f2884a,35167e8a,bd2055af,44be734b,b0e0847f,f90abe8b,17f9a47) +,S(602b8209,c39f299c,bc208b51,ca8bf691,5b8d4fc8,d8399186,7e589dce,79262974,f8b6cda,5d7ca83,6aac43f9,4791a5d8,a5ed1f05,af90f5f2,267cd9da,567f5555) +,S(57a4f368,868a8a6d,572991e4,84e66481,ff14c05,c0fa0232,75251151,fe0e53d1,d6cc87c,5bc29b83,368e1786,9e964f2f,53d52ea3,aa3e5a9e,fa1fa578,123a0c6d) +,S(4f9b48f0,ae9df110,70c4c5ae,2b012cd6,4599063e,5bd32b54,43548b78,6a06db2a,d5a7a0fe,3cafc78f,66f563eb,f6fe42ae,980cd621,bf18aa15,7bdeded7,dd5ea016) +,S(e46a5308,4b11349f,44661589,38bb663d,e1910aad,35de0708,5a053b5f,6c5e7375,da46da88,9583632d,fbf923be,9f07ace2,cb8c3d2b,fa6bfc47,9e1a7d32,e1183ce9) +,S(3643d766,b94b161e,323e64de,3c925040,d62f2ad6,2b60a674,15c8b962,1c071ea,faf69af1,1f2b9e05,db29dcff,a020f6d4,80835d4f,83d35a96,7aff1b5b,9f16fa98) +,S(96769694,c026152,1bbe1b48,544e05dc,e6bea57b,7fa31478,f6ff1b1b,bf497dca,4eb5a6fd,7d0dae14,9673b033,bd97c08f,8210fd12,c759293c,40782702,b3e30b03) +,S(2e41def,2c479931,89be0ff4,b4110e28,7f80fda6,f4134ef6,5c867e66,59a24d07,26a14d7b,b8388b12,a3ba1f50,e56ffb3a,69bde3c1,17441f52,158531d,c874c313) +,S(f39d941a,f6eafe0e,9a44fbf7,71eb63e4,db94cbf0,854a837d,b7f284c5,ac03c29b,1ffed770,dac4d12,2241f8b5,507e04b0,72cd5934,c03b0183,d8b62e73,8cbd7b73) +,S(90900d34,4576beea,911f8dc,c2d90625,1cdac045,28017d1c,59576449,50136419,60d38bbb,2a338102,da044498,a2b2c5c,1457cee6,eb34d666,b0c0956a,48161ad6) +,S(3a5e4627,1007f4a6,2e744226,f1d2b782,44a523e3,97b6509e,e3e1a513,d8ac2e06,50f01fc1,74cfc3f,256dee2,fa415f35,bcdfcfe,57b79d90,f75226ba,e8202449) +,S(f66ea256,f6d711e4,1ea5492e,f6f6e46a,b13ac258,a8f0eb87,a06b6c3f,13e24355,fb8a1c47,980ea6c,87ec2401,4c0f6d2a,8f32a2a0,6f3fd0b5,7fa00307,26243841) +,S(cada0520,19a16ccc,fbb6d4ed,6c7436d0,c946a485,ab3362a8,5c62580b,d3038fa0,e249940a,34804324,ac706963,91ae7393,421de971,af0f203,2b5f2d21,7d32ae6) +,S(d16f5b5e,820b7295,96bd5192,9dd830b2,ce208413,5c2db712,2c4e75fa,cb759cf1,70edb084,cfbebcd7,ddd36380,75e05147,6ecdd585,e228749c,e61e3784,6a448ed8) +,S(bbccce8d,dc6bae0d,cb6e5149,8c666f31,3dc31ac9,d4d949a4,84751134,d5f71535,4da772fc,63ff92be,5271b479,68e7bbf5,c8941f68,989fa6e,a23ce5ad,23f91eed) +,S(515f28f5,cd8b75c4,325e940d,6821eba,e7d5d2f8,e836b291,5f606152,ed4243fe,a13143cc,f5d2b8fe,14a09f46,68229258,e1855a82,6f7db2a2,4ba2f1c4,63668b47) +,S(bd2f46ae,a78c462d,8691ed6f,9d381278,68d356b5,b8fd7f79,df6ed845,21233837,8f645ed3,f3cc803f,7eb32f70,ed7d6fe2,84ddd9ae,62ab8324,b92bd7c8,79c4af11) +,S(8576f13c,c3d32122,69e10b51,2011a450,4f8d7d3,92e0f133,47d7d65d,f9e37dfa,fbbf2048,3fa0e131,2309eb8c,19eede8b,86ff9028,45b66195,8d19d903,f68b1a4f) +,S(70be1e91,8fdf4e47,d73f262a,bf2361fd,763a83f2,d31cf41a,23b8c9f3,8309db4a,82f80575,e4246ef4,c13fa48,8892943b,a1897ac9,dc3ef188,29f3f708,428bc573) +,S(bb8a093d,1d586b53,9bf54a46,1a353af9,173529a,12312361,c8064e91,4b41180f,460e0ed7,8456a251,cd68d66b,ccf5de7e,28707540,d221d65e,72334d85,af478269) +,S(7817ae4f,34d9194c,f4b30628,7071fa1e,7b976a84,754c1860,6dc4a124,bc5c2e69,25f4ec56,c4e3b1b5,bc6ed346,e4f8b340,6afe1c0c,f84ad7b,481be5dd,2cd55cbc) +,S(85c760dc,411f59fa,6feed8e2,a0e5bb5f,e72af5f1,2734c9a5,bccfed11,bf66abcc,92583db0,b57c9c71,bf0f1248,23a67e5b,89a8910e,6500e8ad,10666b26,cbcb8cc4) +,S(20d80d35,4d9d762f,f2c739e3,b1e7377b,d9ee7123,47ea979a,d4c81abc,5d5086c3,6e191d7b,8017a675,e8123b7f,1f1351b5,ef6ed6b,1b225cf7,48941df7,62f0efe5) +,S(3306922d,43f2c4b0,65f6d9c8,d1289804,ec26cefc,97090fde,86dc3e0,fdba5657,98a8cc9f,c93dd7ac,7079f76e,fa1c4065,86f0e941,9f87cd88,1b865c30,13c7efc4) +,S(b35c7597,54d37f12,440f7703,39223681,8a1b9aac,b085fc1,8acde6c7,3b2fb001,484b90,69b08485,95c58ffb,df5968e,2ea789b4,6f93d660,a7af6b75,13cd649d) +,S(9bd41b53,7f8bc303,6cc9d010,45922b1a,5c647f8,e90fd587,86ef0975,474e1f33,590afbf6,55ece125,da486bfe,1ff389a5,8b866776,8d2013ae,c25d03bc,bf0274ac) +,S(2a3a672c,a9b3aef0,bce89703,a38e0dcb,6950d93a,7359420e,5278f160,541ded42,4c3a94b6,13f3383d,b908ebef,6b62bab2,c95f850c,f88aea5f,c6af3b89,c2693d8e) +,S(31ba6af2,a2d94f8,d4df3800,353806dc,c8db945f,16dc5bf6,93794382,58f74d3d,ad19dd02,b290eb1c,ba5d915e,f60344c5,fc1e6a82,c5427f4a,236238cc,2329df5a) +,S(fa2199bd,74b014f0,5df0f9b8,ebf44a98,587c0251,e9c49bb0,5bb12952,bc869720,4328917d,6efdf5f4,b0f5c483,860e1e9b,41ab6ee,b1f5631a,66d2d213,b163f45e) +,S(417b9046,c7f53c0f,5ccf2847,692ab63d,8aaac02,e3bfd99f,30a469a9,8be22d52,78c15e65,5f309788,dff6eae6,91706e00,7aede9a8,3bdb08e0,d495d6a4,863b82c0) +,S(56ac91f2,47d51fd8,8a0e6eca,67a69ffa,6158f498,1714964,f33e43d5,6f18bc2a,351b7d5c,9e1b1a4b,717c518b,37b81c64,429beeae,26e7a740,c54b1a66,dd0680c7) +,S(aeba32f8,83307ef3,152d835a,a0babec9,e164ae70,10c90250,68507d65,37215f8a,8d747d39,35cf5f2e,6ff16557,7ccef843,7ce7e3c6,a41cc40f,dcde2ae8,582c4e21) +,S(42c7b219,9af00c97,693d6bcc,256ed047,79ee10eb,e4dbe63,d47d681d,21db5813,a15fb708,1fb1c7cb,2ce44a4d,f8958432,a5fd875d,1fcf7c75,c3c4865b,b219378f) +,S(4337b297,ecf365a8,88bfe19d,1bcd5fe,25e0dba2,9c39e2c,36ca116d,a24e5d98,49c723ab,c6541edb,cbc83348,5e06db73,28d1ef8b,c9cd9722,915415bb,2242b7ad) +,S(18998c76,1481932c,e968af0c,eb84b250,aeefbf25,27e4ef84,a2519a1d,b7f857bf,455ebc85,64518443,5cac9ae7,7f3289d0,91133054,d0bf9ba3,9b7c8128,26c97fa2) +,S(64c76320,fa24572a,590516f,1bfd8b4f,87767b64,1e65588e,69cb895b,6a49b2b,a39a2a5,c4795095,a03ae76f,86825ec1,78366c8a,8799d395,d39fe8cf,74b9603f) +,S(41657405,e35eb87c,a5ba5f2d,3c6f12a6,dea917a3,3b3b44e1,ebbd3bf4,812b0ad7,8e2169ae,36f1452b,4577fe78,7adccb53,4d0ed75c,2096b491,6b68dd6f,95ff815d) +,S(aa200fa3,768a4b89,16e110c8,f4a6315,7bfd4a11,2c10cb6,8b76e30d,c0391f6e,567bd959,28b21555,dfec898b,d7d198a8,c49b79d4,6905afde,7fb3534e,a584695b) +,S(7aa78328,841d2f54,b843ba48,c8c9c623,eb529bd6,9e584966,555f9bba,77131599,6b4a2715,e4b8478b,24da7e7a,64e2f6f1,32711246,29a583ba,1bb44af3,69f698ed) +,S(94b1a7bd,6a2767ff,459234f,c78fbbbe,48446b4f,64bbdfdf,dae34475,396969a1,8f3065ef,2273a871,dd29320a,8b9aa41e,e77e2178,e8b8854f,df1e88cf,991cc33d) +,S(6b957ba7,1bfeebf5,294c8cb2,7681e0c0,5407df71,37a34710,35fd98ce,d526573a,67e4808d,3fc1853c,5e5cd4ff,6efb5092,35c6df0e,c0a5f7f4,583fdb88,7a2724a0) +,S(8b274330,ea34100,3be93892,ab1fcb2b,f9a6dfb6,80bd9cb2,b8aa6916,43717f7f,54fa2abb,77855883,e627f828,49c71389,4ed141aa,9c9cda3,c99afaf1,7998db90) +,S(d3f64f9b,67362339,491274de,77ac665f,3b686372,499a12e7,5d145e26,7b58db05,c06116c8,52bd15f4,145284f4,3899faa8,9bea5850,4018310e,5c82a050,c9a52449) +,S(198926f8,ce0e4329,1bb9280,390f795e,870d071e,801b4d4b,c4aeb555,f237ba79,76125bd9,5b8d07e7,5e27658f,a0dcf10f,5d6c10d0,4548dd76,a833f206,d2b3d34e) +,S(1bbd4d,595152f8,39746cfb,6ddc2584,ee4358fc,6f878309,9adca58b,cf01a13f,18f534de,cceac5ea,7083cdfe,3de5ebdf,ebdc70fc,4f0856e0,b587e9fc,df8d7733) +,S(88737f45,b2639272,37cb551f,52022693,52457f,21db398c,1312e275,f5a3132a,79a5672c,2895e1e8,4b1a7b22,21ba0c5e,e3e61cfe,c95aa029,b2a179d,e0c496ed) +,S(cbf3e18b,1f277773,34cca35e,8fe1cfa9,2d68497e,46e7a252,4e14bf,cccb1e83,db00c395,65bd456c,3c9d242a,5f24748c,7b91f770,926ba9a4,1ff5c94,86bc3f99) +,S(8070ef0c,f186efae,5f9c8846,72a93a98,8ab65b20,2720893c,40b1a641,c7022f70,da9805b0,46946a05,46824cf5,a87fd838,cc85c853,a745d8ca,a249d881,127bd9e5) +,S(acaf984b,8fa45dbb,e84c5064,8b6fe23,5c57dcb6,21243e21,90286980,c3f71eab,46f4ec16,8259fa2e,f144dfb0,bbae2907,801b8c1d,f17dd0b5,d1db3bd1,2ceb278e) +,S(2893a05,91f9ecea,735e8a32,a57e3d25,e8916252,52a44099,4eeda971,fbfdc965,6ea29941,91e4b123,12b5186,efb7d255,372aa6c2,aaf12a1,8c3b15a0,7bcfbb6a) +,S(64974631,68f0cb60,9c926e28,5ed12df0,cfccab0a,58f11b39,dc05b644,c2be951d,ea74181b,2fa885e2,4344bb21,9f2509c7,d432b5a9,c178b406,160489a,31eafb7c) +,S(b938443e,513394c8,b2d4f7c2,9811039,918621c,5d3a86e2,d1bf0e88,ba1faeef,af47f2a8,c7d98642,50784f38,45ff9414,c52473c8,9b669be0,96387daf,c353fc85) +,S(bd1ee245,ad10f50e,9f8fd4a7,876346b9,24f4758c,cf69bb8d,42f6dac5,9d2a5320,776e2e3e,69d88d5,c26477ac,74ffe92c,134ce443,64b39518,af787348,e0039605) +,S(cb7ec68,805e855f,17e7dc05,4279d8fb,6d8e1320,67a486a9,7d49df43,c660650f,f50790b2,84c04103,11f302eb,71525fd,b12d7339,6d259b5a,91ce4fd8,229e903c) +,S(ef07cf7e,affbb5a,29e22a1c,7c84cda7,1968c615,fbde2a15,e1c1211b,ab30cf83,98f4a6c9,422630d4,103fc2fe,e4c80f2c,2ca5565e,25859979,815c425c,70ef574f) +,S(4ffc1948,4d7fcc59,ccce4ca0,d11400f1,13dc5064,8626781,4eec26ad,3e7b8fc6,be9ebe07,98ff3d83,cb5ac107,5dc87f12,d94b65e3,937ee669,61b4e587,7fb75aa9) +,S(cbdd5373,339ed493,b8cdf0ef,ac6371b0,fad1ad6b,2da4db63,b4ed68bc,61d18396,527de487,c3212d47,1f538b6f,f709c130,3784a7d7,c803e5fa,c77bfa1a,d6bdb13f) +,S(ea035b2b,d8a1d7e9,db7f6b06,5e003f99,4e650aa0,e3035fed,65e7bf5b,c67cb5d2,aecb4370,2219f488,86772e91,afe81c6b,2cd57e96,2a3b0edd,dbc64608,8c3761c4) +,S(de1a4fd6,c1d6240a,d6e9dda6,b2d43fda,911648f6,901ed0cd,99ba8ef5,99f8db89,effc94d1,61c0ff41,d1ca6085,371e2e62,f85f90b1,542d2cd,3a4223ea,884da03e) +,S(2e644141,e8d87ed6,e1215787,8bcffebc,d75e118a,f00fb7f0,e58cf5b7,e6a076ed,4aa858dd,f2ba62d8,6b8a7011,26d22c2,b45c240d,f65f85b7,320e80ff,cb34b8d2) +,S(3844386a,90d6b878,90fb78ad,8f2d28e,47ff8879,2d275c3e,956883b3,71b73a33,f7f5df12,1a8149c0,75f6bde1,2ca8ee89,ff284557,f17cd57c,714fd474,b365cd18) +,S(e1fe9b32,1b91d362,2b618cd8,9ae8203d,bde185e0,bab2fae8,ff7e96f0,74358e42,c590fe90,1797132e,a25eff10,f2bf2a76,cef4f064,acaba1d5,f8537b4a,ddf3e1c4) +,S(560a00da,2f57d821,b6a0144d,45898af0,aefbbded,a1e08a49,9cc727c4,b27a3c0b,64874e4e,39db1377,3bcb79ff,983b152e,5db86d63,4dbbeeaa,a8b0112a,e795e208) +,S(9f33fba7,7ec8de2a,c1b16424,856e2814,1afe9b1d,bd0cd1dc,e5cbb2f2,f379094d,97cb8cd8,1838e2a7,26034f19,b5decd61,d972abd9,bffe3848,92fb0a9c,26fe94b0) +,S(98822fa8,24057512,48f9da04,2a0cfb15,e46ee253,e06a1226,da75047e,72d7a1b9,3e9eea35,7bc54ac,da547561,1f9590f3,db975d4c,ce7c4cc2,a553df14,feb19285) +,S(b814d1ac,4b757268,6ad88327,32f0f84b,bc72875e,7e21707c,c4086a06,ac1dbd88,b6364488,3749a122,401b8ab3,c4a7b8a8,c03462ff,18d69c36,cf145299,f18a98) +,S(246484c4,1e42113c,cd39f7b7,eed9dfcf,b39cf842,85c28cd8,6233c1a2,bd043e97,f35025b0,2e31bdd8,41d36f7,9d0b75e6,80f431eb,44a50502,3877f5d0,eb9552d3) +,S(9f330365,7b41b2ec,d87fff0e,4284e4c3,bbe8c524,91d358e,847afb98,ff51db91,4b9a7bcb,221c8870,de176a43,d4f7cce5,adf519c1,75613dad,317f4337,72d5e70d) +,S(c2e78e9b,3c75433c,5f5623a,8f5a4dc2,b0e71951,4b16161c,225b9bca,9d529d25,1e75c8f1,938376ca,c6387b20,9b24a2e3,e794362a,d62441b9,50588a3c,ab9079bb) +,S(89340ec4,b6e81b7c,855c9636,b548aeae,2125c40d,2907f86,7ce5e6ba,a7695391,f739a94e,263e796d,df1cc2c1,3e2bc10,2b2a9c9d,55248671,575c3ea3,792c72c6) +,S(9204ff15,f1443cc2,78facd4,8d38a6c3,5d66a93d,8fd8e2da,a7e2bbe2,d6629d22,2b9de875,456b50e9,6205020e,c293ff3c,13120555,82727253,be10263a,7559c019) +,S(f156da10,41122fd7,ce6b518d,c325f5de,61fad9e4,a7bd684d,7abc495e,ebff04d6,c73294ab,f4f2adfe,dcbaa78d,2031a5d9,7f2c404d,739f5703,76e46a0e,1b631d4) +,S(771a2d78,37d6413a,13099861,6050c362,2c379a55,26506265,9fa7da02,3280fa75,8b6bc39f,5cfe1f5b,82bef0b0,f6c8dd1b,e4270304,d5bc70f6,6b600b26,5d4c9aca) +,S(14cd58e0,36bb2c59,f63b52b1,f40e51cd,aec29f0e,b1cc0401,8e512366,85a18f69,79c254fd,ed354641,744c7262,39ea4e8f,ea15b19e,746b372e,f270c8d9,9c5e2006) +,S(e5f54077,1060072,5800bff1,390a67de,cd539cc9,52b6b43c,22bff27b,1a8633f1,d6e1c6c3,9baa86c7,5838e691,f9af8a06,80274da9,b0f54b5f,4c3b2028,8d666367) +,S(b0eaaf42,9c072037,fbfd14ba,79693d93,6791344b,3d37c3d7,5b8eaf8a,e7429197,d72661e,4a171b65,4f124d9b,d0201710,bc237382,6a2f0341,51051716,9b7af26d) +,S(e022d70b,44edaed,35957383,284e4ea0,5380f92e,cf62ce88,3c2e11e6,604d67c2,423c55d4,3ba0ed0d,1455228a,3153e9c2,7aed89b,2c3ddc71,52d2b11c,91ab4143) +,S(92a2d73e,b2eaaaf2,65a70f07,b949511b,af1a3eda,9e5d8651,349a665a,4bc5ab5f,4492d419,4794d254,9a089fff,53a32631,5f1703c,5ac34049,92d68121,e00fa973) +,S(43409686,de50a9c,cf35ac44,47a9ceeb,b12f102e,3ee6003e,c96235a9,8db9cb30,2f781040,952e1017,8e4e38ad,bd9c6c8b,c8e1e898,7f316cb0,37d2cddc,4e10bba9) +,S(d349dd1b,643f8d4,1b83aa5a,d735dc4e,94542643,3888a4e1,aaaa0ade,2394cd12,67f2f057,1da2b6ac,295c71c9,ea00efe9,cf082257,ece35bc6,72adece,433249a5) +,S(9a909a95,7fb87ebb,35f6834d,272d8ce7,babad39d,8f8323d9,c6813781,66dd10e6,ce3ead1a,32771a28,7f624835,2a2f6001,c12f16d9,f7093cec,86386572,a2ddbca1) +,S(f38b1e18,df2a2a64,9a3be25d,3686b5fb,1d77f971,1214d452,a67bccf0,ac07fa0b,5c9e9a,7f71b201,ba11ced5,9c0a4623,419a20d8,c488f9d4,591671ef,71e65ea6) +,S(42360fca,26b8d095,df52738b,c2762ed2,7b909784,c12b79a6,a86e06c8,31535a67,6b6f4ce5,e43ec003,be88bc43,2bddc453,db93aec1,657f6f66,5dec1912,468345e4) +,S(e3d7198d,a7c5e3b9,997993ea,a32377b1,b87325c0,5a002a94,53404c36,303f4a1e,72437218,ece6148c,df742be8,35fabfe4,a05f19cf,3205e65f,5c813781,2053ef4d) +,S(39412945,a8301110,6b54f625,8191529e,2f93db5,bd68db48,d6bc6d9,687cb59b,b8db822c,60f5c319,18b05784,40a958b4,e08b0a80,a1015d9f,d2826506,f250f08d) +,S(4d275f7,7e0ee98e,76b857c7,ed9368ce,d93dc914,d54ad4f4,21d2c097,cd241fc2,ecb803d4,9b502911,f619d361,f952ab13,935448e8,90cc2f05,277e48ab,a39d7473) +,S(29364876,c1db9cbd,a3efcd5b,6599ed59,160b145,3c8a9e03,c013f807,869556ce,2bdb4af4,cc44950c,84f56237,95941f7e,43ffb56a,77df186c,2dc31910,f23f6ede) +,S(7531f4a9,63dccdf7,ab83ef10,d3ba1333,6febcf41,f4b21e55,d380ee6d,e4878034,4753da9f,91d56bc2,1e9628ca,2d6269b1,e1dcb1bb,87c55e,9c44034a,1ba36ae8) +,S(8266d626,3d12feca,440dce7a,4bdf8ac1,6050ca28,5bc16777,a3d9450c,5c286e08,2500f2bf,fb8a4eb6,6a5e7e36,399f633c,96d908e2,5cda4877,5455df2c,afe2328b) +,S(66480001,4f339f15,8c39b26e,84389f87,6d5e62aa,59cb63d6,9eaa86d1,4bc589e9,a0699b3f,e3eb5a37,9f078526,375ac319,f145ffc1,da8a42f5,96c7016c,4ad92e2a) +,S(f8efcc85,8b9c0fba,605921b5,e6c89343,f641e2b8,e1f45134,86b77ab6,4cc70d49,ba97202f,7086f0d9,af5a0ae3,35d9a3c,5f4de2e2,79278834,f8b1d875,50a9d607) +,S(a5c1227d,254324a3,b1ec627c,93abfb3d,6f2485b0,1d8e2e73,6c542e09,9c992540,c9189db4,8a163bb5,6d99bed7,f38a7f7a,64cfef45,cf977da5,a1d16dbc,86ecc7cc) +,S(271b2619,a5b253df,fbb655d,7702dec5,6c85bb00,9260d893,8e050606,b8bbaf3,58ccf3fc,22cb8f27,dcdbd174,6abe5591,72bca7e5,d5af3bd8,d86c9a49,3ecd2ce5) +,S(c9e1382b,20c79741,d81800c,e721d4f2,1202ba30,92cac36a,d90c1dfd,570ae16,7eb1fcab,2a47cea0,3a92f707,d799749,6f7a0dfb,f9a43f6,90d213b8,1231e5b2) +,S(574b25,65232a04,1d58cb75,12b48945,45897e6a,8bd47dec,b1e0941e,309f2,bbfb86a9,567d74bf,93fbf2cc,6a9c9dd3,474db8fa,c2b5fb72,38b3af8,fe4615a9) +,S(9efe86ac,a6305eda,4b520e00,4dff6c56,1135e7ec,6953d2b4,a988d508,63046c38,4f92a291,32cb0818,af7cbe67,ec3b4d8a,7afa4f79,91a9ae42,551ad831,aae9af70) +,S(82ea48a0,ff76fa17,374bf4c3,d0918e6a,df26cafa,33d87284,13aa2dcb,d813f254,6a029539,9bb555aa,39de1ca1,417a8950,49b4c2d6,26ddf8e4,a7086b1d,bf2ac9f2) +,S(c289483e,817bb06c,31352a24,ba60adfb,e3af2feb,de329f4f,5fbde755,bdd2baaa,3b7ee90d,8b4aecef,62b6854a,1feb595f,9c49945e,c19685c0,4b13a1ce,1c780a53) +,S(6bde46cb,b5580d58,ea68deb3,1b0587b6,1698660,d78a8300,1c740b4,96e12cc4,3188a6a7,c1cd166a,4894ce75,c79d076,a41cc5c,d142ed91,e096eb32,e9293292) +,S(d1d2a3ae,2844615e,57f0a11d,66fd7571,176738f,a066cbdf,4519ac1f,65827cf4,7c0cfff7,c01c196,8b7697d7,c51562eb,8271f936,5c7daee7,f963122,67f603db) +,S(b74c0c87,4d195557,3b551c85,2abf9a5c,e276b088,cfaa0be8,f6515ed7,ba27370a,f0cb0e,380c571e,fe5e307b,ec4ed8c2,6f0c325e,114d71b5,51e0f1f7,45a662ab) +,S(a9a71b9a,9f126c3f,a17c3041,2317e118,84950077,baee298f,47d42609,f9015874,c05f3ffd,b31bf0cb,7fa4be1d,f634cecf,f1b1137f,551220f0,8f34c2a6,a42e0586) +,S(d6de1153,a161f27,ddb51416,2b3f823b,2b1b99fa,3fa21c25,9b02274a,80dbc68c,6c620863,659785a5,eec15d25,9acbdefc,714fab61,4e766215,348c80bd,bc59764a) +,S(dcaa1dbc,3acdca5c,51f8c22f,359487fa,73a7dc36,2a796df,11292a74,776b73f1,dc4131fc,c22c607b,4833719b,1715179,b4b4d49a,958c7514,7c8c4a8f,cc85159) +,S(135537a0,c4be13,1c3aa93c,677094d5,5f3a1300,95499d21,2206a244,5ab6c,7ef69f1f,d2d3df67,335f0d1d,dd52370b,8f3ebcf,e3483330,48c2f045,64fb0f69) +,S(28f1d817,c23262e6,4cd572bb,e3fd99ae,751dd6e5,5e9e804a,fb3fe9d8,39de93ac,24f5861,987e3da4,2dae0e89,67c835ac,8f5dfe8b,d41e5cb0,97029b48,39e2cb7e) +,S(f7c4ef83,6e8fb7fb,8eb31155,c08102df,e0779b87,9ad641e2,5f8ce135,44294289,7f9a781,db339621,d6150f09,16eb9682,16470d23,6957a0d1,3629964f,1f6bce2c) +,S(f1f5ae5e,1ddc9b35,18b66f7e,25a735d4,ddc8d018,5112faed,a8da8f66,1a28b3e6,9dbff12c,97924d80,50a4a8df,24fe7a8f,5c5c3486,3edb7cb4,1c6d9ddf,b9ad4288) +,S(95f83173,d170ce9c,1ca0dbc7,4578b639,257c10a1,eb65827d,c2afbd73,8b654f,63a83ebc,8294a88,413c3c91,c6918a31,7d5ab83b,7bee35b8,b75d1cbc,3412487) +,S(f4ada65c,9f095e11,eb88c8e3,77d60553,96474935,91be3a7d,f8c83c09,6a3ff750,e7683f28,a38545b2,e6cbc87c,3dbcc4a5,2ede1676,1b0dd78d,3ac51a5c,ad861ed3) +,S(41afac96,f714db3b,1b7bcd59,1dc7bc24,40b82756,d9394fd0,3afe7ae4,299e5fd2,9c2e9c6a,3292ff12,426e98ae,ac654a44,61c52d00,5da7af20,474e9a47,499fedc) +,S(37f30b1b,2cb81c9b,61941fe9,cca35f0d,e1b8dffd,c42f3ffd,ccaa16e,e8487405,92bf7a85,e3401d51,d9fdd08e,1086b649,8086bb3c,a4c9a2bb,61b1d54d,8cb88a0f) +,S(2f577166,646e7eaa,21531202,2ce0c8eb,605a2199,454c205b,9d760716,584fb3ce,f0d7326f,e43dcead,5ae0dc68,4d04b969,af32e8da,ed624ee0,98567dff,3d5f446) +,S(8abbc780,92c5512b,5eba0af9,4affdbf8,3c2e24ff,bf9fe7d,fd57e5ba,64b5150a,58f5998f,c2ec19a,a495b974,ffeccf6d,bb87dec,49152327,91a167d7,f6896b75) +,S(e41ace8f,a01376b3,27c73fe4,7e57cfc,f6da7cf5,c2810aed,219dd065,c147571c,b590aada,3c2a714c,322d0459,272f98e5,715d4545,196127a3,7d8a94bf,776844a2) +,S(300c9877,8b6355ee,ddd80f7f,4124789d,7c0c84fc,9d9ebb5a,be714cd9,890f1d88,dac2ba62,c5718731,c8f5c7a,4e1a7b80,68c5076c,834dd385,20f5e93b,e39c9002) +,S(69e339d2,19d40f84,25a072c1,f7876c3f,dcdb6623,26ca1b5c,87681707,12e24c61,8d439150,59a44700,2157e849,9b535921,4cd47280,937405a1,bad0b86d,38babc50) +,S(e56493df,8e47a99f,8ab3ccf6,41fab7b4,cddd779f,51fc746d,a2fdd484,cbbdb909,68dba20a,559e14fe,d0806036,d41c18b5,9745319d,758c1145,b6e49ca3,e3f5ee59) +,S(37a91c57,8998511c,d39c11e5,86e00eb0,f76532de,574d9c61,1a34d38d,e7f50587,e3a188af,d2d8a24,735975dc,9da895,feac2710,ab9d381e,e5d1dc43,b3145f18) +,S(c5f059fb,5cc262e1,12c629c7,194d783a,6224016f,65e4d24a,86c52742,dee88c1f,1c85bf52,1a96a95a,5177792d,590b46d5,8c090705,1efa0623,ab15578f,b38c890a) +,S(566edecc,d605ceb1,a298c59d,78401acf,c6323c63,f2845827,62678924,9b8716a1,ee0d1373,5adf6f20,789f85b9,32d332ff,8c40b3af,c02010a1,5ad062d4,5a44cc90) +,S(327e7033,c6ef4f87,52e33d,bccb4642,3e6cf4e2,c3ebb4c8,db69ccde,db2c7c7b,fc49092b,2be0f29b,4aa3e266,709aeb1c,12266239,f7bd9263,4aae16e9,53e8db36) +,S(989a7f69,3ac0ac86,55f29704,ea6caff6,84ef5ae2,8c5f5e1a,1eae7009,97778024,573d127b,3396458e,74bb5bd4,4acfea64,e8eb1fd7,3b0b292b,d1b7b642,80dadfd0) +,S(9ca7672f,14f27f54,ed1cec4b,74f49a57,7ce313fa,4a665976,9c22cc61,b30fc94,f920c4d7,31d52a4a,30803f81,82df8d30,6ab14104,eeec11dc,d2d6ca0f,3904e4a1) +,S(db100645,654fe8e1,95831687,17e2721a,6097850,ed2ef0cd,e1d5555e,7847f5f5,2b2c3ece,a9c90ecf,34fcdf89,5f76c8b6,619287ce,e745014c,96281928,31056567) +,S(4e2a0c9e,82743b42,5e6110a8,f3bff14e,418a34fa,65269c07,bb94d00c,d53295a9,512ac2e3,e00bb04b,6b4b9059,a3ac69c,8a34e5ec,8dfa14b3,d98b2c4e,3cccca7a) +,S(c12b3f70,24ea8acb,5136f98,185fb1cc,60c71a77,2943b68d,7334352f,66ac77f6,b799f99b,6f4b76f0,1f09f5a7,bfbe2526,d67a195,83327323,9c07bddf,2544803) +,S(64e5a2e,daf34e1d,ebd7c0cf,616413ff,d6c09b82,bfa783fe,aa755464,8ffd7e58,e020e09,66f032e2,e905d611,adf0926e,7509a2a4,b51844ff,72651f34,3c2f4a50) +,S(2b0b8b55,fa734380,f6ad1857,e03f02dd,3d66ec57,2cfb3b9f,ef040895,3f0a838a,ac897251,a9146597,8e0b45ba,e1c880a4,147ce01c,3408e476,5bd9013d,9e73a61a) +,S(ae0e3d30,a2026133,d3a54529,965a9679,6523e8b4,1efd4c5b,d6778930,2a88525e,fb6918ff,85632d24,250be67b,339ab260,c80c087d,da1efee9,7ec5dfb5,38f80552) +,S(2ff9c711,4dfea166,ffae46cb,1f44c3,3bfa1530,edf23454,a83de862,8fe00dd9,53f667a,4441817,a3e38351,78195c5d,acb0d707,bd20e759,9b5e82c4,6f318783) +,S(cc027014,88b959c6,c043f60c,c42b1449,9e2614e4,c19f5726,3edb116a,4e7bf695,eab3f590,9b22f677,666ce655,149a5f07,7b5325c,2036dfe2,e572e64a,5bb6007a) +,S(1801efd1,3c8035a6,5efe3b47,68495d27,f9dbf45a,f019d455,84d68be8,28a945d5,dff2d19e,fcb5968e,f4ef49d5,9a82f8b,f44a5abc,e0b68568,1acbda1b,fa59c4fe) +,S(6da2a9d5,7b60962,357c09de,4c7ababd,5b698fe3,6e747f8b,e6ab78fc,3cdd7cbf,1e274e70,4aeb8ae2,295ac9f9,b37c0af1,71310b82,99acc378,d505bdcc,e275060c) +,S(7e8fc96f,6a9215dd,3bf9e8a6,ea944ff0,c7dfe23a,1a99f44c,832a11ad,bafc82e4,e9a4fbe1,e0c26ca7,f739ed00,c63f3886,57d09503,a808ed51,ddc872e3,b1342bff) +,S(a6362f3a,77d6d6f7,fe266ab3,78707641,9f53e133,718ccf27,559bb448,7e0caf64,c01622da,3fc2385c,60a5cd86,66f751b,e29d8539,f473cd70,8784d61,d2cc787e) +,S(51865222,28b47493,a3da19b4,7076c1a9,8582bd55,37c25557,44970075,9b37d2b3,f0f0b979,68638d9d,93fca65b,f40cb8ce,826558b8,52451ad1,7d0afbd0,44287be1) +,S(a2a0909b,a9f1b9c3,8c714ff4,f71995ab,4d80212,9e8ee8e6,7e8bc3d1,81d472ce,4123900b,d45ec7bf,71bfdf98,ec453392,8b364d1e,cd925a6a,1e8f5c5e,ec40068d) +,S(da518122,454e7f36,a63f5ac2,a1bf979e,f1357bea,f9f0c921,2b031f87,b83aef2d,bf877efd,d415e80,c828c5e,1b9dd8b9,6cb7f3f8,b9a0cb32,b6bd8f37,686da722) +,S(41c40c54,1a983125,e59aa572,910c5aa4,8a698306,d483f82e,6cbd7506,3947a87d,76dabb65,6b89910a,bba9f129,ffbdf5e7,ef840033,c30f4c81,4e86f101,a3bfc57f) +,S(c49fde83,87f2e464,6847c980,acc50d88,28745e4c,88a41318,709099cc,9aaddbfd,a65bc512,dfd07bd3,79cbaf9e,628be7f8,c7ddb4ee,6611fa94,bbb48c7e,ae7227e1) +,S(85b17d61,b6ee743d,4df21940,6d7b7426,3a6c6b88,e8c51071,7a1f0183,e0fceae,22b9e8a2,74c71feb,5046ce02,2f4bffbb,ebddc53e,704f6be8,92d3092e,55868fef) +,S(c8e1d37f,e6d677f1,3e752189,505639ee,3914afc2,c8d4e43e,883f5c54,f117964f,b0cacd18,d08f5a91,af46ba55,91f99497,ee4a7ab4,36ab48e4,f88ad5ab,39bfc21e) +,S(dfec0030,7d25888c,5a7d6f83,33112995,1a30baa0,b97add9,866078a7,e483836b,4e5a8a06,bf2e9447,ef466416,82af8e44,f407ca0b,6fb97809,56e13a90,bafaa00d) +,S(eac6c438,7c18d8c6,eed7618d,c9d3076e,c842ff6e,5f4d4b20,92594d7f,7f0be9d6,19d69bbf,fc0c1b82,ba71802a,c0feebbd,77a86a67,d734a163,4e823a6b,2265b8d1) +,S(9ff38c4e,4dcddec,a4824db7,97f6ac80,69432c15,9cbc99b7,4d642011,b3424cde,f72fa660,b7c1bbfe,df45b0c9,3cc84b81,266bd041,b94f54f9,1d26221b,51619ebc) +,S(5e78593f,3a5a3293,5f9e4f8c,4fe28555,9153f69d,d44b2c1c,146fc644,a5313f36,9d9d5844,dc63bdd1,b2d95b70,5d63c97,58cbc5a6,1b2d114b,89da9b9a,8afd9c47) +,S(a107c7a4,89284b6f,b01ba38b,3e221c2,ad31a48,77af9b32,d22c8544,71009ae4,66072d4,6be46591,ee386cd5,bc0f9f2b,653b580b,c515d4c4,a0fc369a,27d9f6b5) +,S(241f1d0,308d9845,fe2445ba,67929976,ff98e88e,cc23a8f4,190ce5fa,41b02af1,886697ec,d413a88d,fa15723a,daf91d32,9c881ee,c5ac9c74,366b7ea8,a7e194a9) +,S(319ee8d2,627f906e,83d5c6d2,6eac3b42,34186016,8b9a9283,c8790c6b,e48a72fa,59e496ed,a67816e0,3409f849,1cb458c5,76034453,65fb281,9d0cc427,3e9eaa57) +,S(1866811a,fdf9bd,937f4f7e,96985759,e0100866,192878e1,a2614625,bfca4822,215e0465,e85f9c88,2783a131,6b65fa7c,585f0319,1a642501,72e51269,d5b7ae19) +,S(7effbed7,b949000,5db429fb,8cf64099,3989675a,f7394ce6,9ff2f769,53992f26,6efbb5ba,28f26d4b,5256affa,cbf2dc0b,616d8b6a,c6cd2aa7,a1d09ac8,40c7c749) +,S(d8c72bd0,e59315f2,1fee45c1,937952b2,665c8d66,70f14bf0,957a4d25,2b168867,64c02d62,fdd40a6f,d11e2cc3,a73fc60a,8a2da31b,2c99ae6e,5a946c61,be56fbcd) +,S(710ec622,ce64f381,43b96bbc,b0b0d691,87bbfd51,fab4d47a,bcf18308,18d0db4b,edfd1086,526c3af0,c2e9b961,890f531d,3d275c36,beabb0c5,4963314e,4534d994) +,S(9427964b,9aeaedd4,9c168e76,38086ddb,70574f27,9e4c3348,68e4c595,30d51ca6,110b41cf,2a6b0067,eb3b312e,928583d9,e0026bea,684c57af,7300a611,5c4e2dd8) +,S(aef79435,a8b3ed9c,9eb515c0,6db62165,c5a2e816,5eaa4a5c,46a59b39,8f55565f,6616e8f2,1274c425,c50cb93d,8942aab3,3653511,3c3552a0,118b17a4,5584b91d) +,S(3ebdd832,3546063a,68f40193,59d72f26,f49f0ce,4a5af994,a4ac67f3,3074b5a3,12367d4,b29549ee,d0eba318,f395d712,db7962f2,c8e2d9be,ed895006,78460238) +,S(a38d9e5e,c52b0871,d0bc6bc3,b673c848,19af86e2,534d60dd,729b405e,426aeff2,ebe46771,d9ae6c5d,13895538,3c8de4d5,f6d13428,8ac36a1c,b01c75e9,f32cad02) +,S(e7d29f82,619cbb19,90c407f7,b452cb8e,334369a1,16901b0f,9f4ec342,48a7d624,7595ced4,618b5160,6b8ce230,45d7616f,15b6ce14,aa8eee07,42bec5b5,9fc4e614) +,S(ec869eb0,279227b9,4ae333e2,6018f00c,7523de5c,e3e8c4ed,f81cefcf,4043ceae,a421aa55,2c89c841,a48bdd26,4e67d82b,ca3fe577,64101556,ec6ba7dc,711ac92b) +,S(4549d908,e44a8c8b,6fc5c057,144a352a,6f07523c,e026fae7,c070ff35,c6ec5e71,71d8e320,7707e04,10208c19,e2c8dc79,64b48600,1a6d640f,44c1138b,7ab5dd7a) +,S(51bb6e9e,fef7b8c9,b0a4f381,3e1406b3,2cc7a53d,165b385f,f98144b0,a5b070b2,65282be9,dd794fd0,8a31de11,d46df7cd,5268eedc,aadf3bef,de5956b5,a467044e) +,S(7cdc3297,4c7caa82,44203afc,d48e625e,aa2027d4,d91613e4,5a83eba0,696d001f,b92b9943,3b1a55b3,b78027a7,a289e5a2,6060a411,6c2cca36,19253490,83519565) +,S(3ca9c6be,b8e989b6,a67722f6,d817a6be,aa478fba,10146fc9,3099575,609c9314,5502ed7f,f4b81bc3,8386bba3,4124ca30,74c6e0da,bd148e4d,6bb7f096,ceca2c0f) +,S(aa2abe6c,45edcada,f01bc1c8,38ed5e63,90e1a229,cc920436,864111e8,ad354d0c,1b8229c6,6f91304a,24c61251,f1ba2b26,95bb3da8,87154d47,c44dc9f2,f824f6cd) +,S(b52cae3d,f28c9d59,319f226d,ef73b60f,75466aad,fbe6f75a,2ab6936d,8e3bc7ee,ebee735e,22c091d,cc873848,8a7c958a,421e0759,2e17fa3a,4462db88,8bcfe220) +,S(c1085703,62a6dcb6,13da6283,23496169,635469c3,47b65661,838d9053,3821ef54,fe6442c8,c1e6a8eb,2dc2cac1,40ad4c7c,44511cdd,82b79cde,c38cf9b3,4ceaf517) +,S(f09e9d1c,fcaf127f,59d45476,56422907,83477fcd,2fa6c768,d5a3965d,af08c11d,f01a722,1f44fb15,bf428fc9,c5d7efd9,a5b2e663,cfecc9a2,7e8f964e,8bc15d10) +,S(602462ef,1e473ebe,d88b3b17,9d71b597,fd3e805f,e03d341a,36c277f,495c4527,f91db461,71411dce,aaad9f23,53f2159e,fed2a9b1,eb9d2ce2,844e1f6d,63a079c3) +,S(273a881e,8e0d99fa,104ae355,8126a20d,6b828d13,96bbc70,720197fe,9bb582d,5bb26c58,14a7b914,cd3b2f72,7f76b6c0,d1b40775,79a2c3da,29534a1a,684b0d5d) +,S(7c1df346,616cb72,b42f4172,36fc98f9,e8cd0504,1da47d9f,566c8df2,e80cd54d,ad3e7e0d,d602b9be,45ba8d45,6bc12558,73153c2e,c16773b9,390ad630,4fc41dd7) +,S(796e2634,657ff114,7394551f,3ce800b7,9ad644b0,539786d3,c62c6551,3d942f94,b65bbe38,ed587111,c480eb9,c30081a4,1e8ec66a,8400db11,bb1cc7c2,a14f1c60) +,S(5e2761fa,9985f68a,a469953a,2a6642c8,62b0565b,602fc206,193bded6,1a302bd1,5ba09b70,9db24f5d,2f47c07,51367d0,3715c9da,b7d430b4,713dbac5,7253e274) +,S(46458c92,fd341a0f,eb1ab038,5a246b40,5c004c22,98db90e6,164126c5,4fabe794,859d68b,345341b8,58afc324,263f1ca6,9d018fae,eecf33ea,f02a3dd8,d7446725) +,S(fc481830,bf817c1c,ffc9ddc3,d6f4e624,a410e134,cbfb952c,5c7379a5,81153265,a188b228,bd3d7da1,44a48e89,fd9db4ab,8dfe385f,ace8e169,a43a2787,59322551) +,S(42d9767d,9771a550,3c702742,ce2aedbf,3a780466,804ad901,7792610d,5eed03e6,df69432e,9764f337,3a2c782b,e02d2433,d2e0f568,d0dd83ec,e89ea1c2,5ad50417) +,S(37122c49,993ab297,72e60222,615ed912,462deefd,d28e04dc,dc72f4e1,b9477148,627ff4f0,924cfbc3,aa0422cc,36402b8e,410b3ede,a552408e,f1d3820c,5996e39d) +,S(9c548182,94bafcbe,743e52cc,a76e1ead,3619a557,a5cb8bb7,3140ea1a,5c6896c3,5fcc472e,b88e8528,ec71dafb,f70504c2,ec0478b3,209494c5,b53bf05,b38f7fcc) +,S(7b9d7ad7,aa5b1f69,75c4e025,17123608,a59277f,d63f2a07,7ae69b80,f65a2db9,6cde1ee8,714aa229,d01c14d6,f514ecae,c4a7f15c,a756812f,abfd61fd,d7d1bf8) +,S(af5ddaf2,c985560a,d656d948,e41e082e,6990e950,6c77d53e,171cdea,58a9a102,e348451b,72896ff3,c4839ff7,6ce16b59,1f685348,eff943f5,fd4581f9,eca5b505) +,S(42667f18,e957bd19,5fab366,2e0d1565,d26394b4,14e2a9a3,95becb69,2111293d,288dd2b2,69e9bb63,4e7fb16c,1fe25797,3c0076b1,aecaa2a2,e57020d5,66bbc7a5) +,S(5e9c7a1d,50ab8326,74c2a5a6,f32665ce,9be97161,5e59b618,587541b7,40b276d7,92283461,1f39af42,34292c61,2c70744a,ec466418,ee08b5b1,a298456d,5fa11f17) +,S(98c60ffa,f486b582,2b4d9ac9,7b320b97,8b52b506,8b46bc48,9a2a4f28,dfed8b2a,a1c26113,c2534955,812f42fa,306edbe5,70416d84,aedc132b,5807b29b,745280f9) +,S(92bfa982,1ed52cd9,3c286e71,f350e5a7,f309481f,d866516c,f0a7599d,c385babc,a3fc9796,c71ab4b1,b7a54e73,8dfe24f7,6f527692,9516bcb8,2fae9ed,b2c1ddb4) +,S(9be27408,bd8eb59f,ace413e8,402b0c37,7b7798b9,3bb18c4,ec197382,fa5b865f,11085580,19646a39,68eed2c8,1bb92dde,def3ec29,5024c027,f54e8bfd,a67a2f61) +,S(27cd6a6c,b7bab059,6b791ce3,8c0918bf,7751bc59,db9e5827,5b1b9c46,976350bc,890d5167,8fce2ac5,f13761df,68651e7,2f41d04d,4feb4011,a16f80ee,83faeda8) +,S(e896e14d,aaf96139,4c8f6597,a0c66463,5f22be3c,96f30e1f,5d8881ce,f468f2eb,beb004b0,512c1ab1,dc4d971a,fd88baca,efea7e84,dadd2726,bb9f2b3,b196030b) +,S(24e2d269,ac485401,634b3779,efab2c0f,a9dd2389,850bb3da,54ec0d67,e53f8ec0,de702ec2,642bd4c2,3bca2ca,663a05a3,f5beda5b,e41fa460,8929aa58,219e525) +,S(97a627c9,48c1c9e4,5d50159b,4b121a50,9b5c4d01,de0a7db9,5a9d9c09,681d1676,19bd095b,55399c29,fcad4303,7f5d5c21,8d5f3cf9,a7c90b9f,fef7ee92,6f3203d9) +,S(a70d8251,e604ec5f,777234c7,f9d3c850,33ed6760,1fa0814b,40bd5370,7195b08f,df28d907,74e23de3,f152c016,ac710d43,85325a89,6a859f4e,e126d50,acbccc4f) +,S(2d676c43,4b276472,ce01a007,13d78b17,27743a97,36f3412e,a7c8c15a,fa42f42b,be28cde4,6ef5d32,403b8f94,1082b684,52fa703c,339498ea,24c08ff,c9fa7312) +,S(f66c25e1,75167275,5db857cf,cf27c036,46c89d29,b4a0d729,28fd42b4,b29cf5,3ee23ad4,22c4a884,4c049150,cd9c18ca,8d2a0231,bad69b6e,5926de9,c7193201) +,S(dba47c4b,9d39d87e,ef44f81d,24e8e005,ce6e77ad,8e4fdc6c,29393d7d,2427060,2d5c6492,e53d000f,977eedd,4dc3b5c5,5240f28b,9fcfb597,338edbbb,3d8d7622) +,S(a17601d9,4f627dc5,5895aeda,e91da3b6,94788f65,f083b01b,bfdf8815,27e10f0f,74089fc8,cfea1b15,afb025bd,99905b3a,baded5b,45e30890,fa3d8403,360a1183) +,S(dd70309f,b84afe90,7e261a12,5fb7ac8d,1c24c6c3,54eb83d5,188f3a13,4d80e141,32014ac0,ac93a77f,9d35b786,2c88ddde,4bdfd566,f6555868,2a836535,44bed563) +,S(79fd503d,e746baf9,701253f0,4c6a2f3,cadefb93,920c83f7,83b57768,87037afd,3c5cb658,63180931,3fa20c26,647a523e,86a4e600,8e8b17f,1e0d690d,eca61b93) +,S(d1aaf37d,77c7d63b,1f4eb896,16a29a4a,1e72658a,93560956,6b92c122,ba0ff6a0,e535b7ae,5cfbba07,2bdf0e0b,bf435bdc,c7cac39d,9d9ae32e,cfd13945,3ca93bec) +,S(68ff1b82,b351d94b,9b6b74fc,2cda4345,fe525d58,d6599644,5c752757,aad93c4f,abbb0ef1,c422ac08,d06194aa,c5d93bdd,9186e374,8518192b,79818f3a,b465a13c) +,S(22785c97,18063e5d,5db73bc,f4ca6487,14393ea2,62ece24a,5c41c059,9610552d,9c08026a,d7a7a80c,24c5e75c,8a75cd6e,1933e64a,25cb98c4,157181aa,ae1d8774) +,S(626cb5e7,563fb757,5f066258,3fc21762,e2678063,a77d8580,8891f244,4f5ffebf,8369ff6,72c3c3f2,43516184,5a9851c1,953a6da2,5662e11c,ce170cbc,668498b4) +,S(a99f0ef4,d6f46105,80ffa430,b88a4f28,61c8c4e4,b6fadac5,5e668f5a,80d12d2a,972adf29,39db0083,77802c40,6ae2aef6,4e2f064a,f8304d3e,28fff33e,b1053d06) +,S(b243ce27,2ff0b2db,cb80a3fb,dfbe94ab,784afe3c,cab3fe61,1931de9,c7f02645,db2ead19,fbb8c820,c7233df8,fea51836,3e85b858,4622be9f,41a0448e,360b7559) +,S(c74e3c9d,685cb62c,6a71b21a,a1dff5,43efb264,543222f3,f8bdf570,4363deb3,987d8261,fbf23d05,a38358ef,c4efb61a,5cd550b6,1e833ed4,38734486,edc4b2ec) +,S(ff2f64a7,fc984d4b,d1c885f3,4c096e9d,d34710c2,43dc3047,8886ef0d,ddf71c47,14c06258,fd5e2fdf,1eec9125,7690c0d7,9eac60d,785f2497,65e1a85a,a06e906d) +,S(7d92c4e1,3f4cab24,d36e8a8b,140f743a,6819b514,f6a19bad,ec162141,bb712085,606b5762,2ec7d7d2,a9b19330,9da686b8,3e0dc920,e6be33d1,b726f416,81b698c8) +,S(3a43d4d,9ef45289,89c9487c,77951602,4ce0cc20,ffbcd518,a0bd2546,fe13b6c,5f24d325,5768905e,6ba28d61,e6b126a8,eedad2a1,53499912,dfba3fc0,d9deb36e) +,S(8e72f02,80105e4d,15cc67e7,371d0c5e,6e59fd05,b3c66308,67342a6c,eea25f8f,94ddc51,58fdb86d,f09870da,47b79b03,1eada5ad,9bbdd509,9ea1d9de,96b368e) +,S(b89cfc23,6dc02762,ca77f9d1,8343f12e,ab8789b0,e5872d6b,fd9d013c,ccef54dd,9c9a7285,45a5996b,4a6ce6f9,df860d11,c3ad135c,f1f7437d,2ba7b904,411141cd) +,S(e85ee008,979868b4,bb190b53,5624b3b5,6744a43e,2c473ebb,c64e4910,41ccb59b,d3afe70f,9edec50c,227e3b3d,7eddd1d,e1c9a8b,f842d723,a8075a52,12cbd6a2) +,S(d8dd6bf2,774d6d15,93cc8e16,d5134066,f7f90651,39915b3b,fb0d5d93,b6cb97b5,5a203094,5f734f3f,11431862,b85e9f8b,25f7e6d1,91512b2c,6d256f4a,535e26f4) +,S(77e081c5,328fbdeb,45fbd554,5d133d84,33968ef,98d36aec,3e6385a2,76aa94e8,2ce853f7,ca25f2f8,45a6291a,3e080504,ba597fb7,91a21669,c0cb6be1,14c2959a) +,S(510786ea,e8a49682,6820b82f,549f07a2,b5b9203d,b1ad18c4,fb9c479f,67c904ab,dc130385,4e4dc69f,f63e21ae,71dc8674,b39382c1,eab1d8a8,fbd96867,af9cd96b) +,S(2fbafeb3,fbdad5b6,4c121056,e080d0c2,1169e433,3abc0dda,bb642789,a242639d,a85d82f,d9e6a14d,e599ef0a,11d3eb39,5ff199c9,5ea5f1c9,2f3f8a7c,14405cd3) +,S(200dbfeb,6e6e463c,1f3fbbc2,6b5f00c6,aec80809,1e28eae6,73b2b5e4,7b12ae0a,4852a219,bdaa3d97,83e1f071,15491827,83212776,fcd1b44a,c59dc01c,bba95ecf) +,S(27b140f6,259f7dc,93d46b6,e52cdb85,3ec22572,54218ab4,1acff2be,24b8a3d9,3ceed09f,70cbadba,d40054c4,f130e312,28bb5d63,71a74f7b,c85aa7ff,c0583387) +,S(fe4941ee,535c5311,8222ec35,14c2b02c,e175cca,d728ca0f,cd1d64ab,e95b7e71,e9cdc9ae,286d651b,d89cb442,2a64ada3,748e0ade,585cb70e,d357004e,e51f56f6) +,S(317d209b,4cae94bd,36f443d7,65be2f17,ce47ced,59935d88,5a03925e,75ff1cdf,c191495,68fe571c,ff945af,4b6a801e,c942a5df,78a62864,5434a5eb,8a262d72) +,S(f951a777,764e30e4,7705f8ab,150e9ab,df32e80b,593cecea,d9f9a143,cc93f9ea,efb951d6,25f2223e,e6ccc6b8,b12cddde,6ac2613b,11ae3052,65570f15,23afd925) +,S(71adf0eb,f5fd8e8b,f0f229a9,ffe496aa,4f251af6,6e5a284d,3091f344,3389c8ef,13f47463,293a5536,674dfdf7,2dc73add,98ed5672,e7676425,39ce655f,6b6969f4) +,S(2ea0406,58c0e80d,499cff39,ad463412,c3fbab1e,81f6eea5,911c45,236be75,be52c74,6073721,f09743d2,9a0a4e3,d82c08ed,feee2234,29163bc8,954f923f) +,S(42352390,4b3e80c2,750c4222,33f0b1f3,a373442d,96278935,d9b7e51,b6182aea,7f582349,b27b5166,30c8e48b,a9603224,fe09e8f,814fa966,395fed67,d9221d91) +,S(524d3c82,a92b285b,96064bf8,e9abe0b5,7702a29e,dc08ce53,771fab9e,fa7dda91,a47a0217,fdc6b2dc,d4b68e05,331bfd5c,366a8477,d3ed894,ec747240,f0f29c3a) +,S(f6ee1e08,5ce04de6,6aaeb5f5,f232329c,fc83caf,d16bcc48,776bae16,c056f7e8,3328b26a,7e2bd49a,aa193977,4947d7b4,ccbc955d,18b27c75,c2f6ac6d,bccea4d9) +,S(9c2f7d2b,b88f1417,722b5d11,95077d20,2ea84e6f,9bd93dae,3134d16b,17273978,1089f003,66c8b435,ce73c592,7c5e56bd,d338a4ca,ee5307da,a571be3c,2dab2a3a) +,S(593a1eb6,730fb6e5,1fd24f15,253ae1e7,5897b7b,48efe28f,9b9813c6,ca99cc3c,fcfb7820,fbd22d91,bc03a630,f74e519,9e35c1a,a3b1cace,40433001,7744f079) +,S(62ba10c3,83a7bacc,bcc4bc60,37f87a5e,8ec0eaff,de5a39f4,ef352b1,51f957e3,c267a1b0,dc84a161,a565fa19,aa0a2501,9fd01e0e,d7a660be,c2a7e9fc,cc7bdd45) +,S(1de2ac10,deae62a1,63f641fe,3a4a9da,39e12390,14a77c6a,6d73c619,5f731f64,60f43c95,b6d7969d,427b5ad,782214fc,a512b75f,a6f50006,d7141a89,dbc8d2b2) +,S(f11a5552,709083c8,83d08612,31772f18,c48e9271,6acbaa6d,a43416c2,fd4e1d3,a6d0ad64,7cf48c41,b6ce397b,38d5b3b0,2be51554,da2f3f4c,df593514,a2d742f4) +,S(f4454640,d75697e5,21d5cc01,fca5c7f5,3dbad43f,116c243d,2aeae96d,7cdc33fc,42972cef,46fe7704,5d6d7053,1a74ec87,6b25996b,c4cf66cf,b3784f79,66549102) +,S(2bfaf073,97be067c,1b7c20fa,3b319fad,10905b8d,8ecdad4,cad2ec8d,a1b8780a,ed526499,ea97c967,3d28bdee,9970f4fb,9077deb1,5f823cd5,775cc526,4e590285) +,S(fc1abc81,2b5fed90,bde3ca16,3422f73a,6df6e058,8ed69222,cfec54f7,4cf5f73b,db1c6edb,471cfcbe,468481dc,4b1cd1c4,7ac68f6f,4fe9dd8f,af0d1136,972b975f) +,S(d838c2ac,82e02f9b,a376f92d,293c02ad,b717d65f,be31cc76,12476e6f,4c506a8d,d87a3067,388f8e0,3c176f6c,a7eab123,532dd1cb,3e0f6ae2,51d7b31a,35189377) +,S(4b3a82ff,7295749,a259d54c,a9a5e539,32c53ff1,33a1c4b9,2f697e06,b13ee38c,44372b41,a788456d,3f66a0c4,6c815210,bf60734b,e570a290,32db3075,ba8d6265) +,S(d77cbbf3,6731ad4e,325eaf6a,9bd52f70,8e79d290,e379c2f2,b8d6ad3,fce411aa,ee466d25,f07813c7,91a81237,748bda9a,51f4266,4a385b50,5259bf84,ff8372f0) +,S(3867f6b2,58920b82,6eca75dc,953ac307,bed1872c,c0f1c6ec,84efc6d2,eeea1483,cc6a6adc,e6078097,a013ff18,dca9c5c9,254d70f4,68ac1cf4,b8267135,af88aee3) +,S(7b008875,e85fc84f,618ea7df,f20f7f17,2123fe98,c07b5279,930b52ef,cc1b0a9a,3f3b30bb,8dbc9169,a5c55a1c,4150772e,331f7834,b50bb904,a8c56600,bf075f90) +,S(ba5b44d9,16304a49,87579560,4d4b796,907e9b7a,4da49a5,ba7a1d77,8e34ef3a,16b49baa,48219e3b,9bae124f,dcd4de,4d47ea76,3ed39e13,f874c75b,cf333661) +,S(691eafe2,7fe4120d,852b3a23,b5bfa646,910fe521,355a3594,342d629c,e2b8d9df,43a06097,42184dca,7c294fd6,a5227dbd,bd71ea1d,c4bca878,1887f9f8,b6c71d85) +,S(13a6cbb,c9f5a86f,35173e38,a45dca65,551377d7,c37542d8,44006e48,54a54123,ecf3809c,9a964d9e,ffdcc2e6,2e8faf9e,8a43d38f,3023c4b8,84d18948,8488620) +,S(33fd2af3,fb595cd2,93d731e9,1b4f0e5a,da665420,2dcc36ce,b712e8d5,e6f10e45,e26a307a,a8bdda4,4b981bf9,808cfa3a,80ca5331,b3a94c31,f6331e60,98ed2cf) +,S(75954033,59e47f78,76b3ba57,5a758493,b0033298,22f4e44c,15cbe58b,34b774f6,7ee9a040,70b8568d,b0a99855,3442c000,b6e6651c,a7ad1253,f8e703de,5e0458a9) +,S(79199fb0,c3b17e68,4e815e7e,8414bef4,b3dd3665,10d032f3,6505da59,6f5b9480,95bca973,f358c9cf,ef3aacba,54a055b8,abaab383,4191a1b5,54ac3ee,53d9a0ab) +,S(9705f4e7,962ece0b,2e7ed64e,a33fd40,6edd0bc1,ac8997b5,d6d70000,a51aa352,4d4ce757,ad4547a8,a126193d,8921d6d8,58f40855,f71ab99d,b2bdd728,499ff347) +,S(881af067,b841ab5f,30560b98,3376674d,cadeeb75,b8b16e12,df7da3ce,312fd777,ccc13fd4,512ef05d,7c10f62d,8b144b1d,7588be3d,1a3a3701,9accdec9,3483b84f) +,S(fe8f7a44,33c2c9d8,f42e14cd,97ad0794,41bfc3b7,2fd412fb,1f6d5f5c,10e99621,e5b576ee,cf34374,96dc4ee3,a846c79b,4c8babf3,cc46a657,2a93fdd4,b6b3b2a9) +,S(ff43c8da,18e08b38,3f92f832,3c34e83,84f40064,9e0506cb,91893abc,5c4d798f,a575a059,23a9da02,c0c9dde1,981dbd86,f5a75433,a4bb2fd5,2427db01,7ddf2e7f) +,S(4715056,b97f4e21,13485242,74bb1b33,d8f9d841,73678a42,ed3c6fd5,28db276b,b4c0d146,3521f1d9,fe8cd71e,fb98aa28,73a18bee,66fae12f,cabfa201,854302b2) +,S(85c9d808,c5f51d5a,c2a51394,cb83e7ee,acd85eeb,31a88814,9744871c,271fff51,2a7c3bf,23829b88,66991454,d6ec7f5e,185050d,1982deb8,b4992bbe,5b666a7d) +,S(c02b94ef,8b1e368e,3cb4b25,903445cf,f46b60c7,6d6d2f24,529997f9,7d70dac9,bbb97d29,bcff81e4,8d417825,ade1d28b,10fadba2,acf961d6,80a343c1,e725f3a0) +,S(4b1593bd,28e26f7e,431ac439,3d353a1e,fcb8b63,fee7adb3,e29472a8,38241df6,8a67a728,f4966855,26225b11,3ac9d858,3f184f8b,3ccc8ef0,d6e4e34e,f2fdcc56) +,S(f640755b,ba51dee3,ad650555,9d52869b,7a8e7f6e,4b9dcdd2,31d1cd4f,26a64dd4,7387f800,a53e290b,d4c29f6e,ec24ac07,91e0e3c8,55d14882,a48d0539,6e87e1c8) +,S(949346a9,436836c6,3df6f42c,d708cef8,16d0a522,914a606e,2276979,7789515b,a903932d,952a0201,ef65c847,b8754174,31dd41d3,ede5c073,31383b9,a8e2b356) +,S(1824099e,c769edfc,2390b1f6,698c22f2,cdcc9783,c5cbe45c,de46008a,67f91a60,f8405fa,81e04dd5,6ce051f3,bfa088e2,804a8780,37892ae0,adf42767,311bd1e2) +,S(e6b46fd8,e4633d92,8805f34c,ce95f3dc,683aa792,139c62f9,2ec8acd1,d601d341,533db813,f3fea63a,528faf4a,7cbf58d8,d6c0bea4,c28391d1,6391d300,cc1d824a) +,S(63799b30,dc19b18d,d48d150d,3d4139d3,a04c6252,f176015d,60a436cf,ff992b93,26205112,5ebf4dee,d00e72f5,ff064178,7f485cb,2ba35507,3c3cdb0d,16dcc41b) +,S(8cd02f5a,b1d5a02d,e85b88d3,ae370b0f,7fac5324,9f1fd676,670a29f1,2ead7338,358b42ac,ceb689d6,612cb70f,bc9bba7,511d56ee,c4390627,8e2f0961,bcc0d8e4) +,S(d5e167e6,d48bd1dd,e95aba41,bf33b065,f7612766,4a0a8991,d3ea1a9e,ddf82fab,6cc23982,d653cdf4,fc4ec9cb,3cd86ae2,aaf45f62,38257d70,849c2686,ae71d1f7) +,S(c4073500,6987f2df,1334f09d,97f00c19,d72b1942,5864b0cf,4ff19dcf,7c9bfdba,f6566846,6b461326,a9b366bf,30378f82,b760ff0a,ca568ca8,2bf0c9d3,ff7ff262) +,S(9df1e71,9c501bfb,8a21db2,a838318e,29a7c2c0,fb2deb91,1840c7aa,f0c4fde2,cd628cae,6d0e0c02,b0315ae5,4901e703,e977c75b,43defea5,80a5325c,fad00fc0) +,S(95176429,df73c309,23108ee,6922c597,1c91c249,ad7165b,7d08b84d,2a4c696c,3ecffc49,3b62dbcc,82208470,375c929,1994fbb7,240740cb,dd8086cb,e9c0fbe4) +,S(708c48e8,692b0d35,e13a7e0e,94be8fb6,f57fe187,34f5556d,a318f600,c5628c6e,9534e302,deee1d1f,27e0432e,9f6a2f00,5af7e601,3f7da9bf,e1cde320,a105a664) +,S(2775e17a,b82dc739,b5d62079,4b26be15,46275ec0,9d32622b,2991cca1,4e5b4c09,3aa6ee7c,80e8359f,deeb52c2,8da1328f,338ab228,8744d52e,8a9b7908,1b1ccddc) +,S(47c1aac2,39c4f31,cf334959,b8fb48a0,44da6b34,3c383270,be19229c,30192da,5dad651c,5ba6c21d,845cd402,59a051c4,e5813f5a,21228355,1fde158b,600d7cc0) +,S(f80f445a,4b864c96,1bb2bf5,9cfa25f1,eef459d4,fa28ac70,d77daa1b,b8bad15e,a383de04,6b8c6996,6d0b9da6,ce9f88e5,83cd57f4,a5f12c88,63f7ff70,b374ff16) +,S(2924e7b9,1ad33619,a8df436d,578b7172,b2208125,9f2d5bf6,f9cb903e,bd4d2f66,b8642169,e2319f54,348e4f3f,e15d1f06,afa41255,ad62ceff,a768bdb8,48841875) +,S(37d6087b,91a64ed2,8341854e,3a2b9ac4,4310785e,77e32e2a,f13405f3,76dc4d83,35a23917,e068bccb,a823092f,32e6fcdd,a3ac9f09,2c251b1f,9bdb9971,3df25003) +,S(d748a96d,c79f1be0,6b43691c,bcf84b4f,e000d2ce,8294cfd8,391dcb92,10f4fab2,75b4ade0,65da902e,ce57e5c0,4b817228,975c0927,aafb76c8,223c4da6,f05bf51c) +,S(d05d2a25,eb5084ff,262361ea,33b6fb97,9492414e,c255fa8f,a0233d06,e42cc30c,14bbbeee,cecdc8f3,85b51429,8aa03d9,ba57a198,5ba98f4e,75efab60,69a6f2d2) +,S(69ba995b,d137edbe,5aff3906,764eca9c,b4684bf5,e8a8c302,78c89d97,483ff793,2b1cf451,b6226596,9833e864,91c5db95,a79ad96c,701580b2,46de1936,5bb63e32) +,S(7f01e9a1,5d0ecf28,fde0342f,f506104b,3a50aff2,f1ec997d,9a82ff71,54419461,1c3c9594,a6b8d375,361e25d1,fedcab63,d2704065,a83470e5,e03dcc43,ad12dc68) +,S(719232fd,193b9041,fd201bc4,7184e4cc,f2413d03,f0f8619d,813a409e,56e48cc6,161fc718,7dccb053,5337ff60,9eae05ab,12fb55a0,65f82d1e,68b19d3c,ae29a953) +,S(15b84120,155f7310,3386009a,57bd28bf,9a63bcfa,46c8bd08,2f53dc86,76e78c27,47dd637e,c9017e2f,e9804e0c,840aca4f,188171a0,ea9fb605,1402c503,31737816) +,S(ff429d97,bd380047,7db52ed4,eba69914,4a95ce2,7414da2c,74c074,bbfec567,7b3a6fbd,6e635bab,34973f62,4df77c03,6708c00a,cbcb8f25,69a5aa01,d57b3048) +,S(ccd705b,16be74c,cf1f476d,12c77e81,37917404,b2611ed8,858b1e55,d50a6ee3,8741ade7,5cc7b252,4dd55e17,897f78d6,946cb4c,31ad9f1f,737affc3,40e87c01) +,S(65b61a5e,24b3c57f,91678e81,8300ecaa,94e4b406,8d499534,d54c37d5,bb65b27,90d75e28,aab97b82,f1b86fda,2ae0851e,f65ac4c7,a5c664fd,79c16a76,75ed0c40) +,S(671529df,8f4073d9,43f82bdd,758fb8e5,4ffe0487,c1a38cf1,73c1419f,7ba06ef0,c46d9f2d,1f23349a,dd1121e1,d51ebe4,454fd141,c7076950,4d854cfd,14fede59) +,S(2af8a76,e7a1697,7af8e70,30bbd2c0,73da3fdd,4c6735b6,8e823cff,901b0440,55565be7,9ada7153,c7165976,91ee33cd,7c34f5ad,d65f543f,72ffd026,26c3c1cb) +,S(acd81d6f,c5ffbb87,4fcb3b1f,b7cc730a,4def3fd5,ef59fc4,2fb9472a,6f575707,8e319a8e,c8b8ea9e,11ef47eb,5071b696,b87c0ec9,63e851cc,e0929646,1d181a3) +,S(ab77e7d5,3ab9e8bc,2052d0bb,360aa7f2,ae062ca9,9b91441b,d60ce8db,80ffb912,5f92b6d9,cb0ab95b,9eb992e5,e1d70412,aca90998,b5d6ed8f,dfa4c752,2df96b5a) +,S(798b8195,1a6a8c7e,f8beda09,b06a2303,1d7efaf3,7b663265,e0188ab3,78124046,9592da1b,baea430,3644a7e5,4e67476f,d91382b5,f1181de7,a1bf9d44,e02b1bf6) +,S(f2486aae,c3be77d,8dddea22,488aeb4c,9dbff93a,24ff6f29,ed6d528b,9777b096,8e2b2d50,fe75c847,7c50327f,e36afb0b,d8409b62,8d83a8cc,41325aa8,4829126b) +,S(222e3d09,3b8aea8b,e0f64ee3,3aeeee72,d16ca088,264f4333,f9397488,146d2d54,eff500f,bfe6bbc4,1c2dd16e,8a0ebd79,37ba1f78,ccb098a4,351b539d,cacdcaa9) +,S(6768d3fe,7ca93476,245a18ee,ab53e002,4f99241d,9c321bd0,165b7d04,c121c1c9,402c9d73,c9b99722,2319ff1d,9e1c778,c4dc825,d030a43,823aee8b,90272877) +,S(6eb6740f,b2f0880c,eff25697,bfd7815d,b0b62884,cf8c8ef2,5137f098,f22dda79,cf7e8531,c12f5713,c302061c,1f42e6ac,79c4b695,e458db68,5209f03f,1485c86f) +,S(7101f348,4eb05a7e,aa0f385f,367b6a7e,5ede8959,71729ac2,950006aa,965fe51b,8d1fb913,a040fb75,778fff9f,c71afc2c,2605595a,1e44944b,e264f893,10d5c3f3) +,S(75a9e45c,acc6a25e,3fe4b25f,12030362,a0de03ea,cefba87a,11c8e6d3,e886579,52a85995,e91986d9,26a02cf3,1001fd82,854c49f9,55683f7a,dbe7c02b,cff69c6e) +,S(31194d92,bad76572,98bffc54,27f99ade,ceac14f7,830ac1b2,954d6730,3737dcbc,99e81c45,f5318eee,9d2449fa,33cc5bc6,8c556ebc,dac2ef19,a2d1ff3f,5fdd2832) +,S(904fa3fe,76fd6f43,86ac6138,70b4cce3,c1d743c3,8457d23c,522958ac,bd505af,94273262,1adf4633,79e929e4,54c70595,8dae9bfb,3957a304,5c8aae41,a7c1763b) +,S(1d1861f3,1a828b32,3699aede,f3fa265b,40de142,78a7df26,b5fa93ff,a4a8e0fd,b9657781,f13ffeb2,8e1306e3,b84bb965,3ffc30c2,63a65f61,1995f44d,d899f7dc) +,S(3bd33def,6de1a5d5,e5ef0289,e8565dce,aac95922,8443c09b,73ce545e,6819ad64,993f0109,eb560bd4,97436627,9a70e9bf,8bc9851d,f52441c2,97535ed5,d4f9c810) +,S(ca1b7d45,2a39aed2,a7f27b24,8e5a07c7,e4c257eb,7150e61c,7bec7f6c,58958634,ab11fe1b,c0357c37,b7da9804,39fb5481,179c0f7,442af2c7,298facda,3c4afcff) +,S(273a95ca,dee8386b,53ff29a3,6ce7d9ac,df145f7d,5f928f61,da6d57d1,8671aa58,88a6359d,bb06537d,1a6c6d83,24065284,315a031c,73c53ac2,adb14f95,1a5bbe2b) +,S(7ea4c0fc,a139bbac,553ad79c,d3921c01,c06923f5,29446279,d0f910f9,ac5561e6,bd049d47,45830e2,f31e7982,2639f198,2eb71c37,71aed93a,54dfa0bb,296dec96) +,S(71f1801c,a2babe5,d4793240,15ccc684,d3823f68,fcd12ce8,bc49607,9607d336,41ed07d0,8384e54,209b7de3,7e8fe7a6,14430c0e,439dca6c,f5ae6ddb,1ff1b4b1) +,S(b2838873,652ba1ee,ae8aec51,55541a3d,7000ffd9,6279cf2a,1c90582d,21cd8828,47ff155,73f5e3a5,245faf65,86afcc31,ee4d19f2,a1efc79d,2a0b4811,d27dce5e) +,S(34ca8da7,22634bc1,6873fbdc,c089224b,d9f8164a,6bf0acb5,b68d898e,b55a3e21,d8afb760,36a9c91c,7769055,d85a3ff7,1f041a90,5192df4b,73f9100c,e5c5d986) +,S(212cb397,d97341af,ca0cf5b2,ef6d796b,4b76eb87,89c3915a,a0e72337,4b19cc8f,f06e2cec,5f29f06f,97685f50,1126c50d,ff17e273,2f78de64,875c35d6,42f170a1) +,S(bc0367f6,43bd13dc,32582dfd,e7893f69,d5f29d2f,ce4b42e9,ffa8091c,6ca6228a,9bec6c89,d1251f06,4aff3e44,ab59ac32,c1764179,7b96f73f,527ff429,74556e78) +,S(8fcb1423,5d8e8894,5ab169bb,4d198e4a,5e489e33,cdeb69d8,dec100f1,a9bd5672,fa1cb396,bab390b2,60302a46,b4408427,c45ae320,5b1d1f5f,e52db790,e7fc057c) +,S(70ad8505,6675ec20,cbc43e80,11df60f4,d4917e84,cca25044,e15c2fa,e51e64ae,f4a51356,af9fa7c9,a5e62475,df5b713a,b63d68e0,cbef44e8,c004fa61,1d5a800d) +,S(ada7af47,48074168,86e6df81,f9718c06,bcf6e6d9,846fa880,3ede1f6c,b9695842,f66d51f,50f427d4,dc748bbe,771d952,98369c91,c41dd,575b76db,988a582f) +,S(f1b87d8d,7323ebb1,1bb8108f,9d34f8e9,bf1e977b,a527c52c,7f045d8b,1102eeee,bd95703,51ebe7a0,9ede5842,47b755b3,7e2aa0e7,7e380b7,9bddf768,b4346556) +,S(93659d5a,d55264ea,c900c301,cfed7b83,1fbf7c51,766cc833,cc591356,492a0553,b69389e9,646d0165,afa137df,1c1d02a3,519ff65d,8856c89c,cf46de05,c0154beb) +,S(e9d2bc49,2a9b4ffd,c482f54a,415beeec,409a62e5,d1781f48,b1738f7d,8ed4ffe2,893e4652,2dccbf80,ddde313,f4f25383,8d639208,36150631,60830408,44305df5) +,S(1424160a,7bf1ad91,18103eea,372da6a5,825e0bc1,a8760744,229e2af7,906cb210,c94da226,96a75d71,1e6f1d0e,10b23e96,4f1519e9,1f63743f,209ef8a1,3996af23) +,S(7f902712,402e4bd4,aabe434a,eb5fa7e9,8686d058,e6f26300,c458cee8,9c9efd87,bc00460b,2aefb418,b16cdcdd,c88446a7,1b8b018c,15261602,669188ac,62f95fb5) +,S(d327ce7c,66cb0f53,e86e5f16,c8dc2936,2a133f6a,38147c01,255c61f5,6f72745c,4dc1498a,c3cb39c1,6908b85,b8c52dca,618cc6d4,1c6f95f8,353758a3,86bea436) +,S(f044eb19,c9d81106,13803b,e8bbfc31,137dffce,547bfd1a,d5396ad,e32db3b3,5ad4428d,9c4c3e66,7f8551ce,ab282cfe,8128a8de,ffccfaf7,c102b9df,7e526f2a) +,S(7a6c5237,b95d19be,af46a81e,bdd54403,d135bbb7,f3c03d55,f67c5cbc,e18daf4,62a2e8b8,47fceb5c,484fc6e7,4ff68fed,bd492c66,8a70c1d7,cce2922,a204385b) +,S(59c7fcdc,b069c0b7,bb772afa,f5c20846,ffae949b,47589bb5,80495bc1,b59f82f0,82ec588c,6657566b,71ba4d79,ac8e2c7a,c09b3652,f24d46ec,3358eeba,126c38ad) +,S(f8cf3c21,1ed4558c,c40d3dc6,dbb85e54,81d99fdb,cdf27ae0,ea01bd4,6b6543d7,bd8049d0,1c3df630,8951f5db,dcce3043,5506a5c3,e0a8bb20,54de9dc,87a9778b) +,S(3855d764,b2389d4f,1ff47189,33aca82a,4d2dd23f,cfd13764,2782ce71,524504bc,82c4ea25,4af2abd0,2724ec34,6aae3aa3,b14a71ee,df13df95,9446c0bc,759ef72d) +,S(77644b31,1de4f0d8,d30b1d73,35553dab,6d3e0e6d,af7e6ffa,48cddd1a,52de5431,645e17ce,c0a0735,737730f9,92bb7431,7581c930,695829b4,cdbf5214,f45916b4) +,S(a4d4af43,afd6afbc,b2a511da,a6537abd,56bfc0cf,76659d34,56530663,d9ca138d,be6c9fd0,dd2df31b,b907f073,7d63df34,88b5db5f,3d5ff747,a25a2beb,73bb09dd) +,S(417ffa3f,e673a081,f72c3d64,5e64bc61,2da352ca,fb66d1aa,aa8fc060,74a75be5,9ab8be2f,90849474,809472af,d5a7490e,cfd9ca4a,7f738be1,de093e0,68c50151) +,S(78175154,93115041,6cbd772c,c74212c4,4f19eb04,95e88622,f75ee838,caef73cd,37d4d5c8,ffec3650,26381b91,d7cb18de,fdaf2cb0,a5d94ac2,dd7bf7fd,34d0d3e6) +,S(365c560c,3acc28ea,f560c66c,7e76625a,3c2ee7a4,8f62ef0f,736253fa,b1b5121,25cbc6fa,96c0f15e,38b03f88,338f8dd1,6990aa15,dcec58d6,4517d37c,5b74868f) +,S(c945ad25,1010023e,9126b6cb,3a19a925,6c6757fd,d88cf808,a94fa182,8f5bac7c,c9a8e90c,b4ac43bc,ef08ae3d,fc66f6db,99df4abb,2679de5b,174df92a,d654e2bb) +,S(4aad85ac,45e6d57d,73822387,632863de,ac8c3fb7,b7d3beec,629c0e1e,2c2e0213,38eee8e1,9e81bf64,9641c192,de53a071,29c03689,376f6595,2130b63c,fd6a2708) +,S(2bc10248,b0f6596,adcf9f66,3f624461,907e37ea,7d35367f,24b9f69a,26a291df,e0ac3ed3,3016b37a,91a780f6,b90b7743,24ad0c30,50812b2f,4f35426f,4311c79) +,S(cdc05991,abd28f93,e81a2c0,9a04e1fa,eca89400,81fcfcff,eb91c8d3,93ddfde2,dfda4ac4,4458e2b0,3feb9852,d1a8822f,8bf90a4e,bc79ab32,afc9a1b7,580193a5) +,S(5a24eff0,af2dc429,ff4ea857,f8aab10,31d285ae,9c8beb7d,793bf9d,db46a047,179db914,59739160,897f40dd,b7af0b8,a98b6f61,6aef7327,b53b6005,9c4c8f9a) +,S(16c1e53f,51603ca9,374aae6b,57d15fdb,e7c1d2b0,b0545467,636fe2ac,7838183a,bf858ef0,56e09bbf,5d8af50c,7e0fdc90,8d1f6c1a,570594b,a5368976,63a183e3) +,S(792f1eea,71b92f9a,d893a116,ac177801,a2f2405b,1c6846eb,c3a6559,eb01ccf4,bc062f0c,c610ef39,311ecf87,a7866b9c,52c0df0b,be1e0129,3ccd0b7a,2832a79d) +,S(1b399c40,f057719c,f544dc51,51137fe3,917dabac,f0804dd7,335ba65d,a57378e1,4d6794d3,b6e8a085,41de872c,1dd333a2,bfdd0712,aa846f6d,380a775c,600b425f) +,S(138b313e,b9c45ced,e0cd8219,b888c51f,9f8cd278,abe16ede,c210bffa,ba238e4f,a199a357,cbc8042f,4b6d4951,2f0acd26,13f0f76d,cd6dbf7f,d9e8723c,e6ac56d6) +,S(3e06c311,9c765664,d0068b24,cf4ae1a4,8f401811,17c93122,84ffc24d,eb542338,63a65596,e5607f1b,6a9c4596,39a90d06,93b08ab3,2807b696,498e7557,673624f) +,S(3f32f9b,49c88932,574e5455,c179e9de,80f0f6de,ed1ed25f,8a3de8b4,bbf8bd2e,a2d2bb1a,5fc96f89,ef490257,bf42a9dc,91f49ce,e2b86472,8551fa6b,6a589f17) +,S(89adc417,ffccc50f,a129602b,f5b1b82a,2c4f5efb,e3382b04,1fe77299,46414ec5,4ce7e75c,291b751d,155c291,5aa619ef,6c3daa28,25da8bc8,e2c7ef54,8c253215) +,S(f33fbd62,6bec8c9f,6597d486,2f54f65,e9f208fa,7c1d619,a13feaae,5ce4e9b5,c8f0602b,ebb9f152,87fe2eda,3050b032,a6f43c8b,7726825e,df02b424,51593774) +,S(eccc8ab,7b90e2f7,e45f7703,a0e97406,117fa04f,4512071d,568e3e64,a4a7d6b8,8456f705,a9c4a0d8,f2f3c233,3c8bb367,fcc8a645,f1fc560,48e1699a,58a1b6f4) +,S(f6962b33,a7ad862e,58181c75,42743ed0,e6e31d5,4df1fdfc,a4e3e95a,157de915,af3d47fb,48515ceb,f9f7e8ad,2a0159aa,55c155a,83359cf2,9ee3202,ea9e6605) +,S(3f1f3c6,7996fb10,65ed5df0,2095926a,5c45d2f2,38ff59e8,42b9d234,daace24d,d585c9e4,f0a29f0a,28e3c30b,22228dab,73750706,5690811f,1104bd4a,6d0ea28e) +,S(fcae019,36290e43,d8bf93c1,6ad2cd5e,dc33592d,4081b0e3,4aedd451,6e6e589c,8e98579e,cc42a444,2dc710d8,8cd09996,c8acb958,b9702c24,3a207ba1,471165cc) +,S(548f27ba,355229d,23b7922b,5fc8efad,abc4247d,baa312c6,d89570ab,151f522c,e5597d8,bbb47cd7,c8cba774,ff37c81e,b7b63c63,39b9600a,cb77f1b8,86ab6fa9) +,S(e2f64914,e8bf347e,d465cf1e,f086b7be,49797db8,611803ab,6e439bbd,5c146fa0,8e69e76f,7c641e4f,15248257,77aef9b,88b27a94,72d565d1,d2ed7463,fc6ae76e) +,S(8c532a0,2d970c0f,1d8f9762,2298b40d,c7d362c8,f38cd122,2cdbeaba,2c13db1d,90f8a2e9,428d66d,9e8ffc9f,bcb7606f,568251b6,2dec2768,1b6ffa8,7062bd0e) +,S(64646efe,e3c51972,f6af7e0c,8052aec4,6fc0ed97,af566f6d,3c323218,62291a23,9e29e150,f6ca370b,36a76ee7,171f2ddb,a10eb88a,986ffc50,d6c8f4f7,287a69fe) +,S(6e8ba4da,1df8dff7,cbff69a,6ef65c9,329199bf,9a67d1b5,1eb1e1f3,473be659,ae7562c8,959441a7,35ff2188,3e537bd7,eb5a34a2,7e144a06,f674679,815d852a) +,S(8c21abc8,f7812c0f,6de0d7e1,cadbf1f6,c94c871c,d5b8e9ca,e76c1f33,2b6bcaef,5a7c9cc3,13be03e2,5410ed03,7e0cefe9,5a36d6fe,68ff46b2,663a0ca9,747ed53e) +,S(ce0e383a,7c487e14,26636ff7,657a28f0,10ce5102,1eb89fea,3426b269,2f9f6353,3f95a465,d43f7804,2804e9da,4c73c8ec,97fcb9f6,fdace280,532c0c0d,6232e03a) +,S(7e33097f,51477c4f,f4459848,34673fc2,8078b6c7,c01cb700,80a37ee,1d698eb8,c1275bc0,7317c679,d881d274,e49065a2,e282b7e6,970065ad,141c1ca5,ca2d75a7) +,S(ef4d9cd6,b1487e61,fb31cf42,9eff2731,d686eb66,cfb3f867,9317b0e4,116837a6,c4f6beb4,280ddd5a,24f6461a,6ea1eba2,3bd2ff58,7ff612ec,d118b76a,3d63be1f) +,S(f3edc145,2ee49324,f7890bcb,9a5f8ba3,ce53f4a2,df0c94b9,92c573b2,f3716290,995446ab,fbc9b27a,8db301f0,87c2ae93,5c390565,491c0dbf,552a9820,d3fb2f2d) +,S(c1f62251,7398e914,d6134160,318d20c6,87d17427,2bc62c92,bd170ca8,2bcaa975,1c85ae27,36735b76,d5328d59,3292f718,f6d6da52,1c75cab,fcb06720,87769e99) +,S(a7e81df9,605f0881,d4856153,3e310715,b206c601,9a55b889,7141321e,463dea8e,3ae220fd,1f361be0,f0b70dbb,a7df796a,eb23deb,5c5440ad,aa16fef9,7cae8a4f) +,S(1b69bf29,8f5df296,7a3ac028,87d4ae5e,f46af5ac,5a8cf326,2fe7282b,e46a536b,c9c624aa,2d99a71,ea375c68,419b38a2,d7e9d7fd,8880dc60,28c24f2e,a846a91f) +,S(cddfef74,31763b9,8df15cb9,6b3b3127,b31c9987,fd17251d,b56122ed,dbbb44bb,972fef4,2e935aa3,4c679ce2,6a32a38c,225f0867,8f780b65,854459e7,f24869f5) +,S(32fe1cef,2c8a5163,66b47d30,9ef01e20,ee07f235,e7c0129c,fcb70fff,60e957ff,9e861731,bd376124,8b33babe,c354ea,3d13b2c7,c45b436f,e754edf2,4fb4588e) +,S(a382fbe9,f4914119,d31d0ccf,6afb61fe,4a759657,26556908,505225b8,79c24b0d,aa300360,39a1bfdc,273e0287,c7c222fe,cdde6318,c9838a55,5136cda8,d2111857) +,S(b53b5439,9ae330ea,e13e2467,7c0344d,59e305a7,96a228bc,6d6914ec,1a80ef88,99809053,8dfc6c5d,748f43cc,8ba8a8e2,969d8d1c,47551a36,8f30ee30,d5fadc7a) +,S(621b5253,f11cfec3,fb4bbfed,98b0ad9c,710fe2af,6aedb8d,f521d0da,fb64169a,2a234dc4,8b716af6,22dd025b,63e05c5f,3b93005c,13614bb3,abe0dbe9,260378aa) +,S(83332b6c,cc9c3c7f,3163f442,80f5758c,1e5979fa,b9a500be,d5b315e0,f9435b04,85360612,258c1f1c,bda41025,c402dd84,60c77df6,8762d2d4,16aa16af,dcd30ea0) +,S(27c8d8e3,91202622,2f72d926,da01b10e,fd54e21a,7a4746b6,68aa868f,dbf6538a,88768e3f,b8f2484d,56c9fe83,fde0fff7,4d0c0a81,213ac090,e90d2b42,22d6eb91) +,S(f349c70b,bcd82005,2fd2e05a,c42556ef,6ee768d4,f08b7a91,55d1ebfe,60067e5,6d595c19,4011d050,c7c3c4e9,e7aea90a,93fdc5b0,71d6c9fb,9f621a4e,750c6604) +,S(4966567a,b2029966,62b1368b,ac3f89e1,a0183b20,173a7156,edb827a7,13b24f90,6ef89436,c2bb3bb0,94910ee7,6c083e35,a097b859,16658947,1f59c33,37e21ab) +,S(4909501b,491da13f,78645b84,9bc63fea,75611b76,5ff6eb6,9a7414bf,913e0886,2c20c6b6,f2ee070d,c1dd4c95,6822ac5c,38b1acf7,5e093f17,c54b65aa,81014df8) +,S(1ed2e667,f5a2d140,18cd3ee4,f4163f7,bd5f898e,ee3dda72,bf84e356,10cddb76,bb4970c5,64fa4cea,e204babd,d869e36e,934810ef,68a22794,f9919e3,26db8e7d) +,S(c47bab41,a0bc37f,addf9c8c,7de86d68,c15d1a0d,85257d57,2a1d60d,4612f17b,e52acb1,36f47de1,1128091a,1a3cc3e0,e84ce767,cf8395cb,b09eea81,a2db09e3) +,S(e21068c1,4993cfc4,35490b52,5ece7657,f70825f3,dd2138c1,8f5ec6a0,c67a7394,cd610137,d48f8d9b,2bf99755,35fab6fb,65360fc,9db04a12,43027083,c732da) +,S(635f547d,47a72f5e,b069e144,6508a46,bd6a6f,11eefb87,da07e4f4,3ffaf917,8ea0a9f2,3da273b4,f324c8ed,81cb0bf0,21fecb57,54eaa642,21736923,2be64128) +,S(24632c0a,8648b4b1,fff2f79a,b3f8e64d,3837b6ae,9329eaa8,48565f02,45bdb47b,9c6d0788,c9e155d3,3c260360,862ab236,177ff875,a3823179,8146e442,f66e0426) +,S(43748dc3,cfb229d4,8549cc56,ecbcb01b,146541e1,5d2c3b5e,d59fbf7a,6b7bf503,9975a1ed,23a09906,3b87ea7f,2ccd88fc,b20607e,1aded9a9,265f34c1,45fb9c5c) +,S(8f848323,b8c41d68,31603b40,69be1dda,bb8750d0,11527a58,4bffdca,c3ae3ac0,77a8ac87,128260c2,86f5805a,b17e5a45,be81f83a,2a575c6e,2c88288a,c2d1b37f) +,S(29ebc368,b54d846d,bb5e8be4,81c19c80,2d8907db,c54412cc,6e2952ba,2948422c,e6b793a2,81d59d90,53aeb2d6,f79cbd1a,426f79a1,6860310a,ec72fe26,37c7e845) +,S(9414cbc4,ccf4012c,8c0cbe21,eb714953,d84bc602,9f8e4810,5ba79967,23ed345,ad1eeb92,89e4a109,2d132790,ece35cbd,da45bb64,bb6ae72b,39b9eb80,d57fdeee) +,S(1bd8565b,769d0024,613ab814,90f214c8,bea90a5,db1e75d4,11ec3dc7,288f756e,c050a46c,fc781e91,b79cfcb0,2abdae50,b69c2cd7,dcc56b13,1df2175d,c1d375d8) +,S(4f7584c,35ad66be,3d409154,eb8ded67,14ed0ae3,288593f2,76cec90b,629cb01,f4be9248,232a120e,11ccf1b3,e9c5a17e,1520fee1,8f1da048,fb01eb3c,17712bb0) +,S(5b0009de,7e85b317,ab127401,fd2f3ced,cffd1684,c4772b35,2b9c783e,1dd9f13b,f4585704,f531c34e,3377cb7c,e672c78d,cb8839be,ecfe048d,bb412328,b973ba64) +,S(c66f31c3,79396f01,2ea5fdbc,4222df38,37f85353,3f3ed9c3,ad13bcac,63b32815,7d7b808,4ae5e9cb,c123ca86,1b505242,4113ee84,bbac5ca3,ea1cd3da,6eb22668) +,S(33097f5d,c8b09934,26ba51b3,ee99e696,3d7ba455,e91a7af1,a57c85e6,5e63abd6,fbd26b3b,200c189d,c8b9e120,61869766,987401ed,66e4ed80,63835922,c270d7c4) +,S(1ace5245,a3b7ec60,b9a922d5,ffbbe43d,aa71cf0b,84e395f8,c37dd2a9,c85ffff4,72c0ed67,94708f9b,f29c51cb,b6cbb69c,6ad3f4d,10d62987,1c444da1,bb25084f) +,S(bc197b9e,4cce4c2c,bfb22524,93f9202c,6ed54e32,cd52f512,692a5af3,6b0c4471,d5137663,5182065d,a4d6be56,cec50889,3cad9b95,4d5d17df,adb084fb,dd673f70) +,S(66997931,334bdbed,174cfa73,3ecad896,13c6f500,b79a7fab,76ad0bc8,dcc7df70,fdbd3301,948e198e,ee3e7d3a,504ac560,ab00afdf,26940331,d49bd2c,6599435a) +,S(3ba86cdf,b38d82f9,7c20b962,103f79a,5637422f,370b08b3,89083cc3,1a6eb4bf,acec9811,76debb13,9bd7f981,9b476e1b,5377e32a,bdecafee,33dd6ad2,3258dfc8) +,S(f62432f,9db971d8,4c3acdbd,c2d915d6,6395199f,76e81243,fed930db,ef1603cd,ee89cf3d,177b4cc6,e5856acd,5de8757e,82269f4e,eb11a444,c2e0c797,4a7b5f28) +,S(84b41bdc,6a6dea46,ad6e650,5b280a1,b6d81250,794e0b1d,688aeea9,c067bbaf,9f78703c,b535b4bb,2b88cdf7,b5f0f0cb,e452fe6e,5cd0f2b2,ab8c2439,9fc00e7c) +,S(8e2dfea9,3ea64a14,e28f4883,98b8d455,48c52ac,a5399f88,28a42c1a,c89d4c67,fec01549,cda53605,335df10d,d8ed04eb,e09d7474,f69deff7,5935a499,f2781271) +,S(c3bc6dae,5401ac1d,3fd75e36,4cbc2fa1,dbd2f6a2,40e912f1,18b27759,9b105e0b,170fdcf5,5b739326,fd234506,303700b1,9c5dba48,b6f0cc34,a650c3f,3b63d6b4) +,S(33093e93,1b1e52e7,ac5a289e,27ff810,c2defced,e935795d,a10ecc89,a3c14691,7fbba584,5bd55ebd,a67dc842,1ae10fb9,2114f0b,d68bc47a,7ee87a7f,70deec38) +,S(21b35438,b6d1a3ce,6c765e,dc78dd89,3f121132,ecbcc208,a36fe734,d8141ef9,f6115a5,ed237dc8,f61a82b3,66fb508d,e2d516be,3b166a7f,2566bf06,eae300d0) +,S(ced66583,aa1bed17,30248edf,28e9e4fb,ade70821,1c2e48de,3782fc6,d3892df3,4f43ad36,f29da03b,f0fe634e,3c441c42,c3a81835,2407f1b6,cb38e738,18fdec96) +,S(c5a74420,f541a8ae,b0673122,29fbccaf,37f6eb7c,ccf2bec0,23a8573b,ee6f71f8,ae634c02,44263d36,c00a6e25,d25fa592,1612a535,4934d709,6c864865,60adb259) +,S(304a048b,f30f6b4b,2a725521,15b15ea4,8311c51f,c4cd212e,f0a4bac1,48b9de9e,8f935900,3d6ebf0d,129cb5dc,8a953fab,11ceeb85,b2123fec,154b065e,63bb3cd) +,S(ff96b5ae,7eba0af5,ac9875e,97811e91,6ecb66f1,3bb06519,72ebfbcd,5b9c2048,24af2186,bca71cea,e58a0b1d,b56aed1b,3de89cc8,70fd4e3c,31919e2f,6352a887) +,S(5909ce1c,df732eed,4147243,76fdb3ce,8b6d38b9,4a0b35d0,50bdce27,b1b701a3,2e44944,665e761,825cf223,90383a3f,7d3731bb,bf7792b0,37fc05e0,b224dfdf) +,S(ff6b771f,86d66610,6fa032b7,92844548,8ef9974,caf05ad7,cfb6b30e,abd1d527,6abd2a9c,9393e91c,ff77e055,7e9f6a86,9fcd0bae,3544bf50,b25f0427,908ba4b3) +,S(943ccf04,94dd1fad,1efda48a,12d9ace7,be919685,7e7fc5f4,befd7d23,3a1aa8d9,4f08b4cc,2dd93f8b,3751a23f,ca7e4f10,6014e01c,58791c52,3d01134c,1a0a7bd6) +,S(a79a7a7,a89e1cdc,908e0968,bf26c341,47a4638b,1d9cb5b3,ee6c49f7,405f172c,cb53d967,14b5be3a,e5497f34,ec0325b3,ebadcb76,b9838cd1,b3cee90f,f3bb8ceb) +,S(28ff2efc,71176efa,a861667c,d173f78a,4f548b36,aa33db2f,a50c0515,1c7b89dd,475b3707,db4ba15f,1485e165,68d7dbdf,8e67cdb3,37d79988,dc6e2249,d6fe4941) +,S(85b2c332,16a86885,c0704fa2,55b4ca00,223e897a,f0ae7557,f8687eb3,b1012968,a1f58d45,ba664056,efbcbe7a,f0ef479e,1f2bcbe7,98d055c5,7045d735,d657ea11) +,S(e9fc2d09,eefb32de,4068e2ad,d7bd3692,7a02b3e0,d354dd47,c2a70c9a,5cbb8778,ee009aa5,1216d068,3ee219b,bf53ccf4,f249d7ec,bd8c9cdf,80d0ec5a,5b65c312) +,S(da2dcb50,afd510d3,26e38af9,5a22850a,a1cc88d0,620fed65,763042f9,a0005d9e,1eef47b1,c3700963,5e16af23,f1308de9,ae0eab9a,b16c9443,6d501ebe,133eaeab) +,S(20daa29c,c6b166eb,ce717402,70873566,327891d3,ff7b6f08,b9b7da3c,1eb352e0,2ff6982c,ecd6fa4d,ec1d6692,92c3a326,a30cb526,4dc27a4,299dd3f7,7ae8a3fb) +,S(e16b08dd,2ae5be13,67547a53,496f9f4e,3aab8440,6cc34bdd,71b2ebf7,53674d9b,b70f724b,d9522b1c,8e43d60d,6357b5ba,48a1afc8,b7136c1d,9317a1d9,1ba06846) +,S(888a2daf,2d69db34,ff9485e,b06d44,c59670ec,3c68475,80753567,e56b93d3,ddbe4fa7,792e0b82,ac4753f0,5b271aba,8e804384,b7949a9e,9ba79fb6,31d4e3f5) +,S(747768e2,9090fdd5,2c22e308,131f97b2,ee6d8e0c,bf43d704,d50d60c7,616abd12,eaa75f40,8d1ce0b4,bb52879e,5ee7ff36,27b26645,c8ce3840,99dbac60,9cb61058) +,S(8569f2ac,1c7d131a,8d337cc8,87c00c1f,80897a58,f9131143,5a17d79c,fd8d6eda,504f0b44,252d06e8,2f8e700a,746a3393,85e43baa,a4e5da8e,dda7ed6d,83eacf71) +,S(4f15f3f9,a67221dc,4fca1d68,429b874,c4418df8,be480591,e57d6841,e11860c9,982c0d56,1783a9c1,a16bda10,87d29061,3f1154bc,4cc62a82,b795c54,a496b7ed) +,S(21e51a20,1f226e1e,3ebd56ce,6f7258d6,4e4f9db,aa425943,9e1bf7c0,144a92ce,4c47a801,b6a5a4ad,25c1486f,ec9bd0aa,428f3167,45136359,18d47079,75aac869) +,S(fac7e42e,8865ec0c,d0b4c4f9,dff6bf8b,e0f28336,395bdf2e,d5e2a118,9c0211a0,36812d9c,8337199e,fb1fece1,1997307a,ce656fb7,3bad65c6,41e6bba2,c4dd695e) +,S(a147839e,c91bc77e,cc568671,442d29ee,57f0f42d,7b9cb469,91064549,1a26d225,f404350e,bf7267f1,86120257,fa29fc1a,fc0d064e,2f14eeda,b730770a,c85bc5a4) +,S(d1212cf9,e5086804,44883c1f,4158f3e3,44a7900f,716ade2b,df19e41c,18636b8c,720b851,7b91665,128183a0,f3235c6a,2f9c21c8,e8c6ec0,5553acb0,27fc0964) +,S(13d5f334,a7ab2578,977c125,1a07d7a,2e4852ca,8927ce7,2dd9fe90,8b948975,973869e2,d1d0abb5,1ce31db1,ae8c3816,ff998753,479fe82a,7d87b6eb,798773ca) +,S(1f066961,6dae9e8e,76a9bec3,26bc2136,5ec754a5,34c787e6,b9abdfb0,e463507d,da48070e,b4ea111f,881f9fc1,2993a9bf,c6f99974,b3353ce,b5bd1cd1,c75b262d) +,S(729e187,38681dc3,c4ad9a49,59f975f5,907b15d0,114e029,8d4aad5f,69150269,dbf2ed8e,c60ea01b,6de0022c,8b035a7e,c1901c82,9e8d83f2,4560659f,8d455442) +,S(e92fcbe9,61353477,4d42435f,de190c26,8e3692ee,c2042fa0,2ee21687,1dfda12a,a75b5c0e,3f5280d6,41e36957,5e6ec5cf,585b1451,1f01da84,fb852cc8,2d64f2ff) +,S(85c2e61a,c69f8d39,e9c4dfbf,93f6b904,1ad35bcd,7f2b5c1c,789812d4,c8da36df,ca6d9187,694429e1,a5ca50b3,332ab11a,575264db,bf297752,f38fabb3,c0b53f45) +,S(10d17632,c33cc6b4,f5c2791,b5ae4f00,3adf9958,879c24f,10f147e1,bd1bc05c,e15ee734,f1ddec6f,45dbae00,88e4c5c0,be8464f,31205718,a8b2c929,939a687d) +,S(a6942345,25938972,f39820bd,27ea0bbc,92511dd6,827476f0,28fec86b,e25d609a,e06b3616,870f73f4,93f6d1b6,6256cb48,af49ee6c,b5296bd,ea73083,4f11d6e9) +,S(b4a7d8ed,2b3dae3f,43eba052,45b6c4c7,c401a675,6bb0d906,4f66d88,df94d8ac,ffc81c63,1a2cdb5a,fd7def11,9d07af35,74dcb04,e10a5ecf,d2b0a46d,90963456) +,S(5aebe21d,aebd3c57,285cb660,d9aa55d3,f84fb2ff,584f1266,3031e2ab,dda6fd17,22ea513,6a51b532,d178c40,cd5c8453,8f5994ef,7b35cff6,d9dcd999,daf1abe8) +,S(ac684664,194388d5,b796d64c,b4563aa6,69388d0d,83861c51,278316e7,2c8c7f87,cb9426d8,2dc90b01,97bf114,3f693e93,4d710988,26586e5f,f8913ab3,9ef41ac1) +,S(6f94bd49,f89e621,874c58c2,f27ce8a9,76ad2764,1627e835,6b82157c,24955250,d24330ce,4a54dc7c,5c7d9cf6,8f8622f5,e3633a85,8ec0d2ec,d8df3f9,bc7c5614) +,S(3f96c8c,e149947a,6d9ec5c,9ac5ff44,775e068a,785a2fa9,d0940905,a008f137,a91dcfaf,7111a506,3cf613d4,e360c9fc,9b7d9e40,30e00ce2,b120eacc,805f3f40) +,S(d805b05c,dfd675d3,b862a4c1,74909974,405a5b61,9b2a73c8,f3470959,779c707d,a68b544c,c7279f2d,e3a2abdb,fbb7fcb1,84366ef1,3cc3a66,b6d8cec8,3c3b6865) +,S(d2293c0b,d4189cb6,6be0efa7,874abe9b,59142233,6f2f71d4,808be34e,79df0e4,5fbc3248,87c54960,b9bfe70a,5cea3871,7f24f79a,3fe0d313,18cc068f,212682b1) +,S(931f090b,e22623fe,7ad49d26,e76b3c5d,e3f107fb,556f9657,facad9c,5b209d5f,cc255e79,d2a89899,865daf74,81aea395,848f57c0,1850c144,d5ad1a17,4b1cc087) +,S(118a6283,6707ff6b,c8ea72f6,285403a4,6e4e690a,db340987,a0359732,39e5ddc9,91f00fe5,e65a9058,36f9d447,d96af84,b6f5a18d,85c127ad,72221980,f7ff818b) +,S(81096ceb,5b6cb49a,d014ba42,d1d49e1,b811ca2d,2e6614be,1891c6a4,1f6a985a,da051c5,f8f9f3e5,78050a3c,1354b674,3f494860,6b04b8f5,b4dfe970,b7607e5d) +,S(9a80a438,5ff45ed6,2dd3559e,783eb47c,351b7e43,6ddc468b,9f410989,300cae06,845d1f99,21b69c5b,4628aee8,b0c55398,bee65659,e3e41cad,30e57bf8,b804b6d0) +,S(6a3168f3,b89955b9,7fac1d59,61e95fea,2143954d,fbbb6090,81c2408f,46747906,5b5f1f88,6778f108,3ae44a3f,82c901b6,12c741e,811d5403,c483c572,8cccc005) +,S(9a03ab11,78d165ba,23bd4298,58bc8ed7,797710fe,f4f8d8a7,3db0a90f,e1214af8,70888ce7,e61e4bf4,91512f2b,fa556f51,59a5550a,1d50a65c,a652b5bc,89e85665) +,S(8c90c18d,78b8d9e1,59a61575,48c14971,296c8c41,991dce25,e7878ef6,f4ea2f5d,2a5428cf,de628e51,a1644a5e,5dbb7227,2b97c0f9,b6909a68,2814882,cb1ca074) +,S(2e9bab7f,3062024d,84f7a5da,a02c9ed0,93327923,339fdd43,b68d6dd3,508a8957,c9af80b7,3f3803c9,f21e21f1,9523b2df,ea7e4f8c,9a376aca,4a147530,d2a43345) +,S(2734bf2e,718ecfef,64a95e7c,1fbe6a37,e2129898,343af84d,b5c17671,9a466322,f530098a,9f115f0c,e36a0ce3,4697312c,7d0a1e4b,df8a3ca8,f0a63631,e684216e) +,S(ab9ecaf9,500e4a4e,6e81b997,579b5214,4af3257b,8c8f40d5,e21c2a51,d56aab58,f7d38746,8e081844,9bd5e9d1,938a8859,d0aaede7,5743dbc3,ff30d51c,3de0f047) +,S(ae25f546,a4c09ef2,e5a9cd3e,85baa880,292b4d4d,4e8440c0,1696435a,cb1af368,46a2b3b3,7373840f,b739a9f2,2953c6c4,80bd59f2,11013d59,e051055e,f7f3da84) +,S(54285da6,4ef21cda,f597efaa,884fc00f,4e35abb2,bec04ace,54a83dc1,c12e6142,483beb2,144d7b5b,a47c2dc2,9225dd5c,b962a849,d46ff6e,5220b6c3,20cdbc3d) +,S(bece8434,4bc231f,60ad542e,d6a7857c,35a627ee,a2914874,c8deb661,37dca65e,a229fb80,2f9e72f,8e477fb8,de081254,fe1c93ad,a4d3b4f8,e9c2f4eb,3e2f6a95) +,S(3d55747,b148b857,472fe5af,1e820bbf,89994a2d,ae6c326b,26fd9cb4,fb5e81d1,dedeca5a,e86728a4,f635bc4f,1b2b162f,c9ea7dfb,efd5852d,b90001cf,bde465df) +,S(13c68219,d1633c73,59f6361a,88bf6a72,1846b520,33475715,fbc97dcf,75cde5d4,ce8a3cc2,39fc7f20,96abfe7c,52d79e9f,bddf0ce2,ab2b6e55,935413f9,37f83af4) +,S(e9e40ae1,a8041a47,274c481a,dab52f18,36690a29,be837433,43650126,d5b0a6ac,c19958b7,9c9839b8,1371f314,749147cd,9a22fa22,a55da9a9,577646f2,38c6bb7f) +,S(2e3b4553,7460a1a5,f7353a53,78db61c9,13af4371,9a268eea,6321b4c8,a1493068,f7ba5e56,104966c8,4959d3e2,290e5501,5ccf5cf2,b6fb5bb6,e0452c5d,cba54dcf) +,S(9855bc82,b9214b00,67eaa40e,bf670dce,6a59f3dc,4cca491e,db1f0f48,b4c62b8,a7d93f6e,3be6c73c,e9e37d6b,5b071603,87184e21,38478009,8d4c1c80,ccfcf435) +,S(37f820a9,b9342913,6d44bee2,69cf27df,67486bc5,233b8866,982f8476,15253979,fdcaea9d,aa629d37,7f345a5a,37c566a5,50dd893b,9d7ba88b,2a568a28,7870ca15) +,S(e82d2c98,a92a3b0c,690f6ba2,8070c59e,3e0cd0a2,a384d3b0,3cba9d1f,ded41a98,31e73a32,32d85b36,14833d34,4c7d502d,d09d7ecd,614b060,95c86be0,c8501460) +,S(bd492fc3,6dd4c906,6a071182,7eaece3b,ad46901e,b400bf3a,24b93799,9a923419,caada3c5,1e1fd5a4,6676dbd0,a7fd4049,8b93da93,bcd25af5,fdc6a0c9,1dd7798) +,S(6c8b46da,42d1ec4f,3ca2c4dc,15a69c80,cd8f0d99,7bdf3964,1cded32b,8629577a,d3ad4f62,729e42e0,f72ef596,5bcbc239,cbeb988e,e62b30a9,7f124004,c718c956) +,S(78b1e9e6,799bd3dd,854a25d3,4d356b4f,effee71a,ad0c8f05,ea9ebcc0,f8f5dd62,31503ed6,a26788dc,c07d7005,7a300665,d726ce2b,702e65c1,dd25f892,3931145d) +,S(f2ed02a6,63c5523e,3c68cda6,bfa4ab6b,cb53fa5c,15f0375,c8974eea,5aebdccf,3bde5c3,afdc0320,e3b92241,3220ad32,937720a8,d1477b67,773e725a,3cf36382) +,S(7e43f643,a45800bf,7e54d83,5ff6ba20,f67ab101,5d1aaa60,cde0967d,42caffd3,1f456eda,f473399,b57fbb37,807b5269,58600d12,b556879a,76e21459,5798d68a) +,S(df15e177,5eb73697,aa4c0a62,4b4d2ce9,7ccde2ca,66555d07,6430b656,61319be8,496cdc,f1543818,c2173dfb,8a60ee2d,8397cca,b16e4e53,b35079cf,b27311ad) +,S(edf1d706,295bb20,12dc1648,7940e84b,6707a3fb,91a14fce,ef37f669,c782e2ae,e3a0f2f6,fcd76c97,b20b2dd6,8e888eaf,9ed8f598,f08e4d7d,239a8964,fe019a2e) +,S(c15022b2,6b15821f,3be3c313,73d0464d,fd92cecd,6ba87c2d,9b18fb5c,16f8f6c0,78cd2370,d94e2842,e07961e6,92e9fa04,65d57f25,a80feda9,327581bd,ce136c2e) +,S(bd4df6b,b6ae15e0,109886a2,8a8f8c90,c6cc2bcb,b52dd105,e277da7e,c76001d9,499659b2,b0b4cb96,5b8e5029,96ced2e3,a6f6fadc,da01b875,72f8727d,8ef1446f) +,S(dfcec232,873894ce,525f9b4f,162f180e,1e2d6eb4,c846bed4,b2109700,8fbc0b76,afbc761b,f4c88e71,9c318f05,9a10ab3c,5a477ec5,33243b95,3f8ef006,69b4f92e) +,S(b0076c4d,e3c94fae,23659b00,5b8b41fc,b8473935,764e48e1,a9eb1fef,f5c94e54,e1eb3255,3c55a687,6f42ee5e,44830a09,fe17fda1,b84e8551,f3ea2308,f9c7d4f) +,S(9a1fe9c,17c4255c,c11e9fe3,3d66787a,fe9ebb0,99be88be,94b4c3f0,da2d0c11,e6aef709,99a8e739,6e23e1aa,c7ad1cab,25f6fd6e,62df02b0,96af568d,e88e8379) +,S(1d89a934,126bbc15,d9b99b88,b6c65106,e1d8b16e,799630f2,2576e9e4,15212899,b7e32256,92db0722,e9a79ef,7d95c509,37d64644,ed36cfd7,56780d59,a6f8f4eb) +,S(c60f5c68,b67b3796,3c462d4f,7530edfa,34546956,21bc80a6,ac2be433,700c7fa4,88f8b071,97fff0e3,a19b5a67,60dc92d3,b5507b53,5cec02c6,53f75a60,bf8a7e08) +,S(52cd2b6f,d9b2699,1b76499a,d301be43,6205761c,f768eec9,e6b7d6c2,52d9d949,d127cc66,1fa33508,a0d11a3e,ac782b26,26356382,f547e4aa,13802138,30ec835) +,S(1e44499e,a639835f,f384f107,fd16bb19,c21fbea5,cf4e3be9,20a34024,6d05dda9,41c6a8e9,a9042f9,950d12db,74fd0f21,8f8adf23,e961488d,27412c2,f2d1f53) +,S(139144f0,a56394ba,d1e53bae,360136eb,984ecc56,56a05cb1,c6727543,fc6861de,70394737,ff37e9b2,1bf174ab,6c042bb8,964f3d01,6ea1edc1,25ed3b4,2ed0742a) +,S(934ca02a,2454df18,61fcb954,6634e685,34fe75c8,b6db6eb7,5a2a74f8,654a2280,779e9784,266cfca0,b83caee,74fd24f1,6865ce3a,6be78be4,375fa15c,db195761) +,S(a64f047d,9e1c2459,77da8c32,9d35ecd4,af913baa,2d4b679a,7acd326d,886a3be6,e11e830f,f3b4ed6d,102145e3,b24759de,3210f309,8ec57581,e6014818,79112b2b) +,S(e1c688bd,cd629088,8d8820cc,df15fe8f,cfcf45c4,b8bd434e,2a15428e,818757e1,bc10c6e1,71e7c8e0,13b8e00,e77bb745,a34e7d1a,15267600,d130f6f2,18c77f7d) +,S(b1a30c95,123170f2,d9456de6,827afcc9,ba2bded,d955354,c6deeaac,68137358,9c76a0ab,c16c1caf,d3844346,9040373e,a678797e,dfa1b298,5a17d410,b04071f5) +,S(24cc27b5,fbb0291c,3468ba23,58f5e253,4c7cf99f,699af4d0,d6892bea,e6166e85,eaf369af,2516ba42,673c52e3,ff0768fe,d51aabce,2312b8dd,d7aa1ed8,cf9f71d5) +,S(8bb4017a,6166d1e2,f7fe8921,cbd31cee,bacab577,84da8a92,217aab2d,948f6a57,c899740e,6c476986,356e34fc,7182996d,a09cad72,93d78c8a,5c30d56b,88dc331) +,S(55d8b7dd,d82fdd96,e0ec17dc,20b303fd,e6dafef5,a527368b,ec99a33,60497f6f,fd624511,78bd66f,4361709e,44e72e9f,f4f29230,d1fff657,bbf84762,b7b8beca) +,S(82aa2def,5a5531af,519cbfe6,105dbde3,109d4626,ec47a845,5dbe2852,34c94df3,61160bea,9f83a2e5,8c2df91,925fbb25,8d1e60fa,6a147c4,ebc0ee38,cd811511) +,S(36c1277c,c6df7ff8,47c2cfbf,3cfa9198,804b03b0,c28e1636,ad3438cf,2cf6f7f4,2304fba2,74f81c74,5455d821,ea58e047,a7bb3b60,e32f020,aee5a2a5,16fe4833) +,S(f376fdcc,5b44cad7,e16c9e86,c00b366,d57b8925,fa49b18c,eb8856a,e0cd9119,2d6acd32,e4dee81f,489e3ef,11acfc8d,c3d0e7ac,bdf5c6ac,74fe7aa0,50a028cb) +,S(ea4e10dc,5372e9f5,d96e8ecb,907d3a89,97150b6c,39ecfd1c,c7aaacca,5dc5030b,b0896ea3,93b626bf,c2f486d2,9fdeb897,36d6be60,144fc3f9,5206666c,36d96ff5) +,S(74f392b4,b2664a17,9d3f0a2c,71b144b8,a376ea19,f1a9d91a,d181ca3,a6fdeb08,9bd4db21,428d588f,64ecef67,99b46735,c9523036,406d2636,c6eee083,e09e1fc0) +,S(3a36c842,59ba7774,a41a17da,f0e4c821,11c13a6b,58b82774,ca6962ef,cd4855eb,6ddad1ad,9ede928c,d65720c7,15ef39e5,f35e46ba,45d8ff48,2f095d2b,e0fa5e3c) +,S(9d77b2ad,5636a44f,16e73981,46b17ea9,7635ef18,8f32764d,eae50d2a,5c98c019,532dd027,a775861a,b9392b8a,cb2db097,eb5936cd,9d2f7234,f30c371a,22ee3eef) +,S(2e7402e9,450e2f80,e05168a0,f0c5f1bc,deb6117,ee46ac1b,39aae7e7,bea3c4ab,41e8f36b,5606fe2b,8ed6b3fe,f8821013,cf85721c,f242eb60,34b82afa,cd82fc3b) +,S(aeb2cb25,4ed0b5bd,81b33d35,e8f00a5c,6a6806f1,5314b320,de0c376e,533ebe6f,6b8116f5,2d7bfa2c,b3028249,fc83f317,5d761c0f,76833d0b,142c4d6a,29b9d59c) +,S(c86224bd,55d62c97,a00adabe,3a797929,4cca663a,ba3a3655,fbbcc3f4,5cca7895,a319a3b7,104f7935,36693adf,a6009db4,1d857353,fa950c21,844323bb,cd1cc214) +,S(1d1164cc,2c576a0d,d7b5a28b,cfdce6f4,d53ddde0,534b3a66,aaccfbba,3eefe561,b85890de,aa25d897,fccba694,7c470e45,ec600989,243ea91c,4670a,b44995a7) +,S(2b54fab4,13b915b5,ce76620a,5c493ccf,5e7f0f41,8bcd793b,92f26118,a440e3c8,8aff8d25,56fead8d,7e9bdfef,bddddf37,7a61ce4b,2effcdb,30ad0016,4f9bf5d1) +,S(1f1f2a24,a4e72a1f,609428ac,853e46d7,a9718c25,f2df9887,9a3aa60,5729b340,450dca4,f4920bba,bcf94f39,26871032,b631120,4b217170,991df216,2c421cbd) +,S(412f658e,e6777e4d,24e5682c,5007e057,83fbc559,f22f3200,f185ee52,c8ebd4e5,c2e0b64a,9d9394fe,b930b3d7,afa64cb1,c8399e3,27690e32,887b789b,6571c8f4) +,S(8495dcb5,567791de,976fec9a,367e250d,95102ef9,f92c11fb,f561f854,4cf4912b,65f809c5,7d3d824e,f5e63f19,153bda4f,542e511f,464e11c5,e2a9c32a,2a152443) +,S(f8e7bdc0,d841c95e,3a945b8b,c85ca4c7,b4a18a9,7a5646ee,1bb4ff08,5956cfde,cd0ac83,f93a3679,37c9d28c,24b9fc08,6d6660d6,15df5011,1b4edd5d,f0ed6d42) +,S(8324625a,4e4c1071,24876751,7df28ad4,8c8c5648,76e4a131,64f2f730,62854c94,761b1960,49922825,609c7ec3,70626025,de65e2cb,240b8356,1f5cc230,1f9bfaeb) +,S(8b1c49ff,99f87e22,af4b6bef,d353df1e,16a8e160,3023f2cf,213ed859,13ca04d4,cd4513d1,e178865,2d1cff72,822de250,6abbf975,7e2774c0,2ca1bde3,23ad6c23) +,S(e2ad61a1,20d24d80,8c830e89,d630b466,59deacf2,87aeb790,bcaacb82,96f4f138,51cd19dc,fc1c4867,daad2940,5acdc7ca,91849769,6003321a,bf5dbc6f,b2186291) +,S(e8dcd7e,a9a9a6f3,16a6aa91,53105601,e10356ce,7f4793ba,9eae3ad0,34c197a4,c835bad7,91f3aaf5,d32e2a99,e71c4add,95f69892,6a68695c,2e61ca85,38ea6b5e) +,S(f0b748e3,5875b8ef,361bba69,cfb05c4,d8643f95,9b207556,e46908e9,bcf81233,6a264e51,5d163a7b,678765f6,c29ca61,c1c0aeab,a9ff423e,91e9401b,2dd6e908) +,S(900de96f,9975a16,766dd305,bffe2423,e6eef8ae,93ebd796,2ce97d53,39af3a87,894ab2ec,d9c058a3,a331bf65,dbe69a49,f33f8e9b,12121439,650aa700,4d164478) +,S(8cbe7930,d2ea2342,730e306,7e9ecf95,ce7fbda1,e6d34645,a6e214a0,ed88aa53,867b156b,f875a67d,ae27f2c8,e232c934,85092c70,ec071ac9,919ddd85,70186b83) +,S(a0cbb1c9,5b35d243,945a65c0,fc5706d4,e79237df,c13583e6,9a292fec,9a25e68d,b6d7e9d1,3cd61a45,f81c8a55,40dc06e1,3c6d7024,5e850a40,55ba4eb1,82047e4f) +,S(148aac72,a3fa8cb5,aa6d3bbe,5e987fc,d8050c3d,63b47f4c,832a4488,262463cf,7f29de49,a6e24485,5aa45f6d,36f2e2bb,72749f91,8258c0b2,92a33322,677e4a61) +,S(3b9fed07,3a1afd6d,e6ecaf7e,fa20e2e6,c28616fa,25a218ce,fb07cf33,66f3977f,f0a85b3c,5084c964,a1f0c936,e96ad3e3,4fa9e7a1,348ed0fe,ac7003c,12c65fc9) +,S(7de45ced,5228bfd9,557b443c,30fa431a,7c9cbcea,dfbfe0fe,cc565ac7,ce3537aa,515ddd37,69107033,bcb794f3,ac55062d,78e0118a,60c98fc1,1999cdde,fa2686f0) +,S(9cc1a35a,534f562,98010274,74f3a857,c17cf99c,eba1d5aa,251e61b2,55913dd2,c092cda8,f30fa4f9,96115da3,7bf8e12f,c653e243,af2bc7cc,c691684c,3e433ae5) +,S(d82f1968,759b3b9c,c76ad729,828a7283,10fc71fb,22258562,920b690,7ab52ec6,54cd0a05,26983b0c,73808f8c,ae1c9d81,1b372082,dcac3306,c470af50,8818c607) +,S(16e6a947,3d95a95,c31bffc,c291b60d,1f9c548,85e5a498,24195ead,b87b7586,19e29938,581b6b8c,2e50d365,5a957c04,80ff4c8e,4ed73276,f882c558,dbd8aafd) +,S(d07e7af3,ee4f24,e46b4670,477c3463,ad57a74e,57a17197,ff098e52,3b5cd237,fff34e0f,43c91656,69b1019b,ef618888,d4d175de,b6f20b1b,c696f24c,135d0e20) +,S(2bf644e5,6dc027fc,63a118a3,43faa4e9,8ffe42b9,c983014,50a1f4d9,e5665380,bef5c175,77be1fc5,f8f66fb7,a06b55f7,eb84ca5f,66ea4477,c924f925,5a262ec5) +,S(518f0d37,db1db93,48c80101,442597c6,7a88107e,5e25fa3a,b97ed524,fc5cb045,dca8750e,a4e9ed01,66f113a1,44974250,6eb9f3f4,df8ab741,8dba0397,694d7294) +,S(bd48eb6,c50774a1,2be9893f,8c21f624,57bf54ba,8799928e,9a9c725d,6f0554c7,200a6da8,cd8f0300,6774bad9,769f738,dd58f350,632742d2,e2cfa787,f570f6e1) +,S(ccc8d93a,871169e3,69336622,b64fa1c0,800c5b45,e3c0b130,2aa99e34,db1517e2,40ee7e4,d45e6478,efa11f1b,c4548668,88837309,4809f056,11efd6c3,6d01d845) +,S(86f6392c,75877992,311d2e9a,27be9ea7,27e8d01c,fc27dab,8f4527f1,dbf6bd1a,7ee29611,b647aa2a,3d2b1304,c49ee690,57150518,fd46add3,e7caf34d,10f7922) +,S(e034f4e5,927b0fa6,c3794105,338751f9,9bb5a381,6da1dc1b,bfc41d83,b7d7fdfd,dc9f02cb,838242e4,13282b05,cbedcab9,e902567b,b279fb6f,f2248e75,41a5f89d) +,S(8fc36a16,a9dbf00,5ee3a66a,b825510,75eadfef,b86e1062,837b49cc,6ab51045,c7ee2c40,9605981d,217d9957,a004a4be,66a88527,9ec9f74a,70594999,23d200a6) +,S(d7bb40bc,54077d96,d6489b71,e65dcfe3,997130de,b517d12d,9c10adc8,e73278e0,e2096366,2f64bae4,5aa0706b,d96b5cb6,5897c0be,3a8a9b46,8ce9074a,a68b0a4b) +,S(d7357685,8054c714,1147d2d6,c265ce40,3c882681,157b07e0,b8be0a88,63bd2ac5,94f8754b,2fc94239,c254099e,9cd5804d,d2ce03a5,380c59c2,4f42ebe5,85a9932b) +,S(5b6f8aae,d9353ffa,71da7e99,bd3fe165,3e720ffd,657dc2b6,669ae0da,858f8392,4eeafd05,369c6eed,fa6f85ec,34e245f3,e4966840,30253c10,6e74f473,418f9089) +,S(39444d12,67cc29e4,384b4f4,9c4f4886,ab4076a0,19a0fb39,f7b72c4e,42222000,65c2502a,af90ee2d,8de48adf,35388eb9,329f3057,1b77d0ba,50ea01a1,ca83d771) +,S(53de00db,f1efb0a3,c159c4a7,dbc9888e,16ebad95,cec2d003,a18488b,1b0752c7,328ecbd9,99475dfa,752d6228,5e7bc51a,87dc6166,4d14a6d3,3a556322,5e2fbda) +,S(48a3baf,9b4f7213,e280eef0,d5fb6033,194d1bce,eb48d9e3,d4814a4c,bd5ead39,3b4ac9c9,e04a3852,bbc6f7fb,cc94b20f,7e749eed,44a9a9ce,7099a8bb,28334186) +,S(f00d7630,503c1ced,3c418237,27e22d7,acccf406,fa16eb6e,b524707e,5b3ac541,9a1ddd3f,ec177626,b1254605,df8ed593,c9e2bcff,db7d0404,f47571b7,31ca95b5) +,S(e1ff1994,3ce7eb59,e570858,2e8c21a0,c4f8eec8,40815ee8,9a482658,8941eaac,528e5572,746e72e6,ce61b53d,78aa57e9,dbf27e3e,bc36c3dd,3b4972,d7353b7e) +,S(e4f13c20,c48e750e,e15a665,275c27be,23b3aa04,5915ac55,2562bef0,7459bd49,bebc7ece,c6e51f99,a2e6b9d6,a7b1bbb3,63901053,362a9ebc,a2d21cc7,6e87ca30) +,S(e36e8cf3,824b66e8,7083d371,60cf2719,598c6c04,ac693ea4,d2dd5c83,886f5f20,4ea0e193,8afe57df,3db74910,481a54dc,f5be9fe8,64f249f6,c88d0cbd,a086c60b) +,S(51e1f319,3286d2fb,29cb4a06,84d7c547,797ff5dc,fde9572a,63dd1e0d,2646365f,ac470e3c,6f30ecc6,31a90d7e,6c4c3d43,b8640ced,b9465cb2,ace2cc87,52370e3a) +,S(8e82daa9,c40d4e72,605dadd6,45bc26dc,22277f41,56d2a248,29bcf79c,d5a5fae0,7f8155fd,be9057b2,2b191dd7,233e291b,b01b961e,32a124d7,33ad99b8,167c53ee) +,S(79e56744,273c7aa4,34ffd5e9,525fa788,38bea674,64e2a595,9881b359,3e2c41e3,625089a3,c50defb9,f00ec764,b47122d7,eb786a20,f278bc33,e806e7cb,f385ecab) +,S(a97e00e2,d19c1957,51deb891,84e24a22,af7fe156,f2f1e068,79ded3f6,62743f79,881d7ebd,8bcb2c49,354726bb,c44ff91e,f3f5835d,ea73b282,944a5097,cd8284a0) +,S(3bf10546,7bbf5c3,14e1c3fb,40542378,9bc52fbe,8fb38aa8,f4a70727,b338542,e789586c,fad5b7ff,6dc68e5f,ef840e05,9a87ba51,e58462b6,39042c64,24f6367) +,S(80296c77,58791dff,39b4ee87,ecf3406a,49cce0cf,8437fb2e,1f4880b,55d9cc5d,3b06be11,3c7f781f,ce28753b,708bc514,902e4834,bdb09284,846c4ddb,90152dcb) +,S(48e2cb7a,a3eedbfd,f6a9cc12,359c4ff1,b7b0fe4e,87e57023,59896506,20ba52fe,dc78417a,fa909bbc,594411ba,87f72ee0,a0a45631,3cff4aac,7ad564b0,9ee8ed1b) +,S(dc91351f,cb775488,286b482a,a187d79c,31a3db2e,99730b6b,7b4805a9,73403d46,ed720e0d,2d13192e,8c180ecd,5e09fa5f,fc52e35c,4e509b2f,fa93ff96,f7adb1a3) +,S(5d37c139,48ceb4fa,9cd05b15,1fb344e9,3a2b2653,5b052b9f,1797319,e990a670,f790933c,2590ba48,7a832ad,6b940634,b62e16d2,7c9e748a,1856d53a,1974cb01) +,S(98bcbab0,f8d69b22,6fd7eece,a848ff4,15c8e325,ad9e8157,708eca17,77070aa2,7671e3b3,db715487,e6affd61,5218a7ef,a08aa949,9bb10206,e2de58d,ea150212) +,S(60e2c1cb,3de9486e,fa594384,d5903340,12ce308d,2247a18,8fa5c112,3f35b1c5,6de7031b,9767c66f,5c3c11a3,853bf722,4d58d086,b68e08fa,63942f2f,9369d1bb) +,S(814716c5,aa8256b7,50bf2f70,2e2f9bcd,aaf513bb,329eb467,d873ea72,304885c7,eca644ee,8fa96189,13fba31e,23533de9,eb7efac9,a0fcb58,6300a42d,c7d297ee) +,S(25789f3f,1db412ef,af60f7b,636686d5,9fb71586,200e8e3b,e6d934fb,72f8de77,e5222798,99d1e21b,5734a6f7,7881a686,863bc03b,8c58cce9,633c8302,2c7de0ac) +,S(5382f40c,98bff8e5,646a87fd,f3fcb6a6,27f2a91e,780a1527,ef18cdf2,a0f1bdcd,231d01de,e41ca3a1,da068ce1,39d97a16,39c027d8,38c7879d,9a1e85c6,4a32b502) +,S(448cfd20,9db2fadf,fcaab14d,8f57dd01,67d9ecb3,f18e9dc6,e573238b,a11d1f2b,bad8e2e5,5a4f56c2,435e8d18,14d2824b,2ba1bb67,9520587,5a11c315,9166fea6) +,S(d917ca4b,fe6335f,5012b69d,5444bbf9,f6c4893d,eb612ab5,667afbe8,2e5653d,3fde9a4b,e6a49756,27950f1f,f17ce5f0,aeabc055,3102c33a,4bb85bae,f32bad17) +,S(c7ee9f5,17a883ad,733de053,be3ef583,1dd974e6,a4e8570,db35f24e,91ba8f72,8db7738d,26d367bf,657d2a31,c6a08ce2,e06a7e4d,2df39f3a,2bffd062,79bba44) +,S(83f0a19d,983ed6de,7a2b173,77c843bc,819a77b8,a32acaed,b7085e0,94d9a30b,d2ab3e96,67be4473,d8748b63,6113be60,880acd47,6d574e00,c37f4875,2cafe6a7) +,S(f3f8aa6a,61687c40,98fb56bd,e74d83dd,59674079,7c52f2e,2b299277,2313989d,3a690c9d,98503a3,2d201ff9,a896365c,caa1b54c,36857a21,ad63994f,41a109fb) +,S(4c1a11ca,a30bd6c7,d95d6e8b,3ebcb4e7,914fdd40,4384716a,283ee1ff,5032249e,e7e718c9,4653ef40,d214c604,e65339d0,6598f17c,37f82880,9b7e5215,b9424da0) +,S(2941b952,3419a018,53f3bdb0,420f3182,529ebbc8,5a1c8f6c,1d922c19,3ee5477d,377f226c,29ca66a0,aaa05baa,7f6c1ede,80482b51,8982763,864392dd,3e628413) +,S(9d04d07,aad49af8,65bb3eb1,8c7078ac,4b5f25ef,e18572c3,3842161d,8591a6a1,f572968d,ec2ca89f,b45ae02d,119644b6,779eb0ca,1d48f724,f8512ba2,2c83cd34) +,S(4401f767,c3c3a101,b99a983c,9a622824,d660c50,177bfef4,a2646b06,43d26e20,7952faf7,8e1b114e,16429309,1d0669e6,999f8bde,ee980c0b,b7d669de,86d4e342) +,S(94b6f427,fc4017d3,b328665b,acc863a8,ab8a1c4,7b283fa6,8d7b7f0c,1bbba31f,1336067d,35f0d2d4,6ec8199e,99dd07a9,9cbe7725,a9981868,e09a0217,df40d85a) +,S(41621ba2,92c79bbd,463b87cd,de75574b,f2fba59f,92025445,7389b4a2,4de7288f,355337d5,b6f30b78,81389951,fe67b943,3bc70a07,b294d11b,717ca2e1,a2cd3188) +,S(b0838415,6256c1d3,55900dde,6126818b,8a9b27ba,ab14d73f,c33c399e,fda3594e,2aaf9190,55b162e2,91cc5371,b6a4285f,843ef8d1,5069ec7d,c5d68475,c5a954a5) +,S(cc99a14f,ef418fea,5de9f437,7ccc1426,7d910f13,e8448fb,8ba92746,6c0dc9bd,2e30b64,7c01c12d,d42f164b,ac0c9bf2,22f7b3d9,2cffd7f5,c77aebb7,18536f28) +,S(8d2bb24a,dbec1858,d565d59c,1d805d8e,7b21d6b5,b967dd50,a2f420dd,5764e37,cdc6d730,e78daeba,712537c7,8a09322,fc371d0d,6a5645ef,e7014bf8,999f712f) +,S(63cee6de,f18cf4a,e6ca1871,7750e328,dbb94c6f,27422192,3b233a3,e50f7c9b,81230dad,ad2d233a,1b631b8f,7a885828,ce005031,e1365436,7ca34173,1efdfeb8) +,S(62084e9c,1dc6dd03,9a68d5cb,fba19dda,b2e4d07f,b8f46114,926a59e6,92755a0c,6dbeb4f4,62fb1af0,dc273a,aa827e0a,cc9c7f1a,fbcdf02c,c4bd98b7,5061a26) +,S(110c0eba,f65b6280,14e368ec,17072acc,3f34a937,7df79238,c2773625,5d8dd827,1a4ba716,6f236258,961d5865,b020b83b,c3c3e74,2dafaba9,649ff85b,2ae75c6d) +,S(d848a51e,50fb234b,a807306c,fab97405,baa50a5d,23cd12b6,8927c9e6,f1c87e00,9db9be62,88fb00c8,4cae4b1c,c99449ed,51fdb49f,3cb7aadc,16a72b6f,a96a4fd8) +,S(42311893,a2706ab4,52547f3b,3901b9ee,a8cf2660,581b0023,96bc9a7c,e14c2b5a,750f86db,9ba6222c,199c2a9f,77609a47,d6129a1c,e9ef4d70,daad3d2c,ae4165bc) +,S(4439c4ee,471adc41,32f45496,77ca1e32,6b252f1e,5f17f741,9fdaec0e,3834d37f,bd75c32c,22c5c3de,62f16ab6,6f86f93b,617c9565,b3859195,81a00ee5,75897e87) +,S(4dfce3da,b19231da,648b0bbd,8c52fdb6,e02e9e79,9806fbbf,36bacafe,c113b053,de8c5f1f,4b727fba,440a1c3e,147cc1a2,9d647c59,42feb42f,69d45a2a,13042c3a) +,S(3bba2b2e,e8e72736,f54f9158,281f6c14,9d0ba6f3,ec6d89ef,cddeff9b,8117dc9d,ff087274,77897e56,e5e93f94,7af6ca0f,6f9a2186,a6a60d2b,af690a30,da16ab24) +,S(a2fede43,37bc6b2,482d92ff,f55ab0c,e239a00f,4fbb0595,27f7d67d,8317deae,2a791508,43beffd7,ef08e195,d0ce022c,f780116,2f1852da,98c3638d,45869ed4) +,S(221c4e2f,f503eb4c,4a1aa8e6,77370085,b3d64d09,8430a185,2cb1cc3e,304bc0a3,c3c37b1b,f954e79,c124fd70,ad3f8765,a70a7929,4a262de1,99e11dd1,95b7ae41) +,S(a0c32f80,f7e4ba05,caf945b,49b91306,f909c8bd,559e4bfc,a58ef3c5,14740ed0,d3eb8f01,46ab4700,41de4cfb,dced45c9,966aa1c6,38a42c90,41ba1891,36f9562a) +,S(762e7a18,b4fe627f,1e1ca7,57740811,bf33395,cc962aa1,dff79be4,18da85c6,a0df0f46,50461c0f,4f8a743c,3455b842,5875f795,4af56b93,dce93234,c4f51ec5) +,S(2f02d935,cd95caf3,d56cfbe4,4337b1f,78389f34,1146f561,b8d632c4,b93a29f0,173470d8,23f190b4,f8008872,b23f1a32,9c45441,c12fe87b,e74e927,18f44569) +,S(c9f877d7,2eb816df,1c5adbd5,9fc98a39,c5877d6e,24ef1612,314e6392,e7eab212,14ce9917,88cf7eec,5a5a52b5,8fcaa9f5,88bb0052,754b3ad1,b0858e4,6a067c4c) +,S(cc4dff69,18a05cb7,a6f296df,6cbf5d0e,d6dd1c23,ae76c5df,239d2179,a0baa172,1cd438b1,b8471750,261b0650,663b4a56,e4dda0ba,b5390cd5,b7869448,654a4dc6) +,S(faaac74b,3ed2713a,29c10219,a78acd51,ca015a8a,65646a5b,cccec828,efcbfaa1,adcad43b,dcc2ec0d,bd65c46b,7fe79549,b2e74cc9,13fbcecb,f8bf661a,7d30d934) +,S(171356c9,30fa9bd0,da1444b7,35be6c0e,8a0025f2,3d1a2480,dd0aefc4,44fdbf46,770e9edc,991efb9d,ab44361e,d2398e54,62e2464d,2ee2a14e,b2e149bb,9c9bce3f) +,S(933f56a,e0473763,d2d491af,55f9fb19,c055017a,7a81b43,b641007b,e5680214,66059c47,481cdb63,481ea647,f494e541,ad1d70ff,93b1eba9,f85a9cab,a0ea76ad) +,S(a300f22,b182ad37,d7e44691,bc9c9c9,8a397f76,1ec1acf6,64ac1fe0,5bbb6b34,bd6f2ffc,a90974b9,460de269,4722f215,684abe44,6228b500,7b42bab4,5433593d) +,S(fc5e57ed,6e901355,f97c1d62,dee4d630,878b79b5,528e3fd6,85d6e3ec,af8fe1ea,1122127a,6c21cbb9,e598b1b5,68507bee,bc7c8549,345c9d49,8c4a9b2b,2f5bab01) +,S(5a2f40e2,7a64811f,bd4721c1,99019523,899e956,ea340bff,f3f452fb,5231ef3d,6b2bf95d,12578c79,74a06d26,39d71c31,d8c4a53a,6279886c,20a122d3,2093d547) +,S(59783333,df0b99c5,be76610d,67d7ef62,fb15757d,8dd1f310,6f9179b5,64f2084f,f2a9ea80,dd3d170c,813f4623,ba7583eb,7d309d97,c34f4c4f,a7676694,7e5b7f5a) +,S(cf61124,6b513fc8,73f72bb3,87a29c2d,a1c8bed7,4ca7ca08,1546db1f,37672d95,d23c3c76,697f0443,9ed1d1a5,661fb0fe,1e182cf4,2e07c787,3eff7abc,2f8c70ee) +,S(edd14f05,133a1480,e26eb7eb,8063f8eb,1cb871c9,606957ba,ac14b173,2ffe7d52,d682f280,d295d528,4c1b3aa8,445c274e,ee603308,ca4792a,61b5f8d6,34b1b70a) +,S(f9b0fce9,cdc8af3,8b26e790,2c95926c,33cb8d30,a5de80d1,75fd95c7,fc1a1713,ec7e8df6,f3d163d7,181083cd,c8cf4a89,df958b8b,d6fce2b5,d4752240,f2a3e6ac) +,S(ae906599,54187f57,89306981,7417c566,d9ea4315,f07094e4,e46bfd24,1746a3b7,2241bdad,c09d3313,e9d006ff,2a04709d,17335573,5be5b10,6775457f,231a129b) +,S(55f0f800,76492f7b,f5e134cd,e581ae3b,f68fe9f3,44107540,c54b350e,47d956e9,22a0891d,e68488a1,dfbb4b8a,35fe9835,e258dcb5,c70ccb98,2c8a48cb,c33956ff) +,S(90c8ab06,86fb40e2,31923bb1,df86647c,6cb7e3c4,c451d0c1,b871994c,19663bbb,dc748cd9,570eeb2d,c6fbb2c5,c417979,cb30d718,94c8e463,e3b7be3f,fcc80ab4) +,S(cbf47c2d,6b21ebb9,fb268e73,56ea849d,3e476d6b,ac09eb60,4bb2e27c,84a4c694,f0288fe6,8042894a,39abf8bb,e5962421,416ed9df,dab081cf,16e86fba,7abb2873) +,S(7c30885f,c18b68b2,8fff758,2148d738,d8f1bfb2,46543b16,37e9fce9,7d11fe80,3e2d1cb9,31a11c15,b26c6d37,8c886e10,52c06718,a63e621c,7ea51c76,3c013f2f) +,S(ad614919,d1bcba0,dd2a9da9,de9207db,e137c772,37f333e6,4f11433b,f66d7753,fcaea18b,3512a188,9d604619,2ba759b4,190b72d7,ec53d0b,aad9e01e,d239753d) +,S(8df7041b,af8c9c15,70ab50a8,1ed335b4,a7bc4171,a3939715,a295ca7c,4e5e29a2,e892e43,82677bdd,f3566b24,c7ddc6dc,e12eabc3,84a19a13,99b64ba4,bdce02e7) +,S(9f4c1e57,61c8520e,9a751891,ac1bb5f6,217f4e77,7dd88fbf,2a127804,2cfdadd6,fda210ad,c6cee889,c35831e,b3e12c7a,ed4b6963,9f3d4860,9d9b960f,4e7d0f50) +,S(a436f4dd,23ac70a2,c093bacf,91de3093,174de618,7525947c,2ee8ccab,a515acbf,c0e9d9d9,2a615b9a,9439a450,927bc128,5879e8b3,7d460ec,9fe57eff,7e19afb9) +,S(a38eed16,699743d9,16d8627c,5039695c,37497c67,c59547d5,67bdfa20,b86f1930,6e3e3ed6,effc3b5a,c9b5b5fe,3f26c91d,3be89bb1,48414c18,bb0e5454,49d9d7fd) +,S(5f4590d2,d4043a1,faf659e3,36b0f24c,b6f1de5,88e92586,83361eba,e2fbf3d6,250c0a73,42ceec0,3ec1af11,764e7ff6,ccc833b7,240466,15890be0,55197db) +,S(7565860d,c6ebb900,68ed16ff,8f7282a3,d52beac7,73cebc55,1be51f44,34cf56c0,4b56ecbe,526ed458,5428ad7d,e9d7f3eb,9b84687f,e01e1346,c32461f0,bae24c26) +,S(3e7c7fce,3a56ef01,cabad50f,2003a5a,77292742,be80b5de,c537b50f,95a9320c,98cd94b7,926e7111,f3778904,599fa9d9,d5dc342c,c495b914,a32d2722,93dbfaf1) +,S(131eb457,14cecf84,abf1aaf5,ec4c62ab,2ac91a0f,6af57552,2eb07274,b7cda208,a93aed4f,f0512604,46c61393,faec55aa,9b017a13,60d13031,27bfd897,e320839e) +,S(371bc601,e46963d7,388bff6,9c4b5f42,a98e68e0,2db3e6f1,637dd24e,a2a11ec8,e2fbeef1,932fa241,a9785238,c1b89269,21bbc7f1,3aa6bdd3,7b39d94a,49f84622) +,S(4770db04,92ca73e8,a0136bc2,2c45185,b4d45934,e4430237,1bcf5045,cae47d6d,e1af748c,25b1d906,ab77e080,d21df4bf,99a92f7b,4b1d790a,f1aeef36,2d41ec22) +,S(b31a8643,5af5db57,759dbae1,67ce3af5,e8e2ae34,20786fe0,da82812c,9594bfff,3793425e,860dc99a,a96a85a2,585b06a4,f5aaabd0,551fe0cf,3c743be3,c09aa4a2) +,S(e05eec52,84a2501,fddfe6dd,1619c374,a94121bd,7d1c99bf,9b2e665,bd3631f4,c0115f17,2122f806,99a24ea4,bd742425,4d883d77,6d269ed4,f6cc5626,ffb8e622) +,S(e55ddc84,ee407d3,45b84305,d97d3f57,e57810ef,bff3b35c,e4d8a325,2973d5c8,71f77bb5,b0fa6141,7e43e425,78ebb13c,abb87a6a,fa0cd1a1,26e8936,427ee677) +,S(ed7b6ab1,a5c8a9aa,284bf3ea,5501d33e,1aabbe76,f26a9f0e,d46dd23e,decd788f,2280bb54,19d1a620,18454a4b,cdfd82fb,824027d8,c51770d3,77233e01,1d0db63e) +,S(d4e331fc,3da4d8ae,e13a3329,acd4ee69,ce5cb71e,224f2001,f9606714,8090e79a,895141aa,2f63cd30,9f4a6b42,d6a88112,77821e51,6d08c52,1ae8e158,655e10d6) +,S(4f0ada0e,a8ec1ffe,6682545a,bd8152c7,2654718e,120d3d54,d648b487,896d4417,a603b9ac,6026ab46,47f5acf5,5a9fbaf7,20aaff54,56c88cd4,dc5ec7f5,935aa591) +,S(a2d13541,b08eeee2,4f086a9d,20df7528,a884cc05,4106b1b7,543eae3e,fdca84,5ac0b166,294d6b91,527a5249,7fd605ca,4bb67c35,85e002d1,74503b7f,5c803a45) +,S(4c1d520,14a0459,2b8887fd,afa945ff,cbfc4722,2ce008f,64fe8123,b5b6c8a4,243c4280,17b7918e,57d06597,f348efd4,ebcebff4,3950a608,3bb3e334,50ed738d) +,S(5f9e5a6,7d13e9b4,cc35b8e6,b2305cb0,fc2f5b7d,ff32ac55,1a5970a9,2bc54390,74808637,96965f7d,bc45833c,e8bedf00,85eb0cb7,26f3276b,30d9543b,7395ff6f) +,S(d76c6f80,95381b17,80ad28a8,80e29ab4,4447c297,34a4d286,98534bca,8954575,44b6c3f8,6b30e01a,61205178,90e429de,aa8273f1,277bc498,59c87300,a561b27b) +,S(7577729f,f78775af,703a9eae,b5864a18,6ad19f1d,dac658,e7a8a05b,d9df3344,6b519916,cceaaa53,92d2f822,98e7ecf3,3fa7c5b1,2e705345,32ec3f99,2f0afec9) +,S(50378f2b,457f04ba,d0b19425,86ada992,78700c8b,36bba67,fca916c5,8edc17db,cbd1451c,26bdcd49,1adbf40b,ac5338cf,26957364,f82fcad0,5fea3c2f,76273fc1) +,S(3748dc68,64365160,26384ba0,ec078ff2,7606eb44,e3d62b50,b9138be8,cc9ba86c,6c04e414,f624ae9c,ddd005a0,4e01828d,6e7bfb81,d350d271,96583c99,6611d709) +,S(b23a59be,8ea8d561,fbdeaea4,49eac729,3402f342,d05fd404,7f9c5d1c,57eea53b,bea47c68,f2d35b82,ce3c359c,83f5fa1a,95d40eff,702ed9c4,2fef0e84,406dfb9b) +,S(e4b451e8,7b42a5be,5c5f443,5701d2bb,9538fc06,925ccb49,ebfd71c1,16a64770,2af84669,9a790749,48efa86b,2b79b985,4cb261a6,8a9081e9,e1467b77,2f156da4) +,S(864ac6ec,65b8b086,346e671e,8651ddf9,de74a215,64f3da12,42ff7548,96dff165,f35738a7,7ab48555,91ca5103,c8d2bebd,b2cbf902,dfa93188,d68eb600,271a8730) +,S(b7d04a3d,a6a863d9,b7809022,56643864,fd36c5d7,9a056ac4,ecb27257,f02ecab0,cc40634c,6ba5dc23,e59e4e3b,fe6a07c0,1519abbe,7530f1a1,5ec7ef70,6f83b0c1) +,S(ddfc1af9,b51eddd8,2020de0c,4a8377cf,bd6e2531,ebc844c,7ca8fca2,714c1a0e,cf77c8c,1742c4e8,b22d9f54,a25daab9,c30f23f4,da3e1ad9,57b9660e,3ffe3951) +,S(78fcfe69,d5bb91e3,a13de26a,614d8479,e00c828f,8868fc30,ea75b47c,d51fcbe3,9ec67963,6b7053ba,b0cb231a,ac28143a,98021b48,4340f060,66da6e72,47f2d47d) +,S(dcd918de,16961d71,8222b4f8,19e76ecb,138c9884,7833a8fc,d4204dda,1115863f,abc3d8ba,c8d808cf,ca12318d,d13c2932,3ff7fb0d,813a5ed2,f5e52aba,cb23bb04) +,S(39ce2ef0,5de08106,93294eef,537bc212,e6f64fa2,96ccd2b2,94a0806c,c6c3177e,25eaf4cb,b7697a3,97a0ca92,6f3a266a,bbb5dda,78943492,39fd29db,78730556) +,S(495e4db6,43d4e89e,df50e937,e97ac4ba,1464514f,d3a46b5a,bae6a53d,3157a04,7d327e18,b2960d69,ebe4251c,f8c416b4,f84bb81b,a20ce6d4,6e6b1c57,e6ec1701) +,S(91c17e8c,b6357c0c,1c36dde5,29f9e6f7,a6cb6e97,f5b67dbe,fcaf5b96,637c33c1,2fe52097,fedb8ac2,efde2692,20f586af,f07b76e0,f685ce85,c965ec1b,a54c39ba) +,S(e3c4f480,3dffed44,6291f11e,cc5c9590,1c28749b,d6ae18d4,c0371221,d5ecfdbc,5a2e7102,571e27ce,974ad71d,acef8b28,4e7fb827,5453e40c,65b2be92,cbdc62d8) +,S(b3ee17f5,a0e81e7b,48814377,af9dcbb8,59ae7bea,5680f33a,cc15d8ed,75c25073,135a3c0c,9a6d2825,a6035afe,139ede23,b46332d5,5739ecb,6d092e7d,6cbfe86d) +,S(e4cca844,2bc91bed,342628e1,f6492335,7ca6e8d9,5e5b5732,29866066,eae76b75,dd55a555,39b5670f,f70b42b0,f319ac72,409f74e2,31d9cec,ecc8d90e,516f76b9) +,S(ab39cfc1,81c96089,998c02a4,64eae7ae,e517e4ea,962b6359,b5ebfbf7,da223b2c,def6dc57,b4dcbbe2,e6dcfec1,8281a189,72ba3b50,f996096,a22e4ea9,77d2fc4) +,S(22a32663,9e6e0469,fe4cad40,964f081a,677572d1,94b3ae01,f8e45c84,dfab402a,1c9c9d95,bd4e0ef0,5acf6148,44c98fcc,db44cf50,5d42af26,1b855f98,40d2b437) +,S(2bc788cc,eff94bf0,307c5ead,4fbc4dea,db269da1,7790a903,7c2fcc24,21f9cae9,172f3461,648c5520,44081c43,a8c78c3c,ccecb248,9d60d384,aa703e4e,24bc4b41) +,S(b930dbd2,a6720601,35a75bb8,8bbe69e8,3872c636,9fbcfe4,c622a300,2052729,9983f03,a872e8b8,2830e7f9,a7438b39,ff3f6836,3334debd,83940ff5,ae06f366) +,S(b435738a,2aa9ea40,702db448,da6f186f,29bcd03e,872a3466,f33b2e39,7514e3d3,5828d246,2d3c671f,85617e55,bcc34905,1678cb8e,f61c74e,92c54473,9098636b) +,S(c91f2e81,3acc9baf,2c52df27,d4180dd6,ee1fe67f,9db6223b,532dffb9,3072bd25,1c9c57d6,96c12f13,13afa0c2,b377e1e2,b027350f,bd24f455,69c15f07,85b73c0c) +,S(bb0946c2,8099ba93,8f28068f,416d9003,bad0d06,f8c7d31d,2b995f00,5c8d36c8,8e3878d9,3b575fe9,78fe1a62,1e978f28,1560421f,7782c164,8673906b,ed76da4a) +,S(485e3aa1,2e823374,cd506521,a707f367,5298dbf7,cb44f398,c31a06a4,8f085c8d,a12c8af5,7079b2b1,5a339d4c,302fc262,af0153e0,dfb4f878,a4b60017,86ca9a61) +,S(850f9448,d3282256,940da03f,e8a96eaa,f21d02a,78867db3,e8a9fb9a,713e844d,4551e4fe,3201ba2c,a74df3a,f58a820d,3a67836,a5a8d82,59ab2442,3bfccb7b) +,S(a74816b3,f66c1fe4,9f8e51b1,8eaf51d9,449cd4c0,54b6dc43,682c853b,be39884,4e7d5fb2,47ed7ea1,45af0cfd,c4cc1059,396626e4,80ec804f,15ecef7e,b372f7fc) +,S(2af5c56f,c71da217,79abcc1,73412016,e1eb702d,6b98af77,85ead6b7,7b20136d,7f3110a2,c6a82623,b2c49e95,a31a6b8e,783911d9,b532932,1b651541,86b706bd) +,S(9291ec91,a61adf1e,90d63135,fae60edb,1a313714,97260903,9684fee4,339b5834,d530506b,e8b0dbb3,fc09649f,1832de93,feef42bc,ade2de09,bac1dd17,bdd03884) +,S(160ad3c3,659a7816,4e9cb47,4e18ff6b,a8581fd1,823ce8e1,14444292,cc605b54,1618464d,5f28d719,a61f939e,b1eb91d9,a59f2c1,818dbb58,b6e1f426,a4d141fe) +,S(352599bb,8640920c,2d85a5d7,673dad8d,ea4280f8,6358a572,b4071934,60ba9d58,a78a591b,e8064f2b,22d7707a,d3c95cac,aa2ac3d8,638d564a,50f7d1c2,8b538d0c) +,S(ec20efbd,9a8c634d,92f7a728,1e9e15d5,adb37ce1,2236bf33,4d12c4fb,7b6ba527,acdb29bc,2a5a3115,3919315e,27af9d8a,e8c54792,fd5421e2,a9a57b3b,d51b70d) +,S(40d1e4da,8bdac6ec,55ee847d,c59781e9,bbd38785,1863c64c,5cfad460,e2dbebc3,c630581c,b7c92e68,a67c7d5b,dba3ec18,4e3755ff,27fb53ac,d3a2655a,316e9ab0) +,S(fbe12740,2faadf2e,2b1ac1c3,98b66df4,81674c2d,f0ffb512,7dbba444,e7d08c7,d00edcd7,f97914d0,3ac87182,14491698,f3dfee34,e6e8587c,52f2f7b8,b7f412d6) +,S(d781b5a7,47d191fb,8850fbd8,fb1e123,4070d9d6,2643008b,b0cd930d,c191eb03,a4aa95a2,5c74ab55,f95f2924,519b2911,9762ef30,248db792,d906b18f,346afa11) +,S(6472fc42,d926bc7c,115045d0,395b5e9,22790c39,ee520529,44a446f0,9ccf02cd,512014,a92593de,e2264e37,633c842b,45d1ab5,e2ad068,63db7894,4605a99d) +,S(eee180c2,e09601e8,6a517a93,54607a2c,5fa6cf26,4c80ffd2,c5715ed6,395e0c21,c8cba798,221d6fc5,b4fdaff7,f785ca3,49490af1,ae655711,e0649669,7483e7ea) +,S(900b262d,a172ad41,15bec071,c5763077,9103bed4,db500ab4,fad4b750,45ada2d6,316457f2,bbadfe91,3f418e7f,b3fa34d4,82c4c1d8,516755aa,371423e0,51e2cbaf) +,S(7e93db87,4e1e5070,772d3371,b9ef29d1,5d5e03b1,e66bce20,420801a2,13a34c9e,cdeaa624,750032a6,f5faa0fe,e00cdc10,63f3ec47,b5bfb56a,bc2c2339,e38465a8) +,S(461fb424,65f3a55d,e66761b8,44abfe3a,d172877a,3edb1f5,da98c82f,89a379ca,768261fd,ba032718,f5501dad,c05e41c1,1f584aa6,6b8e732b,7f15285b,18e815d9) +,S(1d9f581a,f0f61a0f,e5d0f0cc,91ba4f93,6de28aa6,5f35059e,997de778,9419e09f,7fe9c98c,7d59dc56,160302e1,89676f54,3f02db1d,622251f8,adf369b4,891bf6cd) +,S(8cd70b52,904b2aa7,240f7a70,e4efe379,66386dff,3ccdf62b,e2343821,767542c6,b3c3d03f,4c7e0b1f,f08bb2,f72bc6ba,e9e293d,886541f1,ff86bec9,b5ddc2f2) +,S(a0b547ea,9c08865b,99a5b8b3,800daefd,99097b23,4e442a2e,819aa628,eb4a5261,607ef115,e585100d,c003cb4e,1a27eb60,fd9d1e18,f2d23a22,80cddd89,f2ca2952) +,S(ea8a60f6,547038e3,683a649c,27e81ab4,192406f5,5fdbd775,78dd6360,4344d289,98afcac0,b05ad5ea,8fcb9f3e,3bc22f16,881b5fcf,5060c691,ac10f746,79822fb0) +,S(e6051a9d,882f9ef,77d488fe,55bb7829,48bce506,91350755,1a8cd4a,14b0a711,1c9cdabe,9d9eb555,cb9257b8,a60af75c,c1ec0c82,4d933498,ffaa14f6,2e920fce) +,S(600876c9,c50fd337,6ce5efb,c07e0e5b,165338c5,4f8eaa4b,39a525e9,88765674,401a671e,f52b21f3,83df5da0,aa0b215b,b044202e,606a746a,213796e4,dbea4189) +,S(3b045b9c,5ef6fdd0,9b3efe12,169e0414,3c0eca56,5b7e0185,274f1e97,f6b2ff40,aa5773ac,b21107c4,2a8085d0,5d6914c3,a135a47b,cb136dfa,d20e6813,62780a28) +,S(dce98d32,ee0b55e0,4d67807f,ded9cef5,f9504b1d,e552a2dc,643ee7f4,b1f0f1b6,d03ac27c,9e992497,cbb746d6,7acf5427,aba058e2,801df1b8,d435a1de,1f3fb086) +,S(365b1148,6e8a60fe,8a91c07a,93686787,dd5aea7f,22fa1449,58be984c,e378fd76,2c7f5217,319e5d50,4c5ecbbc,bdbb8ec1,b36e2767,54f405c3,f852b761,ef01c9c0) +,S(2e37935a,4dc465ed,ee8dc3ca,d4ede356,3c3720e8,57c986cb,b9c73b2e,ab6b5806,bd0873f1,5278f46d,802dc7f9,d7f81a4a,839cb690,10c6d522,c0e3945d,4bce346b) +,S(49b68e1,93745ad7,b60ddf92,70d71958,81cd8585,6e47b0bb,fbae94,f1647568,ca1d4bf0,13e43ef,53bcb2d0,5f4b85be,1dc82d31,f4a7795,755693c0,72819dc1) +,S(6df53d6c,c79c5a88,2c2b6f66,e9ede075,6c8cc6ba,3e60620c,b8130fcc,fa744564,48c3d6ed,3b2b7c59,2472f291,41a61495,4597f77c,afb576e1,729804d1,26431344) +,S(d99f8f06,9104e3b9,26163672,767145a2,2f9467c1,c8e32b8b,d28e170d,bf4865a1,ccfc46b0,55aa5d93,64e67c4e,2c06cb18,c2b43333,e4111479,fd1bfe50,52543d7f) +,S(77727c17,ebbf8338,ba807572,8558a059,e23af7fd,c68c342a,538ead93,e59930d1,a037dc7e,2cde1802,fe3bc65,75f50ca4,ede75194,133e7083,66de0338,40c629ea) +,S(1d40ead8,563a4ff7,c14c84cf,ad1339ac,36ae3789,99ec2663,77e0ca2f,6be22604,8497b443,b093917f,ee65a5ac,1c4dfb87,3a6b0c2d,a968d713,a711ec12,20d1face) +,S(2a39f41,adf5ab33,71a27c20,51840d37,e3226999,17a3d0ef,40590710,406bfae0,cdaf7a8,58e99fb8,23a36b04,8e844c18,8dd1a49e,c70488ed,155f2ac6,905c27c5) +,S(aaae4b1,d8b08cc4,8971cc92,fd974a21,66f5ea92,b6ce215e,28137088,19c684e0,9237995,c10a348a,84fd5cd5,5151e33,c63739d1,3a425bde,a34d78e9,e3cd8f0c) +,S(a5b0c042,591a53b6,334939d2,9ac2c9e2,11315a54,831ef440,965fdafc,e6477d40,ac3e7cfd,5d1f0248,b362b206,b3c7dd60,bc9904c8,d2a416d7,e117a5cc,4a62ca6) +,S(c1b7164,e6166a96,a8f643b4,7f094be4,3c16e3b5,3ebf5a1,2782e41f,27c63f0b,8469161a,4ffaf1ff,5b50ba81,1de3ac79,e34810bf,73ed1207,fcc0f01e,75663a98) +,S(98fd825,4b7963f0,4d8e0f2c,8eb26dd0,342e605d,8fdf28b4,57b98e14,adca63bc,e297a80d,213f6664,77f9dba6,5cbcb99d,2dc14325,be12098f,22061115,b1a192d6) +,S(f1f08649,71b6ed49,2d34127d,8c2e6f19,48c464cd,816acdc1,63eb3aad,594c3281,26ae2a0,f9e04fa9,13b8954d,85602e6f,506a0de5,2fdec31a,346338ab,f31f5c) +,S(ff470cd,c324d2ac,a63441ea,c0506fb5,b63af83a,61a23a91,17240e23,930dd197,e601f66b,b18e77e8,4607a772,a1efa73b,30734b4b,8fd31eba,5a5260d2,5627788f) +,S(90eabc6d,968aa196,b5808127,baabbaa8,ad0f82b9,332ed6dc,d04442df,bc6c63a6,d6df0f67,ffb23cd7,2dffc4be,44476b2b,2faed3e3,dcdc30f9,4c1fa4ee,bb5038f1) +,S(e217b126,acc507a1,b41e0826,b300363e,bc0a43b6,feaf3866,ecd4b8bb,cc7e11af,7eb28def,83db33d5,8b8eb733,2b27a386,921e3a5f,b0321ecd,a8d1fc6e,49e98f30) +,S(2a196fd5,82b85d5e,1772bc21,84d8aad2,b5d008ee,c795628d,20de68a9,fce1d184,994b4657,ee9ee3d4,fdf8dc8c,cad2ff1f,68526c67,89d82230,c3399f6,62201303) +,S(bc9e3bc8,3a6eca7e,8a9897c8,1118f7be,ca770cbd,7e66c2e6,1321d026,7ade4342,9d7ef7e2,d544a561,ab899291,75f35d24,e2b07661,2f84b0a3,f346542d,714f3f4b) +,S(ff2813f3,842a9f84,fea9e367,6f12f209,7e76b8ed,e691ccdf,6f6512aa,b2f198b3,206e3bd6,66d0c161,ac6de438,809f485,b8b6682a,f402bf76,18a484a2,c3fe1949) +,S(6e7599df,2d38d63e,be142321,769d7ca,34a50bbe,4e0adbaf,6c7479b8,d1af05f7,233dcf1d,4b0e4d88,4a9ed56e,b6b4946b,25614345,ecd182cd,5556faa5,e3654c8d) +,S(1edd9cd5,6c82eb28,14d844d1,a9e5c167,8397662e,b576f9f9,ba250719,33666146,a00f4a85,b2ee83e,949b5cb0,4d16820e,39d48ddc,95dd965f,e24251be,3df43f4c) +,S(2723de06,1f794cd7,76a4a090,738a81ea,818a2f73,92d7ab07,18d79fb6,407324af,35c7a9be,f9810c50,3c53429e,344ab888,38daad72,77cd0e78,3db1c1fe,c6bbf41f) +,S(4c4fb244,4cb54def,6d9659ee,b43c13c2,3874ec2b,a7c6b53a,f469ca26,ab9a213d,bbd2eafe,56447a9f,feb9ad15,349b338f,d4a1aed8,5a356472,82751e5,5b8efa3d) +,S(736359f7,347995a8,8e306977,1fb3fbcd,12847ed2,8e4e612f,25095720,667593e3,23bb37ed,4bce0512,35a215ca,6b8f9868,e303fda4,80d655f9,72c95bf9,12bd3741) +,S(15cb9594,ee936bd1,4b981394,60879bee,6f33b0f7,c0ccb293,825794d9,85f595be,aaad772a,2ec81ab6,13775e9,edb274ef,e2e133e6,5e58949a,c7f25429,fb1bb152) +,S(3b5489ab,97e5cf1e,84a90eb8,20b8772a,df574777,a61f0a9b,41e6c567,6be78fa4,145d13c8,e9674a17,ccecad63,f113d64a,d59a1eb,bbb10cf9,e7134cf6,562219be) +,S(78d1b99a,a6f9d385,b09bec7b,b59ce26b,23323e4c,3a259c56,68417597,a29dd2f5,1c8d11f8,e883b210,cf54369c,e9f6a280,a6b890ce,15b4a0ef,3cd8837b,7e16a122) +,S(385e4e8c,5ceffbbd,3a813e3f,938912e,d2fd2d18,2be81210,70cd15fb,39661e85,f4a1c414,9f5cfbc5,213ceb21,c1cc08ca,c9b168e2,58cdec70,36e2dacb,ab68069c) +,S(310f8c70,d8e46c6e,48930df3,c53e9292,a7c87230,292d6b1f,c28d9711,951aec6a,6fe319d3,c92c07b2,56715154,d5d7046f,59d92d5f,6dcedefd,b0386f5c,3417146f) +,S(764f3c30,23d1d50a,e170b80d,48d58923,c1f91a96,42210912,94066585,d7c70bbb,bd92fb1a,becdb4a0,ed941146,878c99cf,c3ee9eb8,c8f2b8e4,b547cb40,e3dca724) +,S(3d5d23ba,b357a37f,1bd3c86f,84010b8a,b37a8075,3c47b1ab,36f7ef72,a3e68126,2bbd1841,bdcf0265,838893c5,f5f9c0dd,7ccbb461,93068e0,8211595d,6b34255b) +,S(a70431ad,cdfc7b8b,febd2aff,d6759e94,6d4ddd7d,50f50dc0,87e256b8,2a7f8a1e,3ca4362b,9362b2ea,c33d77e8,befeccb8,23163921,86ff5f20,384247f5,9147f593) +,S(2a388212,2c1b2ecf,3c800432,7c5dd403,2263e9da,245dc697,bf7d63e6,300e8a7d,ac96d188,53b87bf0,3dc5f2fa,fa9b73a9,a339c0d9,a7245175,fd72c822,12f6ff78) +,S(e99c59a4,ae3022e,b50bc545,f57e3013,56b49bff,33069a9a,b4d17c0a,424b5451,29b24b79,fe55fab7,6c3737b5,61505916,b4fe1a98,20837349,baf445d6,2e9bada0) +,S(a0a42ed1,bd5ac5ed,f63f1a3c,3c3fe2d3,c0be26d6,b0da384b,f19c034e,83306d4,c39ff3d2,d4442374,7a293e28,8c320ee8,8aad0879,672679e4,e5bcf611,5ca0bbc3) +,S(b952e5d6,9ba9f063,f1d1670e,1419730f,5cc17e87,b6f0b01,c0b86ebb,c09e0053,c1e8099f,a230b8da,6e71c9b5,bbf250ae,273a4f9a,f53cd0ca,fe8f0c7,2dc46ae0) +,S(3aee273a,130f5f4e,463892b4,512621c9,be83c18c,655d5a2e,620f83fe,95a4e904,edf475c6,921fb6dc,f2c3c6a0,b93f9470,9237b035,9e8c9131,eb7eeb0f,bf0af7e7) +,S(96ddcdc,dc65af06,acb10d91,b87827fc,aa2f9e65,d28d0449,65ce255d,ba66ceac,2e6d0368,17fd4024,c830d4fe,310bbc23,9e2bf37e,60203584,215f852e,d100ab39) +,S(fd50f406,c757ec9d,b10e111c,32941fa1,e0d07ae7,9e3584d5,af45fae4,d30334a3,71b77494,d49c068f,c7db1d36,4f8db288,ed9ccb0e,c6137348,324f4bcf,d53fde6f) +,S(6f2d8268,11954523,614915c,9568ab9b,bd061112,bca3ba77,d3c64f91,6ba097d1,abe41199,849ca7c4,d317fe72,2a5647a2,97261d68,d025f5af,e880ef78,34787a87) +,S(d88c0db7,6dffb62a,27683d2c,e832a312,9c5099db,e2623c9d,3f064247,21cc1400,5134f15a,df6d7e92,5d81726d,f08732b6,ba5aa289,431bb4ea,542e6352,8dcec51f) +,S(a8de9ae4,ddde3f28,ead01363,2202fe4c,b6c0fd4a,a71d5562,d95f557e,747105fe,179e946b,5a71b614,90bc39a5,17dc752a,53682043,6efa907e,383e3da,a3be8803) +,S(626c6827,f7dc3d40,9daa4811,80e65b0d,799c94ef,e48077ae,6eb250aa,8fcd45ac,3d659db,87cf7b28,32e4a2db,8db88e5e,b30b7ea1,7819c00,fcec5d63,31bf2f32) +,S(28a3a2c,f00efa47,db4b2ef6,9f56cf02,1666ebef,b5220495,5b5484f4,2ca77d02,8dd00ed,fc9870ed,99ce90fb,927086c7,fc16837,9794db01,f7799b16,8393c82b) +,S(df0b029f,27c46405,245d0dc2,f178a48e,c3b67275,7fb92bd5,dbb29370,c1545786,f133ed05,c7e159a8,810a5ad4,e1019f15,757b474b,fea1679c,6ccd18a4,2a1099a) +,S(dc6f57af,9c1e0be5,2d2162a4,e8a6b63a,c549783,4c7c2c8b,421bbc5f,dc1a49ef,6f586aaf,e610fe5c,962ee20d,9b389bab,66fca44a,1c19379e,9e97e104,10f1a0c4) +,S(db796ea2,e0d2c690,19adcc0f,a81c1d93,8162472e,a0e3eac4,bf13b398,b255cd15,2e60c6a7,32e1fb44,641e0766,2191e28e,79375420,43bdb3e2,9474313c,7d05ac88) +,S(569b669e,72ea98fd,a5ba3efc,e74f88ce,881fe269,30b063ca,59fe369,35633a2d,badd8eaf,2551f872,5db3f740,6eb5e376,220b6a6f,ff4f8ca2,f76b7755,f8ca0c8c) +,S(36132420,1f9a33bb,d4b6b6f0,e2d175c6,ec795111,85fd2451,421ac333,78468ae4,f47b56ce,f7bc7366,6eeba135,14756486,62a58e17,d955dee,2821618f,fb3c4314) +,S(cdeb2037,1e4d2014,918fa243,182db0ff,855a0783,c92fd5b1,b604ed33,494a469c,7d3c7718,6829381d,2fd0098b,c84ee506,970a7ed5,5518b393,a83c6f79,d8dfa7d8) +,S(6035cfa9,d750c5ec,d3b721,ade88fff,ff6c4d74,f8db7755,c8717cfc,171598ef,fe1798da,160b2436,412dcde6,5482d202,9bb129d7,d58c9cb7,49f9fdb6,7dd675a) +,S(b1f52e97,e49998e4,e0e75b0c,47178f4,bb250b5d,97d92ac1,8dc9e41a,3b79c0f7,d83f3d65,4e4cfd8c,5f24370c,a2651c5f,de484cf8,1024f33d,8087a50a,d3df795f) +,S(aa799b53,4c73da0,9f011395,dd5f709b,f1a5e056,42536477,d7862b21,6df1b641,3a327047,b5e95b64,593f6887,9f38aa86,dd592007,cbbe7338,a003d2d3,33248646) +,S(da4a1964,45bdf4fc,479e56b6,6d339a45,262d629b,dd8c63c1,8d35e9bb,a445aa03,7b3a5eda,25cc63a4,66cff29,634d5eca,353376e7,26c2c6d5,63f3f92c,b69cb70d) +,S(c300b4ad,c2346d0d,433eba80,f0eef071,7e620d46,a07b384c,231e733f,a1b8d656,32083bb9,48d27ac7,f36aa439,a100b95a,f73448da,454de356,6f4a8771,e3cdba42) +,S(c559a528,67937244,d639bf7b,90df2b2,ed64a907,e20cebe7,6a358b2b,94359f04,9fcac1aa,5c08c983,20d671b5,63f4434a,806d78da,15964474,d2470cd,49bf5977) +,S(39b10147,a46dbf4,f074bca9,a83c10b1,b0911ceb,d3e795fa,9b96333b,dfe83540,ad35dcc8,c3b22743,4daaa313,cd6334e0,168da417,d162855e,64294196,2d308278) +,S(39c9cab7,d2dec601,7f840597,19994c9,4129ab2e,a2779d6b,34774a04,2f7d6d42,c73ebd6b,835a8a13,354cdd45,37ddfb3e,72ca72b4,c8049362,3afdce9e,43781845) +,S(1a625998,8a30b462,adec6097,2e218ec3,f8f81c4d,44131466,fc7b5eee,eec679ed,739beabb,1a97c9b,bf6776e6,2e213bd7,3651a39d,ba042037,bf5f8cdd,334114ab) +,S(396ed910,cd35c308,d412761e,bf283a98,85f33ecc,3ef643bf,3f422dfa,ea4c4308,721cdda6,a08a614a,4dc48cf8,442a46b1,3945e158,83671b7f,556d19e1,144dfe57) +,S(a50e06e8,a2e8ccfd,94aee96a,b0bd831c,83e15340,25e3abec,af7b7af3,9b299a47,593205b2,59a18063,fe5a4575,e8e085e1,4521fc1a,3ab5e14f,3fcd64fe,2bbeba52) +,S(4a9f8023,17b0d1c0,e62c8bcf,7393fa34,dbe15cd6,46e8f4a3,dc3f26b7,11c3e1de,40eff6d,915fff,cdb30c24,434e8928,239867c3,962655ac,2894bea9,f7c6bb71) +,S(8ce5e20d,9decb7e6,10b18562,e2ffbb88,7f323262,55ed9f05,5d2da2fc,8d608b73,eb69b6c,f363e164,e92371,b592727a,63f024b2,aa7011b5,4f1f698e,1ac720de) +,S(f32695d7,9b53e9e5,1f2525e2,8a5540ed,84143ed6,3700be0a,36726f9b,b483f24b,e8d36488,eea2055f,6592ca1f,6fe23493,1d81bd16,1c61523e,f1ee1907,c08471c8) +,S(3826fd86,3bf6592e,5b51ad14,6e02089,d9274881,25d25959,4856de1d,d6c34d07,ea86f1e6,a29035c7,43e82058,a7ff9f82,20da001,a8901e97,26583b1c,ffe4cc83) +,S(7b1afcd3,2e32b0f5,1ba09868,4ec72762,ae8611a8,98e87ddd,dc6410a,40ccd551,deba6ef7,79e10931,8036ee3,9bb6d0a8,a3ce0eb0,bc5620ef,c70828d3,d2e37884) +,S(3eb1fdfe,d2c27587,540d39b1,b66a36d1,8dedddcc,7f7f7b63,348460c1,35a91bd4,b8aeaaca,536ae794,619506cc,a812a67a,642c5345,8cfcf7b9,eb898f96,d26b36cb) +,S(9d61dac8,aae9fc5f,532290cb,683eea2e,b71b4d9e,901b7c45,c214beb5,9b56da8f,2e7caca4,2ea1b22e,7024fc3e,e267ce99,280a8f1e,78a2a271,7938762b,3a446036) +,S(2db372dc,3167faa8,e8e1e37a,85ed5546,e91a43ef,fddba39b,e38d0eae,3e11c7d8,16ab6f61,bc1abd6a,16e79697,fb59f0e8,84f00534,b7196380,9b06e10b,59707ffe) +,S(98f7cef9,f7a2b538,538e83cc,9ad3132a,5b03dd67,f7fc4030,2ff023d2,8805dc80,3b40f823,2813e6c6,bd56df89,1e96a175,468bedd3,f9518dd8,d658105f,aeb98943) +,S(eeab2e6c,c8ab0d24,d5df5852,8a89db42,c48f0861,4d488c7a,363cd195,edb62548,607c41ed,65d3328d,72be2503,f5edf14,523a7f74,402822cc,1709927,c82649da) +,S(955feeff,b2161c70,3469a9d6,c5fb31b7,b7cb5ed1,ada6b537,6d935705,b3db942a,a9195a48,a561c342,779c984,6a710059,283fcd0a,682cb5a3,fdf48ee4,15c0864b) +,S(219a4d2d,70d2ee9e,d3c8f541,1cdac36f,4db23bdd,a981a5c9,d44ce5ac,dccd85a7,67441968,43008ec1,71284aef,2c64f7dd,3dbfdda9,5c6c8e4,70a564f5,c4ef53b4) +,S(4976290d,7794b161,2e2f5cbd,282c1036,d594571,722e28a5,ed542972,f91ddb23,4cfd95f1,60fc5655,2fc8354b,446dc510,23571c24,56f57aec,79004616,ce17ebc4) +,S(472d53e0,268ead1d,bbbb99ed,599f5676,1866e0b3,c14d4a4b,5c44d722,b072b1c1,e9b9c009,6115d4d4,a8ed42e3,1d967b89,e4dfe82b,ec642db8,e31693ec,c2831232) +,S(2a6f5b7e,7a4db95c,af875d61,75a6e1b0,3f3462fb,c0dd5d50,da3327b4,70ab18ef,91b247a3,92aadc19,7d9f5b78,f0b013ce,c9f3724e,a2f37347,9ade7e03,8659d506) +,S(dc1815a3,bf48d81b,b5e5e654,fe0c8c3c,7431a62b,9d1065ba,17df9c45,23146c19,fe20729a,311550f0,e47e2af7,4747effa,d837c5f7,b08c8f36,d0fbdf2f,d594be8f) +,S(8e7953ec,ad8feeb8,97a95db4,f03ffb98,a8b47ecf,3e68bc4f,1df0b6e6,98397776,5dadf2ef,81b21cc4,26c40a39,51f31462,12f7c6fc,dabb5157,893b1637,c141ac5d) +,S(a4d91e6b,49d5724b,9e899fe1,c6686c89,faf96a05,6e666a74,72ee44cc,119b41a5,abd68615,e296498,f5abb820,cbdcfc26,fef10b2a,ba72e474,14ae9de1,960a4893) +,S(b97081a4,f3e426b9,d3a66dd6,8e0e442,754c4922,acae141d,d0294843,6b00eee9,558f6c83,99214bb4,baa9cb64,11550b12,2c8c2f77,8e28a4f1,ea61ed6c,b8f153da) +,S(6882b6ed,82279bce,70a73c6e,f6412c54,b873a5a6,b634a25e,a8c34210,fb825848,c6fdeee9,c8233e39,2ea79c61,6689e8a3,1e3a3b09,21f2b5ae,d6b9e14b,9ff21b3b) +,S(9c542731,1c715709,cabbf11f,a4fdeb3d,1a0dba80,ad50d1a4,62c7ee1a,44717fe8,aa041b10,78163458,c446bd40,ca77f760,ef4b6471,c4f2058d,7ea42975,d1f2b045) +,S(73a14da6,776b5c12,e838779d,e3be58de,4a5ed917,3b195d9,3577330c,780cd32c,c4068ffd,e98ec4d5,a7467bb7,e8bf2c89,ceb58574,cccb3a78,b0ce4a70,7ad2c49c) +,S(6488a286,27d26c4d,bade9d26,1e6ddb7e,8748d835,d9def8eb,fdc6c576,b6af91b5,27f8b1f0,b0501191,8af0916a,945bb07f,3c7f0695,5ada697,b5c601bd,3d6d8ff3) +,S(96546e7a,5b544c98,db9ee2ef,47dcfbce,cca1d38e,1978f71b,d8c9d4d0,5151046c,d04fe32f,8fe9ecff,220f07d2,2095c982,3b10f772,b261189e,84160ca7,5f4309d) +,S(ba046f56,4598b143,a02cdb90,972022ed,e769986c,82d28066,761463ed,8cfecdf8,fc6e23ab,d42457c1,5407d37c,d3d9daa,3e57bc0d,778dd68,53603232,3e27250f) +,S(39554751,e633ca7d,df6d82ed,86a8204,5e76557f,b13ca7df,310b80af,5ad0e4ec,a456ba84,f040f20e,977df5e9,5faa3f67,cdb2ba3c,2fb9bb4f,89486b02,a06d3b1c) +,S(c5f550e7,5fef9fd7,d96c924,11046c3d,ba56b8d7,e1b17c,d46a68a4,989c22aa,548582e0,3aeab617,556a987a,cee7d0fb,8d65ea42,dc8f2cc2,173c3636,27ac3fa9) +,S(2ccc1610,a48d8db3,9a80b2a0,ee063a43,26d4ba75,79b2727e,b999aacd,6e5fa050,de6dd7db,2114002c,8dcb17b,179e5843,fa205d69,4928eb70,a073f97f,f8348c84) +,S(93b07ce7,3e941c84,1e4089ff,2d8e6464,3ae59cf8,fe6e92c5,add89e10,f7084b3f,a6c0476,c5a7267e,54ec362d,3629a1ae,533efcfe,e18d3634,cb5a80e4,4018fa63) +,S(453c01f0,55c14679,5e3aeec8,26859b16,b0ec2707,61cbba3e,438c0566,5a91e7e9,f28eaec9,b9d3c8a2,2ef73843,6088425b,e14ac99,e52e73d9,8745bc49,a56766b2) +,S(3c6df1fd,ac078c28,a0a148fa,d15595b8,c1d09a4c,4a96794,6f8d6465,e80f12f1,4619a84d,4eaa134b,a06a6821,2e7ed292,d443db5c,150b54f,6dfcf267,82a5b58d) +,S(1b7f6968,39959785,30542989,59020dbf,f12054f9,2705efd6,dcc583,11b98630,279dc63e,e3e8fa8c,fbd731c9,b88ec6f0,67ee9e15,d0c14a37,372d9c20,c645c25) +,S(e1b7b953,9d49d0b9,9b90a642,74d2276c,6256f2f6,9cd03006,97ad842f,bffccc19,2b23b96f,51dc6569,8504628b,19e81534,f2acfedb,27f93316,fd0dd8d0,d5f9500f) +,S(404cf0c5,6fbf4233,4bd5f79b,ba97464f,9ce5525f,a56212bf,4bc817c8,af54f911,b5920609,88300588,5c61a6e0,75e3657a,23c04b5,79897c0f,2e22ca64,1f1ef662) +,S(43f1d986,da626bd8,efee817f,a09a3440,e7819aec,17ea971f,43fe2ec9,caae0c1,c5fa5ace,ce891aa,d2811f51,8175179f,3e93f438,2b3ab583,e51a200b,2a74f9ad) +,S(a18845c6,b3209951,16a183b8,1b762112,7bbcaae8,b67ee8fc,d23ecaf6,c5b9c1f,980ed5d9,d7e07e6b,2cfc5350,e818671b,8f54e7f1,5cebbb02,dfcc2951,bbef1f44) +,S(4d9c7eb,af99824,605cc17b,e03c929c,254c38ad,c026d5aa,2a304920,e7ac01ed,c64c5b35,bb0dce53,2273cf00,f3360f74,97065bb9,9fa9b1c9,70d41c19,53e781d3) +,S(e18d22f2,fbc3db09,bcd31783,3e8aa605,55953ef7,4c64814,edaeadc8,97e7c25d,cc258a81,71152072,24f7989d,fcaa8700,f15b8b2,85700b59,53ef2a22,efc7e07e) +,S(160575f9,f220904f,8d2ec9a6,c1417e8,35083aa7,9bc37d5a,3c8bdbe5,2a47879d,1e56b4a6,127e978d,41191c60,ad439fed,2c38704b,309d34ce,d655f93,5279a5e5) +,S(3b651bc7,57b1d626,4d6b7ebd,d3c5355b,4c3c9f6a,a1437e53,f9aa0372,5192d514,977a8774,95990312,ff1d8ec,5dc8a49e,5feb285a,8a1e2e4,19e56186,80231c3f) +,S(9085bdef,56facc02,76025015,498ab286,a9660e96,1fd6bb0c,d9579a8f,16ba532a,fd05d108,a557559c,5e7f791d,90e80e7b,68364c16,8f6b93b8,c55510f1,7ae9fe89) +,S(4224306d,f64a3862,fd33aab8,c1f0ace8,67cf1b25,76e1cc21,fef45448,e40569ec,8740b667,5279bc1d,ce887c2d,c59e42e4,63e72395,ff967249,8bd13d58,f60661bc) +,S(b7376697,4a512e31,a6f806b3,5bc55ee6,e0e2b2c0,ff5a0918,2f83ca35,dc22935c,d350c820,2676fade,ee4152a2,48fd5cbd,890b3e03,9d688462,51c2a082,85420103) +,S(73ba4f8e,d3b5d4d0,a7c505ab,1c1a7486,bb82e068,cba81574,557424da,4d0eb97a,93af3914,552dc360,549b4a2d,863d3f9,3a58ba9b,72541215,adca4bfe,26188271) +,S(285a014e,174724d9,8f0576c4,5694b052,ae93540,6bce1bef,524be03,6fd3d8ea,6fdad1d8,d2ce7757,e6ff5213,f91d4db7,9d406765,968ce8ca,b393e7c8,6a9af7dc) +,S(b0934dd7,27bfb54b,a2a5cea7,c6f8c0ab,84c2fd78,eca0d180,963869de,c28e768f,dcaf0d11,56029f31,4bebbb26,edb09913,484c94f7,d14d71bf,2bc709d8,f0b982c6) +,S(3b627add,8b69a9dc,b751c8bc,cef15d0a,ffcb49cf,357bb65e,c45c8c0f,5b681561,bda1980,9e380b7,2da13364,9d27cff7,693cd2bb,a77215e1,536296fc,dc46d19d) +,S(7e48fdec,1f2289df,a052e3f9,a4766daa,e4593876,5c8aa7c9,a62a369,52cb5ac2,e87af87a,ac116885,66e1e10c,5bedb49d,68449b8e,612939ac,61e384b9,bd8cb5f2) +,S(4031f08a,5de33bba,b6a2c267,feec2e40,d094d890,caa1008b,181ce43e,263ffd9d,cfdc4fd9,9737a5f0,9a789beb,91dfef45,a8f23be3,11b946b5,8a79b7f0,51b0be07) +,S(ba652b7c,61dddbb5,bf6e656f,4d441cc0,ec00a22c,7b900b1d,d5407ebf,931ed764,87fcb392,d1228156,a330b5d8,d3c67e00,1d207095,9a590088,a3b44d07,29556) +,S(fb936572,d1017653,ac7dd95d,2d8c30f3,62c967b9,ba0d3b1b,ffdc1ed0,6590e72d,adfa37af,db6b6a31,a779965,9958be2e,94038246,6b4a4587,b0879882,4836d8ed) +,S(294473cb,5e7c0852,f7c6fdb7,8861129d,b97ff328,19685148,99198870,b03bae7b,bd905536,f991867a,78a09f95,1bd5b4a0,78463e5a,6c767617,246eec38,7d90c86a) +,S(2fc0f44f,73a633fd,91737ced,1683b74c,7687dc8c,6d3a4c09,44a6c873,c5bc574e,29917cee,ffa063f9,4e949991,2ae373eb,ac572f50,9a451184,15e07354,1d22ad1f) +,S(811fb251,882c5a7e,f59d34f2,c8ed8a31,8da210dc,83bb8c40,b9ac0251,116d569e,74df6547,2cb55afa,4ee04ad3,f940de6a,d480e407,5c3cc00,ad291918,d8a0c55d) +,S(45a9e17c,c1d6cf09,1f451894,ad4e7e53,c47996c5,82fdc57b,a9e7e614,b7fc5d07,5169dc4f,2661f5,fb2d1920,89832b7,4e19196d,c37fdbbb,16d1caad,7b069be1) +,S(d577f7fc,45cda7ad,4743d96a,ab5c7bd4,abd06538,b78c0102,645d09ae,b5588e67,55172b71,7ea257df,ced1db61,88c78cea,765e2c2c,30bfd25e,52107128,303be07a) +,S(a6429a95,8098aa6e,39b71e08,d4b0cefe,4fb22d8b,777a59c0,650e11b1,9b06e44f,af494e62,5587055d,cac440f5,786240ab,36ab1825,f2c3a7dc,f6aa64b1,947dd2ed) +,S(f77c304,b89314b4,258b1c80,cf478ee8,50bca37a,63e20679,7396967,a39a743d,c487a176,29d914be,60845213,60f40f19,1c32f414,558e2c72,7e78637f,8dc1c7ee) +,S(41c6f2f6,15981247,71ff0a82,e1ededea,cd76ea2f,fb2f9f5d,ef766165,96d1c988,58a0f544,146c1a07,5ff9ed4f,f9b687c6,3642770e,45dbf1d3,407b52a9,5accb68) +,S(c8724ec8,c13d37af,9eaaacb,35765e3f,7ac2d2d7,1fdb5916,cdf66ed3,2eb968d0,70ecf721,42103e6d,e7d4bbf2,42bd9a6e,6ade66ed,a7862989,5ecd255e,44d81221) +,S(e2888c46,dd58e36,be2204a2,b75fab66,3b139e4a,e070c650,653ba9f3,ff1fbbf2,715910da,e1393b8a,b7d88879,720bd601,bc158498,9522108c,3312b353,2342509e) +,S(f1f4c384,d72d80b8,6b5999c9,aaa66f99,f56cf736,11ea9ec1,c14ac36f,66d834dd,b5543bc2,480142c8,ebb8527a,3c9aa786,2198388a,696b3c44,835e7375,24cc7e3f) +,S(487477f5,832fb7db,768d412,6edd7f5a,17aec3a6,3419de73,f61812b4,31940a5b,90322dde,4203fa98,bc44e3dc,32a6d56a,284f556,36db7c54,c5f78d5e,1b2608a7) +,S(a726963a,583167e2,4b8f957e,b3ee9f5,c55df02,9fe1229b,ff8af037,14ca75af,8fd7a984,d68929c0,81154d15,6b6541ff,4a636925,53a5a32d,99f6516d,c08f7449) +,S(d4c20db4,cf80eb1c,9d93a231,e699a68c,baa763c2,e2013033,8762ac5b,8b99e97c,ba1c77ba,2555a50c,84aa2071,39190a35,f5abc50e,589287a,426c6f9f,6ceca01f) +,S(7cf9c53,89ae702b,bedb5a55,ad8d0f36,5159ba1d,ac56fafa,fa59efe2,3a748168,ece3b324,338c7bbc,a2cec347,c31348ef,489bee0a,6ea4296f,6ec38502,b72336b8) +,S(920108e3,c1ebd4af,3979f9c3,326806f,eec92833,b4dbaf49,6992541b,44b73e55,3e22b133,d8adc483,4f03f348,eba48e65,6cf8f478,524f5395,ba92e200,95f466fc) +,S(1566af8a,98c48762,9b361337,2ad32a53,fc760538,49566a8a,4feb69c4,26479e90,2848c566,4bd72be4,c797db98,62fe1c7b,da5d3ba,eb3f7926,daba8516,da997796) +,S(a4db5e71,2eb8ceb,c7d7a704,12b0a8b1,d2f6d9be,271ef044,c0f76abc,af61723c,663e16e0,75a73ddd,f604bc0a,27a9407b,272f5f2a,f2b9f6a5,6958c8ca,c42e8ca4) +,S(d0c9cf53,8bbdb8f9,625d110,6c79cf1b,33d90e77,60778c13,8493bca7,8d53e5fb,b6ecce0e,8b9fd407,cc0a2125,b8bd30c,9975ad88,7dc1bd9,68379063,8a1d9a60) +,S(765fba92,480f57bd,70596d67,bcf3a389,4a58d514,54e3a04c,e657ce78,ffd8391f,5cb1dbba,1035350e,5a3b552e,3f41ab4c,50879bbd,5f3ae3db,af6ec902,1e18302f) +,S(9f9da9e8,e846702b,4aaa7b9b,68b652f8,9bd3f88e,5af4a503,2c51ee6f,8bfb4a5e,5dbd499d,7ecf17b0,eb17320c,a0688aca,1d8da08d,d2c0684d,edfa2d7f,5696a0f6) +,S(af86c83b,db95894b,72fb1a16,61aef5f0,ad949c9c,b465a5bf,b1192022,13fdd3f4,ec06827d,55410119,603d2b25,cc41c26f,4a7bb9,b1b88e55,123f3c12,d799e117) +,S(fbb48993,2fccbc8d,772b3fc,c80be33b,64c8e3b2,2ccbb09c,d94fa350,fd587e77,f9cdd24,279333da,b3451abd,634075a6,58598ad4,257bbe04,81111b6c,d8c0b858) +,S(40ecb1a3,ad97c2af,62b15eca,e2adc9c0,621f36f8,90a9269b,ae6edc1e,7ed60684,ff9ec194,fa3a617d,920e3e2b,32301fb9,9a41f4b3,ed9845f2,88daa005,3558b32e) +,S(31f892f1,c762b42,fcbd9014,bfe0238f,39873c30,c7d3b691,9736009c,18878f52,d9bd5005,f31f7345,53131066,ef6b92c1,5cd610b8,f7d4fff7,be536734,95718c95) +,S(ba122529,e9f6051e,2d94d150,c5d7739f,921f8193,8cab68f3,1c696fc8,24886c5c,c33c071f,7e9bd539,1b0577d3,37ac9c20,7c02859c,c396bc20,d9c7249a,856b1ed1) +,S(35316412,9a26d311,c993ecbc,5b9a0263,ef45d993,d58158c5,30c215f,2924cf03,86a620d9,521623bb,9ce3e2d9,c5b6385b,f92ef06f,91834e3f,6a9c6d35,7a3a9742) +,S(3024770b,e4134aa6,35ece92c,a4ec7f9c,4a4aa7ac,7851b3eb,f9718a21,52c8e462,1fcfafbd,72147afe,16dc1579,ce7384e4,ab3f8faa,f818d225,bbceb050,ffc8c8ee) +,S(f5ba313d,a40ee86c,5b6dbf16,9941d8e2,533c1ba6,4dd0871a,672d01c8,6bda6564,10a910d,b9697907,c96e95ec,15557649,8f965282,437f58c7,2944bbad,b800647d) +,S(685e17e2,972ccd05,34f7f426,b18c9518,e485a23e,132c18eb,b33b59c5,7264e2f1,96545b38,be84aac1,a77a3f47,51156daf,470fd42d,dea0fa0c,b930144e,b9f291c6) +,S(e01285fd,facc9822,a59e1bca,7e91c07d,fdd481dc,61d268e0,504f65d1,9bf119eb,ae82153a,2479daba,ef83615b,a7202b99,40bf5b5e,41c65063,f77d6e5,9dc39909) +,S(c61e4586,327710ec,784d6720,93201e4,93798a93,7635f220,b5421cb0,55839601,e461fbf5,aa5b64e7,a1e3e016,3ba555ca,5d42fcf1,7433c26d,cdeb8cb2,746c04ea) +,S(1c427acb,4e5890b6,e24d8ca2,513b61d9,3106fc34,90029af3,be87d65f,1fd192d4,1d96e025,1518528b,9bb04fa6,ec3430a1,84935ad5,ee8ae3e9,c9cec0c4,36cf29d0) +,S(5e577bfd,6d51897b,4b6ddb3b,a7d470b8,5a932619,b5982f54,431df6f1,f12fd8e7,c1a17292,9734c19d,3a836e90,8a5a7fd0,123cb044,c7ad1ff9,203d4d79,211c6eb4) +,S(cc78b333,1f968a40,bafaefc8,dfbcadf2,adc6ae76,6d3ea8a6,8173b40a,28237b30,5b7691b2,a5bc068,ff1ef04b,41238cb4,dfc2ce7c,9436f8aa,14eb0a40,45857d42) +,S(3855c437,487b44f2,9e5dc288,faf3ecea,c445372a,95adc16a,b1830a4,ec919fb6,df2e1e9a,48cbfa28,54fbcd5b,308bdbd5,ed1949f5,e1a39519,11c287c8,289359d2) +,S(c05233b4,a83356f,c5ffcf6b,97db3d6c,dc62cb21,b7de7c92,8f158466,b9d16b19,b1bda39,ce78847,3fa0eac6,51e8de54,956616f5,16233275,25ee3bf7,9e54f500) +,S(6c064d3c,f34226a7,d9a00024,5901f355,b736c1e,6561810b,455e7dec,99dfffb,160d9442,d25ec1a1,f80f8fd2,a1c5c42e,aa544477,28d242e9,925824cd,609eb9a7) +,S(9658eb89,70bb1aa5,1b61a93a,de6a7d,b3e20772,4789d009,bf37ba9d,8b714cf2,cd4ba4af,f7da8f8b,7821a903,f40d89e0,96be8949,997d5ff7,a58301ea,92c51cc2) +,S(6e023910,a5546f70,91f2b0c4,c3f996f7,5cf1f969,a71c31b8,7a3e7ea6,4bb4f0c8,f6ed65d7,90ec734d,d9ed8cfc,7d8921b8,7faa9b36,651c3589,99b9addb,34c459c5) +,S(3a35ac98,e9700499,f903528e,330537f,9262901b,d60c7a14,1e68f899,54c7ff6e,913d9516,da631c30,5394ac0c,9eda3824,1f247ff8,a7644eb6,c4d38da1,972069ed) +,S(d089fa51,15dfaa45,a8b6def3,b1948be,2317c66f,249763db,7350e57,76af212,4e6ae973,f326fac4,77a5120c,f3ffa113,a18e5dac,4a190f6a,b12fdc83,18a6da9c) +,S(e733c52f,2aa62ab4,748ea0f2,33d9531c,5b9cd9d5,f790b6ab,45bb2c2,d8cf2ef,701155c9,3c677293,acb23ab2,8d7ff753,36ac4885,70c52d89,fb80ddf1,d582a291) +,S(4b6f7b7d,c006684f,e64aa6f2,42babf86,1eb4770b,b8195b9b,e8caf763,e7f14c7a,6c58b780,ac757b33,c1805d8,a53a04c9,7bfaea05,d8f21d5a,2b0645eb,2194e00d) +,S(1b520402,cd1fac0a,c4d7aeb,8c552e73,44ff51c2,3b4778b4,81126e5f,e267f79d,8ee0d00,56649304,a0c4ee94,39add4d8,30b252f1,93d93c1,9e8ec375,37db1a39) +,S(8936e6d5,d7f1ed85,fc2da4c6,38a885e6,3400cc3f,43d864f5,bf9af2be,b97139b1,29812a20,b4b932a3,770cdc8a,6fd32625,8879f217,a5bd7c47,78d2b041,829b402b) +,S(6808ae7f,4813554d,aa36c043,a55d9171,aebd396f,5ba1a1ee,c4f11045,c96b518f,6afcae6e,88728ddc,578e85fd,5f41575c,f581b983,7c749c22,31b993a5,9c425810) +,S(586c6694,44c73f66,1211bba7,601d8009,93e23293,55a9b10f,2367924a,35a2cd1c,74b0901f,f6eba3cb,408f5507,d37cb7c7,873537dd,ef0671c8,862012ac,fe5416c7) +,S(789c825d,deadf1e0,4c788453,e918541e,b183aa5,99ccc66b,7897be8,1ff89e11,8106aa6f,641bb13c,6be7480b,89f98a9b,e40cc357,ffe9903c,b8f78938,e46cb5ab) +,S(d7ab80bb,fd26faa6,620d0ddf,97f64bca,e520426e,e1d8e076,acd7cfbe,a9419797,26af9f72,a6d1b103,aef4a85f,5139d14e,6e50a58b,9f32eefb,c7184537,90c5a823) +,S(18f712d4,4daf1ab8,4612b311,b1ebc418,bddf0f33,ca02b315,4c256d2f,36f67f7f,c40b1950,f92fd4ce,edb3c3f4,34ff7bf8,6b06d8d3,215d3ee9,f2d9bda6,77d25bc) +,S(8873276d,9f6d188f,78e2a7cb,f998bcc6,fc399d32,21de85b3,eb9e6ea6,c7e5a06e,297e8137,8ee9b9e8,ee820a3a,7e566178,dac97743,c04b6b4e,54a7081,e7c9e1a6) +,S(101b8101,5bd217eb,c08f57cd,fdf431cc,30fadd66,4df79157,1452ca66,c688e0ad,fa6c1b2f,ad203831,185816d4,a8f8dc9,4c7542b4,6c94dab3,39b73718,5d179e6a) +,S(77b3c157,76c31460,11e520a8,cb2071fb,abe3b3ca,2984bb6c,d81d4c53,7f42dd57,8d0bceb1,dab601b7,1c084c9b,443ef5ac,40cce5d,14f0c244,92589905,fc4a645a) +,S(151f2d52,56ac60b6,ff7aca33,8ba66f12,fbe2c189,33c805d3,ecf6a6a0,fddaec7a,d2aacd77,10cd4bf9,917038d6,49e94235,c4833c88,9cd57ea6,74ece9f0,764f62d6) +,S(dd75cf27,f41e417b,46338dbe,24b46df8,9508811c,111bd1a2,29a3809,171d32c7,e328b855,a3389b80,4ab03c33,cc91d86c,ee22170c,d8fb53dd,46c32224,19b67be5) +,S(faa1feb,bdd1d9c4,9de366ab,3f661b1e,6a3f6b76,335b428a,494d7eee,791d7a83,df361d4f,8fce02ab,8c248ee5,61e46555,948bb29d,81a569c4,13b5713d,b825d572) +,S(3cc10dbe,5bc2bb31,fddee65b,66789594,a4cadadf,8c6a7545,671dafed,4d8f8be5,802d45ef,8c66ad6f,e692a3a,9d42c974,7101120a,ea42510d,bc08e657,7039c2df) +,S(9544e725,325dec1c,914dee7f,752802e1,856cc485,35e3a1e,af576bec,a7b93ba2,cec7dba6,81513c04,ebf39b03,717338cc,aaf137dd,e5087686,aad83115,deeeeb49) +,S(94a0fbdc,d5d06236,7b17ff8b,4dcdf6c1,54eec66e,2779deac,38be37c,9f83a964,f25f34fd,5ef06c81,b7223e16,9a42e2e3,fea74213,5a2a30e5,76f29ef4,cfefe82a) +,S(989e29b2,c3fc7e2f,695fbd4b,f217ba43,14f67c3b,9f77633,100e84b3,c6b579c7,608a6d28,cd00297,2b4f3e9,917daaf9,ed003a43,1c22771,17250efd,b621c888) +,S(c38c5fc4,4295a59d,3b0e979b,5934ac2,49b4bd5c,e94097f1,c81064bf,73494a5,16240bf6,d354b36a,648e471a,e0ebc167,1d1dbc71,7cbeeecb,7600462d,61d1e2fb) +,S(de9cf667,35c4046c,58b41d8c,5c658efa,7dc656b,7ad877e1,546c138f,fa7a63b,2fc2824f,ba9162e3,e2372927,5448010b,ecc19de7,d9b94cb7,57586de3,506639ac) +,S(24cfd37,e56708b5,79d84b3,88c33c9f,f1dd9e08,4675a3c4,c8c440c0,f6c06522,1cbcc8ea,9820157,b4b4d289,55ac8672,1aee676a,cdb7df00,7383ac79,c42af897) +,S(9d6e3108,6ad8b9b6,2f4414a9,5e091e9d,2b275d8f,62641ed7,26421639,e87cc121,b924700a,6792a67d,4dab59ad,5a743cf0,43c46ab4,de751bca,757979b6,ead3abe0) +,S(52a89ae,28b28395,739c21e5,38ed38df,74aea22d,d2765d38,673be080,8609354d,c183ed57,9b65830b,d37cccd2,76b2f61,469b06d5,987b5708,89c5b1e,d8334e51) +,S(2ffd3272,491d1807,243f5d31,d727caf5,cda3bf8c,2c172550,46bd3420,da27571d,812e8fbd,6f38b334,a31e48be,6deaef58,599934b5,d3419d52,131cc9a6,535b6ad5) +,S(5d60c609,4269a43a,35e51b66,db193b16,65df689c,270662f2,eba959c5,9c973fca,f591324f,d1afd619,2b31bb7e,3f40cd40,6d3b9285,969c448a,3aff1f48,850efadc) +,S(23e0c40a,bfe53353,f4426340,e1c1b560,4c86daf9,85784d0a,e6da6b4b,3d12ff75,e90844b5,fc86092a,91baf68,280ca144,f19d5a79,9bacf827,f9921511,28191d9d) +,S(945818ab,5d4a1c12,ca6f20d7,7f37da80,50e67d79,30bd2bb1,155885ce,7c6094f6,b5f2c1d0,e2f9ae6d,aa669c96,9ededb60,32ca8163,fafcbb6f,9a11cd56,4a695e03) +,S(d1f4db7d,2586bf6a,187a469c,a0cd7bcd,5043be5d,6206d24b,c41ecd8f,d8724c8c,64054f82,77c4774b,bd480ce9,b2929c66,b1525eab,1c6f365,a1ca5ace,12206839) +,S(4f5c4d4f,24586e9c,1a85f2d5,b42a3d11,158b4f2a,5cf75e18,60f7f4ec,ec14a18d,57576e71,6d547960,6953be2b,e7ffbec2,1e48bb9e,970fb350,986b4a31,b0efdbe5) +,S(c13b605b,dcb31443,d8a3cf5c,5e4f903d,3f8edfc5,1e9a118,c3840cb9,4998150a,8dce2eaf,99f1fbf5,2e62a8ea,948b01c0,6c368e49,f41922b5,2f603cb2,16cb8435) +,S(1937b32a,b66f254e,4964a5b5,a1ceeb5b,a3df2466,e2669753,39174cd0,2429cbb6,9712b0a0,6f1b075c,bbceabb0,53fffb1b,181e079,813e022b,b5701738,ef2e385) +,S(e4a5333f,2f1772f3,84ef386,c3be1f58,d757bbdb,7ad2c4d7,47e61b07,419ba2e4,e84f7da7,2ec2e4b9,389b717,8bc15642,132571cc,9bc14c7c,5af14a7a,cb6b6f56) +,S(2f8a38b0,a3f42a8c,5080a0cf,5cc1085d,d57a8341,ae154dcf,fc7fdb4b,5606cca6,8764c6a5,2c301db6,56408d9c,4eed6294,2fa2a72e,1b1264f1,134f38c6,8e4681c1) +,S(3d2bdc2,c51c2d77,b6c585b6,3ceab5fe,acd14599,b841870b,8735712a,81a55ff7,33f749ad,bbe263df,a99a808f,f0476e44,92246036,a3e8b5e9,496b8dcd,b6d3e9e0) +,S(fc87f808,d6764ce3,376b9acf,62bfa3e2,1ecec215,22dbdb3e,6e5f3cc1,efab7d3a,ce75eb03,c1f4f937,70815dd8,750a4ac1,c0343024,ce1bc581,717cb971,2835176a) +,S(7f81b85c,62dee11e,be8885dc,cc98485,32354952,1c7e6cb4,374270bf,5b1e68d5,b7adef7d,6a84db61,c15ba062,d96cf739,1750aa4a,ed5c97f3,ad70d2a7,6a9c4558) +,S(d618d43f,7afd3ae5,e8dd8f47,f62ef91e,33cc8f89,3c21688c,8268b903,e1fd5557,6180817b,c8ab9b0,82b21267,9900c7e4,42ce9e8d,fc8c3fb4,fc5bcaa6,e0cd34b8) +,S(ba5a4c4f,f2379b06,daff540f,c8383b9b,694430bc,df76c931,ccf94cb,896e4940,3a221d1a,b138e6f,4ed309b2,4f2e9333,25299de5,534a528d,b91075a8,fd07b1f2) +,S(c69189b6,bee3746,88359141,5b35bac3,80136395,c83098ab,cec29fa3,18cfdf56,a185dbc2,b862da3a,cdc232fa,7e3407b1,9795e61e,29b7a79c,5828bd49,d739268c) +,S(51f67d44,32fb401,ab863423,b99d403a,70dffd86,87e5ad71,bcd3732c,1cefae12,88b17485,a2c404a3,2bcae68a,3cbf2166,403e23f,8a64df5c,a8eb2d94,61e10e59) +,S(cdacfe09,e5585f8d,4346fb69,a94b8b65,6001e117,ed3cca36,fa8bee6d,eb7c4bd5,ddf1bc5a,993131d0,15812176,206699d7,af5fc403,59455ece,fdb84492,6e028542) +,S(8129e771,e1fce476,9c701d70,cce90888,481eaaa1,d1661be3,19f33c93,8bf0e769,3eb5713d,a864bc56,39ed8b6f,974966af,8a4db189,b5446d70,d40a816,f045c6e2) +,S(b97062ef,6d415bc0,f302fc0f,8aa730d4,f39c14aa,f82889ad,a68132bf,5abce3ab,8ad70688,cd76c93c,fd8dfdd3,8522247c,6644c9e5,51116829,490f313,d53db3a6) +,S(19c3c98b,4e811b5f,ea5d6af8,c4e86be6,50de67ec,5154bca4,22a6a14f,4f0bd913,bc523f96,48bdc993,30e1b5c7,385097cb,c18b9d5e,924767bd,d5d746fa,a190a109) +,S(b9ef34c7,3616ee74,b1ebe43f,889118e2,ad7697b,efe63559,67a9b3c2,b5b42b9c,12f1cddd,d55b1ac1,b89be271,5e623952,e8dc05aa,3570e254,3b70ea68,5b661bea) +,S(7718e34f,58e2cdb5,80f9c39a,96d84dc7,59dd2a3e,bdebaca8,6e8edb97,f503c34a,a6d105fb,dc0841b8,12dcd8f9,6c4bd17d,cf5e3728,8e0e3093,13567b10,3e96df7) +,S(dab3884b,8e6de737,63bba89b,8d35a369,e259c1b1,8afb6ed6,21fcc871,c77e8dba,f44b6f29,c59a2d42,2babd4b5,edb4a009,c9316e09,2aef953e,e503a278,14a11577) +,S(cb3d0e10,1139782d,e5e6a897,8b5be6df,a6736751,e847ca18,76aedab1,e67f4366,27fe888d,d227943e,67969b33,be48f1d9,572aff67,69c150cf,189f9709,bd57d3ea) +,S(eb1b1ff8,55619d41,8d193db,bf62b4b7,656ea564,6ea2e79f,cca7fb3b,e8c3c6a0,c27fa0c7,5b73d5c1,d7113741,40384565,d36ae93a,49b327a5,cedd03c9,62282ea4) +,S(5d5079e6,bc40f11,f75a1117,3ab6bdc,bee8f9f3,d2e57aeb,58709786,1c39c5dd,14ae112b,a40db9d5,dd65829b,4be7bdf9,4d8435de,1872bab,80581221,446e46d0) +,S(1060ef7,6beb6af0,6d28acd2,6b214bb1,b708098d,e0300502,384fcc0a,a1a7b38e,ce40f39f,f6c6c642,9585464d,aa2183d7,34252c05,5207e2e2,75d0ec48,c3bdf9a3) +,S(9651c463,c001f731,8947c271,ac274529,e7bcc894,70d63e1a,fd723873,aa170695,4e362e7f,e8ff06da,73d6d17f,e8b63c99,3b16ba7a,5a9b154d,21837fb0,e654eaf7) +,S(5c422b76,592821b4,2f6822cd,cb428b19,895cda4c,d224400e,e0928f27,1f363dcc,2fdb4f4f,9e4c77ca,3448258f,f6c07f5,4cb6b4d8,15281484,44e5fcf6,492b9400) +,S(db147d2b,5d98250d,73a3ce51,9452cc4a,ab3868a6,cd4f43d2,b7224d93,a9faba2c,73254380,ad3c6acd,fa343227,a7299684,9fdebffe,64c4925,8a391a7a,50ed0de) +,S(9a6763a0,f97abfd1,65223767,8881e899,e1beca26,ed84d384,a41d16cb,e5454b4c,bb51407d,b6aa5817,32f1a3d5,51082908,e7952f75,92c8bcb2,737a01d3,3890306a) +,S(36fe7933,e9108af4,f4e5c889,ef94f584,7b45a9e,8c520000,7db6a00,e5daea8,d024a5ba,ecdd5a21,c8c3a0f4,a71e15c3,1943c7bb,66b459e2,7fc85bb4,25227ee5) +,S(40dae663,f04f7e68,ce782fb,87529681,44c749ea,5b7386af,c445568a,3bc784e7,49a463fd,ac6bcdd0,2458c85,423cf252,cea2ab47,44b16bb9,47811176,5755050b) +,S(ba1616d,c8fff3b0,8e8c6d10,b15afd9d,da55faba,79fa8a75,42c5c9cb,adc5b8d1,ef096c42,a6233c66,1965a3ac,eca095b2,7710455e,5f0e1019,7641ab25,b0a786ff) +,S(30486f67,23a54952,4d68c948,dbc71273,d69b4a05,5fb9e7d,a702d027,619c4a66,38ca4d4d,279ec9c0,85ea6369,5470a4b9,fd6acc6d,9a049ab6,5743ecba,c2444c76) +,S(1b83ee94,95ead1d5,80f67174,dec2a026,d6accd93,9a89d970,90f25bc8,d9e6932a,196d448,fb5e4851,e1b73d6d,a2e7d0eb,3d263034,9c2b3e0e,34584bc1,d6e20196) +,S(4ea9dc2e,edfa5a11,2fa76671,5c1579d9,328b6132,14ee64f,2e30f10c,b7517396,7414efc9,6ef83e29,5883f0b1,4019b41c,d4a192d9,d06cac9c,21e8f0f5,b06e50c2) +,S(4166c19d,bee9ad08,83b217aa,3b657436,87677792,d5cb9b31,1a097fcd,2eb033da,62c5065c,5fae6aa6,932b4d29,ab375ac6,b80e113f,d38d81f8,abc236eb,7eed541c) +,S(b17567eb,b112f54a,69c511a8,7d3d2f96,bbbc6686,af8e3f31,a2bbe0a,85a74899,f6676341,3788be54,ae3fc693,4b8936df,a6936721,c671cbb1,bdbfd72d,4c9f52c2) +,S(cd2b6515,2ab97f34,89d81fd,f3513131,a6df0685,5022102,12c2b8a9,be8095a5,cfe7952f,9ca41935,15ee40c7,2d44d023,22afff84,b8700bb4,5f492e31,e78f6a53) +,S(375603c4,9f33140a,3241a72,907ac0c7,2086c979,3aeaf74a,44732097,3618229f,7bb740f6,6322a773,e11ddb46,300975db,de08ba13,84480699,6681637b,eb85e837) +,S(102067d4,390a3dd9,6d83c176,f341dde9,7e10955d,2e001632,978f202e,efbb7432,7cf6cfd5,4d28ccc3,a7019f11,b6ba9df6,1d8b7eef,7e70722d,afa81a2f,839ba83e) +,S(47617e73,e3fbc53b,a703042c,f8b48fad,374ef42f,e8c2dd54,4fb7625c,de63081d,1fa4f423,c92a95b,b2c40f07,f43caaff,50cbae67,87c3e2a0,e4782f39,c1d439e8) +,S(2c431baf,57f75062,9f57aac0,8e28a060,46b814bd,318d74ca,82e1174e,f880f84,ddb9e7bc,68574b32,c1004108,9853f41e,62755a52,ac58badb,b8ee58c6,f209de50) +,S(91963643,8143b6e4,19b86b1f,79b708ab,3f4df44b,d774b41,338570dd,8343d599,9034ee17,7171a0d2,9fb91d68,26b87bbc,21be334,90f44049,69622a8b,76312f0d) +,S(bf28c201,af656c7b,838d42db,95683b06,2871859,2b016ddd,a4a4f7f7,c4b7754e,bbd4f04,dda510d2,a8a66c2f,46ab0681,ce6ffb5a,ac320e20,c50b6df3,a345d109) +,S(fcac7386,21825f4,4e1d531b,f598e40b,1aa4262c,a5aeb5a1,babb4f35,9518b137,3b196b7a,957bbea1,f3f2d1e4,1ba37eef,7dcca7fe,87e7c593,6ffff685,52e67b64) +,S(9cfea1df,caaee192,141f0278,e467f809,8ad89cc9,b47ed982,3029c1dd,726e9331,72d81e4e,7f30ee05,8fd0b646,95086e30,96a071c1,5b75df47,b10146b,18db211d) +,S(548d3f42,123553c7,965c7f21,f2802c30,455c5151,99b98e20,1e966f34,6a1334da,612ea25,cebb03d2,89538eeb,15b94686,8c0afb1,311278a,42694a0e,956418ae) +,S(e5be619a,ccf84c26,9b5c545,e8c4990e,ebd46756,c628de22,a6c8bdd6,74295bc0,640864a5,7d841af7,ad83aa74,fa858b91,89e246cf,9b361837,a742e2a0,71b08bf3) +,S(b560933e,3400ed4a,eea8f733,d2368c8f,a260460d,f734e209,e194e9ae,a1ac668f,5438f93d,31337853,9feab182,6cf17bbc,ac0975f4,de29a886,1b1c0c02,2c5f9da3) +,S(21dd9a97,baca3e79,77ecf7d,d74433fd,dedf2d96,8c3153c0,2c652aa2,1ccf60b1,de6e60e0,e048b0b7,b699bbd7,cda0c0c9,b851c4cd,34f4b8d9,17c07cd0,2684797e) +,S(5cfa560c,6d39439b,4c9b0a52,f9bda301,2f147874,48c9ff37,bcaf2900,fd934bbd,c7927a63,cc1959b,f3556998,ce936f29,29d5a5d3,3f0dda32,35affab9,a5b11b06) +,S(4a3b95bb,5adcd41,5036204b,394fcc95,6377afe7,b4902f49,461c4b6,866d4fc6,d59e3ee2,f1bd1e4c,c089179a,4db9387d,8d6be47b,df708023,2a0d00af,a8e84f2f) +,S(cc49a313,b4c69c9,13c06b7b,add06f17,404edb0a,dcdb3d4a,81c4b765,35f4671f,4bd722ec,c35e525e,af36c194,3d375592,ba483715,2c7a91b2,4dd57a89,687bc278) +,S(9d75085a,7426a69d,9ccf4f90,d8b4ee0,e07fdac0,18df3d37,40b264cc,d4146d98,5991253,de04b32d,4772f44,de49467d,ce174ae9,3f941ae6,a4f6e3c2,2cc4b0a9) +,S(dfd064df,737bdadd,2eb12cf5,d9f1e192,caa87c0e,fad20d18,b95b0d06,83210fb8,519f883d,a5bf8d33,50b1d2b,89012fd5,9f317299,3eae1226,13d81b92,9103805a) +,S(2b50a35c,d2356c35,d609013e,a66318bc,1cf20582,685c12e3,bf618102,807eaf9a,7d0b51d,303aeefe,b81f5a77,d9b5829e,fdf4241e,435380f6,ce74abab,1dc76335) +,S(e26e8f4b,2cf175e7,c76e2a59,459cd45e,f3202f3,3027f0c3,70481fa8,685abbc7,4c82e7ba,aa0d5161,53076702,997c34dd,716e5fe2,460eac0f,194f72fc,3ac2013a) +,S(5903db7d,54f4d857,6a584057,ce78dc07,1fd90e51,f825c959,b46d3483,5d0f87fb,c55e2fd3,e9ce119e,47c00332,9d18d6f7,febf9440,a18de0f3,81608011,1e9e99c8) +,S(4bbb0ecd,342a82d,c8b881e9,635241b6,1040e6ee,28b98204,fde953d4,4d25e9c1,12eb090,f3445b7,52abee8d,604e8784,82e97e9,b44d2335,8211a8c8,2cb0ef04) +,S(4a2455a,ae87bf97,c6e6eb38,fd3279e2,7029967d,41b9575b,647550f9,4bc4e8d2,5a340ac4,ffe3bee6,2d52bea1,e276178f,9af3422,f9c61c47,4a595550,73936074) +,S(f086d68d,c8ca19aa,54c329c4,c07b530f,94470abd,dce244ad,1decaf87,53477623,911c49d3,84a16af1,65be4161,cc4869ab,4d9e8ba2,808afd80,20d30971,b4bdbd08) +,S(4f1b177e,83b76c4e,24a53f91,2095f1b5,d4b7cdf7,29788cb4,c989f921,b7ba856c,a5568c4e,b060909a,fc3dc2ff,5bb9534b,99debb69,dc0b811,e1044705,7d80eaf2) +,S(eba87899,29a7e45a,23d2fcbc,884778d,c4fb5ae7,fa67954c,76534303,97db5823,e6f8c729,b3570917,9fc46b4,7f03af9e,801b26a6,1724aafe,e730217a,2dcbf68f) +,S(df117b13,34c9a5a7,92d58084,4444559f,130ee539,89cc6e7d,87723b63,a82282c2,dd87ca57,8eea3c51,2aec5492,ea55111c,1a2fc55d,4e2335a8,c9be5641,516f7120) +,S(d775543b,3e68ab88,36eaa1b,df5f6a06,1f5768e4,baa01a68,621321c6,e6ee82c5,70221b05,47c97398,3cee7a26,c4197f9c,27a2bf46,10506e18,493a9ee,1881436e) +,S(a7f10dd5,5a231ae5,abc5c611,68cd58ca,5e006f7f,fdf064c7,1482febf,4578515d,492a33a7,b66b9694,e225eb38,d1d99399,b2c24af2,d69c31e,b4797a9e,703c13b0) +,S(c79545ef,3119abd9,11336c86,c6b74846,801c6b3,812da05b,5d36e9c,620120ec,24c8fcdb,95b6eae4,51473f8e,f7dea06c,738a33c4,f1214382,bd7204dd,d3c28718) +,S(98bab5e,744f888f,5f843ba2,9e2104a3,afa14dd6,6a2206ec,8e783e0c,52c2cb11,83b5699f,e5e87ed8,c51d929b,8146bcd6,a7abaed4,636afcbe,b2c30d2,bcb94df6) +,S(6dce2828,7b6fa44a,c8213053,d39dfff5,60d84a84,ac264110,547752ef,dcac586e,1e1eb62a,b9d60cc4,5ab2fa8d,d065d1a4,c79be399,53578a5c,adcfc629,e237ed66) +,S(e386a59,287a73c9,306b091b,5b24ad8f,db06a9dd,8f6f0c1,b7fb0ace,623dfa83,4a7e73da,663b64a5,e624ce89,9e16fcd5,c0d3b221,42284ed6,852960a9,d05b34e6) +,S(8fdff782,e62fbe31,98c283fc,9b9543ac,cea0a318,2626d180,4beaa27,ea4fe4d5,fef8f471,9fe0d95b,673ed650,8107e887,a4f5301f,4317c708,c5222d2a,ac086675) +,S(4c9093ae,7842b148,1bbb8b8,4ea564e9,36ed1cc4,35c89089,a10e0442,292eaa37,2d683334,93d245fa,e5ac0903,fe9356f7,8642362b,f85a7426,ea2950a0,a65298dd) +,S(cc0634c5,5c5c52a9,d92b80f9,be072a35,56318c6,fd76cf2f,e866d5ba,33103a1b,750b7d41,b13cb69e,6d236eb0,87fc8600,4004aa77,1b699e88,7e8f0b08,d07f0b32) +,S(9749a673,41fa7ac5,8bd33f5f,9cca4ad9,1d53c7ec,cff76656,9a56f71e,3b918255,b685f1c1,9dc7d6,7692a2aa,fe37d9da,5e68fd69,cfa58d87,ec6ced8,68916068) +,S(b04abcef,b57862f2,5a57fdc,b7da0b1b,a25bd253,72bd91bc,9e0377b4,697d8e75,50479a64,66ad4be3,489b5869,d8b9bbe,62dcb8af,da8e7d42,78b5014a,19e168f6) +,S(d11f7de8,5481fbed,f1a3b395,785f00d6,295059b7,c8049768,22624e85,45c78902,1d163368,be0c1290,1a7369d8,11266982,b48928cb,448039c3,17333658,6f5c3416) +,S(a21c65f4,65c4c7a4,93225af,73b63cb2,fd615160,b29b2b90,970b880b,5756fd4b,69a26b89,394de60e,7dde3476,7048a295,57f1e3e2,5f7a586c,7666aa30,9345ecfe) +,S(53c626fb,b080360e,9243d399,9a58ced0,36ccda8b,186c76a4,fdeefee1,6a497a1f,ad926008,62a7ff1e,519106fb,933616a8,8264d7a,c40476bb,eda7e1b7,742ac9b7) +,S(cf67b587,1b2a3ad8,d0364fcc,8741f10a,11d96933,11b72870,60116c4e,74e6ff0e,2c963b7c,10ccd74e,f68ac068,cce1e30a,7be6537f,259abcae,6d36d29d,22b68422) +,S(50216d8,8cc8700,29da89a4,b34cde0d,36428829,de9f58d7,31ecd6a6,c90b4bc7,920c1df0,96bc4891,8defce32,2a512d5a,36f65d7e,65525e0c,123d9fa7,49e38b21) +,S(1d845594,f4686fbb,7b0cc62d,af790aff,3d6000bd,e26ec1a2,67766c3d,93d1aef3,eae11ba6,bd9dda02,ef134035,1847dc6c,92450b36,cd6a9734,25c09f9f,3134d260) +,S(11ad4f50,b6c5b97d,767d590,859e2ab5,2e7750a5,6f7e70c3,d5c52bb7,9e4785e1,2c2bba36,8725d9c5,2152496,f14cfa71,1826e846,fbf7e7ac,4e263db5,a8023b94) +,S(3568d27c,d72373e1,29a4a519,86082a1f,f76ee425,969d6e3d,12b242b0,bd49388c,e36dfa9,6d094047,16e35668,10a8e57,8eff108d,839cf3da,f04c76d5,8754fdb3) +,S(3772ab35,45e09d0c,5d2abb91,97007742,46310f72,bdc0b8ab,afaa2c17,f17801d7,25229a8c,eae0c746,2d7a50cd,a8b012e0,775693af,8edb7260,5340042,a78884e) +,S(8151b24f,72c4701a,e4624779,c8b93ad2,44f3b299,d1ee131f,a13054e5,c29274f2,58938307,25ffd619,de73fca0,50c28d77,73420724,4d2e4c99,86ed5512,b8bb6429) +,S(46a4855a,d4101f8c,60c59705,e537080,1b57a81d,9227f4c8,69234946,5d539c9a,8fa66dcf,21117195,e2c117ae,e2f20bb,9517ad24,5fea8864,beed3e68,89e36b59) +,S(b81bd54,3e654f3d,eec15001,c38bd2a4,efa7c45f,4ece2d4f,fd893c6,15803d16,15c3f7aa,31299a76,34431622,8f93b6a3,2b3947fe,5a894c4a,75d2ba01,4e9d3e75) +,S(3e169a1c,f2a0324d,2478c054,94d58801,423f10f2,4cfc9fab,a5cd5cad,12e7706,20405bdd,d814ac7c,53469075,a700b4bf,4d454b,fca920f9,86923562,19389135) +,S(74283e4a,b161b33f,f67a1b8,cde619bf,557f39b8,5443efdf,534bdd2d,4da65956,22296be2,89785c04,6773ad2b,c881744d,380c1717,1c77b159,bfee3689,d0b3df3a) +,S(62715786,cb76bc9f,b65da0a2,3b7954e6,1a617fb4,de828092,bde3da39,ea6b756e,3c27bbe3,8829a150,3b563337,bf995110,eec54d58,21e1f17d,34a5fd90,52c2db32) +,S(96200105,db23b893,84336bc9,d5596740,2c93aee2,ca35df73,9c55a000,6f7c8aae,3192968d,400a2604,c80307c5,d9865f49,ea41cdd8,e3fd3b19,a2bdfa17,84a6ba26) +,S(bd477798,bd2691b0,8cc52fb5,cbf8b2c5,31787535,541b5c31,3aad9696,b71d13fb,be2b51c9,a4ab0033,c21dae50,c4e7b2b,51978b39,4a66d50b,6be7e140,abddfc3b) +,S(fa149388,e46ff849,bb5490e8,3aac6788,70da101a,f52dab05,9039c305,475289e7,8455577f,a8d85674,3b32080a,dcd26a1e,c75af3d1,c184d5e3,7f22030b,8867b2a7) +,S(4228db83,af1ffb1,d4bbfae7,3781a70a,8ab50d3c,47200e86,ff436ae0,3391ba90,45db1d0a,b0e6f0a1,801560b6,419bd2e3,2413ddc9,4b4ad637,d4071d8c,b7a270a7) +,S(a97ab279,fe0df5a0,3d494c02,eb69c686,1dc3a39a,fca2bd49,f4161ff3,817c85c,5006c8bf,f128de17,3d72f99f,7cd6deec,5d4b7441,6b1ca290,e535c8d,c59bec7d) +,S(c0d46c57,6bdcc661,4e1a3a1c,c19fba37,9f27dc45,5135eb63,f8d44666,904c668f,396b60a3,b28b250,2c97d7cc,f93c7609,3d19172f,47fffa71,f190936d,cb215f58) +,S(73c5d7e0,4599fa7d,e09b8c2c,25c5bca2,b7ae4c6,e1b88e63,6de3363f,b1a8dbbd,1d9ed08d,558bd642,9e986b0,c431d67,9229adf,6fa8dea3,faf17da2,747bc617) +,S(370481d,a2ef4843,8d897c6e,f1a01750,b4788c65,62ad3ab7,bbf3c89e,e24827a7,a88b3876,c2051901,1d84acc3,3000f0f1,ccf794b4,5385aaaa,190e435c,760fa7b1) +,S(2dcbe303,3006f0a4,99dbb7d8,d34790be,f2b68cbf,649b9d54,eda8819d,637807ec,b82b46e3,c7ab329e,b915de2d,f3fa28d6,92cf43d,584f9bda,5d6f58f7,1a90c1e1) +,S(f45f3ca9,16db45c5,de35d957,c24f7a59,44052b64,f8f423c9,8a442f6,17bb4b7,79ddf02f,b3154d6c,da1d6a79,5c64de61,5b4a0ff7,810bbfc1,dad68e60,229b5a96) +,S(500caa8b,cad0567a,465c99bc,c4802553,ee17346b,e3a9ae93,4fe7e95d,e787605e,40847ed0,75dfc8d6,ae19dccf,73ddd256,4e1beea4,7f822a58,f0570c62,f238370a) +,S(30562986,a23962c5,5b746191,e23b893b,7bcd8b87,6fa85557,c525eec4,d64c3aff,2d5abe,41c45383,1b60c034,7bb55464,e19d8d98,8a5d5fe9,37337507,80577a53) +,S(f687d51a,32526b72,9ed3f690,be1e6205,ec72382b,6a30478f,63a18e0e,b48e422e,efce1b35,19c94f7a,fc54da2e,d36b15bc,f197e2ce,a0c2d680,211e12ab,7d515704) +,S(104a63f0,d385351c,c9ce207e,500ae7eb,22199ea7,dea65018,472884cf,a1ca505d,69c21887,50b20b3c,5af1600a,a2a2edc,a6de0be9,33d2e67c,e05ac4a8,30239cc5) +,S(50966099,4b7b8ca1,abf963e2,ff4d295a,eb3d59bd,43029c03,5e6ac9a3,ea80fc6e,d48589cd,40d019b1,81211674,854aea3e,56be56a7,bc8ae519,72963adf,327287b1) +,S(3106d6e7,94e5e135,1d788e85,eb0f2c7c,7ac22e9f,d1c86a0d,d22cf88f,54513c95,c05e593c,4568cc2,992849d8,4006ae18,4ad2888c,82ce8dfa,dbf984bd,2fa2bca0) +,S(4c967d1c,9977bdce,84f76ac7,13b9e5cf,d1081b43,de681235,e7914f6e,2059fdce,866470b2,a3e99b74,15c2cb09,83a5c7dc,fcc10d02,a28e90ee,206be515,e88968cd) +,S(96319099,ae8d7741,1d8bbb7f,bf58f62d,b4027b02,ff5e32b2,e4aff910,3a781a52,6c110074,daf2849,a3b148f8,dbba2f0b,d776eb4d,b787ced4,22edc5f5,67947389) +,S(7c93bb23,87a36cea,9dd7406d,95af56f2,b972242b,759728b3,bdf30fa3,58247ee7,21e4de98,33487c86,6da01e16,895a0e24,17cb34f6,e3d64e01,8f7c4d99,9e989942) +,S(c65e4a03,88de1618,6d9db143,387a3229,c764dabb,7c6ddcdd,c3ba9195,7f1e074,d586d143,8005b28,cea25a45,7c45c1fa,2137bc2,fd78417b,daa499bb,cfca658b) +,S(d895a924,90c28692,bcda380c,71d8d1b8,381b1fb1,a8108f35,4d9a17d8,64d674d5,d30bda25,a63013f,79ef5728,dbbcd259,c7cf2ba2,b00af73d,9804f758,7fde17f5) +,S(90467c3a,5b36b9bb,faffa164,63d1f70,c892e23a,3c7f1132,27bff1e1,5fdef988,4ec70191,40247d9b,3cfccb41,ba22ad76,20522577,1e33d568,946c8081,ea9b15a7) +,S(5cd03d63,d0e025a,7af268f7,8f53efc7,b4d38e5d,58da5981,abcad74,3e294c7e,c3729f6e,5517d41c,ab1510cf,ee4e0e48,f168e043,34dd8781,1a10b70f,b42dfb3e) +,S(5130c49c,652bc5ce,a3dd7629,bf362294,8bf69c02,f9806988,fc700a25,c7e964b,7e46e219,4bc9dbd3,99f98c7,b7a44313,a027ef23,1abe336b,7381c215,6f2cf563) +,S(95899c2a,33b8d4e9,13947306,6b924812,261a3155,e5a7ddbc,c5447796,8edd34da,8967be99,84240292,9ea7277b,5be0d045,bac79fb4,93a08a41,d4dc5991,da6b7cb3) +,S(3928013,8cb3e93f,7c4650c8,8184dfcf,6e55d238,2e75e604,9dd6e40e,f489745f,70b25e98,b897f3a1,c89bd6d4,72f2555a,56bdf04,6fb43799,58709471,f8006a52) +,S(a47e1331,b5fdbedc,e490497c,bff1088d,ba72070d,3cfc7997,fa388fc3,2f80b451,ca54b8be,fff00465,4086c75b,da3ccb9c,6244746,522124ec,ec22666e,a9576b19) +,S(cc1a608e,16c57528,3cbbb134,4083cfd3,f1b325cb,b48df6c8,2d50bed1,e0cfb96a,5b8aca44,67d9b224,413b0c98,78e09213,591b8f87,b024bab5,55120a83,38cc6734) +,S(d8354bc7,591ebaeb,7ae4d1df,2db3bde3,b7438d1d,69b5991a,5d70f6c2,c3fc3cea,efc89693,6765f03f,29422703,97591bed,7d95afc7,29807a31,fe266f08,9eab5ad3) +,S(6ac1c963,ceb2740b,212ef42e,6da07647,481ee21c,4e3fdd6f,f2ae3da2,8ddef8aa,4fc8817,1b6d5ae2,45453c94,f5f2031c,c52140d7,a110d9f,b1bbf3e8,e5164281) +,S(be130f59,b52e4148,f9c47469,778fb36e,74d4da3d,a00f5c4,dddd2e47,6f18b42d,16dcd9e2,f739a58a,22a7d76,1c1cdf61,c5b9f8b9,46449516,9398dc1,fbc47069) +,S(685db8cc,39864a55,68b56e59,96265bb1,24ee71f9,1f9f4f3f,fc3c79e6,c063bd2f,730a7141,8e5b2f7c,2d333b8e,5be3021,22b396bf,9a75f493,37bae5c,86b50f29) +,S(39f41ff3,89f74c1a,e25e564,b9bc189b,f31f9af,cf0ee4ea,aad66ee6,55d743ae,fbea0f6d,e25d4fee,53f0aad0,9338f739,26fdaeb2,edf9d8d8,8e1e520d,d66c8622) +,S(d7a69574,41bc9639,994737b3,d483bc0f,c29b1b62,cbf59f28,b12b208c,4c20ed1f,ce44e2da,cdf8158e,9c07ca25,1b9a3d06,91eea29f,41f824ce,ef2d631b,65ba8cb) +,S(85bad160,9139cbb7,2be86793,42b37884,22f5981c,5fdf30ba,4914395e,c1eaec9a,99fcd461,29e576b2,b25c57e8,8e3fe3ea,362055c7,843838db,4196a485,cf14dfec) +,S(2380bac4,d428a159,23c2ffbe,8f17da09,74d986fe,4210b72d,51a1eb80,23ea49e5,f4af7313,fde4c7f5,e45e38bf,c4d44bbb,3ca1015b,d209065e,5a6ab074,5ed6f54b) +,S(c0561359,b7d61dd0,e359108d,f221202b,97c1acfb,894f4e9e,46fc29fd,364f9cf2,3c377d80,1c72a9f6,2cfea5ff,350ceb32,75b16103,cecf492e,2901327,d27d83dd) +,S(72c499c1,b8f4f2a,eb9181d3,9bba5b2,76481c04,a588fc6,4ed438c4,920c2a06,6c994c8e,60825314,2a34867b,1f82bc1a,f05ff8ff,b3045e7a,72d01243,b2b1ce53) +,S(8de84cbe,2b66209,f8f8e2f3,f06feb45,66e02c9c,b5df26f8,84e20454,ffcf477d,c7f2f680,c4d07d88,69348e98,6a3b7ac2,ac9e8542,a019f379,6410b993,742a34a6) +,S(dbfec9d8,6581d762,e5ac8048,886b9d2e,9a2d02ee,63c5f442,7d02d12e,401710f2,6e611ff9,827bb1ac,a885acb5,906648d9,b46496a8,98a13c90,48868d,c0daafea) +,S(9dd651f8,6099edd1,b3d0ade7,82aae6b3,9588dc2a,291577f9,f2456f23,d1d0453d,4f6db617,f0d7860e,18be81a,dfb6d773,cd3f905f,98611845,5f5a0b05,ee715ebd) +,S(2fd8161a,c869de35,e777a885,ee608f96,356445f2,fa2f33d1,926260bf,9bd66a15,1d2c21e9,674c2d92,b64163eb,12de6347,98c6e7a2,9787daa,7c6b4c80,fd307f25) +,S(3f25bf89,24f505b2,3f1538ce,4940edf4,8b6d8765,f88778a8,495e8a84,a29dc391,70253583,e7e0782,18ab0252,52c613b8,34438254,9dc57c30,afd47297,2c8164f2) +,S(3c0f0359,d5f72344,f8f3d2fe,28458f30,467dc770,b55eab47,ff2e1ee2,6c773f0b,49583a39,459f19c4,5ac50d78,74626524,b9c25030,e45f2c7b,12729ca8,1edb33c7) +,S(56380666,ec1b5df2,36045855,fa0dd93c,87e38d70,fb170dd7,3be5c308,36b73a15,700690f0,b210ac6a,9aa91252,c8af8f60,b5cbbf93,8291fb11,7bce1f0a,759921a7) +,S(71ca710b,b9a5f7f,ec6b228a,af3fc47e,25f90201,fbe3c673,8bc6d2fa,9c9298bd,7dd2528d,c0750899,b1891287,170159ae,c759bca3,51e243f8,fcc9efe3,2f9abc89) +,S(78ddec3c,c938850e,7c2ec20f,98e1be3c,6ed87fae,827c9102,5112d0b3,5d264575,19072951,766a4050,c8585048,d6f19e60,22b9c163,f1799ddf,d486dedb,3d680321) +,S(9aaebafd,8852857e,8c670950,93dac29a,5813249,ed03e67f,3226ab3c,7b4ed70b,8c6a2acc,b541bd51,65e13bc,a3c4d2f3,2457bdcc,406ba71c,7b9cecd3,4705fffb) +,S(586eca74,941180fd,da16c7b2,8b9bf139,a3096a6a,20ab9bcc,6d12be5b,db2f79e2,b3b1d12,361609e5,afc5a7f8,26a21ea,ac4bfde,56016ad5,bfde6f93,a3488d71) +,S(1857bc3e,dbe4de2c,86fed7d4,cc3ee63,c0e0b6b1,36acf97e,e3638183,8d50ddf8,ea5e807b,e7a588cd,ec759c67,3584675a,8a7fbdb7,cc5a1835,119a4f64,8c275363) +,S(aa4cc744,7572c62,22a6cd,bcb8813b,64206796,27f5f7ba,863d8566,78e5b01a,ba969ac9,d259244a,9a3b7f9b,b3821a61,a4a97b8d,af7e08bf,f39f099f,8fa2f836) +,S(4588ec09,59174367,6885fad0,a43d85cf,d6f736b,cb276179,e794da35,204f36aa,fb835e7e,cdc681c6,ee1c89d1,dcbae3b,a9511692,a54c9c37,2f86f4b,cc7c62e) +,S(867acd03,7a3e5f86,99e33f22,72f7b1fc,25ce6622,5020a4e,ca3b3111,e880653c,e9112ac7,57d3f905,3249ba3c,ff64640e,639cd94e,5d6cf946,d8d7f3ad,25764646) +,S(5e0a4169,e4f81dc2,28ae4663,9ae3bd4,b527814f,4616fc13,318fd5db,26df370b,5bd335a8,fc23934e,bee2e32c,3bacad4c,c38cd624,8cb34ca9,e58f8add,3140d001) +,S(90053469,39df2418,1b5b2e57,82a82f15,542a55a3,adfe8263,663b4fff,b101c0f6,4ff0d589,973985f6,858f3837,89c3a5e1,74460778,3a1b1476,e3f1ea51,37e3d991) +,S(a99439a5,53df33ba,6a32f33,d90b1500,4e2db077,22a73561,8f4c3b0d,63cec63f,198e0929,f11fc777,ea9cd8a2,e4e6987e,6f9c1fc5,f703ce7e,7e6423db,39656cd4) +,S(51f2a136,1381ba14,c8fab71d,f82aa2e7,1c7789b1,b78c355,a0e2fdf1,5f085282,fd5f129f,ca15fea4,d6f23bbe,43197a3e,6e2b7b26,84934ea5,a97197cf,eb2d16a2) +,S(3a91f81c,8b064b2c,99509777,864c5b4f,bed208b8,f541f68e,82053158,2ea91d3a,9d59003a,d4ae39e1,95077329,e585a8e8,a542b594,b6010404,8573a01,23a513c9) +,S(71e99d50,aa22fa17,3f026dee,e728c114,5e491e84,e140b462,1056af19,9736c5c8,ff3e4f77,68588846,7c662729,1d947e77,699806e3,9bb0bb26,53f67ec4,176a4995) +,S(ad149e93,3a0344f7,3fb53286,ace2f3cc,46f7450e,e859980e,6d392001,7c8aaa39,7dbf4798,85a4f354,b4f14060,39a83789,65a5ab3f,f1157e3f,2a4f6fae,909e81bd) +,S(44f0a37f,5ad78f6c,4a40ca20,7969105e,86e79ed7,7ebbcc32,1a247f91,751ccb01,f404d867,911eb3fb,efb1e559,66b5128,70836d9a,12891905,af649555,c353044a) +,S(4f77dcc3,de8de08c,4c0a4a8b,29717868,50f5c0e3,b271ec1d,c0d38a61,b30ad5d,73c7424f,8ae80ee9,2118aa5a,b0aa65b3,58dc7300,806ef2fa,55836a39,4df57c69) +,S(794a108b,102a0923,6366efd3,8ef658c1,6d6d5c24,e5e2dc0d,38d71371,e6005555,871965ef,efd79050,69acf0fd,c1f84798,7c9e304b,5fdcbf75,1a6f6737,ce46ba2c) +,S(f1988561,234b863a,df5bd49f,5a0b1252,a72e297c,ea3083a8,22da48d7,14e8e594,7adba507,d0ab51a1,8c036612,dfda3f8f,abd2f573,d31aa03f,ca6eb361,a83fc418) +,S(48bed556,c07c99e0,71249b8f,7790aaee,f3fd27db,f82d1c75,491a18bd,cc3f4a80,9dae5280,21be418d,1b4dd08c,be5dbca8,46cf0122,d4943543,8561e555,66316e94) +,S(bbfef3fb,e53779d3,8f376fef,974bac74,ec8449bf,c2dc8a1f,3bfcb33f,943ab9c1,bea5b772,ee798aff,c610e849,5be0ea8c,ed462563,848030b0,8006c6cd,e312551b) +,S(42af3415,27b3cd52,3806b04b,ecc175c4,156839af,eebc212e,b74bd6,95b7f06,686e5fe5,ebf16ff6,2376d096,188de980,f91a5518,25bfa137,e7b46df,59dcef4f) +,S(3c56d78b,74ae87c4,6efea376,d58b7d5e,30749726,40c24d69,38ade127,71ce10e6,ce97decc,f9d1e215,d363b36b,6ca2bc6c,39fed00b,511bf883,50732752,48d54a41) +,S(4b122599,1944ef0a,ae6404a9,e48f69ce,67b52a1c,da4f291d,33afdb09,b789b61a,5c8be350,27a3f992,5377932c,b6d92bc0,62b1bc80,78e4611b,f3ebbe66,b6089571) +,S(9e42867,c02c9314,a3658f18,14d8c59d,71674955,2b00be9a,cd37350d,18d49db5,5d26d035,1ff90d73,d783155d,afe20cf0,39f65b1e,6d8d5d0d,831977c7,17a8c761) +,S(9643390c,5a95345,2a027d0d,47bf6fa8,306ab31e,5dbd8b94,402db973,275359ae,b354d7f7,1019e9c1,d23560d0,50fbd4bb,abbf492d,f595c0ce,a699721a,b27a3933) +,S(8b4916fb,86f77deb,505374f9,1f15782,1b6f7884,feae9f77,bacf5620,7e126b69,9a83c0,6d86db13,55c3d59,cbc87fae,ce6d2af3,64f9c213,816cb326,28be1fd4) +,S(d29df4b,109782c4,1f5ee9ab,b8488f7c,11de8efe,9552eff3,7ba3cf0c,d0054b9f,1bf06237,ea242c4f,bbe08f6,a79b6808,d1a5a444,1989fd1c,98a60981,40ca07a8) +,S(2aaf397b,a5405044,539167d0,55113acb,d4a20265,206ddede,203b8ea7,21dbd41d,374e32c7,1132bbac,91e4b4a8,aa32f308,13a81c2,4f7b3c66,63d8821e,9ef73081) +,S(2239b3d2,23eace6b,8ebd287c,8b6a398c,1ca58a94,5d8b7b81,7b1133f9,cf57ef48,fda880b7,4b54a8b2,8af4b26,78e03f28,f01d70fb,3e4ebbda,94ccbd43,e2b4cd46) +,S(8b3287bc,f47e72df,7edc9178,51edb145,b88ee233,9f254f62,e86ec624,a7c7e365,54a06bc0,9f60d54e,5f900868,c0c3d37c,db6d9969,1eb605be,321f0f20,9fecabb) +,S(d9accea3,3e3cfee9,10d7e1ff,3e87539d,ace742c7,24d6d36d,d8d981ca,984f7993,6adc974a,a901e5d2,d8cf5a05,a20bd02d,62947f81,5425e690,565638a8,427dc88b) +,S(d7fc57f8,34c348bd,e6692b50,474ee038,4af245da,40b8f6b3,8df2ae5,a8b3206d,b253e4b,41fd9fea,9b28e04b,a6db0324,231edb1,1f9af406,e38d2b30,244e2d19) +,S(25808fe0,ec4a1409,36b34e16,595021e2,b815f660,7a23d505,9ad5b5c3,14d9588a,d0664ad5,b1d46ef8,8c8a1eef,bb9df1ff,a75bc16c,e8bbcec6,6f4798f7,c58e7b96) +,S(e4474780,113955d6,72152fa5,70da35a7,59e67a76,29a39ecc,3226ea13,99927914,493cc170,aa2f0486,da6834d3,3566c78e,ad4eb3d2,837ef5ea,c1adf3f9,43793bee) +,S(c5040dbe,2af9d706,76ddd900,d00f1046,44e2b985,82d46f11,47602b91,126311ad,840aab11,a2316171,cc9b6466,778a9ce5,a7cabc1b,1077586b,91a8d280,324ddb15) +,S(23391baa,316d33eb,3a7ca123,6c47d4e4,8116cd4f,93bda3a8,12a228eb,437d9f14,1d81341d,9e6d76fc,1ca69af,f6d8d119,bc97c79,c7cb8b7f,1ebb54f5,cb7efd4d) +,S(13211756,3de3ba72,2fc6682c,beb39494,8aeb8fd8,c0b95eb9,45eab34f,bc39ac38,9b772721,8a4b0823,7c961431,e26cbfb9,aa527905,41b753df,89eb9ad8,8d74f006) +,S(3b8bb898,b27a2fc7,a1cf896b,bb5cd7e1,708b943b,afee896d,2ff77a95,ba789708,d81e541c,668003e5,5a1e13e9,6a1635de,7fdcbf79,c34068c9,248100c8,9d36c1cb) +,S(e1d70a2c,9af5c4ba,c505e4f5,5c0040ff,d94f162c,815a2e21,c7ce899f,e0217b4d,b25630d6,d20e0e4b,3686d66d,e2b1e53d,eb063b99,e79c212c,2fd3cfec,97a4532e) +,S(1b1e3823,a51778fa,d38f0c56,e2b36dff,a7e681c8,30fb41b5,ff1aaa7b,d912de1c,f2e99a90,a951201d,ce725855,6bf7fd27,bebe1626,8328116c,d593ff32,2584d4c1) +,S(1e31d838,94f56191,2c134817,55e467e1,8745a91c,d903102,e48f7282,21bda7a1,11dcef88,35dae18f,3c02c6d9,7f80896e,477a7b27,41203aee,5048c94c,7cd610ce) +,S(cb9ac34,795cbc99,bf67a7ff,2bc3b497,311f687a,51b5028c,422b0301,8ab7100e,5e5f0621,c804b35c,e01e95e9,a8dc13f7,e5ff32dd,8a44f320,74e44836,3cd0db1d) +,S(afc34ac4,67dad38,a0e326fa,1a656c48,24dcb884,f00a20ce,56c73835,b4e11c1b,c8b1c404,3f6d647a,382ef031,a02c10cb,77a033ae,bfc6dde1,d7508136,28bdcb96) +,S(3a6fc160,ca85aba1,619430bc,ba14e12,3330f636,7a78273e,603f85fb,e270aa81,594a2b72,86dbb390,945a7a48,3707bc32,cb72cfc9,19c241bb,61774dba,222bc0a) +,S(a840f695,657c9c3a,3f64f56e,af18debd,bdc1e4a8,e3eaee43,46b19601,433ce7d4,8a8a7ac0,ca41e2df,461eae96,bc00131b,1a77b824,7273269d,7a41f49f,ea126fbc) +,S(c044e01,70ec6914,c39d08c3,4a293268,65cd7762,d6e0f3e5,5f69d80a,e80a39d6,7bd63082,7ae51516,25ee0b5e,c2f97b37,6dd5fd7b,9205852a,92dbf922,3a0b4657) +,S(cb90135b,352b969b,45eb5c6,7cfdd288,2bf9271a,41da4b2a,a89dde94,eaa00b3a,14cbeca0,762d9b11,fe4b6d26,7277a8f7,b4dac82c,52634b49,2a84b616,2d79be93) +,S(fa7bc437,a24dab0f,21c7c063,3aa4a8ff,c8216676,75ea6963,c58c84d0,b182a0e,e24267c6,d7300c6b,6dd09326,c49359e0,fdf72114,401f244b,383eee54,d1a5aa35) +,S(e6354cdd,3f503d25,37b2bef9,91533ad8,35e95657,3bc8afcd,d0c1c05e,57b3299a,d6c17b70,6291c8a1,989955b9,ae9ef9c7,cdc2b6f3,f5cada0a,3c4d0b86,859ead7f) +,S(9da36530,7e815e3,df0dce9d,50d7d812,132ec23d,2bf0453b,483af1f,bb45cce8,bb374566,98a28ace,a86a1b10,2909ae91,3bbc4b23,22f4d09e,bd298e51,d067a8dc) +,S(dc457a1e,1a19cdc7,6ed1c3b,a416a886,13b25788,22d691ba,76319b8a,38c9d4db,39f93f66,de5a650d,d49919fa,294638a7,85e25bd8,f8285776,dfce813f,bbdc3b58) +,S(b2377b1f,1b1a0e98,5ff57bc6,64ca456f,ec216c6e,b7b389a9,62b9d82a,ccf0374d,383a5580,d723509c,bf114e74,b3eb9746,7a040fc0,6232adb5,dac199ac,77578c1a) +,S(8b1a6446,755d3a85,3851fabe,b95c24d8,2a5a86ce,5e5df65,78051124,acfc7e50,42b885d4,cb632a67,51a88aef,192a5bfd,ed1cd461,438cb623,1caf3346,9655cf75) +,S(9408819c,bacf1a0c,9e5f1416,23a907a7,c3a7efa2,30a15b3e,7d5a6ff2,5103f5b1,a9758ec9,d6f84f73,fd107451,f0ab79a2,1df08c30,cbb2456b,d6c68cb,c506f98) +,S(8bfef047,7b3f8cb,99d7c933,a884da4e,9ce6d473,c243d3ee,9c319870,b06ce25c,8bbcbd87,d06af17,550d17ee,83017c58,627f1d84,e8a07e37,ca73c12c,f7e5c498) +,S(2a857f0,c12202e1,1dcb84b8,adf582f9,8eff647f,c3803cc0,dc1d294b,414bdb61,9bac456d,a7fd9318,244af8c6,48ea23aa,62c8ae1d,af7fa9af,e430efec,46db6548) +,S(937b8c5a,90485ed3,d06b224,2ff53e6b,b94b1ee6,a493c835,25e3acb6,5d5cb5ec,d37b136f,f9fb374a,50f5a311,ae366ca6,c9c3d867,e9b7e788,da3b2766,a7ccd808) +,S(5f544d53,e2bfd6be,d9150ff3,6a1e5c5,22b24933,489201a0,65a0e0a0,3a43c77a,ba9c20e2,8c47cd98,1752c413,70ced32,8f4c847e,20165562,c3137e0b,12990f51) +,S(67b63388,90bf8baf,a5b64fa7,eb9fa4c9,e3249cfa,81a55cbd,9c297e7a,a7c807b9,dc185675,2d94b811,42b54577,edf808a5,d871ec1,6c8ba567,62061dbe,ae7625e6) +,S(587a9dd5,99cb448f,9f92ffa3,d6328032,b76604d8,386a2e2f,bd324628,98439442,496998e9,a893faa7,a49e73ca,2dbbf533,488aa687,51ffbdee,6b6d6dcd,dbae9870) +,S(36fb7b1e,c576ff9f,81077312,35d18612,18dfe51a,58642a56,8f80294a,63c29b38,34a45ac9,b82cb1bf,2c96fc1a,67de8a63,5c1a1589,61baf8e8,a2f01572,1566c4aa) +,S(87b71c8c,a0afecd2,dd8f49c5,109ff434,ab8a273d,4e4efcae,f775624c,71f4ba95,8519151f,51122588,76527c56,e1e6d9c8,5b3626a1,bd6ad0b8,1bc382cc,525676f9) +,S(acf65cf2,805c370b,a3bed962,c3ba3b0c,56c98,b81a696c,f433a0e7,a463e040,f093929b,f45be16a,f962762b,52f57ef2,dc7b0e23,cd68e3d6,63b3b402,15692d5b) +,S(e092bfed,8b010c85,b91f1674,1cdfb1d,e3e045ba,81297f44,8990475f,2147acf1,e0bb9842,ecc8683d,e4016072,86070da9,8c4d18af,8bdda91b,65770a98,77902c37) +,S(9bdfd7b9,8260bcbf,17812735,c70501db,ba386b7f,28ece691,97c871ca,610a52ae,9bc65398,3f8c4cce,731e01ba,a5f509f4,887d9a78,40620d9a,ffbcfdeb,5e371eeb) +,S(3db22321,d9311589,5c85587a,9095421c,afc8a80d,86a4240e,9a4a2f82,8643545f,42af30b8,2c57868d,e0f23c9a,fb19947e,fdd6bb45,4efc68bf,ddbf7349,8fb78eae) +,S(e9d3f14,a6a77ffc,f86decbd,c5e43fa3,c3757a64,22d37da6,25627961,622b3e5f,83ac0bed,1e2a714c,c6ed0764,da92cc17,fd18ee84,36d667f0,2f90f818,30e67de7) +,S(412486e4,f29b4887,e1448af,ad59599,b31b9085,8682580f,891d51e,9842f2a4,c31c5931,8c0d6790,c2fbbb03,9c2e761c,bc5577b,53161a8f,80d397f,de7ee3d) +,S(e9deec71,41ed506f,e2dafbe0,c9ab75f9,609f8422,a4b2da26,7c529d92,36b4ddaa,8728544,d8463bc2,d846029e,5d2a0a40,8dfb767f,9adb79eb,2209478f,6d94a21d) +,S(5a0a2292,553c46a0,823a1761,2b8925e1,bbf01c2c,5bcb7173,5f0fd6ff,b264218a,3097cdf0,adda0f10,a261f897,6447ff9c,12de696,8f05009c,e90d1575,e55dbae2) +,S(49cb2a37,8b681ad1,ba1dc23d,8d12f186,563a40f9,ce0ffd00,5bade11a,4928d1f,f235e2af,c0f65fa0,ff15a938,ad804a3c,fbecc5b6,e276bbd6,32a06959,3d6732d6) +,S(d4d71cb6,36881177,b05ad510,a621cd44,3dd1afd4,84d177cc,f99abdb9,1615feb3,3ad65378,de3eb9b1,606f385f,a950d533,5316c363,fb076c02,ac7f12f0,7562645b) +,S(591b2e1,4bdd6e00,64f798c3,14e86cc5,529c99b8,3f47d148,b7e3e642,35bfab2f,4f686266,fd2a4c66,4d6bbaf1,2a368d59,12a51789,5d783aec,a986a568,a8fa59b0) +,S(ee503c85,c984bc49,3d7b63c2,92eac9de,be253400,f4988086,970be236,47356876,bd828abb,6f9e89cc,741704e9,614d6711,39449bb3,a7ebdccb,976c573c,4bdaa47e) +,S(2f9b4fa7,2e5a1fc,ca36a3f9,8987c3af,756e78c9,77fd5697,758c95b3,14b3f89e,9668615b,3d5b3c74,4ea2e1ce,e909d9c3,956657f2,1a65fcf3,3f0ea150,1ca4a15d) +,S(18b6d06a,a34124f8,5f92b204,e2a010aa,a1f4aebc,6e13a62,34eb1c92,7afd46c3,66cc31b9,bdf600b0,7e624bf,a3e079f3,258b0ba5,5437264f,b460481d,1f4bef4e) +,S(3bc07963,bf758dd8,fff37d0f,30db6eb,67662a4d,65395688,1cc30340,ddb44ba0,60e11ef2,68209a1c,2df9a3c2,276db6f8,8e6dc1ec,b74548a3,57d770c1,ad057e5d) +,S(bf585d6,5b325423,afd49af3,c9fa68a,91498b5a,f0ee9e3d,d089b288,53a46a8,2f8944e9,ea484b9a,51256e2c,fa9e5396,4c000c1,3451cc05,94bcf6ad,e38e66a6) +,S(887c0a2e,be7a0257,5d5b59a9,11f40ef8,f0cf1438,d7f05a7f,64e9c133,cfb69294,45f334c8,4f9bc66f,50fde594,94175491,9c37c30d,d20f6a58,40271e71,60aec5c9) +,S(9dad7af9,a73325c,59a17700,fc3dc6bc,3718e79f,804a2116,1bf9a36,622f7d4f,2b7c225e,99c6a94,c7e326ec,b89eb8dd,40644bad,1893136,6442985a,e6159525) +,S(847e4f95,72bd29f7,4f3e9a2e,d73cdfcf,63bcb61c,9caf8694,7cb84594,a7dd551b,ba6ed282,e0a92c62,fa86286d,370cb344,f6f1182,a101c4b8,1ea89a15,b393ee16) +,S(25213205,df1c3600,4673c4b4,49256c70,b5d8c62c,cdd3d580,2684af47,f047a593,36dc81de,5af4709,fae2a47a,8a205647,95aabfec,42a79f3c,54763d67,ef096837) +,S(75228cd8,4866df7a,4713a25e,f2fb29fc,95ebfd70,5d73229a,b170cbce,1058e87a,fba4879b,cc02d3f4,fd25f056,c0854415,68a47355,929bb812,a7dbb30b,c012fe6d) +,S(74945539,22867c08,6d02fb07,c0424890,981a1337,42c63fe4,b6adadbb,59b68568,7d774917,8df8b19c,8af0bf0b,5247e751,3e3b8d04,46465180,341ebb54,1d1af3e2) +,S(69db7f53,2899e39c,fa0cbadf,c29946f2,71d28ce3,57f47f7a,609e0fcb,ffc9b04f,cb0243bb,103255da,ad423ffe,e1d50f9f,26da7cdd,764a11f0,a6694b63,199feabc) +,S(727ecdc1,fb4a0dbe,fd2fc37,8902f922,ec4aedf5,53dae225,1d173c29,2929f8c7,ae5bb2ed,13778d60,66446ee5,e5754db2,bfc4f7c1,64bc035c,224d495e,651f453b) +,S(903ced8f,ec2544b,e207f5c9,e2c7f2bd,91213873,5eebc382,b129e334,7ef25b72,2117ca29,ee13d31,5e89bf33,afa8b7db,ff75c795,6be40c8b,b2e41cd5,943190a6) +,S(c4d467ef,5149e117,3638a5ad,6fd36373,1c8906f0,80336ca3,3a6bbb99,1a03f33b,ea5b5b24,4c536bcf,ce3d437e,abf2fcec,431ad80c,ff975b63,bf398163,629b5c7) +,S(16b577a6,5f6d09f7,b23b2b7a,dd80a2f1,cff7a8a6,c36bfcf9,d325e37c,ea37326f,66ba8e2,14674e5e,228a6576,a52a791,84d98be1,db1a2dcb,e9073934,d09f15c1) +,S(ad4bcaf2,e480adfc,e1e45384,6bd7ddf7,67fceedb,d2bf1f5a,6768531d,9b63412f,51fa0360,47810f59,11b1b3a4,525ee72c,c4c891b7,56737f4a,a61a380,e9e741ac) +,S(b249eb38,52d2e787,4a52d776,d1bcb399,51ca65de,dd9e9dd5,87d73362,c33b571a,3e260824,14e4ece8,83cd84e,b177096c,62dd7706,a79c31d9,b1103232,53a66258) +,S(634192c7,696a01ae,81310d3a,59d2c53b,74dd0560,7e3be9db,ccfd1ec4,bde14a65,455b4850,e366e077,d86dcd70,9c787b18,4fd4cce4,4b92954a,dcbe5222,57b0e00f) +,S(ffbecbf5,d433f80,49e159cc,c14b198a,acc3c5ed,fbb1ace6,fd295dcc,4a2f5099,422e7aba,1ec66cf4,36489acf,9c03ba33,dd68d368,8a48685c,aaa1de52,440be3c0) +,S(65b4c4dc,1067e823,9cf4f1a9,d0632da,b6a8c83b,509a75ad,8c133dd1,5c1868af,f7cf5d9d,d7654618,5183f8ae,7f42a03,20c67817,9d5226d8,40dac1e5,f94d260e) +,S(d380ecce,9d603502,d518dbed,405b8d0c,8de48dbb,35d5b559,24c1a560,9bf9c67e,1ae84480,fd18ab10,9eb0ac15,265c609f,8b241b4d,a80b13ae,50c35f8f,db64c128) +,S(17189d28,b5ce1bbe,d78a1d96,15dd1a50,3fce43f7,19d042df,63484ff4,ce44511c,fbca28f4,7c7b3e39,4121b948,ba561289,85c53298,8db2fbb5,7596a473,a782350d) +,S(fbe332c2,e2a8b07d,a85ae4e6,1925bf3d,be685e4,fafcdee7,3f558382,80c2e84d,aa917342,5e187da0,e3f8c6d7,79b42cbe,b11c43e0,6b594eb3,e1a5797,ea4e29ca) +,S(8b9e8a87,8b5e725f,8b4bd518,22e9cd21,2100d1f5,cdaaf210,2d7963b,a0bc834f,331fb31c,c28f56bd,5ff1d6ad,80b65702,b2e873dc,4552c563,bed77a08,cc3ed659) +,S(97e92411,a3c0bcad,17a798ac,eca61ac2,34e1a68a,b668aa3b,d730cc8e,8de111ca,b0f170a4,bac15e17,2e75fb75,93c21a41,4794976,bafc7eb,7cdc4bf1,6947f48f) +,S(20358813,33a13c6e,cc8c76f8,2c279577,49aa3c1f,d4d51691,9cd23b25,d044eea8,480afaa4,8c86af0a,ece2f951,7df0f344,259fc4f1,4d9a5c0,ee73c891,780c7f29) +,S(caa1eccb,1575740a,90155103,9849befe,617579e6,22b7c343,a665beb7,a67dbcff,aa695bf9,f1c972ff,b6fd3451,1bf042d9,1aee5113,9c1ea577,e0bd52e0,a4e0a20b) +,S(8e7c2ba2,36f7a8e,fdaa212a,7fd6b883,f331049e,6e8f2bbd,138a3adb,c2620719,bd03702f,1434fb3f,5846c4e2,e779f8c0,d9b6e031,1feced02,20a618f8,2eec105c) +,S(e07dc033,6dcd04c1,fcfebf09,40c07783,88fbad11,8e4eb3b2,4dd637c7,baace975,b13bd0a0,e5eecb0,762ccf31,1bd53156,ef6f9268,50044195,10d6616a,b32a2c2c) +,S(6606c825,2679af01,9d8a904,4db0b28c,95aba791,d1c33072,97afa2df,bb8ce0cb,7505e59c,a9807993,5710de77,747868fb,10fe6c57,36ba2054,6477cac8,8e1d3cc) +,S(9fbf4cdc,ec48226c,b45450f,b0de5dae,2b31f935,2b99e0b5,22ab9935,1de6f061,f2e4d0a2,3da020e8,60a0d58a,2362b7dc,e9c5b646,7034ec91,a7dfa601,1ef850dd) +,S(e06d697,5195ffc2,988b0403,e977d32c,b7cc8167,e800db1b,976f6186,286916bc,8015370a,27d3d221,7af80e04,a49003ea,68302bb,c1a5c83,63244c0b,c30bb8bb) +,S(adcd67ab,21d2aac,65112fd4,e6e16cd7,ff792577,e9785a6b,cf4a3f0a,9293a6e2,6527b620,29062aaa,5058608,f5cc3bad,8e4f40d4,9b5be93d,faa5c2b,57fd7fb8) +,S(1d9069ea,b43a64cb,1187e963,d96809b3,5a447317,68910e13,3e0bf7a2,e1f2bd38,ab03dede,854b8fe9,4ad2f9a6,8ef5415c,fc78c28f,a4ec33bb,f15df31a,91e29108) +,S(f1f6b776,b8ec892f,148168ae,8ce83f4b,603206f7,2a38140e,3a422e67,a20a768,892ba036,3413da21,17d9b11a,7bb25cd9,e7136a7d,82a7f45d,14abfcb2,b9bff25a) +,S(a884f94a,ce79f4cd,f3a8d1b,f8a2dc3b,c21d1c23,433a7fb0,401c5df,1efab379,5f53356c,6e45248c,ec282fbe,ef03ddf7,c611affa,5d0d3082,dd630f80,dea05c96) +,S(b1988430,197a8800,e1016564,b48d4f7,1fb2be08,35e9efe9,81a80f10,e61da9ff,d5c7864d,ea7d12d2,5be7ace5,86e141a0,e515a41,5ec70bdf,44a68d8e,4dd849b9) +,S(15b73aa7,529d5b84,bd5c1db8,2b6c93aa,46985aae,942f6d4d,1094434e,d27fedb,297e32a2,bc8ad13c,42011259,b1ca3d40,632ac6de,f2fca262,75dabc8,ee721f89) +,S(339a76e0,443c1fb1,65992630,116e523f,8e35cc7a,16cd0f3f,57f7782c,7d97d40f,8990652e,fecd784c,33e75620,13b52e6f,914f0f6b,c413aa22,9e5bd773,cdfe9659) +,S(bef26cff,fb80ddab,9458312e,9b09044b,b1c535e1,84f4e51b,f64b5183,b67adfef,3818929a,ef076a83,58f20518,c5b310f5,2c6943f2,1675bbb5,ba1bde45,9d37490b) +,S(cdc56c81,8dafc273,4f4dae10,84f91b08,3dd40d86,23125894,c71d9243,8b2427e,f4b309d,e9c828b5,44542569,45579f91,b4376935,3f586c71,f07107f0,1f503cca) +,S(3ddefe81,b1f38479,ec9be80a,1961c5fb,a09312a6,2a775911,cd65200e,7d75bc6d,75d83edd,1eb9b479,4effae4e,ba8007d2,7c7e2d51,a9e95d3,a1e58358,56df055d) +,S(da7c6776,99032cbc,4c2bae12,59212cf2,a18879d2,63aaf99e,76339041,10576826,2e7a6d88,360ac45b,9871f779,9e80698e,4314cc3c,3f1cb1d0,c07ae9f3,38553f08) +,S(2611b435,e0bc20c5,88cfaa80,17f4555a,b8aba4c4,ae1c0385,9dfaa911,aa80d927,eb58f81a,e51dc504,465ff8c1,c0529fac,e47549d2,429e5b41,7ce0cad3,7d4508d4) +,S(b0fbe548,36f07c4a,a715aa08,806b71d6,b8f4c09,6945a7bc,3defec7b,67962961,cc60a224,66e7744d,c58668f,ede30ca2,1c1749b0,45ee50de,2a881a53,83e5abe0) +,S(1a03336f,dc51ee75,facb7688,b4603c86,77d371eb,5ededa9e,b50bb49e,c9020581,3fcf1b03,9c0edf8,99855fc3,6acfdbc7,bd507145,9be7e18c,e9f715e4,98daa7d7) +,S(763a1215,c8349155,aa849b20,f2f68a36,cf72892,49e4d3c3,810ee72f,78c159ed,37826a1c,cf30e1ed,a1795fba,d1f2f227,7b68d5c6,9ffd390b,d7dde5e6,58482684) +,S(7fc7b4c2,30183e37,dce0a586,a6f0188c,f7e664d8,5fa05eff,63f2c27d,cada4edd,fd7a780e,6ea89a06,f0649343,abe7bcf,6338d2fa,fe457f50,ac415c91,2bed6a8f) +,S(222807c9,b0686f55,d9eb7d7,412588f,dc543bfc,f016c8d7,74726135,dc65ddd8,b9670902,456c22ef,cb36d155,319393da,9a34b2b4,301c898b,43d957b0,a56cc2ab) +,S(79d8eb36,98d8d06e,6ca33f69,ca04d3c6,db636346,abfd603,ed0189f0,fc5fda77,bffc97e1,1b0234a9,8dd1d460,e19db522,931fd49e,26d7ab28,f1326517,23d955f1) +,S(a2366618,8e72e1b6,d5ab7713,decf6e3,1f801a6a,ac88ddc5,d464d127,ebadd34b,ef23da36,f3e71913,2774cd1c,d150ffb0,70e99ac8,5193faeb,b1736abe,77d60ed1) +,S(b6bad04d,dde6816d,9123e8e7,43fa46a5,b1fcbdb3,fa1f13be,480fc1bb,49dd9612,585fae09,a290b273,a68b7f34,645b80b1,850c6507,d959b546,7f1b0100,b6a4e511) +,S(2bf21c25,3353e715,283113db,8bb5018d,33fcbd58,f3d6face,b491e1d2,f4c3dfbd,e3a033a7,4e8a4d5b,c8c49121,43a47b07,b9fec4d8,a0d5b3ef,569c44c9,cf8d896e) +,S(64c27a41,e978e35d,63f3a90,e71091f4,41e9ad26,6a05edda,358dddd2,5d842744,fcbb625e,8fda695,988aac9e,cfe67c16,bed76802,3b527d27,521c1339,3dae32d1) +,S(620a1ef6,fdfe5b5e,9a4ef435,63cd7c8,af62acad,a02fb399,b7542d2b,6481a58d,b0b79e3c,550393a6,fa07f105,c547e203,a45fa7c5,ec825ae5,7bec305a,ddb8054f) +,S(1523f131,7cef7154,347ef68b,424ee0c6,15e71251,a06bf8a1,ecd74675,307b95cd,c72554cc,1d8ad664,dc1fe67a,3f11e5b4,a55806c5,53dc2612,bf5516ff,f0743b1d) +,S(d765303c,a9c8794,c00d4d8c,2cd73fcd,b43f763c,b753700,f66d7294,4eea0cfd,bafcaca5,204dd77a,a3a17b73,da3064dc,35b4cd22,ae01a623,781603d2,57bc267b) +,S(a75eb61a,fafce965,65198759,c25cbc41,ffbbf87b,61839a8e,a17f04ad,64c468b6,99802893,240f48aa,53c49b18,1a6d50e7,a8eba321,64d587b8,41497d9,65869873) +,S(7fa41b4c,d0bb91b6,c25813c7,1241e691,e7053f7d,beb0bcfa,4084e06b,bce59f2a,a0941779,755a695f,8317e7e2,f6a2c57,9431e22c,4aa09f,7e583b1c,e184aec7) +,S(816c0db7,2240f12a,d8deb440,8ae2276f,3bfa1bfb,d820bd6f,cc5ccff6,16e4dbf5,2a52c93d,d91ee658,9449dd4b,bf70255e,e57acbd0,a981ac9f,67c16604,3f7e52d0) +,S(33f635f1,317f1425,51390ac7,346905e0,ddbb3d87,b0c1780f,bb7dc950,c23414f8,7435a155,84eb1988,b974d570,bbc2b2c1,15123580,2bf93bd,b626a543,e54bfbcb) +,S(d2943ad7,4b0bb03,35307185,fbc438a7,bdfe11e,7b5e0eb3,e94bec46,a251999c,2dca8fcf,19aaa314,ebde41de,fff6e9fc,b6097d6b,3bfec06f,19aa4941,676d577e) +,S(26aa1fbf,c54375a6,fec54390,b5e44a0c,fb524b65,c10d1516,b0112525,9dfb1da6,49eceaa6,4c575ce,337d0b6,ee7e8198,83973c6f,abfa2f,d4b24e03,99a91b02) +,S(780aec1a,f866a030,5ca6d7da,1948f2f6,ab18717d,e82300cd,65eb58cf,a7d28d20,da650041,e45a0e1e,a9075b6d,107b6f7a,414b3a02,18aaf929,92cf2978,bc08b91a) +,S(1dcff259,8e59dd4a,3e515853,b3cc41e5,ef98113f,29ff7b3d,5eed6d50,2cb88b67,d7978630,7c6871e4,5654307a,e3836e07,aed86cbe,a9ab92f2,8c680172,1ab77271) +,S(b19af4a2,77321937,93e367eb,5ece1c63,8f336f3a,9cdb4b01,e2488ee4,373ff70d,a3ea8839,a5105a2d,4277f27a,26a8ee73,b9e73fcd,d54f641d,c214d5f7,9c821dec) +,S(1c8c1f29,548a9df6,f28b6126,b9324972,35f24e2d,a488e066,acf782f6,b4f6755e,1a79ab52,6a1e1aec,5ccc7e2a,3196a07e,78108b23,a86630c9,1795ef96,11ff432d) +,S(b6ff8dda,1ad6c3c2,3c8a10b7,b4313968,e4d70075,12c421d4,f0b1153e,bd5716ce,4d3869c6,b7b74167,ca0d21e4,edb3e01c,af8dbec2,aa87a32d,7c9306f9,a5ce61b8) +,S(dceff4ac,f61ba84a,81821932,9fa0ad60,ec08cf9d,830e6ccb,375488ce,d0f47b5c,949aece1,92bc61b4,883d5508,aa4a4aa8,fb1b8db0,385613b1,736a6eb5,c137d6f9) +,S(5561e7a7,b709689c,97c4aa18,9a3ce841,843ccf98,be851c8b,131eeb37,dca5ebef,4b108c17,f298be36,430e6b7f,26b414a2,33b924a6,e65dd5a7,9a1f15b,a99a14da) +,S(4d989577,89b01595,8e5d5bb,2e064e9d,9c56a254,5b3c8802,7ca0c997,a395a257,aaebaf33,ac950756,c5b200c9,f5b009c4,506964ce,5b706675,7951f221,40b6e0d0) +,S(82b58e6e,6373c4b,30ad55a9,d66cc804,e9da512f,bf4af668,1246a12f,e33bfc8e,8378122d,98dc1e37,2c33b5c2,1ff4c429,d6d7577d,2ff353d3,87cc0478,1a5ffb38) +,S(f49fa88a,a773784b,fe57d880,9efac44f,714c3d75,3669463a,d1199be8,2c6cdf3,41aff6c0,2164a411,c8be7281,493483be,aa9855b0,49820772,b96aa39f,9a18b3f4) +,S(67d485db,ac8445a1,8c1b97a7,8c1852a5,ce910f0,d78b073,969c58ce,c0efd78c,71dda92a,24ff2b31,5fcaa5a8,28bf07d9,596f49b9,cf19f4be,44e6f320,84981e97) +,S(9145f6f2,c19038c3,cff99883,b5a71760,30a46f7e,8b5d350a,db2a9610,4704d4cd,9d9179e7,852ac5fe,1d4664d5,4d778b3b,6c8e422b,b6e78add,56700dbe,6a22b0bc) +,S(492d5247,efc2f5f1,1cf3848c,e0719abd,53674089,808de4b3,5503e23f,46b2631b,374b0762,7812c898,7ed68877,c995a4d4,9f021d0b,29270863,d50b8c40,808fd750) +,S(5b8ddfb8,bb811678,9298d231,72bdb9c5,25c6610b,46187549,a381ca6,17dd1dec,b47d3764,fce3218d,17d0dee0,133d4f3b,c7ae170c,3e8831ce,a92a3531,7b1f7568) +,S(88db73ba,25a61641,af5e603c,cd54c6d4,63c6feb,da11ec5c,6a35d30f,e406c65,39b06f7b,1c1dd7b7,884c67a,e295f8c0,9b8b5be1,c14456b,4027bf1b,4800a753) +,S(3495cc9a,a23c1eb4,2cd85070,bb095563,2a7037bd,e330f721,fb38091a,9c382451,7feabb21,6f3982df,74429957,3c7557bf,b82ff4f,462fc64d,d9b3e10f,b69799ef) +,S(e8a5cea6,970e10c7,93f75666,9d2309b1,a4f7b52,c19db4f1,cd69a652,c445d7a2,daacdabf,bd5259bb,96d2dbf3,668e8c16,fab47624,294d9982,b961f0ea,32402b96) +,S(6e8c78a,e81a7ade,3989c483,7d9efe50,51af33f2,b2b2ee32,b5700b43,67931f9a,e5664504,751b41a1,45b5412c,be10a782,7d1d5193,30dd69ca,47be2975,2c291d35) +,S(b8f520a3,10c5b2f,8291722b,1e3a92ec,b9551db7,744dd208,ab4d1709,310a539e,65901c3a,b6712ded,8f66451e,1915113f,a96d3d1e,d9074790,9e291d00,970f3d75) +,S(a0538458,64459815,888bd917,3a2c16fc,ae0deaa7,cb804adf,e49dec0b,b2d8005a,27882f00,23dcc9fb,890dab73,f98925d3,e712608b,3d6069c8,ca58ca6d,de0d7a67) +,S(41280416,aa7f0924,1ed8b631,fc2959be,2117cf03,9c12f600,1faf8a05,15222144,c2fef80d,fd8e8433,ee55c363,c43f7e06,613f354e,32aef8e1,808817b1,af7f58e4) +,S(c4b8ff36,cbf83d10,51d130b7,e3d613b2,8b536f0e,b050a41a,7dd8f8aa,18c7a1ee,87d3c44c,8867337b,466ba76b,47512399,f6cf6c14,ad4977fc,276d67ec,5e7b4d47) +,S(40eb693a,7cb938e3,a6b85010,6b7cd257,1de630b9,86da02a9,3b7a7f5a,a0a51ac1,27b875e0,14d3417d,cbc3b770,c4cb8805,c7ede7a4,efa9f89f,a51e36c3,af6d8d18) +,S(f7491902,54e30180,75365d67,5f2ddf24,ac0c9d84,df371fb8,6e94a9bd,7f81dad4,6a271b36,c549080f,dc9bf1b5,ad275d62,68af0cc7,2ec68c7c,17ac24cd,5c5a6e46) +,S(cf13261d,e4ce19da,14e6996c,97a23f8e,f16388ac,c364f2e3,6a053254,849f287e,5568858d,be1a7447,f7e4ab51,bb872a78,8218c483,c771ab7c,4a0a968,73adac10) +,S(9c6bda62,9dd087df,d5516606,62226847,94cfd517,72c72a81,7263c761,ad3e8cb3,2c77dc7b,9c7fca7e,bb35628e,d62ffc79,9e5fbcc5,e25bb0be,5b1b67a,10c0eb3) +,S(d8d1035f,64439dec,20ecc9a5,5b314959,c1526d7b,d15b1922,bb7ab7e5,b9d26bf3,ab7e34d6,ccfdfea3,f607f697,b941bbf7,b922a436,b9cb4314,3eb1b948,ccdbbe30) +,S(c6f40a23,b8227a60,de32e104,7080f087,7d53aea5,b00a22a9,39cbc228,d1c1d424,e16bc58f,cf4b8c5c,9106f1f4,b8b2374a,63a3136b,e5a8c64d,7fe6bd0b,c1d80345) +,S(3a69da22,9477d3a5,7147c2de,cce22de1,d1e007cd,61d22509,49400b8f,63a43536,c79c4fd5,c4ba6062,c7cc95e1,c9b79cfa,46b98cd7,389cbc39,25cc2fbe,49a0e284) +,S(1b5fb8e5,492fc48a,46b7f6fc,a658f218,814c3d82,90aa339b,7bc7b794,325fc9d,a6290b12,4c9e0819,2b6f49f4,c4935b01,d2ca4235,8efea982,1646fbe7,dc7fff39) +,S(fdba0f02,b004b4ea,dc9e1c37,d1a7fa7e,8a755922,31f054c7,47bbe8ec,349a3845,42da61c9,e96471c2,6fedefd7,e30c43c9,6c3c09d,d72d662a,e2b82022,391646fe) +,S(c39391bf,cb7b9662,be7279f7,6338988,7c166343,2faf1760,f38f0cb3,a35140df,ea14e034,53dc82cc,484b8b3f,ff79d81b,449f9f81,d7a52d66,4c5b563c,9af556e1) +,S(254ff13d,c716cb2a,1ac0e36c,c6cb20c4,19aedd0a,2219321,675e1744,859cbcb,2644cf3,916d26af,9e36bfe3,247f5be8,896e02cf,83eb3701,c400ad2b,92e35921) +,S(24e4aa60,e9b464ad,a2c8974e,98568026,1769d35d,aa7c8c5b,71c9f57,28930474,9df7c2d1,82a94fe0,80a2244b,ccc9406f,6ed37c38,d9cbaaf7,8d973538,e8479f8e) +,S(7ad9bbad,f906685c,3efd81b3,8599fc02,fb19a4c1,8bff1ef8,702c4f6,d17543a6,9878b970,9c4018a4,f713ac8f,d8a533dc,da45e243,44926df0,133aad64,c5246f95) +,S(97d8fcd9,383a8717,e0c9eb2d,f7dfbaa8,c6e08339,be5fa2b5,1d12565,62d8ae53,1879ca4c,f5784f86,7f8363e1,5d85afa7,b1f114ca,7f8f474c,4a2c028f,7c6a777) +,S(3e0fc785,5a08c32e,1e14d1a9,2c56ffac,2af1acef,505ed72c,b8771ddd,8afe7572,6d79b7fc,fd1e8894,f0844fc9,da30b555,bb1768f3,df15a0b5,884e5b09,6e149390) +,S(d9da17db,b132d864,1da3a9b5,389d6f5e,fda483e7,fc7577ec,55b7ecfb,65602562,80e471e4,5feb0d70,2ee7f9e6,3f8f23b0,33a4f35e,8a0841a7,b67f8c63,c623b70b) +,S(1848f766,afcd1e34,82935daa,7b71212b,f38e2853,9d6fb9ec,a3d9809b,6fca18f3,ca9a7882,645d54f2,49d35df6,3748ed94,5f9196f4,a93d4b7d,ee70f44d,b6f5884) +,S(ed3744ae,9a7dac76,5ad65b2d,4fc2d15f,1a9d0047,f72c6be0,a849ca04,497a9f2f,3cf76d2e,d4e5c6f7,e4b23d03,23c477ef,2fdc5248,7066ef36,b763444f,6ab5fb5b) +,S(c4607b73,edf3545a,b10a3a65,e0312707,91212acc,a86226b7,b1ccfefe,5f3676d7,31ad465b,8595f783,d5c0cd03,6230e3dd,2628ac9c,45dc6d77,28c42093,3d7eb3ec) +,S(1c0962ed,2aaf69d7,8b20af04,93a3fa50,bfb9ad1b,64eb0699,641e4b0a,bc0e96f0,49f11af6,e088e3a2,a429c5b0,a87a7f6a,591b5a60,a397c123,2d56a4a,adaede44) +,S(6a0476c,9a41959e,98dc6ca,fb7b4381,82250e1a,ae62445b,1f09a098,ddc19454,56842c97,8ae3c4c9,2c266cd3,7c8e3514,ab4288b9,ccc7e33f,be552ec6,f511c7e1) +,S(24da0f6,53a30aa0,a6b14999,329f03c6,cdb59a80,e9ca68f6,b9367830,a0191f1c,83e79080,aa78bcf5,b810683a,f061c614,cdbd3b69,9e200b53,d1a2c757,2c138235) +,S(6c3483,22479d07,f5871901,3264402,a078728f,227c75f,6f33743f,9a1a7764,a377af74,4a125408,6bf128d8,45bda458,be779210,f0d85bff,eb192c0b,a0dcc4c6) +,S(212aabbb,4d14cb26,b26cf249,882b36e1,1cdc26f4,a1494905,15478f99,d5c43baf,e9140a0a,81d1582b,98eed57d,7ba8e584,11c22ea3,fc265148,ca1d6050,3847e281) +,S(a27478f1,2afca20a,8d46824e,5b0ba272,f26ee0c4,24a951ed,f371425a,b343b10e,51e74b86,a7fc97aa,5a3bdecb,67818d7a,70ad0ba3,7c7cd759,8ec80a4b,bc4036a3) +,S(e1c1269a,7171f9eb,a2e2fa7e,8f55e0e2,b9b8a507,e8cdbfe5,716f711a,572e293,41cfa170,8953242,f98d8e24,2e827684,5562c4a7,6d034848,e639335c,32afba46) +,S(204d544c,19418e19,bb328e1,ecc0fbd8,62f0f78b,24208780,4d5827c0,f5e09efb,c66098e3,1f5d1587,10a3799c,b4f980c0,18cf4ed4,534e49f0,6d057059,93d52fb7) +,S(16eddf0a,11a6f2f2,df230de2,f78b4cf0,980138b2,3ab196ee,361486c5,7a5172ad,e3db358f,ed8ab3c1,9204a792,6102c420,1327bdb4,fb81718b,b39a0ce2,b5992684) +,S(7c9f7831,2298d96b,65e6b7c1,2315379,3df7001a,79cb080e,af6829d3,2b8995f1,2037cc3c,90e3a0f1,b242018f,c53cb32e,b2481dd1,bbb700e4,a6019546,edf51e5c) +,S(129c2d46,1dbeb8f6,c1b913a5,b2d69602,63aee7e9,530c6dee,21168b16,6198fb1c,29ffeeb9,61c027f9,a2a14b72,a287d566,7bbd80bf,7cea0dc1,747ac25f,55137964) +,S(8be2e565,30d4932e,f6d1f9da,a3225b52,de204927,e0633b12,570a049c,1f6175aa,364b4e87,1a130cd1,40007056,e3c0951f,fabfe4bd,6a687404,23cc1800,505510c8) +,S(40b43f08,42ae9c67,ab0ceb62,453b4c41,42a6e12e,5f880c5e,27c90997,6252fa6c,6d1ac6c5,de1b2e5b,b225e46f,2c5a2d2c,248f11fe,d123ecca,4432a04b,cea2068f) +,S(47e2238a,2f34df3,cf1caa55,93c49db5,4c2cba9b,e3724f17,87473a0,5ac669df,4d04cfa2,3ee255f,eca104a3,60a52f7c,acfc6127,608dd908,9399be82,9cf31f3a) +,S(17286c55,3a45c6da,b4843323,84c565d7,b3de474b,5df8ed60,7c7a5c9e,e1cfc35a,6172d347,75a45151,60b104b2,79543107,5b194d24,793340cf,6d8723c9,6320007f) +,S(3451af9d,3c1492ca,d090bd34,45632ac5,a3e96c9,4d9ed258,b7fb2042,8dd7bb31,dd493383,21236e06,e7284fd7,84c1a3b0,7687c513,927cc79a,cc5f8b41,b14974d6) +,S(b00aa481,eccc5e7f,cb5bee2d,a6e0ac44,ed9afa3a,5b2a9619,d23d0252,14e5ce2,687b486,1f0032ce,f42ceb7,441f81fa,10d732a9,e7e76242,4a2ca8fb,e88866a1) +,S(53ec8e9c,c75bc91f,f248a239,34d735b2,ef706d4,c0761e2f,a8a55c7e,a0b23311,1b11dfc0,63c4b1ed,1b5104e0,15d5c5a8,c352f54b,9fd82768,8b5104f6,45d45919) +,S(1ecde1b3,9c072c9a,3b3eddd8,d71e3383,2fc80d78,7abb70a4,cdc9186c,a5efab66,4f5aec7,5a799762,b70cecb1,82049cd0,239f0c30,948a25f3,daae0bc,ae6dd626) +,S(1fe2fc3,702b558c,7ab9b479,fa08efa5,1e90239d,677052e6,5afc8754,9bb1394e,f6b586ae,3a395d3a,c216df2b,66d48fe6,11a64c0c,8a7db26d,30fbd720,c6845c2c) +,S(b53d0b2f,b8ac2ad5,582ba0c2,f031c7b,76e64cc5,28a5b9ba,872718b1,e06d5dec,8984e589,51ab87aa,64bb034c,17d23252,4101577,9476887b,351f034e,92e3a289) +,S(54e516,3bc2366,673fe5d8,1f335d81,a06ca310,a2116ea7,bc0ade12,8f37cf95,f471c826,9deb2c2b,f1b7206d,6e817355,9236607a,4b9930b4,c5b3a781,7312bd4a) +,S(e7efb772,a1d423a2,d39e2224,4c8bab91,3b8087ac,65d51f59,8c4db283,67b29a7b,f2dfb586,31d08b0,bf2b47f4,17f6a18f,704a39a0,a152e3bd,587e45c7,93a9b6e7) +,S(5ec59daa,e8a263a8,2afb4309,79ef0321,b163f2a,dc083e67,3446b98,d0b519fe,2eab4cc3,6a3deae5,30dc6aab,94e5584f,a8a5316f,5c05b04e,84215ea8,79ef82b9) +,S(427b5cd9,20589dfb,dae975c8,efc1f098,1119f69,c40d1216,58ccb903,d4bb62f5,d055e6e3,b8794842,4162803c,35fca878,6500b5a3,6871b18,d9846866,56d1213d) +,S(54954b15,fc594f3d,8f422c7,9dd42cb8,2cc30dd8,c0d10736,554844ef,9d05bcad,86a7cc65,73569c20,2aff8e04,21a00e4a,9c6b88f5,ebcc3975,64b4734c,f735373a) +,S(ff6f8f8d,23670fbf,2a1aa7b3,39568653,573eb480,67a2a1f0,1b55a1e6,b1f32559,7a53f1a6,c7cabc57,d731552f,9fd9447,36cd33f4,3f8f57cd,2d4ac1dc,1ac7e218) +,S(74d725e9,9021c210,e82d852f,41e0cb8a,3bba8efb,8a01552b,8420c265,958a2381,4ee69646,aa9f70bb,883d6ca4,e1016dd9,92f18de6,26ca27c,aeb5854,f5bb2bb0) +,S(e9439f7e,fc0342c9,c2d68fbb,c58d85d9,feca0570,d77448d7,6d3c3251,e49c845b,27da0d98,1b7e257a,eee90b45,9d0d7065,566667e7,a9287592,2031be02,3e233916) +,S(9684a48d,81a60856,6dd26622,b3ffd133,5facb32,9f2c4f1e,2c055cb0,a5c0b911,92038ad2,50adfbaa,5d587c31,f5e7b4e7,294bbd25,e7af1816,1be3532b,f24e68b2) +,S(1d003af9,469e26e,c7f0f121,4dc58728,9e4cf837,5f9d19b4,16277c97,1a0e7609,99c7c3a5,30822c72,b31dad8,146d2604,ed795f1a,7c37e139,c84afe9e,f71e5123) +,S(f96468f8,73cfaab7,76c32fa5,89f72c09,d680abf,c601642d,1c649ca,e197a149,1ffb4bc4,8495d31,b24a7ff3,353857e3,b6708186,c18936e9,9793e4d4,fa083b1d) +,S(b6ad4106,e30294d2,bcac86a2,131150bf,d93c14f6,51ec65f5,32904412,b3f89d32,19a366a6,74279641,d055201c,c4c42b43,4fa40792,90c1c3ee,5db2a4e6,38d228ce) +,S(875472f7,190bf305,9120fec3,ebb69fb2,2d47828,6cb1c108,a977e7cf,e45b9b9a,1adeffc5,f5dc59ad,e15d163a,95f8049f,a172d8e,30544562,50a7898,55a97c21) +,S(5445a9fa,f4245414,e64f7ae2,a1cb1b1f,54bb6fd5,af4a7407,4d9eeb05,9a27a670,496c5207,7da2e082,3e48978c,a3fb7a1d,3bdf07ea,61fde94c,e87741c4,e9418018) +,S(dae18625,704bac88,51f35026,7856830f,74d3a8f9,7c1f662b,f4c4cc3d,7814d138,abc059fd,7ba90619,83988ee6,35ec835f,c20f62fb,c68e2bff,373bda91,3be6f87) +,S(8a088f12,e8523de5,c7ce659c,107e1929,3d009b81,1fe94d02,deeca893,9d9845c9,4251212a,fb8ebb76,5d2d703c,bc18b208,41f8df47,fc5e44ba,ef7b0f76,7e29114a) +,S(d78f46a8,8f3b08d1,334ed25c,78f57910,716755cf,2bceaf6e,c25b52e4,d7af6d01,eb1855f2,29cb2010,f20b3f01,9cbf1b2d,929046d3,242446ee,5c9526ef,5b06f44d) +,S(1e0b4312,78ae0e27,5e55c4ca,cfefcdd6,f589809c,6faaefa8,3ec0d5c5,f99b034b,f38c53c5,544d3ab4,2ebd74ed,b8348503,fb523fae,9d73657,8bba2881,904918a7) +,S(f03155b2,9edb119c,f411f14,4a588f34,ab02d7f7,c415638,cd534465,ed7cbbd1,72d153e3,ff4fff14,b41d07cd,31960565,31736749,7f9c6495,599d3f06,b8e85813) +,S(f61fd68,3edc7fb4,d14c84fe,3416654b,8df66578,6d0bab41,53a96e39,e5de4c8e,952db567,cf0913b1,885d6884,d260fe4e,e11fc139,f58da12f,d38472e3,d42e5f92) +,S(78310e7a,29e437b2,5cb00e3b,13a4d86e,1ede6d8,4b1f344d,7ee9c7f7,e017dd77,26ff358a,4d5629e0,4c20f700,97c202d4,7030bd3f,43134a51,a7d101b6,e182f2d2) +,S(63ae8c4d,6b7329cb,a61509c2,d0b61ebf,4e6ac94b,c8a096b9,7a4027e1,1f781a3a,a8e954cf,bf407857,d19629cb,338a93a1,af16c929,ef8b96ce,2e483e95,dcd14f88) +,S(948d592a,594b354e,e2d03961,6338574c,ae662f26,ff79afa9,16579725,7cca739,37ff98e2,5ea0396e,89d3992f,773bd6d5,ce02758a,4ee25557,edc867b,2f1876c) +,S(653cf16f,a3140368,50b04de1,8bfee880,660a4161,4dc67a55,398e2d34,46100f45,acaaaede,5ff1e552,6766741a,ee43105b,ea4d3419,3e615c36,49c1db35,125a9202) +,S(46fb6882,8a5edc8b,f24fd1ee,e6a7789,141e1888,64508d2a,f3c511ff,8e8cc782,9d4ae53f,d52ce9bd,6ac9ff4a,e82c2e36,f4d26698,47ec90cf,ef383e01,37fd8887) +,S(5f11a0c7,23ea2a71,7c1face2,b4b0f28a,4ca44208,7a2ae0ea,e24c2005,7138c0ed,5ecaec84,ad97612f,ba7925dd,f126e4e6,3906eacf,6f991d5,bb273316,b80c8452) +,S(b9f49e1c,929bef7a,6d6b6b3b,deb10890,dbf2ba3b,3eba62c0,320bdc84,c2a9039f,98729e76,7e4f8b7b,bd0ecc1c,534aa030,6e1b684c,6f42d15c,2bf6820c,b501e558) +,S(ec8a102,e7d2905f,f273eea7,6c9a4608,965dc2b0,3631d2dc,63c38e72,15ade2c3,d8c899e7,242d96cb,49383686,8f671612,706ffe5c,368ccb6d,be5a3edc,f74371c0) +,S(107f02b3,c351805a,6c92a3c7,742a5259,582c5b0,39cf6daf,cdace604,2be236c6,517236bf,1ab47601,57d74685,8dc724a7,c5c2d55e,82c4a3e,685f389c,a99bfb9f) +,S(f0fb14a1,a5c1c016,d7b8c1fe,a8317872,b10d637a,daf6f6cf,b9860653,56298971,e1d9ed14,d33e65d,4258e87c,7280001c,c40b89ff,b3164337,92fbc547,964540d1) +,S(a5371adb,ea784ede,f6cce83c,ebde068,78a1c80a,ff83b47a,333f9b35,44489459,f5780572,127f5d74,773acbe7,b2a22cbc,7e3d09bc,ccd13edd,48ece3f2,c8129224) +,S(3c031e5e,1b0ba576,13c10971,5fa7d92e,2bbbb817,9603d3b9,99e4fadf,be17300d,d275a3fb,392036dd,474e65a2,cd7b6cc4,79cb40d7,1c363e6b,bf9c272e,ae9c83f3) +,S(87b5899e,685db530,a0969a68,9392080d,f8a1b9ae,523ce18b,2171c69c,5a5318f,6ae3204,e3f0afa5,a2d40b01,a42e84d1,1b1166fa,f99cec08,1f5af48f,fda775d4) +,S(d9f077dd,c002c16d,f9d8eedb,56b7e7b1,ea00d04e,3fe838dd,2ae40501,9b8bf74,6518d51e,503118e2,53cfc486,f70cb9ee,11c27302,ee5512f2,78f21265,af3ffeaf) +,S(9c09ab63,8d15acc9,609ce305,32277f63,7558a492,aefb98e,c9bc721c,f8921af7,b2cac58d,535abc10,8bed6ab3,165225f1,bf2f84a,9fbdf3d9,1caa4b79,e0f6fc) +,S(6ed1ef8b,4c2d9232,5cf8948a,5c369a24,52ab250d,ed0e48ae,1676dc73,9a8a7fc0,c1b7a08c,2cfe5154,fca74136,863da75a,5c6423bc,1c904585,f54ac87e,f6742008) +,S(882e8d70,154b7f6c,279f71c1,e2ba6087,cfc458a9,3079d8f1,3fbd3be2,506928d1,8949b22e,97c41872,9094ac62,e67ac1f2,8b31565,edbb3d1d,9b23a73a,6fe64131) +,S(708472a0,24c86ea0,7119d0af,b2509814,516840e9,fc23246a,a6da139f,b37aba52,9809b7a5,1d551532,a5b378d6,594a3665,3a8b057b,80cd530d,b7a53fbb,128fe5ac) +,S(3a44fad5,9a8b708,4ada1250,d8d08353,769d573d,71a225eb,d87a8cc3,af9fac3e,f29f4551,1250d0d0,a1974bf8,46124813,f9186e45,2d3c5c85,cb0c69fb,4b7f20cd) +,S(a3519dd8,e09e1bd4,160564c0,41c23362,36ba4c84,5899f90a,fcc370b3,cdfb9f30,64cff159,7c910711,d0199faa,6c74d08e,7150088e,34fce674,72dd3ec6,1b881d7e) +,S(5af16ce3,765f5c96,4eb3513f,19d99ff2,bea1affa,d68f829,1c4f0767,5cfcf1dc,864eb5,3bd711ed,4a842db6,b0164a78,511ff7b8,a87aa3dc,1f2402eb,a3815daa) +,S(1ff9a522,19cae5c2,5de1ec08,2641040,18848bd1,37a5949b,4021c2d0,563d54a8,546d634c,122276e1,b5cfb919,a5374309,8f85d7dc,149b14d4,791c83b0,1718e031) +,S(d7a6dcad,72a51ed8,f84926eb,cfab368c,7f02fcdc,aa66482a,c6b6dd6f,43d3e938,9a273cd6,3ea6ac86,5a68f378,e4466ae9,8598a058,6c97278,bde63b22,14e41c96) +,S(154f63e5,5bdccc7d,a696dfb5,2b6cd4c6,3c874b93,1f221282,3f4a8d19,1f32d797,e98f9722,17bca1c8,ea7269b0,d2aa6bc6,f0f29d7d,b340c67a,2df59135,77f76fae) +,S(f6ade08b,8513615c,ccd29095,c21bbdea,dbdbb7da,87ce9991,c27ec758,4c399bf1,98c81be0,19fccaba,131af074,b28a6311,3fc1c5ca,1318e96a,f037ad33,8f234ad1) +,S(9661cec0,3b2715f6,c6d29048,65fec2bc,b786b3f6,943a883a,3e51cb2c,c747637e,eaa1f7d9,9b34104b,74a8056a,9ec739f,cb9c3735,95f0b254,7fe75620,4f5358bf) +,S(e0a5323a,27d608c7,34c03465,f03705c3,480520cc,f5ac777f,53d498b4,655d19a1,1f727d78,a8b8c562,ebc60679,8462975f,63d88eb5,8e7cbaee,836bd629,260cc606) +,S(bab82efd,4646f2,f281980d,5250c6af,8206e95,dece4118,c24ce31d,282f6409,2a60b1dc,26a20126,8df8375a,5656c55f,cafbdbbb,46b7977d,137cd584,8d1fb82a) +,S(389e1399,ebbe958b,1806e9b3,ee51baef,2d7edd20,79e6a2c2,21e814ad,e1eb2631,6c158633,1f3cfe45,9e71fb4d,112a624c,e48adabd,435e6fd5,2c9459f6,ce9ae2be) +,S(b78179ca,c0dc553d,19f08174,7fa4511d,87d8961,1ba44045,8c307727,729d4515,7020be98,c496a50,6e4caa5a,94577d71,ce0a80c9,bb974c97,a6892351,e83e0de2) +,S(867ecd3d,d170f9a7,123d13fc,fd90058e,baa6a6f4,12ecadc9,f1e14d55,ff104306,3c0db3e1,bb91ee23,8fb27689,79f2b543,d698c5e2,fde48dc9,e2535e4a,946759bb) +,S(be71654c,26a1025d,41fd4d08,384b2ccb,db25bb2b,c15704e5,697be2f6,d4eecd38,316ed20f,c37a2dc7,a0af8d18,e4da0efd,2dcdaee4,44b2c1df,cdfaf6af,49406afa) +,S(5a8e1cb0,24d62685,e755b9a2,ad1e0165,41690544,7963dfda,6b6deba9,76e9079c,4c793173,743330de,7a8f4351,68dde95e,3889db2a,91de0a27,d088a222,f11ebba7) +,S(3bfad00b,2347bd0c,f13a761a,d0630453,bb884d0f,ae3d31f8,57216412,b82e6131,ef33c560,94157fec,3f7fe8e6,36d48183,71e3cbab,6f5b0518,96ebdb42,aa545f61) +,S(2447ede,684dce09,c896c2d2,b5c68cb7,60e02635,3b4f2dc7,428191ef,5d2c1961,ad38a82f,e80f860b,62b39e55,44438242,5ad6cb54,d6e7f377,62427f30,1ef7bfcb) +,S(a5eae321,eeb4b9f8,e8807e49,ba8de764,e7685f07,417c5239,9d857d4,8bcf985d,2acf8aa9,f5c1b7d3,2ad5f523,39e65595,17881d,48a7696e,ed3b1023,ab4def1d) +,S(97de995c,5337d938,3cca5b97,3ab05e8f,dc035e11,5c435251,7e575a,e890b13c,4fb2d969,2e308a29,34c3fb4d,c4dcef50,9202505b,cd891f79,e8f91210,e069e6dd) +,S(b8caf25f,a864918a,f803dad8,d0abdf95,25b70f44,546b1f3c,c6b1726c,4438f479,7c51b5fa,c0f56eb3,6ffa8c5a,76c074a,c30e2f36,b069ed79,23663da,c9c05c9) +,S(b5bc868c,1b96e2a1,b24f3001,af140107,b2cade8a,5b1f3443,44521764,ad07b2e6,8d6cfe29,4e929f33,d5aaa456,f545c33b,672a8c07,b214a6f2,38bba367,4938d639) +,S(5f51587c,242a3b22,10db666b,f2414c28,32ea2662,1f13f6e9,784a8a1,373ff602,2c3b260f,ebf20a4e,b853950f,99ccbb9f,1b39418a,66adb427,f5886944,8b46c858) +,S(1d0be0f9,5009a2b5,12a52e17,e044f3f7,4f08e695,60d0dfeb,822b4674,7a2bcfde,c3a82bc3,dbd81877,3783181c,f7b81ddb,a742c3b2,4f866538,9335ce4d,8f3a159b) +,S(3ef0ec28,b8003331,a6621bcd,6ce30ed2,9e0e62d5,b492592c,cecaf4bc,8d22fb8a,fe2c84ad,77d40e86,c92a03da,e43cc7f7,512fd363,98db0133,7d929ba7,a144b16d) +,S(84c29a24,a4ec04da,c76bef42,732a3648,f62f12b0,e7f0ead3,2ef9649,b7555fc5,e7620ebb,283a54a7,10eb454c,f22e49fb,929ec453,38e457ec,b18a7f0a,794f970e) +,S(6bba6634,e75d5fe9,21f40f4e,5f1c177b,a309cd73,107f1e9,28331573,eacf43a8,33ffe08c,42168243,1f086b44,12209c56,5b47fdea,54671a97,9d86be36,fb421582) +,S(13b67af0,51b0c01b,c49a6046,d9e5b6ea,488f6298,9559dbfa,47cf1674,6def0150,d0e8914b,1c1bf0b,5337cc35,d84acacb,a54add59,2321509e,e29f1d93,a0237608) +,S(161221bf,b5dcb62a,ebeabc94,6ccc4a26,fdf779cb,63640720,2c5cf13e,93af9300,d3fde2c5,dd9d6df8,70a66bd3,2b5213c,d1a212db,61aec7b7,2a49b7e9,2cf83b2c) +,S(30c5360c,c62f5846,3af60277,2b52201,7eda1fbf,866dc3d3,9a590bf8,e2eb508b,c8e91af5,9b9a2b,8837dbe8,edeac615,6c30e8c0,1b7679f0,1aab4a81,cac44efe) +,S(c0659a7f,dd9151f5,ea67f38b,7249727e,640364f0,87371007,a38b800b,ec3576,a6f648cb,6fa131c3,5458b5a7,77440361,8c57faae,1ca33ded,648f1601,a5cf47e3) +,S(3215224d,b795a892,446472a,8e1ab1cb,7d50fe95,a6844be,43e2787f,2679386,25750662,97f28d86,690c7eb5,92cffc5f,faba831b,efc3e38c,c5e501f9,358a9bf0) +,S(257654e2,a87a7048,3bd15445,da5c554f,fe776264,998975b3,b19a68a1,a1871145,fcb9319d,c67f14f,9d7fc4ee,fca05b18,9efe2430,96691043,9c28c88d,32636ec5) +,S(a4786a01,e504f154,f3d7926e,6e6908a8,17c8a66d,6db33e80,ce98b17,82f1b49,576e4d42,fc2e4f9f,e81a2967,8b7cfa7a,7f86e8e2,662afbfd,b028612,d323a2fc) +,S(5140f7a9,260c9856,4493ae62,a8af369c,90b484f7,e82e1e38,3c5a59a6,62db1e71,4e5172c2,b0879dfb,63a6aa92,cebf9153,94ddcdc0,985261fe,2f64714d,350bae86) +,S(f559d60c,f0f50b7,9c7d6d90,18a579d7,b781fe13,5210d342,31e6cf32,4ca66dfc,12d9ceae,8e5852a5,ca95fb56,abda8e42,5f1f05dc,ca29e08e,2052bab0,8d4eed15) +,S(88907ff5,fa2d01b,c970e0be,53a05354,a4fb73df,9a337857,cc869a1,b0547e7c,f5853b56,cc1211b6,427145f2,6fca6aaa,5b26401b,c00db73d,ab9157b9,7fa3d2f5) +,S(cc1e4bf6,4541506d,8e91fba3,1e1d8ffb,c8ac82f2,4def27ec,fe4b3ea6,e58c45ca,7617497d,a875183c,684585a6,306956d,1efcf1db,2753fb77,5902a63f,38d27592) +,S(7ee2c437,ef744210,5b6a6f9e,f1edde01,6c39557c,93454dd4,eca10daa,cbca99d5,21754734,5eeff5d9,f30503f6,9515da57,3e6d7b70,dbdee5b1,8274968f,6f3772d6) +,S(72feea2,39f9b4a9,a3f3af3e,f6bf420c,3605ba4b,b42da90f,6539e05e,33e2465c,a036ff,df7adedd,c8c2ad9a,d029428c,85482cd1,6b0cd20a,36d2aed9,e9f553cc) +,S(363da33e,94a0dd00,669b627c,4d7a3a6f,c8a0cbae,2641707c,938c8f5e,99914a,9bda9a77,ef1307a4,e236099,c1506f47,a2f936dc,d478b59c,3d0e98c0,7af58bd9) +,S(76540864,c8394290,9af4a48b,bbe05fdf,93af0f8d,1ec9b6e1,a7e91860,f2c133fe,f06923d7,738ceb02,2213a236,daf3d6f1,b3cc98f5,a5ed4845,83ce5c3e,54a3ecc2) +,S(573f0821,7a318a9f,8bd945c1,62e9a4a2,51e38189,34709606,c94cb401,f2b239c4,7e78e4f2,7de69e4b,948b105f,ec3ebd14,496cc128,d7c73fbe,7ca1d53a,b746bef5) +,S(8537981,89234b93,b5009656,f57e5ed6,f90d2184,819a5467,213a934e,22b01f5f,c94a79e8,cc990998,e1c69bbe,89ccefa2,9281fc0e,c99fa820,ed26f01f,62e475f8) +,S(53388512,29890336,3b1ccd4c,1cf0ed85,6f00a30c,78004512,57f6132c,edeb6041,d56e2a52,f856d1b9,a4f8feac,dbc9a844,dd22f55,469bf722,fd78b44b,6983334e) +,S(41ede48a,750ef7b6,5c49f913,afb98961,c5cb478c,39c4c85,2f33aaae,b0e4796d,d74c7bf9,4b6c4680,18892ea7,f04b53c9,4bdfe9c,d1a4c65b,8de2409c,32559de4) +,S(97e931f3,6596f736,992eece4,eed6a9df,fe762139,3acffeef,b6dd3b53,e5f08148,3da89933,53b9c52a,9e76ce7,7404fba4,39a24614,b62d42c0,9b660e2a,14dd5f1b) +,S(4caf4eea,3ca8b104,39847633,5252b37b,5c55b664,cc4979a5,4db00937,b222579d,c266732,a93bdc0,7cf88580,771d58a3,45a19100,4c0d1464,62171cd6,291607bb) +,S(857c1e90,5b3483c3,3ab24ee4,e51e3839,b52960f8,21a8706b,b7ea7c84,9e7b1ca4,8d6e9d0c,7a578771,b358380c,4a2e6bc5,1c6b09fd,e9b40c01,be5915ba,fe69dd80) +,S(410ef70b,e0dbf7ad,a68fc124,8dcba3cb,10ec39a4,9686b22c,1e7ed2c1,bcb5a182,d26e9ea3,331a56f5,cef074ae,e0b4a5c0,e6925d79,808ffdb3,b7cb9423,247f9e94) +,S(8caf87a8,c831eb10,817e5ec3,7aa431a,89dff6f9,a7e63f7a,30710419,5751029f,3f0bd6e1,c8dda6c3,c8e65ba0,7c3a4649,13aad207,3c5da058,bfe90872,67c8890a) +,S(eedee2cf,e92d2483,54a6a8a3,9d314fb1,b35ca18b,ffb9b779,8c16d5fa,fef10e8e,cb515ab0,21f0befe,4b31181f,3f9ce1dc,9fcd12c9,6793d624,c1eb35aa,e514c4c3) +,S(8cbf7ac7,1e77b7f7,7bad6a4e,9116db52,48bb2a75,744d4312,f02eecaf,2aebcee1,765c4b31,f67b26b5,3d17f97c,30d09636,b6f6697f,db6b799,169a2c05,779b7320) +,S(70cd45b4,cd449aaf,34ff0627,f0e01122,715dc6cb,98642dfc,c19fc672,54995db2,82e59456,761497b1,84320eac,3ada16c6,ee184ad9,10b60c41,20f0c538,2f535c8e) +,S(cfe217f9,783fcfd9,1e79d558,e37bec3f,50e5146,e0f442ea,702fdfb,6c7c45d5,537cbd0e,86453fbf,c57d70d8,78c7c3ac,da225186,17bb4dfc,7b6f7079,95c419d5) +,S(9826c0df,6486bb8e,2bf3d4f7,4cfafa71,ccabd2cb,12bf317e,651790f,48579d52,3dbf3586,f86d6253,d3749c05,2fc36d16,ae3bb457,8d4eeda7,34f172dd,b9c57342) +,S(ea18fcef,381b4bc2,c6b3fa3e,3744e9c4,a13e13df,576c8e74,d0f4f596,e28a02c4,c3e6bf9d,2bc445d7,87103c7f,e595a30a,41c9aa4,c41d1874,d7ffe69f,ee09f397) +,S(6de2c465,c09d5a54,61c618be,c9c16ffa,21b82e5d,673033a0,e88cf90c,fe6d8f4a,367acbd2,8950882b,428a8199,d3b21f5b,e1c4ccb0,3280bf5d,28b65cf2,bc4ee2ba) +,S(d6286e13,ee10c7d4,5ae50f80,3d1a5417,cecc9c68,9efd2847,6ffa73f,1a183f4e,7ab92bb7,55204e89,c7e3ca41,1c829e41,e965ab93,57db88ad,37f13e93,6aa56f56) +,S(7526e6fa,ea67460a,25525962,fdb6f209,73f0c861,ef3c364d,fce83df7,23c3bf58,2c76a8e0,d5a8611b,d3274411,cb323751,25a21fac,12e35ae8,f008f48c,18e3a674) +,S(fccaaada,56d64a3d,6d1d5d89,719f51f6,e737c803,893e8b2a,b785070f,8879308d,8262c566,3facf792,efd750ef,a969fab9,a2ee95d3,fe6e7d7d,8685c6a8,479362d1) +,S(b60d13b8,eb8a5f43,cc448379,7a397847,bd6d91a8,b3a6888a,fef4b115,59b57fe3,abf73ebe,5d2b8585,76104acb,ec885f1f,8405b053,3755b8ae,94ecf838,60ebaa54) +,S(332d4b0f,4a0dd872,ffd6d2c1,4379f925,4250fd66,dfaa2d90,127e6ce8,c377f8be,37f3143,47c2350b,f4333d7d,9e0b17eb,110dfacd,d87ce354,b7887cf3,1bc6232b) +,S(e99b2ee6,2ce6d633,1e0e880,37bd138e,5d021620,b555b94e,52def87b,4cc5788f,c9ea06fe,dabcca9f,6df1df26,8bb3e550,e2858dc2,b91a7c6d,2c048416,4e5546bc) +,S(89ead438,2a977aee,7fe692a1,d7199bdc,5af24191,e80573b1,dfb056dc,49c54353,b572ddce,db2d776c,2a967f70,6b7010ad,7fec43b,ebe5f19c,2de0f9af,d9994ece) +,S(cdad98e,529b413f,b46f6fa,98c74058,4777baff,b090d488,59587b4e,d598268f,d405a95e,543e639,470f10db,821f8786,ceabc281,788b0cac,3efee830,bfed034e) +,S(5096ef41,1cc1332b,e67f69ad,3cc3140a,c269849d,5e0f4f5b,e41290e4,86ee2cc3,7f33869f,ccd4b06b,ed61f312,30a7b3f1,49ef34a6,f2d46bb4,18c45343,73f8268a) +,S(bc0bea70,a0966734,8607253a,2c8be987,8c4d59ed,638ecdbb,8b9f60e2,a4a5be61,e19111ac,3c2b4e0b,4a86129,e6c4c275,54d1ff0,29ddf320,873e20cd,16873b78) +,S(2d166569,ac8f5a08,e0674d3,8aa7d747,b024bb8a,5c8407a7,dc451403,87223ec1,48af1b38,62216a5f,12a7d92d,4eec4e59,445c1587,e22238f7,3dd1bd77,e19a597a) +,S(b8cbcfae,bb8b1150,ddce37b3,26ec77b5,2947cddf,e3cf1d40,f27e8b7f,8145ba30,d5234cab,8b2ad2dc,8630ec02,2868a1e8,ffc2c3fb,cd5f5a05,62b6fddb,34823ca4) +,S(fb396092,563f12f4,ddddb9c0,f1ac19d9,fb2e3ebe,608eea22,7a9aaec6,dc960ee7,65e565df,fda1a394,3d27f661,c2eb01e9,646e88bb,6943953,58c9e62e,c9823c45) +,S(1c6e9d76,b8dcdfa,90625150,db2274b2,f8da06ee,21000225,80affa54,a414b297,706b450d,9ab0b0,5466edcb,bbed8b10,85679fb9,78d74057,607bc2ef,a5666255) +,S(2e043dc1,46ecff0e,6e566b13,d985cecb,77f55a0d,555e0277,dc660351,b9fca1c3,1c4f1ca,f75ceaf0,a051103b,90a7abf,665da500,2aac4e14,28a71e45,726d8398) +,S(5ae17b0c,a1bf8e90,e663ee12,d97d7855,9549f9ee,2d89592c,b4b0bc9a,585f482f,bb0df734,931700bc,73c6966c,1e8e5a77,a71806ad,88d731c7,16f236bc,b4fc8111) +,S(fa8bf342,6a24c3e5,d3c11c46,e75eda94,fca910df,c906a71c,1b08f468,a7caafc4,ca69817c,db07fbd9,e35e6c84,65b3cf05,4e2884f9,e57c0043,5dcada4c,2f5954e2) +,S(2cdff1c1,846dd7f7,b9df67ae,a3f4394d,1e1031b5,de7083cb,f905afb,991a88a4,4bbd724f,3827e42b,7d0530fe,de304711,6ea0d88f,8e564d3b,507ff3e2,ef76f39e) +,S(6fadbc00,55ca49ec,afdf82b2,96504f89,c5bb8291,ca942df9,5f5b3322,9d3b6905,f7671184,33a8326,a56f9472,8c411917,911a3053,f593e868,c06f57ef,54b7df62) +,S(c514695a,2f26aa40,dceb15f5,5d5ea8d2,6f4a1e06,12591fca,2f5a00e4,b8dd0841,5056ba08,2e78b06a,90937567,73fc4ef1,652905b1,16d8fa6e,8005283a,b113266c) +,S(83dcb8d4,93474f85,54c368dd,3e188c11,aad758ee,fdd1f064,66c11e16,cb7ff933,104e5b3d,4e57192,7c67a029,e119e79f,d6ed6fb,e61e288,e9f8bd84,630a53c7) +,S(bc65cf8a,cf9a0b26,43b69089,565f9a9,5f9ae882,2e2b1127,a8bcabb1,fcc8a93f,fdf9716b,a31ddd06,a080ac90,f6699b78,23ff28c1,155a79c3,ae9c292a,14fb2143) +,S(48778fa9,520b12a4,12d74b47,65ad37a2,695e37d6,4070d53c,1e09cbd2,4c9f140b,cdc64805,bec15940,387b4c02,bc51b469,446dd3c5,b2e35b39,fbeca21d,769c373e) +,S(9db2c42c,6a735886,8edc8831,2ed6873f,28077bb5,32d186e8,41f67ddf,a301dc25,e01cb235,ec9db45e,e1193e06,46a325b0,aa0ac5d4,786d0ac8,56990262,bfb3a0dc) +,S(cbcff58f,62bf025a,43a1ef44,256b27ff,37c6c8f,2496d2ae,fb280734,9cf8da6b,4fd99ed5,2da32753,3a9251f,e1e136bd,28f5331b,c1101da2,818de6e5,3bb1896d) +,S(9d520b97,87e68c45,817a12a2,93b1df96,70cbcf3,91788270,93367253,6f4f3639,615e115d,2b539895,d91885ca,a325625,41fec07,9d8fb6bb,22d9ecef,b6bc0f14) +,S(c648ddc4,57c2bc,bc23d182,8cc6d6e,4b0bfd3d,f83b2e7b,3ef6a341,9225dbbd,ac9a863,38dd1966,9bb47e99,e67a3d9d,ec16fe61,dc17ecaf,209a7fbc,518ab3d8) +,S(ae11f835,ea96f767,afde3f1e,79221dee,b80ead29,7b45e29a,7e596461,e82137dc,20453bec,b65a62f2,8996e1b5,f1953acb,4c5dfee5,4e5f9a15,c2a2178e,4c452596) +,S(a35549ad,56f8a64d,d23b9293,d8ef5128,699f6fe,365c0fec,29280d0,a364d46f,c84041cb,a38c9981,3015ffce,17ffece0,8f55a292,3c64868,f11cd6e1,bfbbe75) +,S(75877029,af5575e1,8dbfaef,37dac89a,2aad8308,d473a64,9c347097,e35f8077,843b0497,d19851bb,ed243762,177cc69,603cd674,216cd65b,2e5a85cf,5fc2b8b6) +,S(44ee3168,ca7ffd50,c467b1f6,83e532c1,ae00b9e9,f2eb1ca,917607fb,32d4ea99,10a20ea8,120b5a13,beda9f9a,9110eef,22564e3,9b96c141,1e73eb7f,c92c3270) +,S(9a013c89,8dafaf0b,90678f92,f3bb98c9,461e4595,42cb07d6,477b6f66,7a5337d4,11f8485a,c96623a4,e6c9b773,f5cd9fcb,fec396f1,ff53205e,8774ba1f,da3c2a73) +,S(b45e28a1,44d54182,20819a61,5f50b349,3fa12d17,2b8b5bea,83e73d69,b6b47d5c,d987db83,ccdacd21,dfff1dec,43997253,fb1c2092,95bcae4,5b76c306,92c29f4b) +,S(9e7d6a53,49845888,a8865d07,310192f8,9a659205,1d2a603,cdc03d35,a641a0c9,ca1774ed,ace29fa7,f57e5690,b4d1c0b2,ce5f1fbc,b21fb323,3c001498,54f462d9) +,S(113a1429,be1b613c,567b306d,5805c163,e433a940,8ef14b01,b9afea43,54991f47,225ee5fa,6d26cbb8,49191ec1,a51e385c,321e801,9152a3c7,50014567,7b928697) +,S(32ec8dd1,2cf85df,931e2597,f6b005e9,6d6eb0a6,d0dd7964,77655d71,418d9181,fd718dd0,78b3e4a5,9bef7f4d,9c430764,3423bc05,e1aa22ab,dd7bbb,aff9d8b9) +,S(ada43267,f2cedae4,5e1a5f1,46151f89,b145db70,ef477865,b1218e91,72e9246e,d148bee0,4d1f4d29,f9f15c57,8b047469,16e39686,c2b2ca54,1f3e0d4b,247cf82c) +,S(818a0abe,debd74a6,91fe662b,edba1a52,65f5ca07,2017c6bb,bf7b9847,95bf0cbe,e7b2d06a,1872c73,6988da9b,ce273b7b,ac0f03b,90903bc8,da719ce3,89c0a53) +,S(2f49eb55,ef77da10,804c1a1b,f596f09e,ae76026d,f2d12f14,d80be810,7d0b3c94,6a225810,2f1118,eb689aa1,e6d4ced1,1a79036b,802caffa,5694e383,3e038b83) +,S(7fe54d70,54cb025f,6bef8029,bedbd15e,bf66d5c7,986c678b,a5cc5353,7afaf74a,fdc617ec,72ac6632,6d16afb6,69188554,a47a82fd,db757695,2296c10,b4ad89b0) +,S(84f59366,2b8284a0,c9db8675,db9c55d7,411ec9ba,deec1319,56aa3f75,8eed2689,836e65d9,6bef6ed7,825119c4,c4511c89,48042592,f41eddfe,4de98e83,acd0d88) +,S(c90aa830,1a84820d,e06eb6b7,1ccc9bfc,a46b1612,5e2b5f52,da0a6fb5,4185ee1b,ea86d7c0,b285d82,9331e05c,d99c58a1,cc213449,d9226efb,16135237,f90dc8df) +,S(ffb4d576,abae49be,69f047ef,636142a9,8669b2ad,9cfdcadd,c057d96e,192ef100,3740cd14,b2d5e018,33a700e4,c80f6a8d,3d95966d,a5238120,80a9101b,b7ec6c7a) +,S(408a8d89,67ad6bcc,eb7ebb61,89afefff,12c24b5d,2c33ca3c,8b78fca,cd403de0,3b761fa6,378cc42e,a28fb66f,f1d8171d,4acd3557,fd6313a2,cdcbce47,e1caecf3) +,S(580a33f6,153109db,fdde27e3,f1b0ab04,6c80c04f,18326712,3e3482e8,7c53b787,bb8073c3,fddc81e0,e99ac5ae,69702ff6,f70a33a3,5639add8,1d353c0,e428431a) +,S(2d310a94,7054ccca,c46b1100,88349ad1,4c7860db,38c698c2,505e789f,8344130f,1ea2069c,3c6ec90e,9c11be0a,913d90e,2df1875a,2e26aa9a,5d28dc81,3e3db697) +,S(2874282b,e7b11cad,3f22f2e3,ab835aed,5d82b424,24697b32,985231f8,6a7aa450,286332d,b2e1b922,222e3860,e41d90ba,cf39ce03,21f26b74,cfa23171,f0415c42) +,S(af9e779f,f77bf3a0,10af5e41,82b77981,6940f85b,9530eea4,8b36e401,eb6231cf,9d3d4350,dbaf15c9,269d958b,86d6b88f,4deb7083,ab1ff389,c13f7541,98e84c67) +,S(445edb8d,515ca735,26fd2757,73b2778c,bc93ad8c,a661b35,4471d035,688c1ef3,94917a3c,fde762f8,3b774361,1f36a13e,e94b759a,455382f5,55d64f25,7090dc49) +,S(e010c20a,370d5306,f89993c,f7ec34d1,3e76feba,2b6612aa,dc75012,701811b4,cb45172d,280d9be0,52d57a21,4cb3cc47,798a6426,f215e3ce,e3af64ff,106fd8af) +,S(d34277ca,4625c7e5,b1134080,cfb44cd2,ef548b3b,67bb73f9,eed42352,ae5af8f9,a35f5779,7a628f7e,bb37bd60,9e3f44ee,c391909a,ce27ab44,1ece58c8,d7e4a4df) +,S(be0b9399,3bd54241,b684977f,ea4733e3,d96182c3,c9fb1c5d,d665eeca,cb1d628d,37904353,744ed26a,df76272,8ec41898,13218b0f,5fb09da,dbf5be84,fb7fdb8) +,S(308295f1,ed4a21e9,1ed9f48f,d6b42829,edd9bd34,e812f09d,c3b2c319,fd8f3980,6835c34d,5c360e1a,49a14c31,4ee4cca3,797d434,897c4181,a8ba5d7e,aeac0230) +,S(66cfeb51,61aa879d,fd791604,e10f5fa5,c2e07a5e,66a37b41,2b88db32,dc495b1a,a0e07a9b,f8a2fc01,3e229602,b483bc26,5ffba9c5,fb6ebfe3,f9ff9c9b,3252a1e1) +,S(f42b8fb,849cea70,4cfb3d9d,334a4a11,bf7b3aef,9b55f648,ec885a2d,6fe39ba4,b60621e2,a36d4aff,9f75db65,dd381ae1,f5b0fb4a,bc9f19a7,36d160a,61e8b22f) +,S(429c1785,22906323,2ecfdc46,2666f8f4,c57b7fda,608cc8e3,85a31254,bfab034f,e190ba59,1a868f57,40bbfcb0,481aa04e,50b3969e,abc941f1,8e69816b,2962af35) +,S(c8939d7c,94789a0c,b95e4237,fb378ee4,9895b985,6fc67d7d,fafdf7b8,debf611,143aff62,6e94617,c36d05e2,3062d2d4,47feb77e,9b15e2b0,4370f81f,1cad3682) +,S(5e4155bf,56303243,24e15ae4,142ad81e,2b82aeb7,8dc3ccfb,1d36f3cc,4398ef94,6801f527,2325a3b9,a9f3807f,216d7425,b9083364,203f3b75,ed6f4ff5,eb5da55a) +,S(1196b198,53f093be,7bbfa851,a7114e23,eb01c530,6078965b,5e9dbd3f,8d1b573,794cf0,54bfee20,d80dea44,d183db44,fe79dced,fef0a97e,5c557fd2,bc628795) +,S(d818d920,74bb737b,7db8fcd0,168030e3,39803e5f,6b76ba1d,ea836ed2,c73a6094,6ac7dbb5,1f63118a,80cd2aac,fb5f086e,ff15d51b,fb4ccafe,9d96f179,176e504) +,S(c0276b4b,f5ccabe9,ed9a433e,eae5c989,7039042d,b273ed88,51db464f,b06c6204,489270ae,6349ac81,d481a582,a8581520,972593d4,9b3facc5,fd52efca,24f4756b) +,S(94b2a1c,ca23cd30,eb9b300b,43d0b24a,b898906,1c4d8a7a,d3343d7,cdd83307,47c5ed56,b709bdca,5b960801,58338b9e,e6e74683,99a50640,6075302f,9e481df1) +,S(f2aee379,df2bf54e,e4a1c385,c28fb64,9f157d2b,d345995a,66868876,ae7d5108,ae766bae,9c90a1f9,c9079d35,1676eefb,19a7bf8f,bd56a311,13f2dd56,35c8ef08) +,S(fc8fe44f,3dbdc4b2,afa9cd04,3601c6a9,e81e4da0,456ce222,8306bb85,ba9833ad,6a321b78,a98f52d7,64330a52,ea5082b9,2b07655e,ce8c5094,ce307538,6d56fe15) +,S(d38cdd79,19a4f3cb,fbdaa3eb,e2ddc10d,7444d04b,5830eb7c,5b8b464e,4c255c14,6a0f1ef1,823a2fdb,94a311fe,cdaebe7,e1904095,1ddaae6f,1a565551,2c8c15fa) +,S(ac02e6f6,13d8690,d0c71943,a26b5e9f,916ea119,d7773f4c,14247538,9a4b41f,eadc499e,436b4eab,bed9c5e7,68fd2f67,72659819,437708f3,99531ba6,c05ea2b1) +,S(3948b1a,c36bd462,ac7b5cd0,7076f9ce,dc6d1a75,1ff65177,d7d9b701,d06419c8,ca91fceb,a01c03c7,ab141ea7,1cceb61f,72d5d18e,77964bd2,732bb95d,191765ba) +,S(4c7dbc8d,21d600da,6dd4c0c2,cffd8842,ea9e73d0,5dbcb554,35e31971,7e706e9a,86a77f44,b87b7abd,29c2f412,97f7e859,6db46ebd,8cdb442d,35dc17f5,278230fe) +,S(75228daa,b3825e2d,9f8c2f7,a0743b0d,b7dec731,d9df5e06,98ee11e4,8244f623,963c2987,e122f107,dba37bdf,ed282ea4,75e33665,260a5aa4,51021a88,780a1676) +,S(aa3a86b3,2ed2161f,8f6ea92c,71b7a47a,b584a73f,102c0147,632d2c2b,e80a579,b8fe249d,2b4ec64f,dd345d3,210244d7,f7e517ff,7722c2ab,bc4601ad,ae4e6cb7) +,S(702b912d,9828039d,a58b992f,7d6f3af9,4c03227d,3d3c368a,bcfd3164,193f22f7,25892c49,3a32cd78,130a4e14,c714cc7e,b576ccba,396ad36f,71de5c42,c6bac387) +,S(4ca10c88,6d44bfa6,2a221dfc,10c57011,269f703b,8f6f3567,829d3b5c,9c90ba75,3323eab2,9282e358,d4de6f27,72d77db3,95b04a22,7f0374b9,dac3ecfb,4ffde3e7) +,S(1619ea36,30da6972,2caa436,2c174efc,f3601c35,2e946d34,2da56738,92b9c325,22ad140e,13b8679e,a6d88dd6,148ded7b,a1c12697,91c7ede4,b98a72f9,f0e881e) +,S(21dfdc38,18debfb4,9cd409a8,a302f8ac,64d589ba,b65074c6,365bd398,d34d3032,bbbe7ec2,e835204,a786ddcd,bb6026e6,106d193e,21725c45,79eb17ce,784099a9) +,S(60fbe5dd,802f1ab2,cbae99aa,12cce0ef,36a472e,bbb1bd1,c0ddbd40,85069fe1,ea83b59,2dd304d6,82fd07a6,85408f0b,99feb1b2,b78b1316,7f9be524,a7349dc3) +,S(c804b465,fdcdc5bb,a848ee97,559405d3,dd7c2479,4dc4866a,e29676cc,1e147f96,aa4a2eb7,1fd82b70,ebebf43a,9b828e4f,fb10cca2,cf9bb522,3a7eeef2,5badc5a2) +,S(77a6e3e5,51373b55,dc51b338,3c32f6c0,5c74cfbb,3192fb7b,d96d9d3d,d50336d9,21d2326e,86efac71,48e075c1,ffcd573,5de35d6e,3856f2b6,7d358b6b,c6f047f) +,S(86ddc187,4a72eed2,666706ff,26a4ec65,a89d82cf,64e3d8c9,4731d62d,d5f7a5a,51f7cc40,ce45a123,a9217816,ba3e6dcb,40507b5e,4cde95c,443ce5ab,4f0cc29c) +,S(cf49d0f8,db8eeac4,6c108675,a155e327,8c80d5ef,84ea28ce,4a596f3f,c7d3beca,6ffdc741,ebae75c3,ed82dcd6,a6191d68,7cdd64a5,c3146d41,235b96df,420086fc) +,S(1d75ef89,57eb6722,2d60e872,1e126cec,c9f5c851,5fe18381,518cb54,b75875f4,82c5dfdd,9288561d,dbe4ae2f,5fa1d429,c2076625,7765b3e3,7b99dc66,b78dbdb4) +,S(bea4b735,f62e6122,9d8d9466,69503348,5bb5b7e3,c6ddb6dc,a292ca89,e7ad0689,90e3278a,8ea9e10,e7d9a451,7b7c01f2,7cda5836,f52a011c,d8e20ad3,7a08901) +,S(e85b0ade,a90e5170,18d0aaa2,75d5989e,577f5cf0,b3acb728,1af396a9,6169f2bb,d42970cd,3ca175c6,3916fec5,757b7f5a,30ef1269,d4083358,667f599,e650aaa8) +,S(d97592dd,24050526,e41ed550,fcf7cc2c,82ca5584,c0228f5e,3ffe42d8,a3928934,eac6c169,6bf01c3b,759a3852,a0236f4e,4de0db45,26f2d26a,2174dc4e,fe2d102e) +,S(e023ea4,50b620e2,378e60a9,a8c65778,fd772575,5aeb53eb,edd35ee1,666e00e7,4e4ed850,6dbdcf89,b060f0e7,8915f506,6bdd544c,e37e1e30,6a966353,6894797e) +,S(615b5c95,5cd4fd6e,a581b9f7,e6a857be,a7c0ec2d,c302dc9c,c8304ec2,d935e5a,c221c766,2602325b,bcd845bf,f5d754d9,46fc8074,f36a78d3,6e421b14,fd5f4d46) +,S(b1dfa434,2e12021,b9ce34d6,1391bdb,fa2a0d85,a004985b,c2cc7358,96ec13a7,fa3d115a,8162f828,1dbb7e9b,6f818b4,13c2a5cc,58993ead,d103ef59,9748438e) +,S(b64b601f,afbe47fd,ac675b83,5e4ecdc8,68c7e1ab,32598974,36ba3c9c,bbeada7c,af78c039,d2315746,feb60662,462dbc9a,652ae90d,573487d8,5ea52374,e9dbe68d) +,S(5429d346,fda1d9c8,6c5027d4,e94d7565,b0981f23,52715336,4a0f3264,6bb579cf,5b8ce197,dfecd92e,390754dd,2d74636e,162d6659,51464f37,ac696a32,995b1880) +,S(890694f2,56d6718,b040bb78,1041749c,20e21669,f3787f94,ff954b16,2a6f005b,d966934a,890dbbfc,bb90d7b2,26afd0f8,7bf505b7,31b94df3,5df1c141,2d753341) +,S(3ae75292,cd0526b7,fa6987a0,5fe060c8,269b5d1e,44a2867c,cb92c2b6,743cc117,10959cc1,5a74a82d,8f7d5416,a33256bc,f004eee9,87b82871,d22a2dd5,f2416a94) +,S(9d745a9b,ff717d55,5a353fd5,f1b9fa1d,347bbade,8a4abce9,3bb5dc7f,299b0707,cef338ae,d513c60c,7304f615,ae734de6,10461cff,ade0f69b,bac28e6,7ede8134) +,S(699e9c2c,8130c939,105ce7f4,f922c060,abf1b896,648509f0,aaab9519,d144f166,882b490e,1fb9f944,95d14583,83809d69,bfb7da29,97d244a4,38da39ed,7c3a19cd) +,S(e3a01cc1,dc520509,a91ea704,bcbfe298,ae79b4a5,4f433550,3884a1a7,85591f87,f3c641f3,68d19d57,fca87e54,6ddaf495,2480a891,37490b96,6617fd4,1edcc64e) +,S(5d150dc3,d9df375d,46dd2362,34498514,cc7ccee6,fd8ff5f1,ee5ee38d,6ac433d1,2c091250,d2e2ea0e,7d80263f,18401092,399a83fe,bfadc061,a32316eb,52ab0316) +,S(49fb9761,bb12ba3f,644aea5b,5e011f80,ec477880,58a6eb16,c100c5c2,e0996a66,7134220f,b7208914,58499caf,21654c5c,d9086b1b,92978370,89cfd06,d655e23c) +,S(34c55eb3,a4512dfb,de799021,1adcddc0,bdea055a,1f4f7b13,d530c945,2a44738e,258cc688,beff401f,9a910e26,d0c979e5,fdbb695,323321f2,ba39a4c5,4f98fd16) +,S(7068fcf0,7c3efe00,4ff7b82c,2af0c9cb,9b1c39f2,30dc602a,b2508d42,30a3a98c,e48730d8,844578c5,2e7657bf,202b5df5,2fe50679,7e2e1d77,aaab197a,e37ef1fc) +,S(e1d8910,a987aaa1,12ba1f95,ae8e346e,f49e5254,a2b01909,f73b874f,6b355a1e,8ad0311b,cc4947d8,999c2c14,9fd5c59d,d4a56a20,a0b90235,d7bab907,fe3cdb8) +,S(92509b88,ba8631b,16c6b2d,c60df45c,6bdf06d8,ed4dbd57,c10ac3cb,72d2caf2,3ea47a31,633b6299,a9f95651,b95f1411,ee6f0f33,35ddb8c3,3978af58,746a3ccf) +,S(90fd402a,e8d505e9,96aec994,db7d29a5,6446471e,34dc7512,6a356ac,1a66a519,68c0ff7,bcdc36e0,ada31816,ec4f0e67,9a6dc658,46aaaa62,e1958ba5,bada3b6b) +,S(b380ecb,7d9bca8e,1e35b0dd,d412b128,4cbc77f,c66c5f5,eb390d9f,a9400704,fd2a2092,77d9b783,9df69a7,229d55cd,18fa71db,e1f5f8a7,d78f450c,846a01a4) +,S(40e2e041,aecbb6cf,6f866140,b6149257,f3d029ef,ccf2a752,d3ef7b0,32b83f0c,122710a5,3c83888f,54e26679,417f2329,e1eda641,8e525326,704744c6,bc2291f0) +,S(8e609fc4,3f4e30c9,3893a38e,9aeacceb,7d254eb9,f77b49c8,c99c20a8,aaa03583,947c4c6e,9a821504,7f259a86,b1d70378,837fb57b,e0d696d,66a3dc3,7ac1a3e8) +,S(b871c5b2,2bfe9fd1,6898d00,1af89a8f,8d9c9324,52fce0bb,2ecc0835,f435f5ce,e302e5a3,ecbd0ee9,9f87226b,6f038003,507fe8ee,60b64,cd656f26,8f1d3078) +,S(526daa7e,39e891a,bb524170,96fff4d5,c6f80f57,cce87f83,2ac07cd5,50841682,69f04499,4fb7130e,758fd397,5ad40f68,c477bc9c,cc5c5f43,c5f5a554,b3d210df) +,S(c15c244a,514e3057,ce67cc07,3fb66fa1,5c031f51,8add9ba2,edc12f94,861ad25a,db1021ac,ecc3c897,8de34780,bbc9a8fc,16449ddf,5cb05b90,1ba39598,72846c50) +,S(37e20b19,466a038d,b3b63873,50dd3dc5,d3494876,cdb7f344,3e234173,eac1d388,b80a24,546541e2,ecabcfa2,7db57aba,5ea5bb79,f69ecf25,2d68ef63,fc3b89f0) +,S(6d091f28,feae0142,b311cd81,f57958a5,6a0da5c9,7ff5eab,c598e4fb,564ea528,48bc97f0,4d7ea6c1,38189719,6c85dd22,6e9d9f7c,5a8ba74c,27c29063,fdd07906) +,S(3bdbd416,a76efb56,ed01664f,b819dbfe,d3e545cd,3edd48d3,5ca635e0,bb54fd71,a6954d72,3ed7253f,ef301621,91fbad8f,9a63a893,82b98d26,a6bf36f5,2ceb0639) +,S(cd4e36a9,f111b55f,8c05d41a,4bc33ef0,c4109540,d9871237,4018b2e4,7e9d61ce,478dfa16,52632e69,6ef95ec,452df807,abded9bc,264e6dda,df0c6215,454e3e57) +,S(f23cc4a,9c59c0e,3bf21413,170ac67e,24845771,2e77f1c6,272a9f11,2df24efd,e933bc72,99b6effd,5cf58fc0,72f7a466,dc71cdce,74a3d3da,9ed5e7dc,577fa4b2) +,S(d98c6585,8c97eb35,b6846840,cb6db623,d7a349,435d4989,31a695ad,ed3c33e0,443fea24,ffe8825d,eb6c953c,70627395,ba13781a,164f2eb2,a85b862d,e3114990) +,S(2269daa6,c055dae1,b6d2b9d1,6c74a9bd,65325ddc,a249085f,a946e66b,6c744225,159d01f9,a61f0456,b08f0fe6,a42efdcd,30e14ff3,bb47fdee,2352dc9b,f5bfb3dd) +,S(335044fd,8eea8792,8de3880a,546b01ad,eb4d75b4,23ae7ba4,87740c03,167c48d5,69e503f5,26266bbc,63b0f2bb,757b3be8,cfe1d9c,e63d8226,8187a309,ceda1cc1) +,S(ee7a263d,86f9a83e,54cee87b,7bcae75,a601da9b,637aba50,46bc5f9a,3ff6c512,9fdd3192,203268e9,2388ac1c,840e7635,22271483,161f8f60,42d82909,41373d56) +,S(529b33b3,36f1631b,6c7b6111,ef44a888,bf95f344,766a2d97,6c5e5d5a,53f44245,12856106,93da6f4a,2fabc1a0,3280249f,6f29f9ee,9ccd7000,4cf0a857,ea061099) +,S(f2b3346d,a6cee9f5,1a933718,2d655a88,6a251353,8ebd243d,d3e3cd65,abdf1849,d41df628,be7703fe,9e866526,2f6278d3,55aaefcb,324df2e1,f483b0f7,77b77da3) +,S(535e9dbc,f03d98c6,70d03d04,5d638c7d,1db7a12a,22f3837b,3f559b70,4582befa,2c233228,bad897c5,bd4fa98d,67f8384a,62ea4761,4f64e4e7,40bc1f65,9e358392) +,S(c131688b,70da6ac6,5ee3172d,dff34624,b019bf78,85033970,8253b4a0,b299a7f1,fef187b6,e0e748d9,69a11d82,e9f996f8,d6e1aff,8b84d20,7dd78519,dce5f3cc) +,S(75dc84d3,f7ab7985,10ceddf3,da6bf832,a984d00c,98726a64,5dc71b21,754d3ba9,f5d9edf3,5e110491,2cc5e4d2,82eeaa53,84f62deb,1dc2a183,af5b232a,e3841c50) +,S(591dc7bc,9136c38e,ae727310,25c5fd52,82c6dad7,6f98c648,78847ed4,f32a36c5,fccfa4c4,f81cd382,e003aabb,4cb6c5e8,8d4875b7,21d44233,95397268,d7a421a0) +,S(83a59c89,2a8392ba,e7548fad,b87acf7a,d2c78db6,4c588f0f,b14753ce,12712596,7d00ac1a,33b12065,d67c598,8822ff3c,46f090e3,15cf919b,e3e5030c,e7c5873b) +,S(e9b0dfa5,8c52b2f4,a9c1b8c3,76391eff,6608f968,ec45bfc7,6ca93e2c,ba6f6f83,6449b28d,5846de0d,27489124,feb3f3fb,5c1f0839,a7809be2,e5cb5def,2e0a7c8d) +,S(16cd2f9,67b090c3,d151c002,d3a3d25c,c76adf50,d55a6f81,b1b9a650,b72bc03b,c592601e,2fe77090,39ccc091,bd78458b,a23db74f,848ee06f,50ffe4c6,8ad63a7b) +,S(f347d3fd,1bcde363,69e3d9e2,44d6e5f5,d80b8dba,7b1866b6,f584a38a,3aff1cbe,1c435ab9,ae38a13,98dcfc6d,64125e8,c7349f81,1584fa97,66dc4d24,7e87977a) +,S(5b190d87,d644854c,90c49f11,34921545,f349edd2,b4e9926d,534374cf,da428b1b,8a4eacc3,63efd6bb,5c93ab25,65d2c157,9c1d3176,b2713ea8,56bc97be,fa5401f3) +,S(a7786cb2,d7314ce8,f21e9665,bccacad,c49e78f3,7772c3ab,105f67d6,1c30834f,4fc7acd4,18982e3f,2fb1f911,cb70bfc0,6c4ea71b,a05f6371,46e96bd4,a9441953) +,S(d3654f53,e9071a18,8c5faedd,c0ef3616,abf74d26,f073ddcf,545a01fb,2fbf33cb,a56f20c7,213c0394,5978502f,c4a716f3,77c7a3d9,26c3cde1,880f103b,432f4383) +,S(e1138a87,400acbda,69d8ac3,bb6db4cd,27d03176,ee88994,2039a93,7822399c,f29a8fbf,dd3f6d46,5c640de6,b6853e40,1803cd95,f5e012c,9ce967d5,13a162c1) +,S(d29eb63c,91c0f4e5,b3c49c6,9c9ca952,5714730e,76bb87e7,374ac995,86317708,4ad93702,4e9180a5,9d22ab4a,c856de6a,d9d38c9f,1cb3fdd9,d73aff61,fea5f1a1) +,S(a9d403ba,a6717fd7,6577da1,d8b8ecb3,d2124b30,d18df147,ca48b482,26ee49f8,1eedfe7a,8c5ee1ee,50937bca,d9591144,56f1e49e,db74133f,f45176b7,26d5323b) +,S(ff7b58e8,dbb6055a,eeac6bfd,112d89c9,8d8f3763,98e41e39,ca076bd0,9ef57528,4e4e39d1,ad7a51e7,d6cb57c,836c0685,8e39f1f5,bd41aee6,cf5d250a,fc381121) +,S(43c50a9d,f7839f61,e1b6db23,4e2f146e,1672ea1d,566f5613,1e7bafd1,bd362979,f20fda98,81541a8b,a83e908f,69e05218,1e215885,f60cfbd6,1ada74ea,83f449ae) +,S(f608a9b7,1c91298,75662ae1,6be6d043,5803a9d5,29d3be53,9843f227,174ac30c,5ef364fa,e919dd42,1bad3243,413bb565,d788d266,d7b508f2,83c486a,327ad5bf) +,S(c913e029,dd1ef043,f9bc48d0,c267657,3cc11722,5cdad56,8d013327,445a117e,97573f0b,9c31cbb3,7bdcf07c,13526a04,32a38f18,43e26d8b,ace85a50,19a83049) +,S(aae0c49d,b17e7bc1,66c0c58a,cca847f,61318bb1,3482f63c,ce7dc55c,82a7d728,41170bf3,f68c3dac,22051aae,658cdc0e,810396ff,9d5d9251,6a7e6377,5c6be0b8) +,S(f2805f1f,45a0b622,59b9b15e,3de4a05d,e306c8b5,ebc5ac96,d35aa388,ebc846c8,f5d72739,6ba37244,57725cdd,912fa38,b36e201c,26409dc9,9789d087,6b8d1267) +,S(6969e4e6,e150d12e,4a230e59,37d865a0,f7d2323a,781270d8,7b0a7a90,fa4f39,c71c33d6,d323ed0c,3e77ebe0,8595dc9f,e030a0db,aae16f88,8dab7187,5e14de3a) +,S(aec2bf0,7a0e257a,be4fbdb8,e872dfbe,2aa0643a,411943e3,e4cef039,8d988f3e,d8e9f557,e686c380,c84bc528,fff0a830,bcc3b6a2,724d9df6,ef21d545,c8c931d0) +,S(9c6ff99a,13dfc35c,a502890b,69d91dd5,198f561c,790bf322,6bb243bd,4926f710,2aef920c,84a4f5ad,9d88f541,1ff46839,2f7f4e63,3422b11e,9b683403,f7ef849d) +,S(fa43745b,37a5e238,df0246d6,7eede652,ade75aec,b5dd8aef,afb8e6e0,96d7f1c2,df9d5aa4,2a3c6540,3793c8f3,fef939ee,48aba7f8,59fe9ead,dc44e82d,a98689b1) +,S(694a3288,6c4e26c7,eb3b84d0,9e777f96,ce3b74e,58658741,27643dda,a78d46b9,a54d6c6d,7645e5,6e8909be,922cc5a,a700d932,cb1318b0,1446a9e1,8bdfe67a) +,S(65499597,5be06b28,b4c339a2,b126210d,930fe920,7cc72be4,3d4ad17a,c08f38a0,bdee23bb,467fdce3,2d2cd92c,e81e3f5b,d29fe8b0,8b35abe1,c684443f,72f7900c) +,S(3791c8f6,75bb14e4,b7d4f084,483aec44,ea38eb2,9b108137,400099b0,799f0bd,2dc8f74a,da5e5eb6,f3b96ddb,cbee5ee5,8b2a3f45,c31cb16d,15a4e918,eef7bc76) +,S(d5e41065,eaf890e9,e9046936,acf6a43,59795c7a,1939d8ed,42941a8c,6ef31364,191ec4c8,a559fd4e,7abbb6b8,f2e4c32c,bd2f30cb,d06ff6d,21f156cb,f65bbcad) +,S(16ce2280,fa0b404d,28a29acb,62058b99,e504e6f2,eaaa3ae8,b77ad650,2c970dec,3d4683f4,486addb9,e54bc252,74e590c,b6eaec5e,7f96e9b8,8174b81d,56efb09b) +,S(a6b0ab30,6cdfb1f3,90e5b447,816841b7,e08f997e,d7d47016,bf3b501,c6107d07,2a62842f,b67e2794,92ed337f,d72abc9b,94e96e4,a10f658d,9cb9a4b6,a80abf7a) +,S(d7ca6d38,760b320b,21cb779c,d709f376,52b9d08a,8ff6ad90,21e00628,56033583,d6c05f72,866d59b9,6b91b6cb,b1401619,5e2d1cfa,9982db04,6d672fff,849e7bb5) +,S(78ab0563,2d3f707e,738cb134,7121c73f,e162405d,61a0bef3,75f6cb45,f5609d33,fe1a390c,10c7cb4f,297a4b42,4baa5c50,350eba49,55fb74f2,1094ec5f,ee75a6b0) +,S(c053553a,5b9fe803,65fc5a9,60e48fd9,218e2128,28935879,bd1072c5,180d6f04,e02da774,214dab04,e11c45cf,57be2802,7d0d28dc,51cc08a4,7528869a,3e719192) +,S(bf85d713,e2a995c3,ef98d403,30fc1fb3,5faf8e95,81385b4e,b65d5ebd,23f02d03,a5d45947,58d7b0e1,a8542a6f,21ddd207,dcb68e96,88284bbd,6b940748,b3e59b18) +,S(fb73b6c9,2be578b8,fe2ee0d,eb0aeec0,13816905,9e55031d,69a4d0f1,1bd280a,72ce7893,9bf5a55f,d4430bd2,55bde818,e15bbc98,37e3dcf3,e31d22c5,9614cd16) +,S(56496e5a,ed338dc9,201b04f7,8f4b6c2c,d9928135,83360dfc,1e2f370c,1628aa79,81dbf48a,824fca70,12315d3f,a56d5150,92ffa54,d1300725,86c8a476,be8c2db1) +,S(d698e395,9e81f098,485edcc6,2f2a421a,aecc0a79,58c9f6df,7905c931,b7a2130c,5903debc,e61eaa39,dac01a8e,3e970a39,79408bbe,1d0ffba4,5ce78c9c,79563d27) +,S(84b32e40,86709450,b32ade00,d3404b34,7fad8d7b,9387d931,780764e4,c566ff80,4c80d078,56cc4296,2b7941e3,195c5350,9bb5b0e4,325c24,4aa3a581,bb1cfdc8) +,S(7129c799,2a3689b4,c1873a45,f1ed3327,6528e243,28f30cf0,5ac38a61,8db2ed6,362b4fe8,482125a5,d4d15456,79009aa8,44f86619,cf3fca68,ce38995a,660810e4) +,S(93164c87,fa48b6ea,6b6cac08,8c991c34,5f8cad7e,f68c5b98,78139d28,d180d824,a3ac0d5c,c91cf0f9,cb97771,d16396ab,bd183221,c8d36a87,2785e847,b5d9e26b) +,S(4f90e8e2,37c4937c,a384c7b1,f929f329,94744d5e,8b89ad94,808ed9b0,9f305a68,cde776e0,2b6b484b,83f417c,fceed07a,ce725e00,343c4e70,14748f08,992430b8) +,S(4d9603bc,9f40716a,e6913fae,253eccd3,4442f6a1,3c058ed6,a10f91b6,75f716a1,92b679fc,278ce355,97165827,aa6fb450,9c52a412,284aa493,c6654ee4,3924add6) +,S(8b6f651f,91c54143,12c94f3b,c1632e13,f90cd718,67f906a5,aed13c4c,4ab17203,88c159a4,b80f2556,bb4e2b78,c126c40d,9ded995,bac6ac13,bf83655,210c7066) +,S(6f58b852,cab98347,e86448f0,78d49916,1909e1eb,60556ee9,8cdc20bd,b25ec256,3a4c05f,233d9305,e6abd30d,da0cebea,1681dab2,ad805cd3,2fa7023c,98239885) +,S(6be7f6a8,4021411c,acb710da,3ffafa32,8bb6ca91,59a91008,6cb98071,100c44bd,bf64a6f9,d461dfb4,581c8d59,b5fc1191,86f339ff,320e968b,b5810145,4836bee9) +,S(b2fcd0b,b8ea9e66,f2cfdbe1,3ecff9aa,99661f0f,2ac1844a,b3983d2c,ae102d39,a046989,bb3b8fa3,eb2cbba,d3a7e810,27c38cb0,ea33ec74,1444e8ce,7182bb86) +,S(a1d6ed0e,ab559b29,edf7770b,50cc5913,3916826b,6d99ef12,91bf744a,79a6fd96,bb91657e,c9255ae,173bf93b,51848094,2f17df30,ac6b391,df2237b4,c04ab69b) +,S(28f6570d,ed7130d7,35366201,e9ab639d,440da5e7,e1c9701b,d08a811e,912a9575,39191f60,119c59b2,3e91a7c7,fbf4c2c,e2216e5e,955db62e,dece6adc,f2d2884a) +,S(14c8ced,dbb83de4,218b089d,101d7b6c,31cfce22,49637853,b9c804f,90271fa3,48052d2,a5d02e71,135cba3d,24c7894b,de1293d,44a2f84d,7a8fece4,ea9a41fc) +,S(eaff9f05,fec737d3,d2a28fa1,bc8450a7,a75f563b,9221bca9,eda2f8fa,e12d489b,d6d4419b,5c9873d,7d3349fa,520f463a,2ad9f348,1a111c3d,d3fb70a9,23b8c139) +,S(e8ee4c6e,b42a3712,85b52457,52e7fc3c,ce0757e0,96932a43,d92bed15,14b35e95,d86bd4c,27ef1831,f107ff4e,6246cb7c,ee55abfc,cbc5de2d,5f230a2b,6a3b748a) +,S(98c61909,8213b06,6b70759,1c88a51a,d5e90922,6778386,a0776e6a,ee41e7e4,eb3d2e2c,f98bb904,42e90e2d,38ce4c53,fd72da8,1a37fefb,fc241aef,f65d4c8c) +,S(d4f66b81,f5d62986,c57a0dbb,c38bcb5d,89319806,4e28e17d,946cf7f3,f946dd29,c1930f8d,eedf1a00,cb7c5579,d814b5b8,2a12298e,530bb32,867821fb,7b7a5fc2) +,S(14d73ce7,5f8919b,55d54369,69866f0d,a13dd4c2,ad447c4e,b9879060,1411087f,69b94622,b9cb0d3c,5d106df2,caf4208b,b71c48f2,629d467d,16ee06c6,93ededf8) +,S(57efc935,59c7a0c,6ac51105,8a50a8d5,5646ab40,8a711711,5bc34c20,23da3aec,fca9329a,60b855c1,74bfba0d,92ae5529,27f959f0,5332cc4b,26272c02,b5c5dfd1) +,S(91f13a86,63da80d,a90b9458,55a9f3e4,171213f5,3683873d,cb6372fd,95b3677f,7405e0d8,6734f110,c329a7ae,92055639,e0332ece,134156d0,3cab4efb,419a90ea) +,S(dcc84d0b,46145e25,a83dfd64,b40dc5c2,c3322716,d1337767,5f9d6aff,a1607592,e46a4cf4,8e4dfeac,8df1526,f53246a,51b95161,a7030adc,8bba8ba8,1d2d6c66) +,S(28ab06ac,d5a6f432,116011e,6bf3c6a0,df0bfa1f,df16adb0,54250174,3348676c,51272a1c,967f49da,e9d1d6b7,a4ffcfef,cc31f42b,e0da52d4,27e56b63,97b0cb9a) +,S(7c01b21,f8d1dfdf,d3f2adb4,5915c636,d9c2a92,320c2d00,beff0f45,21d8b240,b4a48fcc,99906d81,fc6f78fd,aaa96b3d,6e7ffd62,d36d1aed,f76fa25c,542c8b48) +,S(f94eeb78,30f8e95f,2a362423,9c0e8fb,a0d3279b,e0cb5f5b,428a99ac,d14d98f1,c96d5b64,69676b9c,a5dc91be,8bb4a93f,7157221d,9513cd23,5cfe3ca,43649527) +,S(ea4674e4,7788cda4,bde0dd8,5f5e32d3,9a6d6477,30e9045b,d406f5f8,11ec35ca,769bf79,a9b9122,3070032b,a18bd769,fb622a61,424e9a0f,e1a46230,a75a235a) +,S(da5a7419,7f8f8685,1317260,682bfe28,19b7b38d,376745d1,7283c250,1fb40112,a60b5eec,5871e18,1325ef5f,5d6373bc,b5a19f41,2107290c,eb663e3b,95c37a39) +,S(c1017fa5,52560fda,18c6820,ded7b76d,a75ebcec,23b8fb6c,22ff72f2,26e9d41d,e947b19d,af2647f9,167da3b8,dff05897,9b5dc1da,6782929b,1b078114,349fed39) +,S(be7c0e1,4e814476,78a15238,b5809a75,1b964658,19bf0b16,4b3e914b,29216a7f,a30ebe97,f64219a6,f0b072b1,5d648e81,880840b,8a36204e,4f1627a0,feb392e) +,S(6758eec1,a4d6c0fd,cc118405,62fff82c,59e0fff2,cf80414f,cb53b139,97007cea,4653bc66,20fcd852,422c8898,862631e8,a0149bba,d0b9cedc,b4fe3eaf,7cb316b3) +,S(9cbb51d3,f88f4d99,9d80cf05,9e8735b3,11014de,69acddae,70d850dc,405b6116,dfa2e748,cad75b52,800e0ed5,17efc4d2,47c6381,9190a3d6,e2510bb,25902360) +,S(63a5aae7,b170792f,17350229,eaa5ad18,65328bd5,3421cdea,3d6e1510,d8bf0bc3,1125afd0,f25d5f49,f7e6250a,ed3634c2,12a261d7,8ce58ea1,95afb883,52da1010) +,S(adf96249,3e5f0328,ebae11fb,243da21,4e036d24,1da62430,b0fe2c89,b2f10657,509834ba,fcd8ddb3,2d018b16,d17d4b5f,219a29de,8a03f7f7,84f34b57,9b1ea1e) +,S(a0d8f5b,7fb44a15,93583364,e04d7225,bfdfa549,c2b25f32,f00765d9,e34d472f,61eab66,f84c2687,949da99f,3d97fe3d,630b6c22,f9f7c48d,d539b122,ef998ab2) +,S(b98308ea,9596a2db,adcdbf81,56d8025e,7a3ee0d2,5b27c33e,f686690b,ae61fc1,cdb4e317,7566a4ce,b4cc582a,3cfd259,445bae6e,586786f5,1250cd05,27ddbd37) +,S(e1a64f1d,37e3d6cc,119eefe3,793ba303,cf3969c8,db4abf63,7f0232af,70b98134,588d7ad8,885dd2f5,ec4d2084,b3f581b5,ddbd3567,8f4ecfc2,f955ced4,1c3231da) +,S(fbd5dfed,e8543aa6,e72253a1,bd711911,318929ee,7af14eca,49c2276a,65fdaaed,317cef0a,432c3516,3c405d51,65b8c310,f234891a,dbd0d6f2,f76cfbf0,193b78bc) +,S(fac4b7f3,b0a39510,84f1a882,2f7b6f20,30b87c4d,c0178a2a,e3077ce6,84da6bc2,7029b920,9e9522fc,160a5c54,a628fdd4,386ce0d1,55f19fae,390b2995,bc867d75) +,S(ca8643de,834fcf50,802c0296,41b5fc7d,3c29fc51,5c75c53e,e64a8185,43ef7c2b,907a6c27,111e296e,2436fd4d,ad9d9fa,f8ecea31,cee714c3,b26fa964,afcf17f9) +,S(71873649,d700ea1,7ea26b19,efe4b48b,a4a73b22,bc54066b,1202c96c,f3315f1f,f6cd8447,4bb374b7,753fc614,de5cf429,51512748,2042215a,bd82c11d,87ded2fd) +,S(67e738ff,21c3c732,26e57482,677c63f0,175b768f,776cbe6f,15ac3c53,48c5e3d7,14e5140f,2343dd72,577a5064,47cf6093,ebd2854,5d1326bf,ac79350e,eaf2bdb2) +,S(514b3f31,f875253f,205339f6,434ee17f,6c5a5c42,662ce934,280f55f1,9a198893,4eb33993,a2fbec70,4cd1c538,ce7cde4d,a61c0fc2,dca9669f,e469807e,4ae9a090) +,S(426acfa6,eab03e75,6ab30a41,418a0392,ca53c216,f84b3586,f9858501,8bc2dab3,c3d63eab,21cc10c5,c0a06682,d0573bb6,d34944d1,749da74,acb59aad,f1083926) +,S(b946bb46,68c05737,ffdcbee,94597c85,b8ad4a72,c58205ca,d420e8f7,a2d7a09c,cc700ed4,12633826,567e63a5,e65bc603,969ea13a,49feeb2c,dc723bad,1e3401b9) +,S(e6a844b3,f6c8b45f,511d7d3c,ccd75df4,1d1e38f8,fb28adcd,80335b95,d98e33ac,7f24789,3939890c,74a3268e,e1f717ab,6c4aa109,cc9257e2,c0b176c2,ec58cce2) +,S(43e62bbf,d9e052e8,c1636b41,5524b98c,493e903f,2313dcd,117d140f,96458001,f481853d,a90d528,30999300,dcff31d,ebee23bb,49ecbcec,8e147799,a63b352d) +,S(c44ef40e,3427476d,42e23e1c,41ddb9bd,e555a844,9125aad9,e94f44b8,8047f817,bedd4313,e43ee593,f2818e14,776f4ae2,38f664b2,db84c9d2,498b9ea3,8e236fac) +,S(a1b35313,dcc11895,c096f93f,5f8e4997,7f58f2fa,afd9b7e8,d408bde0,53212385,bd7eb25a,bf0d50c3,7309f9cf,5093d817,135a9ec0,20262c55,bdc8e8a7,a3079f5) +,S(48a6f3f9,fd6201c9,a37f2f0c,735bd98e,1382229a,d1589c91,b6748a92,1b5e964e,1b545155,3d41a8a0,64862c81,fa9d5966,2c73e039,53a5dc91,9712c50c,5b4481b4) +,S(8e01f574,651db06e,8a19181d,c8eecf1b,75f050cd,c5b2354d,b06285d9,a4061e9f,9d156ea0,9800e7d5,b6c6e90a,2eecada,7d7ba964,ba1f0cae,256fbfb2,275e108b) +,S(4bc0f8db,9e6db576,3eb68b19,5a79f8e6,28e375f3,1694a58f,43da4dca,fa05345d,c6a70789,a1e6b164,bba380e8,126a4a69,6338053b,6a32d9d9,8d0f215c,43a5b555) +,S(966fd0cb,5f5edead,d6230a66,50b7dab8,f4c7ee8d,b00ce55f,32d54a23,ba97a768,9d644e43,bb4f9b65,f5819a1d,ee0a16b8,1e8929c,a9e544e1,6546cf79,811a994b) +,S(6ab519ad,49522ea6,592dc7c7,4438e337,20d50eb8,862467f8,2962c510,857b0d8a,c5ba3a34,2b7250a2,62b67ec3,554c21ee,e82653a0,378ee0da,8a809151,a3ae44d) +,S(f8b0b8e4,3e5060f5,39bd0a0c,d076e163,e55f18a4,25327856,d526d6ef,aa76c62f,743de052,a65853fa,58cf29c8,62839aa1,7d5c95ba,43673ad1,fe1ecf6f,d4d48ba4) +,S(c4509ef8,579d8ff0,ab585c0e,5223d5fa,967e9763,9d15b0e1,6587a125,3ed18bad,7b91f7e8,ee979a58,5a36d8d3,574b8ae7,81199dc0,86f11cf9,7fe58e4f,1db08362) +,S(9a00135a,6ff450f8,e2207c53,894c0e4c,4cef732,cfab43c3,aacb00fd,ab42379f,393ec748,3684c5b1,4760902a,28cabb90,b481596e,8b847d59,4dfb8ff8,1fa9975d) +,S(3d775bdf,173f8d7c,de90c17c,25d3dee2,a484d331,4e525e3e,aa4a405b,6f488601,7e6b08bc,a560f6a,5bf287f5,59d74e25,38a4025b,89972046,b3de98c7,b30e51d4) +,S(cebafd3e,a60118b4,513380a8,d10a29a,a95e5002,d703d7b8,f5d0e983,7b03b529,19477ab6,46f59f61,ff603594,e33ba046,5f6d8b1b,f55290c0,fd61534a,87b74b4e) +,S(ae8a3cac,1ff3e3e1,ef01ac16,2e49b237,7ecbc963,f58adde1,58cb1987,cfa731b2,5a4b0675,2052b749,733f6af9,e8dc773a,ee26fd2b,114a7ac2,baca1e9e,51531efe) +,S(d74d38bb,8bd47123,5c118ede,e477ac4d,fd39b635,d0fbeb28,30843753,ade3b38e,f3e505b6,f17a2839,7a985084,31ba6de2,1ec0a0fd,3936dc32,5d66bb37,7cb54451) +,S(f4287675,7780785c,d14dc1be,fe075d1d,4d4f0b33,b0ce9db2,49595b14,f6beb2a8,a3df2231,eefc62dd,c658bf6d,a361ad6f,950f34d5,3ff25536,4eb1e1d8,60514b38) +,S(e91d576b,da19ad62,76bcaaa8,69cb2099,e6277688,3ca1d454,50dc9401,46378e94,b57e2038,c8da2cb9,9ac313db,83265d8c,20e7918,37e75db8,7acca971,3840779c) +,S(269944e8,7d77e176,3791b53d,af2aaa43,e035e1dd,f3c7daec,7e830cfe,38c66ea2,cb011764,34bdc7fb,528ca43,9b323c9,56764145,7b7eeea7,39ace76c,193707f6) +,S(ed41e68a,8f0b3681,1aa61c68,57bb1765,fb099317,2ff6ea5e,e94e01fb,644a3d1,f2cc907b,880cbe04,26ba1e44,83d95800,71c918e0,8cc085dc,1dd0deb8,c508231c) +,S(6947664a,96cfcba5,e2e36e4f,53a33d69,538192f1,3322113a,b0b79642,dfec0de,6481d1bc,5b65b6fb,a91b76c4,d6ade333,25610195,decf5dc7,7f95dc2f,a38fb6cd) +,S(aa3e187c,e22b63df,6a80a42b,ba9265b0,4379012c,70e8ef66,8ea85c57,1e27fb03,a638dd6b,98109fd1,96ffcab7,3010543,e8732f48,e5cdb29c,38fa91ff,8d011be) +,S(5de4e1,a4bef94d,b4a9fbab,6543fd6e,bfd5ea37,9124e1c5,eff9be18,f84a944b,21c4a282,693be294,b699513,f7744761,58f8aed1,a7ec7442,9679ba9e,7957e2d6) +,S(6533dcc7,2c87b477,81c96c79,3af0af22,fdd18fee,a33a30a0,9646c2b4,287a7ce5,7f03e5f2,3d82f9bb,ce9589fc,23442174,482748cf,a3aeccd3,f8c37058,837ccc51) +,S(139e5f3c,129e584a,bda008ab,85343531,c5109f23,a70b9871,a5ebb00a,64fdf354,497b7e57,41fb8eaf,a53182ee,98352b62,6bf011e4,826ac9de,6190a2f7,773f0a98) +,S(493fe9cc,f7e1e950,83cea991,8d8f2561,3ce57b81,81915f0c,7c779aee,8161f7c3,e69763fd,62fce1d0,454aff6a,6a3bb448,639ab615,8bcc2f40,88cbe4c1,67020cd5) +,S(ed675fdb,d8dd70b8,641ac2fb,4903ca77,900e3c15,766ec8a7,446e6b36,52a064a9,a61bb379,85cef5b4,6e0669b4,b0188ae,23ccffb2,5ce777fd,1f26f313,68416de9) +,S(173670a8,9a769e3a,797c14e3,15393d52,b6d48444,3861cb83,136b0ca9,9a260a4d,4dd43921,c1ba4d2e,95ea1b28,e4908410,d140b3f7,7dd82bc6,d683da27,c7bd4904) +,S(d5a5e3a0,8f87e154,6f11e05a,c106e80,a1da933d,2cca528c,df9e1f09,635d1610,7c6c55e0,daf3c092,8d0a9c6f,2c1ffb0d,aa20df74,20a35167,2552914e,5d175352) +,S(54f5e9a0,4ab321c,692f2e2b,94d6697d,a0a99932,74ee4ebe,4175a338,daf6fa2a,58cf13d1,75fa6e47,34aeb761,4f828dda,58a7d9ca,855ff42b,5cbd66d8,89f2de21) +,S(d6682898,154de995,62e5544a,442622b2,fd9a632d,94445d4c,9e8725bc,7febe6da,98091e3b,9ba3b857,50e02c50,a7971aa3,b2d5045,f760c1eb,d1371dc6,3190f206) +,S(253019b9,2af2c4c4,8d9f6e1a,82decd36,610becff,18c908ca,fef49bf6,cdc2da08,617d335a,d9509d74,e5eebdce,810872e2,3ffbdd3b,da53aa5a,495b86ba,397c680a) +,S(56f64ca,461bebde,560d2bcf,ac08f292,ced72574,50e44f16,bab67cd5,104da6cb,5b2085cf,dc278328,a992bca8,f2ee8142,757cb553,b903a3ee,bd83bf3d,593aee44) +,S(f39c9571,1e153a9a,f0e5c192,87e3ee38,5a31a1e9,bef312f6,4dded245,8f553420,4cc94ac1,1c206b9f,7879df90,8498c132,e742ef62,48bdfa97,4b882930,e3b0b1cc) +,S(437eaa8,cbdf873c,32d3dad,95c5aae5,b2f3034a,5de0c536,8c8ddd62,c13128b5,27d8ea0e,b00310bb,59424599,3d60da59,2f8d1b2d,df0c1fcc,721e3080,993c59c6) +,S(ade1a589,3f5d6798,4490ae62,11c57534,3f13e7a6,14ef71f,a79eb4b,a880e9b2,bd49c17c,537e6a3b,ac7404d8,c3c1b429,e801882b,7f241304,9022e262,3791c715) +,S(936275d5,c3091a5a,b9f57d97,7a4e1b6c,a87ef978,c7ad198f,d16e2d93,3ac1224e,6852690a,d8bd84c5,eab75d96,c6e224d0,ed598851,b17b857e,5aa01207,df6b9f32) +,S(29e55fd,3e8fd5cd,e046db20,5c80b9d3,e294971d,76b5e8c,c33fb5a7,6b9b786e,769e57a,7eb934b9,4578312f,720ce44,2bbf3e2a,d61a6f57,af6cde49,8c010a0d) +,S(df8362a7,350185ff,198b5275,45e16f78,3ae37804,7647c584,168b159b,809051ef,afcb3446,fbd4a3bd,e826b604,84b16c3b,735ece80,ee48da26,3a6cae0b,62af6bab) +,S(5f443123,9a35fe0,f9566037,96cc619d,b9a01e83,96cf433c,25415ece,58a427e,385c2812,fc0aabc5,29272b60,56aa9c17,37d81c72,48fafc90,6fd7d4c2,b0901ac0) +,S(c19c4215,53c6037c,525b77a3,1693fc4c,8c5323ff,5d3dd63f,4b7e3448,15dd2de5,9f76ea8a,879177e1,27116189,6d9e6b20,a19d2255,92c99822,159c8ec1,a93900a4) +,S(8abf3a1d,d1e02332,ead62fdb,36394246,14d19d92,a82113f1,d62a1423,af2d45ac,325a967f,dcf5ec3f,75e7a984,ecc2d9f2,defc2941,6dd507ec,7de1b598,a7e36dde) +,S(c8bfdf90,b93161e6,c4d4a58f,a71ea84a,57c1dd76,c0607b94,33fa3cdd,f759ae7a,23dc38a3,d172fb63,ed47efd3,c3e5aa3c,fd7990cf,1535ce5,b51944f3,270b20f9) +,S(976666c,35c55997,a759e7ab,85f90d7a,a26ccc40,5b77b8b4,43c7e86e,2d2c78d,6d342c3e,44facf25,bf2db2e4,e20cceef,92c52cfe,b4370f89,60551614,381ed0ff) +,S(e7790ba7,7737e4e1,c7bb8e8a,5bd89c3a,1fd65b6c,feb2273a,1c12a8cd,f963252b,2635e20,1534b58f,70e754ea,db28998d,f7138ff2,a9e92e1a,810259dc,ffbdba42) +,S(42cb817f,6bfcec83,f60e3ecd,5b986ac3,b471cec9,975f3efe,37577d81,4576fb0d,ed35e128,b2f9bd90,f2162050,a5737909,144a8596,5075fcce,2708a4de,c45cf49a) +,S(a0886870,1a239333,ffc60397,ae11f145,31902428,a4fd58f0,2450e0f,412f3cbb,c8486f37,1ad6e034,8e51995,b4887ebb,fc6002c9,9cc00ad6,d8a81f99,1883af52) +,S(a40cca41,9f101b8b,40fd8e8,b364a52e,e6a9642c,22661aab,3486f25,732c4bb3,f421b69,3ec096f0,2d1e611d,f0701cc3,b0655b9b,95009285,babb150a,9445a910) +,S(90aef978,bbb0472c,5a75b70b,c9f5755e,c532940f,141a350f,efe604a4,35beb721,f9f05c70,737cf6e4,ca88cde9,2e478ea5,93f58510,9479d187,a5f87e11,e14bbf0d) +,S(ffc23a81,a0f61f39,600292f6,8db9acb6,d73ae433,bb827f1a,7bc6997,ac3407c3,b76a0612,bce5e139,277c7463,d47cce0,4f313b37,a0746803,6865f284,574d4b66) +,S(d3ca7b94,40bdf990,4262bc16,298425a6,742c852e,df99ded,2ab0ff50,20a112a5,9daecbac,ca7e825c,4f44281f,9813ce2c,5ef191b7,341fa2cb,1f9780ff,de4d637a) +,S(2a53a2bb,720ab31c,2a6b7589,ce0e1ac7,469b21ac,d55eeb41,b23b3cca,51bb9f06,11aff933,ffde9646,7a4d0f52,220d06ec,27f7810d,ba44b256,c21a57e3,d451f84e) +,S(487e5356,80c40287,a6fd2f77,bb8f5cbf,22b2fc71,7fb7487d,5a08474,ada1ac96,53bd7fd5,46070d63,77b65326,d5130445,29c9625,520c3a73,1e990d0d,5aa849c8) +,S(3e5a5fcf,291da0c1,fc332cfd,62f4b629,cf23c0b4,8209fa29,63de5b99,667b3e16,86987f2c,43389a1f,4b028df,773bb130,8b33d7ef,7f55dc97,b060ded0,fab86825) +,S(4f90afc5,15a847c2,2c42493d,22dd5704,601840fb,57086b8e,d5f7d779,e3e256f,46e31958,ac2e6892,335f6b08,9ac0d3c2,4ef93994,2b585e33,226ded0f,aab831be) +,S(be07392b,40be3ea7,a6a73807,121be982,c2ff4b38,a4585a17,82c585c1,e23601fc,3a158457,657c9e8e,7bd775b8,1dbe2109,43172771,e66ec38d,a57a8216,f1f258db) +,S(86c274e5,2140375f,222f9e6d,47c24e06,ecc2f741,51b5a603,e0563412,fa1108ed,4a02fab9,4065d590,32eb90b6,4c98987d,2703f276,f92c03a2,aa009692,40a96ef8) +,S(4fd3a6b,e7923898,127b3056,1dac13fe,287277aa,21127626,2678e04f,3573cf97,6498a1a1,63cfecb6,c6cf4b4b,43bc7e96,f07ebea2,3b4380d2,38c0342d,f11173e4) +,S(cfa435ca,5423bdd7,8aafe78d,1fccfd07,cd2a5f86,ba81918c,b68c7695,dd117c94,bf4c891c,2dff79e,35b77854,66845389,c399b53b,4a9f4cef,d7d68357,10ce1fe8) +,S(aa5acb1b,79533cc5,9b29e927,77469afd,414119e6,1f3c90c1,cdf93e2c,3e1d446c,b0df29b7,8713c001,fb6d3854,e183767e,8b11bf10,9c75dbc2,6bb408f4,22a498ab) +,S(1b93c2ec,c21bf558,ddbfa1c4,41bca52f,435c09f5,4d06d175,6353e0a1,545c3d15,56c455ff,718190e6,5ace8a5f,d5c6d263,f72e67b1,a20dcc4a,eb53fb4a,33195ed2) +,S(1744cbf0,2566d20b,f639438b,55f72b0d,c8480092,246410ac,d8551498,2fb91760,7e77a7a2,32b0b5c5,9d1d5da5,7a7d2570,68dc0f8,4bda1f6c,683f5229,df4c66f5) +,S(a0be98a5,ed448c02,8c2f8ffc,607b316,1b9cb9a7,a2291bed,d24a8407,ff02582b,e7cc2c6a,2393525,b4d44462,cf6ac8f,76b86981,ddd369a2,274c1971,11da6ea) +,S(e0e593f5,dab5f7a9,562b2591,d8d75ea3,8b2f2b19,cdc8fe71,14891006,7b845882,9088c762,15e35db5,b3bc2614,1a42ce2c,b5464dc6,49f469c7,e785f5c2,cad67334) +,S(7824d895,a4982eab,d6f1b928,de7b0d65,ffe5796c,5e492b40,8b9fc879,c29290f5,ae175c68,8e428528,38a2d8bb,fc232c60,d6bcf117,57cdad44,8a4af01a,bcc7ee88) +,S(49d2e57e,e0b611dc,214e4a2c,d019ae2d,2aa51393,e976cb5c,4211cf10,f9d96e66,ffa0c4ca,88011f72,779b7919,829bb9fb,11c81e4f,a78154d2,5cfa3cb2,bd5b770a) +,S(da605f6b,8f701a85,86012e8f,83898aea,eeb3de32,e9c7bee8,be2139cf,c75ead00,5ba0c12c,e98a1c1a,89f0ca5e,a93f50fa,5a24307c,6751f633,d699e5ce,9411d246) +,S(aeeaabeb,cde94e6d,5a1de2bd,1d9c380a,9307be3c,1c32e785,652ffd9c,bac16ff2,30094755,8510ecde,500a52b,f107093f,b62e491a,c2596460,6641abaf,d50bf840) +,S(62f1892b,35f3fe64,b1ad1e1f,4305f9e8,66ca0a0b,e5cb778c,b0e1feb1,a10c40b7,1a44205e,e600bf4a,2e287f09,c5bedbf,f1f89052,2d14a883,8e1813a7,3f5780d) +,S(c2091ec5,46772d69,28ebe9f5,50a68083,3a567b33,dae25e94,4ac4d589,96979382,599a765b,d2e89d31,735fa722,a1fe1946,eb610c69,2d5a82b2,3828502d,cad4b31e) +,S(bfd7c15b,19519235,700e1b23,79fe7c22,e50a2455,5f83dba5,97d00fdf,1b242367,ac6de7de,545ec735,ea127213,fafd287,f4cddac4,8d6fe694,372bd46,bc66b17b) +,S(d4d4e784,3cabfdf7,903d8507,3831da81,9581629f,74f3cfd1,16b5f635,132ddc7f,1e49611d,582cbacb,fce65a28,44755cb1,d1cd6d4e,2b8f082d,219742d4,61758a6) +,S(1e575009,c378b34d,f3b434a4,95dd8c31,4945b4f8,df617d02,cddc11c8,8f908fdc,5ce37fa2,810c95a1,2697458c,b8f209cc,10bf2123,3ffa8565,5bd8587f,cf6cdb7) +,S(b5a66a2e,ac237eb8,a1f5e690,ffdf65e5,c9268c6d,37104ee1,108f95c3,b9408fd0,99005ac0,aaa4f6ea,60842ba8,68668c6f,f8cc3280,307630de,3c43ef28,cbf72798) +,S(1da39d35,2599593c,66c90b06,3baeaf8d,66bc3a30,21e3f6e6,cfc3ee6,7f26fe0d,9272a05e,b6b0151b,5470d076,c01c3000,f7e58aa7,8fc7fe48,9f285b85,c941311f) +,S(7f3b10b6,b10000a7,652862d7,21f428fe,4e900c5a,f3844500,2b374434,b5a971b2,b94a2fe0,7907ee33,113bd4c9,256fa08,8c4a4f74,df3c3a9e,1f5d205c,a2ecd385) +,S(426107c6,61850f9b,f6beb61a,e200c2da,e5dc368a,3f5d18cb,baf84cbd,7a4eb2e0,e1fa7c78,a9e6ed0f,8d713488,bd3afea4,857cece,8e8e54f5,40f8c70c,67e511af) +,S(555e2656,708fc4c4,312093c2,1489cfa9,d6c94099,680f53e2,fa374a43,45be9697,f5efb7,1e3bb76a,22566e06,c674ba11,a7822422,c6f44cb0,2f2e2be,284db6e7) +,S(7170b17b,5736e07c,262a927e,725b709d,3360625,4642a8b3,af8fdb12,917dd290,ef437ea3,f8998813,b5ad86e6,9a77ce0b,98b2c6a6,b6df5608,627ae735,30973b1) +,S(1ca8ab3e,66fefd13,49e329d0,72a44f1,eb4de646,c8930172,aaaec311,5a5c2180,6fc641c9,2a87d776,81dda2a0,f4984ed2,c70103a1,5531b274,fd20efa6,3b0a3c49) +,S(8352546a,f6d42e82,bf150c1e,41c1a72b,85f057d3,487b4797,7d5e4f8d,c05366b8,76be5ab2,7ca25b12,a888d7e7,21c2b1c9,ac92b0e6,ea0c484b,1383a835,86c5fdb1) +,S(2f112f7b,1730b9d5,63f988ea,765c48ef,353123a1,4d92e44c,3e988459,9c904cd7,eb348e97,f6487d5a,32f70b16,d2ad1740,27d7a8bd,41a031bb,743a6825,2e34a44f) +,S(e84023c,164dc6c7,1d72494a,d410a5e4,2eb6fd09,16a70f1d,5192508f,3ea5648a,634f3585,29be0328,89b2f510,622816bd,225aa031,ab145b8a,48a6fc80,1ef4462d) +,S(951c4d17,45daf527,b803929,114d57f4,4da40342,31c669af,d6e40127,8e28fc6b,f9083b11,a8b30fbb,2c696f60,8ae82627,b9592ef1,c72fc921,bb2ae4ad,5a27f0a7) +,S(adaa9457,f60b9f3e,e0a5548c,51f945b9,78845841,51ae87fd,689b892f,8ccb19f4,834657f9,2145fefb,8df9b047,55674997,f899b951,40ce5830,2e468588,1761caa6) +,S(649296b3,9800a3b,516ef3d8,52d7fba4,597f3e35,1d303397,7495fdee,619e6ef7,44ce9c90,10215167,fdc5f078,e2edfebc,5c8b441d,d88cf853,5c78533e,d61df105) +,S(2c1d7e97,908575bf,38afe2ba,7875f1d6,9f1e9db6,b11f92ce,4bc94d3f,6006266f,9eb250bc,30abd08,bbbb4e4b,bc09cb03,8c6c8ec1,fd1a6ff5,ba23726,da2cf7f) +,S(b130ff8b,ed4ebc32,78293b10,52fa197,b44adaa7,d1bbd74f,f6d56f9,744647ec,4a0a45e9,b785c7f6,76fd0a95,66e4228,136f60b,dcc1806,212590ff,eea5eb33) +,S(4f2a5997,62ecb2d9,31ae9c74,ccd71cc,29bf684a,d68f0117,32a0cd50,cb0e6231,debf8db4,5cfc7083,fa700dde,7309edc0,fc44216,cf7bc237,377c0bf5,7ccf17de) +,S(97f9e9a1,7fbe6e25,e41419a1,8a5a24da,a178c0b,a99e30d1,cab0d2de,7a23c0b,1ab1226b,cceb480,fb4fdc8,70fb5386,6cb622bb,e71d3c0a,4ddda232,57559128) +,S(e17f3fe5,e9f5d17e,40182067,3b710940,bfd486f1,ad3ef4c,bb93b47d,9d9d8cb,f1126a52,615d3a8a,6b360b26,305124af,44ad7d62,e03ed96b,59c2903b,b5272f58) +,S(1a39f846,7d638182,900c3e94,538a0fe3,3ae66853,aac36688,7a5a8bb6,7b2fa2de,ae7c1399,5a625a4e,42b4dc01,9d7c7501,18492f3f,bb4567bf,28ddef5b,82903aa5) +,S(8a5ddc61,27f6fa44,90a93e52,f4faffb8,baa60581,5142be68,cd18692e,b42f5320,5eb62325,853dddf1,a42559eb,bd5dfcc0,328e69a5,fc787389,74c80d1a,896b0d8e) +,S(117dbfb5,74b7d6fc,d47dc17d,56f5b5da,b864906f,f08d190f,7afe1f9c,fe38c299,4acd2151,30b7144e,437bc923,302640a8,c504712f,6b903b26,bd5db8dd,5d90196b) +,S(b0c31228,431c7eb5,7310706d,950a2a60,eec84ec7,418199f3,f2985a39,8a70a537,a7de9b34,792876ff,e98c3237,260d8237,85e47c,438fe419,a1048b00,b064ff78) +,S(7c210cb9,f493275a,e17e6d5b,517606be,736cbc86,5a5897e0,8d1d1f03,f243946f,17b07523,a8bd185c,ea4a92d8,7af1f1dc,920a7fac,30faedb1,c38e3529,1759c63a) +,S(172e5167,578bed44,6397b519,2b0eca17,177b14b2,f4570aa1,38771610,6ed6e650,9c15752e,4776b805,d63de803,83c73ad3,9d3ba817,c1f88cee,1737cd85,33830ba7) +,S(161afc40,df25fda1,3637317,3dad8046,c95a6ef3,aa9c19ca,47e9ce2a,20030686,5e6fd083,c1265f76,b4b9c819,3a45e0e8,9926f160,b6257759,ab90d6f0,126089ce) +,S(b991f2a8,e18aed33,4d769cf8,b6e39144,2d194e90,ee1518d9,459d3ec3,8a16a85f,1d2ba9a6,b89f71c8,ea169d3e,923d2c1,7e6e590e,21b28e8b,1a0d0cd6,1bcab7b0) +,S(dae0689f,5a6cee77,f796f488,1fb3647c,7d623348,7d5ab502,6f1ca30d,44ca8afc,ee67b670,f730bae2,a15e6964,33be5b95,43ccc1b0,314cdfa8,c6cc8873,c39c329c) +,S(47a58ccd,75f89c15,46a17ba1,4629fb5b,d72805a4,16a12e61,aeafd8ec,8a7e4e41,c15e7fed,1bbb810e,b4be60bb,61fc1f0a,a4bc43b9,73d94767,9b954f3c,29fdd889) +,S(f7ae2fd0,2e3b6ee3,30c0697c,94ef65b6,d7582f69,5c509698,cef09b44,6b040e3c,ade9f8aa,c527139b,c54d8e6d,ddd41ac9,5eb49565,79934ea3,6a9dd8ad,d419ca03) +,S(155f9ea8,9be2ae20,8d7e9c21,4c244a58,ae61cf24,5d5f8dc8,b6c448d9,7c12989d,1204f5f3,840cd19a,fda04abe,6cbf4490,cf5ea60f,4cd17680,8c1ce9d3,65b009ff) +,S(a83cc9c3,933b5f14,fa5348a0,e0d3ee39,e35057b9,13c5a51,89a61663,1e9d74f6,40aa66d7,fad68476,1e2a9c78,e1fbe478,52b91d11,a283e1db,e30d4baf,f072a74a) +,S(ca4951cf,c07b5c23,298a20e0,fa44b554,d7acefbd,bf2a6cce,11fc3ea5,67b5f5df,186a8bd7,6700cafa,c79791a6,b28c799a,35aac545,78586050,b8012c4f,9f4afc2) +,S(cf92dde6,1bad101f,5e71f2a0,dbc2438d,d6760ba5,b84791a9,ae0ce712,9eb6787c,a7d351b7,f3e31e6b,cbcc1f05,329458e2,6c9d8a9d,1137d595,28f53e23,5c3bcbd8) +,S(b1ab0b3e,cfd8283a,3b79df9b,e83e8b37,b06154a9,6e2a687d,8f51985,129c1179,cdb7f2f3,4bab534a,41f4cd97,b812900c,99e97395,3837f058,12d5d0d6,e9506bbf) +,S(a1743329,9cd4c9e8,4fb99295,f3febad9,197296a2,98b30354,24e9524a,e1789ce,40994ef4,4cf53577,6f078088,adcfa6d7,5bee11a4,4f2f3fc4,4282f5d7,f77e1afe) +,S(241b486,4efcac7c,3c7b946a,61a55317,38b31846,607f1e0b,d0a1a2b,d9c0573b,5cce8848,eec61cd3,325f3ba8,fbca403c,2f980159,bad3997c,832f5c98,1fa0d574) +,S(81f88209,64997984,699559ad,f799ab0b,e3efd354,d258137e,d753e3e4,de91b387,8f9fedb8,5bfd7061,1b9e5caa,5f3cc8da,43bda599,afa29967,a32c71e6,aa26d15c) +,S(49d64231,bd2c2145,200793d6,4a2ec254,c22da96b,655706fe,8fbf5d49,464e5a5b,faec8eda,b0d72cad,81df8121,671c6dd9,bf986440,3f1a702b,548d4333,c751e825) +,S(74c14c32,4fad3a41,1c7e1f15,9b740980,6daea24d,9476e938,7e77db6d,66e0ae4,af795203,1fbee5cb,f031a2cb,946e6b65,3ee0165d,abdb89fd,5aa73880,e0641a41) +,S(88bc209c,7342d94c,be3f4215,81383c6c,930f9c19,d09d91b2,a984b6d7,12a1e7c3,acb7d745,76dd8723,89a88866,e287610d,b817ebe6,1581aa23,46ac994c,4c5b3e08) +,S(486c8c68,c81ca88c,df7b93c8,5a1525f4,9bee242,676aae77,c1bd85ce,2a6eb3f8,e0fec94b,35fa97c,d5e64870,6f5e6849,d6249004,fb33e34e,c1add26f,4fe52d54) +,S(4a1efa11,6c588e23,7b5e30fb,5d0ddf37,ba39043d,6e5faf14,e28ceb90,4a681a3,bb196737,3c907165,a8937dd3,1bce476f,65f2acc1,41bd8d53,8fcfbf1a,997b64f4) +,S(d7745c06,c69609ed,db17f30,8efe7bb4,2632e85b,7f7f792f,8da44294,78eb28d2,7575a75,4d1b2bd5,5fc46e11,b1addb1a,5371f007,f702a97c,ad13f082,39b96a73) +,S(bd752f2e,a3db27c6,a6a08ced,df74a87c,dc333d50,fd9995f4,9ca7afa4,2be68def,378f8aaf,67478d20,ba4725ed,26d50c62,ef5c576d,da9c24d7,91dec38b,a5e9491a) +,S(ef588333,15a3c7eb,c6602bff,ace00d5c,55eb304c,7f3301f9,4be457b0,1f224d21,56eb3aab,6253dfbe,3d9a95f7,e843751d,eb52e054,cb5a523f,f46a0c12,b517abd) +,S(2c1de374,7355825d,a09beea4,f42df241,6b495ce,7edf1f1f,c1dc6043,5253727a,98593660,9082f5d8,8f9986bd,f77672a8,5ff92cd0,28d2c588,73a3b1d3,87a150c2) +,S(49f8d71b,23e60140,f50c9001,6f39b2e8,b78e2a22,a88f2535,324ff50f,280daf99,f66bb665,4807e7dc,330ec339,3f6fde20,308111c8,1fe42546,22b93a86,b58b04ec) +,S(365c9f85,754b61ca,2b2a30f9,954f3a52,d18fdf78,db593ceb,6df617ab,189f37be,c43fefe6,aca56bcb,ffa6aced,60a32794,7681b601,22369a3a,f1405a41,5132825e) +,S(1cf2cfe9,e89668ed,c1a446c4,da311cf2,7e2cb53e,1984a310,8e24e8bf,21f1b5af,71e56dac,43c53094,7b78f104,1a685f23,aebc7b12,e2caf803,6731ef5a,20c966b7) +,S(f3303479,62660226,f391c26f,a7e87796,219694f8,e01cbd52,25dce636,b48ca3ec,7dea0bf4,c110e945,dbb59ab8,74f83a42,afa585c8,56a93002,6f48f8fa,62762827) +,S(b689244c,4bc16c88,398664f9,2297ea0,8756a969,1ae7adf0,587c3253,e4b27154,9b488748,1357368c,c97f89a9,b4a75a0,bd7483ae,5c700364,c27d19a8,e450c856) +,S(bf34fcd2,d6b4371c,fef2f874,5e4be021,a78b4302,240d4517,f3eb1140,638cbe41,ce6888d2,7e326eae,8e772914,e1b43bc0,1ef6a238,27f67546,5464e195,5f97ac02) +,S(c2097a6d,231bc796,ce85a594,44c00250,d51ffe63,c45b9cd1,10ed4821,118d74fe,58b06413,fc4ac173,e1e3a85a,ca674885,d1f92b3e,5b99f72b,1350b6a0,bfe4ac87) +,S(874a6222,3d8804f3,a11b1de,3c647aea,e3e81798,40db2618,4d46a330,417afa81,4132a5f6,7986e622,976b181d,5c98f356,b31668e0,ef70f8f,6b13a0ed,af80b429) +,S(ac7c6e8a,1a05d592,8142227a,b0c3ed46,1f28463c,ccaa3b85,b9784e0a,f5bc605c,1a59a195,581e3397,eba60a0a,963f5c71,c107a9db,68794da4,a08b14b3,118a2186) +,S(3f13e2d8,d825a3f6,8875c01,a1715a5f,44bc12b8,2f254a65,575b163a,3333342c,baff6882,fb2c2611,ffef76a6,8b5e2293,6a2e6ecf,d7ba6724,3393fa1c,5825e3b7) +,S(1ebeb354,515e7f39,dc3e2631,51d0630d,aa7e400f,4c9f7cec,4d5f95ec,bfa8fe2d,a2e35cef,c2cdcf,384a2473,c185f3a4,c70724b9,84c72dac,a6ca11f7,ae5c85cf) +,S(c2dcdb65,b211e765,e6c59218,d12b45d8,b47d8f9c,e22b99a0,d2d19a1d,de02b2ab,e0aa5b9c,a960117a,7289326e,9259f886,8722e032,c96b5237,b146f50e,24f3be50) +,S(495d69f7,e2a9d144,8e2ed8a9,c038f6c6,7f360b8,270c9b85,841e8791,64bc0d45,5fb3fe2a,1dabce7b,83b4465d,74fac6f7,c48584be,134283e7,bdf59e0,957088d2) +,S(ceac4569,2139e4f9,701be43d,8da3f515,270a9477,bad5969d,2037ac87,3453bab2,bd1fd9d8,15f4e872,b602f2bd,9604b6b2,f385ea40,d5520b3b,ca32c160,44908070) +,S(7ed1d0b9,3196b8c0,1cd284cb,c0a206af,4e6dba1a,d6cd406,82f55897,9407e0d,e95a3ac9,6ba60be6,22f4ee73,2d75a9c5,11018ec0,d840ce0a,f1bca18a,1d2801c5) +,S(72fb366,4f42cec8,940fd436,5ba7cc97,ac5fe4b2,131250fb,a24b7178,a1040b04,c182b1a,93a211f5,f5de5c9b,4b52ce90,63d551dc,a21ee9bc,dbba2653,c47dce41) +,S(dd06cd8c,9ca91e45,d6720043,d3e6d857,4690192d,59154309,2160f04,6008beea,cdc17327,6eebea3b,f9fa8a7e,e83ebd81,4189705b,900b3ce2,72b85dc6,c41e7ecd) +,S(80f6129,e90a7f0f,1e650439,8bfedb10,3c708c43,2e2c743,da8a9a99,3978cd13,74d97812,145feff4,a3ef594f,85b644a6,d95a3082,3828c00f,e7226d4f,39deb82a) +,S(56af34da,f56b508a,eee970af,bafb9dd2,b48f83c,4c051b24,f5bc27e7,105995b6,d41dfe52,9e788e19,89105a4c,c219dcd3,decca65a,dcc5f34d,8a3ab0de,d1ae68bf) +,S(820225ba,795565b4,c45e29c,4689d91c,148cf693,a1a1c1f6,ca33c44e,4e3f91ee,3622ae5b,c89b9c2e,66bf5a3,17826928,11a0f4f1,4b387334,b24028be,ba4b7db4) +,S(7925fdbf,cfcc202a,895a1b7c,a8c7f09f,ad388db1,5652b703,3bf232be,a2ea57d2,46f7ef01,c9cb7dc9,1559cf5e,c6d3f5f2,1ebcc21c,a8414d0a,9dc37309,4e90525c) +,S(4b224b6a,f38ae731,5b316eb,8dbd2b1e,6638794a,9bff79f6,1027f60d,5d81808,3143ea08,b1633002,bbb2ad2e,11ffe5b4,b6dc6888,1fc669d4,23ff9cb1,595c3dac) +,S(2c0767fa,4135f4eb,602a1a36,e6ce488e,2c1bdd64,aa4113cd,28daf20c,687380ee,ddc3effc,e78d3061,7cc2da71,1373de0,6a65d2b,1050b89a,5f71be3b,fbc16a7) +,S(83837d3e,e7179a84,ef6ed2d9,41a9f835,37b5a2c2,5d511ef1,982d9bba,50a7ae7c,62201e16,60957b4c,a86f1a49,5a6027b5,fe2294f2,7946c8d8,556024b6,e3b66dbe) +,S(cf075b34,e560f057,53a8e011,835bf1da,25e50d9e,1d70dd9b,da427109,5895387a,c73209d0,330ff4d2,38e19f6f,33df38d7,2b11d8dd,180d6a14,4b07184,a2127018) +,S(d583f8ff,9b1875d1,ef468030,e3ebb7,9d06ba2c,1008329d,cb01b883,7c8931a4,f8cfcf1c,3f092ba,6bfcfcc6,9596b508,aaac7c9c,333ba58c,d55be53c,6fae3292) +,S(551fe9b6,21d2389b,fc185372,342edb1b,27568bb2,da1fe220,3431b792,43eaefaa,6c76904a,e48563cc,c6aff505,7f31119f,ff48e5fe,971223d8,c3badd02,563c24e0) +,S(1bb778fc,74062f24,b0962be7,bce7c990,51f06394,bc8e6da9,a9d63f6e,d16a80b2,2754f53d,2f4ed167,3d2700b6,8ff036fa,60e9352f,1dd7bbdb,14be1740,61d88318) +,S(a150af7,1261582f,8949f1a9,3ff8d539,aa0744c4,e97cfbe6,e4a3fe10,e7e364aa,e22a1afe,a68671c2,f9e12471,56e1bf47,100737ed,5f96fab9,9e0df721,eaea4773) +,S(c94ec3df,727fdf91,d7963a03,8e93d68,835ed2bc,2578780b,7242e15a,e72e2a9e,a476a0e9,7bda53c5,46312b35,f0fad09e,11b2810,b3f570d5,a934d21,7152009c) +,S(3366b9db,ebe13231,7c542739,4235a72a,f186bda1,784c7f25,5f8b65f7,f146875a,5ea2478,95f52889,42321383,5439195e,6b620619,20171862,eea32726,1345d3cf) +,S(616c8e6c,e52265ec,cb85ef36,5092b2bb,58bec6be,444c2373,974c38e5,e0e8ba25,4d3d5543,3d6e258c,d8b286f4,5f41249a,724a9890,2f1ef3ca,ba049bf1,cdaa0970) +,S(74df2177,2e38e84e,8b81d86e,f45dc4a7,2617b3a6,32094b1d,432291f,6a651827,4c32baf,30f09527,fc4abc6f,9c9b9a57,2a9ccf1c,6a1b360c,48746d8c,22e01334) +,S(1814a1bf,76b74532,979966d1,5ef42faa,532f8dd9,bee0cce5,d68fc500,21accbd1,5f5df5ff,da9d439,b2205ad2,5fa93b9b,7af1746e,9b2eef3,154bfbad,acd46bdc) +,S(28911e94,98ff7526,badf2287,8e85fbdb,5f444d66,c422a975,c7476c02,b98625cc,5a341cf3,5cf26006,9d869542,fb221ba6,eac150bb,e3809ada,5e4c903c,1e638537) +,S(d5acff71,e82a455c,3a1ce292,689e8686,f441ce1b,e644e79a,bd6d0efe,29270865,aac6d48f,1b46e970,a044971a,ad13f033,ca8cde96,958d870e,dc7d80,1d26d5e8) +,S(5cf51c1b,2210d85,9d765e17,32109514,8f03fc57,51004b6a,91f098e2,e2711596,1eeb19e0,610df459,2c31e58e,aa2a2148,17fe9ee,a3995838,f395bdcf,26d5c3b3) +#endif +#if WINDOW_G > 14 +,S(21456873,b58e3687,52c75800,8d3bcae,9efaf1f5,c5727842,25e3d854,8fd421cb,a2f2d10,c85e8a0f,4a136ad0,5df991ce,7d3c5585,a263d5cf,da50a4f4,3db76cb0) +,S(c10de5c0,51ae2d73,28ac06ca,cca840b4,ed7ab204,21c6122f,1d68fe7f,7893d38d,ee30e086,a891484,2ad4041,f9ab9c57,cff1a315,f0642d31,b31c2914,faac99e0) +,S(be778032,f12c1b77,9bba3d9e,d290ca90,30ac7050,bdd77a2,7eac09be,eea65c0b,8657348b,a1e27a63,1dd2a54b,e2d5270f,4cca817a,219c5378,4d4f73ba,2c932e63) +,S(a05e7551,f8f090c1,bfc8ffcf,fbf7fd57,9d033163,67d5ee64,b85c4f69,33d0ff6b,8eba561a,f42d43c4,99e1fafd,43b49698,a8f3babc,c9c94c4c,4822cbed,a741b309) +,S(6e4d47f6,b17501b8,f3b220d3,83cf5f11,a395c0a,f0023988,c4e7b8b0,ef66ed23,e01c4330,16e3e6a9,535f1d40,905e9b3f,8be9f05c,b53e6143,e81091f5,4b76b57d) +,S(f626750e,b7eacac1,7cf24afd,43345019,c6c32292,c72503ad,d4125d40,67b7e66e,d669f903,67f407d4,5307578c,ee91fa01,f030bb9c,b66c7111,34b91757,1c993f4d) +,S(437acc60,c555f7c4,778595af,db4676a2,1fc8b3cf,2c8538f,cecbae12,811511f1,985fd2c0,7385fba8,4cf25a1f,46cd2c3e,de8dd359,1c6d20ac,584b4a8d,8a65dd67) +,S(8d50555c,6245e43c,a619fb76,ce45441e,dc585c7c,4fb2f33e,1c07965e,d4e35f5c,ea828c37,331ad0aa,44d168ce,c328a9f1,c7deaa35,47ee4757,c776fc46,439ea5d2) +,S(87f5f6ae,580ebfe7,1b2c19c8,cfe770ce,cf8d4223,62718914,eb853f1b,7f4cbaec,eb61df09,12e06f58,ed6d85da,7240dd72,aad00c3c,6a3a9c11,1f378664,cf359386) +,S(c1cfcacc,b95e6577,4e2a7d12,3cb0071b,3325c27c,5d58beb6,781a30d,ff6306d3,fa9ba55,cd95e721,12d98a19,8e3769ef,8cebb355,dde5b62e,e6f3b8e8,52a3e81d) +,S(d68bf50c,89f25969,a765af90,854bdb89,d67acdf8,f1e16bff,64868338,8b88e311,b62d1866,55835dcf,8064e13d,aca1e896,2157576,a02e178c,78d27c99,9cce81a9) +,S(b8d7c25b,8c20438e,702197cd,a3bfc05d,c6577717,c9b6a527,15ef84a0,2c0df867,316b527d,4be0e62a,2015f15a,17a412fb,72ebbffd,b02e53ab,6e5e9791,b771b45c) +,S(d98b3403,a299106c,9c6fd52a,8abd9ee5,cea9ab0f,17a15b4,7eafc809,c34e356f,bebcd24a,9300c739,9bb3af8c,12fa813c,78c6838,dbfa00a7,4ab09669,4df9700c) +,S(dcd15a1a,7cccd53e,db08c2b2,c6367126,de55cc46,a4eaf5d3,335ccff2,1238bbdc,7de57d26,bf74764d,bcc7e15b,72ec272c,58061f47,cc0715ec,48bcc032,60e63a81) +,S(2f6a844e,e758e3cc,8f299e01,ba5753a9,d35e6c51,6a87a683,8f5ce28a,fca17c62,5c29172f,f907c0ef,95e78768,2625c8ff,27e26eb2,cd86df92,b9371203,8b332e73) +,S(e63add7a,e511eed6,93f62498,17f89221,c7a3a909,253faef9,23f37a64,9e2a2f67,c392df22,5ffa1438,c3d10c6f,813c3956,4f94367d,6fa26c63,1d562049,99a77e0a) +,S(f9955ec9,20fc68b6,cfcd163f,34bd033f,4ed7dc8c,30da7f16,e41adb,908c9b7b,4dfc49e4,ab583975,90bdfae8,56ce97af,91c92f60,a17df9fe,9ee923b9,9fe2cf14) +,S(d974d713,bce1db76,c5ea1143,b63ace02,5a2362ae,fe6b84b0,ebb0c49f,22341d7c,991181fa,3ae5f188,38a94047,9ea9e4dc,e8ff9366,78583189,bc340d2b,40481577) +,S(4f0af691,424d441c,698dfa3e,c3e56bea,e2c52fa3,bfd9ca45,763d7805,33a3037e,caac2486,81590630,b0c67160,89db929d,26a4e15e,b06aa9a5,2e19c92f,a9f9817e) +,S(ef6300a0,70060df2,3f9818c1,6ff4d315,fb1c7d4d,fef41e85,c96760d1,3cea49e7,a0622360,2def9738,d87803e8,6405bc00,88afa82e,39666246,10f5d935,993334fd) +,S(fef30954,1cd2a90e,1d473ae3,699ea7cc,ef69fe75,54f7d710,33b1f23,c9e96886,c2479c48,59423c87,5d76f6b1,5c671ed5,c9489af7,79266341,4ca68675,cab64fec) +,S(457cdf17,b1230409,c3d35a88,390f1bef,859994df,3ba21d2e,ba5f826b,6dcb4fc6,5aff71af,708863df,3074c236,446ddd33,5695c0c1,a45bc482,e0787788,a0e4ede3) +,S(a66e86f,fe0e9cfc,686ab0fa,11b641f4,28499f3,450d69a0,dbce1895,6181ea39,de0cb1e5,ca720556,7c6756ce,868df6b,5174887a,61afd354,653e759d,b3e3ec64) +,S(ddad5a09,c37f0de6,67eab59b,fa2cb47f,b79bf6f5,b8b0403b,f689acfa,627f1014,8aed1b91,c9e567b1,9806082c,79ec433e,1a152279,69df00bd,239fd8f3,f8e8d385) +,S(45c5156b,f1439eaf,16a43b39,5c0a393f,a674e17f,76f96d53,9aa6c99b,49042c42,c9bcc2ed,c5b5c8c4,b17d633c,90d45b9e,1583898e,41bb9d90,1d1b5097,57f5f516) +,S(c83b3c9b,564906dd,60049c3e,9f6ed0fa,b848366c,3b93650b,7923e9ab,8172a8d7,5709dd74,1326ab97,8853304c,a02315f1,1f0bed5e,bffab6f,467816b4,4c60a332) +,S(a857354,dd08dc83,ce7b0324,7594e4c6,99692c95,9a4887e5,344cd0a8,7970174e,becb7001,ddafd72f,1f845579,ca8d56d7,2145c8a9,be816924,957ba324,3c396691) +,S(8bba6b47,88259a19,578adb4b,6f7f51f8,d09eb70,ea790d62,abb2ed45,84f94f33,afa42da3,8526a485,60919f12,d30549e7,1d19608a,81f4cf6e,8e49cb00,2492b143) +,S(bb4d27eb,412e73ca,d2697d6c,46a143ca,e4420ec9,30440025,47aefb71,c99a53d0,9ec07a19,842a1e5c,9cf9f76b,55ad98d1,9485e683,b6b6700b,c905e190,bd9da19) +,S(af6f6827,d197688,f00dd3f5,ded1849c,11fc2abd,f90fc7f2,18b33776,e5753277,f9227693,c9405a2b,10e9b725,aac7ed35,eef4281b,ca04e,bd75b143,89323646) +,S(40453814,445cc67b,e7a4b71a,55e0b993,2b8b3477,f093df6b,f27f55a2,8bad2e1b,ec71d7d5,4e823687,d01d7558,6de9a1a3,7edc927f,e221941f,46051747,a69baab4) +,S(f35a6c29,bd596f0d,93cabc3d,c07b5f68,300f6ab,8ecde5d5,da8299d,112c7bcf,73fe2c46,e1b13112,718526f9,7a39f1f0,3d47ced1,84a2e4cf,1e32c168,1c470121) +,S(ecc7ce7e,bbe5da1a,596bf41c,4d19b51,b77f7019,bc431aba,e5ecea57,b095fa93,1ab89d03,9e7c6ddc,7751c9bc,4eb84ed1,b077cc8e,dc828ffa,37426609,e089c8aa) +,S(559820d6,bb3e47e,f68f48fe,1259da06,cd0b380,1f6bedb7,970c079b,7e373bd9,2373137a,a4d88574,151540cd,ab8cbdbc,5831fb7c,4b901c27,8c9a593,172a64e0) +,S(9c9b7e18,4e76bd16,856addae,9352590e,310d653d,809ec800,415f3c64,149be4a0,182cd167,55eedfc3,21d71199,7543b26b,d08047d7,c9363e23,20bb9516,da37a146) +,S(88e4e3d2,2cc3e6f6,19e62ffa,c7a4aff,63b16733,202e5410,52cedde6,9cda2733,ec6e32aa,498a7a30,e1c47136,5671d356,bf174630,d1b984ec,d9453e24,d275e067) +,S(7f2f8043,8e7d7fcf,593e337,a91b06ad,3ad1c461,fcee7bd5,82df516d,cb1c198f,2cb484f7,5a4472b3,230369f0,79f5e654,8dfdce60,98c4e561,a1310224,13dc1d80) +,S(fe0c5945,c5e67d74,ed498120,dae194cf,33a3fe5b,ef0f1ac,2c64c292,59827d7c,4ebff1a1,7d59c8c,469fad0c,79ef819a,8a897ce4,c0fa1121,741c03f6,cab0f659) +,S(ac0662e0,1be37c28,be457bc9,4af19e72,34a9d3e0,8667c009,ec58ee79,7e539642,b3adc375,bdc81a76,8385c9e7,2ecec61e,9b2b21d2,55f65450,c5956187,837f3767) +,S(15e0f7bc,d74e77a,af933c13,6cdc5b1a,1622de61,251090a8,f8509b05,d7dd527e,4d51a063,1fb81f2,fa1ef534,5fa306c1,a0c64f94,66961cc8,b574b06e,646767ea) +,S(e4119d0f,b79bd8c,e1687abd,4ad63790,814f9972,50fac9a4,f1b52d71,93ce282c,cabde097,8f9a566e,32ab229e,63bdfbd3,89f01378,c7d27b0b,f101cc3b,36bf3fe6) +,S(27a5b030,2005a21,5d89c0b3,4e4ee323,5e94742c,262a89b9,29e286c0,ab8e3c24,4548d58c,3792f7fb,18238cfc,993fdb26,f755379c,e0ed1b0,4df26132,8f987a02) +,S(a18ec59f,7621c8a0,59bcad5a,12d3f536,142d5c94,4c7a54d8,b9206132,d993e08,abd8204e,867035ac,8cde70cc,f7daa29b,d47b888e,1faa9be9,b20744e6,ec5a43a) +,S(9bcc19a6,71b787cb,9da72c91,8d7b2264,b9497ab6,313de85d,c3efbeaa,2f492219,4bea790f,67b8100b,9ad9a301,61e3bd9e,583daec8,b77f4628,568ed554,70894bbc) +,S(7ccb2731,cc3eb3a3,36d36af7,f44a0a64,e23aa0b1,12ba0e6a,11280c5e,1ab36205,8d60552,1813ede4,dcfcbe46,c75c5aef,7ec40c69,99cf301b,28b0e875,3031c6af) +,S(94107245,fa13427a,7d21f7c7,cfe0c4e3,2943821f,da0f77b4,23fde091,ba596939,89846c62,7868b1c7,4c546492,dd4821d0,cfe15fae,36896af4,547deea9,295ccf84) +,S(959bf7d3,989d3460,5f4b8f3c,cd12ed86,cd0a2a93,a8d4e1fa,aeb5d6bf,24f1115d,7cc703f3,5417d7b2,b7229626,558be68c,66a915fd,7cc52829,dc98c81e,c0162b7f) +,S(8e92173,ff2de4bd,f468e2cb,fbf6264c,5fff8f23,2fb57e1d,2a07ee75,3b45e7ac,2655133c,8833040e,4ef4c98c,e5c75818,be781f42,cc0b7314,7baa3ef7,99cc017d) +,S(4acbd2e6,98f349cc,42998c5c,53de7b6,3dc29b1,c2b8a569,48cd3489,190f0255,8837f8d4,15b3551,4544878e,1a71922a,ba4a0790,22c74b60,325c6f49,a411b978) +,S(f79cfd2e,b63f6be3,bf0f12d1,fea3524b,1188959a,425f5e38,fa569648,df433fce,9e412cf1,698805e2,a92114de,5694a925,17c31f49,ddca7e0d,b2d83d80,74d92b2b) +,S(41910c81,78f7a61d,7957c065,5d7e2596,a0e6d5e9,a0a9cf23,28f23569,5d818c76,26b318c7,e8a880ec,94c59a6b,d6f1cad,84031d0,e62ded95,1e265ba8,c3603367) +,S(5a864466,9fd276ac,ad8782d3,51bc27b4,9445835b,75f70a80,2ef42a0b,4885cfe3,b2510d98,60be4e66,edb8c935,3c8ff8d,2e008c37,6dd271b0,1f77276b,f3a5a48b) +,S(5e3974b8,1b87348e,e3ae5c83,2dc56d1,85004b16,90445b74,1b8e262b,ecfe0e01,63f644bc,397a1809,a4d57ba8,f18f0372,cd4fd083,1c3d3449,1ef2a654,46275568) +,S(154e9c88,589ff342,6fe2eb5e,dd6e1db,e253498b,2c0b3e0,52e84211,caf9cc4e,3a897093,df7d31c3,754f84c2,68b0594e,85cfd4a7,c2731fce,e01cc3bc,2bbc383e) +,S(b95aa134,e48967f1,bd3a7a48,d89d550e,3c3c3c6b,3c73de48,f2e6fba1,81c93faa,b6f2d3b8,8d0821b0,6b1134d7,ddc898fc,e84898fc,4719f8aa,e3570daf,168b03e8) +,S(316564c4,ff00502c,f159db79,62984516,4d6d24c9,1f20ba73,66669808,95e58b92,6110a6d5,39ddc,d4185b72,cc576b7d,a4577e80,3dd47a92,d4bf346d,ec5905f5) +,S(222b179c,29ff89ee,d6f2a0d2,d38c6246,33237c5f,7803d8c5,e4315f93,6a9bd225,8bddc333,6eeb3cee,a0c3ac01,e7caf4f2,f44a50f2,587e3e31,7046c85b,a57cb6f4) +,S(10347fab,33fb4ee5,6cbf75ac,6cb768dd,f51f9b0c,5498466a,6679439a,32048904,a351f45e,30f32caf,e10d99f6,9e9e4be,c3f4aa22,5388984,bc45bb78,c0c5148e) +,S(7048c0f3,1e600042,4544e9f6,e26783d7,baeb411b,a2c29c7a,5aed8953,bf831629,4683ad69,1d9f14a3,f67131bc,55d28c61,1b78b2aa,329668fa,8fc41736,c95840f7) +,S(a65f7371,b35de05a,78b71171,40ea9e02,7b777785,13fdcc3b,484ad9a0,4bcfa1a3,41d1268a,77b31744,5a270f73,956bbcfa,3f291770,d248d1e3,364b4aba,72b961c6) +,S(dfa35552,8518d1da,ee31f04a,2673d053,11db4eee,cdc81f15,bce79c64,3267a315,19ed047b,4fa52430,18863cd1,d8ade0d7,dad60ecf,10b767ab,52f5cef5,9eea9a8a) +,S(663ec2a0,80564f1f,943a25b7,2f60d3a4,17b62130,3015e17c,85782460,c601a48d,fce25852,5a4dbb52,4057f8fb,a4393116,ebcffea5,5ae3459d,3d8b19b6,a0387232) +,S(cc714eaf,26f9960a,b2cb139b,d2fa0928,7a309c9b,ea852537,e10b6333,2912431a,c1c5c0c,48c98ea9,b57eb13c,fa64146e,67a95569,b45b8643,7752b037,9269d070) +,S(a6ceed6a,bb8f1ac6,13799527,38a19b35,ece44537,e74e9185,a4ce3939,c14f8e77,c0090ebe,d410f2e0,2e56b4b6,adfd5495,488c2930,2c5e7a61,3926880a,88beedae) +,S(e0b0c34c,8d4f77f1,dd09ea34,8b0ec683,cb5ca777,6720546e,27ffcf55,a5e5bded,ed4adb20,ab5da65c,2d1d5d68,9ad63ebd,90170904,65f7ad03,1bf3d811,f407d09f) +,S(2362ff0b,9a2d0f7f,d779a83,8b26da93,65730d32,bc4411ef,fc4fd182,d9e486a6,d3eb4ee4,42bd6157,557e4e9a,dcc9c103,892ca05f,5c5af804,f736ecee,d8a6fc3e) +,S(2f1636ab,a1516634,a00a464b,aa30c507,af25e83,3f7f6fdd,ccf0706e,d5fb57a0,a664c955,c24a54ee,d56f1aaf,fc853c2f,6a81c53f,1ee36c48,46b26452,fcbcc054) +,S(243a8fff,6230829c,73368eed,fb4d62f5,bf478b4f,1752400a,91ac177f,70c303ac,29318b21,9f371dfe,4048c4b1,2f5317cc,b2e9c44f,ed72b537,a2f56d06,65229235) +,S(b17182a8,5f442a65,839230ca,5cc8f67e,835e54b,e0296c6d,e2b62298,74ae804e,11a4fbcb,9f6f8775,9d131a81,939e0125,7f7b4fca,e36ea644,4da3cc16,a161e5aa) +,S(5c9abfd1,9cae1a47,bebdd324,d11cf758,a1224471,6e83795,e42ff5f5,a8142a6f,38a38db6,f64d9d07,4a08a909,28768bdd,adbdd858,79ec847d,28c94dd3,a122e0d) +,S(44a8a4f2,ec3dd02c,226ae0af,d73a12b9,726e03c3,2a41099e,b70cdce2,767e390c,b7e18dd1,e6adcd88,1d1dbead,e1c83ed0,1f1d7b2e,50246539,b6bc2811,d63233b7) +,S(8e477766,c4de01c2,5cc17218,7f3cb6f0,dbc8eb54,fa888911,33131b7c,219e6e13,ba8f447f,10286c86,d1330c82,2647a999,b4b60e56,4131986,a6c05128,a480d83) +,S(c5f862ce,dd253879,8100eea2,92e860fa,321d7709,596a4dfd,6faf6345,82fcd3ae,81ab1260,684fd3d8,1b47c5d4,d5f0c319,93ae7db4,fed1a781,61d9d9d4,50ff831e) +,S(a674db01,836fe328,8566d977,753ebc2e,d55f0116,5ebf0349,51caecd6,ebf899db,12ae8327,737f7db3,56e26fb4,1ab306e0,2294136d,71206f43,78300b95,60f580f) +,S(b0cf999e,f11dea14,3e6b6254,aedf30aa,ba1e8e92,96c500f5,481eee45,a0e15adb,e4970d00,e02adc6a,be5e2433,7e017dab,17a61de1,d977ee99,969591,91a5563a) +,S(b3615f09,29f9b2a0,6a4c68ef,c844ae5,54959ffd,f03f9266,f918f16a,b517380b,31a7675b,83677cc6,ca87c525,27fbba60,d06ea317,fefb17a4,7d7a4242,3595f1d4) +,S(7be97bde,b271f807,96930353,b82c3cd2,c6cce373,198572c7,d289511d,7cf262a1,1af89a8b,cfa4a399,bce5bc21,e26c97d0,5126f8c3,211d8051,626c4f2e,c6f128b6) +,S(692e447d,df9c77f0,2db1d34,101bc355,519d40b1,3fff2cbc,aafeb555,29473d4d,d21950ec,fb7bb723,4e4e48c1,98b93a10,8a85bb5d,5228116e,da6f5cfd,8968fda) +,S(61b6fe3a,21b0bbd2,dfccad11,5123db4a,98058bbd,4f8a61b5,e416b03d,b1414243,75d3dabe,f3e2266d,65d408ef,af6b32da,7591f08c,7fe7de,ff20b9d6,7a3a8a8c) +,S(fe0f9f,aa49555,2afe97f,8462869e,e8a584ac,3c3fba4b,886208f9,fe260ec2,a9c0fd7b,cfa239a0,299afa47,e2861197,f382a331,7607e129,967bb22d,3ae3077) +,S(7f7c9a0,a240180d,c645e77e,c628bff8,fff90d48,c85d2fdb,faaf76d9,b93e26a2,1b12ec74,f801fbe3,ddeeb37b,c940c605,84b0ef14,85e9d888,f3f81c05,607d1222) +,S(3e444ef3,b77b49c2,75aa0524,77da59d5,a68dc6ee,6288e2ce,140512,92e54c60,e211ba3c,6860a898,9e1ee04c,ea9ddf52,25ed88a2,c6ecd9fe,3c2fd500,88367b7) +,S(4844747d,d33f7e4d,39aee79f,138b5fd9,223b4e51,c86e4894,c917a3d4,746d824,68cd147,2560b5d1,6b9bf538,b7f1e193,d2f220f9,ed9f742b,d36a003c,28e2357c) +,S(f0211c1c,8f87fb96,bd591255,6a799865,7382380d,6b5b020d,9095f482,4e8f531d,649112c5,9cf7a8cf,7f9d920a,6b6d1102,d92441f1,1bde7561,9cda8eb4,a26d7493) +,S(918118dc,15520a31,c715adcb,3e02ca4a,4d77c92e,310ef057,3f9c7a4b,d5d2d54d,37d2c580,337de379,925506ab,c6b7d9,4a61584f,4cb2179d,560d3a7b,406873af) +,S(78734d5d,833a5d24,5546e5bf,9d3e5ce5,61f818c4,a4c90fab,c8ae4630,a2c307f4,4b150c27,e054fdad,73506310,80eb5308,b39c6861,23b851ba,aa2349f2,c26b5981) +,S(ee988075,34a02de2,9fda41b1,c821c41d,3ddd5d85,9c5a4ce0,d14ad743,25943f13,ba7fda65,4389494b,40a9fbbb,4b72739b,6f85effe,245b895c,b8c7e423,8d6b7973) +,S(4a821b26,bd1326a8,26be6fec,b90229f7,d7a37a2a,c49e97a2,5bddabef,e854e509,8a645892,37ea07bd,929aee46,6fad63bb,5612de36,cb951200,b9faaec8,b11bfdd8) +,S(23658500,fe8b5ddb,93dd3b50,a46f9914,d04af9d2,2a786be5,9c0fa7be,7c3eb2bf,840e5cca,f9f3e8bf,fe51c1d0,a84de234,d7122cef,fa1f0ed8,9f1701ff,d17c40d3) +,S(71dccb97,7f8e77f5,a03c8e8d,e4b2a30,11d01e13,549949ff,42af13cf,d7ecf208,b70ad10a,5f03ad94,dc8d91dc,e7797eca,6ace74cb,4715bf6d,2b628bd5,f767f34f) +,S(6174a230,e15b2584,7a25217b,9d95f07a,e183f2e4,74d0503e,108994cd,69d20e6b,18cda952,ccd68c2a,5d78060c,6849fb21,e2379b48,425003c0,6f148a34,bf876efb) +,S(57cfc1ee,38d905d2,897dee9d,105fd4b6,90967618,2a2a5d3d,70781cc,9134bb97,bf6b5fa6,4de9110e,7d26e67f,65cd2765,fcedc182,1627243d,a85bc955,2bdcac33) +,S(26605be2,e03705ea,7f199cad,d4d6e711,9805453d,6d4feea5,ec2ae3f8,cdba59c,ced5f775,b62bddf,5935acd,9786847c,e7825da1,5807b117,7459f51b,72fe5774) +,S(6d89e2a6,9ff96c49,a3110a5e,7e17421c,4ca2d07e,6e807a3a,98d79954,7fde2457,4835767c,8f96da1e,78f1788,d9764dea,e4e4a0cd,238ff35d,851ee7d0,9c915df3) +,S(e3607608,338f4229,d77c51fa,cef2697e,f6010c8d,5138e0c6,2b724ad5,6ae79a74,da6a0617,a42d6ccb,44155f27,7c56c58d,42d6037,d234f1ee,ffd720d9,2ae23373) +,S(c8cf20c0,c12de1ba,1ad4dd44,46f76533,7cfefc3e,213c426a,e0cd25ee,2e8bea9a,ef7285a5,ea7393a0,cd78ea31,ef74f605,3d3312ba,f17bf6a0,77b919b2,33227ed2) +,S(f3d2870,fe782b7e,26a1a4f,9c7c3ba9,30e0ee0d,df6593f1,9bf11509,1fa63477,e470c266,ae26fadc,b2780985,9b9d60ca,fcbd9de3,5dfdfb67,9f4fd450,4ed6f3fc) +,S(702a6778,bdf2f3bc,4ee954d8,1e7acda3,1df7127e,a7920e59,a7028253,9019c6c9,2ce19ef9,10d773d0,cc32a503,83f9e968,ca3e407c,c1dfb652,377d08dd,1dca5b96) +,S(ea85cddf,4f79d7d2,a5db06ff,f1c1e3b0,87b0242e,1d7de713,53d8f73e,1bc83888,3806d40d,ccd867c2,2d166056,77d2d64f,d7433dd4,b1e83e25,91860599,2e66fb83) +,S(d0631e8b,30ef6467,de6af60e,61b99112,1949b324,786ff1c2,fe633249,a832aec5,deaf31e3,703df166,b0f92ee4,eff1cc02,684911dd,40054bed,4b21d4da,17f4c05c) +,S(b56cb88b,617a7104,c205e089,b83320c0,5dce438a,50411e5a,d342e9,8b258a3b,757edc72,52d76fbc,24a5515e,417625ae,11db0072,24c02fe1,1e249064,b5127800) +,S(e91ffec8,bc3fa3bf,b0a600b6,89db92ea,7c3ad411,d025a42,95570596,f44702a8,38fd56ef,1f7b476b,2e36aff7,73e190b8,61ec6370,f6ae524,d5dea16d,cc4833c1) +,S(4cd9e6c4,8bf7b1ea,9f855b14,fc904ad4,5e3bb71a,5745b449,e1ab3165,3bdf53b1,b5a075d5,ca9060b7,7d3a00c3,6fbc6404,88df6846,c712afdb,1115798,f382b4e9) +,S(abb07ce9,c4b711ab,d01a12ba,45f0040d,e3ff5a4,e59140d7,cf4ff289,42b5cde0,a8a0e68,350a88b2,397a162f,fc969d28,ed937f60,4704dcf5,2faf755b,d21f503b) +,S(95fac51a,c9deb5d2,b794423,a71cd282,b0604afa,bb3160ec,557a8b74,c578f18b,da99fcf2,abf21cca,c6f4e89b,de2a6e9e,ad199cb4,b97f4122,4f68bb47,b7caead8) +,S(2ecd3e62,b79b4f69,609f33f,2042b56,bad2a9a4,18e2852e,9e8f0d41,1fba8ab9,ef964275,95061068,478e11ec,942b6a2d,99e5b557,830ed0c2,c4291305,41104046) +,S(437d446a,d139d88a,b5437f06,6fdf8acf,7b538798,6baf9551,a414fd4f,101a6440,6c532bb3,38a34a07,28d3273f,e9d9c70,aa79c484,6cb337ed,b41f6029,1e2caa13) +,S(63149b01,94b4955c,1b7e9d51,24e7e7d0,4bb5d902,7e86e63d,f3add9c4,8ab2a44c,c867234b,b4ed27d0,dcdf544,be060a12,4c460c5,7a9312b1,46d2bb61,fdfa6c1a) +,S(78e509ae,99e6469c,41c44dd6,868ee402,8fda1cf8,2c83be01,9fdf912c,1e638bfa,ff3b584c,5ffcb1af,4980e2b3,ace00f12,3be630be,cd91d045,4e031120,245e92be) +,S(cb1d5bf3,f97b2bc4,bb33babc,72de78ea,34cd0a0c,e841cb55,7b3dbc98,61e1544d,e619e8a,dac79a61,eb46add0,96bbcbe1,31d33a6e,b6c99220,123dc9ac,3f27df60) +,S(3247eaa3,9ed5b604,d3038127,9661f350,53ddad8b,8e29d0fa,5c27ed6f,551cf374,1d29a713,d7dd351d,87175b49,afab518b,f268ce81,7fa39ccb,f08b3c58,de1e5378) +,S(d493ab52,8d6c627e,aa3dbd3c,8d809ba9,8a9fe920,307a0c66,2917f8cf,f68b3941,30e4336d,e1621a2f,fe7247ff,157a37c1,edc4f83b,e9fbd84c,af4f96b,8997c7ad) +,S(8dfac8d8,b65eec8a,a65f96b5,571830d9,22469450,42fb2baa,f76a4db2,ea5258c6,c204e9c0,72f643a4,1f53d8fa,dc66e3f0,fdf0d000,c27a5492,6323b2bf,b376af16) +,S(331ca867,1098b530,1b1e6f12,d231793c,de67de5c,640f0a1b,fbfe485e,5d2adff9,b52fb89,3a466c80,ae61d534,cb03fde5,95078592,1da21e0a,a8103d7c,c2e3d8f3) +,S(f34a338b,bb05db6d,55beb49e,526c9d49,fd515792,f407397d,3b520fda,3ffcf26d,6a6921c,4831df6d,91e7cafe,869c4274,faada27d,9d09175e,e86a0b9e,dd70910a) +,S(56d97dfb,284c7417,2e08fb73,3a2d0305,ff774495,2f229bed,cd36e7ff,6058e75f,3775df48,aeaafe14,a8005434,dfc19538,2d10ca90,d05bcba8,edddb2ce,4a4ed7d1) +,S(70e668b0,e854cd8d,d3469cc8,ffab1709,2d9341c4,4831196d,72d9673b,43dfbf7a,60567ba3,5546cd93,f2c356e3,927dc89a,c43fdf50,5e33ca9b,52552587,c905e311) +,S(675af615,9fb50100,56ebed3f,4c9784d1,17538d58,afc5ec75,fa93ee00,29d32390,c501aa90,4f9dfa9d,78107844,983e17b4,34872e3a,a94e37fb,6677186c,fa1abdc1) +,S(99f8e5cc,86ac5587,81a67270,3059442,88b19703,551474a9,9d433d6f,37672d90,30148ff0,9fa33b4f,f4410d57,9afcb705,c1146663,bdbd0fbc,8434f4f8,eacb09dd) +,S(8dcec207,3d74b9bb,bd47f52c,394b263b,e71881af,363bcd80,9adc345c,b9ce9892,d8bc1ef1,79ac54e2,68a685a4,db35e3cb,5b6774d8,e8d6b738,f4d65b66,86782a5d) +,S(d83f7e8d,adf27d5a,f8502d8,3ab81001,a2219805,d942cbfc,76db2764,c4235773,48472e1b,2609f81a,8b12326b,1b19b422,763b0ed9,d6fd67,51751c2f,8aa46c2) +,S(e6f8bcf5,d9ea8209,cb46ab60,643555e0,d0569f3a,dc62ac76,edc09a43,e02fea2a,7974cbc9,5a9dde1f,34560043,7b628eac,3641498e,612c19d9,9a79ae4c,cbde2d82) +,S(d2f30716,e4c1a665,a37d0606,3987d0c5,c19c072b,f1cca8ae,cd0e4d8,6a9e8c1a,e26e6d9,9fbd198a,ab83d0aa,ea53228b,539efd37,ee7ee791,365cabd3,8850eb29) +,S(d7a891eb,551ae5ac,baf366b8,65755a56,edc7bbce,7304a806,2729655c,f7f61cf8,8a7d915c,3a9a1500,616205eb,798915fd,9b33d7b0,6671e9ab,cf02b5f4,667173ab) +,S(5bb03484,f02ef87a,fa07f852,e3ec0664,67ffdc38,39fa28db,de0da07,2fc31246,e0515751,c377266e,ff95f755,f9c9373d,226ccb66,3678e8ef,176af5f,2fea3504) +,S(58716b31,48a0cac1,2024760,60d3734d,ab066ad8,c0f8d8ed,cf5824ea,83e111ce,71ae487,701d16a9,c1d2ab68,1ec7c8b5,8367a4f0,179dfc18,6778579c,553cf608) +,S(4a344869,db8d561d,96944c8,94a3c196,8d649fcc,bd430c7d,4a66ef0c,dc2ca550,285433f1,ff0e7dba,5bae081c,1b33c762,6f30224e,dcacfe66,46787818,da0f810a) +,S(3ecc369b,e7789b92,cf1448ee,28c0448e,ebc5d277,a8bdb5bc,a22d3151,5e246f7c,a5532e1,47848951,cf11e065,3f0627c4,6530436a,5f3773f2,b02c9bea,c1b60e78) +,S(28a5d794,21db38dc,8d7c8cf9,d120a3c9,97eea170,f0f6ed43,7222bf4e,27f170be,88cb09e5,ea40b566,39cce9ee,1245384d,2f02f983,3b3116b7,31ae5576,daed7cf9) +,S(4f54f945,b3afc07,c38e1aae,16dafcbb,b7c5097e,4895a789,e70e0993,cbc905f,6ba69303,24adb3b1,2fc1f8c7,8ea58729,5115adad,52bb1138,7281b9b2,997fa597) +,S(f490bc4a,20f1ecbe,ac2dbbd0,56f2bb77,d258a914,9b0732a,f29aef2f,7ec25f47,aec6fa89,74c124a6,576475a,60931a6b,533d0da6,4e621fe9,c298f03c,a894336) +,S(73b2f8d0,e91e2516,d2ebe348,85b973d,4a0c7919,1ac857b4,74f713d7,348d343d,9dd7a951,efdaa060,19ec71b,e41b294,d047ab97,d0cef4ce,25a607f2,f11bbc26) +,S(d911f5e9,977489d2,847aeb66,8c3cdc6a,ffbc7b5f,4a5aff62,1761ee01,567c5647,3ee4afd0,2ef6d3af,a2b16d34,b59444a4,2c70b3d,4db17788,ad3aac57,184e02da) +,S(87b695f1,5c5d7852,88218586,96bca8c1,9c5a6f3e,f23786d1,fe010fd,d063b0c3,21b54a,46ee82fa,bb5ffe0,e3137892,31623502,9a8e0505,645a9ec9,29984895) +,S(39de5a90,4ba6989e,5d16dda,a7ff67b2,15e08f3f,b593d7a8,4b6babe2,ca25c658,eaf5e6c4,1e1e2fc8,c1581f6,211bc8cb,34dcc08d,58f570a6,e6719626,7124c019) +,S(18c1f673,ca19f805,c426162f,11e7eaea,c675974b,6b4cf0f5,9eb03288,83bb0af1,ad1690ae,65783091,27f602fb,93652b59,d7507414,e76d9b3a,82fef166,68b7aecc) +,S(8d70ebda,893e8d03,d15fbd68,67528b7d,308ddee7,b2620698,15e7f3c7,332d42a1,254be26e,d9e9009f,e4aceb8a,b97020a9,9196a9be,60777fb3,a9d1243c,66df1707) +,S(c32fa0af,ab39b1c0,c96852cf,8e2382e3,93e5b59d,2e83ed50,d5307a0,14ea330,381e8afb,85d47c3d,dc5da037,d6bd82aa,ff2324ef,ab0e48d5,5da3fcca,bf0ee3da) +,S(c350235f,e5ad084a,1aaaee80,d156b302,d34ec03,360a7c0d,3a883cb5,19f4b27,e5ea7c5d,3184e9,b62fc3a9,6c8bb9ae,72535fc0,497f1b58,67bbae06,672a1f79) +,S(8ef5e1f4,8d905df,dbbba4b2,d4b22162,db839ba5,b28c755d,46bc2f00,e25e20d5,6300d9e3,11971dd8,a3e88192,84f3a228,9986270,45b901a1,80f831b2,4153103b) +,S(9b3783f9,c638a6fc,166aa2a3,3a40d95f,35a4e7a6,c8cb5fb5,1e596b9a,f285279c,41b2dd9,c3abce77,fcf798a9,159f36c8,94b55ac6,7c917de8,75b18cd4,e70dcaf0) +,S(c262215d,720180ac,669f0bb6,885dceb1,2c941730,93e561c2,660a4a1e,cdf0a244,7fea7ed7,f654741c,c67b12b9,f115aa40,ce427cb3,8c6498f3,8bd291a9,d73e9f2d) +,S(bb72f723,f0a16f09,7716272b,b905a111,c290c229,94f400dc,c6a24814,f41816f9,52a83ee6,53214a5,3ed2b13b,a367324e,e5606fc2,e3dc05ae,7ce0cf05,ccd6c36a) +,S(d896a5a9,a833d66,51b17632,70b03d36,eb423236,bf3b2b7b,6b2ba97a,f9282a03,e8a823f,ecec375e,280e0d50,49625dc2,1f48e269,77ab5eb1,b467d3e8,a0fccb37) +,S(198cb33d,9a2b790a,2d6fa355,58733bc7,f64cad76,e3921dbd,8d7a1f,8db52b64,c7e93702,ad7df0a4,94fba344,8a8157bc,eba10ee2,8f66f000,7e7f7655,8e6b4a74) +,S(4354e475,81d63d84,df19bd08,d98b2315,67a55550,477e1c53,cd425854,e67cd81a,a612c262,74d79c46,89734884,5b87ef50,29d0f87b,4a06e4a2,8ab36bee,ae6a6ce3) +,S(d956c71c,1c8b110e,19f96ffe,5709f2b2,83a095ad,977878fe,287de35f,283b2606,7c029c97,9a807375,bb589c12,a20ce37c,75178be2,5d5af713,f4fd4070,429c8d0) +,S(2c04b299,1775ae36,ed7d5b1b,d9b0e65e,fb2bff8,ab99dc97,2cd860fe,19b1789d,8b3f3b00,6d63c81a,86f225a,bd8e658d,c9c4c1d6,6787678b,6fa4a692,bc7f78e6) +,S(c7897c17,debd6456,a81f8d96,c0ea580b,db5daffb,5fc8e8e8,9c8612b3,7b229f7,f7334550,d20a1a21,c422f73e,d23fb159,2fb3d9b7,ca61d7b,6e124fa4,147ea63c) +,S(3b37b93e,ff554f0c,7e7f36b1,864ecb73,7b33a93f,6ff31d6,9ea18aab,a9487505,50ccac12,e071f469,3f5e5339,462a0cb8,66bde539,5842ff44,620f7acc,aff09a71) +,S(4584ea49,8a2785e0,b12c86d5,2b839212,f21b2e33,3b64bb0a,9713674e,66216547,2851de5a,b67354cd,6610dd4c,91aaf4ce,b75c4c97,26d524d7,69ae0ba7,997ad79c) +,S(c0c971d9,f5644eac,851ae8a1,d87b4f09,a802ae07,32d9b5a2,d9589051,f139963c,83e07a5a,2b7614c,c064b4f,815b8a76,6df7eeb6,449fdd50,5c43faaf,b0bd075f) +,S(370e8fd0,858c6fbc,f479deed,f35fef5e,80cd2338,90d4b227,1867ea90,6cd15b5f,ef382477,fd2dec6a,fce439ba,9b341a21,17d6ecf4,c8c8d63f,b5775094,6cedcaab) +,S(ad402a30,99c5d5dd,c7ad9631,b592d5a5,862e8d3b,5ed47dfa,c288193d,69366625,b8c0d468,5d0eadfb,9f7e4ce6,11c61f5,7098da29,aaed61f7,6a50961b,b45b7c5) +,S(ec16de3f,32ea8f58,c1dc93da,d1cabecb,5ca33ce2,e3fa3bfe,bf0ee989,f3ebf5f9,aeec3532,c5391ce6,1e23bea4,5b7b5847,2c36cb8a,6c5f1363,e457c003,b18824fd) +,S(5a51f9d5,f5c48520,dbd826b9,49f62f67,c299a228,259e09cb,b3bd6fe2,f4b0e60b,3c498d86,225a83a1,f506eb62,a2e530f9,511c56a2,eeed77a4,18ddec4f,4404b9f5) +,S(9696865f,64523eaa,456ea65c,40ca6e0b,12c6e6a0,211cf8dc,20963f03,7980b684,8f879d8b,491f11a4,1f0025f7,b35dc8e7,c71e420d,7d7d9001,bf5da111,9ad6c2c7) +,S(80c43c8f,6325cc30,8065d4c8,6e3d7bec,6ed85f74,412f6127,4fc3ae49,b1e185a5,31dfbe69,a48f1f39,a0cca355,f3d68f28,cbf3e14f,7d47cfc7,d9e82e25,19bdc292) +,S(54940550,ec4a6ca7,561946c0,65769b4d,d4683f1d,11dfda66,4aa2f8cb,8f1ab2d7,f41aef26,64466fa,ecc076ed,cd383d3f,132b4fe7,5a17f16c,c394b6ec,e4079378) +,S(a9787f8,42b3549a,9a3bea8e,4182555,99addeb6,416118bd,901afd9d,ad4c134,4efc4f67,65c7cf5,ccc2336a,e9eb14c5,a1361067,7632ce89,68033d57,4bc686b0) +,S(fa83e81d,63b85491,92e800e9,7a422ca8,35c03bb1,5579bc05,bdb4367,198a24da,779940b2,ad301a1e,205c0504,fe3ea104,cef6a459,e0479849,90fc94a6,871954eb) +,S(ae9a8d1c,a8a560e4,8a373666,544a7b9c,84bf0475,9de1a63e,4a20b55a,2f25c132,b9b0bd66,4c46edfb,ca2a0bb3,a94ff043,c00c1441,9f1df886,2aaadc02,e25017dc) +,S(a2f47145,296dd22b,3a6f5185,47ab0957,4d3487b6,8786f87,6758cbe3,5f4c0ae7,2ec4171c,15e7a82a,f6ace24a,60176f7b,6239561f,3c369a9e,efc80d52,3fd216e8) +,S(1bdcf82f,a7dd441d,91332a11,35f50be8,4d275358,f95df300,25187f2f,9828f219,99f12980,92a3ecf3,dbeb290a,67d72aae,6acd9cfc,c21918e8,9ff7ad4e,548d3510) +,S(b73c91e1,ae33767b,11bd329,361fdae6,36642d92,6c2792b6,e19b6e3f,947a5be7,b6502357,11ffe955,be5798d1,467eafdc,94df5911,29d2aaa9,b747a2ec,befa9d7) +,S(b23b4ad2,e983e556,e941a35b,b84846a4,40cd25b6,82487f37,a3a30eef,eef15d1,7010f10,88749d1c,f95e52dc,eae1a379,b87762fb,55593d32,a65ef0fe,dcba2485) +,S(e3aad2b8,96fe34ef,9d775743,6e70a70c,b3bb0c6b,8436e616,a23174ca,985fd8f7,5d6edc38,89beb099,dd191564,eaa83c14,3ef0b74d,7789590c,d6083704,61c6676f) +,S(2f22a14a,f69e6257,b909e3a9,50aab3ea,dc09c281,ec52e47,8c578f49,68910244,4ab723e2,43c71baf,d2aead8a,479a1a2e,fd2aba74,800b5eff,56ca46d0,532e81d7) +,S(93806026,554bae5e,9b91f534,f864b79c,81e581f7,bdf3b2ef,dd007e32,dd6872f0,800f8162,a6836801,d052871f,6892ba33,b2f60f82,89a658ea,a8af25fb,f9d9c444) +,S(8895d121,ad1f2be2,3c578faa,1e33656a,e9403ddb,a1f1aea6,1cc7bd03,817a46d9,4f7577d2,420d0d0d,7cc9ed68,ba3645b8,f9466f59,570ddf16,ba168de2,8cfec881) +,S(1838c15c,3bcf1189,546a9e3d,69fb8a73,de39c862,f5faa4bf,423e1dbd,29046ccf,49484789,1b67ea0e,2e7f7eba,4a596d66,b3ed9842,3ffc54b0,e9292a4e,bd6f5487) +,S(111e8eab,d9cb3ec,5eb63cd4,14ecf59e,3a3f0d56,70959226,ec8f203d,947204b0,4ab9b3bf,dc853571,2c0db9e1,5fc2832e,4560e420,af96b043,e587d1de,d996e38a) +,S(80369d1,ec5ab7c6,492db1f9,aa2fa368,ec083d86,75d6c1,e7262e73,a612e493,cbb28c30,db7f7d03,6b8dda93,7e0c4e18,6a09f1ee,2407e55,7f6dc54b,a8c0553) +,S(903c9034,dbd3f982,41351979,c9306a8,42b88892,48cace15,c3e3a8bd,aafe1ffe,d55adb43,d0142740,71499c92,e9b851d8,e6ece26f,f82ceaff,ba63a003,14960f38) +,S(d6490ce4,74bd1e80,82c99e87,a0510a2a,c2c2772b,1921cda7,dcdcd5e8,6ecaacc,85a1fcc6,de4b93b8,b2314da6,31d7abdc,f96b22e4,b44a5545,f274f941,454e98f4) +,S(12f2342f,aa8b19a8,bb0e080b,2ed3487a,14ddd1b4,83e0bfa4,9ea08484,157d5306,eee0b9e4,30a51a3a,49da893e,50360ba1,21660b4d,ebd3ad8f,82805416,10f4b7fd) +,S(3bf1ef66,57bdcbba,a9d9a23,36c75429,c4df4a86,1d71a767,2d7e956a,deff234f,fa98467e,83dd1ca2,2a85cd8f,f12be1f,53d5a939,352f4046,a626a208,601ef6b5) +,S(d0d0f8b7,9a04ac8e,b6e010fa,3608926f,3b5bd886,f84c361a,8e1d9dd4,b01ff717,9bb32b90,6d7de56,c75bd202,b9353128,b6440fb,42dae8e6,74ade0c8,fc96386d) +,S(19507738,80caa9c1,f042f8b5,d1594a12,161635b5,a83e4675,35ffe51a,fcf631fc,9280d033,f7a8efc3,ff22f501,6a6ddfd2,f78159bf,1f13be4c,f758b150,21126ba) +,S(f4f50c3c,eb750a04,95973b47,53b96ec7,22cef833,f4ee7459,a51f884a,f9a251cd,41f554fa,d3d521e9,65fb0768,66caeac7,d9f5c6eb,ba7ba7b1,d1d38c9d,c06d85ce) +,S(8b669c9e,22452528,57e20692,2726f045,e97b8cf2,1154fb74,e199f49d,11951b84,550c47fa,c46060df,4d893afa,9f08713f,cc8e719f,a369e90b,fa8846df,7938c65b) +,S(941cb4b0,31edf346,64dd5e7,92ca135a,1d6cc6f,55341322,66644493,aee5fe32,cfa91a79,29b3b47,d73b8ae6,77cf64eb,cacf9408,3cdc76f1,79e25631,d574ff68) +,S(557e36b1,27307c56,72232c6f,6e92e4f6,f5da9d22,1567b464,8e79d97b,bf589023,ab741e35,109a0313,e7adee7a,2cec2c10,79d18d72,6c27f1c6,5a808b98,8e99b523) +,S(d8081ed,9e7cf1cb,e1ff07c0,b8ef3f9c,c7eac02f,1cf1c6ff,833f4b74,b2a33269,efa297d7,10fb71c8,43e358f3,e04ac308,53027f00,eea43d03,9b87c3ca,2b0fdd2e) +,S(b5e4fdf0,7a443146,263f6539,f6c8d991,7486da78,95b4ba7,fb4c9f14,78324d44,a3ef979f,93ec1a0d,602950d2,ddc400c8,4f018643,229cfba8,7cd9e3,f2fe657b) +,S(1a573259,a5100c21,d75efcc4,41d5a834,a81d96b,f4149731,eed4ae67,508bffcc,8a993dcf,49f94f6b,bc71766,9d37ebfc,614a45f4,1d70a1ca,f4da8834,5711223d) +,S(33d9f9f6,c9ba653b,f9c52166,c29e9c06,2cb7700d,ea2f40cd,28520bf,237b4558,dc80f57c,fc0e73ab,bdfc4a8f,f7e8f4c0,3353e889,bd54cf84,6361c1a9,af5a0a79) +,S(e4ca84fe,307c9237,4d39b2bb,b017b5b9,e478b26b,95236b8d,5bdfb220,f44419d,c0cfc7d8,92271c95,7ef235f7,2f310c7c,7d0ac297,97d42ffc,ba37061c,83775507) +,S(8f1f2d2d,cccb07a2,a8716b77,8c74f3fe,22990d36,b951e6dd,92f5896f,51bc23aa,9eaa792b,426d3400,31a862ca,b805d0da,ed9a4c73,591c204f,c5179b17,22aef870) +,S(20f7f6da,86eb5ae6,6a1b7818,43fd7fe4,c458e3e7,bfb590c8,76afb601,257b2ee0,6dfcd6c3,93e7e9dd,32c7e826,42f90d69,ff1e1ffe,18988de2,bc1cb9ba,db246fbc) +,S(3a3df365,8d65d718,2dc05797,8bc48fe1,5c5eb6d8,6bb241e5,9e178ca3,9cf9a010,ffb89791,7435e8c5,4865bc79,52fb7bd4,1578af51,6f611c54,1f7cfd5,651b293) +,S(7aa435,7dbbc5b9,a01b5f94,6b0240a1,36daa942,1ae1a1c9,b50f66c1,c7f15e48,4640c8d1,ace8f69,6b08ba1f,9a46d04c,f75c5914,3339d5a,181a7dfd,bfc92c0f) +,S(198e4848,8176664d,40fc14c7,acca9eb9,aa22599b,b2370959,5856d78b,5e932e94,fb9dcfdf,b27d062e,8ea5246,275d80e5,6fc7cb09,e81bf066,dfca888a,8df1de6e) +,S(25da8876,d3215051,75694915,c25056e1,2c1329b7,7795b7ec,1d4b66f9,3c911cc9,b8cf4a83,db78787a,6d80a157,c7c205f1,3664a71d,a6e78db5,b52b012b,930c4583) +,S(893d2e9c,3b6fa8e2,136994e6,14121842,bb82e577,89826ccb,eef51fab,de32c0b,d7cb9b4a,1d49b34b,f3f743f2,10c32a25,cf8df45d,8552a7f2,1268e270,ee6fed67) +,S(dde2e8a2,988fd777,4959457a,5c14384f,c8248d1b,a32c7ce1,a727af27,7b217688,1fe0272,137e4c9b,1c6df618,41a240a7,be3b5de1,7b93fa24,ccc055f0,e7972b1) +,S(52a73b51,5326198c,81bd988a,3033e1db,abd9ee27,9a91a434,e7a76813,453e27c1,c23130f,c4b8990f,ee308443,1cbeff25,62963b1a,4a5acb4b,a1319b4e,d77c745b) +,S(1b5afdc6,4598bfee,4ef31904,f0d06796,17b0149d,ac19e7ef,a1d4f19b,c5385490,fcc0c62,47d96d4e,430ae0e9,c19dfa2a,3719e66c,ce25a2cf,d7428d4,4c91e96e) +,S(76da558b,d533e761,4d97b7bc,5a1a98d2,af043ce1,1f2b323,185377da,c0e0abf0,f8dfecd7,94b3d069,ec22f01d,8418bd90,27c3dfc0,62beb597,e352bb70,271d3cee) +,S(17f01b77,d2417d97,e3c14f10,18af67be,c12c31a3,58521f6d,203f101b,227cdbc0,fe16d66f,a194c800,e3c14bb3,f1df0a2e,3ec319a8,66c69d9b,3b492d96,327bba04) +,S(6010e0a1,2cacb745,6e3a8f73,d5219a87,cc14dae6,54be7265,ffbf70c8,c4d5433,7d5f0faa,579afe50,2541a2de,4d525bd4,e7b950fe,2b2dcdb8,d67d3d9a,7b11da54) +,S(91e938c8,3f319320,baa876fa,23773a7b,d0fb81f9,bf9d99bd,13180560,bfdfad6f,b662f401,7a4fa2ff,6603864d,77a6b930,181372f2,5fd6a67e,12a1df6b,f75509ee) +,S(de2ef2ee,633355c3,3d259357,efca96a0,5b669f13,b515e64a,c0bc467f,2abd665e,d3d6254c,5c30daf4,64843190,7c2a8c1a,51baeb23,13605a58,b88c9a78,a6147c73) +,S(186151f0,dc37e48b,3178bdaf,900e7bab,49cf251f,7a2a1b8a,76da8750,2dee93a6,2a240dc,acbbfc19,876c3680,fdbd7ee5,d1085b79,96317e4f,db73d5a1,9f097f8b) +,S(6f19619f,ace0c63c,4dda566a,9a1e78f,a9568db1,1c46f3e9,771756b2,7d8a5c1e,4716efed,7166e06,722a744a,af89d145,4ddd2f0,f7652862,cc38eb3a,2beb1925) +,S(a0e450d6,fb8a6da7,e8f6e62f,7a08c2c7,277a832b,4e5c6dd1,8cbed37c,37db23a2,775223c6,3f81b2be,1bdf0831,9ed65ab8,d3e11c56,38830851,d55a8893,730979d0) +,S(6337ffcc,64f5d358,d90fad1b,646d8d7,46e2fb7a,2a6cc378,9b55ec52,3824de5,98286287,578bfd97,4c161a01,55f9a2ef,707858e2,a32c3fc7,319416f8,5a6e5427) +,S(914a8565,cc1bcf80,19e1eef2,87c9467c,bc42faaf,726d4399,6485efe4,6f99e32f,846c42d3,b1dd8c20,3a744f5,560396e9,b9a92380,2fccffba,c6ee22c7,65bffde8) +,S(dd79a02e,2460ef86,cb4e9ba8,3ee7e231,e99b3303,1d4a6d7d,6dee8b1f,b0050daf,d6a75b67,ba13f76b,172ae0e7,d63b20be,db3e54f9,e54a96d2,aebc326a,131ea271) +,S(b2776e23,3e759f8e,38c52394,d50fe177,c6842acb,f238eb56,c7638549,174c1b2,e18c89b2,dbb6453f,7b610518,8bf090c,f0410e51,97885d52,b50b2507,ffe4dc81) +,S(e0716c4c,c5e84f7c,282adc42,f294a36b,56bb26a2,58cef4bc,c36a7f53,1d5283e1,1442ddf1,57491db5,1692c7ea,5c92976b,8a2488b6,6aa6f38f,7a62946b,a24fc5bf) +,S(2b10c9f1,bfdd659d,9d1e073b,faaa4b13,2a08b678,f757ef39,a137e53c,b291df70,7d22ac48,f4e0aa71,8cf7882a,57a46746,94e0f456,f2cc3aca,30a3f8d4,2b240dab) +,S(fa762181,26a4813e,e97f2718,c6eed96d,da9f6912,ac463af6,a52f3aff,f80f07e4,8c8a04b,f38e2599,4cfd8905,27ace017,e57e3f8d,d378b205,2e767954,80dd5701) +,S(6b893eef,bea81e30,7ece156a,e79abc26,d9f0ca5a,b2dbde11,bb0d8192,f138e58e,510a308b,9fc47167,f72bbc4,f92eebb9,88a6512a,b1679102,f9016b0b,d82c559d) +,S(6cd9b970,332f421d,1aba33e4,75f26a4c,5c5fec37,4a549ac6,d8c10fa6,cbc40032,b57dbee6,68bef693,67188a54,52e3b4d2,cf1c8c25,8e36bc09,432b4f4a,dcc24086) +,S(ba4847ad,40530fc5,f77ea79e,ef7a1c0b,821b5285,5ec4ab8e,d238ce46,48a09fa6,627ba437,8e0f2044,20e61431,5f3d110f,2da9cbe6,2025bbdc,5bc1cede,c36030c9) +,S(92837329,4f59a142,ba84f897,7acf2e7d,9df06a27,74ad88d8,98689900,3750c513,4e938012,b6e55d6b,6f7871ae,c34511c8,40912a1,1a32012f,3bdd27b7,90f86c37) +,S(470c19f7,9aeb9a7a,142ba010,10ea4929,3de57e25,68658d45,42b5a626,864600b9,2e99dcc4,b93d9a36,7544b842,ef4a3085,2e24bc41,e98ff2a2,d9aede05,da703225) +,S(2496996d,c38e4bbc,851f9bd,f9a21b42,5fc7ce2f,2b06993e,97604a0e,db555c34,b6e02a63,f0e2e54e,1cfb9d28,7607bae5,8a68ae6e,a8300ee1,c1170f0a,9e567323) +,S(92366ed3,23ded4df,f4029e42,685c51fb,a8a916d1,999c42c0,a90feb44,4112a78c,88dc8af5,f6d1d14c,5c09d216,8af0e752,3fad76a1,5b311021,7ead491c,12b63191) +,S(ff9760e1,ce161564,22c4962,4962d89c,37e66e64,cd7f8e94,4125fd00,c05974a8,8ca4457c,a5e52e23,d70639c,a9a26f3,12312451,8f0de070,86d385b6,777a63a8) +,S(50d1d5ad,79f919b3,d23c16b1,428d971,5deb186f,2b92b64e,7a1ea1fa,dfca4981,ddb07de,d4ad81b3,cfefe726,33521be1,c7418c5e,aa759440,20dfe92e,b4653ce4) +,S(4934f753,29844b23,80183df0,254d1c7d,342d7d27,9fa5e804,68dbee16,4e9c2c6e,a4f8aba6,7a488a33,40e8e943,14f7eed,5cc25487,5acbaedb,afecfc2d,5405609a) +,S(d7b99142,9cbdf755,5cadf030,7b2c4a91,c0d25710,a0553511,eac6afb4,c544ff81,17bf03a6,83b1a0f2,366b944c,aabe57d4,eac4d86f,bfabd006,66693983,e0241420) +,S(834b036c,145d6905,58199bc1,e7a7bfc2,4831417b,530b0b97,8cc1fc16,af00b966,4a45a9eb,299f24a0,1c520751,2cbee44c,bfb75d0d,14a7eb08,b1668b58,ae58c47d) +,S(d7a8c30b,fd7b8aaa,78dd23bb,86ef2624,5a363857,6ed69739,25ea9d9,194bfb3a,7b5f9ce6,380abb91,6e041388,13baaf24,229ece27,3541f4ca,2883ad77,9e501fa6) +,S(ea4c7ed2,7ced8b13,4a2ccb2d,3828d29f,f80c4825,e5607597,3faace04,d2fb7763,a8454c9c,be19ec44,8a3234ea,97b8fbb,b256a148,11ba0ede,becd8641,42684d14) +,S(a2cb70b,f80d9f6d,696ceaf8,fe8052bd,e59215a9,99d4b92c,ce806a19,71d555c,997bd94c,e5cb12ff,886c1cac,bd21c3c,e2f144f0,3af644a2,c2aaba2c,825f75b5) +,S(89a91f5,c7c8700,175ab017,8c4104f4,a927af06,f269645,36cb78d0,19f8b8f2,6a2f8ebf,e1258b4e,31bf9a5c,31c51a3f,1cb58aea,6e18582,3e87920c,3df8e7e9) +,S(27d7191a,71ecb0eb,71b43dfd,5840079c,bd368c0,5ce62fdf,2967dcca,78f5a6d6,11120002,d0d0fa9c,8db51506,4e1fcc2d,92d8fa9c,8b454294,bfd01c64,889d5e6) +,S(cefb996a,d36deffd,c3c7ddbb,11a5013b,70baa98c,1057adfb,185b4c9,62f3384a,c93cab46,7523b0d2,baef4425,c9ff048e,c586d4c8,69c69cff,3ab9d72e,e3d80f83) +,S(5a8ff765,84746f42,4e06b557,77986825,e91312c4,4f79003d,c1b381cd,4fe5ce8f,3946177c,3c741458,7bdb9506,85ad0c73,b422a8b2,5cc3ad3a,cd486e76,99a42f08) +,S(b179dac7,d2f400bc,bb039f32,91e813e6,f9a7331,80a1a5d0,db51aafb,af582fb6,89a70304,d70cbb61,ffb3a499,1815cb17,458404fe,e43f09bf,d630d480,5978b1dc) +,S(6e14a53f,ab32be84,4eb14242,a3b6a86e,e178cd7,51dbb7a2,b14cb763,ab2fe6de,a22ed4a6,d98c59d8,ca85e111,cce0efcc,60e20df9,6b06615d,69aa3cfb,206494b9) +,S(12ac42bf,d8f919d8,c79a8138,1aae69ef,b789a573,f58332b5,79694dfd,27e7ff20,4ebc3b7e,4b0136f5,19a8df5f,baa7ff59,17f4f632,f85ab1f2,ce502fee,bb3a3a87) +,S(87bf22af,5e9dc061,eabb01c4,eaa867c3,4656599e,da744da7,774fa8d9,aad68630,d34f530d,fbea0d52,9d2d64d1,323fa44a,d80cbe01,fa2806e5,ff069e6b,fc0ce729) +,S(33fe6bd7,ebe2b197,76251415,8bf866cf,b6d3ad5e,1f68519b,edb513fe,6076c96f,c5970cce,f44aa84e,f95a56eb,588b7a8e,d9164f5f,5a2eed83,1f70d308,2320e9e1) +,S(5fc2f44c,fc0f7ab9,9f03b67a,d7b6ee99,d73fa9cb,d74eb5ba,6d931d9e,26ba51af,8b1fbfe9,de201400,6c07da02,4bbcf53e,13bb9f2b,ff3dd6d9,5135a6fd,5842f0f0) +,S(38fb5cfb,e4f348cc,1fa7f9b2,ea600daa,e8330aca,53308f09,b6a7d8b8,5ca8a88b,ac1bf91b,7f53e824,d845c0f6,9534291f,cec2808f,95acf58e,4afba07c,fc735be9) +,S(3ec2457f,fc848504,6f74912b,5c58b270,1be6eeb6,f88da0b3,c5cc4454,48750875,b63209d2,641c65bb,7105af10,61d7513e,409f153e,5d1b5073,232eacc6,f76dde22) +,S(32fe812,e67ef62c,687d248f,e75ef399,48fe8ae4,a01ae10d,ed65264b,fb5050fb,d9c85369,db22ddeb,baf7682f,53642962,cfec2afd,3a20de77,588e7473,18044f6f) +,S(97d7c69b,2aa0277d,2b20e9c7,bb1066a2,be6f443f,d0a428b6,d78c5fc9,6ff71b57,f84ba781,70837aa1,f75936cb,fc50c444,c40c9fa3,22d90088,ac6889f7,e7c0f861) +,S(3621a4af,4d698e4b,60e7f497,6e0c10e9,ca32834f,ff917aa0,6aff912b,2ad80cd,22cfd248,a17886a,ae5d0e11,53621e9b,46289acc,ecd8155,a1bd6372,120c4da7) +,S(ae79a6e5,848b1dc6,cb64958e,87b737c1,858442b3,63d4a2,e9f04561,7d73f8c7,c147238c,59885f2d,dc5dec63,de421eb1,c5a19438,ed0600b3,4c77f4e0,e7aa557a) +,S(36eec623,700e51e7,723a632a,55370ddd,d6b1f917,6ea39a2e,54a2a1ac,52598c35,29698c0e,56b4e2b5,5389dd9c,3d8b509a,e0b87f99,4872d865,3fc74269,7f5bb7c) +,S(50f70061,804dbeab,cf2ab4a9,87ebde2,1f5496c9,a4cd28a,4dd9da7b,310e876f,77e27710,edf831db,6ba9e64c,545f03a7,eb390842,8d9cfa3,3d0e1c87,61371706) +,S(c2ad6b2d,e84bf60,7fe77b8f,a9fe26ff,bb5e1906,1494e469,8da44a33,25843844,17b92ad9,d3938fef,7a17f543,a169a7ad,8ee65dce,36eeedfb,5e3c0c8e,a1b24fc3) +,S(a53504f,e2286269,427fd2fc,fcb64827,bdefdfd9,feb89d50,12651d2d,c60ae99e,6b9d73e7,e046d11d,ce78b114,8aea837f,770d8267,6642dac8,f3b3c035,c10eab45) +,S(5410db61,40a77b31,9f19c969,34a8364a,4881ab60,ad76a6c9,34f317c1,1b658dec,ac45bb6e,2e5fe23d,57297370,cd04ffdd,dd89a9,15a1e9ad,15d7f9e7,6d8b3aeb) +,S(882cbd69,fbd3e262,5093385e,ab82fc9e,7597c38e,45fa5df7,f98c94a9,3bf25467,2083f00,b25b28b7,f92b040d,a4294dc0,8a3d97e3,d951e724,da0e692a,5737a87a) +,S(3141e0d1,22b4c136,f7793c73,9c48f308,c5ec8043,19db116d,64eb14f5,aee83942,9c2d06cc,d765c6c3,cee09b70,247f8806,227d0178,13becbb6,96c5a344,b68b33b1) +,S(1b2f3686,5a63df41,65caea4e,305d8d66,1de6ccc1,c2a28cf5,2373527e,27cecfc,1239d8c8,d60fdcb9,fcf3f5d4,63305037,6d47fd97,4cd6bc64,99e0e951,2d2209a9) +,S(725168cd,9fd59e41,14918b77,6ea96fc9,6315b4f0,86672dac,1eaf59a5,e61ed25f,946f03a9,84a6735d,e72acb38,dfd21905,fa2358a5,e66e7b0a,2f8836a1,8f5d73c3) +,S(4207faa5,c9dc9622,9644df1b,a099a84d,654ec6d2,aa69efcd,a4a31a3c,61f2e1d4,ea72a92,836d1597,5275c18a,900c0e7d,d0502610,d97b6f79,1f6a28c2,1b3ddfd7) +,S(53900d38,a4740830,a6129a11,9dc90f6d,30f32847,708d48d4,20b77764,ff5b9cc7,66822ed6,ed941eb2,20aefe94,4325daa7,a619dfed,5c76bf75,1fc25342,8178d3fa) +,S(d0204932,a3fb8d33,9779851c,d69f6adf,be1a9957,59fcfce1,b8d4f047,e4e4dd2,8ded18ff,bbfc663a,9c658ae9,286f82e0,9ee9381b,3291f5c9,efabf0d5,fae318f) +,S(3ed8ce15,2d34e621,94b8b16d,55605766,41fb2673,14a08c91,d916fa14,f21abde5,48490fe3,9769c60e,38996370,27b57df7,230060c,2505f414,5a1c7f1,4ba16660) +,S(b7d57614,9b5e2ce5,edef3c30,b8cce79e,6f122c70,351d04fc,ed2b67c7,f5cb2aed,7c8fc1c6,bd42b25d,d45e37c2,5cb06f0a,bd2f7051,4a50e6e1,2a67c0b5,b199eda1) +,S(2489e06c,c8f0bfed,9d5ea722,c07ca795,e9ab40e5,45b036e0,f0c11f28,53c0d35c,dff65f5c,20766078,9737f1fd,5af05ce8,3b8edf91,37002b19,f5e1599a,e76c48bd) +,S(9b2140e5,509817c4,465e6689,a3bdadcf,b79c1803,883d493d,4e4e99cd,55f30a29,86374501,705fabc6,62e8c869,a22d2813,f7106006,ee09b6bd,b582b690,50186688) +,S(48d6fff7,d5c37c30,11c9e63b,b3342f92,776060a6,dd179e3a,e2c6bb69,d2f88b3e,783353e,adb6daec,536d37dc,76ae3ff,8dce14d9,65d21d3b,7a17515d,7d3341aa) +,S(35d46a17,b6951355,a055e253,42b4244d,8ce65459,c630f2fd,4708687b,e6a49e7d,13bc21d5,7cc2954,62927cf8,bc31ef3b,5407021a,62c5253a,5950e8eb,b9c735d7) +,S(17ba438,24168f06,274b2f5a,d080fda2,3c0dc34b,f77e81c3,c4413cd2,f594575d,e8b34f9,1ef09f92,7b5d9e51,662216a1,30ef8f87,2e0febe,3f5cce8b,318fc77a) +,S(2a09e4bb,4f6d6b40,f59d0299,93eeea7c,755eb00a,5eba0477,3fc0c796,aee68a07,cbe72772,e5d8b761,15ed6f92,f20028b7,cd06aea6,74e10667,899e78a3,df403f0e) +,S(f3838250,e9a03da6,87139583,2bc6b35c,2d427b60,4cb7d25b,149b6816,235b0e4c,164b211a,60562190,d415bcc3,87d1a147,66e45f14,dfbeda44,833ce45f,b815598e) +,S(b307de85,c4c2e8,4e076d19,647bd205,8c1a3c96,a0261481,322e73f9,f4a2e94f,5af7f6f5,ae7f65cb,b62f021,608473e6,b68d032b,4835540a,f265049a,e506b2d8) +,S(ff92c7ba,5f89d3d4,5273688,907ab9bb,794e5622,f8f300fc,804934d3,b5820e00,3b2e2d1c,420fafaa,e53c9da4,957e22b2,bc76ccbd,99f323d,763fa1ef,f92ea71a) +,S(49630ee0,a8ddf91d,ea678a3e,1dcb623c,688b7c3b,9e39196c,b578d30e,196e63b0,4c1aa073,d1375475,11d81776,e2e59404,aa08db5f,95b80e56,c39613be,fc2bfcdb) +,S(d41ead31,f2fac884,e762ccac,85825cbc,6ab2f8df,a069b2f3,fce3c6f3,d5c95a33,f15e3e23,e19baea5,677390cb,acf97180,86876f96,50fac740,9b6e62f8,b6d40652) +,S(5e62e95d,27ba07d0,781ad685,75a7a11d,df9f2776,48cb5cb0,869ba586,6ff02869,291717d,1a1ff532,e92f0311,881fe2d1,6c8844a,6f5ad7f3,b1ced51,e5088302) +,S(dbdd4f57,1f6d01cc,8a1025ce,3b92ce3d,56d396d9,635e456a,fd856239,27b53bd5,b929d5dd,816bcdd7,78abd34b,c15f2fb9,deff3f9a,aa44de0b,9f7b46d8,b8d70373) +,S(63a8349e,1a891037,9a74a60,babb68a1,4c8cda6f,c2cbc0e2,1a5aca7a,fff7a19f,38858c42,9cfb1e49,5fc90633,ce07abf5,b7c4a4fa,22b955ef,e2c137df,143ec70b) +,S(1805ec70,2cbb1e4a,5da4841e,9e24afcf,b84a3e45,dd6c39a6,cdb6a661,d5c6b1af,193be01d,d3f28479,e352f164,de99d21d,1b3fe8c4,b0af8587,8f21c858,cdadc27) +,S(2d6ff24d,fcfeddca,ab3b19ec,b6a79793,7f5c5d3d,373b9df0,6ec68549,6d075423,b8bbca01,551b2b3e,f6ec3a37,ff020f3b,6b1f5456,69bd8b90,f8a55216,3fb48fb6) +,S(3aa21099,52cf0464,4bfe5de8,69cb2d4a,19d3c4c4,661d6782,967dad8d,cc353a24,68252574,69dd7940,fbdd26a2,483149f0,f71a4b12,fd25b063,73765c52,d45985af) +,S(d6422a71,443b0e37,cbc06f90,4ba1f62d,c2351b7f,e4e0b909,5fc227a1,7f8f551c,ca92a69d,2c9aa758,46c2518,f1ae03c0,d7138170,447b55d9,37108604,f71b9feb) +,S(51e297bc,46529246,a36f8460,f285d713,b1e9ed67,2027eb35,37806d5c,7e756177,5d56e447,63bde166,b456531d,94be0d,7057081b,edbbb89c,be8c4732,13eb0ad9) +,S(378a552f,c061e796,c9ddd101,63851ea0,663f09f1,3fdf852b,ddbafd7b,bf6c258a,6396c9f2,a26b62c6,f33b73fd,98824958,8cbc7c10,e679bd4e,ea0f4ab1,dbf38f72) +,S(bd85fb00,1db4f2fe,95c61f1e,825e65c3,80761832,37be8a86,a20f6fc0,7a586daa,52c21cd8,9bf874ab,7d7e0f4c,d0095d7,6e8c737b,e2ba9d1,a21fb795,d968f61f) +,S(fe68e6ec,3c8e681c,e7230a92,e8762f0,af3e206f,f3b0afe8,be61ab34,2ca076b3,f8683d06,af0c88f6,93a0a6b3,1200cd25,ea2c7e9d,2b8048f8,b983474b,b1dc20fc) +,S(83e55d38,bbe2daa9,f8147b1e,674be115,d919445f,70d2b3a6,cb917a4a,9ff284d1,92d6c7f6,dbbcdee5,8b11a244,34cbe7c,9f9fc0dd,c93f6fa8,b6354a06,5bf90ab7) +,S(fc9cbaca,ed0e1df5,e9d8120,6bb55f26,67e114e7,30347030,8b333554,d0735ad0,d41fc02f,2d4b3f74,f4e9ec00,7a879540,54d12fc9,3d53242c,a45bd38,c75deb9e) +,S(7adf7a3d,12268d0f,c2568d5b,ee296d61,fafcd739,f081e5a1,7b39fe7,40132b05,51aeb855,a84f377b,899392c8,a7daa18b,70ec2a94,7929c93c,67ed8217,41adaa21) +,S(e9631ea3,7da9e68f,eb61f9c5,6eb91bb0,2fdb4d58,d99874c5,2c4af40f,9716aa0c,51d5a6ea,1a5fffae,39c598f0,158272ec,bdb48c4d,faa93da3,89af20a7,d2a1b8d3) +,S(e892f70d,15639bdd,ab70739e,83ab9f04,963e1dff,e2bd81eb,e075173e,6bdd116,2e78cfa8,30b68c55,68f635f1,b260d823,55f38ed3,f5f43c33,b178be12,dc006b4b) +,S(6f3ef2e1,e8d4fd02,2533f4d7,410778c6,ccd9a7be,aaeb3c8d,d9f01699,89598def,c4388130,c278f8f2,7a9947ed,4948f8e4,febe81bb,88bf873d,2d565b4e,3481b86) +,S(cf24cd64,84b07e12,37640f0e,da7e776e,3d4db192,6da8e929,19b36383,15de412e,a353cd6f,a796c46c,49f34c72,64d36df8,6d53f556,a36f430f,7f3f6ac9,3527ca7f) +,S(a2e98e5,36d517d6,528d6353,8bc2be93,4eeae1c1,cd8dcec7,a60080d3,fed33749,205e752c,49a09b0c,8804cba0,62b28ec4,6d9e8f37,9cbcacd4,a7cc9049,47bfb296) +,S(e5ef194,498445cb,718f7c77,6aecd0f1,949a4a49,73e32ce9,a4915867,dc27139c,fc774f2e,1e51f03e,71e637a4,158a0013,5aef5a18,b15ef0b1,e5696338,82bb513b) +,S(311b36a7,1a1d13b8,29c78813,6a989c0e,1b7039d4,d75110b6,ba97f000,749a8d06,2f441c15,6b80f4d,51dce0d9,bceca566,2f3fdd9b,965a0d84,55f6d154,3a661f7f) +,S(324420fb,a5076214,9be852e5,ffb88d20,d1120e1d,2eb9c132,32bdb13f,403a5f6c,378f5d4,1dc1011d,1fd338d,b6073df8,903fb4c1,e17b2122,bdad5eaa,496965b) +,S(7cf4998f,5095c102,a0db72bf,9935ca91,eac814c5,4120eb0a,262f246e,ede142d4,73e6db13,d6db9486,fc870698,7be096f7,7440dd35,67064888,e61dfeea,e98c1fb3) +,S(d6fe26df,d501241b,f8c5e74f,e30714da,7d690be0,91cfbe14,68ed6bbe,23598f7a,102c4907,60fed9b7,239c0443,d01f2742,fed0a0f0,fd7ab9f6,9fb1c58d,c5752fe7) +,S(805ee58e,66ab8020,c9c32afd,4c7fe30e,960f4c3,ae51e94e,da9e5242,af09c6f,19154d86,59fb1837,3d0adf6,daedcfc8,3937af0b,ef9a7d15,f990f60a,c5457617) +,S(491717b1,f22f93ba,d0a3cce4,fac57160,8ad7a746,ba73d375,1713e605,8bcd8450,9c38b3e5,4c89d38a,2307546f,f46bbd68,d4e4ad08,cc45bcc1,575fd120,acdacaff) +,S(a8e23e38,27c54d4f,ae2589ba,cf3c4e1,93f97e59,b11506f2,2016fbe,a9fc2522,ffaa8b74,22b50822,dadd781f,d31b5a31,eb384c50,2fa0bc2,89252665,1c602f3e) +,S(9fee31c6,88b0f7f7,78a39786,a84567e8,34da7ffb,350cfdc8,95d65c4a,afdf69c4,2116e31c,2a0d25f6,48a3ab47,1c897484,d71dd9e5,c678af4a,292a6388,d9e45e94) +,S(6256ced3,f08f1812,ca7ad618,383f1542,baa2bb06,332d4c1f,72d862c2,318854e9,9ae0bbd9,d2fd51d2,9347aa62,12b6c0ca,be530b55,bfd8cf18,6732be1e,c66ced06) +,S(ca1cf364,a5e1f47e,cd0ab0e7,52e785fd,935b8c37,964c5654,2cfb3249,a136d669,17412d75,2f350795,30db27a1,7394c362,45fa376e,d20583fe,b9f7a7a1,2c3b67f3) +,S(19004a4b,28e5352c,7c74def,cf129ca1,cb5c7dc1,5099b37f,dfdb0d5d,1e694400,68ed1edb,9ac650b2,965a4034,2812a692,23b3cf6f,24ab0a05,2e1b8eba,f7335020) +,S(c605e97f,27199d86,18fca176,54e44c9c,8dd20994,aeae0466,dbdbbf0e,ffd1b3c0,606955ce,33ff7b6a,cc6de4bc,4ef80b34,bdf6ea17,b29dada,4ee54f06,f61e9d22) +,S(3e89970f,15e79b51,fba90202,a16da6ec,3d3d5d53,72218d72,bbed0626,31affdfe,5d9e27d0,bdefa8cb,b02ca682,a062ccb0,61a8fc47,b2cc72a3,9b687b45,5f83182e) +,S(c077c861,575ab0d2,944f8e65,8a9dbe54,9fc1172c,6b7b7428,476af472,e625d5cc,c01e7abf,6a3abe2,d2aa2457,76068afd,9ba78fb4,fa39e531,8155597a,90fededc) +,S(8567c87d,c12f1479,5f351d1c,807604c6,636c670e,11edb286,92552ab,382ddaa5,71f0be2a,12ebee63,8a63e848,fc4d8116,e2dcbf99,ecdb15ae,1f4ec6c,84f359ff) +,S(9f1b7785,7421626f,87978ee1,780d0,1e9d0b28,df34c2ad,15332b8a,d94d8dfd,6df504cf,66144d9d,ed530e2a,1436a4df,634a84c6,9de752d8,42e076c9,1f129b8e) +,S(f45c2c6a,2754fc31,c5770e3d,38b19e72,47b0dd1e,5ade8ed1,f2f3219,ea7accce,ee07ec18,8190ce54,e736ffd2,912075a1,128d24d9,b178a7ee,72aeb6e4,9b593f4f) +,S(51a5441a,f3446fb4,cc63ece6,c9650a87,2fa5567c,4918f5b4,ec8668c4,ddba6e0d,413186bb,adad4943,6abc46e9,280a1571,a97ed7f2,a839cad2,935675b9,d167a54a) +,S(adee3e1a,e9a2ab1b,da34fd5f,afd3b3e4,f51255f3,5dbd94c6,8efb994d,afdeeade,f330f0cb,973fd732,eda39ebb,82dcc589,4c148165,428adfa3,b4ff865,1ea83e24) +,S(a8946504,eb084214,d0153ac9,c3437fe7,3ff5696,16e01672,413a62ee,27c97db5,3dd63d46,f74a56c7,2cd5d45b,5bd6f2a8,d913300f,b4ce536a,e504d4b1,b2e311dd) +,S(e34ce586,990e48c5,febc2fd4,70770cf0,4c81c782,3702cb5f,289be0,f4a97205,d1774a35,cdd7cc54,dc68827e,f7c723d7,5c167982,c314dc62,bba17478,611f5854) +,S(7a8a5d9c,edbc4c76,1fdf2958,8289bea,d524edd4,f7cad978,deaeca8a,de47435,559d473f,3a9a7ee3,4ee0a1d0,4acdffc5,6766db36,94fbf08a,5ccef8cf,31e25b6) +,S(848cd57c,62c67249,d84710a1,5c7abc27,93fcba46,497a6b0e,b23c2ad,f8acaac8,a48424a9,59922131,31a763ed,30369b72,b331d9f0,cf46f8a2,a15515ed,6726f735) +,S(6afbce14,1f2d2c4a,c52e7e05,5ba6ea60,7612a590,d74a2a5c,1344cd5b,c49f2f03,910d69d1,cce10aca,bb1593be,2d4d4d28,9745f97a,29fb78a2,a1eb6f0c,a58e4b61) +,S(61f3727d,718644a9,2e08ab04,814c4446,c5dfae82,c26540cb,44fbd310,a5315a11,56665e3,ee6edadd,a154563b,11fdc203,fe4365d1,ac36879f,a30778c2,badab836) +,S(582962de,e00668e7,91741dda,8e86ddb7,b8ff7773,ac1ea51d,1aac139e,a810f3d1,6bd353b2,e004d66,f1e90cc0,7c68a0a5,b532e709,75a7bc58,7a6b1c67,71022f6c) +,S(5c4426f9,f6071fde,a9304e6a,4a2374a2,e2591225,28b62d20,5fc3016,c471b636,ff6e8c71,fccddb0b,5cff9e2a,10c606e7,c571245e,8f5bb5f7,77e0a7d9,733560a1) +,S(ee02633f,c6b41f01,c3c24c33,719db7fd,a9e04b1f,7070395f,e8898a0,efbf6af3,ecdab00c,83cb3465,1d48a696,6a8e4f03,ebecfba6,f73a66ec,4d62a668,48f14798) +,S(fab36b80,e5bba465,63c9078b,b727e0af,c9bb0af0,2e394f9f,2c90e0e,fe9fb816,75173a7f,f5599da0,ab84519,c7c25be4,1f10172f,fea39762,8e7dab7a,3ecbcfa0) +,S(68a89a2,62015a57,5f882215,48c6d3a7,b4ad1f92,f5665980,367107a9,f4cc37a,43ea7b7a,79397dea,c8354436,d53e7731,c94773d1,5b067063,b108c559,c05bc46f) +,S(fa6e2972,87a0e97c,35454378,4a76fb0b,56106727,136474d8,a3edf8b4,e03f95f4,1e80751f,9c127fff,ce28ae,8ce5afe2,eea1c566,fb0a9f20,8030cc96,e1197725) +,S(25474cb7,805d22f8,7a641116,34628321,f086d1a0,40404c47,ebee913c,e9e02a6,2b3aac5c,85ce9672,61757c61,d6a72dd,4ff81e00,87f0b8a4,999b927c,7b069609) +,S(6f7051ef,10fc1485,a9c80ae0,8683397d,c0af15b5,f78fec70,fe4c456f,f33b6689,625086ce,ab7a9173,d9c370c4,c336c63d,2aa85ac7,b8391993,7ffe4118,f6a7b849) +,S(f4720462,2f579de0,701f1e90,558c74b4,ab634664,197c03ed,a85b0fe4,50df4951,c66a490f,f9b588c9,2d17b80f,7f66e5fc,a65187b6,d965e81b,c16039f4,477fdb54) +,S(3b718764,7e722fa3,de42fca9,e3ba181e,de982728,5b8b006b,d51a58e5,ed898c8,bf872047,f3cd3ea,d7a439b,9d4f7776,7175f940,d6cae8fc,930aece7,e1b92202) +,S(5255ba09,df1e199,4c99bf21,709849a1,cd7c4f58,a283e344,6b98872d,a416c40f,a1099eee,e3ad10d9,6bce7a58,839fcaee,1b43e0fb,29ac0300,4e0eb15c,63d1f604) +,S(f4b64a08,16dfe224,595d3a15,8173df8a,7d941a4e,968ac02c,bf87d9d8,93954805,e5585209,2d0cf600,b8b2342a,8371894,f422e3b6,68ec4078,2379a60e,944228ee) +,S(236d83ad,b789d7df,5fde69cd,86d45d5c,f20c5867,b7f2b398,b9373960,b22b29ab,9758044,d3e06295,e33bebaa,befc5776,5db45475,b3aab963,5fea8dd6,77a478cc) +,S(42071659,65af2fda,c9e87319,6dd0c723,e7d61bf9,b71e5e70,667c9858,6371f3f2,fddfce02,588c1d4a,b744301c,6117e504,8f9c2636,5ccafafc,8a6e19a1,ea7b1b37) +,S(7d0c2917,aaa71cf2,e79f1041,5e5e583,ff01b24b,65f1f409,240f794b,d346a452,1e857dbc,c86c1032,e748d8e7,c8f5839d,57295223,22e6bdb6,187b00f1,f489576e) +,S(f0609605,d6e39141,e5e4f0e0,6bb6d55b,9ea2ced0,6a58d4e1,7c46a3df,18257255,e6d54c0b,10826de6,e95553ac,e4689fa4,cb03b959,65472e65,a085988b,d045374c) +,S(86e66299,819b0807,af30c89,228447f3,71fad56b,75f238b5,30bef3e0,b1123204,de635715,b1997f4e,c367bcf2,8f8def4,7a7a2069,3a555b5,396dbe4d,19b1e8ff) +,S(7710dc40,f72bb934,f5f9328a,1284efbf,fad3518a,70c2a0a4,55028bb3,a8b87e9f,d2ebdd39,7dd91ec3,7ffcd8d1,a9b412c1,78f6d228,5e099162,76f9e8f4,a6a28e02) +,S(3d377c80,25607e9a,fd512e8e,7c37a2f2,8d316701,dff7f318,eb24cc34,348d935f,20d2d95a,e8503a11,de19db36,5bb62213,6cd55735,966c25cb,2a56f07f,19cb2664) +,S(812a4ad0,d004003e,fb190ea9,336659d9,7b7d6df0,29f29f97,bc9c8d68,f284a696,6303a024,b2d95d18,f04fa94c,df3d0749,60ed45df,584e16ca,d60a0843,551f94e7) +,S(51cb80b1,9c0dc55a,888421e2,411baddf,6c0eb167,ed9bd04d,294623ed,1bb61dad,d14f756b,f905da5b,6466bc6b,26685501,1fc90892,93633c74,479afacb,c34559f5) +,S(837afe72,82af09de,108711a7,998dd45c,36654f3d,a3cb392d,c46bee0a,b43cfc8d,88b0ae50,5c30a2b5,72c0f69,8e7ecfea,87ea1253,ec133fe7,fb2aff9f,6adc2e15) +,S(ab967cb8,463da438,ad360a8b,3e066669,231fbd,cd590904,fe827ecd,dff3cca7,d82043ef,c614db53,8d06f6d9,9fae98e1,ee6f5065,31b05822,ed2141f3,25ebe544) +,S(5a0b6177,50d828ab,fbf4fbca,576ff8ff,5bd19330,bd357eaa,a5564e39,c718eb49,f6e8d743,e528429c,2cacc478,368d7226,823a45bf,358d9128,9da334b8,5a1b4426) +,S(351b4334,83fae045,ce964f04,f63af62a,6964e0b3,5c1444ca,68d09edc,9a43c9ea,f571f442,7b308ac4,83bfdb4e,87987455,a2a49f77,73220511,dfedc616,20bc18a) +,S(fe64fb54,727ce446,c00dc3cd,5de496e8,2d5a0e9,b13a9a7b,99a96a49,2d0d288d,452c4c9,aee35675,33ce8cbb,e444590e,f5756f14,33865ba0,efd00c4d,26db7d8d) +,S(9403ea3c,773544f4,4eae3cb8,91457ac,89b11f1b,66c3c397,aea8d816,ccab1d49,46ec1e05,d13b40a5,f21ce743,b2ac9756,8ba98b2,8fe1443b,3b0c9cc8,f8a49deb) +,S(e81a5512,2af7093b,b361ab58,534df80f,dac734d,7a863ad1,b080d691,c4396dde,fb33ea54,fbc0c05,f9854f1c,49cfabe,90e259ce,9aafae3,353e8f51,594d49f8) +,S(b7511df8,fccf50c8,192dc3cc,bd79985b,15eaa528,89c4d01a,e21767e3,96bec9ee,c937db57,ddcf0997,aec742e9,cd522c10,d4a52b27,b50104e7,b59c441e,3d0fad4a) +,S(5625f122,4406dbff,a818d98,1e88b5d4,80039f5b,415acc20,ae69ae7a,704dead4,aed9f73d,5265c976,760d094c,e9ced8dd,722122cd,e0b1b34,a8296fb1,dccacfe7) +,S(1b89696,dca54369,27bcf0a5,de32ff1e,e79f6ea5,6f6ffeaa,bce6190e,bc7e2c8a,52bdf0c7,52cc3e5b,1cb9b5df,adccaca7,929046b,bb67daf3,10ba793d,9369b358) +,S(4ef2516d,796d1c0d,9baa8491,7c2db149,e7b89f61,a8f8fb95,e14116bd,473d730d,9a0063bd,6e25255a,70479159,d3089a75,834e54a0,a28c5c61,ea3c33a8,7ab20969) +,S(b36c8db5,51fabcb0,c3fa59e5,9faefed0,1a53b4d,5470ce15,937c889a,a93faecc,1be63f1e,7f85bfe7,2e782cd8,22776567,e3b58794,5f37e2d6,b137da7d,42c8cc10) +,S(7db8ebbb,88c7c04b,fed18b7e,1830df41,490028a2,2918098a,9b34b8eb,c110457b,73fe3f91,f0f8a43c,490f4cbb,f8bab5b,9a6569b9,22a69e9,93ab910c,520fa9c2) +,S(47bb0b5c,c207ef1a,db28a389,7606661d,e5d4c740,3b2858f3,209b7dc0,cac3021f,150e2ce4,44f541ff,7883cf31,79befa4f,5df9c3e1,9da098f2,1d73c37d,1ca48b16) +,S(7803d64,d7622ab8,70a8b927,74e012c6,ab97fad8,4bedfc7b,ac4ce6a,74dad4e6,2662e4c6,1a60a1ff,5485bb34,c1d41d29,3a09a69f,7fe8a049,95245e2a,7770cbe0) +,S(61a64d4a,9a801549,4fa670f8,85988b67,7d317b9f,9b75e3eb,fc6d734e,fe3d3aa4,ff25af65,16e639b2,b6b0dd56,c0e12610,b1b00c3f,d8c59cf1,3fbb1b74,6282d91d) +,S(f2de8cdc,ce609b80,af8b34ca,1c1166c4,3ae0ab9b,e742b510,2ecdd5d,2e94307,d624709e,79346b3e,81b98871,84bf252,949c7f21,861fe6f6,666ef5e7,18ec5be8) +,S(8c740f9f,386f5a0a,228ea52,18a43461,142f744f,87511e9,67080dd0,f3c65d2a,a641bdc8,ae1d4051,a15b1083,27581bf0,22e92b26,a5bbd186,86fb4e59,79f7cd06) +,S(b15a4b19,17448b75,df927416,2795eb5f,60cdb4f0,e657afa9,989e5133,646ae240,e09f731a,226189fb,429c76cf,1ed9fe62,2c148475,92f26b50,c2c45344,ddc73370) +,S(44a65d90,26bbdbc9,89b0dbfb,aa645860,d7a15652,5286a9e8,c67b5a3c,e2dde08b,f2f23e44,bb6cd570,f58ec2b7,b90eb66c,30775109,81279b50,2fc90762,3f12b52b) +,S(60bc8123,92f1e7a2,4eafd5f8,ca0d8fe9,c5880133,209f17d8,6b95cdb2,c9df479a,4d39ae61,cf4368ef,279231ca,b72be100,cfee501a,da7c873c,3db18742,82076a98) +,S(ad5b9079,36391697,61edf9bb,6ed7ae2b,f7e852d4,bae22afd,655a5ed5,754f3618,bdb40449,723089b,ad8221c0,8a46824e,cefe4899,d5e073fd,8606524e,a81a35e3) +,S(c8166cf6,97edc986,6f824df3,82a515f,68ef5d13,dba7e0d,43e85727,c6e15911,86804e47,8118c092,3ab97ef1,ab9dac34,2bc48c7e,3fe24e6c,fbaa74a2,2390f4d6) +,S(3e0a96a,94dcdcb2,9f0df535,970146d9,7f0fd71d,7a4196ed,cd626903,aafbff06,5f6eda99,4651016b,86d28c9b,39efdb4a,b8ad08a8,5c87b230,eaf7ba70,6062a8ce) +,S(e72351db,dcab669a,f1df2767,f5e5f05,ca80608e,29ac5f09,b1ff76ad,43178a5a,552249f7,7a8b3462,c9a268f0,fee20713,5cc14ccb,15914be9,2cd16d99,b2520af1) +,S(a08e1278,71ec784c,4f80099b,5d83c5f0,91978e38,7b0b37e1,f4622c15,80fea335,48e6aef5,349f25d7,40ffc9c2,5de543c8,7e0553f0,54990aef,fec51f0a,9b3585a) +,S(ffb6f3d7,92596141,f7d15157,d1a42bb9,e9b51e21,61a8e297,5aa05688,ba67617d,aea9ba56,8aa7cd30,b9940c75,29cc1e7a,dd60a5b6,8911498b,9fff470,bc4453df) +,S(9c644072,318933ab,4d1459b1,d684c066,d3df3371,d7659a82,fd396bdc,a9fc9e,a115ce28,5a7d9bed,a2a962db,5041cace,9d3b2a3a,12149b05,ddbae7de,30cf52c3) +,S(5cd3475d,8a6fee1f,a6e3800e,911de939,a7568762,4f0a6e69,26ea6160,4ddec04,20063702,1d1d525a,f250876c,c4b49590,9ca8b39d,74603979,8c8b4b39,fa07c17f) +,S(28519616,c035ec81,4e851ef5,191e0545,5f0bbb57,12fcacf3,2b36de77,1c351f88,42ed56f5,5c51953a,6a367398,815963e2,64363681,f9a0723e,7b622784,5cc939c1) +,S(a4e11f70,b3554f05,d0634209,86549001,53d2ed50,1f09f787,99b83308,4dc894b,331b9d59,4260e0fe,381176a7,1873a66d,a7a3b9f6,2a930e0f,696f68c8,6939755d) +,S(c5d7c22d,7a8cc553,7ed85a85,46adde7e,ebddff6a,f7e8a6c9,96f50df4,248a4ddc,dd4749ec,bc029503,1106812a,cee59bb7,acf41451,45883a71,3256912f,be9ee03b) +,S(b56ad6a5,c6fab0,934257f2,9e266052,cdba0bc7,8c8aded9,f0e08490,71770c7e,6aaa84a8,99a4f8f6,3ca8dee1,6df7c090,264e644,de1e58e0,49f99fb5,fd5f4c34) +,S(16c4dbde,37e8df54,aff88810,678f4707,310f29b6,e9e5fba0,384220b8,4f0dec11,4fbdd92d,56a3f76,56b4dcfd,8be6b589,eb02c645,8a247c9d,264fb65e,c84a3a3b) +,S(15e63d71,f02f6bd8,1899f95b,d3051871,84b68d93,6a2ac10a,d29c39c8,d5ba9748,20204657,ae0e1078,6df04a71,938055c,ae208105,ef1beeff,663d8cc1,df478ed8) +,S(3c07006b,8a1e1fe6,fcbc3a6f,fbb7a780,a0008ed,513c9967,853a8cd2,5827dcc9,b2fe428,d4c8d974,72066ca5,ddf32e99,18b5e79a,e81fd6c5,e00b8142,566ce904) +,S(c7f2ddf3,b3dcfa04,91846f0f,2341b1c7,81ce2cd6,ec20acf9,a304fa5a,7dbe73ab,595d0b02,faae2b6c,f6e84bfe,1183ab9e,dcfd6c9f,411d7125,dafbf9d6,60ec5d01) +,S(4c239c01,c05d9c11,3d25dad3,3d14ab28,f94742d6,8c9c748f,1773b739,445bb643,dab0d447,de6a8c79,6809563b,e77c89e7,956f6c9b,ed930d18,f25696a2,e436ebf4) +,S(9e1a100a,c44c33ca,543ae407,f98fef31,28bd1755,6a16e5a7,c1390792,187fac5,540a4e2e,9864a32e,3eedd96a,bb08fe11,b499a551,497e0c83,cdba140,3b303821) +,S(c3b4d7e1,bf3485e4,d028e424,81608ab3,9fe37649,de75733d,78f725f3,63255d18,8f8b00c0,2210cd63,c04f07a1,e10b1a50,f05ad863,b8cbbbff,9b73c84e,c59b5ab6) +,S(dc226233,8dadc96e,5feebb65,b290ceca,f8f5bcf3,e1794f9f,6ade4eaa,b89f3372,25bebe7,cae8b7e8,d755862f,dbb929cb,872e1c88,6b7d03cd,b32303a3,b8b5ab9d) +,S(184b11c0,a52865a4,5f530101,24cb353,dfbc2d26,bdb3af35,d5f029e,6bfe53c9,237a79d,b53bcada,f0a96804,d8072832,4f59f03e,1dc7a76d,ac5fcd01,3838b110) +,S(4ab97ea3,943e8157,3cfaa8ca,680252f6,577ff2a,a93178e1,e1a3dcee,242b460c,b8a6293d,f316c9f1,5fb8850a,87bce47,27d2a38a,d1f5f63a,39d08c92,e9d6d242) +,S(a531936,799791f3,cfc8bc58,4a2967ea,66328c66,98ebad8b,5e5fe8ad,8cd025b,c24d6ae0,8fac8028,a3e0e079,426b94ee,2ca7c845,8efffe1,58f6cb2b,c9046c3) +,S(37cc3686,a6e75e4c,8d7375a9,f291ccaa,937c833,f9e16d77,2591e74c,787b1f7f,557c1bb0,a7c7ed52,93e44cd3,75b04a47,7788181b,b20dc1f1,f6704c10,5a8e399c) +,S(94fab00a,9418e31a,9a229706,112f9386,d537bff,f5f0c4f1,b241c475,4d7336ed,14bced66,1c6eb134,7684cf29,6a303e0f,fa5abc38,ad569011,c09cbfb7,8316540d) +,S(14b851dc,c6b4382f,ca64791c,74a3faf5,adbefe65,b36de8f3,74e12e6f,e3c20e1a,6353d0b,ceff99b8,53557d0f,a893df50,598e0335,249f96c9,4e7a46a,3c02ce1f) +,S(d08e3027,5e05da0c,22991340,8317ec6c,e4362dfc,45b946aa,41e6b541,92c7589a,9553748,22228787,2ae61975,d0969373,8cb346dc,15d07e23,68800ab4,deb5d463) +,S(365ab0ab,6d51bff8,d4bb479e,a666e110,9a838863,2a5f8cbc,b3241bcd,5ba88ed8,bca2f90,ef0d4145,90cf9add,2a9d6793,d678f981,1ad851b,b2f54b6e,6bd093d3) +,S(879e8da9,e1363822,b113e70a,b8072081,f0e34a99,49d698ed,a0f55b4,6704089c,d5091dc9,d33861e3,daec5550,1f52378b,65b25a74,27a04483,c862e0a2,dc1038da) +,S(17006515,8ceda656,b23941e6,33ab3ab,ebb527f9,52ea9876,a8341600,24dc10e7,39a7ce82,b0afdbb6,33e74517,5fef5165,cd44c8c9,d81be0c4,56ee0251,6410b0f2) +,S(574a4f4f,67e294f8,2055793d,e94bf7f8,aa7106a7,f7ef0f2c,3bcbf2a7,352f017e,eac4aaa8,f4b4cf2d,ed8c328a,99b24623,16ee6e08,8805f1ce,783c4cc9,eff7baf3) +,S(4ab81205,32603ea2,9f88ba75,f2f0c4ae,330bb5e8,7f371806,de04f87e,69d5e6b2,1f1967ff,cd42f9fd,1f892f43,f8ea945c,c0135544,acb8010b,8285403d,5e621456) +,S(9a4e968,82b11f0b,5e431867,80dd208a,ba25b3fd,1350ed84,f34f2b43,f03c4378,15653ab8,375c04c3,d7488006,1acf13d9,c5d669f7,bbf70490,44dba189,372f611b) +,S(267b8cc8,3ed6ef12,47a93f07,b4f1195,2fb1de83,6c3e3fa6,782b5e82,80cbd8b8,19bc5752,1a41c7a2,a9dc29b5,cafc66d,7e2016a3,334b4be0,e2811ee2,4ab8599c) +,S(69a8b170,876bb1aa,2faca2d0,a4ed8c02,44d2cfee,a849293f,5ffb4243,256a1017,f77d7a37,5315381d,97ce835c,296593b2,80c395db,a5311a6c,c7fc2c98,d314b4fe) +,S(88aad570,3a4365c2,96946510,5a3a7fdb,6e1f3e66,618c3fbb,ee4c4e13,f333b1ca,10ded35e,c15df656,fabfc4df,a1140b09,196d10af,e1e99b3d,7e1113ef,f7fb8670) +,S(50709e9b,8620f7f7,7b8b6c69,1360062b,cfbea4ef,6448917b,471c3485,55691440,3946b364,3cb1bd81,818b828c,77c771d3,833a1d4d,dc509705,2e5db99d,6cde2137) +,S(1ac1d530,7cf465b9,8f1140ea,bbe7a939,df8155a1,bd656168,55ae128e,bd3959e1,eb02a759,82bfa30,1f9fe87c,75b9dd8b,fe2d64d,7ea89836,1aafe22d,448b418a) +,S(126a8f88,e7f59ac7,3226f2c8,8851773e,873f1ea7,a87342fe,da5d9795,3a1dc956,1ce623ab,abb29b2b,b9fcbde6,a6a6f12b,ec68bfd7,aa98733d,f2452860,bf9349f5) +,S(592fe608,92c09243,20fb32dc,39e7a42b,1f5125ad,1e7d6790,9978ac10,5471427,c4d6ed82,4d33f52c,d975d34f,b9df5698,968a0c57,9b44bd19,8a67fee,9935d310) +,S(babab912,e526a92e,d903a942,ae8ad2a8,930ea5c6,17cbf913,7c074060,6462f0bf,76c7ced2,4318c1b6,c7295d9b,52bbd4b6,707a4170,d020e7dc,1c7b5e92,aee7a4c8) +,S(6554e9c9,bdb1757b,408164ad,1cafdaff,4642a3bb,cf64e785,42c324c7,5be1a903,439d023e,f6c63252,311cf494,4c46a8cc,a3d684a1,d66556e5,dc488d40,e5ddd500) +,S(79ad3f8f,4c429721,281a9b17,d9c05463,f26bdfd9,c856451a,1050b3f7,805304f2,3be5cb37,da868333,4f9a4def,aa8711a0,adb6721f,d4b2bd38,5ad7298e,940dbb87) +,S(fe559c8b,e982e801,7427d308,e50e4d94,d7094aa0,635e553c,c591181b,c9593015,9186fd9,c9fbecaf,f4747597,22b34b72,49fb72f9,f02a67a7,627c1562,ae80485f) +,S(d2b4bcca,38d1b073,5248b4a,7f43f277,8e03f46c,8d7f3a33,ad2dd9f1,70ce0af0,fe0bfaed,846a3f80,10fca999,d0c3b0d0,b54e2fd8,7a0bf751,ba40f560,9eb952e6) +,S(f6b9ecb9,631c784c,8b33a7f6,3fd0903d,baec116b,3dfd2414,4865b297,5c290faa,95fa4ed7,e67b828b,4c685850,4b003928,8ad9e27c,da175b4c,81730fc4,5b063355) +,S(3e70eafc,653ef528,aa12ce46,59c90ee4,32979f0e,9df260fa,b9063f3,d30de2ee,e240ec33,b224a5db,3761796d,2c1285d8,9cff64b0,7c36a184,996cdca4,839a0a65) +,S(dcc76f61,46d05c0d,67bdb161,dc395c83,663ebd48,6bbc6e62,f3576335,a8ee0c59,e451ed85,a9ae624d,4617f11d,67552eef,7279811,6767a29,59708e,3c21208d) +,S(3bb03660,430c43f7,e3b68acf,fe692b,5ed6703c,c808d7a7,503b3536,381180fe,c84c669b,2822cee3,627d4ff7,7c01c9c2,57c57e80,f35e4fdd,eab84a6f,b96fa1ba) +,S(5e266477,dd106005,6a59fc2f,df36b540,e051bd56,c9120b9a,41471c46,b1c5c60f,d6a7ff4a,ee4abbe,cee617,1ad01373,d7916899,5370031f,66f62229,1057e6d9) +,S(c1c13157,56ce83c7,93ca3a0e,12dfc0f7,270a0bf5,38177522,8850863d,37e5e537,750dae34,9090f275,5487778,5a126ea0,f3c2c0b,e3cb9241,326a863d,3179af7e) +,S(c03ae6f7,96692287,4cd10b76,d06ac08b,578511cd,c502762a,cf14eac6,4f1a913a,b3ba2ed0,6cd40752,dc97e450,10699cba,90f38f65,cc4623b5,44d7a57f,250640e1) +,S(5938d249,4edde81e,6fd50332,d81342eb,6cd0d938,f1f02ae,562d1305,cc665bf7,b585c184,1e17e6fa,9924361f,8d06b172,89782433,1d65b3c1,7f2a109c,8be27b13) +,S(e3457146,bf3f5667,e0621ccb,500854b7,a08836b1,e4315d4e,6479b3af,e5c2bcac,3de9142a,5c495249,14d3619,a92dc5e9,f20e4603,5cbe2c8a,95a8e683,bb287fc3) +,S(4187afe,4918d05b,74a969cb,14f54b70,95387e68,c043a581,7dcd1d80,4ca917a3,4e1c19eb,b38f0a15,36afd31d,bda30d09,3c776545,f2d8d823,bc3eae61,35585569) +,S(60cabe6e,ffbc3735,dcc19c15,1abfdf4b,cf082768,e62a1176,f056c4be,ff04640c,7b0fbd84,ee9d787,2896b9c7,19448412,c68a1ef4,e5c6cff2,51ea823f,76d6c4df) +,S(fc6883a1,231355da,115af629,4f06eef7,83447185,edc19e62,b53f3156,e0f540a9,73805d95,d8b2e4f9,d0fb36c7,9f09780f,c315c1b,724c5de6,98d96861,c521a6c3) +,S(90f37677,e738ee2b,3abc9d42,54085349,9cd02836,474624c3,9513950b,c325b66b,90884e24,a4171613,da7fc192,f1bc913b,31bda925,38fc0501,6a55af21,e08bb960) +,S(55e68c72,f76925a8,52d38e8,172e6340,3966f148,2a212131,cfca2497,ca40db3,ebd22c3a,1388485a,e4b48b4a,8b69b98b,755084f7,9f9018e,36769d5,d78cb7e7) +,S(c74f257e,e1bd81f4,fcf512a1,f866b9a2,19586a3c,62e7abc1,112b5946,d5b90e8e,aebcdd14,5555164a,bfa127ab,9f352034,f31a19a1,d36cda02,f51a88ed,9662f44a) +,S(bc63fc6e,d1963da3,7fa064be,f7a371a1,fb471ded,5bf084d,946a6eac,fdbb8d36,a26a6ee7,e178a31c,4ca535e8,e3d1dfc4,dadee69e,140a37cc,a306546c,26a75a2c) +,S(9d11ff44,5e331ca6,fa99f29a,78f5e769,44fbebc3,e3b45a6c,d46ad17,74a1f29d,2f007088,110e9ec,66e5f134,b6d61ae8,70b14741,e9b6259b,ff06753b,fcbfbccb) +,S(5aa47205,f01abec,79b52b1a,2625b773,659166f8,1e300d9f,46bbcdd8,532599e2,f56747f5,c7431031,5b630fe9,b162fa49,26757780,c6ba59e3,6e91c29e,c82fd357) +,S(14dafde6,c8818744,2059563d,1e2cc095,f4bf18e0,f7e41b9e,97a74089,f678ce60,6f6a348a,a4f72e60,9a44b01c,b688ea96,cdc7c3f5,e559ed8e,d9a1c7bf,cf1747b9) +,S(ad8cb71f,1a3739c,afc8a4e1,ea77bd9,f5703d4a,55812381,c5a04847,e85e9950,238d1945,cd5d6094,dee8c6f9,41a19b48,d1eb88,5c986dc4,b8f3908a,508d46d1) +,S(e88df4e2,8b7cb050,aa81792e,ad108c4a,d95e735,6443dc11,f77d70b0,5968de2d,9541f907,f29d79ef,83c25f29,fdfbf819,49f21604,adb5a5df,e939afe7,511cdcd9) +,S(d6b6549e,1ef4fecc,ab56860f,c7a8a549,a354d9d5,63b9d459,9bbfcd71,7631c879,df7a0e04,18a86774,ba87bbe6,132028e2,927985e3,b1319c83,4e1a400c,7b0ae231) +,S(d919b999,faaa7cba,99c79a2c,febbdc68,6d94e07b,3edf8350,6e9a729b,f0f834d0,4b19faba,9b6041f3,9d33a21d,285fbf7d,638f3a07,63e2b15f,df102131,49b94ed4) +,S(b89d011c,57cfd499,fffd2d1,8734f604,83df00a5,6efd43a8,35d5983d,573d902,977f7c06,ed8cb0d4,980c3160,b152a7c9,294d489,2c90fb88,1da40f39,adfe2825) +,S(264873d1,cf9f6f35,d6bbff5,a2405f40,a5568a80,2fa35069,ce422c61,d9f2146f,36b8e9c6,e73044dd,b9b9753e,c682db1b,550d8310,7e3ea3ce,e8ecf031,500b3c31) +,S(d4c388e0,950d24ad,6cc1dfef,a3735bf,bd9e729d,99fafc8f,e4fb5266,8816dde1,3d583de6,27789a58,fd4afbe1,af3f931f,5d12df61,7f5adfaf,95830cb5,4b13743f) +,S(80a2e2fa,40aed900,a7a55f84,d4965f0,2c5632b6,1317e801,b83ec659,cc06e35,9e61e863,69c8a367,72d6a4b4,c2b7bd89,405fad38,4f99514b,485974d3,2342f47) +,S(e36eb1d7,72d5d498,3cdbeed9,b64fa04,1da7f1bd,e324f1b,a734323e,9f5331ea,6c879df5,4a96d33e,6a66895b,f4d12fef,46d5fe48,8d62f073,238fdbbf,d94126d) +,S(7852402c,a08ff966,44a4c1a9,3f7186c1,43f0e1fa,203b5991,d3fda009,1e0a4e76,a9b15d95,3ce9b219,a53da27e,e1b03aee,5431e26c,f035fa1a,a067f1d2,d36d5402) +,S(5d33032f,f7bf3996,14a08ee3,a5b67ff4,850f37b5,eed88e4a,675b020b,90cc4ac,ff5c96f0,5ba73287,f3279907,ebd0fb7,9e0b4866,c32f6fbc,2541d8c5,cbe12112) +,S(138d3701,98eb6569,17b3fc46,c2a3a1c2,3f7c95d9,d355d51e,c85b6062,4675030d,94314f22,6581dec4,3518cd7,61150f31,51ccd59f,3ecf79af,482c4dde,8a24e28e) +,S(3f6ddeb3,4756ed69,de83946,b48281b,c2b60882,d0cd721c,5d76c5d9,ff898c2,be8b8841,12fbfe09,9af67a96,8f4bdcdb,db4469d2,34d64d96,99c6a575,518c48d2) +,S(74676fc7,cf3bce8f,c0c4a774,89b320c4,736b9ed6,171d0b42,17a1433,eeee384e,fce3cf3f,630452a8,1cf3fb72,63c1b5,b66df4fb,864d4b39,7e66c69f,2913c54b) +,S(e0d1a049,cd49ee87,d71ebd9a,95eef0a0,b1d7450f,617841b,590eab0f,3e883eca,99e00118,42e6a78a,d4c3ec3f,f7a61bea,a1a5f8ec,2f4e9066,978e96d0,cbaef51c) +,S(531b455c,c6051fc5,f0f3190e,9523aa5d,2d0485d4,3901600a,aaf207dc,7d2b1fdd,b95f8c0a,b0e63acc,542df948,4b112b2e,e49f53fa,7f3e1dd0,307d9161,7c0f313d) +,S(b86ba09a,2b05e91c,c23db107,9b34807a,778749c0,ed725437,69ff6c17,316e7db7,a91c815f,f8a3b2b7,e5d44357,20e3a513,32cf405f,7501ca3f,b1aa1f59,a01c10ab) +,S(b63b43c5,af63f2ac,3f6e004b,c790404f,a146ea97,94b1bcfb,c4d0544f,2ca3f33,31654108,481b7dac,cbd48e8,c20de95,11406381,ef38fe6f,950b4321,4b145093) +,S(63a09087,e237e0c9,686f2a79,af977ba7,26d77118,29c8ed91,4f99dc43,90c64d08,7771ce4,a5e7d43f,e12b5e8b,c819506d,3b85f52c,fdb0f9c2,92c22bad,790d3b93) +,S(77640a42,4ebd84f7,71734050,7ba400cb,9e8462a6,a91fd0a0,b8f152a5,f5f7868b,516688cc,f422e660,15afa46,b5889331,3cf2d622,d6c829b5,f1d11386,bce41640) +,S(963ae02d,62739bbf,e75965f3,d1b7786d,c3dc6fc,5667aebb,5544db3,157f8a17,b3a109d1,b56570cf,2a5e5056,fd9feb05,2e8f53c4,f2ced1a5,27c3311d,87ba9dfb) +,S(81324144,454cb304,36f365d1,c78ea5f8,9a73706,acc49d5f,125fa282,c28ebad5,77a71aa5,54c0da45,31ed307c,c7fdad32,ab82a4b7,2f2a5154,cc405a2a,fddd3cc3) +,S(eadb105,e80bf2d7,cba9b468,6f6b88ad,34008c85,a7ac4d53,d3fff09d,dcd566b4,199ebce5,872f9dd7,6c14821,622fd343,2b7b6437,3484fe84,714b137e,fa782bee) +,S(a030450b,52b387b3,35cfe8ec,683fe625,884ad73e,2fc1c728,c8d9629e,dd2024ed,895545be,a9009f2c,dcb20441,33f2fad7,ac704ab4,9435fffe,b92836f5,57a114fd) +,S(57e8022d,816255a5,f4d577dd,867d65bc,7d7fdfe9,ed8f993e,d9b30531,fa36888b,9b0b7929,3cef66be,c21b6fca,140e6fe7,9b9f2e8d,48555338,868b6c78,d300233b) +,S(74c14e1a,d52761b1,7206b61f,fdff526,f7008f94,b3707a5d,e5c2a600,97b0dd29,18778822,89711679,c5e41fb0,41b1a806,9b12b709,b526ca1c,44839d5e,3b51e72f) +,S(5a9ce7b6,6368077a,73c09869,38656705,c017faa9,2d9cd40c,69d8e57e,63f8e229,f716b144,cebe2907,928f4618,821af2fc,9de249c9,5ac61bd5,99a550d5,e97363d0) +,S(f0fe4fd9,99c66687,3ab4c904,b9b7c0d2,7f033a0c,7e6c1b6b,4488097b,cdb49fdd,1f4643f0,6f700657,90aa51b5,911b4866,c286128e,de489dc2,8e2d6b64,972738e9) +,S(e86c729d,19347238,a9e97433,355530c8,7b701aa7,d710d26e,6b15ebe7,4796857c,d6260d35,466dbe3f,58d2aab2,1c8d76df,18271247,9715bacb,2a76bb95,5b75730d) +,S(b4e3a39c,8fcb0dc,5a23610b,bbb564a6,765c0135,1a8b666e,d680291f,c97df351,3f1eef0a,7a235130,b5236a2f,f8c9d2a5,fe5f1cbe,22326ba0,54557513,82ec651d) +,S(a9c8482d,a54adc98,4db2d7ac,8fac659b,51c1237,eaf1d524,9bcfcf1c,4ae601b5,446ec925,fc148900,8ef10348,ee167a63,a10686f0,7a01772c,10f7592a,2a544a9) +,S(17adc7b2,c36b1ff9,ea40b398,53246d71,bb973bd8,b469f7dd,fce49aa5,e77b8c06,fc3111a3,8dfc5219,7f41ea77,1682bd8,618f9825,bb2f842f,c7de15bb,224bf573) +,S(328e9a6c,e7397c45,617aefee,130cb6a1,dd26e727,efcfc30c,3d8f415c,187d23b5,6320e80f,e4a57574,1fed0624,c0f956f1,d5b30914,b5da88d5,f63e17e5,64f8b927) +,S(22188680,f765065c,360c52d2,851f3081,b2d3eb5,4201dad0,60b536bb,a45a1a41,b1107c8d,430df246,3b3e91fd,904883b5,cb877b,c10b6f,397a0cf1,c4b6eb35) +,S(620f5772,5919db4d,53b8f89c,5669fc6a,5a3f3846,c31faee1,1e93e53f,b1d20bc7,7d739bc7,4becbd29,2784be81,294185fe,db047d4c,c16c764b,678f9d00,6d27feb7) +,S(49b1228b,b624c71b,2c23e334,b098e84e,d3d8fca0,56303057,49dd39bf,5296666c,3f316e5e,ca9c1aa1,fd5d23a2,613e756f,8ac5e819,8ac16650,a9dff05a,1c8d76d7) +,S(97ca98cb,fedaeddd,b13b86cc,4b6bd7d2,140fde57,dae7b847,c51b118e,e3d6b8c5,1b95c9f,1d6c808f,397c3ec2,a2a2b220,6fdf546e,8c70ac2a,78086ad5,ebe28142) +,S(a679e7e7,3df904aa,e80270b4,d5d57dfe,f5ae819,f240369,b773fa3c,609a1ed0,93201a4b,17286928,be5fdfef,473565be,879cad73,24124c6d,6e1614b5,4e6e5124) +,S(fe17af2f,70887958,1b9b176,4d45d76a,afac0afc,ff50ac8d,9179e53a,c5e3777f,f59728d8,67c3ab63,6d387352,a029b5d2,e9f2d531,7a508894,9a0f6515,f5c4d61f) +,S(f7601ed6,fd64cf22,57cc15e8,e554dc8a,e19e4f4d,ad3fb3ea,a7e819f1,98b3946b,a3292ed3,ff088c22,e9a62b85,4ec87dbf,394cd681,501184c0,b841656b,def0fa3) +,S(3dec302f,cad72c11,54c6b588,ad7f77b2,9368557e,77a723ba,6dcf9357,82d9d917,6484365f,537611ff,49f157f8,6c4bbf07,25094f7f,d8db9a2c,b318ab4e,632cbfce) +,S(a847783e,46ccf334,d7b15f1e,d3aa7dd8,c5b3ef4a,7ced2501,c26d1dd9,4358adbd,7c56f1f3,323a500a,a3496729,ace84a91,6bc6dddf,90435a09,8ca51f6f,5fe5fa99) +,S(dac6ee37,3c655763,b01c5012,fe01518,c3ac1b52,543cfd7e,9ca24d6f,42e4bcfd,6b861af2,f2a82f0,d4c458f2,2d264d82,54f16f46,87e31cce,7199f061,bdbc941f) +,S(27dc7253,90de6a8f,6cd9918a,e3b2f33a,8ca4307d,ca4acf6b,f9c5d0ad,f01b4dd,2a0798f6,7e583426,cca8ab26,e6742692,ee790f21,cb3560af,271b0a09,eb9f8b31) +,S(1c6a5d3d,10983673,5e27dd2e,ff04adfc,7bae277a,870eb4c6,d6379467,de2dea5b,92658db0,8b6b85d8,5c20ad21,f3ad33c3,8de02319,4bc54d0e,4d758093,b4e8695a) +,S(cab35e2c,b731cb9a,402f77ee,44565fa,d6623951,be9deb97,88da09cd,d5abb56e,37bdbec3,638594e2,59018bb,9145c4e7,dfb55b13,bda50c6a,c33e975e,6c5d96a6) +,S(97e4cfd,9e1ec85e,cc49cb90,ada87b99,bcaf8160,9b04417a,70fa66e9,78bf54b6,7423ded2,bc56ddb8,11db577d,f1863fe7,dc758999,55989e4a,d344ed4d,5faa9ecf) +,S(f2a9b193,6f63e9f1,8333cc3b,745fb2ab,7b3749a6,c59e7d6c,42e387b1,1e9d86fe,3c6b6bf9,1c2c4a,859538c9,db95a2c7,abbf8c37,b6e172b3,cc2be8f0,f18b5484) +,S(49024a25,11bdedd9,6c84aeb0,707b5b70,f027afb5,8b4053e5,234a9312,771160c0,22ab8282,914e69ad,8d573e7b,841e9eec,2fdfb939,c76ff330,fb2fa5b4,14a4523d) +,S(781c9886,4bf29760,c44e1f98,9a5266e0,4d25c6c5,f941e2b5,cf92b958,99ecaebb,994a771d,eac92f91,58ecbeae,6227d2b0,4c09df72,c5ee4439,509f0b2f,6e361509) +,S(8f7e703a,ae008b13,590ccda8,b70d2cfc,4c98480e,2a5032bd,dbd5edeb,aefb7f8b,54226771,863fa87f,ec101303,9238da1c,74f9f446,26b50f07,f35d6b59,bb7ff81c) +,S(ecb2e955,ed796695,3eb1ee21,564125e6,e860935b,20fb99da,91556cd4,e5e57bbc,75103469,9b958e18,638f4e00,654d6eae,f5631483,4c890ebb,7e2d93e6,9f4d8bf7) +,S(971cd7f2,9ce90bff,4c46eef1,9df001f7,afa6af09,b553e8c7,792f4ae4,d3f82cf9,d4180c19,7a579e31,f27874df,f29cd17,98e5740a,36380349,6f7dd211,59bda50c) +,S(7ad3b286,3952489d,42cc8394,413545bd,90fc63d9,8558323c,feb8e7e2,50ececf5,5c566bdb,5efc3683,2b22aac3,c0b81f6f,bf656c11,5514ac9d,8a223071,168f139d) +,S(c905b52c,ad0e0281,a90eead3,3939c836,ebd591b9,26787a4,2983804d,e658aae8,df2a40ca,f95aa72a,181f3424,98024f72,f1b9e46a,3816cf3f,ba5ac699,5b996fc1) +,S(e2517e6c,84856497,8ac94585,5c80bdf5,7c074b6e,fdb01cea,e93c17dc,ae4b3ff3,373ede93,2f369807,56afd100,e2f65794,69247690,61a597da,80d10fb6,bbadd3a8) +,S(4d52a8e7,2f3cd95,2e25c8,175e82b2,726a8d95,b735c8d8,a0f1805b,6d94ad78,248b7174,61287611,8000136,dc92b841,de63ef18,a7c9ff71,a10a662,af76ff17) +,S(58e5b42b,e614cca8,e131cbea,24b3debc,9d9390af,469df700,35a01957,3307ac,be4a397e,7809c9eb,2113246e,7812c403,4d42d8d0,c353d841,3001280f,db6bc220) +,S(3f177142,a6e6eb65,ca5e1609,cc89df40,3e3c74c9,e5b291cc,49fb0d8f,eff86ecc,2a445bb0,b648487d,3b962bfe,dc74e4da,d1d98845,cea5f4c8,d2f0c4a8,2bc4c514) +,S(3389c700,9b2b0c6d,a25a9610,4660a164,172a4c21,d0ddaada,c6902bd1,c9f04b38,413344db,77b83806,80647da0,d6086ea4,d1b8394a,a0047a9d,4c21c667,ade67a90) +,S(ecf3f933,4b2b656e,24ea0b14,7528c490,c3a566ea,c4c51885,d3ee94f5,7370b218,3c07fab9,b6404f24,77e4605c,345d3a93,adf9a06b,649206a4,b369712f,7388af0) +,S(a090739b,58310867,5e460a26,7e29f228,effc954a,137f358c,12be2fb5,8011b2bf,a3563d1b,7f242a1f,7ff5e505,280c3898,13251c4a,d9392d82,d3b12a07,e22271f3) +,S(a251cd29,357e5300,5a8600e5,bb9d56f4,c8251f6b,46b4d99d,5dca7b2a,31f8201f,51764fe4,596059a3,b1eb06de,56c6e21b,d58e7194,8e1b6e65,51e53333,5f9721b9) +,S(1f9aafb3,eb39814d,7173b85e,b027ad41,be210c3e,e5c857d3,56288b3f,3b05c5a6,d34526cd,16e7d3fb,76ecdfc8,c11b1bc6,38762bda,b03c1c07,94565cbc,df41febb) +,S(dbd4b724,1fa4769b,db161472,1179fdf2,6df4372c,d3b0c4d5,1e37fce5,317e7e42,7e9bca3b,bda0e211,5f2e69cb,8fcfc333,fc1b8b85,70123816,802b22c4,9634219a) +,S(9ce40b75,7a257205,fdf51545,7d6f9691,7e54a5dd,32b76230,4ec50c2d,3b89b06b,9b128748,851dbe81,255f60f8,1e5e9de4,6b20a545,afec40f0,38beb9a3,f7402e88) +,S(12f6c70f,46efbb73,2150f775,5f597fd9,2a527a33,7039def6,5533cfb,18df3406,7d9f18a2,4988ea,a41a1364,2a1555c2,bc9bfce0,dd62ba87,fa628b84,850e92b5) +,S(3132e530,9b169a3b,7401651a,351f7fce,43471b19,7ded3d1d,cb0b768c,5620fc5d,3e377f54,92c99dab,84f4e45a,7cba38e,9b589fa7,77dfb334,849310ce,53294287) +,S(87160125,8a8a69ed,d52986a9,25a54ed9,51f561cb,8ee9e1ca,6c58b826,495b9977,c5484596,8ebfc8c9,5f317681,78379b88,2e9c2548,b3c579eb,f6da5186,5d51f36d) +,S(82674b33,ef500391,2dfd5f2c,26722df8,19fd265b,3b6e4cbe,239bea50,298653f6,bb6d0457,2adf23db,86b07019,f2f59fa7,ebb4fd2a,ac36ff16,6b22e92c,3952245) +,S(2efc1011,28432933,56af99ba,ea2628de,a518fe02,c5b0eddb,3688c8ea,39d4b07f,d54a087e,bef0923b,6244b21b,f260eccf,e7d590b5,cf98be51,856347da,ea48779a) +,S(f2164194,5de0542c,de90f1c,4be955cd,98f6bb14,ff30ab44,92691985,882fad46,a87f6725,e89afd3d,6f24db13,39fafd45,5f578c9a,104f6509,c83d0694,ef795dda) +,S(72d2c60c,6f9bf0e5,5de82932,88c298b1,4d851deb,6ba7421e,ad22f3d4,2b47ee88,29626eaa,712e6d76,d85b9f7a,7a17461e,132c9bb7,a2943379,c5eee30b,1ffeb1d8) +,S(9bc6dede,ebdbd843,a5534fc4,71212480,ecfba4d,96acfbf7,25e980bb,8a509773,24ef23cf,e1580173,797ffe5e,baff2fc4,3cbd3161,e87e32bf,463333db,5ca904ef) +,S(20ea6c3f,51565fc2,bd5b8eb8,1ccd20fc,f3aafee0,9ccc9de0,733df6ed,8caa9c81,78328fb1,ff260b0f,cea69e1b,77b35679,d6663513,8f136c59,127ec2c7,d9668dd4) +,S(aaa2ee28,a4724d91,f37044a1,3b264ea6,9dd9123a,b3b7b300,999564d1,73057339,250b6164,2ade568b,8a56ae82,4488e740,b9a65f7e,a2b95f3b,4b11b6a3,1b49fddd) +,S(a1e54535,4a8976a9,33c04366,f0361775,824383e5,2c3aff3a,357788b,38014ab1,a6a306b9,b0a7d3c3,d6530094,9efb038f,a0a2cd1d,79bd495a,487a95f6,ef2b7a7) +,S(f2b0c76,18fc3ca9,f9ec5d65,2f39b6e0,158598b3,cb90b20a,53fdaf97,ac58f7d7,1d63cacc,7e8e46ab,47ce7e4a,e5a3336b,8d3d9bf0,f05bc428,f6f769fc,7ec6cd15) +,S(91843b8a,90a43571,4d7500de,fff102a2,fdb53914,2bab12bd,d3f23576,75a9d62e,3cc6365c,7dc3813a,d51cb2a3,d86491c2,c4e38f2b,10a33181,374bb0c7,ac90237e) +,S(f73b2226,8122a4e1,a440f891,14fd8d72,19cad2c2,9798cd0e,3631eeaf,6b125a92,bc14e84f,ed149aa8,ac261f96,6b192168,26f5a2b7,cfb997c8,3f293101,e758aae5) +,S(e87cfcb7,1f2b1c9e,8506b0e5,c56b14a6,52201397,1bb4c53c,855f1de,45644ff3,7e3399af,b4a9f70e,63907a29,c02e4d58,b2e76517,e4f2f2cf,a3d2fdff,808d5b08) +,S(b9657f0a,6de5cebe,47151293,de1fc3fa,b2745a18,bd5c4b8c,62282f26,84404f21,89590e9f,a787f41f,79a0b8b7,682bc353,1ad60107,771233d9,ec303830,e8e8dad4) +,S(b62d02b9,de395843,eb69e8bb,4d974590,7c8d3b26,cd4b13a5,6b4a0e27,44f449d5,173cb5ee,60d3999c,7e795607,bdadf8b9,acf9282a,d7a68ee5,6a204eff,ce5fe751) +,S(b6998e3c,31e9cca5,251a9d89,1aeb5384,fa86c92,74a0f027,8f2dc67,34b5f8fe,7658a71a,fe032a5b,ccb80a1b,1516faf1,5a3e8638,6f74b2b9,b6d17cea,61c3ac5a) +,S(864d4c66,4db88b56,6471852b,eacce0b3,52b55404,46444cbc,afad4f17,204a0170,7001969a,fb35a3ad,fc553e00,b6faeb21,c8fb1af6,135e86c7,f7e91397,a826346a) +,S(22a0ec9d,ecf7a2d4,6f550ff1,5a8f1c8f,6efeff9d,3ff65d47,97512980,216c025e,9d60fca8,97662f4e,947c962b,48522cda,c7ba956c,5a23c3b9,67f46073,af0980cd) +,S(f1be1f63,769f74f2,947eb25a,194171a3,9f9096af,cd454ad3,35809b17,d7e69fb4,b78b3a16,b734c528,c1911d95,895bf873,fcab1440,b62211c,25aa247c,161af243) +,S(7b196c23,1a7650a5,9db8faa7,39b7ffea,488b3623,a0bd7a2c,48b51c97,f5726c76,56e84642,2c430157,bfab8821,9112124d,6bb968e9,3ddd6b77,7ee08228,9a7e1241) +,S(6ad31b05,5a1f1a65,f4e554eb,31e3e048,8570032f,8af2891f,4436c640,9420849a,edeafdae,d10bf173,5de8ffe8,41871909,79f6377b,4cb566f6,3386534d,89bde755) +,S(fb0f3da3,a44c0921,85d90b80,1e7f5aad,6c85d5d0,b9cc4575,ad95ab34,4fa6aa7f,7857f22d,6f9356b7,96020384,919e26de,b9abd707,4dc6db0d,768f630d,b3589b18) +,S(c39b4ddb,edb892fb,2394e875,7c7815e2,f487f81b,45c60749,1c314350,c929d96,530f0c07,68e66dde,e10f0d95,bd66c07c,ba10f165,dade7bb3,77f8b7ad,ac4a673f) +,S(c50b3ae6,d14b11b9,a74dffeb,a5bfb9cb,73652cdf,a2bee6dd,6cc3c912,c312e537,85ac82f8,e3aad88f,9af29cb7,ba66f8a5,8c340d03,a1f32654,2071ba6e,99705377) +,S(a763e636,4e4959d8,9d3047,bff6fbb1,912d99f0,c092fe62,947d4385,2427ec02,bd799a82,a3cea8e1,db94946d,c7d32236,13b008b,da8eca4,921c985c,c022622f) +,S(2abdc992,b2ba838,1da0c2c6,2b35d3c4,ec1a1e39,516b6afe,81fdc7c9,cf3715cd,8115c826,d214c36,36a8fcca,37e89dcf,4be7f34a,2cce7357,3a6c42ea,9e084a66) +,S(2cb83bfa,ef83ab3e,53216500,944b2db0,e8cdb6a2,caad1eec,c9e14c33,a16a07ec,5b1b1199,6e84c17c,13c070a7,99dc0975,3d374018,6f9ce89a,bced7539,7121ec7) +,S(2687de95,b368b07a,7808ebf,e45fde24,d66fdc81,a02744cb,3e96e847,f0a3ca41,5728b8fa,aec73963,236ca282,d1a8946a,b2a26f28,a239590f,9d38bdda,d05a846b) +,S(b143029e,7f32bd1b,a381fe82,8da79713,b53550e,f3cf867,4ef1e952,d4dff9d,a44a622f,ff5fb466,83b69803,c6ea5c16,8d86c673,3ed94058,81aff0a,2a8edfd2) +,S(4c54d53f,cefac583,6fcf3b87,7202afc4,ccd68695,567c7fe7,6068546f,aa9070d,7f42728d,78193fd5,946f3787,6ab124f9,b1045ae7,45df58bc,cab6f59f,a27c6f18) +,S(6b625111,556e3ff5,db9cd8f3,7f610b3d,718220b,e459f546,47314b04,b2ba9d6e,b3ae66ca,fc58bb7,5a057767,8bf806b2,c204b90a,fd114ae8,4ed51378,53b30a78) +,S(b3fb12d6,e16e4279,5fcdc1ee,23d42f9c,198debdd,56217af,5b76989a,271b473f,d38adb77,4ce1d0b5,e41b65c,7c973a27,10c5621f,594e6f70,d235f5e,a4a89386) +,S(9c7c908,6976b590,ba9c80a5,fe12c5f5,ce6bbdb3,5a4058a,3cc59899,82073ae4,399687af,4d3e221f,6168ded6,31644c35,e41606e,94583429,34693221,9322da67) +,S(28cdf6d0,f0374a35,4dd169a9,1c3beef,fc88dea0,4922f841,401ffe91,8bfbddb2,2b8f1d3a,6f001d60,95aab0d9,d6248cef,cf3b97a4,850d1a43,ad2bbb3e,d2ea4518) +,S(1974b196,a25b6446,2ceda38d,d99662b9,7dcd0d7d,15299c00,9b8d14b7,f139e7af,c685622d,96fd6379,6bfc3f2b,6eacd54f,83281ef3,50d2fed0,2507a157,9fcdb74d) +,S(3beafb9f,4cfa3570,3d3346f1,afa48acc,25909889,a60b76c0,6e7774c2,acfe4367,6c8c09ea,7233ce1f,cacc82fc,9c1dd357,51021b92,fb86d6ca,3749bd58,6dfa369f) +,S(b5cf157c,4586fdda,16a111c3,9a500daf,b1aefb07,e32f78ac,a23664b,cef3be73,1d273f45,58e7c2ed,6f46ed71,e297dac3,59489934,b10afdc2,cf0f4270,ad6fd53e) +,S(9bd52baf,cde37895,9439aba4,b1fd4080,84441657,c2b1b36,c45446a6,7b661d6c,87f63761,6dba07e5,96d71dba,f86df28d,c506a123,c6f082ff,47886a93,da068ebc) +,S(20cfa2f5,b391d687,b89cad8a,a4c5ac8d,8624d4c1,ebc94cd5,d47999fd,3278febc,1bd4a896,4641d8cc,f6926323,8b1be2c0,49141736,ee780ba,d2110f27,a674239f) +,S(e54db30e,e18cff40,56473478,2c61d437,c79adc23,51739315,ba845adf,c7e8b6cc,ef631e42,9529a407,cb3f832f,6aee6fb,a26b125c,fd28f43,b9f07e4e,ad8b0632) +,S(588f13bc,3dd3b927,7508ca9a,82ffe280,fabd5cb3,1413e848,2a2aa4d1,78a290b0,95c81a4a,44e6af9,5d8f6fbc,ba3884d6,d6a54057,1835184e,50f5db88,d08517b6) +,S(1927e8dc,ddc7ed4e,62a32a82,bd4a0977,fe24a571,10b1acf3,78826484,de7e757c,e0a9674f,76122a18,dc6004a7,ebd1da86,f98e896,5585518f,bc5f91d0,4699719b) +,S(7b82c663,aa2201cd,71dd7c2f,b8303264,8639f9a7,9de52706,e2deb38b,85dfcc36,90dd6e59,e98c611f,a7162fdf,8fc503ce,71b0ad1,dd150698,e4c21916,d5ded962) +,S(a15fa4f5,97086036,9e9c3946,5f16a458,c7b36ec6,6ad384db,7803ce19,555a2bbf,bd406283,43e40d18,25a02557,6bbf752,35e34400,dfabf022,6cf2bd3d,8fe80901) +,S(2b6199ea,7c42b7b4,2230da51,a895ba86,83950dd9,d4d5ecef,80512976,a0df55af,26ecea05,16faa497,3fb9865,16415ebd,93ce4a6b,e4b5cf11,3507d3e6,6a70b692) +,S(35ad2f4b,b5ba61de,364e8198,f5404ecd,4cdbf26d,7072dbed,d9892804,364b43f4,5481372f,7d1af5e,9e60cb02,ae8512a,6bcee9c,eab1344c,6ac5898b,aeca2e94) +,S(f4eeca4e,2ab38839,8a459df5,b94cf98c,68017522,353aaa98,bc606bf7,5008c6a3,e016b7f9,aba6e910,6a647662,1e7a5b7,12ab97f6,498f451c,21902e0b,9b6c2c2) +,S(6c488180,aeb6c444,78ef24de,21a47431,b2e26d9c,bbf059a5,84631829,a75ec053,ccf084c9,38491cfb,8cf0349f,fe80a315,71bbe0cd,dad9a7d,a4434cbc,9160baae) +,S(a52e5bcd,2214d405,57360828,10ebe384,a94f79a6,579a8966,6f1ef7cb,bc80f4e,c28bb594,e15c47df,9bf4ef2,2666fe4b,d916dd9b,e62b60d3,49c2ba11,506fb79d) +,S(c55414db,3374563e,5c79d9b1,1103ad01,7b7c04b2,3afb5431,8c469cb,49ea9754,f54a4335,7bbaf088,4d18bd70,6f3d69a2,44f4d527,a6dccf5e,52f468e3,752a998a) +,S(b7771609,335ac0ee,1e82539,3fd3cfad,5cb4b06c,98a05bb9,95966e4b,6fc1f24e,f305d878,33f95e99,ff6a3b4a,2b77ffa2,4cddd5af,d253ebcd,d60abb1,438e0745) +,S(da220e1c,c66af350,10736e75,483e2573,91f6d2e1,d355d05b,8471cbcd,4b64832d,bd028d5,5db1c54b,86f6f123,bbabe6b0,f3e52e02,ca48d92d,464311a,aaad3cea) +,S(1a680b36,991edb40,ada892dc,6c102b0b,186bce17,280f9850,ca50eae4,6951ac7a,f03d7958,b0789cc1,43d61fc5,11b70f9f,1ef17239,dd6a057f,ca394f62,225ed9f6) +,S(af8ca10d,b1975668,b8071ea9,5d474b5e,424d461a,e98b5ab7,bc240cc6,44da9c57,e74ea4ca,59f926fd,89bb2bac,61790ee0,50d746af,5e30019c,5b53130b,9cb9786) +,S(e6014570,2ad63dd0,5d98c576,c3d5158d,162857f,7b83045e,d91865ac,bb347922,52931836,4a9fe323,40f13c0e,15c955fe,f718ec64,4b45b141,33fa2edb,c65baa18) +,S(56eedaf1,fec96ae,c2f1e051,9a1c4a76,dc0ccd67,1781cfbf,7804d215,626dd5de,adb8a791,b73aebc9,c6406e2f,83e611b6,286761d1,a6c759c1,de85658c,a4788923) +,S(43c5272d,a3dc8c2f,edb0f5bc,a5bd5f40,fea4bd48,9f367675,cb578690,636fe0ad,52c62fe5,1cc2dbbc,57de501b,839cad13,b94c9e12,12b1cf30,d8463605,f7871c43) +,S(66e76528,7cd0ebb1,9d9e0d76,aaab4230,1aa87367,c3a3f96a,101c6125,84f816da,39a4d3ef,8d263217,3a3a8c3e,d9c1b460,e240cdc6,9c9cbaf9,89535604,a2f28edf) +,S(1a274502,31f1b5c4,9df7564b,f311a7bc,d5123e75,2471c243,65c0e142,d3b292d4,5eb550b4,ffcb5e1e,c695f22c,dafada32,1e967ac3,7e1fc20b,e0e695c4,324c1131) +,S(36f1c3b2,ab6a692b,5d3b1e10,f53b43c7,7d5c4e76,90e089dd,9e70eac2,773c3620,5553cea3,8e56a7dc,384458b,84c419cf,2d493246,1f75f16f,2d1a547a,6fdf0289) +,S(1ff0f8e7,8318fcb0,2b23a1d3,61015c67,6b1a446e,784bbdcb,c088b241,3da40369,39db7b2c,6923a1a2,379b58ee,cb91ad5,554ed5c5,60d5ddba,225c0074,e9fa4415) +,S(c5d7b7f5,d6dddac5,2a2021e8,437f771c,216bfb43,24c57ba2,e8b43a0b,dfd17e8a,78fc37a3,9586cdd2,f1145cd6,f9beda83,43e8ee5c,854c256d,419fdb4,1c9d2bc0) +,S(4af5a3c8,cf107e16,fdf3522c,47fff7c7,b2fcff70,c6c8b36b,7d66a3e0,4b107250,b1b6e5cf,de869937,45ae8632,c5e2860c,76a5f481,ac24ac86,ad135136,e9ff4e04) +,S(37b59d45,86fff48f,67ff3ea3,f31f721c,3daee8f1,a2ff960e,3f77b793,3e35b50,73a7d048,2c93b9eb,4c2f6359,3ce61497,ed455970,9b2ad7af,2d0f834d,6f070d98) +,S(6e9dd180,d5b7c41c,5f529439,e46534ae,b80bd802,b8b12e0c,ccf532ad,a99e663d,e981b043,e936da7f,ecef09e7,cd118646,5bdeaa64,45a00a59,1139eb9e,5628004e) +,S(fde9062a,9f7e13dd,39117543,be4aa5a8,fa10b810,a2285661,720b4586,68acc236,fa39cd20,a5eee1cf,3727df99,32c5289a,96b1409a,5721b9bf,1ad8f42,ee35069b) +,S(d7ef4012,ecc74538,16c392d0,4d1ffdac,76a30992,4c1489e5,159149bd,84847835,b2f5e699,9883a21b,edda98cc,ccc1ee2f,258fe291,c508cee7,39619659,e18c9720) +,S(8355ef2c,f0e37956,56b77adb,5f700f75,47e2c14a,b5f6a0ef,8716c99b,a919612d,d75dc6c2,fdf0260c,6682b16b,42d022f2,f03bdd1b,1e6ef520,da295465,a1988eee) +,S(cd49e795,63655bfc,87bbba18,b72a0c50,52568a26,53bc0543,3661f3e2,2ff159ba,ab28dd46,696b7414,1365316a,c8cd8dc3,2c2f5e01,6ae34302,d103cac7,4e37d25c) +,S(8f93b20f,28f89a46,1afdf08d,7550964a,dfa8df2e,ba2c00e9,9d351b84,2d6e0b78,92ffb09,812b6970,7746493c,c833bdde,6849a2b6,ee7778b8,2b41adcd,62b5620e) +,S(a7b3fa74,4621cc50,f6719d0d,5fd3f2d9,6acd3163,4dad1114,3ece3db5,d114ab2,948a3716,9394841d,68e5b64d,2f86798b,d78c8530,bb8d4d61,f82b5f51,ed0f56c6) +,S(e16b540,d62e3237,361ba514,a11f2ccd,ff72ae57,b37e58c5,d4c3c49d,2cc8fb7a,67efad5f,f02c36ac,a0c0ab0f,ee5e5135,fa7bb3c4,51472d37,abd0711c,6618a7ff) +,S(589645ff,5c3dc06,9d2ff542,5278a51c,c4fff14c,3de96036,b773497f,8940d240,1ea7ba1a,95f65259,c30ce21c,a95b3b95,83d11b10,3c8e633f,6dacbd2a,fbe44116) +,S(d551239e,3448ccc8,9a83b8dc,41396df7,d3db0c3d,f79490be,9d44636e,f5f0d0d6,779118ae,a8db8a05,f2231b5d,923e9d97,5e69a462,5c2ad551,5a8e7777,b1b25899) +,S(c45a22f2,9f611893,d8577d7c,9c1cd46d,82f41b48,a7c18628,ddb609e5,abc434f7,515624f8,5776268b,5a5c74fd,8d87f8e3,3e47648e,2eb8c2e8,27e9b57f,7fee5a1e) +,S(fb8e4546,639d9571,90f2840a,2f72ba12,a72063fd,85f160e7,18477d01,26132b85,3cead630,f8bf75c9,31d19cd9,6f4f3718,1efc4854,b937ac31,c3e0dc6e,363db575) +,S(ec51e7e1,6cbc70cf,1f053860,fd21e120,98b652f8,df9eb31c,74eb787e,87e5ca5d,bd5afa95,6996b7b,357b475,fa7a326c,d6c2505d,1ebf6fa6,feaa27c2,c2685867) +,S(52c497f6,f8b9189d,30fc42cd,9c2a44d4,2d4f70ad,815ccf05,4f50571b,2570bea5,35f54d97,a45e2712,b0f9a720,38adbb27,a31cfefe,c065ba9f,883d36c5,c070e9fa) +,S(2fd360f,1680b7b6,5f49f64d,5a648e8c,97e4a756,fe88e107,91fce9b6,295cfc85,7a88eccf,c4d82e86,72780c6,e1c34bb7,51a6029e,dea0cb77,3d29a85,b0689f5) +,S(7b328546,25307c85,f9ad0c31,ce2c31dc,e746931a,57ec42ac,16231165,74f63d78,6862d363,4360e404,9693dc03,772f4840,4a30f167,993c8f1b,56244c0b,af6e29ec) +,S(af76b473,4cf5f641,25124792,fb558b97,df60d67e,41c2b104,ba27ff35,e3be96c9,21e6d4c6,c1e0d3a0,69520227,c4cf2ef2,8204d85e,26f4ebc4,5d6f81cf,10defdb2) +,S(5b1237e0,54c98238,df2ccb28,a5b42b64,cabac24d,1126c8ea,5520ed69,ac449521,de7ac1bd,4994cce1,8800ac0d,5499c33d,bdde3096,1a0c9028,58de0325,b91ffc36) +,S(b81bcaa2,25743a49,36fec95e,13c8c20f,f818ee5a,6bda3850,870492bb,b3380d5b,6ea959d5,483ea6f3,5b3a4a5c,1987673,a8196c98,d8efe8d0,3aed5884,dcb391ce) +,S(5f6ca7cd,1054051d,3d8a2a83,73be30f3,516b305c,feffe073,ea2773fd,77eeab3c,89287d8,22775f53,61c931ab,bbc43d38,380488fe,5e35124c,2daa5441,3b36c126) +,S(ffb3a36a,8345f9ca,30369f21,f04dc9f9,d5f0282c,d0e1d68b,f5ca1cc0,c05ca91e,21ddcc3e,f5a94fd,8046295f,c0629b61,b1e8fea9,364fe659,d298e0b1,be5a6c17) +,S(51902e3d,8801dff4,e6bfe7e8,8f600d75,42eef0f6,e186df29,3a8c691c,d57b36f6,48a27fbb,cf9dd38,a1ab966b,f635fbeb,35bc3fcc,52f0cae0,d9a3ad5b,2654eaf1) +,S(f1a68a75,8f0f8937,e14a48d7,15c4cda0,679d9b9,12682182,493cd9df,c3ccb345,db85d3bb,b8431e56,d21e8c1f,4eb1c750,225bb222,38da0bc0,30e5da0b,d4f4a985) +,S(81d88ea8,4969d53e,fd0aaaf4,248a3558,f37059da,a4b3d32,da538bf,ca1a4d15,840fe961,11756d96,5c8cea1,32067ccf,31ac66bf,e1086f16,afccdbed,f16a2d33) +,S(b5830ab6,2e236cbe,345044f3,af940029,39b00b52,e779ce10,b02c446c,84163e95,d8720333,b210a391,499f38e,134a0989,254faef5,126750c0,ec2a5850,e1d4a821) +,S(b50caed0,a4e9e41f,f03d16ee,1848d92d,d4e6b76e,4e2332f3,793e8650,20bc4d11,39195ffa,13745502,eed8801c,40f36e2b,d9b636bd,11d62388,8ebab8a6,41d3ab54) +,S(6190402a,3750824a,149945fa,df942c0b,3622acc,b2ee1304,f260593,8de5c333,290f4d4a,73a1c72d,c5ff4228,41e2949d,966da112,5278d082,ab779e8e,d4cb179d) +,S(8966488f,4e991a1e,e34552be,c6246b2d,b9486442,47fda545,f8083b7a,b0435060,7daa3ab7,87283446,a7900c83,b726b849,f7dad684,6326148a,aeeb6233,738c6c4f) +,S(edfa388c,fd246c1c,6bb7bd9e,6d9d335f,9cbd7018,ff2a750b,4ba976d9,dd922b5,c74e1113,f10e6954,6848e4f4,11a5afe4,bbf7dfd5,d252e66,5789627b,b81ce714) +,S(304740e5,1b99d9ae,97de2a55,8dc1abc8,60bb8b5d,a52f6208,af8e28f8,89904951,8ab409b2,3606089e,4a111377,c8a94e5e,75ecf098,4f62aa63,faaf7e18,f93a37d0) +,S(d4ca8aa5,e31028a9,37d77295,96b011aa,c26f58cf,3a7ff671,99aa7f30,3e00bc30,5ecc09b3,bcd9afcd,309280d2,617cbfb7,e4a9350,b4ef79ee,1e46a8c9,56d46fb1) +,S(4110ec3b,ae03a061,59910aac,4f2e4bd7,77d5e055,4eb6920d,aac4b835,2d7cfb4b,c1237e1b,d6f1cf1b,6fb0f248,9e3712ae,5557e4b2,f72ea7a2,2c482e6c,d84eba92) +,S(f7c55f97,3e9df72c,c9da8e04,b1926688,1d53f810,fef5e664,99b81f44,e4f9800,4b45e93f,e02c3993,95238c80,b65533d5,ebd01cbf,1b3dbf44,4d550cbc,4652fa89) +,S(2de3290f,56fbee3e,15def5a0,5d65436b,9d722e3b,a435f269,a5ee0231,857cbd29,f80d2ac2,356ac72,f3106b47,5cbf3701,bf924e3,48e93c9b,f3327b55,bc203828) +,S(c8e3d2b8,21922146,1862d5d3,319c2abc,7dfd568c,59df4367,eb975a95,6e22fda8,d6ec1b9c,e758a8c6,47e718a3,ee8ae232,c416d763,d2887e19,54ae4c30,30404f20) +,S(50c1a147,c117d907,fc831f72,9be19b3e,e93733e3,aa3bf402,e64760e2,edc82065,acebcfda,80706b53,116e4cc8,cdede6d,5aa1b7ec,62ffc942,572f729d,47396289) +,S(7bab8930,55114c0b,e4f7637d,ad165491,c21d6970,c8036375,1387012a,7b785528,6e31589e,2ecb13e,b7bca5ee,39e3bca,fd2e5645,6574a642,131d6178,901c0d97) +,S(dc94ff4,44a12ca9,5180904e,58802ed3,d1be43d9,8396360,e9e932e5,622d257f,ee2a426e,4da3dbf9,8a6d5ad7,9a5437ce,6fdbede1,25e836fa,697685b5,989c86e2) +,S(efb2b411,e66f8e8e,186b0fd0,c572381b,e9edc68a,903e95f3,759a11b6,b6a9dc40,4a7af79c,a1383f20,55bd080b,f410f554,24a21ae5,7b57b63c,bea36486,6c30dbd1) +,S(2f37ff22,26a0c4b8,77a36da6,7a423f59,497a26ca,8066a651,c13573c4,4954599f,f9d1c91,2b74f663,56798637,9de41a46,683a7cb7,61ac6e3a,86d65094,d1e07a8e) +,S(63aa61b2,e24fa178,95688d95,442844cd,7e68edcd,98eb3496,ea071c4,5b46abd,9423daf8,b6c241f8,785b76ab,a40803b0,97da461d,cf6579d4,4308c9a5,e63ac4e5) +,S(58618e22,93c52375,4db8187,34e355ae,27b73f7c,4469d7d9,115623f4,e8e20900,8531be34,22616853,c2c095aa,138819b0,bccd7c51,1380c64c,65ba2500,ae18794f) +,S(61418bdd,2619e7c8,f32c8cc5,34097cc7,4a9a0c57,a38db50b,ad828a60,f658fc0b,acec4e21,774d283b,db9a8a11,115d20be,20cbfcd8,2d67b10a,3d57dba7,74537c48) +,S(79ed2dcc,dd4bd25,67dad04a,b32c9273,39a9c592,95a69b09,be7965a8,c779b2fd,64860dc5,d17e409b,4feef8ea,8a7d7350,3eec186,1fa15f8b,f5576a9a,39f65283) +,S(a20434a4,c51da2a4,c7a6699,84f41ef4,67bd4de8,a628fbe1,385693ee,6b6d8a52,e2a00a0,d00aa33b,b49743ae,6f9c824,d2fe1f7a,f51f7720,cfb0d800,94279dd1) +,S(d8c0bf47,530ff603,c140503e,84fdf6d1,ed908b98,cd27136d,ecb2c4ce,da9f8c61,19e02399,bd898b4c,b9987fb3,4262df35,9b32cca,430e7cd3,aea9d20f,530610aa) +,S(29f06c46,a20b5387,aeb6e490,ef9a7bda,ce16fc2c,8e8eb202,b75973ea,8dc4f3c0,2220f678,daae0cd6,8514c091,a1dd7060,b21c2630,138b5e32,e0d57d79,b7b06d7c) +,S(b18aa504,d9cda828,e67d4f55,ac51c961,e9603d0c,ff737c16,42f1c8b3,fe81aeb9,1f6d7e83,480a9290,789c016b,b62e6e8c,adb4b500,fac710a5,7969bff2,89578ba8) +,S(e7591f42,e649f9f4,477c9cb,bc8559e1,f01eeec5,e9f3a0b4,8d9bf515,6d2044c,24c8777d,5e7c3f7b,2c6fe0e1,cd0e3845,45bef898,aff192ab,c4e719d8,ae466385) +,S(65992fef,50a1983e,bca478b,419ae258,77ce7a52,339ecbe9,2394dba3,8ba72081,32491cbf,baa7f8a,9cf21a4e,57ffa85b,eaba7653,d46d9f95,b4e25212,7bf76781) +,S(771b52ad,e47d035c,ddbb1012,bb89aa9e,b774e0bc,aded4998,86e1e358,ccabf9be,1a897dc8,420a076c,5a723f30,206db0bc,e9760b09,1f698952,1c4edc17,f2dcb202) +,S(a7d5c532,bcaa8ed6,6846046f,d1570837,111281c0,795d3e50,16cd8108,5721d644,13ccc5ee,4bab0d34,2f740ae9,e538d50e,900aa30c,bfe99e54,c69cecc,f18f6aff) +,S(fb504652,a55d01c8,b45ed7,6c71d,9067026b,27e9ceed,c38bf6fc,aee16d50,a150b6fa,f37b0c6e,ce4ebbef,22277b37,44933fd7,a135a25e,5ba8f7b6,1a6b7d0c) +,S(6242a221,115863a3,73bea0fd,39974dea,3c33b794,68e04087,8ebd8bf3,ca09f1d,b806de29,fe9eddde,1556c09e,973fa20d,c4ff916a,3d22504e,19e33169,f6f903e2) +,S(30382a2a,fefc7110,77af1a7a,d8a4a4bd,622635bb,73e50bab,c58116af,d1e8f3cd,d7ff3c80,9845a620,d53299ee,98cf3c6c,499ade93,84791af5,d6618866,3b6b74c7) +,S(b69ab576,13d1527e,990d747a,bab1582c,af995b34,6b25ed1f,df3490c,5549f36c,cf896a0e,4878bc0b,ffa3a750,f83dd329,ade24fa3,76acdba6,dfdc294,768e3f41) +,S(36f6c331,4071ed0d,b2be8f45,fe19be0f,9b37a675,a56679e8,bb49925,9339257c,d593ff7e,a32103e4,9cbf2995,21ad3da1,5b1b44f9,d6c95418,9c794291,b1e6769e) +,S(fc312428,7a9ab1b8,3efce7f8,17f707ae,320dbe77,e5937cd1,513bbbbb,90ed9995,11bce5f0,91dd9ef8,42a46aee,6f3a1d,7cc23da7,381a5f24,4b5a2638,45b2bb0e) +,S(b0de8720,58e1165f,ae1207ec,5ec0888,5f14bab9,35a2fe6b,1f7212f9,7b4913b4,5bab24ac,2589b8a8,c5e102,26a907ac,391289ed,23fba10,b2acdb74,a142b395) +,S(699828ec,db84587e,31ad233d,c27ce5de,a8f4e03e,2c450706,d625e387,12c0af3d,db1d9e5b,9a74caf5,855aef9b,6b8d0c18,c98c27b8,ce0d8a67,c6bd8467,261f726b) +,S(8d133509,d51edc48,97830f8b,3f8a6688,7a16834a,5ea31602,1649e219,cf899cac,9d188e67,2940f23a,39ac6ae4,fa532478,9c5df2d6,57f8b4e4,eca17e02,5560f08e) +,S(9cd47f8c,a9d3ebaa,d94dab36,4412ac4,a74a4b18,bb516538,10da1df3,9efc7582,de1e5cb0,fd5e7a20,322636d1,883b1ce9,71bd0565,a0eb60fa,559b552b,34b42e1e) +,S(1fef4107,648ca126,d5c4fe59,1f190f21,57274d0d,d9c57fdb,ffe2c348,35d36ddd,abf8fe20,87ca3feb,d8150e5e,c66c5d07,45731121,9b759430,4465bb14,55f992ab) +,S(e372b12e,8d3fed92,9e01babb,1a6517c9,ecb54d3e,6d0524ec,42ce57f8,5351d32f,43e910a,32447627,e2d9d5ef,53cb9c0,ab60333c,b07e72d1,c2c6644c,83e7d8a2) +,S(37c346cd,ae9d76e5,7ba2f30f,d05c33fa,3e6058af,642fb1c1,1810b4a0,b97e2dd5,9939c619,e1e49ec2,bf716714,1c23e135,157c7e4e,949e4fcc,b7dac7b9,7d4932d0) +,S(14e337ac,39f0c1d,98333716,a6e596eb,ad0d0688,b815c7a0,c182b546,88e5c3bf,fe45e34e,bfb94cff,a72b6312,a422562c,8ba782e2,16d5ee31,6425651e,e67d3d22) +,S(25517b3f,79da61ae,dd50cd1b,69b1ee36,fce0a44b,feb572e2,e6eb4aef,d751146d,7d2a017d,b9089d13,9a072803,dba874f0,f169ea36,95786e13,7fcd36d8,8b28a213) +,S(7d5957a6,92fd532,b9991383,cae895f2,8554e6c7,83ae3bcf,e72e3678,3475cb46,fa4b9b07,2bc725f8,e35b01b9,590ec1d8,f205f6c1,3203e91d,d9d39954,922d7f65) +,S(77eaf892,c4f9e0d,f63e33a5,1c088e0b,323ddff5,6f854475,b143b458,3e0e2f81,93d0f67d,51abf50,ea260593,96effe6,7f985caa,a9d68250,224e7193,414105f5) +,S(812c11a8,2851f474,e5a0a175,fb527539,7f1c73e7,6a766cd8,7147c9c4,4c970ec4,f9e22a19,a35179de,30379c37,a616d226,666311d9,4ad62b6d,59fcc579,cd024af8) +,S(b633f071,57c5a0a3,7ff5f626,17de24dc,14b3bcd8,4eb43385,e5a59be5,1c371fab,93e70e48,68ab5a3b,e29dab87,8a50e2c3,a09edb5,bf5b47d9,a09ccf59,53b67673) +,S(5e78caf1,9a2031a2,d92e1ba2,1f43f91b,10a98672,5d23ef95,1bdc1f83,cbb16343,b438317e,9446b88e,92206d81,883d5f3f,6497ec33,d144cfc,3a7dba41,db53cbc1) +,S(dd082ebf,88d49fed,50b76df,8e64d3a4,a1d4bbb4,fcdee50,c3ad6d0d,a91e4ec3,9efe99d2,f15d46bd,26d67bc5,ccc122ed,bf5034d9,28bcc946,e4714784,5edb6244) +,S(1ba1e135,62c06b5,63db5c49,7ed46ee5,73399a56,15fbfb1,4e080815,874e6a2e,f298d5df,43111fb,2f050cfe,2a06b3,c9a1fa02,d409dbe8,a225a3e,bec2d8be) +,S(49477847,a590a536,e7370341,5380459,843da9c1,78a1d176,f2f0133d,6ca214f3,3d1b8f64,a1d94169,2baeef3,86b4740c,4eaa84a9,15e4d03,2bd7bfd9,f5d5bad7) +,S(c4336d6a,4fbc288a,2c69fcc9,691fc8e0,e277fb98,e34b7a66,bf29d2d4,32c1339d,64ca0adc,72f0ff2a,f150f01,ea243a51,e91da8e7,480e0553,c7bb268a,22fbd383) +,S(a510cb67,9970c117,49e4e9d9,acdb97c6,d8712ca2,7961ca45,ddc9669d,9e02207,afa065b1,46b75ee2,ff7ada4f,ac7b863c,f4937cfd,15ca2ff9,c0901c7d,faac88b7) +,S(7cd63347,59eec80b,666237b2,abdd6c6f,e5e24a60,9305165,b5bb1a04,2898cc7d,abf7dab,f9e12893,a8040b13,afe16524,1d749660,93cf2da,157e2a78,e89cc758) +,S(e0786f8d,6f339bdc,9ff47416,4070bc08,c864d0d2,6d507762,19c2ee87,61cb7959,892cfd2e,62f4c352,b296a508,455a1dee,8dcec943,f5109add,9d38437e,87ec58c9) +,S(d81f740b,123cfd5,9c5ceb73,47668148,995ca21c,a3ca1b8c,b48e20db,32f6b55d,3af34294,c83c41df,7d5f821c,68e71e34,4656be14,f09d1858,7a204244,6f74f4ff) +,S(f4ba0503,6ffc1812,efbf3fe3,81423d91,38eca2,a67a0f4c,2d0474e6,5db9efc0,b2b3c3b4,4af46f2d,e53b1e8a,adb83d59,4c32b6ca,a7113207,b7993bef,dcdf78b) +,S(aa6f03ed,50640e0d,72fa4de7,ec3964ab,82e7758f,5e6c16d7,78c18296,e3b1a527,322223f7,ecf473a8,36bcfd41,e50f871d,715f9729,93df1359,80794587,59d9767f) +,S(f2d48f68,23984bd9,e8e87772,28da095,4ca134a0,6b43e0d1,1a8843d7,1fd0232,f0b7d9e5,982d0f6f,5ef74bc6,78ee504b,6202f52e,8db7c069,e179d175,c6f760e4) +,S(70e9ec90,7db14601,9741a4d5,ba604187,a7313b7b,500864b5,383b3763,be303979,63f9ef9d,eea1d1bf,a84e0d19,c8f15665,60b4f1dc,839aef5d,b6fbef7e,d6dc6a4a) +,S(23cfe5f9,7198efd3,f34f657d,158f092a,29748586,29983927,9c58944b,146cdf1f,3b8fdd8d,cd82a757,44152552,35de0cae,c39e20e5,f82c7b6a,2afde8f4,1c6afab6) +,S(b1e2b9d6,4c14d667,4de9a6a7,5499cfb,12b30a92,b9bf7578,f8fdbb55,b6d414de,1e91c321,24341a58,e2c6d65f,18f3f735,f9f98d2d,76d124a2,c694db84,37cd0483) +,S(5092db9e,5bde4edd,f385c67f,357e43a7,c8fc8e09,f5c07c14,25bb405b,7e52d1fb,cbad30f3,f96767f9,553c9be3,2adbae2e,1f27f9d5,3fbb2f99,a361056c,ddf52858) +,S(59d39b90,2143ace3,3a1a1e54,a5cd83e9,6cf56f65,4a91f524,af8c8e19,e25496a5,be21c89c,baaffe09,4f2114be,72ff26a8,22db9a1b,818d96a2,bafa797a,3af056a5) +,S(89cc95d8,cf45bab6,9b3f86f7,9e1fa71a,34fa83cd,3d4dfd16,1c9df1b5,817edc16,5eff0aef,63fc853a,f8b65e8,8a45740e,6c78aade,4bcfeca4,c7413ad6,714eef84) +,S(6c2b8809,79398e60,87c756c,443fb032,f2adf5f0,17bf9ac6,44d164b7,d2aeed3f,bc46cb71,c9ed9f46,b34a22cc,e1332cbd,44318165,85407951,580e4b26,270f3eca) +,S(767ca583,c950f7bb,e3aaa6db,b6aa9867,792e0b8a,6930ab97,5c46d09c,30e14a6e,bb90634f,87133104,1c7eeaa0,4a09887a,e5946daf,e88828a,68761cb6,21412d49) +,S(cf742ea0,35c4d9a6,40fd0686,a460ab96,e2015d0,2c15fc8f,333ecb7b,8af4b08d,2bb94f28,bd69b51e,de993065,fd61fbad,c65fc62,90059a8b,d29948da,20b704e5) +,S(84d5d76a,a5a6ec84,52f024ea,b365290d,9c3b6be8,f33a93ea,b0a0ac4e,e6271059,f5565742,f1a47a88,8d0bb802,b002ea6e,f5acea8,864e2f64,fbfb1565,dda51952) +,S(8f5752a,8fbdc1a6,201b6e0b,7bd5db3,cda2eafe,f18cd6d,559724b9,56767d32,d63c0fad,de72b753,6d0c8606,88e0a82b,9f9e35d4,b1db7be7,efa9040b,82298008) +,S(20578def,f94e3597,50ee95bc,61ca76db,f8fc059f,e25e42c5,bf887d49,665d1871,5fc52a36,c95c6edf,46bd5c38,60e151b3,9f123e9b,c58b2079,cd165c1d,e6f33d3c) +,S(30f2b825,739fdf4c,5af0ca08,47f50323,d3ad6eb0,413b052e,525f837c,38f97a4e,d698b076,4417357c,a49b4306,7d73206f,d3d97036,26ab15d4,f11c56bf,4bc820ff) +,S(2350eca0,b4d0c460,12024be,6d458444,b37b20cb,50042830,182b5e41,d564e26b,5909eee2,e3999d60,4cbe0832,58012001,30a344c5,f72ff127,35e66cdd,904623d7) +,S(ea660cfc,45971e57,852d382a,ae8cc6b,1887fe68,dc1b84bf,31f4409,89f89b2d,52297e86,dfec0730,81a280f,9451623f,9e69c320,6f3c205a,f07e56a2,54cd5837) +,S(9cded450,2a7da3bb,77e06ae3,ef398954,7687d21e,df522f3a,cb6b4fd9,d3d49beb,7b13f455,35a49049,277abc34,3cc6f0a,336242e8,7b69815a,e27122e1,d7838a8) +,S(ac8705f2,cf8dcd77,d409a962,f98a6abf,198dd238,3a5eb258,6b0d2def,81daa172,892fa835,a0af6cf9,dd5bf158,44b22cf8,2af258c0,519955dc,ee4966c7,bd5e995c) +,S(fa026b1b,d5e5fe3c,d6b144bc,6b22f7e7,5512ca6c,9525f62,fc7fb4ea,bcd2282c,4ec40de5,7ffc1768,edb20cae,d3a11380,fcc32f45,f410ad9b,8b674d95,6614aad0) +,S(a928eb73,28285c79,5717dc0b,ccb5280f,92f9a4be,5a0b0ed7,67e58eaa,8b9097db,af57cb66,61a9d08f,4d4e9e25,aeeea2dd,e4c88767,c4e177b,37a87ba4,c2bb772e) +,S(bfc9197f,80fded3,c601a0f,1c8c1d77,cbccaab,1c8357ee,4fb67875,cbbc8261,6a721e0,241ef436,69cd386b,d07fa2e8,900527eb,ec3c0025,24bb457e,1bc7aa28) +,S(ae0de043,b332bb4f,91395870,4f3a41f,65e0f3d9,ff77c1d5,ec3add49,6087d5db,34d697f5,dbef1bdb,f581127d,bcd2755,a5a6b32d,73164665,ef84f6bc,145c2afd) +,S(4433db73,29d75b3f,7df0e229,538b7a33,e41183ad,7a7a5e3e,ccf5863d,6bbb692c,3a66630,a03ab85,9f23ae3c,a0a38717,d82ac240,d271b3a6,ccde1407,d0dfdfa1) +,S(bc7380bb,128a6f8a,5cdb971c,31ad12e2,ba593acf,718f5468,285b7f14,69ca2b90,a17af518,9a7b0445,cb37e797,a281c84f,8cf8ecaf,c661e601,4ecc2467,18f1d8e4) +,S(bb53297b,18d2d785,a4756437,70b387d3,ab0fe62,8b78c09f,bb6cc226,79bc92ab,5c34b9b7,cfb3737,bb515ee8,fcff8592,1fe8f30c,e97d21b7,47a4b084,22b0c811) +,S(1accc1c3,f46945d5,7b46b1fa,15291ae4,2f0a616f,df23f1c3,3f0dcf97,53851fb6,bb434ef5,e30fb9fc,15e99b15,b5f9d766,9681be30,d2b0a6f5,a4946268,158d5369) +,S(2fd61a9a,b99c588d,fbe74fde,e8ce95cd,1c0ee9a6,da7ae59,910485bb,9a3ed9c6,2c214840,e2bd764f,74f9db81,43ddd549,3d322dd2,b25790a8,a681c97e,2fda07c3) +,S(4bfd09f1,4cb492a5,7b9ef3ca,d245a0ab,c4bd97ef,12bf7204,8ecfee47,660f7161,57102f3a,ecc42742,657032bd,aa36526c,e67f2589,2775fdb7,e8b029d8,1cc7ec9c) +,S(f60eb13a,8e6485ea,fe653e74,de1c1376,2df7ba0d,4ff0c65f,24bb1c0d,74cea3fe,c5830078,5b74cc82,80128896,f275fca4,9be94edc,744f8535,128ba7a0,5c1d9552) +,S(2b4c7864,9f568eb1,ce1be63d,aaaba4e9,7c31349f,aa353371,6e9123f6,4c57b041,b5dc9c1a,b39325f9,3ead6f35,66c30479,5f817ca1,b3c37258,554c4fb2,51a0ca39) +,S(7fb057e8,5f559f11,b5d41538,6a25a77a,aeb904c5,d1be33cc,bece20ad,57715ac4,2352db61,6fad3f10,a2decdef,5a7fc369,5c8462b3,7d2d5ae8,bde17311,ac6b4ad3) +,S(a49bc870,bfd62cf1,1dd1bd23,9499157d,247ac61a,a9b34210,65d4d029,56f71a0a,b639709,88ffd1ae,ed1b62b1,83ba629e,f5f0c088,f8a9016,d7fa9157,46642e3b) +,S(30b1f21,f8dd3f40,697878a9,fa0b9fbe,d51c1ddd,165bd5f,ed9d1fd6,49ae913f,d5a55164,4628de36,25895fa1,471e0f5,77326d14,132d8ffa,37e0277d,a928532) +,S(8a015768,8aefcd7d,13cb3b98,373a8823,aad11a4e,718a6ea8,5fdb8a9a,6edfd879,e7d92909,4d198910,44c00be,69f267f3,84aca1db,642648d8,34a5b9fe,518e1363) +,S(810ee87e,45d8a5ee,c0e3fd0a,cb771d2a,5a3116be,f4dd7d5f,bfac0dd9,fe072778,92abfc24,9500ba0a,9cfa1725,da4c37b6,cf081f5c,c6cb6a8a,3af889ab,ddd2b7f1) +,S(a0eaaed7,687f6a94,398656fb,3fb15f49,6522c3dc,c19e04b4,598ac4a5,6408d1d9,792a67cd,677ae878,eae040e1,6378cc36,9583b513,bca68fa1,cca3cbdc,37aa61d5) +,S(ca438737,ffa6f30d,9aa695fb,3d29db01,f805f480,ddf1b227,3a0515b9,5f8eba97,56238731,ff5314f4,af6a3835,b30ae83d,feaf0db,dd4449e0,5736efba,8a8cd51b) +,S(b252f5e5,4b67554c,ba3d481d,66a2f223,a633b5e7,f335e357,29928264,e744279c,c6296730,5007e2c9,3fbdb25d,a33a9fa7,411218c2,87b937c5,dfcf8f45,472533a0) +,S(f61b57a2,237befe8,2f1545cb,131acb03,3015a5ee,f0cb77d8,c73add0d,ec0083f7,9b1e0c93,b326a265,eabf096f,f8eedfd5,9f765b51,5007c5cc,d0d3b569,838f381) +,S(30df434c,1051cc43,4ca35671,3957f964,af406830,38ce82a9,5cdf2c7b,55c50f7c,883bc89b,f54c490b,3be0d434,fffb6b,7e829be1,55280401,eaf44bee,7c445424) +,S(fd0ab148,727eb712,adee1fe3,4e3d0fe4,99bf8307,fbe18e4e,d20d5236,f7ac25e7,f5f38f32,df094903,b3219b02,8413cfc0,e56b8ed5,6ad80e5b,aaa00f4e,3877377c) +,S(b4a8fcf2,b406becb,6111c030,ae375f12,79de175,7f2f3b90,13e7ac55,12de747f,d1634039,59a6600a,fa05b1cc,3c459fa4,f1a5fd4c,27ee5382,c5f01e4d,a0259889) +,S(a6c10f0b,33d1518c,8f8b7055,b139aa84,c96e9998,8e8a256c,5883bb44,10687c72,8f0dfa52,ccaec6c6,789941f3,cab90b55,4d4f587f,bb6f3354,b5f7158c,758e4f9b) +,S(7188fb46,e244a5a2,6e38cf13,bf2e3c4a,ff5bdcdf,8d9f78ae,88213692,d866f5c9,8cb07d12,ec743540,3be09b19,4cfb2f1f,c4a85d27,d940cad1,15ab53ea,4b8e0d88) +,S(fe4f9f00,308670fc,48e45208,4063fa94,a6cf7141,d75a6ef7,4f92b474,5bf692ea,5dc45ab4,77f80594,4355698b,e95bc582,efea563a,970217e5,2bd28ede,d7e8cbdd) +,S(93f3b5df,43006183,47c7bc14,3eb046a3,842614ad,78d3cfc9,a6b665e,3327b7cd,ffe5f378,7ac36947,d635d156,7a28fa5d,45c0b5e1,70508cc2,7fd621b4,47b63b53) +,S(dd350a89,e0c3128b,54a3955c,bf802ff7,3a565760,39e1e068,e783ad00,36c13604,45cdb508,3c33c35,fcdbb29a,efddcc63,c4cf3fe7,c08a15d,8b2cd4ae,dec2c3e9) +,S(4f164801,17c1d338,7738b728,96442b9d,66f44eec,e3eeb7ff,ffa87d24,4226e44f,750e6348,490d0ecd,3be07303,5a8e653c,1b1f7c30,d89e27dd,4efedc9d,755b89ee) +,S(b7c62749,aaf79754,de281314,acb4b2f0,271f2a35,fd187307,20349a3c,a4b577a3,f100956e,ddc307db,56542c1,d2c8f176,e0636ba,b04877cf,3dad451d,edcb0df4) +,S(fa5c1278,1dd929a0,2ae4755c,70531cd6,c309261,36ef51ed,7d57c117,c1c8a885,57c5280a,5f08f0c9,393aab6f,eba0ae81,a32f8c6e,2a76c780,a871170a,e37856f4) +,S(e16d6dee,7830b0d,e6cc5e4,9b1cfb7b,50b7d89,57fa4e6c,42ce9925,2e6a29b6,cd5955da,4c1ba840,a3c98d1,7dea8d8c,f4a3d2c0,1e0cf164,2cdc35ee,87fea835) +,S(a2c659f0,a0ef6147,ba84ff26,ca81443c,ac8ba9be,f6fb32f9,50653384,a5db0213,5176a4b1,88b5bbef,3680e875,437e4209,d2fd2462,77c5f84,4a0eaf5,e9d8c129) +,S(7d507179,6a7c037,77fcf84e,62e6eac5,456f88fe,76e71301,76fe458c,8f301a68,14018264,59d3f62,6788fba3,1505c83a,4161674,21dbc2a9,dc14e1a,f45a50a8) +,S(642721c9,20d9b3e6,72db8d82,34ad60f4,bc74684f,11f2ef1a,8171d02e,b9eb1f12,fdde8b98,8aac7393,be2366b5,6e853c7,b72034fb,2cb176ee,770063dc,42b63d48) +,S(65fc35bd,2f604eae,48a1b68e,1d66cac3,627b1498,247d8376,47082702,293c97d,d01018e4,85dba402,17ac631a,9b88d240,de32ac74,79c7d47a,9f5d9188,f8ac01d7) +,S(65c8b230,2e51129a,b81de5f5,22217f06,f5d5360f,af191c56,8f395a33,2b04375a,3201b7ec,117fceb2,b225f137,877ef481,2be4d6b4,52d1c855,f73adb0f,e99b2943) +,S(b82aa6a2,86fb19a,d2eeaac8,9019782b,d0d6009a,8fa07a02,a0d6295,ea8637f0,426f8d72,ec1b08d2,72671566,1f77f470,f334e4fd,3370d96f,b0acca8f,2df99398) +,S(a3222e7a,c6c27f2,8b24b33d,ac78d873,1ce060dc,be055100,862e71dc,e6671a18,6f2c2a1c,4b80534f,8ea53777,71760fb6,5148d47e,ca097fd2,b7bb2f53,bb07ce22) +,S(281ffed7,48a4022b,c663d08b,5681733d,f1343818,d68c8b63,9f4405db,ad7020e2,b5f18609,d8e5c6e7,990808ec,b4fa7d2d,7d4cd106,b7ad2c6a,e356f239,9a535eea) +,S(c520ea8b,a481c220,bab0f218,72ccfcd5,d7014d8c,fe55d1ef,743af305,c0277d5e,e23eaf34,33e4369f,30d371d6,e396b0dc,a065506a,c4159967,fec4475c,8f6bf78b) +,S(54d39ed1,114ec02d,8005d7a0,82178175,78f827c2,1b55a95f,330a7af9,34727958,4aecf190,229c49c9,31862a57,9131aeed,5518cda9,4695e8ac,7ebf7667,d9afb23e) +,S(756b9bf0,1da8d7f6,1627cb2c,b3ce3ba,a9b6450,c2d24596,feae8bd1,2ef67a23,51c47b15,b2ac96c3,5d7b7dc2,d8c57ee9,69b347ff,dadb04e9,cbfd6889,a0ef70b7) +,S(eef22145,6ff200f,ddced960,f422588e,333a437e,d68c04ca,9758d77e,a938ac54,21587cf5,8b8ffb72,6d29aed2,3c984a4f,25df40b0,abc9b7cf,2c07436,ab7e09e2) +,S(b841b560,c0af44a,35bc9320,3c05cb32,250fcca3,f83dafe,30d1dbe6,61aa3d1,e7956525,3d07a89b,2335e2ce,9e11fb89,96e2c146,271189b3,461cf944,2ceee2d7) +,S(14b98f62,5849b798,48f32547,efccc33c,3ead6cd1,a290f03e,618acc2c,1ce065e1,4e7a2415,805a4486,476221f1,ce8234e6,5b81ee60,e1ce5eb6,b6a2e041,ac885e00) +,S(fb0aafb7,68c19f64,17e417b6,f1c22dfc,737bc74,fe8b23e7,4dc1c1c9,aad7ae44,88b83e23,631c58d,c3729cf5,54343721,e9ec7dc4,a889b85e,31cb302f,f2a6ab3b) +,S(885497ab,e34d1745,a3e2ff8b,bdea904,eeacf100,324540c6,86de137a,9756468f,63f3f160,bd266c3a,7c49b13f,c5b06403,d0614b79,17c49824,bf507257,2ac0b948) +,S(52dc7bd7,17e4d8e,8b634439,f6f06b8f,7121a0e0,cfebe7a8,3031668b,9832b8b3,90679373,9bbce1e3,5c48f41e,942d9f15,9161e9ab,273a2217,d9e857c4,3bdd0a5c) +,S(e6ed2c69,a8bd7af3,35591f4e,4dfba7ac,d82e87ee,e2b3bd28,f0f87f02,3abaa7c0,dfec6118,7396bd5,e32ba2e7,a8fc912f,1e54e078,6f2ee222,35adcd22,8feca28) +,S(9e2171a2,c1025129,1757e26f,ba979e5d,6b68c2b4,975c7289,2afe7898,cafc46eb,3dd062bd,210bfc4d,d30cf01c,51d810b5,cf1b8ee3,d3baf490,6bf5d381,b87c9a56) +,S(ef4b8648,3bf209f3,b1c2e166,a32cda39,44b21282,db8acb94,6ef62122,63bc44cb,903d1088,ccc0ba47,b5ac3252,33ef9b55,924e61ba,7ca80bd8,1925b269,3998920b) +,S(64ec6d14,7ecb6e44,6331907b,b9006b2b,fa4fb854,20ab9aba,f1026bc3,4ccdc4b5,583cad3,b41bbfec,d0817207,dd312cdc,26c0411,b888ce5c,c6ee025,baafac63) +,S(128cb9de,125429dd,e5b9b33c,ef9f34a3,e7b38ba,f22dbcdf,8e169894,3f7ae5a9,a10a01dd,33f5a4eb,66091348,c4dbd90d,62879ff6,7559229a,e53c2896,8fb4584b) +,S(a7d2e7db,ca0890ee,e07c4bbb,399a0120,e71fc284,c5b7c96b,4889fbb6,db95dbbe,b8caef70,404a19dc,15670cae,b19d5b74,e70b7492,50390b12,5f559b11,feda83de) +,S(298b17c0,b8beadff,5e6eafb8,ad7d756,8e961468,d8e12c94,78ff3870,dc722450,a0542f35,c7b95774,b1c10f75,3e9da029,ec7a54a6,97bcd9fb,46c98d26,91ac1a43) +,S(31a39bcd,a3d10e9f,6b46e1e,c30b41aa,557ba664,9b12db64,a13557d7,5c592d1d,814f1a6,15382d4,e57b8d41,351fd782,ce7dd9d7,86aa9bbb,c5b1ca7c,207ab12a) +,S(3317f1a8,1afa54f6,ffa6df13,bd3f818d,e9a29bed,7c119b6d,fa31560d,31d81cfd,aa8eb746,4e9acaea,19a42509,a23a281c,e9917788,6d3de977,4398c57,8867e095) +,S(85511857,80eab56a,274cad22,966ca547,3027d3c,3cdd7e25,7d8ed8cd,a5c6ef30,b13de0f4,45d71bd7,db0327eb,15438e9e,84fefc1a,464d8a2b,bcb8c6b9,f59f93dd) +,S(fdbffe5,7e378262,c32bc4b1,e84ae01e,a2d6dd76,28e10b04,9adf6a3e,ef106e83,f19d0c4f,1411ba50,35d3ef23,153f306f,d40b22c6,69e92ea9,22bd7d5f,83a98ad) +,S(7562779e,6aae0c51,52acc7ee,43bed76c,831ba008,82d89c9c,e29a5f3b,8855b3c8,c83c1662,7cb9e1d9,126e07b3,354b82a8,a0cd49eb,3936c14a,8d8d64ed,2a4e217e) +,S(130b292c,10d5b336,4635d43a,fb6d6e02,d5acec2,c2033525,ed72c030,e82a4a08,d534b710,e1201276,6f6fce50,ed6efec7,3e0c3e75,50e0bf36,d5d625b5,4855fed5) +,S(19fecb77,bcfc0db3,e595fe22,e96f1212,b3ed032d,183be5e0,ed4c1b8b,d0501bb3,6b0fafde,2f0636e7,2b4ea946,a0e5c27e,4e5dfb5f,e8b8a1d1,b36bdee5,75d02e81) +,S(ffc668c7,9c6f9fd2,f5c56104,aac1286f,cd4a390d,ca586af2,c348458f,b4130f77,fd7b748,d15f10b6,4eaf4946,34fb4ddc,439919a1,1155e40f,24f3eb2f,482445f4) +,S(b9797c7b,d4112aa4,8abbc827,fae12fd9,6d19f3c7,81626e21,5c26ddcd,b2d4552,ddb0aa81,3113288f,1fd2505b,d23f2a9b,a1ba0a38,dcbbfbcb,46da78bc,5c705327) +,S(9388c9f6,5bda9c81,62ec04ec,5345ff80,da4afe34,7281f768,4d8daa1c,cc3d7869,23ef5140,3f926d0a,d2ebbe6e,48858850,aa98149c,89490e99,65dafeb3,c82644fb) +,S(44cf864,6c2d2f30,e62f63fd,8e145786,80c1d5b8,a27fd496,a8e34bab,5f88270,9784e329,a434b442,fef9af66,b23ea917,edc0f6ca,8d28a992,bf6944ff,26c5cd25) +,S(ebe08589,930001bd,ecb83ca4,45c4a9fb,fd61b229,60ba9848,2e0fd520,1af5a0a9,ce2d31fe,3c271048,24ed891a,910e2cd2,2b99b39b,480ad812,a5d6860f,71ec817d) +,S(176d14f2,5491c2f1,c1d4fc87,a8f59aef,f560bbd9,41872f6f,2a1a6adc,7620f1d7,42c1e0f3,8a3379b0,c5de8a01,11b846b4,35db7783,caa9b84,8084a985,f0e123a4) +,S(74e96d3a,972baa6f,8ad6876c,9494f451,a12adecb,681c4d55,57eb58a6,de920fc0,c2cd92a9,994ad5,f4700561,e8b57201,96e61a5e,b4cb4a55,66959bf1,35a07f83) +,S(6751dff8,5079fa45,7f5df468,624c4a85,db970586,889cd80f,d4514bbe,8de42d60,7cc20505,deeb3f91,3d78a265,cb301c68,49cd5a53,dc029af5,c0db1876,762ba3b0) +,S(f9c63056,24d8cffd,abce64ac,65dd3a09,ebd344a5,5404d08f,b4140a4d,8489628d,49ad5449,bf1b6def,74283afd,2f315f77,3de82cda,d4c9de21,7995a2ff,c44e934e) +,S(69e8c4f7,3f757235,d0e4f39a,f2595cde,f7ff4d20,dd2d45c9,78f32d19,921b6672,8ffc35fd,8a6d541b,3f7135f5,643efb00,14f275ba,d929671,df610748,6f763f55) +,S(3d03e571,ed2aa88a,3309f014,caddfd64,26ae84a2,a526fe35,f30ceb8a,4e645e22,db95c744,6bf115d9,4af9074a,6b274725,adbcbfa6,77f9ce48,535003ad,dd37bc6a) +,S(e5b764c3,dc73619e,51a2afa,fb2292ad,db2b7b0d,e12b46b7,f14b66ce,f8aea7bc,41fbe1bf,41838b6e,9a57fcbc,b3e2e3c8,60170122,29a5ffe1,7394139f,5e8edf2c) +,S(adabcca6,b4252849,76596462,36b17b0f,9d1b4e9d,279af84a,c02f556c,e0f4c385,7d12959,9b411665,dd23b676,57229f84,ae46773a,e13284ab,1cb608d2,ccedafd5) +,S(963094f7,7ea2a7d0,3115e201,45dc6f6a,7318f8b9,a55ab015,8096db54,48e341e7,36bb26ce,3852ba30,dcb1a8ee,ec834f4d,d5342ab9,f7bbe85d,7addce07,62cb22aa) +,S(30ca6324,b4f34e1a,4c3dbe4f,d6dc6b13,a8ebcb35,2f632fc1,5725bff5,f260c508,5c04aa15,8dae7205,3bb608db,1b9245cf,fc57c10f,d015e80f,7afc7532,632eaaea) +,S(8356d1c4,55479df3,adbca347,fdb73f89,6027471b,e528da9a,d9e6a968,8dfba744,c325c86c,cd603953,8f610b03,21b6147a,371314cd,2c41df91,745e579d,8564a177) +,S(996ca7b0,4ae2dde7,b5ee87d8,c077bf97,9a63ce83,cfb84349,c7d231b3,1e15bfd7,cd1d1b48,d75f9736,68b91101,8ade913c,19a1d785,65adcf71,6c805863,fa6c1f17) +,S(8a15dbd3,5cc16f77,b22a87b4,4f93e5e5,810f0503,56e47d53,95769128,a2047738,cf96df1,9ecb6da4,3895641e,4fbd4f27,f00f58ce,cd34d38d,e258fa78,410a1f7f) +,S(23c1e11c,be9f6a93,6c5f8abb,6cc501a1,ca38b03e,f00b31a,79057156,f382ad7c,1d996782,9f709951,2c9728ac,68c16db,1889bcbb,7df432b7,f430ebe6,56b1e050) +,S(d937ad87,70737b1f,d52bfb7f,86e207f1,9e4bed5a,43b165fc,981685e6,24b8e84c,202913d6,1eb467fc,b488fffe,5914f853,73aaac20,1acde09,ef975cc8,a05fd181) +,S(6457f59b,2c744ca7,89537c59,6485abe9,7835368b,47de3667,4740ecff,72e5596d,30b6ffac,65e34e88,43681e64,f041870b,c85b3b5c,86c032b1,e290848d,ad2f7a5f) +,S(7101d56d,813abe1f,c50aa99a,bc7b2363,9532d79d,facc17c9,f2a5b4ff,50edf82e,62a0b9d2,bcab5b18,9075f6f0,e648a4f6,fa66741c,389a4196,a4c5ead7,cbef14d8) +,S(2dd4cb3e,5cb59cbe,b961af3f,d1154fbf,c21916f1,d5331ce4,c8a32ad6,8f7ad818,397dde68,7b1f6b5d,38e457ae,2f5fb332,74917949,801151e5,3d4fe19,9a34289a) +,S(509c6fcc,ae22b09d,b8f3d191,434e584c,9d17dc76,c268560f,2290d81d,53ed66dc,cbf69e20,c3f9ada3,41e32dfc,581f0ba,f015413d,735d33a6,260e0cfa,7a4e4d05) +,S(71babe5a,9458bf5e,112b23a5,3f87007b,66ddd721,32a45a34,2a9c521a,c2029aae,55ac872,a0275be6,4f569901,d84dca32,ea13e2c6,cbe608ac,de228185,34e031a3) +,S(f5f2144a,46fe975f,82b91da3,a98ebcb,6d5769a3,4e5fc50f,3ca640fa,152fa7fd,2fc05c22,2b20b895,5503f23e,627558b0,e023988d,f02993f8,f495750d,db6344fe) +,S(d6f274fa,fdfcf64,25972a56,640e53b8,15c4d213,8e4a72a0,b8ab3394,2955e416,738e267b,2fe0d9,5774afdc,7c4f559b,7bfe2824,ea6b7a49,d3220eb0,460ca733) +,S(81a12fcf,cc6acf7b,89f30fc,8f61e2cd,7882f664,55923993,2b8d3f9b,1d6e11e7,a8dbc6c1,cdca67b0,64b285c4,e2f69242,cf55f06c,5eb28868,d9bab656,eaf9116a) +,S(57019cc4,941f6f5,9ed34305,92f35a83,39a495ee,fb3e311a,fcef9001,cb8123be,a3d632f2,54083f5d,6f2857b6,9556205f,59578908,9d8d8fd2,4d10bf1a,e6d2e635) +,S(4205a71f,504362cd,576c4d84,c8b65252,3d4227fb,d6aa28a7,e7fc3d70,d1387c80,781bfe55,7fecdfff,c54d1c1f,e147792c,5ea7a1dd,7224954e,e110cc6e,18ab452b) +,S(1c42ad3d,f90472e9,e5c041da,52476ea0,896a2032,ccff22a8,fd7bbab1,4c3961f3,a5072a70,be702dae,f9f93148,4bdfaa00,1e2f2ad6,7d79f46b,5717147,17c5499c) +,S(6c9225cb,668ecf25,1f7862ad,999516c0,145faa37,b4fe92eb,561104f8,f1dc2997,8c12c1a1,e372baa1,4e9b1443,d3530548,d7d1d05b,fa354c7,f47ecab3,23993a31) +,S(72a0fd2d,eced2a05,6885dc81,fb61e881,b09104f3,8650a872,44e40471,ed189992,d9c67490,43bb493d,9aea4a1b,3a50da8a,e1c48523,9a480442,32406d2a,68487e6e) +,S(b1d531af,8faa24b5,69945ec8,1448915b,a46fd13a,f7fecb8e,16cd5d03,52c6c2ab,b3ba6cf4,bd36bee,66deba09,35bb85e0,b9ff7e62,5b5c793b,543a091b,dc83292b) +,S(da79daea,d6ea65e1,4e8747b8,b4546560,a9e5a99e,eb572f17,f2ebcf3f,9a307a86,f5b3c430,e0f2d4aa,2f278088,2d683c48,d84f926f,6feea88b,10e06930,6567a290) +,S(1fe7fb5c,99a69a75,a2276ca8,92f67da4,951bbb4f,ee4df8b4,a54c9833,d0d33869,e2b2b4c6,fe0f63f,d97fa179,331e9bb,55786006,f0425e98,71452aa8,361f177a) +,S(fcdb7de9,4eacf36a,9d662371,edd2b535,af33de37,1985ff49,6ce5293b,9d2ac00a,e332723c,7a9708e8,5172e56a,c4291760,baa17e83,72c98dbe,83a186de,77c2aa06) +,S(daeaa6cb,19bdb4b7,78077495,a9cead03,3be16d2,97e742c6,97ac18ed,e5b514c6,4545ca53,bde3c1ff,6bf32604,ef037da,93134215,7057ab10,cf6af451,e7753f4c) +,S(83e4b4c9,1a923321,196fffb9,b45d089e,7fa1f6b0,5ff45a6f,d099f7ec,fe283088,926c28cc,bf405fb1,17c5f168,20216226,4c89cda2,cf669937,2739ea05,279325d5) +,S(cd7f2b53,8363914b,2e83f1e1,c9bced9,32a682fa,cd72b46a,eda578c0,640089bc,ddf6dc27,a5281d3,b4d66af6,8fc80f5b,16cbb7b6,ebfff06c,6902d38d,4632ed2e) +,S(6f3f5a27,b19dbfc0,238bccc8,a9adcf95,adef6480,fd4ca405,454509b2,97a40928,36a56db2,abf62faa,b2255d86,d8a46aec,361fd2a8,65740c31,babb2e2,c551a85e) +,S(f7aa5c92,a523b86b,c27cf714,51f7dcec,fa18ef3a,9e839c41,a8b20c4e,30ba3b77,fa7d3ce9,8009f23d,f5eae927,acf1b28d,5ce4a2f8,8a92da7d,fcc1acb1,3c8cadc5) +,S(4adaaf95,5bfa6a94,b518f7f5,b0ebbdca,493798f6,72293e4b,36d5fdfd,5f641b89,ce675ffa,cff579c0,61e63c2f,36e77f3d,5c2571b3,aa99d3c2,74086b22,a862577c) +,S(2d737aac,3600371c,f6b638e8,8a29884c,978b783,cb843922,bd449e95,814db692,205d944f,13b21441,76d8276d,74da68e5,142aac9f,ba632568,79753c01,e54cf4f) +,S(7cb5d365,10ef241d,ac378fc,ebad8738,e8f2e6ad,6d838731,e5c82bb9,169d51d4,33b088df,5a572e8e,1010886a,d01b68f1,9f345770,81a465ba,8c5c784f,225f6510) +,S(9872a376,e530e254,8b623b6,b9dbd6d4,d123f2f7,30579f47,4d910831,7c714c0c,3de01ddb,3145d81e,6ac002ec,70086f74,6eb2bdee,6295f5fd,9d2cf8b6,1b222e58) +,S(8242fc8b,2e848618,ba0f26c2,6acac090,8eb21b4f,41a08b76,beb35f85,3b8c2f33,58b94d44,3379ea4f,829fc809,ce2632cd,78d8675e,45a29c58,e29fda43,785f2e9) +,S(88800a95,cf1682df,4e5bcde3,a96de21c,3353751c,5300dfa0,d0f802d6,7b60eeeb,2a35b86a,4e213e9e,c53dfe04,d91afb48,25bc8794,a1574ac4,53e81ff,4b6e453f) +,S(3c8e2755,9611937c,b7e2b2cf,8a87fa5a,e5c696df,fc6703b7,e1e65ac9,111ad87c,c54d129a,be0c774d,dd415707,bfabafdb,daedd1bb,2ea9cff3,bcfae0e4,55c916e) +,S(281af73e,a1f092c5,535557f9,3b5a8c94,54165f8,76650801,856bf926,19f06cb8,deaa8495,30951f12,ea157714,3caab5fd,d30f0dce,ac9b80bc,fcdb3477,dc01ea1c) +,S(6b353e5,3202f63c,69bce96,30535f11,1939fa,849dedb,92ad21c4,89f5174d,bd961eed,c16f285f,2eccfa69,d37a6d63,be5fad00,4858c80e,6fc4dfb4,2717acc4) +,S(68c184f1,a06685de,fd20f36c,82b5446,7446d5d9,8fc9c312,4852bb02,f35ed91d,486a3d16,7d94c66a,31f9e134,1652f658,76d49379,f3e3429f,e9f2da30,84f56532) +,S(5e884531,fa011576,3d36e1ad,74b22e23,f765db14,8b8e965c,80f7c9bb,7d561bf0,34c4f03,b137b627,3fbdb6e4,8ac09ef9,bc3c8ccc,e720853c,61ae58da,ee3a0cca) +,S(10c13f0f,313e5ad8,ea61ba5f,ed509aef,5ddd3016,c3339eec,ffc8f9d8,6f131118,28f6ad5b,324e44ae,64ee65c1,b86710a2,91a8e71,c33adbcf,a84f18fb,144dd67c) +,S(aa99d8b3,1031d4e9,8c078a68,7254968a,9141c710,cd8e4842,5a384bf8,414f5c5f,ee6eccfc,1dbdd5a,c9080cc1,ffedbc6e,64fcf847,ab9c0ce,fa91c4fe,d1de44bb) +,S(f087945d,a464e66c,4c73b58c,5034f057,b96ebe34,f5128397,cfadd7be,22ac6100,c5485411,d78fb395,3f229109,45aac354,1a2b2acd,1d95c38a,f51f36dc,d3cd92b2) +,S(2e4d8752,ac21c22f,e4d465e,3d2f5ad8,d9168080,b2b44930,e5de75a0,d9bf91ad,92f394c5,963c0817,500d5a98,2eccdeac,aa55043e,27a9a035,1a6ce245,a8d048bc) +,S(68b59755,44feb608,15a6ae70,9c2647b1,5c7fe073,aa6af8e6,202b9782,83daffac,b3745e92,fd86bfef,ab9d3d26,cdaf57c1,2a329889,cf646b6f,d6cf869a,f727e0c) +,S(15f5f668,e9576897,a287f131,bcbe1216,84f7a108,3c28c09a,afa77074,63dba49b,133e33fe,9bf06bb0,3b814938,7a099da4,77a3e758,82fb19a4,463ab360,bfbc368f) +,S(f2bf3cc8,ea752c11,db2ff594,d3f9b085,1dc9dff5,7999aa39,b5af2a29,30d50491,6e01a801,c5b7e4a0,a16af1ff,b011bc12,cb0483dc,6127fe52,c992b07a,9fd77635) +,S(1b04817f,46dae06c,120f8088,b3cd09e,267d4ed2,db14881b,bc32b5d6,345dc54e,31634e28,56f61b80,56a414e3,94a34ced,200bb172,e9a9aa07,6a224329,61f55ecb) +,S(693f066a,bca2046,ffb860f6,5e769ca2,3d1f46a3,6c09273d,afe5eb89,d2da45c5,719dd749,5c1b1938,a92af84d,eef309e6,ff1978b7,9adadb96,c58caf2b,625fff9) +,S(3fb25a02,bb232d18,c798f688,b16193ae,cb2eb9f5,e124c999,225f0720,63417008,90db4fbe,fdbf8a26,ff9b4afd,355e3771,c7c95891,68e2abea,264aba44,ad74707c) +,S(4c878f4e,6ebfed8e,e12a0a6d,17298b70,79d9de5c,6a7b5359,5ddefe4c,db82a79c,837592e6,927938cf,dc82252b,2cbfd9f6,cbff1950,405b4511,f2c21fdf,a3f72715) +,S(5ccaf6f4,2b75e152,49263cb9,5fdb34a8,770e8828,98a1a0cf,5407c48b,b9ad4ba0,70851419,379e5e2f,dca9613a,a9f92fd3,8ad8904e,e0ce0048,b2510943,ba8ee24) +,S(455907ae,713d1ec9,3792d488,7d9857bf,a02bc2ce,abd2c599,cf576f09,f7d09d11,1fc9ee5b,90a039f8,eb3200e2,ee58022,3f0cc699,60221d67,86f0deba,f13ca6b9) +,S(6f7acd2b,3683482f,c2c2d55b,eb62a89a,37578a34,417bcabf,ba7c56b7,bec14f0b,6049db59,b6210e55,b06401d6,17247d91,64e84e2c,b8de91a4,d4998c15,6f46d621) +,S(100f00d4,eee4ccf5,ea2558bf,92bec83b,223fa214,ad692ae3,b0a2ac93,c546d558,fe055fdc,1ae02552,1557db5b,96a62c92,556f918c,ca908708,46ffa1bc,8192b65e) +,S(8650c359,664c9f15,935dd776,bc6fbcc8,d9cb02d4,c22428e2,aee3e3cc,6e9d0c6f,89dba800,919866cc,8c16895f,785fc9cf,2661f78a,9e065472,652b71ce,d5ec8732) +,S(22b6df12,b3932756,713e2ee8,2d296c64,5d10364e,cca1ff94,9b477fa4,9a2ce5ac,ac58a22f,42769cf1,e2e23308,b3b5f139,4d329323,4bbd6053,4817ab5c,624e995b) +,S(ce87a23a,1554ae1b,9579ae96,863128cb,926a0cce,e51f17db,75155607,754b5992,4bb953b8,9d590216,e326f23e,66768c0d,17626262,6fecf80f,97435b50,d5dbd503) +,S(e3ae6365,29e3fe6b,cd1c89da,d72b17d4,8bf05c1b,c487ad41,d3b97838,a2cbc19c,4634e222,316b6ee6,c7616cfd,cddaee07,7fb2cd0d,26dd9f81,9d0ba43,313b3f4a) +,S(2825cc59,3a0678fb,e0d37d42,df72037b,6be96e98,18c52c49,fd426d75,324bd620,ea0079c9,2ef91a7c,dc587343,7b454763,f2fd4adf,561cd023,8379c8cb,1d281f6e) +,S(a6b2a170,fb23ae2f,943408ef,60fcb145,106735c,8876238,5d0fdd9b,75a2c46,1ab40091,e000012,60837529,58e3134,5f260890,d1bf6930,ddccedb1,dce20255) +,S(99a36f38,759f0a70,d719e3d5,b741a40f,daef1ad2,bcc65293,3992f134,39ff339f,a36d4b07,a7258053,61430332,6be79a,61ce8eb6,97944c6d,8bbf433b,a565bb66) +,S(e511e0a,de5a9be1,1b8513e,a5706258,6de09e2b,e2df739f,d647fd33,7890d36e,c6cc03ed,e9e50830,bd5579c5,9d6db693,dfa5c057,b1c214da,e4064804,9cd7ed70) +,S(bc9de66d,a406288c,a8a94e96,5ca16dfd,379608c2,63222a24,e3fc1116,20a82125,ac471a7e,579cfeaa,fdfdb5ff,9cccd4e,dca4202b,1b0149ab,ba9f6c09,aa219626) +,S(e98cd505,bd593bc1,496b1203,436f6038,ebe3fa4f,361ce4a6,54315402,a74c3a4c,1350c197,1c7979ca,7464c4d2,39b24a55,a1e50812,aaf92479,d566fffc,9135d977) +,S(47c0c788,2490ca53,37cc668c,5a549bde,dac661cc,f77534ed,d11f7ddc,9e0f37ac,ece10949,be122263,26819032,a2d952c3,60b27e2,7e527673,e8fcef08,a8f27685) +,S(e8224d65,35ea98a5,e3fd8833,7bd167cc,776f89ee,7d0ccfdc,46a15fed,93bee5e3,44b260e0,e0b1e1e9,383041cb,1dd985e7,22edb214,ae58f784,f174ba84,ef51c59e) +,S(c195ee35,5880dd77,67e01659,ecaf07b4,571e324b,b8a1a4fb,75265af2,3ea74709,95c39cef,f781f53f,31bde05b,d0289313,4e478b2d,1c55e741,aef8035a,2ecd4226) +,S(60d989b9,c9cccc66,139bbfed,e2902a95,fb9ca9a8,6c2e863f,21eceb4a,7d73c4bb,8295928a,a48ec1fb,775ea29d,9da1ceab,47e82f3f,1e6ef7fb,c7505e26,92bb51d8) +,S(a33b33f6,9db29609,8cfd34,caefd3e8,c3c0d863,ab695b06,b47d102e,f827fe62,669d9d96,842ee809,2cc31cfe,baab0f1f,4007c3e9,e7e41be3,7a08d221,1c6bc905) +,S(bd25afea,d9b8c833,fe332a2a,a9f3b627,d8328152,8fe1422c,5da90163,4b971584,35bb66e7,35326f67,63f4f38a,c18f8412,26da97da,c9e66902,f28904eb,b49cd78) +,S(4d7e208a,4264b565,d8563cd7,80773012,581e8688,a62921f2,d6a334c3,25625279,6729dd4f,b45ecd25,2c5cb033,dcb2f520,dc928ca5,71026fdd,b42943e8,b5da9988) +,S(5dd46f97,fc740db3,ec56348d,ed73fbbb,c440e3f3,33c64a3,a37b7a73,7f0e987d,7e2d9ee6,9e1c07a4,b764cac,aef3d780,e2d43288,2863f76e,35ff4cc6,832ede1a) +,S(4631992d,d72c02d2,2073222a,d35917f9,2770198b,ad13a847,8d3c9ca0,6ac91a3f,e28ce87b,35a69d5,c43b685a,e59d5f9d,ccf187bb,62517a92,90992b39,86d9e1eb) +,S(9153ad32,32177422,e03b6739,d5654209,7fe04d22,28b1e873,f02e990f,8936d1e3,8eb9f3c6,b54726b0,b4e867e0,5ab2fbca,e76d2e20,ce07983d,6edbd5fe,ebd0cc8d) +,S(939a7349,28fd798b,5036e2e9,60360387,b9c080a8,982d4530,78415667,848c2eff,30d2a2d9,5890d023,7d117cde,2eb3c532,e419770a,8783a7dc,dfe40674,709776f1) +,S(8e67bb29,9f11e01,b50be7fc,bee1f73a,5b335f5e,5ece8619,9a514156,dc243f3f,7fd0cb92,d6f9cd8f,bee9d337,90a4492,b8a7fa02,a0914c48,1f8becf5,d9a9d7da) +,S(a2cab3c2,537d8fec,b2f891a8,1da2f523,de4f869d,3c812806,855013c,73485ab2,765d058,c681af53,36ccbc8e,88d2391,b4894b18,15441342,4c4e73ac,1a8e0d71) +,S(9b39be40,976c13c2,faad320b,9338f985,b0718123,d2fb543,b65473a5,3bc2fce0,10f8234d,455fa7df,d09d76ee,41035515,9b560db,7b92988e,a42f9e9c,f7baabeb) +,S(35011530,6f2975be,73e7685,6456c94d,700e9b1c,4685639e,4f60efd6,9e513692,5992efac,9dcc0a58,ac6e00e3,54e44582,7e2d66c7,248e4b86,f8c216fe,a9e44270) +,S(df5a5b75,d96ddb93,9a341f58,7e1f997,3cb9e799,b04ccdfb,9907b57a,7b005d1f,3fd070b9,8d759043,8a53c302,b7ac0dbf,594094ad,7101d500,1cd5d687,e80066f0) +,S(91f14eda,a0db8441,10fa531e,eac54762,d52ca420,bb872327,6b383587,d40fa761,86cbd213,358d1f70,c3f6ac7e,913daf0a,47a80f8c,bd72445d,fcbef37,d0d71e69) +,S(53ddba06,46853311,9fe95719,15a9efe0,bc7fcf80,59d638e0,be6c1aa4,c5f21ffb,e59de2f6,5e583ab,5ac86c77,fc298301,70a18b68,a1979074,c21c0d8e,4a562567) +,S(56599462,4ad07c16,607afcd,76e86218,b15b50b6,9df84695,e60a15f0,3d7bcc49,c6d36636,ef58556f,9b688db0,eecb6bd4,5a7b30e,a9748732,68be57d8,542c966a) +,S(76fd5413,fdee9cb9,7f92fefa,5efa27e9,9aab744,e1e15029,241e35bc,743307a3,bb23f425,9aeb64e3,8ae82c3,b4691bf9,3b4a719e,a8ce076b,d0345a2f,d02a6d05) +,S(511ff159,2127502d,7499b988,7a3b3bd6,1242518,58bb62e3,dc1638be,89204a0e,21da5ba4,34b7819e,53b51e46,29f5fb77,e739ae5,97af55fa,aa09500a,dbd502f6) +,S(8e948cec,51635ab9,5a057404,39ff17c5,ae2e05e4,523bf2a2,3df28fd9,86de6b15,e16aa2ac,6c3d34b,9535b795,29a82b67,34bfa260,4a74ebe8,86110d73,ba564375) +,S(ebda8670,9277fecf,9b8507d9,40da6c74,210c8c7e,ddcff0d6,e3b52ded,3bf57095,3ca95e8e,112c8137,fe8c5088,bf041674,fb657260,70625890,1fdc5626,7655d654) +,S(eb5ffc4f,559f7ad,2469f48,1c730925,1ebf3863,357dbe72,41a29205,5b667682,b1f72d74,a5a16ef1,d55804ce,76974f46,61a49210,8a1a36f8,a59484da,a9bcbb96) +,S(2a93ae8a,d15c82ed,19fd2161,4a7a65a4,cf562432,623bf7f8,6c765548,b02fb57,5a949ca6,60a1430,9d4baa6,9be69b34,848e9874,62471d74,54c4817b,336584e0) +,S(9ac4a3e9,f1c8d115,138bd299,b6fb9132,c5d64a92,1fd94adc,82eb4ae,fa64704e,47f0eecf,a9eea827,ff339f3,48e67e8f,da9f00e1,a6b9086b,6f5441c3,7ae1d335) +,S(add254af,39d99d6d,355510d7,4f8985ad,3d8ec1e0,1e8d0210,27e80049,f555d65f,5b147a1,fc4bdeae,6c2f1224,b35e9e61,ad0799db,53597ef2,a23a8f3a,344dc526) +,S(d374d326,52cd006e,3b27b8d0,3ab47d44,bfb1c5d4,48adc992,5f63235b,c34aa128,3cc6ee09,c04d4cb0,aae8b1e6,6018640e,d0964fb7,148181ab,e9fd0374,642ad9a3) +,S(fa7632b4,78e5389d,cbf380d,8efbf6b1,d4bef9a1,70aa3517,e4c2005a,71a283f,ef2bcbb0,4b20be5,d4bda0f4,26dd0baa,31037d2b,7b530e2c,24105c3d,c817ce89) +,S(68ea197e,76af6950,1633ff9e,c825a817,80c7405d,ba513f96,6106632f,ea73ede5,633a5f90,587d4ea1,72129820,2ccefb30,c14a052a,6c0ca723,65e2f91d,53b3ff4) +,S(8874397e,1813f0c7,6946a84f,b05a0f44,224bb110,8aee722e,736e807b,b045b73a,ced2e2ec,85ae00e0,2952f55d,3626b613,641d2a8e,84b4c9ae,36177bb6,9ef80d9e) +,S(2ffe42bd,89256069,2e460701,b94208d4,85915043,8a85f71f,32246b8,5dea7594,6e7e4050,a35f1570,f8cc40c0,862e9cb5,59e744bd,8788646e,b0dad904,8b2777d8) +,S(c6d3a6f8,c997cfe,779a9a30,79de4bae,c19c226a,21f166d2,71ab4da2,cbc6defe,a8f8a618,3f6c8b2b,1486e60c,337725c9,9a9adc07,7dbb6581,e5b0119e,ca10f418) +,S(9b51cd75,442203ca,c4b8aba6,e9829b73,abe29f96,92b8dee8,500e1a90,9ea9767f,ed0ee32d,6042b6dc,dc818dbb,8cb00619,6bfeb2d7,88f35626,789cabb6,5d159c51) +,S(952c518f,775c8bc4,dbd7629c,8dcf8807,1b208033,8aee2ffa,eabad5d0,be6eaa1d,8a3b10a3,d9343d39,e7bef8c1,193f5cbd,717efa3b,cd2491f0,2dc1aa17,2e5b629b) +,S(49a18372,63eb11af,77a2e33d,2743393a,7eb269aa,f64589fc,8f81507e,55e8ee4d,7feb4a59,64b781b9,640d60f9,4e7eb291,6025d190,95945aab,7ac7771b,6f96cff8) +,S(cf974d8f,46aceb5e,a8c04e55,703b5a43,ac577e84,cb174abd,88198e1c,12708c9d,c50cf6d2,afd79d3,ce275e91,26bdaf0c,f46c1eb,536d0753,9dcf6c2d,d79afc35) +,S(461a831e,8beb6da0,df92dcdf,2697d551,cbf8f903,138d13f2,ec9b7fa,4a7d4763,e5fd85fa,c251705c,27d4e870,64af33b2,ff99b19,14496d96,6fa18916,faf40e01) +,S(eef4eb8a,9eba3f2e,b27e3aca,6cce7335,49f2656a,c26f1921,60c05bb8,fc3f1165,58f74526,a812ddc3,713217f6,fa4be02b,7062d042,2dbf5625,abd1f422,58b54c36) +,S(d674ace8,a7e8ae,d4bd4b7f,235b9f4c,41ef4355,4d9e6e44,3b6a26a2,d16f798f,8a25a7f7,896c0dd9,b1639f99,5c4b3df1,a3536104,b7d59348,c2c56c0b,bb21c609) +,S(a8eb465a,8a2869cd,6419af81,b3ad1355,1508727c,2b2494a4,93b5ffe6,2c1375,f1a27219,f59f29c,bb93bdc0,6157618a,454075ab,b95184e6,a4601ef4,eb2c8a1f) +,S(ccbd9d,6253fae3,f7d2527b,17854e21,58581e95,11a1f11b,55e3e04e,7326e6db,51ddefc2,5d9083ce,e9999e91,cde32f70,344ec937,d6aa5272,3dd62496,c4b0485b) +,S(524bc1e1,5c75e8f0,6718d2c6,da0f6599,c8b5d83,7cb9b48d,615e8e46,49dc6659,f6c91d14,72a50c31,1bb202b2,3d76f224,b55af957,c7bf3c19,69d175a1,d36ed19) +,S(520e667b,a0604a23,dde663ea,1a29971e,7e753301,9b2217af,296b02f9,de1df35d,9c2a2c52,290b6927,ac566ea8,4caa31ef,cb19b65f,29b4833f,5f4eae8c,f12b38bc) +,S(156282cc,65317dc1,3323aae2,d5d83e8,b7113d59,a50e54d8,dc54c1a1,ffc85d23,840cca23,67da3c5a,15b6427,72f0cd7e,675bb8b7,fb5dd58e,8cda9fcf,cb21606c) +,S(15afddb0,5adcc8d8,f1322a7d,f451fee9,873d4b8b,78b0c1e8,1d99f002,84aca6a,15465563,a129272c,b5e25bc3,ac76c52e,b4e115b7,b216a40c,145c4699,175cec9b) +,S(9eec4fea,e9508445,4bd275e3,f8d0d6d2,9040ae95,c8268f55,918d5f3f,2f75865,b7a873a7,5fb4ef70,3d62a723,81df2ded,102726ac,81685725,424a7733,8307ed7d) +,S(3aa7be96,660652c4,de1c82f5,cce1a864,c37725ba,848180bd,52e4dead,1a33f60c,f323d266,3e5d14dd,18fbab76,271f6c8f,32d7de0a,42724fde,f6ed3582,c886c402) +,S(bae9e070,a8e5a976,8347368,c32b4287,c7a6a20c,b491bebe,fc6acc71,aeeecea7,b5791703,f98ae848,1a9c66ab,878f7c27,d37a3e0,133b4e36,82ccb2af,b518e8ef) +,S(7b12ed88,be061d1f,7dab874b,17602bb0,ef5ccefa,54f9ff40,e753312c,335f5f86,70930f8,c465292b,b02ded5,59a235e6,c4c83480,9eb94442,8440846c,377498d6) +,S(9eb22b3c,8faad620,ba002990,4a5d8d1e,8cb4a054,179e3310,73f4ae8c,def4e1f7,6d58b972,ee88dfd9,4e429a2,4f6961a7,d085f00e,8d6f8d14,ff2066e7,df68bc34) +,S(bb2aa6cc,d8402cb8,e7a9a6f,a755c66,366c659e,bd2e5c85,7fa486e8,aa86b857,443e7128,674c040c,b0316d9b,3908bcd3,298e727c,c805bc8e,ca58894a,d51f4130) +,S(c58704a9,fc3bb18b,c460c4e1,f17a880e,c0dce45b,e2caf759,72f55061,d59d30d9,75216472,aee1c9c,280aef07,7208fe42,136b495c,f80d8a79,e8309272,c6c4d6a7) +,S(b7d7c721,70af0b6a,489c41a6,e817da2b,ce59f30c,88a82b11,83a6af8b,174c70eb,59481a78,52f3726,3a02ef48,dfb366ce,7bf170b0,af3c2000,2c1053e6,5dae1ef8) +,S(b1386833,25f5450b,f4f68dc9,93d72fa1,1e636a3e,8b881ac2,f237cc44,42f3461,64d18f1b,87f9463,10627931,cb003c09,981c4a94,969a0df1,7f717830,4daa6cd6) +,S(7e27af99,500cb8d4,d812a82d,29ca369,5e543231,8432c9f5,96f5b76d,c6d1bd8c,25a477c5,a275daad,10973822,40961da7,5385a367,6dff887c,42bd904d,8e885997) +,S(62e04f6f,d953c744,aeca984c,bad13c91,f4e09c1a,d5441603,2bfbc277,5ebbfdc1,4f1f609,db0befd5,fe781afa,d21efe44,846f9f78,9ed9f99d,f3291eec,3cf3fc89) +,S(b08a1f84,a3cbc3fa,f952247e,6d8d8d9b,1ba3ab01,ba03ef8e,836b94ec,dfe2e2c4,5027889d,e524fd0b,e6ada02f,4f33d1a3,4d0c3822,f0ca6651,ecebaa37,3c54692b) +,S(d417933b,c7a8f68a,9e023d64,498b5117,850f8885,b6254256,f9a12a47,538d5bd6,7ad14679,21349d14,10e35750,167282ee,9a6f6044,b6c9d71a,633f4475,5b432ed7) +,S(575909cb,46a36dc1,c270267a,10a62f31,941fb7bf,3699aa43,1a3bc770,fa37d5de,c12ef954,c937d6a7,bda47e2e,67d9ebb4,9434cda,e1571ec9,f604c41e,b49d6189) +,S(5298ad25,cc5a6bf4,d88b693a,d32a61fd,efd763f0,e4008ca0,eee17730,4365de57,75f821d1,66b60185,41cf7653,9a0cc41,597b8b78,10fd1fed,f0da4542,3a26d5f1) +,S(5aab0fa4,b0beb77,d5d2a8fc,c95d516f,1dfdc402,3e3d36b1,4ecb206e,ee8c5ff,7a4659c7,7c062356,c51ee28d,fd0cea92,a1f36d5a,b78a3ae,8b48ac9c,7fc63fca) +,S(482fc791,7c739041,41b69e59,62b0b815,8a9bfa00,f203afa6,46973980,9b250a23,89b117bd,485ac6ef,4de8eae0,a9e96edd,a3615285,e33282b7,bf0b6a6d,e11a9c8c) +,S(a576ceef,40728a7b,b63756f7,f3095c75,ff2ef84,c7933d02,b9dd8a0b,a6046653,b4c707dd,9d880fd6,d7a1ea13,87dcb6a8,e2433e21,8ef3a7f5,e348d2b3,f9a9796a) +,S(3c9d7c33,f8c62b35,fe977359,f290dbd,c2b46fb0,a2fe126c,d06e0422,54d1527f,cf92e34,3ce9f624,84c04c9f,d97569d6,67065598,9418d858,aa7368d5,bd6a2df1) +,S(56bdd1e7,363c52b8,2198cbe8,62ed6d7c,7b96d184,7da44036,2401368e,b2c83b89,505d385b,747c9545,6669809a,a9da035c,364e7971,7cd89417,3d1d5d58,298a1869) +,S(99e0696d,ed30d242,bff69e9f,ff4ec88d,eaa3de35,34dc7f35,c2bb7df5,9f8b440e,2cd1fc77,3bd071b4,c9695f25,458be688,f662f7ee,ae8f313d,9c373172,6185acc) +,S(7d5cb46c,81f4a4ec,f1e5d913,1772277e,d17de7ca,7a4b277a,d6b135e4,dbe61916,cc854503,d73e8034,7a6ad7e7,f5bab321,b130d7d,3d938423,9e0656d9,74971849) +,S(45cb6ec8,9dda9aed,5242347c,a20377bf,c93ebbd,50e48ea8,159530f4,4f4a250a,411a2ade,aaaf43e7,240bb0f7,cde77d8f,846bc700,4721f6c7,4d313fbe,70ae38c2) +,S(a7e23331,bf08ecce,2dda8c2e,a6c3c4ce,9bbbe3a4,4d40068c,e39e94fc,edea42e1,d1f12d24,144bb258,dcda7060,5348c1d,85faf076,fdd3611b,ecf6c34e,843788e6) +,S(d81aa0fc,b0a8fafe,d4c67dcd,6fddd414,80cd5548,cbd6aa58,35e5896b,18797f12,92af7ad3,89320814,bbe53ab,4cb5bd26,3df11ad1,8d2ef235,ae9ba163,74495d8a) +,S(8d379fd1,fc0acf5b,c96d03e,b73b340,5a7326ec,82882235,918a380b,c3e2669,f8c6063a,eefc0e2c,ef94d8d,ac4e5b5,ccccdf25,663d993f,7f9a0172,6756564e) +,S(5e20f600,6f533af1,8f3b6e65,17aaa2a1,2876b79,c99ca059,c2791a1f,1e466e8d,b23fb129,57640a9d,d38bf206,7649216f,50b913b8,69d241c2,baedd5e9,dafac9d3) +,S(1a0a4f54,80d37257,c62d1b0c,18dda7ce,f2b64754,be9a3d77,b3d80ca9,215026df,2f76696f,f4001927,9ceb5652,44d4a60a,9e353266,42bc2138,1191a51d,7661ca1) +,S(be868184,dc2e91fa,b11833b6,f78577f7,8c190220,a2b46551,53cc8ea0,73a217e7,6ffa3f78,1c64c118,68abc331,beb8c284,2919d593,12bad699,53edd222,2b98a31e) +,S(a4650db1,917b10d9,1fffa809,d9f9cdaf,f07faeb3,8f0ecda6,9c80e0e0,fd27592a,d5a6fdf5,647e26c4,1d7b9c78,7880c76a,b0cbc23f,d4c1840b,78717b34,2ade1422) +,S(944b1701,4a7c7eaa,754c9e03,d56516d9,e21e254e,9a871683,7a14f19a,9ebaa517,ee198337,3822c796,3ae7df88,24687dda,eea01e83,c82e66fd,baa746ac,485a6dae) +,S(f9e76020,cb9087d3,a60ba7ef,7ed5e552,3e5a3645,f61f9ee7,27d630b7,98d37ede,28371db3,433bcf49,f6d77711,d7ed9101,f5e478de,49c58103,b021457b,7a0b526f) +,S(7ac0c7bc,e17509a3,e4dc004b,d18c322e,600aeb83,8fe2045f,6da348ec,6f178b41,8b5cbafc,33469334,4886f60d,ee7626e5,36e9a977,60c0dd18,7bab7e45,6b264956) +,S(1d7ef98c,c8520f5,2310ad12,107351f1,966b651b,4b2a39a1,7a47f658,857e3bde,2b78bf4b,7be6f1ec,61cb235,a26e252c,71d91f58,69752719,8125712,55d47664) +,S(fc57f5ea,b40add8,f00c2da6,c7d24540,1b24b6b1,f102836b,4041009e,2fc6d5f0,11d3e017,bbc33913,b7861dff,bc11bca5,5aea26dd,f956d21d,2f333755,ef823af1) +,S(340c47cd,3b473c01,80526815,64e77f7,6ec29eb4,b6603985,d6ef7b64,29e2f289,994d98c9,c1de0dad,d27f3386,eeb7da40,6144e060,ef4db403,ee8a76cb,8e21bf89) +,S(81b13929,f08e9a23,69127ba,3e6e839b,8e9cd05,b19a9bf5,2292148a,26bc47f9,b6c33861,ae8fe20c,7a6c7830,4dd03fc1,a281ea57,59661e74,7f9e904,e4261226) +,S(6f325fba,15a463ba,4a61e2e6,82655af2,72603643,8a48075,f76c9882,4d7e252a,1f205971,70f9f48d,5421b73e,97bb6260,cd2235e4,6f611e9e,99b7f8ae,cf435d45) +,S(4b388e91,fadb26f9,b23b015b,398c8666,91521b8b,484d4510,b3c162d5,834bc109,ade8365,9d59c363,3191c3b,20e395cd,13ddabe7,1933045b,cfd8e941,f2096d25) +,S(2d1c0ab2,83c80dfb,ead3e083,76024910,c1d97acd,6c8be069,252bfd94,ac1a0db6,c4856c74,e5ef2e6a,17ebc35e,3b310f6f,8e7b043b,abfff733,aa3ed9f8,5a391c98) +,S(4c77a1b5,b88ffcce,1f98fd89,251c0085,9d4197f7,d45bee5d,edfded14,a97e5b87,48b8135c,b067c292,6c316424,2392fb06,f698b6d6,e98b2ffb,bcdb028f,4d85e5bb) +,S(d39cd5fb,11cabce0,e31f6fac,10cce3c1,c0bdbcc7,294119e0,2b433b0c,20e3a4ee,487695cc,8a8ec5fa,aafdfe25,3aa7d635,8d44e82f,77328e8e,4541f7bd,f629bb5d) +,S(238a05a5,519ff4e6,29b0f86f,9d259eee,4e620685,a2f0509a,cc9fb1eb,4e89f5f,6772f6b7,816018af,ec95717d,a6be2d05,3d740ec1,80241798,117ed39f,91f3beb1) +,S(c146bf13,72816407,b5f8532d,91210d59,a8a6db2e,54fcfd3b,fe910365,99f7ed14,e952ca9a,f88779c7,eea67194,3df6fad9,72b717a2,19d1eca6,33106f97,2dfdf0b3) +,S(4cd9154,861edfa7,c29378aa,1a7d6d0,83b134a7,572383ef,3010f34e,19d40bea,9ad99f1c,b5841c57,5f7db959,362542fc,40b0cbec,58d16ce1,54c5944b,6ff2aabb) +,S(d35f2995,2478be06,e86b342b,fd2d2cc5,ede30ee8,509da11,504bbffd,5884765d,a0f66db4,a21462ee,e51e226e,2d20d896,2c4edb1c,babc45b2,645968a9,c7810fb4) +,S(caf9c953,ef1f57e6,905bfec0,2fd64fca,92ded9a1,9435ad1c,a672cb7b,117c6fa,23b01776,7662984f,9c2f9e43,756ed3a1,3a574960,558db4ec,8670122f,472d0ccd) +,S(4bd40ba0,21d2beec,ec7317ac,df3b719c,179ec012,1274a198,d0ebd9d5,165bbfaf,9a5751dc,d7885a78,20d8ccfd,1db3e3d,aaa2bd65,b7b6fb2a,2d7b2902,c629d81f) +,S(560928ae,7b15a63,62eb4444,d4c0e069,1ae43323,77a2de40,83f056b2,70259814,ae97006e,fa5986b6,5da4ddbc,2bcea172,f12945d9,b6f5184,4027085d,bf644794) +,S(7870209,38e53dac,8e250835,9e41e313,25b09faf,95b03a8d,c25e83ae,f8255301,49fd164a,915e0af1,a66af8ff,d215d1d3,92e4996e,5ef68f8f,51a4b895,145bbd90) +,S(7aa3742a,6c82c90a,7e6c1b04,a41e4643,47925d,66f4e7c9,ab2aff17,e64932fb,7317dd5c,f2cb9b3d,5cc0fd6a,c433d1be,d1dc8345,b26e10b9,a2b8cbff,ce2db0c6) +,S(7a400535,be3b134d,4572e0bf,75c13098,dccc0f04,1c10068d,31e2b0b9,149c2e08,c00fd102,309626e5,a2f97ef4,e0374a3e,de0a7ed2,e45aede1,40521086,5d10466e) +,S(f4d71adb,438460c7,9003e150,c4143557,ffe30efa,eed122f,dd97c572,e1dbbbb7,e73588e0,fbae054c,140c0474,348b7ce2,92a1976f,e8c940e3,62c29ea4,31bb719a) +,S(34b68d32,810bd1ae,51d0c82e,ef99752e,8206aa04,8c5c30,7c3e9a25,b2d68b94,4d044a,6781875,6aeb8982,61bff840,a3ab951f,bf60cd03,e8befb25,97203c7e) +,S(f83b78af,f18f22b1,f2081707,3dbb9c79,4f180b0d,8871a1af,94d16d29,5c71f1c2,93ea5b8,c7847ea0,2cd5b783,5021d37c,dbbd395e,fe6eff8d,866e333e,9d6083e) +,S(a4a0d5aa,f521e1bc,2e818063,f4575f1c,99bd2447,80eaf848,2737b297,b2deaffb,3906373f,2111a47b,102b0294,f9fe1a4a,7ea9a9e9,aa2d9595,68ff8419,9f1abd97) +,S(cc211da7,28671182,1f0bca25,b9703fdd,ac9d0277,7e1829b4,4d9921d7,998011ff,c0cc46fd,5519211f,3a4cfa43,d84e5b3,bfb316de,39a5f4,9a50b1b1,8dcef321) +,S(8a07ed5b,e0397b5a,8c33ef,108df270,4b385c45,c8296593,1ed3e391,17b2f531,432023e3,8fc1a637,fb5a92f5,9911932d,f5cd23f7,eb16ef68,c8c573fc,86e8c1a9) +,S(8add7841,86b68399,b08a0bf2,a92a3987,36fca803,3807b564,f97af438,ac70d49b,758cdffc,ef477c3a,fb3028a3,2866d860,c65aa2ef,7b3d6261,9664ace3,658add34) +,S(ec6b9f2a,a1cdedaf,306b8a5a,b021e430,e9931126,a1c505d4,a10e71ec,3cc60453,8139b262,40e2c1ca,8ec89808,2a37d7a9,b78a7e5f,6330ed32,f9786cb3,c4ddb722) +,S(22ce2541,dd8a47ae,227dfec0,95ac361b,88ae2cd2,c9547344,f551f6bb,cada196a,68ce4f4,a677a0f9,60aaf4a4,f8e83a24,ebfbf46c,6ce2a470,255d2ede,c4431581) +,S(ee7dd0d0,3e5b6d8c,ae78caaf,27b902fe,4136201c,12a49551,bf208c0b,f88bd33b,aff0eef0,609bbf68,7ce2aef,9f48f87e,67aedd82,e5342159,3809cf5c,da4ac004) +,S(f7f9a352,ca18b2f4,3aa18c00,9ae0eb31,17679db8,d9fd7e5a,41b77e85,b54140cd,afd30383,ccd2a6f7,ae76b953,5bc80330,4419d38e,73e12d1e,dc407ef2,f3b50326) +,S(7793ef5f,8e57e872,ea9fbb18,bd710ab9,6ea4f646,134d3308,930cbf62,e73f0e1c,8d5b3b79,3573090f,a4a7e7e5,c38fd987,e889bc3e,720e05b2,43e856f6,32ae7cc5) +,S(db743211,ba814bf,e6371ddf,d03ba554,b558548a,a90e81b8,e1421321,656065a8,8236f24d,965a9003,84b382e8,d772d7e9,2dee2ce6,c3cb3388,3ea627d5,4a5170c4) +,S(48c22865,6e51199f,6306a6f1,7dac1e6a,13f82d42,61de0f0a,9158ba98,715d3cf9,19a2a4dc,35d2bd03,5bc5daa2,5526598a,8eac11c3,52e5fe70,be726531,747035ef) +,S(70a28bf4,ce75b491,582b48d5,9a5069b,9dcc1e49,c41702d,ee5d688e,6e643a59,7183750e,2995f655,1b58d5e7,21a5f33b,69045934,27f27f34,f8ebf62e,74e49de2) +,S(a90d8505,596b3d01,a5e8dad0,fe652cb2,4a008a7a,61ba3cc6,8401a7a5,5c2e3132,f98af047,6e925c87,e13bb7db,f992b81b,1be564b6,8589cf2d,b79e4800,3ff7b0d9) +,S(88647576,8e960c09,6aec9832,448decac,6574491c,df737dca,dcc42b84,d7e775bb,ad94bcbb,7309f483,19077724,2582f5cf,a39ead6,a4050afd,89a49ecd,7a9090bd) +,S(c505d2cc,ef72aef5,8130f472,2ab3b2c2,3a6864ab,bcfffd5a,725a6df3,fae02112,dcb82329,cc51dc7a,54e7104,462997c,3d135d6d,5c82463f,45e875f5,8738652c) +,S(24a1d4be,c709cf8c,8b8927a8,8bcfb11,43b0d579,10e0900d,68fbb682,d4e14df9,9ccab057,8440f6a2,edaa4f41,28f427de,adce5584,692b79d,624e8724,572a043f) +,S(48c44581,51df1654,fa78370a,6975e59e,576eeb40,e94f636e,72aeb37e,8fbdc4bb,f48e8dfa,bb085834,43a7b495,ced76171,348e92b0,41b9620d,3cd5a84a,d9ee4eb4) +,S(42a7838,d33d0b15,b4409534,18024a33,e93ccad,946b50cc,a543ea1f,1bb457da,dc2f0e6,4f30e973,cdf6289d,d8f6455d,51c2da02,bc4e1d13,6668250c,e4dd791f) +,S(80988f4f,c2dfcb86,f1f65196,d93a6cfd,5c664e1b,5f8875d2,61e7c4f7,b2ea31e4,1e695c33,b526d582,6210e694,49c4673a,8697e1d4,a197c9bc,a3ecafda,2a7d5b93) +,S(a0ae003c,65d7f1c7,b65cf828,124701b3,876d0be,587c2589,9a618c4e,7b79d480,d7f4ec52,bccd57a,9515e80f,2c79be42,a6b53ca6,253ee13d,ca33c917,ff2ddf02) +,S(392f57a0,ebe08b06,cb4946ff,3c1df6c7,c5cdd97,b9cb2190,dbd4678,cdbab3bb,1be9f9db,dfca7981,b3dbbb1f,daf50e6b,c5662fa8,1b8a58f9,9953eebc,d1d0be1c) +,S(cd904f6a,3d8c4ebf,6ebc4e5a,e536c544,4a04e278,389d771f,d5e7566a,fc592d3d,e3e10f61,a15399c5,f3f29626,af323cd4,3d6572fa,bad4f02d,cf76c0f4,9785919f) +,S(27a4480c,df5782bf,52ddb140,ea5a908b,38dc1ec6,a570580d,2b72b922,e7eb05d9,bd96ddd8,1a6aca1f,88847632,5a6d48c8,4d61e76e,b4d0d957,15d39f80,faa42f3f) +,S(6673ae66,3511292f,fa4dd8cd,bc0f7b36,613c56d2,775602ff,a8cf9302,4329f5a5,d8b4ffd8,8ca2530b,18d85762,529d056,e8048cdc,51730082,2d24cf42,e4053141) +,S(3dbae13,5c395043,d5b88161,4dde355d,5a669076,98c36b23,ac4c24bf,80e34f2a,b7d46059,3154fad7,eaa37c3a,291c6c67,16df2944,4274b044,a9f12ac0,a34139db) +,S(f2db4c09,1c3c606c,9784f6af,7dbfb26c,2b18bae3,b22f13bf,4188d761,6cbc1371,8c84e295,f57a9722,260d5816,c5d57719,c6fe2a12,3ba20a48,189bee04,ac252f32) +,S(918e415d,92e768e9,f5a875a8,aafa7dd6,66109cd5,8fb6044d,d2c8640b,f6b966a7,b53400ce,9ee9f6c6,9cc35b5a,3e04eec3,dc89c931,e545068e,ed4a818e,42073e71) +,S(5eda3e22,bbb8c368,82d46c19,2068b3e9,a65624ae,31feba8b,df725d5e,47bc3437,1cc2c541,ce3ad8fb,ac3cfabd,a492c03,87099e1,659cbf88,bc8f27aa,f9a2fe26) +,S(7df83e06,9cf09a92,5405e0d4,3cf0c7bf,52a8e603,d286e26f,f273e218,b455e61c,9eba2975,7f61b054,29c9e915,a092a591,ac1d6044,8a63a8f1,313f4018,1650f4bd) +,S(b778c25,d78b0bc4,68dcdc80,5de93809,1c3c36c5,b5f9569,a9394b5d,c7afb162,901a4ecf,b4821145,c7d9e56b,75e43ab9,cb7ef8fb,1d384a4e,27033e9f,90b80fc) +,S(dd4965e,f6fb759,104f7877,307e2a6a,f837ab6,8c19aa40,6fbea75e,e8a7adc3,45e92312,b5c77585,3c4b95ca,6b4c1740,a70b57c9,97124883,2c53d291,4b0fd4d8) +,S(ac971379,7dffd8d8,2e33f927,48ca063f,f1c8ccf2,5b88fb6,bf80946f,1dc9dede,6ce10e3b,ee4db87d,40e8de66,fb5263db,2a578d6d,be100fef,d6e28bd6,7377bc26) +,S(6046fab5,37fb413b,29797312,5a6049b5,5c085194,4b058264,c39926ed,fe85c6,dcdf9ed1,cbe469ca,2976333,5a159e42,af6f0d32,664ffb5e,173986d3,a277180d) +,S(a0d94b05,8e3b4d30,7f3b3f09,ba5ba28,d0285a3a,22cd577a,1d949b8,bd23f1ae,37fcdfb2,e3027e07,ea77f28,447ea13,93971c67,974304b5,dbb7621,2ad2db10) +,S(da15b971,1b974ef9,14433ca5,71175233,693cab3a,dfd5f6e8,cf034254,6f73dcd,e08c7f62,90f87fc5,4e2f4ec5,a5a93d19,f4484868,3b5ae9d3,810b0615,c7e79402) +,S(b26ba5d2,72a744f5,562cd745,a3f3f143,32980458,60be4e97,d737fbb9,b3b0d544,3d308307,9830f281,14de6c5a,f3876446,507558e2,95353dcb,738deabd,80c0ff20) +,S(fa26c55b,bac04fff,ccee0610,ba9b60a2,4042aa08,7a564ffa,b891e087,7a2185f5,5b5a62eb,1ff579b9,ee4c5d6e,ceeb57ec,e9881b47,dbfc24f4,3b9a18d1,4addf4ab) +,S(5ada4a59,4802163d,4da685d9,b7479f,4b70b489,5ddac7a3,b06a1c4e,a5f46dbe,2ec25e70,871b4958,81f6b0e5,cf821b91,febe83db,a52fe2f8,1a2e4e82,165c7e3f) +,S(a57751d8,895282ac,bef2384b,db4817a3,539899b1,e7fe7a62,2596ad18,5dcf878f,651eee9c,12ecaf92,9eccf109,635680a,a7499537,f2054e2f,69b0f062,c820784) +,S(3f17f0f2,6a540098,d18f8d88,ad323e9e,e300b029,b7b8101f,6aac6ece,8d375f3c,9c0713,79e35319,7f1e76d,55616e5f,8e573a54,b6bfa56e,5dacd2aa,e2e0deeb) +,S(eabdf476,d2e9d76d,775388c,da759930,4e1ebd59,b3a7e491,e3c9c62a,4d0968ba,f4bfd5b5,e0e8ab41,a04c4cd7,763b243f,b82f56ae,9f08a6ef,bc365f3d,fa227c4a) +,S(c5b76ae8,dabb664d,fc1fd499,36399e3f,c2b7366e,a21cba10,dc7eec7c,5c93e0d3,ef30249,19bc03a,c24c8544,9467728a,c160edc5,7c901e64,b947f298,9bb1242) +,S(7161dbf8,6b1080bd,bd6aa47e,dcdf8a77,17b7e281,c692e9d8,739caf9a,f3f23d6,3c30b786,b095288a,4522749a,3d32a35,5a8bc694,cc9cf7ea,989675e9,a1688e8c) +,S(ed6a7b49,9b74e62e,53183b15,6867d41,3ce902a8,4b71fdc4,fa414f8f,249c2ce,793d0356,1bca65c6,be127ce5,a1034b9,86285fe1,f52075e8,1a9b5bcf,87348c4f) +,S(fe6e1abc,3ee3be4e,22456f4c,bf93810f,282f0fec,96ab5cc8,2b35b08,54492bad,96c76282,3adc2cea,1563c02b,fdb25b55,eb15e769,90a7ed7a,3fb8aabe,47bb077c) +,S(979e7ab1,96e66818,b67bf79,31232826,713648bb,ad956add,ed594cdf,8aec2937,696a9505,e3c473a7,2df68f96,13c2e494,406782a4,f92a8fd6,5017a83e,d7912491) +,S(9f947cb3,f859f2af,11a63400,800c18de,b8813c1a,b396ebd6,a1d5bf4a,9689160a,8efeced6,7f1e6fdc,191ac965,5002a02c,386a20b3,eb2aa1be,7fc12008,b8bead1) +,S(71790030,58caecb5,dcd2e281,b42eb59e,57de1e6e,b77f6bad,7d2d1897,6a512eb4,abff54d0,e20347bb,c10a79c4,127f5f7d,868176a7,4e34077a,8ede1d54,7e339483) +,S(d786ec15,c140af46,841b7eb7,de5fc9a3,c0636885,3950bab9,ffdbad01,d836b8b0,fc90191b,63616a44,72efb2ac,a7d84da3,4892af1e,25bca0e2,d41268c8,d381d062) +,S(2d553f03,31eb83ca,edf2508e,67054734,d929367b,ffdd5b7c,dd78dc6a,2e724534,9abcef4e,ee588e28,fa1dee0a,b8c426c1,67d37cde,f8aae9e4,248c036b,baa1af70) +,S(326b36b,eab4d932,c40182f0,fde043ff,d6b84b16,72fe1dc7,3bc7e518,6ef68062,9d86868e,2e871ce5,c3488624,bec901d1,47b91bf9,a3154cab,6445870e,d51e8f1d) +,S(f7a6a26f,4e3583bb,9552556a,5d248735,7ea4af7d,ad1f7a92,717d19ab,34dfa11,7ace27e1,dab2dea9,704c01ce,50ea3de,529d864d,9a5fc11f,fbc0e8c7,81778b2b) +,S(8ca708ea,c072334,42eae4e9,eb0c7b45,83e153ba,84ed7a0d,3ece41f9,4df6cd15,33f41d25,e446c47b,68ce1bc7,d1dd1740,fc701538,3ac90e05,1dc89a9f,dc97592b) +,S(4fca2ed9,e1948697,208a87f9,a890cc96,4aa9e5e5,7c7274b1,deea92bb,586875da,98a9303,4df7185a,df9f557b,b7def9a6,41e7ad5,a3f24051,435673ff,12f0580) +,S(466da0aa,97c68c05,21b8fda0,fc70d74,bb586eb3,da7eab4b,6c104404,d9234d37,5834296,f94f5b54,beddc0e,3d7f6004,659952b7,90a6341a,de99ff26,5530e5e6) +,S(ae22ae10,d016b54c,c0b5423b,3f4c332e,3180ff23,c279078b,864e8e07,77e26a5e,ee21d64b,d6043d56,de3346dc,f93e2c40,b9a51498,b4d7df61,d476d339,7a2d0c8d) +,S(58cd60cc,ea7e0896,2f65a353,5d45ad06,517fea5,575c5511,277103d9,fabb5167,175a68a9,850b4026,bc7b5684,e859c808,edb5f3,7acebc47,9ba489d5,5aa9774b) +,S(4be8a0cf,7ce26101,49cd90a8,68f4049c,43054aa5,68bfb2a1,a5bfa386,9b2b485,a3bab0f3,e3bec469,f779404b,d025ca14,79e3f6ca,9d496f8f,8ce4aa6f,b7e3b404) +,S(428599d9,398a2c59,58c5f74f,1226605f,3c5c8e74,ad8f9bc2,d62b8d9f,d679d3c3,12a1b04f,add5d70,bdc5e15e,d6347f7f,6785c425,61f14ae6,275cf050,3a1bd5a7) +,S(134ba4d9,c35a6601,7e9d525a,879700a9,fb9209a3,f43a651f,daf71f3a,85a77d3,21c112f7,6a9b9b21,e2e3a7c2,8cf500bf,f48aaf1c,48e0e13e,f15618b9,ca62287d) +,S(d53cf8f3,cc5e5739,bc9f9144,a44e7b7b,bb8f2c36,b50844ca,9b2d9cf0,cd0616d2,799c23b6,c57aac44,90d71450,4388cfa4,689393ab,6f30a347,4503400e,c568e03f) +,S(a1e22cfd,e8d12f17,eea1eca4,ea0b520b,6598c036,d1bf837c,e23bc300,a384e5a7,cfbb52a6,e1fb6a65,77cd0377,8bc965b2,a3df592f,f73c34d2,a91b8008,74ecc295) +,S(72bf047f,a0da1391,78b97ea,7b317168,ed0576fd,71f49409,39a8daa5,2a02ead8,f8d93088,cb3457e,7828ba9c,bd8492e4,9eb2bf0e,2e23bfb0,4591e9bb,5273f462) +,S(c5373038,4b951abb,3bcd1f4f,98d983bd,cb5b36a,42719531,c4d1797,2e9bce59,d921f353,a9f7309,6dc16028,f9e1b562,f406bf49,54d78bf9,f2b4c8b9,2db26a82) +,S(ab20d194,e2a6c4a1,5705d3d,19300810,89342b15,e9fc6224,7be58805,a8682a5e,44dc39d1,8342502d,cafafe40,33c4893a,2dddddd8,ad7b238a,efca50cb,5d5b3186) +,S(1432ddfb,108ee664,2eaa9c97,585f47b7,b92a5ae5,39a38093,b8f3153c,e971c8f9,5362084b,5482e375,1662aa95,dd3b9a6e,65235aca,b0ce1eae,f5153951,1391e269) +,S(f199ede,4a69d778,61e107c9,376bdee5,6430e279,28c74d75,66e65589,be8c433c,5e7f6fb7,1b68a535,f407a9ee,2e42f65e,9835bcc7,2c34b8e7,712e5332,a65e9ac6) +,S(b24dbf51,47452b5b,ad94bf4b,493120ab,61ce2ea4,37b3ad71,62e568a,1d595d1a,b3af5a90,8d063602,6b3869d0,c9f31793,61afd6c3,8db99cb9,77b14e0c,46427518) +,S(d7fc29eb,b681e025,992d9ef7,295db58b,40f36c64,d1be10e8,c8e66858,d4d0d9aa,c587764,ca84b3c7,2f95eba,eb62494f,ce391202,90c42b9,e8b2105d,ed972595) +,S(5c71e90,d5f00ee6,e033f0c9,c1ac495b,d148a31d,143a8e3,59a99c7d,faa3cc9c,4acc164,ea3071b7,a4830a27,24135c49,562ea631,9dc4455f,808f1282,4e3bbbb3) +,S(4c9904a9,a33f7e33,9a3d85ac,c12b21ad,11f7d7f2,76e46620,76878593,9d11eaad,2387a445,b0967403,86ce4634,62dd101f,95650365,ac02ef1d,2417321a,3fac1df9) +,S(58f457ec,12d22482,2a91b78e,26f7d8f8,5fa39d90,59fb833c,bce4b1f2,5c9720f7,90808a70,79d4970c,b2b70ae,390844a,2f0283ee,eae05a5c,7d2dcdde,be656f2d) +,S(9867259c,51414805,3be6a73c,de522d91,a8d8b359,9f9bd39b,9c9575a3,90405bdd,9904fa47,34973bc1,77a3d0dd,f0edc0bd,cbd77b36,357734c0,a0feff89,4895f3b4) +,S(663b4991,913148b6,631d16fc,27471938,20a7ace4,ee85c335,17b60cca,b5e12b5b,1b295a18,16b92c5f,15b88bbc,177dc011,f6ef0760,15b5ea47,9bca876,ae072070) +,S(5e3ff13f,bed18235,fe28dcc0,72f09cfd,41394cd,a9a3aa52,5286cddc,e56acf05,c1488c2c,903bff6a,411697f4,44e6e72,6ed9c0bc,5aa87cbc,ed8f8802,6998fc7f) +,S(54c8aa07,2f1fc5a6,ade56cef,d7c6aae4,846f6855,34912868,b84b195f,78bbe14b,ef11dea9,5cb01680,e7205f1c,62aa5242,2c0db969,9b2a0202,966873f3,1fdff34c) +,S(bc69e00d,4118d8af,baef7647,6e435883,2ae9864b,f154368c,e2ccdadd,c58cfd9c,148aea9b,2babfe00,3a6592f4,d3788893,5be42ac8,a50f68d7,ba2cd738,47dd9c52) +,S(50ccf184,c0213602,af114924,fe100f78,1f0d0cc5,beafb671,9dedea00,c7c3ebe2,b6559878,d7c33082,4588dd33,3054c4d,2da86b8,ff23fa9d,6413920c,d876e36b) +,S(c24ca0a4,8ff2cbb6,235ef33b,42ba032,386d5475,3cdda799,e9bc53c0,5c299aee,8555bb16,bf4d7bb7,5c0cbdc8,8594454,bfc819de,72c3954e,76b65780,2be28fe4) +,S(cebc8853,3f6c3a01,58dfab12,ef52b4e0,a7473d1d,209b3585,bc94a13f,a83abf17,42fe28d4,136bf80a,7149a0b,7ddce53c,45e23c0e,7be85fcb,73c0e66,2c4c0593) +,S(7d921a84,65b11feb,7a755a4c,5d96b6b2,f17e07a,95db112d,48c03bd,18f61422,f0ccffdf,7f04e350,13ae7f36,411dea5a,ef69f220,790c37d7,354ce5e,83925f4) +,S(b6909fe5,6824e868,f4cbdd10,d3d00ca,23e5b4,35c78aac,c78a9a1e,321d178c,3d513c55,136d61b0,73dec253,e1ed817,782d9f76,b536d3f7,c3b0d1f,d06e6c1) +,S(5a3df3e8,c78c0fc,56971dea,ced3a6ea,e1ef668e,2485bcb3,d4e24408,7f53cb74,960721cf,316278bb,56bcdd1d,9f3385fe,8feea6b0,661bdf1d,44771067,661aaacf) +,S(dc65c06,50cc30e4,d759fa93,d4d0ab65,5cb16591,289206d8,7a988290,20c22f9e,be39ae0e,a41a81d0,2175dfd5,5e004e19,fa925a99,2166d862,296899e,2532b6a6) +,S(f659d02f,f2d4bc82,9f816525,24019a88,6ad539da,3f38b083,5d8265cc,bf3a67ed,bc9c7a81,9036c702,338c57ef,26134647,2a22b8cc,5543f4b4,4a4f7d4d,d4339573) +,S(b89bbc05,420a8a65,aa03441e,da1c54da,9ca84f11,e85a393d,47cc54b9,78b8e5c0,5f3a2fba,4cef4457,ca6befe2,7dd3f9af,a5d8b6de,86679eb4,c877c7b4,cf03c08f) +,S(b9bbb789,690b53e6,e42266bb,853cfbbb,f6788b58,b325097,a55470e3,d4cbc3cb,1f984f38,78427212,cbfc8a93,8c1f0d87,59792ca7,17635c75,71b2c4f1,29e35c2e) +,S(d8ae91cf,8a99ef6d,2ca0c15e,3132974,33cd46cc,55a2c8f3,9f909e96,7d50006c,4fe4696a,79d2f269,9fecfce8,8375cc1,81c2c2e5,4109f380,3377a020,5496d733) +,S(35dc2c70,181aea7b,ccf6a15d,1f708c87,cc8bc5af,93671c97,35867367,549357bf,6f27dad,a9abbe5e,5e59141b,78a2e6dc,5b5433ef,dc8c9cde,a6269c2a,68346f87) +,S(a4c042b7,d54b67b5,877442e7,2e81de4a,7edbe667,f00838f2,34f567a7,9e3791af,a8c6f7b1,6b23a9cb,64732852,c9734547,69ef3e4b,9165ebf0,a1dc4967,36c73242) +,S(d6ab68a3,353b6c65,3836b66a,8c39f2d0,892cf856,90ebb56,a5e8e4c9,e669da34,4847a9d5,f39ea1e0,ce392c8f,9e63e88f,8f3feb9d,7b2a05c7,23a932d4,b07e38e4) +,S(e161c34e,644eb3f4,fa217d33,dd3129b9,c2b85ad6,40b56e56,e20982d1,c5483d43,ceafd0af,a8cf7a25,be092307,22c30e41,b6ea151c,d027326e,5152aba8,d9a50749) +,S(94959a2,fdc2650c,b4b0219b,83ac99c7,c477132,eeab585c,1fb262e7,6cca22f,6243f3b6,ba7d4f26,24f7b7d5,8e070b2d,64610aad,b281b4a3,b93b030c,ac0cdab9) +,S(491129ee,3130c2,f262c4d0,a1bfede9,e470c3cc,8e80774f,52ea023,67e2e3de,c1e61e2,a5310866,762a0cf0,ebbae0f,738b9527,46001aed,a991e0ee,d95f0db5) +,S(e2967539,b0b29fee,a668eebe,eb8e47c0,1ed84950,a1f9fda8,6884a421,5ab6f265,c304cf3b,b7faabe8,cfeab6b1,b88d3d41,7e950963,745c2479,85211d50,888346dd) +,S(d90a380f,5283132e,7d6760ca,f2b28576,49445507,b8e8872b,d0e1d5f,56a15af5,97fa0739,7a1357c5,e24d0a3e,ce608332,107e41f7,c65d3c6b,98ed66c3,af30a4ed) +,S(cb917a08,153599e3,e531b1ac,63fb8e71,fcce572a,29fde1b,17de843,a99ea2b5,701c08a4,a9da11c9,3b4be64a,6832af1c,900ad3c1,4b4dbe70,c62e3e08,55b41b6d) +,S(e6ee53e2,98efb026,bce900e7,8d31f3c4,539108bf,d4c5139,16417f8b,49199a0a,bedd41e4,751f657e,8cfc65c3,2a82f981,4b223e62,95ec36cd,da5125eb,da736429) +,S(5f777c41,f4e3441e,75c66f28,852e7815,59d0f3fe,b8b05b59,b6966fa0,de84df2a,7fcc66b8,127d26d8,e0ff69cb,b80acf44,bae5546,edc9bc52,90b73da3,447a2731) +,S(16d312a8,1295ab9d,c08f9fbd,61e6445b,5ef1dc51,fce19d,89f04e7c,66ba2e07,6c555fca,2a1d2f4a,24ced2bb,c3966f4e,1bfc1912,eca39067,503df586,41a4d4b7) +,S(660d3993,fa887e1e,8b05d80b,96e2b70c,341c3ba3,351d2562,5792acaf,3859de3e,87b06f5d,4c6f854a,8714eb3a,55454346,f931c21c,c77da23c,2d069d33,7dcf12c) +,S(9d45e660,879b6e8,b8007a8,ba7fe7f0,c7090cf6,9c733bf9,43f4eef9,965a1ae2,c81a3fd3,9b6b83ba,d163c763,f3010359,ac050e64,a47167ae,2ca41345,c7d95662) +,S(c95d92f8,c81d15fa,a68f645a,c1ebebd8,57c6942e,e75ba13a,3a4eb9b0,c45c43ba,2f55ceb6,c1de7877,7b322a91,7f3e48d9,480b80f,d49e362c,99f8104b,a20f392d) +,S(95d445ff,e8cf8240,fc4e9856,9d41164f,50e9ebcc,1fd3bf19,d4309de3,34b4c97d,7c391704,a75cffe2,f8971ddb,417e8158,f97a3688,6841f02a,c4b699b8,df6c0d32) +,S(40f028ca,907d6521,df1f052f,ba5268f9,a60e705,bdf94328,17881b44,1500170d,4eae26bf,37d04379,126ce777,b1fe1115,8c34d077,bba66994,78ede7e,244cc8c6) +,S(dab90c34,e7460068,d80d2be2,2bd81f9e,667bbd96,4e30c23d,3eaa7a75,a61e862d,cafa2892,5128bf3a,4821cd14,8503ca8a,86f06388,d21df6ee,af92d514,e66c5f1b) +,S(6df2280e,381ef8cf,922505d6,7646c1af,105f91c0,59e8e7a5,3ae2e7e6,cb456be,d94a020e,7776b713,b31aff5f,d72be6c,f29bfe46,16ea3d29,95913db4,698ae3ca) +,S(a13d83d1,3c60cf65,cefc8692,f5d339b,2873582e,938373cf,3e4df54e,ae32ffd2,8f511212,a65d8963,d7df7ed6,27d87fd9,208f83a,1a4dd14f,ab0593d6,38ac71d0) +,S(ad4c1ec8,39950ae4,a7fa551e,5aa637a2,e5d40bfb,3fab696f,ea886a4f,40bf2167,fea9b599,202841d0,c3afbf08,ef1da210,cdd92a4e,6cad485c,a0d5275e,8a5dacfb) +,S(64188be9,af657254,1314e661,848970f6,35a0b6be,7e594824,6dcf36d8,66840610,58880b5f,c3df9b6a,45b49ee6,b90f6b5f,f3fc440c,37855167,a30ac013,3d48e53) +,S(9b71366d,a66b165c,6495e4fb,46ecdc15,84a193ca,d65ad8b3,7a01a3b2,cf2e43f6,d7315165,ecec296c,4b71a860,f3b2f0dd,fb9447ed,5c59a458,8b81f679,34321301) +,S(4a3c5006,74814f95,9e9c7726,595658ff,84e369af,636f6aff,ab579bb8,5583d395,1b495757,1a302c2a,d1cbe53c,2ba34a6d,66bf1aa1,8bddad33,679e4890,5f9a21e9) +,S(e4305e5f,72c43558,79a749b3,d563d4d1,dca704c9,c8867d01,ef503cf8,97c90034,ee563dca,4d31945f,c536a318,e9297d28,81954b37,af992722,9e4e0e9,1c16244d) +,S(3aea4eb8,ee74c9d5,2259f37a,da33ae1c,78f5dd8,d97511b0,2e0a0201,82840a8a,8fc58135,757b8c0a,a8f2c2ab,ec9d9152,20ad2046,f429667c,c4586765,10e93e87) +,S(58e8e94d,e9f85066,7cc4c61d,acd212f4,77454942,33deb015,858e500e,9530228d,5a95aa24,fb782a4a,e64e155e,eac2b644,cd614315,9b46db6c,9bb4fe4d,5e5fd690) +,S(6642c782,7e1df912,ff54dbf7,41fa1567,3e9c3aae,5e7630c6,9cb74b60,c070af1c,ff338a86,34a404c0,cb26af9f,59df36a9,e1a848e1,ac178b25,c37ac177,db45e947) +,S(c5c69fa4,65c79a50,a98996ee,cae55474,5c544a3,ea838a42,e12a733e,9181b30a,6e805461,5a424a9a,1fc229b8,7e594211,697386ef,189d1ad6,ac75eaa2,5727253b) +,S(f4faf099,fb16a1e0,e5f64428,5317d91,a31daeed,fbb6a6ec,b70a213f,ee95217d,ebfd8445,42fee872,1f721f3,11ef28e,30618bd1,bdd097c1,ca573285,5b079734) +,S(773b3e69,fda8abed,fa61ef37,57101756,9d9d2a6a,ebb4fc5d,d9049d56,9c66b76d,1bc051c6,302a383c,dc0756b5,114dfc69,1dd2180a,88a4ea9b,6acebccb,a59f27ca) +,S(bcf80e7,b2b54cf7,971fae7b,db8b3826,85acc1b0,f987f352,d9b0b3c7,ac78142a,20620b00,8c010ad9,7a98f093,8d9a381,f9935d5d,4bc9b060,af2ee6ab,151eedce) +,S(865dff30,47f31564,99337316,ea20223c,5967e034,83d92d54,7486fddb,fda959d2,2b655c9e,37697f10,5535b736,a31b2c6,7f5726eb,602f1438,f808ff62,4bac074f) +,S(e48e0e18,101eef40,f351067e,63d2b34f,4fce76c,d204d6f8,85d2664d,fbc92d3c,594061c,8d3f4748,bff85cdb,f70a4035,5ad826f3,46d44aa6,7eca3196,e433bb65) +,S(9807e350,7a03e134,9bca9101,cacca5d1,a564b647,8c906619,61ba503c,5ee15bdb,301e68f2,d584b1fe,3eeee7c5,85cb4d0a,26621bda,229589cc,2704dfa1,1cb8d927) +,S(95f94e75,8602dcd4,60ded52a,c9d7ab40,1fdf1405,b271acb4,133a86be,cfe5027,f08d34eb,e9cf1b1e,78e1fbec,452e1ab0,412c642e,1328b2dc,f5e08b08,38aa3c51) +,S(7ffa20eb,ebbad406,deec68c6,9bdb7b0c,7615a56f,5c62a646,a57535e1,68a82a31,230241b2,3dde374f,7a039eb5,5181e954,f0472056,79edc688,7c4ca6b8,778333e4) +,S(1dc7e0b1,487fbb33,d1ecdf84,7bdbfef5,f7df9f31,d07ff024,be063a51,53eb5498,ebcf72da,18a1a55a,5aec4aa8,efe09407,263a7b36,f09552e,22cbceba,7a3cf980) +,S(a8052e02,e39d9981,2ac6c4e6,2cef526b,9cb29843,127f2227,50a8021f,4ced5cd8,9011f0b4,9dad7e5c,11222b64,c5d8c9fb,297d9afd,c683f545,849d833d,f2697220) +,S(3edfc4d7,f1f699c2,8e8ac2e7,5cd93e69,fff31607,d99a8195,30603437,f9bfb20d,f901260d,68c6dfe8,aef8879f,ea1ba009,a1e1d931,fa6ba39a,ce1e2673,ba759311) +,S(fdf8ae7d,c10d01f1,c39bee75,3be3307b,53307caa,4af0e8dd,9de7d696,45ce527d,2425a3f8,c6147073,3a44d3eb,eff3d8cd,61e5fd55,ffdac357,d7906600,153a8dd6) +,S(1cd5ba80,fcfc77c3,d06e230e,e7ad8ff4,f9ee6c60,a71d37b8,3718d8b3,15d5a4e0,f90ac118,30b963ab,fc64492b,415db7e3,47eba55e,d2c5a64f,578a13ea,b4435cbd) +,S(3cdb43ea,b7afc936,24b80269,18319fa0,e75de21a,c0587af3,541e492f,1510257b,49b6411a,c74a2eb3,ac2ec784,feface51,8d5a5bd6,e76d694,bf5ab8f5,c146abfe) +,S(165b6f5b,9b1e6d08,14e44cc7,c7969297,bba7c659,58dc3274,7e7c4148,e30c09da,e715e411,2e6cb67d,cb8e1ad,997691f3,bd6119c1,3a5f0329,1ea3928e,35c04551) +,S(d4c1190d,da3c01cf,6c75fa06,7b4dd1ee,e645a0cc,8b034f4b,24580661,8ced0bff,c837ed81,b6a0e5fc,6a02d6d5,f837db1a,20eee55b,41ff531b,9bb642d0,52c42bfa) +,S(f7359bd0,bf7db6b0,48f1a040,a0163fba,285780e7,909ab689,7963168a,a7de9c29,8c71bc3e,95ac0f52,54db6192,5c6f9112,759635fa,95846be4,6a28573e,2b25562b) +,S(4d54a2f6,dbebbee3,8950627e,8cf2c65,6ca071e7,86687f3b,a0a77178,be14c55d,6579dace,73dd14c,695fd781,218786ee,bad84445,ccd910d3,43aa2478,f5576671) +,S(f70b532c,e7203208,d6440bf8,55e1293f,cc6ebd75,96a04b27,9fc056e1,2ee32dee,e9d18f7,126ed56b,4a657104,2441bc08,1778736b,91062c9f,cac28cbf,b8737be1) +,S(bbf3ff3e,577aaf34,157e32db,d977b907,e62b16b5,1ae0abd4,f14e71fc,cca11357,cc1a78ff,44af7c2c,cdf17423,9b3aec17,b660ff2e,fc07953,2d9f9d6e,55d3abf7) +,S(53bb2321,b36d1dad,226ceb24,f55d4292,be245444,b2349611,5a649560,59729700,a5db4fb9,46c4a2db,b1a634cc,4032b7b,cf23f7d1,717a0ee9,6c02f131,24f834b6) +,S(3b863ec5,5e4ff2cd,d32cbc81,6e645009,da444255,9bf96267,2cd012e1,15372186,914682bd,d6a052bc,25cb4d41,e9bb28ed,76e9aa55,3f5aaf25,75140e04,eca69fbd) +,S(4cc4a750,d641c574,5c68a48b,953ee51a,258239b2,fda1f5e0,80831417,7b837946,cd6f665f,6f32246a,1cc8fa61,4da2783c,f4c7b92c,4f42749e,b6bd4a8d,8a84c54c) +,S(6f9b5d79,efddf08d,26183b4c,d6001d6b,fdad9e8b,dc5853,f3a8c47e,7e6f9e96,b81148f2,1e50152a,8cd7727c,ad14862a,37fd186e,2054d4c4,a4cdbfba,a9076991) +,S(9e13d0e0,44cd3fc1,1c7596f2,9946313c,918caa65,bcb6387d,361eec31,ebaa6977,c5f55650,7691bc2a,b2c9e4b8,512f7282,24276490,257288c5,2387fee5,54bc9c0d) +,S(a4441292,d0e0db3,2a4f33c4,8bbc5fbf,d40650c8,d9f5c4f4,88a1f69a,d71571bb,a23ef48d,38abc24c,608dd688,d524bed,a3709a5b,3567ef3b,e43f0240,796b7ad2) +,S(def598a5,c4828c5,16b7076b,9682aa82,4e74ab42,e4d4692d,17c8f289,67f3cbb4,e6b4bf28,6dba0803,e4a97a1e,be55a088,10660466,3d7726e9,300109ee,a1d62a49) +,S(8e991fb7,372df8d7,7b09436d,c9424a8,5a14888b,583b3c58,6d2a19e6,91e75b67,1780f6e9,b8379b0f,ebb1328a,69a96878,9f58b45d,8e3ff218,81d753f4,8ed6c43d) +,S(bae09288,e10351fe,fa0b0971,400ac3d1,a7eed65a,b11d1ba4,8a1c6240,bb981114,dfc2979e,dcc2de8c,abd9abd2,27cf7351,4079d950,aba60e3b,f4c775ac,72c30f4f) +,S(4d09ae3c,b484fe27,411d4142,e41de523,2c54c42,b387c7c2,cf42a23e,e7611fc1,b94fa116,27eaf5ab,8fb7fc25,1345eb28,8f5249e5,ec65e056,d60e1294,41481375) +,S(32f57ac4,3cb29fb,f8a00d8b,c95da8e8,3f0f541d,ed6c9e78,8af17a14,6a2704bd,2a969b58,9a3f9a5c,26b51ab6,1a5717bf,c06eb438,85e4f4a,84b903b2,da5bbf09) +,S(595503ae,e179f59e,bfc581b8,7ac18e1d,55b4c794,87d90d62,492d3ea1,1ec57579,1f25d8ba,e38c0a69,50a17836,a842b418,b0f7c317,9486fb16,9ba11b23,d315ada0) +,S(5555fae0,6f1563af,238184c9,304e26ef,f8b2121,394e6856,79de6792,31a56842,6840bd14,faf202c6,60650541,48bb87,df27b979,4ec0da66,9ded6830,b0623980) +,S(714321ed,2f0432f8,a05c33d1,84619de5,f81fb8db,95ab3121,c24fc998,ab9b9ca4,4470cdaa,7067de2a,e6678cd0,6d613e19,35b1edf3,bf278205,da69ee8d,6086c2a7) +,S(d41b84d5,9a0085b,86e88fc1,499151da,b0b9a574,92b01df6,36cc2288,313bb592,c04c54d2,57fe5ba,691f6023,bd72edaa,20e71a97,1a760bf5,3c990a39,f5ef7c23) +,S(ae34a065,b42f5158,e6a5b91b,9ff54b0e,6d5bc906,f6d18c3a,82865e,e9038f34,bf2c90fa,30639811,2ca2ed02,b7ad090d,8bc990db,b6140a05,afcdc80c,bae8490f) +,S(9b3c2682,3050a52,a164ab,f4504ca4,7750c889,b6465f95,658ba7b1,c279139f,ee36938d,8a675824,51ca289a,55265606,cb9ae4fc,8cd274aa,41db5ea9,9a5b4299) +,S(27dc9a57,999ed109,c3dff978,58d44ab2,73987af7,b617e9c,766331d5,c06e0dfe,4e97536e,67e363c8,add07030,d59061,33a726de,38dec51,e5a20009,61ee0fe1) +,S(c3415e9f,9c823521,bad3090f,f2c48e8c,647e438d,70397e5f,7d7a6f2,b7d7d4b4,8c3bb607,c746147c,d5efbef,7e27d236,c4063116,89794cc0,40c235b4,6af412d4) +,S(f47e44dc,90c8bd2f,150d9dd3,e4922395,14990fa1,f2fc361b,a24f853a,b37e33a0,f4282a26,bf5f358f,2dac4956,8bcc15a0,d7eddeee,b43e6fd1,8f35d5e5,4295ddb4) +,S(3cfa945e,6044ec2a,da895f9,9dc24575,deee57e,df8b1a10,a2d2ece1,9951a812,d0ab59a7,46ac6edc,69307a0d,caa00aa9,e7b73897,b89185fa,9dc3899,ae7e3664) +,S(29df8149,9d83bd0f,8fe61eb8,8f0abe0,96a75e5a,2cb0a0a9,76d8d27b,6533a4ed,7eefc80b,63f927c2,e905a56,62d5ed34,e9bde8ff,4402491f,19215c9d,494e62d4) +,S(eea85a80,566d13bd,da65f553,b2077607,c8b9184,6a5a8096,f57afe93,ada9fff4,b5389645,fd772da0,1cf3b535,6ec40279,cf76d812,11f20a16,71d7ecfc,441d71bb) +,S(e1a69e64,4434db7a,54550d44,adc43682,c128c560,3907615b,9282cf1e,e2b74f82,bd434a85,984a6e64,441134e6,d1f1a3a3,adeab658,c29af8b5,4bc42667,634d20ee) +,S(2d99f69f,a7e9f3f6,6a53eea4,381a4c80,ed17e8e1,4507d7f,4a80ef25,293c5fba,25a6aff9,a23a406e,9e34ad6a,21627acc,96b6ceb0,7896382c,833b8fe4,8e603e0a) +,S(d2482127,1554a14a,7283dc8,1ca70179,42a35cfa,c8659b2b,db78c426,51807cb8,a252027f,3fac319f,c767652e,469421b8,d34decd9,c9042d58,f8aa0ab,70e5ceac) +,S(bd030cbc,5f0de61,ef194eac,38f7443c,d231f75a,a0b568c5,416c5b8b,917545d,ad0833b1,4f1e23a,76c0626e,71129455,60fe62d7,4b3a1b95,69e4887e,c0661e78) +,S(afb44b49,ef00b1e9,59c7a864,19d2a4db,71d9bb0c,4e1746,9550d39c,9a37a161,eee390a9,530a5baa,5350019a,f756185,8038c2ee,7f78c365,dd6f62f0,f0589aa5) +,S(9e584f1b,e06ea4d6,5f8dd96f,206cf4b,88aec6b9,ccf06779,53acf110,99e2165c,6994ce27,46b0eab3,d8608ef9,33b61339,d3e589b,c2acb7bd,aba3af72,b082fd24) +,S(d2265b51,b4f7f4ce,1d0966,e7012f9,76433dfe,444b2351,9505b29c,d520c6df,44414498,df439478,328b330b,6f8c6876,682b6a32,b5d01355,2494286e,a635bf65) +,S(fcd56867,58c797c8,3aa1f1d8,a9ba34a8,8e624aeb,666507fe,706b310f,3342264b,680e0b98,455f0e64,94622fa9,e36f76d4,863a9fdb,a3df93af,c688c45d,fdc5967b) +,S(bb9a0c0c,74db0525,370e8235,9d733aa3,494afc03,fb61a1b,7c2536ed,9903fd91,239929a2,1c0ed586,b9bc8f03,af422994,f81619c6,b2fe637f,a511c07c,d9421603) +,S(2358b078,1989d6b5,666d9158,2fc640b1,13d52e61,ea2147cf,a0a103e1,5ae80db0,73f84f47,a78fe2c6,e4d01d7e,3dc10065,e052401f,64796358,c784d59f,742cc8f5) +,S(ddb3409,ce3184a6,d9d7b4c2,cbdf32ef,ebea1be3,595ba19c,42933882,237dae94,59215423,3760cdf0,513442bd,2fbef84b,9c8c0fb1,ef16fa31,783d4dcc,50f24f24) +,S(f99aaa8d,8d42ce59,86ee8ffe,d4dc8a48,81810a6f,cdfa9519,46f00857,4ab1c3c7,d0f29fd1,32bd65d,7f9820b6,830a3e42,8664f9e3,9cb25729,1adc36db,4e177187) +,S(83042093,46ced0d5,a33f491a,c98aae7d,51f17ea4,1e5722cd,29c47f15,49c183aa,1f680d05,ca015018,664dc767,4de0305c,b09efffe,e7b164c8,c733d2ed,18c15d8f) +,S(339f95d5,5e293243,ec10b3a9,a8dba385,dcaa23a1,bb424bbe,4c894deb,c61cc881,3a4ec84d,67831768,e9ad1d9d,db82f785,52883fd8,b0b63bf8,38495a4c,455d5865) +,S(f94de87d,1123f6b6,97d4536f,7bb6a995,ff158060,b7d72b9b,3c9d74c7,1afb6009,f123cea4,bd4859b7,a852270a,17c76c06,e6050a26,9c035bf3,6c505fc4,1fa81066) +,S(71341ad1,bbebbb4a,17a7701d,30dcbf7e,2a70b901,5f6c5ff9,9fb614c3,d3338fca,6ab14a0,4b4956d4,a687acaf,30d7997e,cf70df2c,b49356fc,5b86453c,5ef6d55) +,S(79b8571c,f52ee30a,4d3632d4,965cc6f4,cc6ea06e,fe1cb7a6,ca2c9c9f,1e835bfd,259c0c7c,b8fa8345,57febdba,2183042e,78f8cfaf,24a41dd8,2eb0ad3c,426683fa) +,S(f3ce9dd9,d879e70e,21737426,dbbb27c9,7af84307,6855bf4d,af141d55,5006e402,302a436c,f8be3a4f,dd70a9d1,8f63cc8b,ecd3ba1,ddc9aa3d,f4285239,61e7553d) +,S(4a66f7b1,52a8cafa,78d0e98c,2f8361b9,a0bbad47,d23b24f,5184477b,e90d6318,7555fd5e,87676154,8f7afd4a,33511daf,b3bc4a72,c9f54d4,92327a2c,c235c02f) +,S(cd3b4037,5cd6da61,ff432898,fc592175,c90fbc31,373489ee,c988f280,3459bba7,b0e86ab2,2f2d8d97,5f68a7ab,3ffa3be,511390df,5b647608,fb07f29d,3155728d) +,S(e96f166b,84d98bc5,41ea8885,f7a48612,227bc907,795782c5,d0e2325d,96cb44a0,18ac220b,8def89a1,e3bcc2f2,7a66c0ab,3ee27c3b,882dc16f,e2571963,92b94310) +,S(87adb3fc,7fe6b07f,795bb7d7,ab8383eb,a3f91564,ce89d267,599657b6,9d793838,68677cee,bc7b3d09,efd0f118,d392d0f,d2d5f2bf,f2b50230,e127acb4,97f5c886) +,S(fdaa2f5c,ad1da3c6,3d241a7a,b4365e63,8eede0f8,229a8187,6cd76a3a,7020c545,5b04616a,a1a84785,c4315dda,da6289bf,e57cb9e2,80c42395,a1b13d69,dfb2ddfa) +,S(7eafa986,1a94fc8f,d263cd4a,1e481e1e,8bc1a385,c4ab748,8715b032,3bcdb52d,d655b395,607bb0b,c9092364,803798d8,17a4bdc9,a30e2844,94be8322,42af9949) +,S(a7fe4656,98538c32,844337ea,bc90fb49,feaf2fcb,8b86da6c,d173bf9a,70e62a53,cfb26d1d,689a9075,55057ab0,d4261e2c,acbf30d6,cdd09f95,9cf1830e,5d635aad) +,S(8bcc3b82,d543f365,478fe32f,dc9860f0,10d51f74,b7b5344b,ca6b868d,3c11264e,6bcc32,f7ff3e48,fa1775da,44b64848,f52329d7,d8bb0a09,338b799d,7452b4af) +,S(faf9aa3e,f1ccd659,2feb2add,a1b58ed8,27511b39,bb981cee,4fbe47db,5cab2917,854b88e3,50a6e9a1,fc7e9e45,f3fdb69c,8111c654,877cd620,fd82ee18,ba2d195b) +,S(77012901,ea269067,4d8b4397,e8976f98,e33b1709,c81624a0,7916da35,af75cb29,b63695d7,cc896358,e119eb98,7dc0f67e,22a70c5b,5e6e2072,e61ef62f,9333bc4) +,S(127602ed,f5f1a04b,813e2b6b,2c27f50f,803b70b7,b9525b7d,902f348e,c03591a4,1f791f7d,2427532,968f7a08,f94df6be,a95b7e6c,5490fa9b,5eb5a3f3,207455ce) +,S(17e82c3a,3731a73b,36501eaa,fde3ee8d,ca9f2573,dae1e4fc,594cee8f,e1d19179,8af04092,79792fe2,273e3f0c,e642f3fe,edf1ffed,59c5826d,a7fb2716,ed365a3e) +,S(3c34e27d,5d5737b7,78e968a7,fe8e4113,f802bd30,1e0367ea,41fc8b5c,14b0dd84,67bfc61f,bbd062ce,6224e883,9092a962,eb3105a3,b6634dcd,d59c61da,906a4ce0) +,S(b7a35907,c7b55a8f,7173a5da,c73e306d,64ee0f6c,cf4f5c76,3416bd4d,4f5359f4,d111c21c,e5a8674e,3a64adbd,4f56b1c3,61350b,44a552fb,19186b8f,95ed534e) +,S(6c7d4836,62c28812,7b904cc8,969ff925,8d9fafae,e88f6d3a,e6e4d771,bf8ee7b2,b593dc47,3c29694f,95b00169,286e3981,afeae4b3,dd7a788d,f32a14fb,6e6a8e7a) +,S(dfc406d7,625719b9,4f709993,c5d15062,4c725ef8,eecb2308,bfeec0b3,6050bf4b,651c0d2a,fb29eab7,d4740b5e,1fc2c069,54ced865,7a6bb980,2de8d873,a451717e) +,S(1631fa0f,4e9fdf51,a2842994,da94f835,52b5bb40,348c706b,54079073,665c6bfa,de202803,9a8d1ba5,b133ff28,6df237d2,a8d73343,a08e7c2c,4560954b,eda5ade7) +,S(fc52b3a8,8f712053,2c7667f9,62146d40,eaa3e924,327d959c,a49b74a7,da11e5f6,7bf890f3,daf8f9d9,49e800de,8a3f5458,5aa46e2f,25535cdc,18170391,e2101daf) +,S(6b7036e5,c5993c6,8a744776,abb0b5b3,31a886b4,93e49d41,bc7d93b2,28566fd8,6ebe771,42a56189,f272b6e8,8f70f356,ed1a3d37,ea2d5e4c,998e47c1,319e2ec7) +,S(b13dc5ee,7333e3a,4b13628f,7ef96ae9,4faee9d7,3a46297f,f1e357f6,e7a57a48,4f30b474,99c66456,33f5b521,9164a890,d8cdb78f,8c7ee211,1bd37fc2,d41bb2bc) +,S(1888e944,6fe20426,d4fd677c,5cf1043b,605e93a2,c8532623,b5951e22,34de08ae,9e1f4fed,d5de001b,378ad1a9,98e31f00,30af9674,c383f287,50172e03,ea0b0f81) +,S(2495b334,9884d5f3,166f8fdb,7ff81f9,9042383d,def7cab6,3c2775ad,226189f8,846850e0,2a1cc051,eea77bbf,d5f44499,673f40c1,190e379a,9b37201c,51a06e9c) +,S(e4c0e483,f21102eb,7dd2a78b,5a605b8c,410bafcd,f2ee4bdd,fcfe1374,ab32d17,b53fd34,568f5edd,a6a3abaa,2d2c3a4a,bbeef0f6,c37bec1b,fcf012c3,dac15b9f) +,S(8f9bfd7a,2e798812,eb927fc2,b0ad5eaf,81a0a30f,a97efbee,a1d6d9ef,19348a5f,1eec535d,1bee520a,13a8410b,6f3824cf,7c9d5a82,8208d2ae,dc89fa13,8bb7c2b3) +,S(1d95c760,f3fc2eff,df51cf0c,4b708538,efb56675,eba3ff8d,4f6abe65,d3f167cd,c2bb1122,5016ffe5,6859da47,4b777703,49e4e655,5da3d9a1,6dacbdd2,d42ab0a0) +,S(9df72bbf,fbcdc42e,adb71d69,1791f073,7f945e8,bfbf4e2c,68c5e3f6,5f6955f,24d47aa0,1626b0ac,ce77827,fd7daff,7424d4c7,1d76ad3e,b66d22b2,6f7d1df9) +,S(2df6ef96,7c0e1a41,2bb48bdb,f2cdf8f4,22829abb,4b7a42e,95bd9cbe,8b7f860f,bace2e70,7915069a,bdecd097,9d133cad,bcfedbaa,7eb9891e,ad3380e,9ca99401) +,S(82bf2a99,624e408,188da19,59599de0,eb947438,fcd45784,9a731a1c,15796028,3b6c668a,e5b8f394,3ee713c,a8fbfde5,8ef0f9fd,84054a9d,b626e274,37e611aa) +,S(60260fff,1f213916,9261edeb,5f1d2d0c,a143ca69,400b2776,21793c11,fbc89d41,bec4bfeb,9d09f8d5,cdb11e3c,f65c6a7f,d4aa87f4,e41d7f4,69717a64,5dcf9945) +,S(6391ed61,80cc46fc,33481faf,d21151f3,cb678e3f,4d667748,1a24a01a,c5e9180,c48495fb,fa5962b,44bfbc4f,491b89a6,a8588fe,91677b19,b872dea8,8e34026c) +,S(20807816,758361aa,d5f62d25,8e3951c6,da518890,26507a7b,c0ceb7f6,a96c141c,8526d53b,61c8427b,eb141d91,7a338fe9,f7789a60,cc1a4a62,15dc754d,a73903a9) +,S(1ecceb4f,8acc649a,dbff29c0,fbc62c11,498c7cb3,7d29ed15,e0ebdf03,e994b67d,1c701af7,a9f3d870,81efb798,2382bed6,5d56b8d3,f050bfdf,6da32b10,a18fd4d4) +,S(be82742,dcafe3ca,f646cf01,80202cb4,7086e0f8,ccea3c11,dcccd9de,aeae688d,236d1fd2,5e05d6ab,8651d88e,33d18a3b,caa66c06,b2b68c50,f6158717,f23b4866) +,S(15252ce2,3f666836,dfb47b60,1e642abf,6e56ff2b,5d58fc97,ab09f29e,1b4ec3a9,9a6b2658,f52dfc45,32e6b482,fe909e47,ba7b4442,3be4d474,a524df32,d6149913) +,S(b0429186,21f94599,f7032b4c,1b53bc6a,9259f142,27922f42,fe774772,4b0ee9e7,e73c32d9,ede68eab,e77d681,dd4cbd9e,a356fdf3,bf066f33,6ff2c367,59bed08b) +,S(5fe0917c,1bca66f6,f34bdf1f,dad88a5,b3dc5f5e,2e0227e6,5f3a79c8,9e66c888,885dfcee,c0947b01,71dbaf65,52c09ab4,c0414f8c,7373ec5,e3080521,401ed575) +,S(455985e6,44d9b679,85980752,a13a3f94,94bf9cc,8e6f10ba,fc7a70c2,27ce272c,47eadad3,15e88a99,9d3f5ce7,792ebc10,2fc68f18,cdfa1df,564601f6,3b26c22b) +,S(3562aca3,2291c1cc,ed072a4a,85fbf82f,6b3299f5,2626154,2b41840a,1c868d4,ab4b2656,11db5875,10c48284,7f72c75e,f822f46c,2e7760e2,a46070eb,5db7100c) +,S(54225801,f82406ae,74416373,7408e94d,d3990eb0,60581c47,b453a859,cf63042c,43834935,a6a7acb4,9c086391,24e80fde,72c0a876,1c13a340,1a4e48a5,d96f6a2e) +,S(3c253039,fc8278b2,8135e21,700af1e4,dad4263e,ddc867cf,a3532499,c2c1e48e,ee01ce7c,f8c56c74,1b4b3593,b0cb90a5,9c59cbe6,9a48235d,1295c1d1,ac657081) +,S(8adead1,d898eca7,9e043f71,aa735a32,763f75f6,f6ba7a70,bc47a284,4b580972,7a370bda,412df63d,5590b3da,80365c71,1267cf8c,e3fdd1bb,91ddb981,d213bcd) +,S(8361e522,34c8d62b,9051a95,8af3f090,4f15ee35,4b69a560,7155ea4f,69548037,ca2c329f,8cb65e8a,eb6488f2,2131c525,29df97bf,c8847c87,47145767,7f82c954) +,S(97d65162,d96feb36,e8f00221,52c92c06,2e97087c,703a9dd7,7241216,2262807,15a260bd,bd591c7b,91bdcbb4,c2684545,4706f039,8fef8de,9173e7fc,a3f31f44) +,S(2609f072,5ec8e5ed,4ec86128,dcee3baf,9e62bc24,aedbaaa1,eed8dd31,c9c07503,d51fcfc2,55398507,7e471397,ece94d92,e26375d2,2bddc0b0,d1b780a9,65caf2c3) +,S(820e8f01,5b4ec57,b884dd3e,6a740d90,68fce86a,a4833636,4b65ba6e,9e272357,bfc87d52,eaf352bb,91f071ab,6e986308,4f197671,298eb614,93152f54,345ce5db) +,S(2116bb76,7a56312e,71ac58f5,ff2a7071,1be5b711,1e9e56d9,aa098af4,b991db0,2ebd4fc2,abd618d7,d1798739,7e9b8eaf,8276086c,2a5066e7,e7525603,fbb4c40d) +,S(e43f029f,97f4370d,65826870,3f29422e,7b81112,61364972,e26892f,77eed56f,4e265fe8,40524def,23b7ed34,54c6618e,ec70d3b1,92ff30d2,1b9b6fc,b1f7164c) +,S(9b4ca445,5cada269,2a77f7e8,9aa3082f,ace4de3,898408eb,6a7d1cb0,8ac15c14,1446e397,d1c3fd20,283f43a8,4679e728,64f05251,b1d3bead,58aca70c,4c0fcc29) +,S(e2abb09,c0566f51,7947f99b,2d6fc4a5,637310b5,5f9d9014,84decbb6,ca22cbfe,f334bda6,a1d9cfa8,2b18f8f7,e90b8426,ae13e20d,8834e061,ab1671fe,4f4665f5) +,S(3579fd9,9cdf0be0,2d7e8587,2e213ed3,3a424650,5608d66f,8f936ae7,72511e28,dd93278e,ce754f69,4b3f09d5,a3c32c99,2c5f2e04,cce0a517,de750a38,ccd88abf) +,S(f307f2fd,d0f6c0b3,12841e5e,1e17b966,47d7ca93,4ba4970f,4f9c0c0c,3ccb071f,4829a5bd,40555e18,bf80ae66,b9742249,32679acc,d0e46003,e079e2e3,d20d248f) +,S(a462e750,9e718317,dbc72b9b,fce5909a,bdd2fc36,d56a525,97d3adc1,fe4b98a1,2f9ee390,13b70415,d2e6de97,7aba55ab,1f7c6f2a,a5a7b541,a7101a62,f2799836) +,S(72ec447a,245624d1,1e1270ea,1c4c060d,c6501f11,70c69f4b,229bb98c,e7c47804,cc32a876,33bb7d62,e660ba5,59cc1804,10a51cc9,dc48a9ae,fc3d8225,35fb8ff2) +,S(b97345ad,2a7eedfe,71ae185,11a3e2d6,c431e628,363e01a5,21622c17,e92b32a3,2ba1cb4a,abe0aaa9,619ea819,4e5c0222,3bea32fa,e4ee3378,ba798472,19670e2f) +,S(f417f269,de287f06,8a74a330,14331059,73ee691d,a7f5aa1c,4e00a100,1e2ccd56,1bb297c9,5b3fb72a,3263f126,719a82a6,b8bf415c,e81f6838,2c8b3a9b,42917584) +,S(cdf7b5d5,f7632248,be1bcc1b,61f56491,e81cfe76,1ee897c6,fcebdf4d,109b9b41,118f3f6,32f18892,d37a2aba,1c8d22f6,587ad56e,eacef09,b9202005,75ab7b11) +,S(3540c9dd,992dc4e4,9aba8fbe,8f28950a,24921b05,e1bae568,2714aa6a,95eebb81,841d9499,7bd92dff,53ee3c86,eafc5f6c,6ffac94d,3161ae86,2182caab,8d5a9268) +,S(70f4ef3,37a5519f,466cfdc7,ae779588,74c9a9a1,9a558550,8fafe6fb,d61decfc,413476f7,78f5d377,31aa712b,5c866100,bcc2a33f,ae1a078e,c5e5cbc8,4b7bac5e) +,S(d08990b7,ad5c205a,e5be2700,63bcf8a7,e13c2a,73dbf321,b0d9cdca,a1648da6,b0aa7acc,f47376c,115b0226,1494162e,d425b496,a2392aa9,254655f2,4db6cf48) +,S(53d6c5ec,f59c49fa,d970611d,b8423bbb,e2f5aecb,d4575877,d903d95e,eb88e455,6a954f77,532c80c4,42f2bf65,8e9d763,617c802f,369f1a62,34927e55,ac549f56) +,S(af7216c1,e51fbfb4,a5ec1e93,717f7375,9f15dbaa,86706ca3,6636f499,416ce194,4ed49771,f858a8c2,bad65a31,b5ea5a53,8841553b,accdced4,8c41e2f6,984470f0) +,S(c560d2be,2f2fa6d7,3f5224e,36acdead,8d91eee3,b99a219,a762adfd,a5e79d07,30d4b54d,a96fcda2,2187a2bc,1562d59e,24ab55ce,f9cbfbb8,570cd89,4d436343) +,S(30b40200,c728bdf7,510db9f7,a8a63792,ff70a9f8,c6262e89,4ef902b7,eb30fb8e,8c98fdbf,29f8c5c1,ce6d7d4d,61a2907,ab57b4ea,a25888b9,e8ce751d,6a19a88c) +,S(d7239e30,814ef236,5193c19e,dc91fcbc,955dab78,45b4f3ac,be994264,2a434e1a,454dc941,4500f4a0,f93f751e,1e2d4c25,8c0f10e1,b4f0c6f,3be39b0d,e5170dc9) +,S(60e511c7,7c8d7496,a3f262f6,376d3958,dfdc4645,73aa303e,a6e6672d,b1c21b36,bf86ea8b,c8a37a4e,c5ee1a60,d6e1888a,ac90530d,eadf40c5,b4f61a38,2ea1e340) +,S(55cd8f35,5a242219,3b64633c,27b1c1fb,7ffeed51,c815e1fb,ebaecfb2,3883d739,b6508643,7e53ad24,1fdf4dac,871e58f3,b5abb87a,d4920057,3c37a1c4,b2bd4b3) +,S(73cdc2fd,468a2d21,72a9e0ea,3d4a04c5,ab5fb13e,2e2ff2e0,8af5d70d,ac9bd41b,682e525d,1263abaf,f070bb47,6f754da9,f6c74d,27f319d8,5d9d2882,6d06fd04) +,S(e5f30676,3c9f620,1c5ada9f,6d01201f,97e36fc7,5bb10a12,4cf69cee,619f07fd,611f0f16,39aaac35,5e311a18,a5dd65ca,70e1a52f,452bed2b,3382ac03,dd50546b) +,S(c2c21323,b156ca78,5e53c41d,10bc235b,8e32e4c8,ee377fc2,42d089a0,d2a27d84,6b9f3faf,64331dda,d25d603c,d8f334c8,5cefcf5d,3bf640ac,96fe3bf7,71ce9cf5) +,S(599ff1d4,806aa8c8,b1440a92,9e2383bc,efd9b16d,899289a4,a335dd06,7e63d9,459cb346,7c387470,1b86aa34,c47b8214,7f48a0d2,7b9098bd,2b53d7d8,93e25316) +,S(f02ddd62,a2456e7,b4a90bca,1cb01e98,8b0a09e,62c90154,42db0f52,b635b006,a5666540,6cad4d01,aab99686,90a7ad3,b1ce936,957c317e,57bdb763,b8867583) +,S(f332b89d,1977afdc,aaf681a5,19bca58d,59852f74,78572346,b688d55a,d55a34b,988afdb1,afa1041a,51ed913d,d780b21,5dc90b8a,b5ae857d,73df2883,50ca78d4) +,S(d6fa4679,4fd4d05b,d6b7bdae,22a970f,8c3c3628,ea0d2656,55c0ebf5,2f1b3a73,d9f47018,86512ff9,9c4691a1,60b62e2,616f5c8a,fa2151cb,fd6dcd80,308ad947) +,S(2a13e09f,5c00016b,d974d62f,2c7c7ce9,e46fb142,e7334f5d,98fa2428,e26b25f7,f300cba4,26636d5f,7f8fcb2,bee6e5dd,b9697cdc,9f9c0636,b02b3fa1,820ca235) +,S(c6480cb1,c1bd41ff,e57cbf57,ea854158,36284048,e79dbb51,44a59027,13d13ba0,fee7ee1b,1652e63d,ad49736,8505b302,f135df7d,4a2f8720,74631646,244cd43b) +,S(559613e,8111c9e8,25fa96,aeaf4b2a,4019ea61,4c67446d,76305484,c9a4d7f7,cee9f4eb,2680a723,9187d407,f39390c6,4fed596c,b40f58a3,aa6c96e5,c8c9c2af) +,S(3a95b2b1,e6d19b19,84dcd59,501c33c2,4ca50b59,d410d99d,b9b6da4d,b1dc85ec,7a802198,a5c61542,81669bc0,640a8f40,6815d25,3bf8090,3ed894be,a1b09c72) +,S(5ae541d,b816522a,5d347339,713e92f5,25a637dc,75c9d9b1,5d834f2d,b265c2,e98a115e,f76b2102,7953f65f,cbbfd29b,a79b43ff,8cd6813a,b65174d2,b03027f7) +,S(88b5506a,72d681bc,d34eb118,3d6a7fc3,77e7f496,6d4c65da,bfa60a18,210ec487,c29638a6,ad91272b,3525ab40,1ebcd1ce,ecebab3e,b506cfec,e7e9df0c,6ee40501) +,S(2942de16,93ce8b88,e7e45657,daf88b2a,2118fb7c,9d2296ed,a1725ec2,f7d408a5,778f43,8b4f088e,fb99cb1,819fe6e7,55b0641,8d8679c9,d684faa5,16970f5) +,S(25c22037,e5a46e15,4adfcc47,480a088f,fb53410c,dea814f8,a4f2c387,df2afd0a,45cfaef5,5c5d3742,3380be3c,c38e6785,c85a90be,7cc92fa7,a390bca6,d3e7b3c1) +,S(b1f78a73,d0b935c9,80cd8ab3,b8237e3a,df5a40bd,5f875f7f,bcb13bfb,cc45839a,466141e5,d465c35e,37f80e57,c4923c84,c3a3ba98,549cc8f2,db6e0dde,915293b2) +,S(39405322,a57a4846,d8b42bb2,58f851cb,5570295d,71ded6cf,b803852a,8b4d8304,c81047d5,92fab5a8,c6139ffe,6887d966,e809d2bb,ee3a10b4,5adc5587,ffb302b3) +,S(7faa8352,31e2c6d5,b331ada,5e175954,6142b131,5347196f,bbc5759b,dd6add0,8779b0c9,2c176b72,5355bfb5,ccf5f739,5fc82ae9,48896a38,1be85e58,c48d154d) +,S(b786c145,61fe4677,54e14766,56d33daf,adddce8,e86e09db,ea93f1a,2ff0c3c0,4c5c35f5,99bb9637,75b4d61c,b30da8ad,a4e83a56,2cf7d2a1,fc22f06a,fff92aa8) +,S(ea4b9a9a,b4b509da,d1e70ebf,6604d624,8b6b63d1,c905720a,648e208a,993ce4fb,f5ab8356,ce28ccb,b6f1368b,344e15dd,372d732a,d8953864,21ce415e,6f0a92c) +,S(c986010d,6339bf7d,2ae3e9a6,c977b9a,a2033a42,14a1e9b3,e700abd5,428e2491,4156f13b,a68ebc80,ad12efe2,d5a0469a,a41adc0b,1dceb765,f651b4b6,b652a85d) +,S(385b81d6,e023164a,3662209f,5d694910,22e84b5b,7034e8ea,346941b9,c04df428,9d12b15e,c1868f27,362662eb,cb3c9bc3,1626ef22,36c2d75c,65e82c75,7ff81a2d) +,S(82196a55,104624b7,6710b4b,864b738d,36ebcfec,55226aca,990474b2,58aa978a,48dbd01c,5af9b1fa,21d88b0f,f6b994a8,38d47755,5ad85171,1a4e3d0e,14ab1914) +,S(dcfbdad8,34d74f6f,9df6c143,abd6dbd4,57f954ef,6323ff77,3a19c367,8d6616c,698d3051,8f8d7ffd,b45f0bde,c32c22e,2cb97acc,a8aa0aa9,c16d8789,a128c3a2) +,S(343b04d9,babecad6,5479cf60,e43350d9,8c56f989,69eeca59,5a5e97d,89c25489,14d00978,2729ea38,a79765af,ce78ff5f,16ada59e,9d275274,e6e0778a,facc25ee) +,S(25af2270,88a6beb,7c76a80c,9e87a412,ed166a71,d65d5722,a082e57f,8ac7bb77,d01d89c7,39508a84,5ea64e03,697c2867,5b14bbc,fb484f94,a530e57a,cf19ead9) +,S(1292823c,1759fa5e,48d0724e,67c93df2,c8ce9fef,9124c5b5,8a477aa4,dd3f5e32,c481025f,ece1bed9,26ecd3e0,3cd7eddc,3cc31836,a12855d1,639a85df,7c69650e) +,S(ed92246a,5a5cb2a2,1618deb0,794ea013,20560b42,273638cf,afc901d6,2ff0bb6e,3675cd33,825e611b,8802c746,9cd82b97,b659e31e,c31ceee6,681a35d6,2d5097c) +,S(8174e89c,9b3666aa,69ed3bda,6c73c572,ff3384e9,60863f87,b7d346bf,afd553df,154d75ce,caff95ba,4b5b7b7e,9ea99dff,499a522b,f0252691,cb6b92bd,98182d0) +,S(54169816,f0440f73,1f14de95,e7ab32b6,702c0183,62794ac9,e55ad632,95c4484d,12e541c3,ee64efd3,b5b8781e,bcc5e273,3544653c,d8b55d51,fa3f887e,d8f42465) +,S(c654d2a5,e31ce452,739f9cfd,b2784d37,eb974a4,fda45fad,13a2aea2,f7fdee9,47c9d2e5,24e7391a,f645ed92,cb04a0e5,6aef0362,9b57d593,edc85b1c,686ca4b1) +,S(59724a3f,eb1a1cd3,7fd6a5c,57c3d055,28fbdf48,5102e709,7ac35912,3f9c2ed0,4df18ea4,c0de4053,6bc5a6be,2df794c3,2db2a9cc,19367473,d88829a5,8603010) +,S(d99168a1,3fbeee0b,6aec4b7b,a0060649,1c4ca151,1cadddb9,2ab3478a,325b1073,c2b0876f,528de53a,f2f695b9,b8225fe0,4660a447,c9e9bd9e,4ba5e52f,beb0ce6) +,S(769c1b07,c26b402a,9a4b60f0,5bb0b318,d20f65b4,e941f525,43a15697,5a8f876b,7880299,413ffe86,94a76f26,9acde007,6e64a753,94701bf0,84324215,debf3d69) +,S(6074f53c,ddf9467e,b9fcc4f7,ea4b18ff,777abd8,895c9eb9,71195a9d,57b1b1ac,de1aa32d,e5488e69,eae8a06c,3c89422,a26f819f,af3cd9cc,762d7fa6,1fda3094) +,S(1f9ea27f,3e9e789b,1cde3fff,94bf8046,f5399046,867a2f37,2da59221,e85c655,c47b5ce1,3d399032,89449260,7db3f7a2,52a74084,20ab1846,fa378674,1e7bf7dc) +,S(c2551e26,5d3978ce,49cee376,ac86a0ec,7ba10804,bd894019,e79f51eb,ec9830c3,23dc4415,10635bfc,2af8f85e,c4cc59de,fed9e9e4,198304f7,e57a1f42,736871b1) +,S(2ca9e4d8,3358ea8a,40bc15b7,8c06169d,ed7a5abd,47147972,45078e94,75264d20,f3324029,9fe328b7,ecd14a11,6fd82bf6,5d925532,85a176a9,b7ec892c,ebb2cd94) +,S(e0db4052,8e3eafca,1f514b26,8b673afd,277c5aa9,e2dbe85a,74478d6a,f2ec1f94,f868c782,40dd75ba,3c6809d2,d62f80f1,ab7fead3,c67a90d4,ecc242c1,687376a7) +,S(d34cd3a5,764d99f3,16a260c,9659955,fda3cd9c,cb305f73,d3aaa61,27d422f3,3f3b80ef,74bec102,2e442e69,8fd4e28e,514d3a9,5011ba18,1299793b,b760da72) +,S(588dadd0,79d2280f,37dbeb16,3e05a70f,48ec61c7,cf3e6455,f3ea312d,4ab2e075,731a5c9d,f803c2fd,b22de461,d51af493,5874b745,4ab8417a,940383b2,9404fa3d) +,S(1731c955,931905d1,ccad3bc6,133f5d9c,9fbb10c5,e800be80,643ed02d,6d7477b1,d7e89b3,1f18ac07,6c7b7380,64d2449d,2d9beac,728ffa8f,6d8a7498,d43baf1d) +,S(e2f990d7,6818c0c6,e73d066d,5644e9e9,29f495ef,507b18cc,594871a5,88e45b46,2ca12307,fb565d0,7c60b6c3,e92c9757,45777970,1733c0ad,2b299a20,8f50925) +,S(b92872d8,a146c0da,ec576be7,35a22896,5242cc61,ba37313d,31b0e5ff,21a2273d,8178dd34,e552e97,fff949e9,b101b44d,35d6b57e,79c0e78d,f91ff3f,2817daf1) +,S(b980d2e,9440c3c3,be5cf393,6eb9634e,923cbde7,bbf2a07a,d7a97287,7d6caf11,51b7d51a,8685bf75,c6d376d,441dcd69,cac67b77,762f6ad6,97a9649b,f3d3719a) +,S(db2f9a64,3c3e3706,e9b5aaa4,5ebf08f2,ee9e967c,205a49c1,7dc76b8f,b20a3a52,d05d486f,ab967e27,b9e8c175,e93df203,4657dd,750ad788,1bcc4897,b80f3d40) +,S(5d5985f8,910be82c,538d70d8,9614ec3f,bc9e1f91,9a19950b,a8fc99d9,203d92b5,3efd77d1,27e43849,a710d1e5,7b18b681,c1acb293,2244fa7a,30f360ea,88565e35) +,S(fac2a758,a063dd8b,46b41933,9c70d2ed,3807bdca,69d3b36e,6369f8b1,23200866,8294340d,6154afa2,d7b730b1,301f5ab,322bdcf8,6fb5676,78fc47cf,b15809e3) +,S(cb92092a,d45ab0b8,559846b0,d02a0c67,a13edc86,7d0cce5d,fcc09e63,d1b6cbde,d2593de2,6371136e,390bd52a,c9811334,e13fddd4,e9b86b1d,942cacf5,4615b287) +,S(d715f4a3,66a4a770,bec8abea,49ab6c7e,99e9473b,73e479c,14011843,9470c844,40aff69e,ec6da9bc,38ec119,df4482ff,3bc2b67d,31284db1,8c757990,de6cd0d6) +,S(77312617,4a395a4e,f7bad07d,f2f38843,22293a17,ebf09f20,4732e7f1,2c418417,602cca39,d6352365,420c5ce2,9d2282cc,5d8919b5,e0669b09,22384b69,7bd48a7f) +,S(a7c4b675,f529ba17,e9f1ef44,c88a8066,66131845,dd98da82,4cb04f24,518a4071,d88edc2a,1eb0cd48,57283e3,f8658d8,2da27a7c,7ec16129,78fbb484,41ef438a) +,S(6362f575,d459b970,db814a7f,9a142605,f26f577c,4357be2d,dc16793,64906f7b,fbc9f007,bd08b6ef,cd49c1f7,1e199fa5,ede01123,5d9b015d,515bf7a9,7192f8c2) +,S(6cfc45f8,515813d5,dacdcbd4,c34c155d,c66b0298,8b8a8702,73a5342a,9249b623,f85c980e,394ea0b6,39bdc5a5,ed185de1,7b1f44cf,b7e51c7b,b9f56b3,496b5ee) +,S(d76c0b83,b8a8a8bc,4e8985da,f6f1535b,9ff3b4fe,e13eed4b,39d6426c,87cec8f6,15ddc103,bc6c4f43,6f7e23a4,78e47166,e3f4156b,5ad2d581,7f3a7ade,7d80dcae) +,S(c4f98324,57330d12,e4e26735,464f24a9,a93dcf75,9194fcd8,a2d12ce2,bce0449,e24a6f24,f9a09aa6,f58f29aa,f4e24a0f,864410cd,80280432,d82cd9a4,ea2ac2b9) +,S(e86da865,238fcc7e,d8c2721f,89c2619f,a2caccd8,5e05a21d,8d23a095,634cc439,85b35268,31871eb4,3323caec,13de6de7,94ddc6e7,5d44835b,7443137d,25ee2194) +,S(a6398918,6969469a,939e774,eabbce54,109b833e,b3dfb566,876cf50e,bdc7613a,c48430c3,fa8c730b,dccb53,451b5a38,888f2e85,1f510ca7,64360c9c,b72b6eb7) +,S(6986ef9e,88c8dae7,ecc8184e,a4c5d131,32a87ad2,ff8367ee,63fa0ecd,b7a2972e,e9acba9a,896e1eb5,bc1d2625,983fd2c4,13f54b47,3056a893,7197f940,92eb4bf0) +,S(47bf849a,e428bdde,ceb221ab,e0ea2fd8,c0a5bd39,175aab96,c2fddc57,e809527d,401a7ba5,1999aead,4dfa6ce0,fbad17e8,e7187e52,806a58a6,7033f653,67aa7c02) +,S(c0c02bb0,92af6a5b,73582a14,89067933,8b31318a,f2d5b142,d58833b4,cf07fbe4,a19dff69,5ead3a33,d8f9f7a6,76b8287f,4bf6b23c,6761b084,12d86508,830f8990) +,S(f2185913,405156ab,22baf16e,644063da,b3ba25ab,f191efee,1ff028e2,f7d175e0,814c64f9,9a4250be,2265cf8e,47c8276b,9e5245cf,16ec98b6,b789dd26,be894f3d) +,S(40d840cd,ac4060f6,de850df7,c37462b9,b4d5892f,a1e74f35,89ab3955,a5d941f8,9892b0dc,ff43a872,6974705e,3a3fd077,c2b91a2c,1c6ee153,7b728359,d3217833) +,S(6f6b79e7,9006fe48,5546c3e8,52a33dd1,cfb63f3,96b44d1b,af1fb112,93271b35,f5aa0beb,50a628b7,b5348817,8344527e,d1ecf0ff,a0766a78,faea2361,e8fde7eb) +,S(4edf60c8,c0488128,29e7bac8,7b03ce49,c8df0f1e,6a3e02e2,ea8ad097,f66163d7,9861393e,fcec430c,c00ccd49,3d4e2d2a,a45e1034,fd9a81e4,b015bd5d,56f16dea) +,S(7ab0c44f,f6a444c4,e0feb1c5,a6650c37,26249caa,38f53e62,b6bf225d,bb1e008,e7f9af86,a2839ce0,80c6ee9b,d86529eb,7a7abaed,aa6aa4e7,207e67e1,a500e5f0) +,S(6a90e50d,3dd2f382,1dde8714,57012b3,5c1103b5,80ee4982,f9bb78d4,2541f8b1,5ccd34c1,8455aa76,4cfe6c9d,61507ca3,cb613bf1,4b9eae3f,8391e1a0,9dec03f1) +,S(289d4d81,cccf40af,a61ef56c,242ef8a2,c9883267,54139e1,dbf018ad,5d251df8,f3fead19,c49de6b4,32869220,7e60408e,dcdfad25,26e6e555,9b022941,592081cc) +,S(a1ee466b,c561919,2e82a316,ac3b7514,b109f442,1c93fbeb,234f5862,d37ade3c,db12d4b7,246e8ee5,55dde2b4,9b5c42e7,408eff9c,a853af00,5a6f6c7,73aff21c) +,S(ab30a856,403a1622,14be9837,2ebaa8cf,8d946074,abfddf2b,8e65e2aa,51554329,7a6b7f22,a6ea52be,8c0c8002,29613020,a247c026,86eaf960,7fc56cb7,d696c56f) +,S(17c5f1b8,8e3e4e08,dab8a5c9,2a679c05,688a7437,df6336e8,7b0d22d5,ed56e5b1,96068e6c,72fa9b39,5993913b,305caf70,3186404e,17131b5a,24e14273,a83dccc9) +,S(a76fbdb4,b99e31ba,c434462a,64c0557,8e961a53,dacb9bd7,68400b8a,823190ec,52e31883,5ac1a3fa,e269a4d3,17bab065,7e890844,c3fe96c6,d04fa015,89c89f14) +,S(17b8bb76,10476261,ebd75e4f,299f1805,5c88f36d,ae65cc57,3c959820,25bb794d,1bd9a52e,585a40d2,67db59c6,b9b1bc59,4b8d5344,29b5d4b0,82bb1c9b,b54e0392) +,S(65aa92ba,8fa51cbb,3954b93d,68cfdfa4,d64d97c0,9e099b1b,d1ba853f,18500b37,a2b12d21,b7a1ffd1,af48e4fc,e80c6fc2,e624783c,7b0cdce7,9f01ae7a,5fc96e14) +,S(3450bcca,5d3b30b0,3743f0d2,6b61ea09,de6ef7cf,eed44b3a,c58641ab,93ad7867,4fca3307,5328a298,d310d447,4806f297,3b09d885,9fa3b949,11817d8,39be66ad) +,S(484bf072,134849c7,695ba73e,5f25a8bf,74a183f2,bfe35ad7,34b53878,a2036be4,a5295452,a0830b3e,3c45043,43fe950b,3289d402,73d3bd49,6c0cd7c9,156a1d6a) +,S(2cdf1bc8,920ec641,63fbc8fc,c72fe5c2,dfcb87ec,15725e04,163e1ac5,1b7ec763,c680476a,28f054a9,ac3a073d,67ceecf1,c8262ed,4bc462bc,44798e88,d0e48e54) +,S(59c3c60,8031a214,d3e6be15,c644265c,b6f3526c,2b37d840,86532c24,52359bf9,2248b28e,922e0468,fd98856a,41ca37ec,2fc7bcf9,a13c7a9d,b4135e28,5cdc1bf5) +,S(4f20493a,a7a1e558,a44e54e3,b81c889c,d45b6384,9b8448d4,20a34a31,c7c451ef,bc1adcc0,d00384e7,93c2433a,a76f1f08,b8b23170,6e285d56,3155dc19,d5aaaf1) +,S(bed9949f,dec9813,5bcf76b4,83117fca,57525221,8a6a52c6,a44f2468,29d48ff3,6ab35499,8cad07f6,250dec89,a0840192,b62777df,6e241a4e,325b0c4c,bdad23ba) +,S(1cf32b2c,46deaef6,fbc892ae,4f05653a,3cb69d0d,821a7125,3c2eed77,4e75f767,caa6268b,b8574b47,840b3626,74f4a479,5a2c6478,c440aa4c,36d88a2d,ebacc8f6) +,S(9d3f7c5e,5e0947cb,d9bef5a2,dc1a3e9e,ac22d6a5,9071d0eb,5f270100,3e66dc96,6ad63f62,22f3a787,9544c330,4c3ff653,2a00a764,5ddce01e,c4ac4933,a5c7aedf) +,S(a5a927a3,f03dcbc,b3d069ec,156a6ba3,474f48cd,4828f54c,a673e10d,265eab6c,b5e360fb,39f65847,b63eb29c,a8b403d3,272d9ef1,8127d3f3,7650d13a,9a5736c4) +,S(48de778b,7bf72a21,871ea379,c02b8887,5da9688,37faeaa9,93e68eea,926db673,d25cb808,7a7c13b,fbe8b1d5,522ac2db,6c44526c,13ca0327,586d6a5c,1aaca91a) +,S(a029831,66e7cb1a,fff65515,48faf447,cee8ab2c,d4937269,db002cbe,b8f1d1ef,ef34ec5,42554e97,1ae8897,b049097e,3430c99,d8e93c50,94377c07,a5619ea) +,S(6ed75b96,c4e976cf,75cf0b72,df83c043,5b15d2c3,f8fb319a,94a4d97f,1394df6f,9b63c36c,1e31becb,e1a5a6e2,1abb99d0,d5c39694,cec00fd0,ffc27b53,309bf6eb) +,S(9372c1d1,6997f792,688a55f0,8f246cb0,f206ce31,d0f416c0,c81cbdd6,8487aa5f,ff97433b,be60eaf6,6f19c182,e8a8bbbf,b24cdcb3,7aabf79d,5dac9f13,9c5033b4) +,S(269c7d84,b42f90b2,f39b4db7,5ea0724f,fa6a1a5,4c66a1bd,a21e4254,6f243bf6,8f6f8b36,e278c6fc,bb0c9918,7325f1b9,75ec3add,69708be1,b4703c5d,53d8f8f5) +,S(62f9cd79,921ec46c,d470a12a,9619ad4e,3bed051c,14f47071,e55f9da7,d103793c,92211db,6c846f43,2867b9ee,3b1ff00a,a08f179c,13aa7475,d64d0731,23a69e4a) +,S(fa432dcd,e7e3b40d,a127d65a,e0955d58,a009d81b,46b48745,c4e24597,4e589a8e,a8dee557,cae7e50,d96555ce,c56255b7,c64d10b7,6639b3bf,8d60aea7,58716f68) +,S(a424d18d,c6861074,40f42e5e,f2bfc95,f4c8f94f,e3adf681,79086502,fd9d80a4,cb30797e,1d973012,d488f54,6033b1b3,d6b50c8a,39badf8,fcc12bfb,3a1c4d0f) +,S(c2a6369e,e2857d2e,fce4ab31,49556c08,3ac6af90,6be418e5,ddc5677c,f2f7ec8d,a7097ae2,9fea3774,11ce3f81,b6b3356c,9a2abb69,986ad81f,46b13f8e,a0e7f0a1) +,S(f5eac1a2,3dc91862,d8022931,3be5c7a5,364c0880,23c0650e,53e22f42,2f91ec98,7dd62b80,3ad606c3,3d8d9bd6,cb397ab8,1cbd688f,8375a405,23bb7315,a3f48c24) +,S(dd94fec9,3bf7ec6f,cfa0ced9,df31a1c,131c39d7,e110b5e7,b988c59c,dd594fec,cb858565,6a32e03e,2eb84732,4bdfe2e6,3601148f,7bc7e56d,22cf9aa4,54f063f4) +,S(d3dfdaab,8f9db2d8,edd3db27,d96be5d0,678e9088,5448222c,5b3171da,38fbd501,6b210554,df32021f,35170e13,42e2da18,72be61e9,481a4b74,ec470ed0,b942025c) +,S(47ff9918,3e452838,f63eb828,a239d95b,62f8a746,8acd0b43,6c149985,2afbe3f9,33b7b8a3,a5b51b15,fadc1f9,baec6b8a,88e0da56,5a54bea6,1b2d728f,eabbdc48) +,S(1e99e92b,aae56401,1cc10c94,dac071a9,27565a17,2d6d4a20,224e1b49,c007660,914b98dd,a92484e5,a43d7de4,7bbf57cb,2346d852,f743fdd9,15dcedca,4393aa21) +,S(e150364e,d95ca778,70fb3367,64f9f417,70bb672f,7e794416,13678dd3,65d84fc8,23ddee4,30d7b565,cf545837,58df61fc,502bf86b,a4cbc1cb,7630a9bf,e339ab85) +,S(44dbe753,dd822ae3,f3ef4939,a1d96a98,33e697f8,c4979191,c64114f6,71e8fbb8,b909bdb1,e6e55571,b03517a3,c2345b49,a5793d21,15fac018,2afbefe9,c726c8d5) +,S(fb843458,725d557d,b1a17ad0,427b4d98,6ba189e5,d6da81a8,81867259,6d9d2858,18f1c9ea,bd8e71cc,72e2dcbc,532b101,c7381475,46c24790,d010a6cc,32d4eb10) +,S(48f43c41,b63bbb05,57f8d71,edc739a9,57baed23,efe9c814,848c54e8,54159144,cb75c418,d5557cfd,b29d4807,3f193343,6eafc209,bdf9685a,72f57b98,6676b193) +,S(5520f175,9be037bd,cb5af2a9,a0bdbcc4,9e1531c0,32fd17a4,66f59b38,6d7de1b7,45b933b4,cf256aa3,c6513a2,8a4eff90,7691a34d,e6cc2e7b,a0b83f8e,a7ed4e52) +,S(83936718,1d7d065d,5c15e246,ce8391a4,bec58c71,7f82419a,ed6547c,63f081a9,4c903568,f5ce9a54,65fa845f,985f24d7,6e66cbe,3ce256fc,1703b4b0,5dd636c3) +,S(66a82c47,e756062f,6586ece,86911ac2,23b84c9a,e53e5307,4e22bfbd,3eae6b30,ab2051c,4c231a40,c6da6ac3,5ee32b9,b7eeea17,222cb1d5,a3abf9b6,512db8ec) +,S(974ce35a,9d5a4ef5,84d252dc,3c365423,1335c52a,e3daefa2,8ff9b75,56bf3b46,8c82a9a9,c49d167,4f3995c2,90ae06ac,fa0a5c14,b1c5f41e,c1e449d9,5effb2c0) +,S(1139c2f3,60cb8a4c,e020bb8c,3d19bce2,1c6802e8,5fb3df33,8fc9ffbc,8fc231b6,59adaa14,7980b3e4,73801b73,9f1e0248,2e9f1e17,65df2ec0,183d9f81,d57723d6) +,S(c1bd3793,3b03d95a,b17c10bf,c5167556,4294e38c,740fa3ef,9b356be6,71883b94,c68bd82f,5e926a59,95a83f1f,1a8c2f4,5966b073,91ee74a5,ae2ed99,106c6dca) +,S(c7778ce7,ce668003,86db9263,cddcf608,aff769e4,b4755858,20554ecc,8407bbf2,92509200,9c57f224,8f9b4e71,532c698c,88b91b77,4a3907ae,1ef30c51,78d807c3) +,S(14aa1177,51626b67,8f32418f,1855cc34,52d4ec13,d2d900d8,8a22432c,70ec022b,6151fdf4,f4372a2f,e803478c,da340678,c18a0a7c,d540b0bb,4168f9da,2edd6d81) +,S(a53443b1,b6065cb6,abb18c84,1f171b3c,7152b34,293a7ad1,2e8599fd,f1398cd6,3a07e076,35254aaf,eb30efea,328e3ffc,3a7d280d,5cb2c8ae,9e70b412,38fe704d) +,S(35c3e3ab,ba4c946b,1eafff67,a9831588,d6631e18,9507eca7,66e22449,f8d294fa,94973920,58f6830a,4e5f413e,4d7d442c,4348328a,5115fdc6,ae5ab638,339e313e) +,S(1aabc2db,5ac6df10,1d097db6,26e3623b,295ae6c9,941e3717,ca849065,512a7fa,2d2781c7,b42ce42f,b40b737e,9100ea24,ecfdf58,fd724244,dd67d84f,4a6cb097) +,S(383103b5,5a4beefc,89dd082e,f0e14211,9bacc5fe,8acde710,7429241e,f16820ca,2000fe09,2b820a28,f065924,7823d6b5,18756044,1856dc46,a9fca8c3,84913398) +,S(2cb0f0b6,35022212,88b8be63,a0ed5d71,bc6b89ca,4b2fb4f8,54123124,49445107,9a9eacc7,cea4c27f,ac63a2be,96884112,435d5f6a,bf4ad519,461017c6,1c87b2a4) +,S(ae63a05f,306e6980,f439afe1,b34c7b3c,1453e110,e477e3a8,d7e9ad3e,fe2af088,6facce76,d579afb1,cded78a4,1dc64c79,b6e90279,d8c5f07b,fc2b0a3c,7243b309) +,S(83207533,78d5c6ee,ae26aee8,4f2a0833,a65a94ef,53a477b3,c8708ac0,35dbc24b,d8306300,4caf8d6,7fdcd09b,267a2d5c,b0e83e97,60fc4d8d,2b07e2bb,c2b387e5) +,S(f38888f9,3337633c,9873d501,8b9fbfc2,ad135870,89f6becb,528ea063,a817af28,8beb556d,8e5342f0,6fe06215,891e6091,f8b940fd,b6eebc08,ded95ea0,99985ecd) +,S(c15cc888,7d13a93e,c2411ea1,6f21e86e,4fabe47a,55a94a6c,aff7681e,d47ba1a4,5bcf5b68,91f3e01a,3754fed3,f70e5052,e33fb62a,753c5f3a,532112e7,f7f58f55) +,S(9b3b0b21,1befb305,b02d035a,1e7cad04,3b8ce04,f9315bd6,5067a73,f2680030,75828df7,eeec11f2,e0dab801,5c75213d,cd93cc84,7e873e19,b7d03eab,e368f989) +,S(2028eed7,50cc8973,c1ca2f28,a30c05c7,73e2a05a,db916825,60d41cea,3b4d0a18,40efea34,b941571e,98a0878f,a13c4efe,1e3410d8,d5166661,115cfd55,53bd0d71) +,S(ca697e9f,8954a7cf,593068b9,1078486b,c8c9a71c,d1f7a890,a0a3e0ec,e48521e0,4268dc9,28ef996b,56af66b4,2f410831,b9f8c6a0,2658d706,975a7624,6468322c) +,S(26c2615c,ebe251a8,a78b00d8,1733aa70,f8f9a97f,85c2fcb5,d9287e34,b786d4d3,ecd17c3b,e1b3232e,bde8f859,39f5158e,f8c340ef,cec4e758,cd54eb7b,df4df77f) +,S(7296b5f2,c4ac6a83,c180cc55,2fc79a84,691c50df,8e56ca8c,731ac368,2d8737f,d4410073,1f98235e,cd75e26f,d251bf8f,f93ee806,52446208,c9643fc1,1b938aaa) +,S(465d9610,c3f6c8e7,366ff5e3,9e1e17be,53ab9eb9,f299be2d,3d9dfe6f,fc601a5e,741cfef2,cd41ca9,4b847ad6,93f29e2c,7e0bef4e,6244dfd9,8e3bcbeb,8c3ae7c) +,S(d3264c87,fe435796,b4d40631,a0a64a34,570e36a9,809d98a3,7ffec23d,9f3775e4,e6fa5190,b66bd281,538787c7,40bdaad6,f37a1eb3,90b19c3d,cbc65b19,9bad22ad) +,S(d925ed62,5551d49d,151dd55b,2cde29d8,fa5dfa21,e9454c17,a834f090,7d744640,e398cb93,1c9fc1ea,d9912968,b335015d,162a04fd,c17049da,80a7ad4a,b3b21451) +,S(2f8339f7,72cc9ff5,c59ace6f,d38a13d8,21562e0,a0d5dc2b,a2c074a4,f697413f,d09d6be4,3678836c,e110e805,68a2fbb0,b87d1657,d568d7d0,e4ba1237,dbb4fa4a) +,S(f954909d,f67de727,72437ad4,d3229c50,8440d23a,9215394d,d09c7232,fa5cd0a3,6656c1b9,8e726305,644994b1,eed6234a,834f74d9,2fe16ec2,c945478e,ec53fafe) +,S(962b9348,d9b64aec,7ae38297,e80a5f80,ee1ea253,6964742,99c5196f,cd58f33e,10601c5,87838f02,5b6735c1,b711141d,ed04ed16,2fdc5bb,4dc593fe,9b804145) +,S(b70436c8,4c6e25a5,34c3c2c3,34f13350,7050b552,72a04032,84a744a8,6336efd7,1b9911f4,72a19b13,e8bad704,ad3fc911,3223a5ae,4939138f,86422536,da1009d2) +,S(8989063e,49605ac9,78705f40,cb916505,615cc465,40c4760c,db302cc7,a9e4c6a,e76c05d8,5b32b5f1,9913472a,be4322e9,ff5149e6,e224da9d,dde930c9,948ce8ca) +,S(9e2c1711,29d01e44,25e4d5a,802f4c5,84eaa0a2,2aa8fe0b,bc0aecc3,15fb00ae,b1385087,ff34618a,d126ce7c,dac3a7f5,1f0fec09,2a7a9601,b65c2786,c733fe81) +,S(3a88a3cc,164795e9,cc668d88,d9ffb6d3,52f90edd,c6b0aa5f,dba493e7,273731f7,95f0b3f8,2fc2c9c8,a25b337e,af92ca08,e17ef68,ae5abcd1,43bbf5ce,d68a1fd) +,S(f5cc5ffc,ad18ea3b,c15ed2e7,d0ee8e9a,141bcd7f,8e6fbe1f,81be287e,e7281725,ec049ad7,6ae3bc58,9a60bb7c,ae79dea4,b512fe66,bd812ec6,91fb3182,27d9a288) +,S(c8af958a,201a29a,bf880688,89c211c6,da59b59f,ffcc02db,9010bd6,65b7ccd7,3755194c,76d6e0a9,3f2424fa,f26a512d,f0605393,ecb5216e,d5f1d452,99b247f0) +,S(16f10ca2,a11493a1,361c80df,40066683,93c02635,78f11f2e,d9153dd5,5d6019d7,b9fbc23c,39323b8f,6fcfbfbc,b1a4b81f,e7eb1bb7,2855f46f,5379c68a,dc4680dc) +,S(1b218d55,81d012c,5e804030,ed342308,29675ecb,e1608d75,1ac1fb26,434744dc,8ac73d03,b888545d,dd8d0321,afe66cdb,e8dd7c6d,f1fbc3d,74f7ca46,c551f357) +,S(d16f309a,820828d5,e2d30f78,2f055428,fc8e7bb9,dcedf9c6,34640c19,7562685c,1f27768f,9a2c63f1,cda9f0f4,132f41ba,dd48a03e,5e387abc,d6c73a51,2d1b23f6) +,S(75c161ae,1b38e93e,b623305,e2566957,a277e515,44c2fe13,e02ccb8c,c72886bf,384bd613,39e4e389,5cddf7e5,b0cce8d5,35c03c29,118624c7,32b75a23,a9befea6) +,S(3327a22a,c4891ceb,2a704a19,e60d04fc,64cbb0d1,dbd5a1c7,bcb2f4b9,8a1d0d2e,1ef62067,d81d66,8a7960ea,a63832eb,5c6fe33d,3ed99147,b7f68eec,cf81551d) +,S(8c9fcb52,65eb08d2,90cc1f6c,9c3d70f0,2b553119,2a0c96c5,f59231ed,370c4036,c986a64d,f3972c00,5618cae9,4a84e74f,2566fe4f,aaa0e2b4,d3f52e9b,4acee6bb) +,S(2465bc60,19bab7e0,72bfeefd,9d974124,19bf47c3,24477dd6,c83ea3a9,e9a3f353,675034ba,c62cc0f3,afbf5027,23127859,280e2b2b,91aab521,9b48a36a,d5bcf77f) +,S(3eaaad77,af1f4e6d,a267bce9,e7095672,c44deecc,a71ec3b8,c86d8774,ad06805f,8a3277fa,6247ad67,e6aab22f,a7e7375c,b95eea16,a055ca8b,32615122,30033ff7) +,S(21734e43,c3ab4ef3,55d36330,adc76a02,7fef2658,92c29ea1,a26972fe,48c3528c,e1d82d68,612ba50f,cba70f17,3cfc17a5,d2d380c8,d62322d9,e6e93d3e,475ea6cd) +,S(d21f30a1,19f86a54,2c7d74ba,20796cbf,dc6644fa,2327392b,3aaf9f9f,ada97235,22d5e9ae,2940960f,6722d2bb,c077d9ac,aa12b5f8,b9a404a,e28224d5,5b604f6b) +,S(41741846,c3c6355b,69e39c98,fcedb9b0,73a5b526,75ef5388,819fbf5f,ce1d00aa,3978dffd,d11f4f53,ae1f5aa6,a04153d1,e9ad984d,8feffa10,9ab57fe3,f58145f7) +,S(cca0a89e,6612524b,a9c318a6,879ef971,d346e29a,4cca7c2b,4619a1a3,1f567163,8ed2e1b3,587cb5cf,37e18db,e9a95ca5,17795137,a8215cd5,293aefd4,92b74dd9) +,S(dd3be3cf,83feca12,c3dbd1af,a9166d2f,138efa4a,297c742b,778da203,dfff3728,b0a156d2,93dc289b,94abc958,f17cbdf5,94f04cba,15b71ed0,197e239,8b56976c) +,S(6c535f98,868e9ec3,31135e87,b80aae3b,a0609455,8d426bdd,3dd400e0,344a3cd2,30bb8bb3,4ccc439f,c343d3cd,ceabc511,3efd9087,d17004fc,37f70d98,94e3c04a) +,S(338bec98,1bbaacd8,8b82a53d,d1ec2ea8,aaf7fcfc,e5f502c0,a13b95b1,d5fd9000,dcda1b41,ca43c103,f0c6b294,5f9e94be,be971eb3,12f18197,b4dc795b,1efe13d3) +,S(b70accd5,24961804,40dbb087,c3c11f33,f27c7e9,886aed80,b89b121e,8d51ada9,6272d04b,3ec35419,be43ecf,72824127,ae4fd87b,640a5a4d,8e8ea05b,5f3f9b6b) +,S(dbf05f1e,b489594a,146de62e,c9423699,a7aa2d19,93919b0a,2a26b53a,a0f1a033,9608352e,a1abfc2f,47c42ed3,8f1d2ee4,bb28ce2,9dc98325,eb137acc,36924d65) +,S(56e94226,a4237f18,c57b5ffc,cfe795cc,b11522e1,fc47d549,6dfad2a7,2f109783,f137a96c,7965b8d3,2eaadbce,d86abe0c,5ee79de0,9b94bf60,8d72a4d8,8cafb542) +,S(c206cc19,28af717e,63e6e7be,781ea37e,d7dd1766,f1553fa3,2acc34ea,c1157bfe,78963ba6,f03b670d,602fdb93,d71dafc5,bb5ec7,b541b9e3,a84d42ac,1a444e29) +,S(8b579cc3,6455002c,372bf1c3,21012fbc,c29e102a,9acb149c,93c651ef,e3dee157,9fa8c521,e2f911c5,3438015f,48134dfd,66fa5acd,8916902,c1aadb94,7ceab096) +,S(3ddca5bc,e582f08f,ded36cce,395f4672,9fbfe7a2,c9aa3479,7fd2e332,352daca8,d77a9165,e281ae70,f1e9a265,630acb60,bcb79f30,9cd926b3,550b6c9b,644e5e6f) +,S(ee7c92d3,d81c3d1c,6384c771,b609de3e,e4979ce8,84df6312,fff84a0a,bd5e662,f131dacc,28415d22,729f2b70,934ef8e,3033b7b,c5a38dd9,1a11e4b1,7843978d) +,S(b9f80abf,ab86d596,521bf2d9,cf500e15,adedade8,b51fd8fe,c1d8de53,f4191222,82548186,bb97991f,1f28a93,804cd0a6,378355b,f7c7ed41,4cd585ed,af0afdab) +,S(1ab67bc1,50fcd943,f0b3419f,e5de2969,fb4428a0,b90981d1,a3893c6,18aeeae9,56fb8eb4,4671006a,805e161e,6e3f2bb6,b0199659,667967cd,3c72ba65,97a2c39c) +,S(17425974,39a91dd3,72c09b53,68d9821b,2acba5bf,a5440118,ddb5c494,fa0a807c,1b73d3d8,5eaad3c9,b37f7451,2a7ddd17,97e10e71,b640a820,181757a7,6cd27cba) +,S(72b080f4,d8e812fe,b485361b,59213f59,cd708e6f,d2f7ee71,27af3d87,971633a9,5b9c6a0f,d7a6f32e,f26a4584,542c15fd,e3504935,baa7b48a,d67848b9,67229f32) +,S(94e5f999,b8927b65,a2f4d318,8e3f2fee,229e42b9,ae3e6b46,9f7ea373,d3f11beb,aa27336,204738d3,b2a306d0,4c6efad0,2ae3a431,1da988f2,c6c1decd,b1fb3c92) +,S(2f59f652,2f045980,833c45cf,ef8f3a37,d65ed946,9b3beaac,2167eff8,142e8a03,9101d9d0,60f1a770,9f604eae,4b4243c4,6096c041,2f861106,dc4b8d1a,d9f9b170) +,S(95a443a7,22a88b70,32194130,a349a952,67b89786,e33938c9,7bef7fdb,d211b54d,3d80619,399c0975,a67ea7b8,9a5f6427,ac454278,42f54932,cbf71711,3ae460e7) +,S(c8430fa0,2ce95d35,96eef42c,69f68502,100a29c3,6ddd1f46,daca1e14,4f382d0c,f26c4baa,4a6d9711,e6de2b92,5042c6e3,cadfe60b,93d4f385,d759ec72,5a32bc21) +,S(67504cc3,ffaedcd0,c5a2704f,af1aa41b,4cf489d3,5c23b6d1,4529f4f5,c49afa03,b3858859,b3749792,4d01676c,d96fc03b,37be7b82,aee57e64,a44ba433,2fd936c0) +,S(d4fd8a19,6a56052f,71e8d51,ee3db667,7465ea90,f8449939,be9d1814,86fdb56f,7fc64dee,2bf744a5,ba155865,fb722e11,f3087010,b566182e,8a39f718,922953dc) +,S(12810eca,7f3087,944d3dd2,69baabcd,491113de,99b36ed0,65520569,484fa7ad,f25d02ff,81ed030f,1e67e002,6680a3df,3f27edd7,76155966,6f043f85,f82c9e4a) +,S(b347e0a4,102d2954,cf3ebf6b,7c0e5f88,6a823cb4,c134897e,3169b081,8bd35f4,78494910,3eaf28be,b2d9732,f88dc9a4,66a8b5fd,cc50a2b2,8b347436,2e05cc93) +,S(54cf5638,7972ba75,48dcd07f,1bcc47eb,5d99c95c,a18de15e,9d2ac40f,1435b27,48558294,410d7ed9,9fb008c2,32cc6ae5,33bffa9f,3f02f0a,76b1f390,9e78e507) +,S(e75c0831,ab9569f6,4844f67c,3650f691,e1f84366,46a28613,653c354a,3107cdb,5e2da0f6,83cf019a,82e44f84,e7bde49c,5d477f34,fcbfc3dc,2a9a2a4e,3ead0a1a) +,S(f9eb5462,7d88b64,5899b177,99257d92,4570b3fa,59fca83e,1e302f38,5c524693,dd187873,9fe69020,970609f8,ca1ff56c,3aeac075,43e6cc5b,bcf75af0,2932d516) +,S(8890093c,5bbdd22d,69c91acc,5608e19b,59d2b105,b75e054c,8e873b88,59865997,1f18b0bd,e9b546a,9a2955ad,492290c1,a041b61c,7b534e1a,bcd4db3,b5148bee) +,S(76b95d04,88c9bb7d,2cb28589,f7f3f9a,e2ae24a8,33adf557,76bc3132,4bb80168,590b3022,81649af7,bb2cb0cf,fa0e90ee,13b97294,1a7a8748,bc9ce53,88744e53) +,S(8b3526c5,afd2a987,f8a04949,bb5695da,8b073b93,d8418878,28f9d49,2a6ff4f7,387954e7,60f2ce55,17213bf9,c987a9e7,f9b9b05e,c4677911,22e7a28e,777ab4f4) +,S(2aaaa06e,244684c2,571785e,a77a76f4,2c4bca21,14fb290,ef66d150,74ff2658,49e3135a,3e8ed289,4dcf61d5,7e4cce47,815ecfe2,5bb1d8a,a5d067a7,924fcab4) +,S(981b94b,be061268,c02db0f1,fbc330b7,351d6229,b645e4d4,3d908be4,241795af,c294f8d0,7b6c70e1,c18ce6da,b3d28c4,d53f3e9d,1f8d9ba9,de18cd39,51c8ff5a) +,S(53721e95,737d09b1,49eb185a,1663999d,23429e88,51ab849,a671c0,d86efa3f,d36f27f1,9f812f8c,c9d770a4,1655ef57,efc1f126,ecfea4ac,dd5bd42b,13e20a54) +,S(9ab129e9,a4d92118,3ebf686d,97286d1c,9608003e,67b026ee,d3d06a8a,e21c0bcf,4683a375,85be92d3,331732b7,8e12f452,480a9569,4c309907,2bbb9427,602ab016) +,S(330ed8c3,3c3647e,7b80f38,f3a1865b,d33abc8,ecd4d0d3,390e8ab1,a20d1c0c,5e3db6e9,33d6d0d9,43cb4202,f9ed135d,ced588f,8742556c,2012989e,768dc770) +,S(66c40c78,6933308b,9397f3c0,3c4263f0,357d0f8,a6a9eb06,725c4c15,c226d57a,697777c7,13cf3b5a,ca964377,fb124f87,81743794,afbb1966,4b126a86,9f90bb6b) +,S(36ce2c7a,9c7f1267,c081c9b4,296a191b,951415eb,12e95b02,e5f5d3da,47809b23,ffad6d8a,e00096f3,878f54df,5cf714b9,6646b5f0,9cce0d06,ea38c558,140223e) +,S(73fefc2e,ca71a95d,2e9d5d0d,464a7408,e38e21e,4450ce8c,51ec9d6d,79b43f52,cd47ba4d,6c2ed98a,c369ccf1,a3d65e05,758f7f70,1ca87a02,5baab12f,5b765a20) +,S(cac2c00,567cd06b,d4e98e04,e911f7b8,7d4fcc19,28a5b58c,635fcb96,bc7c0a8f,fde04dd0,3235a3c8,9b304c97,7889506a,c3ef937a,e1dfce4d,ce29a1cd,dd385090) +,S(f6eb390,2654aad1,1c69c028,2d1449a3,4198e774,3d329c3e,85a8af7d,f6219e1,6403deda,8911378f,7defebc1,ef7a4ee6,20802e76,499993e,15b22e42,3e492d0c) +,S(91a7da19,ecc1a979,7d5dd222,edd74bd5,af76d200,30cc27bc,41304ef4,578d8773,a32b1a26,e77631f9,6a3dfe17,ddf16ef2,f38f4026,4d3fb882,dfb34cf1,5fee2f1f) +,S(90c3942a,7b00bc3f,7b852097,ed4590af,cef6fbe,783fd717,9fdc4955,a4fed12a,aa7d174a,8d9f1292,b8e4d9d0,19dd336e,da305ccc,ab69659f,90011b69,85366751) +,S(717c0973,ee959e19,6d11939c,acabeb83,607f9367,83dbfe6b,911f30a3,c51af3a4,f93d840e,88497801,223992dc,24dc976e,dc0b442f,2f845650,4903c9d8,338c1ce2) +,S(831f9794,c88cc5b2,2d202130,3731371d,a0ab67f3,c080cfa4,d958e6db,aa85d140,46ed65d2,1c8b5565,14e83074,e84267d8,43f47154,8774533d,cc11e6aa,cc655895) +,S(f6c7e9f6,69447c19,843ff209,72c47cf9,5341e0f9,d2d5f14e,c9b17abe,20eacdab,1bc7e847,a9f2824b,5895edf,cde746d4,5ef0fb67,b7db1637,e62d2d40,e046650f) +,S(c0ce97e7,ccec223f,947c0db2,62fe3865,9e06fc77,99a41581,7ec36642,9d5f120a,dc281020,af95986,dfafdfc6,ce122d33,e797197e,c24c09d,7e6f04a1,c5b4793f) +,S(e1eae094,f68fad14,5d905240,e79abdef,562ac20e,d52f3503,db34b2db,d2f72d43,71e4754f,ca9df5ef,b3b86c88,7e3eba7a,33554a83,cd68ebed,f6dcdea7,fecc6486) +,S(acaa286,bfd582c2,c938ee36,23a20db7,5cb6f0d4,95419f33,b0b35f2,59841bad,c3eea949,18a16138,caecb54e,ac03b6c9,282006f7,14d4b024,2bad29e9,aea7f667) +,S(87f6893c,137f60ad,22a5d543,2dc2cb2f,f2e05fac,d643839,38936c2d,206afc82,f6bc3092,1de852d4,4894d318,aaff9243,a9a521e,501ca78f,c7baa82a,3a118ed4) +,S(9df94d49,e9508ab5,63ea1,16cc4502,aeed0bb,7b1db426,c6695da5,8da1f59d,51786cb4,a7caea66,39546ae7,5826dcb2,5abc5a76,402fbe9,b32432cc,aa48adc1) +,S(8a902a14,5ecfe343,503f46c9,71693677,80499405,5df02c32,9446a373,e34777e3,fdfaf856,f777d30c,24ce54f9,d503fc8e,a3cdef47,e292ec5f,f98d6449,a69b3f0a) +,S(ad6128cb,8d9903d4,23558eb2,23fa580d,e31c454c,d3985ac2,6a2854c,733c05c9,9b69c9e1,564c9271,5562d4cb,fc040495,6ca539c9,691e2f02,5f41151,ca6667e2) +,S(c2a2ff9f,6d064f4d,551cae44,f726a8cc,b14c9742,96725620,1d01581e,5375e57b,ae53fd93,fc405150,3d6cf2bd,bb51720e,7555cb24,ef7ee8bb,9ca306a0,59563e65) +,S(56c0fc7d,c2ae8f26,4e132fb9,3a52a634,2b80dd38,f329fe9d,1871e2c1,6529996b,5d012467,cd511264,82399d80,c7f8d248,d9267251,e4d18aef,ccb9bbcf,d854414f) +,S(2131bb4c,5014e751,ef0690bd,562ad29c,d8db4461,9eda575c,9f0f75c2,da4e0f32,7bbb234f,7a83afa6,47599f05,8ab8f5d2,83f1f02a,8f8d5292,15c7cdc4,71f03fef) +,S(e8adbaa7,bb0542a9,9b9f7598,59637f1a,cb734257,13247db4,540b8268,6c14a462,72de1317,fb5ed43d,ec57ebf3,dbec4eca,bef50923,a4743359,72aee4b3,c03190f6) +,S(827e8e05,2a084162,19c8894f,ec6f31c1,a7902792,a1e8cdce,6fa5f732,4b428417,d46d9c86,4fb85e09,81bd40b,b6c3a563,8a74c222,6e7c8299,3ef6b408,4aaff5b1) +,S(3dca9759,338dc06a,8e81218,4c14c82d,3fffc50a,6d0125d1,1af0523e,d14fd699,e6c98f39,b3fd3ca7,66ac5444,be93fe24,3085a38,7b484f28,da571afd,4b8ba210) +,S(3ceb28d2,e59d3692,63432323,c36bd680,f531697d,c33245aa,bc7c5838,52bb8eb1,d2456980,96a36ca1,7301778f,d1661743,f43ed9af,3968e4e7,55ab39a1,6ded2d19) +,S(47ce6c4d,c1dc8371,de44ee1c,828e4b3c,6ba040c6,8dab0802,417ecc31,1e7d79ce,2d6b7bc7,c43e478,6df00ca9,75268b3,39f0ad68,7b0c70c9,ca857913,485419e6) +,S(ad6387f,fde71126,d0784af6,fc8a1ca7,be9bfee6,176245cc,2a18c9c1,c17f156,3233a7a,d7d50605,8cb63aa9,becf9eb2,bf8fa88c,afb2ce9d,a9236736,803dda1a) +,S(8c9c591f,e2afc468,4b64d9c,44b92627,e70babb1,aa9f7f00,6dd5b0ba,4ae794b5,5ed4c9cf,30c7d1f1,ab31e9eb,8d20fd16,77b67152,44db075c,c9de1b49,58607617) +,S(2d601d55,1b07c8bd,10db6a9f,516882b3,1525d819,9df56324,cef2c40c,6753ef7e,d32e4bd8,eeb642a4,38a9493a,87824f86,6731bcf1,6c4b1f42,240f07fe,ff075a2e) +,S(2c67af99,3de02d6c,b9db16fb,7fa99fd3,6e32aff3,69e855b3,581af5bd,cf8f81bc,69fc1c49,501a76b6,e21abdc0,27aca6b,a062dc11,5cfdeebc,b8b98ea,ae35d935) +,S(a904b9b9,a0abbb60,4be04958,74b0bf72,5c1c21fc,1ad75b9f,99ed5d60,d1beaa3c,a2cc5370,58dcb26,6677e730,449cafa1,c0135179,4afa24e5,47b10479,a2590069) +,S(bafa5456,e50152d3,115d40f,b9571d79,7ae8fa48,97801c13,238d8b98,b919302d,8108653b,f4f9bb59,de7e26d8,55f72103,20eeb48e,9f127778,5f05ed34,3e63ac43) +,S(fce057b,560e9da2,7621d46f,bb709275,4a6793fa,eedfcd7f,9a782aae,e35cd9a1,c59891ce,d7c19c5e,7a841620,8d0d819,c8634bbd,2466ed60,214a726a,dbefd784) +,S(b8dd80d9,6b6229fd,d13dac50,23f53657,3b353efa,45016033,58a9bcfc,ab61fe7f,a72beda2,c2cefe01,eaf1ceea,714b538d,8b052eac,3df84158,dd3530f8,9c5bcd25) +,S(c676cd53,7366b97d,9a056e87,2bec47df,e2c35e88,947275b0,53212536,a6231c5,9d5fe80f,763e202e,6919c760,bc96c732,844c4c18,7e7a3a1a,a0760c29,80c076af) +,S(626a28b9,c897481,19d6c4b0,bab6e81b,9d6747cc,6c49521e,6f032f50,36c9fa87,f8373b3c,748231d,b8aaf580,90898566,27b112f5,6697b18b,3cd6a73a,16f2203a) +,S(d72eae41,548363f7,cf5b5b9e,ab73076d,650f7616,e7584fd5,1a5ff2a8,ce1959b0,c867515b,46c9973b,53498582,5bebdc1a,54181a33,74b507e1,f0aa21d0,7a6c0e0f) +,S(6e34489a,4ca57c6b,f3b8a98,dac3b2a2,995a7bd,f90acac3,b81d56d7,678920ea,efe88e16,e60cdf2c,3e6a07a0,ad323e7,ff9e731b,26f9cac7,87bf43f1,b3401169) +,S(a8214f4f,1ab2d150,b66eb9e6,f64ea4f4,6ae08909,9248663d,8491cd2e,90a56ae7,5d252b54,ec694068,a0944f8d,4e0ead5f,2cf0982f,3981240,5165b5a7,e4d628fb) +,S(76591c34,fdb90d13,14c5f85,e76e18c3,aff3aceb,4385011c,d4a74bc,b36f775d,f13c54f9,c32fcde6,94d29b12,f2a8d8fb,a99d19be,80ed9a8f,903b33c1,ae52a447) +,S(17d22fdc,c48ec732,afd7bf62,7fd09d22,d2989437,a8ce1950,3acc99f,ef2c0cf9,3bf80fed,48c4c2f2,f25ccee1,9a717067,976f108e,b1cee625,1fb6257d,f1788384) +,S(2ffd19a7,f46bc028,9b11d7d8,2b391091,e08202cd,95c7a4f6,fc351713,d3645b6a,807ee1d7,af310183,fa9edc73,4c098b90,5b0d4021,6c19b797,1429725a,5763d01b) +,S(63496320,c4eaa16d,ca4ed516,bcbae7cb,124af3ef,10969329,dfec9a92,22f143ab,3ce522ae,ffd08245,d5dd6ce0,17ea6915,aece97b9,9314d61e,2d4e9fbb,5b92406e) +,S(685a372c,ead446b,6f8797c6,dbbdf442,e337a200,1b09c03a,84dd523f,674c1e31,9436ad88,7c61bd79,d0a73f9d,1d06ca0b,37f19511,9d9f9f10,6a6d6d97,f0654d96) +,S(d1aa115d,ebf2ca79,61b1a13a,9f8f2f38,8367280b,c36f6208,15cab71,d235b866,9dffc173,6590390d,a2f3239c,f85ac4c5,3e842aa1,3ba035ac,2824a269,c7c2a487) +,S(d12c58f,5e20c6de,34a27270,d29ed5ce,c2a36ac0,8f2a1b1b,69cdf2a5,d501bc3c,cf7bd006,5bedb875,bef1861a,335457ad,66042a17,c9249006,60ee461c,db0a7de6) +,S(95d9af48,d2d3ad22,4ca83889,2d7f14a0,bb4770d0,42ecca6c,d71b9278,79e69898,39e47d1f,6acf9570,5755c560,22a8faa2,e961b25e,c5ca36e6,3a5ecf5a,e54a48d1) +,S(6e4dac4d,1b6d8404,e84152ad,f5d49de8,d269c9dd,1c66136c,65b8f78,5cffec16,62d1dd58,22c06f57,f2ccefca,31c318d1,175a3c60,2aad99f2,e5c63e2b,c8e33afd) +,S(d026e847,3e8eec4b,d9ffb21d,49c13900,34a9a66d,5423174a,40c8b4b3,4f6fe060,682d65fa,cbb29cc0,91a290e9,305e4615,5a5d472e,16d37c7f,e06a9a40,f578c58d) +,S(683bda54,87643e28,8799658,baee6ec4,73ca9c66,4a76c302,b26f5762,877e766a,d3d80b37,117d6b18,c04174aa,2aba0774,43fbb78a,2649eb38,e5798935,75fa237a) +,S(fe2f54a1,830a0d86,ba30acd7,d208f6c7,22e2deda,4e554a5a,533e8e07,dfc76f8f,6a6f032b,5bb03b33,3b28e6bb,30b2b04,305e0aac,cf53e2b,53f215ac,2f1ab8e4) +,S(2486b52c,511b2499,7ef5d49f,8098f596,568fbd0b,756334b5,d5f01852,191d677,ef82dd7f,9dd36f42,55b75292,40af86da,bbbdeccd,6ebb3197,11fb3432,236f5ccc) +,S(c6fe27cc,79f316ca,5a59acd5,911963e3,bd6ae911,c50bfa1a,f2ae8b6d,69ff8ef,70aa6fed,ba4c57ee,5b3b33ec,ab6efe75,e05b8b43,41c3a7b9,bca5053c,40292101) +,S(be4ff208,8334d043,2d35c9f3,806e516d,fae58bbc,d2f69565,ec461006,99af2be2,49de6b17,c8636af4,25ed00f4,228ecdb0,4208d18e,b5c9c194,d6714550,26396adc) +,S(c5789253,316faa6c,2f87f888,a8fa4312,42618ebb,37a5184e,29abf20a,e6b4aea4,77647e3a,e083159f,afe92726,6c60f666,12e4fd31,ace116a5,11678291,185df958) +,S(27d2c091,b2212a3c,b2a827d0,951a4bea,6994953a,cbfff146,cac83f20,f164ffd7,e9fb5899,d757055d,f0e273ef,c38cf691,e958c6e3,943aae43,85f77a14,8189eb92) +,S(94d45ebc,ce92d10a,3294114d,743db35a,8e2ddb7b,7f5bee72,7d093c89,15d98d45,802386db,bd731bbc,5dc793e4,88fcf20d,15be9024,b94d1d19,edf99ea5,ab1c0acd) +,S(46739c9f,6245639b,692a68bb,8587499c,43184d0c,f0ff467,7b264985,b4a2fb62,9f8f41d7,2eb951ff,17d4517a,3fe7dfed,556aeec6,be518188,8c39a57c,913f7da4) +,S(5c9f57b1,baacb2f,67f1bdb5,3fc85aa9,3293a2d9,d85d1f2f,f62ff40e,d26e8c30,6bcc8a89,7ebf12b7,2f397b5d,ba072f3,c91f413f,df14e441,ae2a2155,887c1527) +,S(9ccb3d34,4c813c15,e9b85517,95ddb04d,c3c790a3,a1ae051b,60202b56,b735f3fe,e24525a9,fa784ee6,2576fa15,6ad350b9,eb5802f6,e5d5bbbc,7f4217e8,73f85916) +,S(f0826eec,162f343e,4cd7e135,df33219b,507876ef,5d29fa13,d8fa2326,3e7ca425,649c1d78,6547e29b,d266f2b3,cb70b823,8e71d198,6791fb09,a19ee4fc,1823e02f) +,S(8b672a2e,1b76096c,80b87519,10b6a09e,1b7204e3,ec139cea,46aabe84,4302dfa7,33f05056,ab88de5,e036f8e8,5bcd51f5,423ef431,4faa1015,7eacfd8a,9db71787) +,S(93cb8f71,9db52708,986fcbc6,26679315,fe79d119,9f8abffc,5c02f375,8e5a50e7,ed7d055d,91843e32,4193d866,81551f5b,36b484d1,f0dd5fec,f59e51ba,57b93bed) +,S(da506843,86019984,4004a723,7ae11605,a7132e86,55145d8f,ce9e0e50,feef7d5d,260f6393,886e1b8a,93986894,a4a98fa2,61771a46,16d04ebe,baf8bc48,29816d53) +,S(2d469c5f,26610e4,6bfe1cc9,43cfe267,e1bd0a22,e451aeb3,e74f17b,b9ec2f76,1d702b5f,fe2101cd,f5a5cdc8,4d4a4890,6720ac6f,ca626979,d942c218,163474a2) +,S(1ea83777,5513ab9,cadd3b53,66cd9049,da1b01c5,d347f7b1,c8a74f6f,658cd621,b9e312c7,2dee3d7e,d6e67596,70c65bca,5bec92a,2eb82fab,a122ffde,5b1c7f5) +,S(70bb25c7,9589530e,f129166f,cac1d5d0,81083ed5,fc5b9b99,e744585a,1d6b6816,63234c19,dad2914,3e99ff95,a906a5f7,a48b3e87,2d45436c,8d987baf,a93b3588) +,S(fd9989c8,f68537ea,a3248b19,ae721256,ba8d0d2f,d825980f,f89bb158,a700f0a0,eb76c5d4,93e52d45,5d27a12f,fcdba859,664bb048,1686e67c,e79e40c2,e0160c97) +,S(f1c32c17,8b36e837,b058e9ab,ed3c65a7,e2c76397,4936a524,838a480d,b3089b7,dd4101fb,92488a78,480cb6af,6cf73dec,5aac619f,3bb42594,c3dbef4e,cc7a3a11) +,S(842d8101,ed396c79,b5b19779,c245dbdb,b1ecba7,9ad77d5d,f78fedce,f9d83f33,6fe77300,9117a404,f4b28ef2,57441145,c5afc6ae,2e655ecd,2497486a,fb1ebc16) +,S(6e9e1a2e,847fb133,cc92a79f,767a5ea8,cac887a3,16903a98,f3ea86ad,3e8cf24f,d71de5dc,12be0a35,b996d880,8442fdfe,4a6cd810,7fe29548,da99783d,9049ce3d) +,S(f6739fd0,1f5429d,27c216fb,2b02d871,7028366f,7af115d1,e154f87a,812b5e37,15186c87,f776c8a0,3532b554,1e1b583a,5a465334,45bcf93e,dcf539b,21663c95) +,S(c3acbd98,43bbbd8c,68f153d8,553a81c2,81dbc584,42edb9d0,e51d056f,2b80e2f2,8397a220,483081ec,ea7de090,5d063412,1dfbcc32,ce70379e,c58b33b3,20f39d25) +,S(aa9c8bec,c845e691,a4c3daaf,a9bf687c,ad733290,32abe151,a26c2a27,1fb94732,b82dd0fb,c53fa616,74b684f9,7da10e8b,77f1f7e7,388007d6,656988df,e18df322) +,S(3df35629,654d5b70,db9547b7,5373efd7,e1781dac,da11607f,e4f3c903,5493c8a7,56fbe92b,25cbc615,96f2cd4,10290da,239ec3d9,360b3561,4199b006,c2d2b54) +,S(bcc8b337,98973e00,771a1955,89165cff,83870f8b,a897b8da,84c1bfb7,57168bb9,483a7f4a,70c8250f,62105842,310ed427,168382a2,5d687290,d54e65c4,c83bb16) +,S(bd2b07e,a84da89e,bf5e39f4,d3f03df8,658061fd,8f78d5cb,99f488a3,e992b870,33ae1dde,77c5b467,f5b3da9b,c71a6557,b0cb3aaf,892d0e76,d9f34b40,1fe60c9d) +,S(2c55718b,87b4facb,8ba9a6d,287a2db7,1b5a03cd,c7d933d4,c6014232,ec35d05a,aab1de0a,d8e3f72a,ae822bdf,f3ff70bc,bc5aa56f,1dcc5352,d1f81614,f3f461dd) +,S(eb837dc3,b2e346c2,aba58441,8c84b20,d144f93f,841180f0,860f7280,a7ee23e,6a342fb8,38a63813,e279d1c6,94b2ed26,79c3dd21,652d5678,5f47aed1,5230137b) +,S(827719c6,9b097381,da18519,ecefa193,9a9eba18,189092f4,89bde77d,33046fb1,e73b0e1d,76e40777,4ee6fbf5,2bafe516,f6d94fa7,c7dd1eee,b3c36f7f,6429dd3c) +,S(2b0da4f1,23095370,1f1b9444,847ab289,5cbfecb5,800f2d7c,16e7a56b,c6988d2,fa8b4d9e,5da41962,68e10a3a,7d69b1ca,7963d4d8,cbb5fc1c,83239212,dbc340fc) +,S(95744eb5,13436e2e,877fb0a5,20d5f1e2,1e1ab59e,15bbaf46,206550f8,d5563134,5fb1c034,62040ef2,28adad1e,83fc2c74,57344c38,7b7ffde0,d247bd35,6b5ed1af) +,S(4c805d94,78793e63,4833e90d,d19822a0,ab7d263b,1ab67654,bb77358c,67b327c8,863cb8f0,dbca3c1e,4011928,e5827619,53df792d,449f8980,bd10cef4,472ab56b) +,S(fac22633,3ffa2cc8,93c434b,46fb0cbb,cdee765f,e848cb50,b1dd6e70,272e0ec3,6a6b07ed,46f9b9c0,86e970b1,d2323fa5,d7d66b0e,3ad3077e,da5766ca,ac5b500e) +,S(b9d6af71,c59f0fed,ca4ecc31,25aaa645,f78d43eb,79c22034,1034de56,f59ec4ef,5509e17e,3d7ea457,c428e10a,7e9d8bd6,69f0fdc1,165169bd,a2101d8f,6f4041b8) +,S(57a68137,90725717,2dcd8c46,3a9b274,69c5ef27,2ae2be60,b10b96e8,e6b47537,9f294700,1c04c06f,2e2e5aca,cf4b9549,265db1f5,74b2328,ef4469b0,1c2bcb98) +,S(58ee2a22,9aba401a,637c4d34,2b1ef408,d9f47c53,6133fcc1,de030d00,25e2f53c,d361b0e5,5ef24c74,94cb9e65,cd273e9e,73da6e50,f452f8b1,7d30eadf,32ceabc0) +,S(b8bae4e3,f2e22824,7ac9cd8c,a68632e5,1bb13d4d,735fabb7,305a8169,31b0e34d,ae8ed4e8,6ac41b60,60ca3423,fe6bffcf,a7f215a4,7076f270,a2d1017b,887b8002) +,S(a81d5e0,f11549c1,373b4c02,a61c8908,dd109f4e,7f0cd250,a667508b,aea3feab,8c6cd790,4cb4bc0f,7e56d928,ac362cdb,f096841b,dee9dd48,429c52e7,23511bc1) +,S(fea67ebf,f8f092fb,dbb3110b,77d6981,efaab5c4,97a23c3,42afe294,64f4746b,1dc947e2,94b0fd7f,952a6d5e,1f5ddc9,5f0acde4,de8db93e,41f37ec8,965d4310) +,S(4db2ae8e,6b8e674f,2d79e1a2,fb7c7d10,921c9280,d8eff92a,df1a2b02,4485bffc,8ed56cea,38c2a96f,b6e0ecf3,22b745cb,35c43313,9b3dd28d,9189a9c8,9f2c055d) +,S(be31fba,3995348a,78303047,24ff117a,48dcf5e8,72356d03,ac059306,fc5ae314,8bf72f6b,70189284,ecf86059,affb4a2b,c7b5f923,d7c34429,6f401490,5a94061d) +,S(e8d716d7,18078be7,78535c20,4f9cb681,e8f49ac1,85baf865,e7b78e19,58ee703,2c79f768,c6d3bb3d,b0923d19,74647e8a,966ce69f,d06a8fe7,5601e51,61f49f85) +,S(20ae34f7,f3497d67,6b0496fa,1a68178a,f4fdd57d,15131ab9,c60bedbb,1a840070,21fc951a,2b29ab95,994cd404,b3da37f7,d21fa790,820339df,84f17b50,3572edce) +,S(73db09f1,3c8e7bb4,48629f24,83d56f1d,a207617f,454edbd9,d51ce59f,b7ae1ec9,1e4e5175,efe03956,cce3f160,791595ad,35bea993,139e8967,f591b973,785dc29f) +,S(14f5ae1f,af20b6af,9953fe91,db5bc192,31f302e6,cc03a265,d661b25f,8f07cb18,b790b1d5,ef6ad5ef,97ddb309,354756e,138f4db3,208a873c,17cff3a3,13a8be2) +,S(94ec6992,d2531cdf,3a1002cd,efb12e68,868be66,b704dc26,3dd422b9,9cc379ec,d2c4e479,ce9e0227,4d9175dd,e2a42639,67ed377e,d0416101,7e41e8bc,8adf7fe3) +,S(f73b5edf,c8d60e77,328279af,ae99381f,4ce0de22,17a4edd6,4c228b4,84816527,86758bc6,f44e1204,68555e71,786f7d50,da7f9c72,665a7475,e77c32e9,dcb13419) +,S(94b51939,45a518e7,c602570f,863902b4,385c8e76,c335cae1,b80e1d0c,e118b573,7c285008,4d398cfa,24c5cc6d,879868f4,d8eb60ad,ffc77214,5debabc1,3f154ea2) +,S(26acc055,2fa90d45,1dd6f2a3,9bd46a9b,99b0f66f,3e6e72c3,16e09e52,f7b265b,997dd988,5d5b15a1,957e1cc0,a45518fb,b0e1f847,d58fe9de,9be95273,cbe61b00) +,S(e8a5ac01,959edc90,2050922f,af51365b,ecebc967,8e57cac,420faa6d,4e2fce98,2c2998c6,fdd97d15,fd0cd228,e9975064,f2576316,6e61a45e,ae532481,9dd96227) +,S(d903bdf2,5ce9e855,60f63d72,512626fc,fee11c4e,304d249e,e13a4b69,60f95019,1027435d,bab3c246,c93897bf,ef7779f8,9a165595,a7c9c536,176fec9,1adb645f) +,S(eea105c6,fc04a751,cdc27e40,25f0d50a,99f8d01e,1110a505,eb95206,922e50fc,b93db8cd,b914dd8f,2b57b907,4df41e9a,d8cca9e9,c3a9754b,e8473446,ef3a6c68) +,S(801b116a,1fc2c2d8,fc8b412f,e9b1b7eb,b19f4e96,16b420ce,16f1b4b8,dad235f0,53def02d,8a6deddc,250de95b,d6a96d27,1c197d36,e137e640,4123501c,15fbaa9d) +,S(db3b8667,1b0dc54,436520fa,c8d437cb,7a4c23b6,bb3c3cbf,dd34b605,af406939,36562d35,a298b620,f7a06498,b1032f4a,33cc3b3,ee185e0e,aa8d3e4f,3ec5c481) +,S(7bb26eab,8b808402,a9fb3fa3,8f0e2f6a,7d82d7c7,eef75cec,43594713,dbc17706,f4f86283,713738b2,a9209e49,f82ae1bd,9bcc908e,b9565546,3a8a5dd,8d0c4b9c) +,S(e89fe301,8d87bdae,20fee2ec,7a3f6cd6,cf932d20,a026e1bb,a82f9c63,a47b97d9,92a7e80e,e7657ad7,c72f471,8f0c28ba,acfc748d,a6090026,1191912d,32b8a498) +,S(c9a10a8b,14d1845d,be6eb6a8,65cd2ce3,a4d0be4d,fad24912,b01fed8f,8bc812da,5852b791,85afd22a,6f9ab486,91340dfc,e9979cf0,bc9732b3,637434a2,25001d71) +,S(257df2e8,cf535cb7,954b52dd,7e3ee08d,24cd4415,d1075dba,8f75bf74,74afad3f,f72d1e76,d4da3c0e,5b41fa82,28639f2a,f4e114c4,94073ddc,3e8fb2aa,f82596b7) +,S(3c64aa9e,548a430f,a815bd54,713ed69d,bc32a0a1,30ae7ca4,1541ff21,a5314886,8377911,7426e30b,dbf84c57,b110cc3f,df5acc95,7313cbc9,86e895d,6e0ec912) +,S(cd509f83,3b65a7f9,671b9239,c5e71323,f183e956,2c2c115b,751046a2,33424ee9,579243a,c7fbd433,81cbd0fc,4330d087,cfe0c41e,449ef82e,12def6d9,8977338f) +,S(27adfe4,febc3501,3ca7a0a0,b5f7e525,3768df69,9d236f63,9ab80782,c2d426f0,97cb4e7b,73b065a2,499a1675,88fc116,be5606f,80619d42,ddb63286,4d20521) +,S(ef5bb148,98dd6802,6f25c363,16a34acc,c6131851,a4efe8af,219fcbf4,13a45207,49f30d08,291e60f0,975c93ec,403d2a14,3742aaeb,3777cb9,87ff38ec,b51967af) +,S(58df8d45,955e923,ec7fc327,f8081ec3,7ca6e261,7fdf7785,6eed51dc,95057034,cdfca79c,92dfe719,2ec63f6f,f93d211b,d7cdcf69,4deac173,d3393fd3,7655a310) +,S(2a4ca8d3,fff5ac47,bce452f0,1587a769,443e66c0,164558b6,301a6a2b,d3d44270,ed73b405,521274a2,3abe589d,c5ecd607,b6467691,f81e3c9e,6a2096db,2ec82366) +,S(84bafd1c,7c6072cd,fce244c4,8ea004ad,9b8e1765,bb8796d9,118d6dcf,a5ac58ce,86ab8db1,7c26c921,604a3c3f,f0155a2d,14bd7274,16f9e319,efb68f50,2b636c00) +,S(c3785528,7cc4e3df,f5e95951,c5bc5964,28705a12,10927e89,890726a2,ce00b657,302ebd13,5643eb43,f0bd14c3,65e385a4,c9a177f,96595054,3c3d96db,69ee8f79) +,S(c3aa3cae,efa22927,56c72aa,53507474,50f7a64e,2df1bf64,333d0402,5dc87d25,c2eed94d,ff9c5cac,248f77bb,9e189302,286db019,64214d71,1a199119,4818ac4e) +,S(443b9c8c,7d8c4f7e,de7168fd,666e79,5da85e6d,6c0f6448,7d349de7,66acff4f,2d4f1d59,b0d1688c,9fff0f2,f80e3434,db72d76e,6ff886f0,63dd63fd,e192b01e) +,S(2afe7ea8,688081e5,ee8a4ae9,87aec6d2,ede5ec3b,ca887bbc,1461709c,bfc6e5d9,5c319df3,2556ffc2,56194b7d,eb46dcee,59208922,1e55c384,2a03ddd8,78add90b) +,S(c62004ce,4d82ee0c,e2edb82c,e0ca98fd,413bbf44,55b96624,a86aa252,c346af6c,b68e4fb6,88f78331,bc2218f7,6a5e43f1,cac49fe3,4c5302cc,d6a3f1a3,258564c9) +,S(f759c4c6,e0bd72a3,9aabbb17,fc62c900,d57e0b5d,ab9ecce6,8f439025,2b17cd1e,6dfaaff8,5f9f3990,ad2c55f1,3c74e3aa,aa0f10b2,90def714,229cd3da,d5d18d98) +,S(b527a6a9,d27d0a1d,5adfc1c1,35308e5b,9a805638,132f61d7,e5e60709,ac3a9d9,e387f69,62ad151a,d920c82a,739af00f,628865ad,4ca42405,efd87e89,55b91042) +,S(ba23656a,6b0a5c57,f9a00d6a,9e6a331e,cf0c8097,3675f41c,7f0172fb,caf4eb02,b48ac68f,1a108de9,18d76d4,95a811c2,b7614aac,3c5f6b18,f28de8cc,7bd4041b) +,S(ad94ec6,fa161fd1,60dea3b3,2c63a480,9f7bbb91,49de206d,8cc61306,dbd18aa8,5240858c,ec88a022,7c1c12a7,862b4d18,e5acb344,5d66bf85,79ff9fc,ba866a4e) +,S(db4cc48a,de1bff28,c8987eb4,d00e1c5c,4c49fa6f,125d213d,bd814c34,cb81adc2,ffd64cf7,3c62c097,a2cb3b84,c62bc32c,54fce797,74479146,7b9a2cb5,d6f821dc) +,S(27d276df,fa39d889,beb0b586,42a0e479,8057760f,c392d052,6751f2bf,d0c75aed,c670b966,575401a2,a790440b,e5e5db56,2914aa74,e8304e3a,407aadc5,c87e12d8) +,S(7663e9d8,e34b525,b336587,eba3678f,488f95f0,6e9a6848,d2e72d35,36b569da,472b1c5a,8ee189f0,7a06addb,e6a8d90c,dcb87039,aa35e896,79143547,34e2786d) +,S(b2c81e15,1c1f8ef6,51ea1810,97eaa280,7e3b4a96,fbe210eb,b49554ad,6e0c0c4f,2d914319,f5ff59f8,c7038de7,dc70d1fd,6c4434ca,e5c0451f,4fa99f46,55bf8e4c) +,S(25131e21,9406fae4,ab96326c,7bf22892,1f18aa90,c52f46fe,b23f90ac,59ca570f,2e8a380c,eed5d51,6c190251,4937aa0b,1f39d3e4,42ab2537,e9e8d9aa,396e4c20) +,S(c2694b68,8e33025c,fb9929a8,c7ccd1c4,7fc5811b,9658ecb0,f41e4558,5d9a0c3e,c443d593,e68abc49,cbaa92b1,757ab2ab,c30671d8,4699a5c4,85a30b05,6b1ca701) +,S(8d528cc5,17a371bd,9605d8f4,e7f030fd,8a82d489,5bfffb9e,fb11f63b,be534fd7,ef2f16fe,64ceab2a,d261bd1b,314ebc65,4b4127b8,643466a8,f367b991,d28795d) +,S(409e69c7,62f856a2,4b6e80aa,baec8496,33b75c21,8943dbd,7280bf,e917b032,7f049016,62884d22,dfbda29a,c8061b7e,b82eb94c,13d7efcb,77531f8f,980babdd) +,S(82c9b4b0,2451fde7,8ae877c,ed9af540,1ec0e258,119e27d4,1938f71d,ebae71c8,212d6e4,99b91fd6,372db1a9,4ce3fd9,c5443b7e,fb37a566,f0c5f54b,fd8edae8) +,S(6c9fd728,37a39ae7,1f0b5852,e5c09d7d,cde66ec,e8f19a2f,2ab46fdd,d17c7f88,430d3385,aac729f3,8ef5ed,922e709a,73df8e70,eb9cdb83,c41e5958,272e8687) +,S(9f012582,e527901f,ad1f350e,1a64702a,ca1f6670,e693bea8,fc3eb0fc,2c090329,a2fa07ae,c15e9457,b2c75e50,56c79a6e,a4c8f431,d3c720f0,60f7b5b6,da6e3dfb) +,S(6a1a49b0,7b2b61d6,474834e9,953aa455,63910582,57db16bb,406b600d,bb01300,d4b93b7f,66ace505,cbbc2326,ddfa2fa4,ebab145c,ffbdc2c0,606e2ffa,9dbb41f4) +,S(981d0638,a585970d,4b12e577,95e76c26,1e10d65c,c5a94f19,43560d10,472fc9c8,f9babd66,3d02e030,1fc0ed0f,75cdaf94,fafc18ad,2cc68db6,d2eff7ca,e6c013bb) +,S(7edb47d2,b6295063,6cdda3d7,169b4296,3616b6dd,79e2e148,609a7722,476e564d,179a20ac,a6deb286,76fd466f,be78c3b6,789d31b4,91622149,4d7d634,d4bba999) +,S(51867800,4bd8a43,8f180cdd,efa17ff6,e16e29e1,e5fc4ef3,f5fb9bd0,bbf14ae3,306cc2c8,60ae5871,8632f94,c9acb7,321ba1f3,5092a0b5,72c33b9a,cd8cc956) +,S(bade1926,d8b0d136,69e056ea,ea46b2c8,2bf0f0f9,a25bc481,8a40ca8e,201500aa,7ac76679,c9807217,ee802773,dde582b5,6f0a4b66,f6e21764,285a6a81,4d584502) +,S(87815e7c,d1e5e88e,eb882b23,955de59a,d63f14fd,457a8d96,4b47a611,b3e40043,ca82343d,8e2eff9e,314ababb,15cd03c9,6fe6660c,421af876,63500d49,ade0d492) +,S(77d815d8,886cbf43,c1b4ce94,253e93ef,767bacc2,42ba7c1f,bfb7ffa5,308d855a,a8bb3f95,37ef9a77,ad7e282f,8ae05ab1,8131e59b,46a67c3c,7e85ca00,a2d3e1fb) +,S(49079a0a,7d9d9add,3a17ea11,747c8baa,d0922a7a,e766e5e3,fb80ae0f,dbb7d6a9,162b4e23,58f03e01,b4e09264,8cd0657c,f2cdcf54,f6c25d5e,fe7330ce,421e0093) +,S(28d61211,c183ccc,2b08168,5a4487d1,57bc0714,d3ffb16e,96bf0768,ff8075da,3da98c13,a2d1b07,2ddda165,3fb68a21,aad4a9fe,b4536dc1,507dd78b,7e51e0a8) +,S(40c34a4b,6196561a,d4591c49,df51b8e0,4106e545,26092e88,72018720,41448080,7a6e7478,3ce7d82f,b83f15e0,b74ae6d4,435593a1,67da6f57,f2e285fa,8c107e4f) +,S(88754e6a,e12e77ec,21e64cc2,bfaee207,f5c882df,80c8b15e,983fb1aa,99037c2d,5ae10e7c,e7464c69,472ce85f,5183a836,6ed5b3a9,1fb1af7b,d5078c76,2512f37c) +,S(8bb7094f,ed62beba,d628ef9a,84a0679d,7e0d2b45,a655fa3b,68d9a6ef,b24c738d,9f5370da,993a3811,48ad4da6,2d7845ce,4cc81766,f26189c,2199ca73,4312d102) +,S(79814e63,7bf2cfc1,cad39a36,b06fcc4,f7e865b3,ab2de1f0,c786f9f6,40dd80ea,aae4d149,f1e44635,e4800962,f533eb38,5f067114,3bfb87ab,9e68e27c,b56df226) +,S(d493573f,93018d4b,8599b54f,848c3afb,816e098b,8e218e2e,6304baf6,c726513,383c7ff9,b3ab6472,ecb80f72,2f70feac,7ff26989,bcb6f984,628d5eb6,a409b9ce) +,S(59599fc8,7d6a7532,5ce8f205,204596bc,4cec40b2,f3eae8ca,4530053d,1b7c731a,7a8d91e5,5d989961,889949a4,bbb71e17,84055697,b396a011,eeb33889,88f0681d) +,S(4a834ec4,da3c9afb,c62fec5e,898aa2c9,5a835e60,ef199346,3e4bf255,e32df096,8736155,ecbec836,e8d51d79,9176a5c6,6672aec9,548aa63,b7f5524f,6b20cf73) +,S(2142b447,f2707c37,45e877dc,8039161f,d222c69b,9236592c,c1b3f56a,d30a975,9a48f0a7,1ebfef1e,615a7d5,a9decf8c,70764133,88b0e57e,da554257,256e41d0) +,S(c3831b8a,eb58dd77,e21762c5,f2e88035,63fa8b1d,f5d1fab6,3d012fbd,27971797,45d1f565,6fb2779d,6ae18e96,4d9bdf61,924a5f6,a7dfbecd,2224f1c5,70292f46) +,S(a09dd11d,b78332da,663acf08,c08b3d45,d0f4740f,5df66e39,d53e6c68,f5654040,649959b5,bfdfe8cd,45fc89b1,ea21cff5,94f6083c,da8f5e5b,94525d22,3e326217) +,S(53b22e4e,8a17b408,6b119087,2b8fbc9d,fc667b40,223ecd99,27cdf4d2,a9dadaa,87eb7fdf,b9c6e23f,e7c6a8d7,fdf94438,88c6c0b7,1a3728ae,ca8e83a9,4403bbe9) +,S(7de0aeb6,d3c264c7,f39b087a,e62dfb5e,aac6fb17,483bf33e,bc34a903,f0ee35a7,43f92307,6a2205a7,f2f0737b,2167863c,43f3cec2,ea3abe32,9bba3792,6f070847) +,S(ef20ed3f,3dd1cd8e,a610f1da,64086eda,a4a646dd,e2bff224,ae72f069,f341b532,c3477d8a,a0acf4a1,e9c83a1b,c890e59a,1b739a82,55d3747c,7403034b,221fd0f3) +,S(ab21ffa5,3c7baab0,4ee74647,5a5e5800,dcae9a10,644c84f3,a108cd41,cb0dda53,3a02b102,dc21cf05,3abfe19a,2747f34a,35ec6347,ccf02880,5aa95119,110cdebb) +,S(ee8aa184,532ceae,2c3a5071,d905c6ba,bd1982cb,391151f0,fa869339,aaa50ad5,157d9d2,be135082,9eaf2c54,94e6f90f,8a82ad35,2d486dc,58068cf1,c96a421e) +,S(6b234cdf,fed7575a,f1cd7ac0,76c4251d,5853718e,2ea07c04,77959afe,5c0af2ce,223c14f3,d3d61375,d104402b,bbd51026,a7644b15,4f4d254,85e9a4a6,e8dc2831) +,S(e04eb879,7821557,a875d846,75496d9e,420ac3c8,6e718e45,347a616d,7616e836,59f33383,8354990f,2189cec8,af523611,df4a1b30,3001c5d,84e1de70,bbc6bf31) +,S(6b8c79d7,791e8423,788627b7,a99be936,145a8eed,178c8bec,affa8a2d,72965da8,28fece24,22f67bd8,a2d6ef6c,66fa51b4,c4abe766,7480b520,4f77bd8b,2e3863a8) +,S(d21a9136,eed220a9,708c09ed,2b22f5f2,87868a1d,493f6ed6,2fe9a455,42a4da0e,efb15959,cc7a2c02,7ab7f5f6,ec8a538e,91df38be,f78de45d,dabcd8ef,9b5394b) +,S(f950b37e,a5bfc8c7,a76ebefb,f228043f,de066a1b,cbb30688,b73e085b,cce1ce6a,6bc569cd,609a15d4,28ce7874,53ab8d02,fcdc9c50,c8c44016,ee2b62a4,16849616) +,S(75a72a76,520a5f29,368338ec,fba063c8,977548f3,7bbe08a2,e1ff5e97,88b9bd3e,41c140e4,5e2be58a,dee8af9b,e64cbe8b,4c82860b,98299d52,3b27737b,3266f978) +,S(4474da75,3d9c68d7,2218648,1ce835ca,4e17220d,533adb53,38a1978f,cdfbc3f9,b5e2d3c4,ae2c8276,5a337068,58e76666,52a81638,27cb6b94,3d2b80cb,36ad3eb2) +,S(e3f3e682,fd38b067,33f3e91d,585f3ef2,aaf90409,ca125479,b93039fe,3437388c,aaef5ad5,4bfddc87,f7c3f969,94564ac2,27e6d5ac,ffd345ab,246ee2d8,60d9242) +,S(140ea6a8,ad374157,396b064,f7a952f5,358ff408,951895ee,b66b6140,d969afc7,2f340af0,b08a67db,e6ea7535,581b763,24308f37,6015de2,a4dbfa64,1990cc78) +,S(257c1e04,2fcceda7,9aac2bb1,1f01bce9,37b445b2,bff51fcb,555395d2,d0c16b89,73b21d9,75bf23f1,aa0efe21,5141bad2,5a235978,e36645d,8503a60,3956cb5c) +,S(c243452d,664d2610,d1acedb6,ab5201b9,cddce44a,b9320806,4824329a,e0b7a550,50607848,db2b53c3,c9ed2b4,8c0adc28,322d2e,1b30c3df,1ab9dc37,64b001ab) +,S(a0ae37a7,3aee0e63,c0ca3e50,e59a660f,c7ced178,10dcab26,7f91ed44,3f265fe,8332d25b,94e0555c,21ebab61,cd209599,bab277d2,fb9660f1,f237c9bb,4327668c) +,S(2e4886d6,678f10a4,460b4ca4,a9964125,413a739c,64b6abb9,c44f675,1b47dca9,96f6bb70,9602de31,1be57a61,966c8227,e5dda6c0,48d3f1d3,bb5bafa,fc1e8de) +,S(855b47b,efa7dee6,2452a602,980258cc,de813ae4,6f580a46,d5d18432,5b423f8c,c27f5513,114fea7f,b5a405d2,3f25915d,775ac895,7fdc6e74,2d968bbd,d86c181f) +,S(dd360b5,38fe460f,9d6ba828,e2ac7973,46dc386,de05022f,fe48e891,a115e2ac,8fbc127c,d9e79454,a0be9bb9,cf25b7e2,71a02e7f,b4c68653,b7e08329,747cd68f) +,S(993aa6eb,47f7713e,e6c5bea8,1a65af55,1036d0eb,3df8a6f7,e091c16d,3f424c7,8478497f,a774307,d47ed357,35462f3f,a680eb87,fda11107,275c1883,e859ee34) +,S(4828feb,5e3abb4a,2df7b990,e20e1214,804ef219,4cb8acf6,cb8e85b7,5696d961,d8d2636a,6b664b15,f371ab5d,3ff31279,f7c42678,ff380ab0,9c220b02,6ecf3e3f) +,S(fb8dbd84,64bbb5b1,904a2610,2321e59d,ee9debbd,afdbe585,3e1af139,f8fc472a,54e088c0,91a67284,6c81d136,85b4edb4,391e5121,3c4d35e8,47863018,62844742) +,S(851fc8f,cf378f62,5edb262d,e0360d2c,2e9566c6,93abea8a,aec29e5c,275ecc9f,dbe6025,e9857155,83b38b7,a167adff,da70398e,85223a6d,9b940fa8,30a9d9e3) +,S(4d5d07c4,23079d83,d001c000,8c76fb6a,e03bb39e,325d5794,b5414b,46c6777c,d1c1e970,5b80fef0,8450f941,1b8d6197,21f1491e,87745c26,9458d58c,18d14678) +,S(8164d5c9,cc72b489,b6a54e8b,d9cfa9f,8496cd34,3a227a74,f37948f9,5d35340d,90b51776,9e8c68c9,20f5e948,755b4da3,2b294bd3,eae81da6,e0c0b287,ce229bf7) +,S(19a42dbb,9ff7a400,aa821c88,807281ee,ff7df5c6,e047cc51,9693c191,6145e00,369e9596,903c35a8,bb38f4d2,a74da3c3,cd2246d6,b0391e98,e01d6101,439a1018) +,S(7299deb0,a9b7bb52,76c8acae,37ba0ee7,bbfc9c0,7845765c,136cd762,7e7b7f09,8a0a1d16,f00e3090,cfd9cae,d8aed291,ebc56d97,66a131a1,4fdcf6c9,ce6b49bf) +,S(12c7adbf,112e7718,a3ec6774,1597d6e9,87763a10,4350650,e6a804fa,507ecf6c,b3eced7f,bc3073f2,5f86d647,6d822b8e,eeeab7f2,1b3263be,615517e8,ef3b1a64) +,S(b2d76aba,c1af6c6a,b4840b34,db1125c8,d5baf2be,90dc7e6a,52edbf79,a4b0ccf6,92938b87,641e0886,3f22f5ef,e27f9b18,80210d14,312ea6a1,eacaca0e,58c0f73f) +,S(818baa52,8251c326,bf545ff3,a56596b,58e0b525,64ae359a,c1d5199,4b52106a,9f8b4753,a7b56b26,e0e79b9e,9ae5f30a,64d0ce27,5898bf3,c0f12e43,faa69681) +,S(e08080aa,21c9b6ba,da128bad,62dddd3e,e8e5afc1,c460b997,45eab92b,b1663a80,2b878efb,95a19892,8b3609a1,cdbbc1ad,d1530a38,b528539a,c52fff24,2c382dcc) +,S(7a8486a4,1d774bb1,32321247,f7b87964,1b18a621,508f5376,99b31798,490f3e8,ee8c3085,5c3fa5c1,6f90b68c,89944aa8,dcb824c8,c37a0feb,ac796403,15ee96a0) +,S(f74e74f1,6e67c1f3,f5952373,e53cb85e,650a6dae,2302f495,f6882b9d,e2b71cea,1b15103c,8566d2ee,cf5c59c,dab607e4,97075e30,1443b75,42620545,2d1d2bd6) +,S(3ab4150c,cdfd6793,5f8718f0,dc961126,114a5d82,e1791c2d,48740425,8e8ba004,2a6c6f1b,9b546945,f9d327b1,437b1c58,30a48eef,6a14887a,9d8ca24c,c6bc446d) +,S(effec0ed,bb80580a,7bdf80cb,38cf775a,43b786e4,2c80d73e,7a254216,ed7ab7c9,c7c27bd9,57c996e0,42ceda33,2d0b5972,91ae5725,6df77e82,48bb1716,127c582b) +,S(5f49ea21,4d80f735,fd5f51d0,55d4e2f0,fbf0f804,a8f32615,340bd6c1,65a059e1,72e0f032,83684df0,98e740df,bcc39d61,6956ea36,275ca5ae,dbcbd682,510496ca) +,S(2327c29a,7f906,4cbfd900,43d28618,5c555bb9,bb64bab1,c3e20417,4cee2591,db1711bd,ac9095db,39e3d2f7,d2b84129,41dc6f8d,116115eb,7bfe710c,13b9e41b) +,S(12f2f427,64f77c84,f8a97c5d,7743bd8c,cd0c6132,5cd10fd1,76975a97,b447991,713e4660,cadecd98,3b0e4986,855c2c67,bc220334,2991a18c,bb0c08f6,8282b246) +,S(cdd3eb6c,b496141c,b99bde6e,a66b2c78,7264e6c8,74efdda,5ffc53e4,b3292a08,d1270d9,7cd63394,b385739f,4da31dc0,80f410a6,aee164fb,8147b7f6,9f2f1cc9) +,S(2ad4df2,1ff316e7,ce29d76c,da40cb7e,31aa7e14,49fce23b,93f0d096,e1b74159,972c77aa,160c98d6,c64dd9d1,4a0cedad,875e09b5,b0d5378a,7311cd2d,a7d641a5) +,S(df0ed61,d6c8f906,f970b9af,b4080368,2f12127b,e318575f,8e2111bd,514c33a8,e9e67c4d,7b1b0fb6,fa0a4640,62d72f,28180e6,bc8bef1d,60a1ea79,2c4f259) +,S(9572faff,160577b1,83aca01e,45d61647,7dfe147f,a6ae0b26,ca0264aa,23d2870f,b7de270f,572e1503,8a4a9b3b,706eb7c0,2a6e5e56,ab0f73ce,9f4b7926,a79c5c5) +,S(52583f1f,1d51acb9,bd25b63e,158f66b9,8e021432,427efd5b,bd629594,ba951264,3267373a,94719487,344c9af6,1eb4b726,a595bfd3,41d78b33,f3db8897,7e53427f) +,S(c95cd125,7e59d04a,6d953d7d,f68089c0,c29b6a28,90ff264f,74b469fc,af7cfa58,f5c7c7fd,82d3fd51,4031ce72,657cffd2,da83d072,9b0c4d6c,66180214,9e6ac90b) +,S(67a190df,e1a2bf4e,cc23972d,24d1f13b,803a9b4e,5c1f3cec,55d2c2c,3b0b2487,5c35f795,c29a2f07,74ded776,72ab5a7d,45902f50,e76a229a,212d580e,5edeb8c9) +,S(7ffcb588,ee9192c4,3bc5bd3b,4d0c8211,28c3f2a0,62ec3b0d,77752ada,69f468e3,9204301a,fd0ecd0d,26f49878,47c42c70,e526f7d2,e69a97f9,2aa1c357,d4140a8a) +,S(7d693f1e,6e35e062,83f35910,3c1cdd8a,5279c4ad,ed0edb63,d6c574ea,322e91d6,a9042da9,ff323c4d,46b2b40a,1d44970c,92e3cb32,ddd8dc21,d32d609,c5611888) +,S(7e0e5dae,8ce3c883,49a9ee95,fb357694,a7bd48d0,f27c2eba,49896e4a,3da04fab,a397f8ac,dd4077f9,58d7b5fe,28582bcd,4c46d1ea,fa253db5,18fe90c7,61dbaa4d) +,S(715ea4a8,e5eca76e,48605688,560872d6,7a499a8f,e84f715e,a91d724d,71fc0f06,9a7b3eda,8b82dcb4,60ba3515,18c22f59,fade0636,dc893050,a51530d,77ef8501) +,S(52a9c85c,ca99e4ca,50f5efb0,118fa604,b7e789b6,b589a5d6,368bab11,44c8dbda,3796e4e7,87dda75a,59c7503a,f27732d,8c973414,c1ea0a90,fb6cede8,a5066fa8) +,S(58f1c65d,ee5ea200,57644796,a94e4a42,771c827,fe032116,657e990,b56e42e,7f12725d,388a22e3,4f191714,9f48f0a3,3d537c8a,1037247c,de0594ea,a11de507) +,S(3ce165f6,5f569bb5,e594110e,ef91f30b,7e330586,e86cc4c8,347d1ab0,f4a8eda1,90480327,7376335,72d92c00,10313f96,9a0c5d18,c852597d,1f88020d,f69987bd) +,S(133bb4fb,1a16b008,80379e4d,ca980355,c747683,cbd7e81d,87a9eb8f,4219a314,30e76cea,f57f8b17,de6d31e,447fb926,b1678651,e980338e,8f8327d2,648ba25c) +,S(cb26bb35,4cf94461,c675838f,653c3844,24ce543f,32ed7b5,ec1b6b33,a2f7670a,d6f9be8c,7f3781ea,fc765264,c9e84f2f,6d2ff771,25b8d381,199b67c3,763c4f2e) +,S(7d944d40,58cb78ac,739b85e,6dd3be5,6b08fd56,767fd02b,1d5bba08,d4639f1a,79716d18,44baabcb,aded3600,ffa68989,45920de9,1f2cbc83,e6326ed4,e37c3fc0) +,S(c4577e42,ad4014,e1fbc0a4,d69fe37f,49937d1c,19a95765,74f2437a,d06e6589,4a76bf04,18a4a8b,af103581,b6c2cd16,727fccaf,12a3998d,52b1a095,c5388570) +,S(c71f462,9196f35a,cefd651b,3f6f2b30,485e35f3,305dc774,21535961,60a17a0f,9ff53452,52ccf823,b83d47a1,a6a70f84,b9c83142,db0136cf,d03b1f24,6ec57590) +,S(35acf6e1,cad058b6,7543eb60,ef4d896d,c21c4b5e,292c3885,d9e42cf3,85bd22be,cce4ea31,c9a37f8f,21e32a5f,6f272699,7cddc6fd,8ab11c0d,12c3ca4b,fe6b0e92) +,S(c2872bec,f2abb3fe,8a258b3c,51a2bf82,6712ec12,587cb33c,a6765a4f,e3a3e448,a739cf63,63cdf69c,15c9827a,f759e0fa,f7d92112,9bce9e18,bad86c0a,9f6bf467) +,S(50fa12eb,c3dfb3b,dbb61a16,a8b0cc6b,6e6882ae,f245360c,e5524143,27d2bfe3,873afcc9,5ed9a3e5,2f1b0515,d901e9c9,3677d49,4e64a478,11ec59c4,c3374393) +,S(3ff1688d,65cc134e,c6f27fa2,eba78abb,2cf22eeb,57163e2a,150ed7aa,17b3640b,ec8f8f66,11d8f7ed,a296e690,63b3393e,58d8bf85,90630da7,3dc2c0ec,e9e05870) +,S(91a113c6,c53b57dd,60b2eb66,e6bf7ab0,e721dac1,acd71d76,2c278b31,f2fc2701,beb6c79a,2fdba188,4f98ec5b,fd97626a,131f5c16,d4466a84,a9d77213,96220b17) +,S(732b5521,e6cb7053,ebfec5a9,c5b35f47,8da4a9b4,c4bc5708,42b0e8b1,242bad45,30afe970,fa640757,bff0e825,93a102b2,e1b619db,7f7d68f1,17f27543,e72f57c) +,S(94831570,f0146aaa,fd2a7ee5,11f992c,6e2999a4,b22cb176,dd516dbe,e0e16e5f,eb275132,385efd06,35baab61,5367697b,8bef0c93,14fac991,4a2c04e4,aaf785df) +,S(dadb60a9,3af95d47,cebb540a,1c0aecf2,839f1be3,e264a294,bbd03317,686726b0,8b4bb755,46efb999,cddcb88a,ad5b28dd,b73ae1c6,48c810bc,cd9d0f03,c200e27d) +,S(148ebf0f,7e23a220,52ca69ee,57237eca,6c1caf1f,faeb8718,b9b8dade,4b97be1e,32f68bfb,464ae6a2,b23ac7dc,3910a87b,89ff7042,e863ed3d,3038d75a,f3689f4e) +,S(ec532193,614ca440,33a8275,49c65e0a,af446a21,6705f9e0,68e448e8,6e882bd4,30277366,58dd1673,d9f701ab,50dc3238,f073a297,d579cb8e,2ee51dc8,bcd44b36) +,S(bcb65ed5,b16fe248,bddda875,28eab71f,d9357099,af71ddd2,9a8471e9,b2b26e99,ed827c35,e6e13dff,ade8b9c9,d2c620e6,576db5a7,1b1e22a0,3f943f96,cb7282c5) +,S(de30301f,18df0e9c,15d709a1,35c30473,28cd3356,95922ae0,f283290a,638d516e,89398261,37dbf197,53012e47,6846f6d5,45a48312,bd6f4c65,255b89f4,a1b9df99) +,S(2eb56a7d,b051e9a5,8a7c12a3,a92509d9,5da4956e,8b820006,aef166fa,92873644,30867ff9,7ef8d955,d497abfb,463838aa,c946d487,d702956f,b75ebf89,e25bddc2) +,S(88f839f6,d7f06f85,82ed781d,12062442,66d4f9a1,e2007a89,f660fd24,ebb30d5f,29ce1d8a,376a587e,96fae37b,521a8903,8f0bffd8,9f9934d4,eada0750,32faba00) +,S(112cb93a,8db33b09,641aef75,c3f9a399,b1808314,64e8a855,16e309c4,99ca9a16,66b1a1cc,f2255c2c,119bd0ed,a75dfe73,fe2e9d9f,3aa9a6d7,43a4b7aa,9d76bccc) +,S(407dbfb5,53b43e95,639aa6c8,d6868ef3,2f41f1ea,70cd4aa5,9d76ea2c,83b567d7,69fdde78,a4971ce0,b05a57a3,8891691c,d1fb371f,b1322a6f,97849c64,bd7b57ed) +,S(16fb5fd1,fb41d76d,ffc130d8,9549465f,7976a3b1,ecd6a4d,9e5d55e6,b2a6a40d,3d39a810,95904ac4,9559aa89,8fa087b9,b84ed72b,55f17fa3,aef8b32a,10e942c4) +,S(e40302f0,6c102ca6,e6be1370,2aa6e860,5e71fd37,6c87e2d0,c0ebbf49,6fcb31c1,d32d294e,1e80cd,94925538,2156db9f,2bea101a,f652309b,8943cdf,b82d75a3) +,S(8f2cfdc0,eadf8b00,f74305c7,892a4326,9cd31300,d716d652,92a7a36f,7f1b3b9d,6d0e726,838fd161,32d19538,147248a9,5d76c7c0,beadf1d0,b553e4b6,b7d1a2d1) +,S(c7a636f1,1a9cf793,4385daa0,5c3f3abc,8c3a1589,7be0b49d,ae789fbc,e07674cb,4f715f0e,e52c638c,954b8b3a,84baac76,6a891889,db0b7f82,6bdf81e8,4040cfbe) +,S(245aed6e,5fc309bd,980d5597,9380e8c5,79dcc887,a2758e13,24ed3a1,833dc820,a7980b85,c6ce770b,13a888ff,22a1356e,4136eaf2,49238c38,dd103016,f0d0b1da) +,S(91ea17c1,d90556a3,722dffa5,631286b7,f9db0f01,e411ac16,f5203c4,1a8a824d,281023e9,88fdcec1,94af265e,c407910c,54d25f20,69d64b13,c5261f0,c157a3c5) +,S(729db97d,35fdb72c,a354c65,a0e7f76,7bff9ade,964b1d57,a98f9bf0,39a74eb1,59596a57,7c888b01,6e00143c,63f0be1b,d86d95a1,ef59e075,fe7e377,1472bfc4) +,S(f8cb711d,f74a4961,1391871e,d8de6a63,89679130,b587beef,f4eebcbb,9daaae9b,4c52c310,c6f960c1,53f386ed,6842c4d5,bc1b4c99,433567b0,fbc40e93,91a5e022) +,S(1700d0a,32624d75,258d80a6,2228b6ec,91e66949,a463f3b5,16dffe43,b9fa08fd,a007bbb6,b687b509,f450908e,b617f176,92918f18,be3113d3,8a80ebe4,4ee750b5) +,S(9f2f3ee7,70a2c422,b9b92eb8,a52570ab,b5354154,57f0efec,fcd9141f,62894132,c977d79f,ef198135,b69aa3c3,77a7f251,3274911a,73736b2e,c543a721,17908588) +,S(86f75064,8a2b829a,91acae01,4beb20f9,aa9ee46e,8e513678,c4fbd7c3,2ac36e6e,1768035e,bd1fd375,7caacc22,495a5902,a3c616e6,49eeebe7,4377b996,30192b28) +,S(1d4207d7,adcbd969,d432bc74,35f2fb75,b35adbe3,fa1f45ab,bf3ee074,b8269f68,11d80191,accff888,928a0835,562186c7,30367e90,91d310d8,2a712a9b,13d70f99) +,S(f782bf74,2e55fd7c,ab249b2,1570d9e8,cfc12f46,5330d2e6,57eff609,7c3d19b6,896e9e48,a60ace9,84d07ebf,12449980,9d96639d,101b3405,59eed877,908394f) +,S(22bde2e7,e3c0d268,f556c478,82e50f2b,634c4235,9067cbd5,a0daed53,1a166a7f,5e03a94a,5baf0f92,7f4beaf7,6b7e9649,aa578eb3,f105515c,ed670c3e,e1fa3e72) +,S(85ef9f8e,b54cc4f3,aeed4769,85529945,7eb4f3bb,1e5849a2,aec7b257,a8a9a074,8a0245d2,f0c8eaf2,84a01114,d29c65f1,c146af0c,dedfb5ff,9e3be650,e2acaab5) +,S(3bd6c026,63620684,4d2e1a89,2378ec64,177145d6,24062d23,ce9c2d08,4f34ca81,7f0e5053,87fade82,8596f440,3687b04f,4a2693ee,25361442,1d9712e4,b3e0c179) +,S(364f9a2d,641173de,4a0cd185,972f6d78,75b06722,3cececc2,9bfb8aed,7ccd3311,39e7616,8d64795b,504de9d5,3049dcb3,a95fb3c9,affa2d5e,8e8cb35b,6cf71219) +,S(8833f933,f4049c7,98493b,e5f764bc,47dae8fa,baf420d8,44c7436c,eec27898,bf615e47,1b0f1029,1afb2839,2c874f83,ae55b15a,58e61be4,12b7c7a6,13868279) +,S(d4fa5129,4835f9dc,49cc3ad,b9401f61,97654f43,ec88f206,9a63852d,6abb4a6,f24535f9,9efed47e,80d66925,8924e56a,44530eba,a2aff32b,70f36551,1db59521) +,S(50eb8613,99f79883,58b9de58,88c47cd7,bd4547c3,96e1280f,2806efd0,d0715b89,dff64137,f74442a4,dd0c25ff,ea968845,f9e14ff4,d3e32010,f1c64ca7,6afb1be) +,S(f8608ede,92c5a1e0,5f61c065,606ae232,b0f81161,bcec88bf,b4f2b14e,22165cca,e583acc4,7ee133b4,8c3c1eb6,5d6f4891,b53c84ec,7bb352ec,3b6e41ff,aa6a2089) +,S(2c00145a,60e21169,98f23b9f,6f83223a,6ceafa12,c1b92844,2a17bd63,582a4fd,ed76c7cf,c65a881c,5dd270bc,7be9ce49,c2990e43,425ccb7a,eebe64e7,eff423d) +,S(b42d4c38,79f7aeec,96f212f,1d5bd79f,bdeb9850,ae44af81,b4b3467a,85c29c49,7bdbbcb6,1eb04e41,9ea8f9ba,dd5289e0,d718158b,63ef0599,55e3c5de,41f833f1) +,S(a5831ace,8c19fd68,85e9b9cf,34b9fa4a,9e80eb3c,36e256cc,44cbe521,6efb7128,e10dc489,3e0fa1ca,f2dee476,5b8ab518,c3778f4c,583abe27,af293869,c765955a) +,S(9fccb821,59ed46e9,18a407b4,967e1154,4566afbd,df6c0639,d5cced94,50e56b17,c430e829,438188ed,a443cb2c,aa7d6939,3004ed75,5ff61e57,8dbe9e64,251615ee) +,S(c1efe41f,44186467,cc0def62,eb0f0ac9,22b8bad8,e2347849,28b465e7,1789fcc5,5d73f89f,709d54d4,e167806f,a07ef07a,7fd1a7aa,dab9896d,33c290f1,dca74872) +,S(805c0816,43fffffa,c9055f2a,996fc2f,fa02b4ab,4fa440f4,8af5878b,4eadb694,b0a0dacf,d9b3b9d0,51ac59e2,b367a8f2,eaae274a,ee2b05d9,18cc0042,eb02b6c5) +,S(d5da1b82,9b477768,bec17829,1c9abc82,b595bab8,6240e705,715de420,fefe498,dba833fd,df1915b8,fb43b39d,dbbd635,8f12d4c4,31b547c4,af07a6fd,75fde785) +,S(73a2441b,1f1b9ddb,844caf0f,8cb0a91b,5adc6556,6f883026,8ceeca8f,7c6c5cae,512e46ba,b47e9eaf,64cfce27,24566bf9,ab43e32a,bb0e098a,5dac9687,11927437) +,S(dbff750d,bed18702,eacea6d8,b54540e6,ae60ea05,85d77db8,7a63a050,806037f4,1f349895,29ce56b8,bba91938,16e842fc,f74b56e1,568857d8,2f193e02,207f84db) +,S(57c73f7d,57c7882c,5d574f70,fa225552,ab3d7741,260bfd3c,b616d6be,9698dbb9,f633edba,f7f6cc7a,9d8ff9eb,75bced20,f865fc9e,81245e77,32db2ed3,876e42f) +,S(6663e27a,7760f187,a1f67823,64044da8,d4cb82ef,e296f5ca,90c5d81a,49b7cc5,4df0d12,4ca9c8db,4885f8d5,18cbf06d,f5b437e,242cf86b,b11df29c,5c83937c) +,S(83f688c5,88ee13f4,a9e72023,5169dbd7,ebbe0c68,4cb61827,3e2b75bf,5fc581d3,f76e519a,151ba05f,df5f11e6,f3cfbcdc,4b00776b,14c4598c,51783088,2b2bc6c5) +,S(2114e129,1f65c339,d1bd4373,6c677937,4385b3a5,5dafa8e4,a0515134,6b650389,88103399,1b682f7e,9ba02fd3,e104932f,802ed44e,b996beff,7fa9523e,c9c2a9d4) +,S(a68b163c,db6c8aae,8ddeda39,7d8031a1,394ddc36,48168f13,47774ad1,d569233a,eba470d3,4ae15c94,57ba1b3e,cf5f3d96,682b8095,f83eba7b,f319feee,6740d3e1) +,S(a44b2a55,baa92a2b,cdd2f06f,36874d69,40416b79,20bb6daa,2bd9edaf,c12bbaf6,d06941d8,28f1092d,3667ce3d,59d23159,54d6cbcf,c0da31d5,1663a6bb,ccedbb47) +,S(5630eea0,8fee5570,c094ded,917746e9,18535cb8,b0286bf6,f6cc294d,5714fd33,91f60b64,3457dd9a,b2a02ff,99f931e,b38b4d87,204de10,d8a30cea,ce576b62) +,S(cc8b173b,d3112432,cd0c741a,8620fc26,ac5c5d89,e05c18c3,13067fe0,a41b4b00,8cdcccfe,b4ca500c,34dc3087,58f424f8,52517974,9a33e27e,8859515a,2f7c0926) +,S(abe16c8b,e0c99bf4,d396e70d,af00af89,b5d95f5a,3ba33570,892d086c,4b807943,14b2bcfe,8cec39c5,826fad38,9b8f8788,51e1595b,b25b1a87,149d8627,1218e9b) +,S(62411146,ca2da616,b557f0af,ccc2cb75,d278b07a,4dacd864,7e449ddd,cf29c09b,d081b63d,67ff0c07,5f00a3c7,2771c581,87804c1e,4ec5bf68,faffbd21,4c71e15f) +,S(5952a672,a50af560,66de08ad,be4f5cc2,38f3e4ee,84160b1d,14534c4e,2b50ed52,f7d7e2e3,e9612005,a0344e93,454f112c,792f825,f3d3044a,28d9af6b,798da761) +,S(128fd5b5,420f68be,3742def,c987da3e,bca771d7,af1cf8e3,12d6b3ba,df162492,afe5edc4,80c1c8b9,5580dd8c,aef14338,c09fbf6a,a1c951d3,57ca4df2,9d3f183) +,S(6315678a,13cd71e4,6e283287,24499671,6adedf31,38841718,cf5168f,60d4bf8d,ff691d8d,c5f97f7a,f2ae319b,dc590518,6ec3bd36,7f492d0a,95cda47,9492ad3b) +,S(50277159,4169f70a,ab39095d,d8027324,e212f78b,c3b0865a,a57f1574,dba1bdb1,e31fb30a,58eca0da,aea93548,bdeb9f32,325d6c30,69b3d936,d610bbc0,de3b771f) +,S(51eac8f8,8cdd7ac2,46375960,c6b7d9fa,a89352a5,4024003b,cada1e6f,df389721,6d4c8750,95d6ccfd,9d8a5830,c4672c71,d414ffe7,cff2cc15,b7b5d169,48e872d9) +,S(bd39330,76c0f542,a0590ad6,398b2418,92b899ab,75ba0065,b1ace928,b8cc0ecc,12f4bfc4,57e97c3c,9d4a21c2,ad106ee8,8cb5bfc9,92d151ad,589e90f7,d65b5d8) +,S(bd0eb600,5ae967e,81214a1,889f7dc5,d1e765a1,af74a93,f5292758,539d6dd6,2e532797,9e6a22a2,63025e57,4805e4c2,6d62b33c,5269d35b,bdeee7f6,4a2cfc3) +,S(b7b068b6,8ed18d80,67a0c971,a06cb3f0,5c96ad7f,371dd849,aec3a2f9,bbe23eb6,89871d76,d3e6b605,9997345d,4246087a,a3fa61c7,dd75f5c7,b2ed1e20,59a00350) +,S(10cf2c38,643a08b,dd842c4b,79efa2c0,3b5dcd1b,c708b253,ef71fba7,f0e51f48,e37d14c,934524d2,dc562f6f,997227e1,44094184,e8342995,d5562000,34e71f4f) +,S(5936b571,20b6dc97,ee242ba2,deaafad4,5ab83795,9f1e7390,54a0c026,df7bb342,86bab74f,b9d4f776,e82831c6,3a409237,d5923c7e,7b3e0b18,12ae203b,64fc750) +,S(67bb9ab0,bc48fafa,3ca66493,995ea995,e36cdfb7,152d64ed,ddc56aa2,6c315896,cfa9a456,dc2c82b7,f87f4216,e365f5e7,97223d2a,820a127c,a5ee4ee9,281b71b5) +,S(5580326,678b44ad,fb313c23,dd8a7dbd,c6869fd,70cc58b6,d20f8b92,ecfd81b5,6d343687,f3dc733b,55dac794,c895e5d5,9032613,563f2d72,ee94afe4,c2a932d9) +,S(fe285767,53d2466d,d056d2bb,b7141cf7,e52c2b96,d0ef3c8,52c728a7,d2dd8126,f344b3ad,c8077e92,24c6c5a9,c9f40a1a,d8721351,6b8691ab,c5fa9f73,726a6c98) +,S(12f25359,638fe4f3,97a17f99,c233b2ea,7a794d71,e677b206,aa32f251,8cef615,dd0d68e5,324e4325,ebd45766,441677de,40c15792,19d65c6e,9c63f15a,91519c20) +,S(f1e45fa7,21bf7fb4,45fe3eed,29c26bb8,bf1ea59e,de7c1a6b,e652663d,233c3e9d,6d145f2a,c3a041a9,83b9865e,66775342,a0f8a435,de19626d,ca8b9328,797e20eb) +,S(6b6ab442,d2623235,dcc7e3e4,85d00ade,7f219576,509c528e,6a3417a4,fefd328d,5d627367,ed25278a,6d3505c8,e13970ba,253a26a3,c605d11f,1eb345c5,56584e95) +,S(83e10be5,d21bbef2,ed1ceb33,c4e558ce,bee76405,257d9573,51f5d90e,f219552,41f5e174,c6e9b283,2a39c2fc,4d4fc573,634a8975,e143243d,14dc4be3,434a4380) +,S(2ba25948,9571ce20,f792129d,f43caf4d,ddd93b76,e4c8cd63,7a9de68f,f8d615c5,9469a49a,d1a814d4,2f460325,b7d58f2b,eeb85183,a370cc3,69a685e6,a87f6e61) +,S(3fac1508,b669f540,77a840ca,3ddeec5b,b70c03b0,ff93a77d,f2f73df,2728f36b,dfbac9d5,ceb21745,a6d27c3f,d6fd96b,af708066,a3bf765a,208b7231,d5fb6955) +,S(8996dc02,9b79d0f9,d57b8c8,549fc01c,2e1c1c7c,2ce2cd70,7a0bba0a,b3420ee,d08fcc05,5194c4bb,2d17ad54,2f9ec734,f2a9ab8b,a7dd0467,c5d916aa,10f7b8b1) +,S(16af9433,c9baf15d,921f931e,f530a477,b04b2e03,e1e8cd05,42e20628,df7c3241,65863e2a,acae34b5,a1dd53e0,5efd423b,165235cc,69195973,2d0f64e,c5b56fac) +,S(d82af39e,eda70e3c,f28e2f6b,b8009131,59ada2d3,854e81a9,3798e402,43d1d3c,fe03de8a,326e8bd,b202b5b9,929c2f3d,4bc8abea,a2377cb2,29cd4630,d1dc1c50) +,S(a7ad92e4,7a442903,c2f91033,7e2ebc98,14bfc943,f2747eda,666bc813,c04382ef,ffba6b43,9379448b,56b20163,44439b9e,8d6da764,72f67a27,9c7f45a,359234c1) +,S(fe9b9274,7b27f7b0,6419dd38,53e61762,de7a5116,48008802,681bf521,21a1ff92,f32bec26,b9d24872,1a47c65b,48426130,b8e72e68,d231bd4d,82c5d4c2,bde605a9) +,S(8e22ed5b,e5d80940,970de428,5ca609af,872b8a4f,b8c93942,fa1e62d8,588ac5f5,6a461962,b74b0f93,afa72284,4837ec30,b99a65da,d688c161,cfa42028,2ed97167) +,S(bd3bb0ec,bfdcf06a,62f0046a,989b45e9,c76f4d9e,b3225495,eff70685,71518fb2,5592029f,3eed8e35,727865f1,dd2a6de5,e19e6eb5,f92e520,529fe97a,c296820a) +,S(50a9dbb0,b08a48b8,76dc65fe,6e2efd92,d44053ed,73b8c279,5b688e00,a1fd1455,4a1fae82,51581f9e,32fe8f67,5675ef70,dd7c2ec6,2a42eb3d,e1aa13e6,717df147) +,S(6c1dc44e,67b52cf5,a4564ce1,7a9da713,c718833a,6d527e7d,ebc6b1f2,c893693,89cb4508,681d58ad,77900c1c,aeb25c59,b307c9f6,c84f1329,35e32af1,e39f8f67) +,S(3ffc35e2,4d4fd0e6,ffe4d1c9,b5097d10,c12dc7c0,4356cea3,b5fad66b,5f3333c0,89718e69,78748c6d,e99d181f,137eb74,6e28b05f,27af7726,e86c5f5c,daa1eaea) +,S(fe2261bd,b40fc492,99be54de,1d0bf22a,634aec85,77b5e9e1,51626d67,3f4214eb,896bf33a,5c9b7537,b621a168,f3da1bd7,dbc94816,922350fb,38925c96,5e57c175) +,S(129b6e5,dba2fe86,749274a4,f1ec5999,b2fc682,933a1120,cb8e16bf,4f4131e8,24dce651,b0fe4770,6c78c217,f0d5ed4d,4bda4e7e,4e7ea6b9,ca59e751,b018b5bc) +,S(c2d1b280,79d91abe,1a44c4bb,96ab548,90323054,94075907,37b39ea5,e1fedd72,6974b9f3,80edabdf,e7961bbd,71ba1971,ded6ba24,90466d1d,a5715d9f,92472637) +,S(d8dc5f38,76f6049d,a9a5c9e9,396d287f,911e06cb,ac0148e8,26c8de93,15bd464c,701d0a43,ab41f321,b8f86ea1,b1f51d0e,c22a3399,c1d8534a,433ebc2,38ec248e) +,S(2b1a41d7,ebb9756a,b62a96fa,57909ad1,a747dad4,b3730da9,a12dac8e,3ee4c414,8ebb1512,3f43224a,c2cb4ba7,c90ed765,5470a968,454d0c81,1ebe3384,5c6ca968) +,S(724fe9d6,e7f75b52,7da19421,3c984e31,f63ac3f7,1b5819bc,344ea339,567bc179,a1db688d,ba1d85fb,20da08f,802b5195,163d179c,7bc60f70,4ade1f26,4e1552fc) +,S(835b30f2,8e54b834,5ce95569,7d71b7a5,7cd4b5b3,17ee3fce,57722454,7695c9bf,f431ded9,b7ba9477,ff041f83,22685e4a,8c88c91e,15a14f21,6b16e302,e243cd11) +,S(f5015d22,16cfe581,e650e579,c49b6ccf,b5ca4dc6,42561256,21df7fc8,19047ee6,45b099ab,febbb493,5356872c,40c06825,47aaef2a,72e80d27,521b65ea,e2d4918a) +,S(df0b1b57,f3a0dde8,b136a92f,bf953a83,694244bf,99782ea,98050bcb,3313f826,6f7c8326,bf5f6e15,538a1f31,273adea,6908e5db,7f38f395,49284822,12124d5) +,S(a5a24cab,96c04bdd,6e5180a5,8fe27f9e,51897bcc,3a0aa9d8,de06de65,53d2890d,4f6dfa5a,a6b44550,105fbf39,7dce3a4c,e0b42362,4a97d979,eb31324f,f1215525) +,S(849c2e79,422d1dce,4b568aa4,c80eba4d,d8acd237,71f6dff7,40849bd3,ecdb7e41,a465929c,a3ab167a,dcc4fcb1,7ef9102c,35d8937c,fa900ef1,8022918a,6ebfe79e) +,S(a9a98d5d,d8f8ce0e,ddcd90ae,671c52b7,1b09b75d,b4185d4a,1ff12c71,70b499a0,a4eb522e,3aad7f1,6aec7758,c9528bb0,c07184c9,e3c965f7,afefe128,bd285c5c) +,S(8d60786e,1ec1fbe9,61e056c2,d6a57c5d,813d7f20,bc8c68ac,eea0020a,2c4e57af,3a39b0f1,6cc346c7,fc695f45,91b557b6,3c1f8500,89d742b1,60c39744,90e55720) +,S(4710166e,65b9a2d,8de5b80c,192303ed,25cbb80c,b91c57a0,b31a38c5,5c218fd1,b4cd95bc,fa48a016,658382af,37ada302,26887fc9,8200f77c,2b8819a9,ef489206) +,S(e2183510,40815901,c78a304,e6f0d545,5a116560,a91d84fc,157f061,5ed6c0de,6c557bb5,358454d,419c5cb5,1bcb85e7,db3b04ba,d18e1a63,a75687c9,8fd6d973) +,S(807cf529,8730d656,e68b4aa6,5f8d8692,ce246c2c,4e668c69,b5e93e8c,d26b289c,b22a6fc3,d7ffdf57,f18e7447,38cb1bb0,aafb7b39,101d3259,d31574f9,fff644e2) +,S(568f659d,f19f14e1,5d91f3d6,bd2a4690,b274901e,cf6fc684,dd0d8615,8dfbdd85,28eaf8bc,1db68471,4ffbfbce,30977c7,606bc591,dfb8ec02,e43a31c2,ecafbde7) +,S(651dacbc,564fdedf,f4e5e3b6,f2dd366,37c69140,7fa923a8,ce88ed1c,a65e6b86,88dfdb8e,6f117a1e,b99ba423,89ed2db6,cd5608e7,8be2c896,334ffb8d,2e19aa79) +,S(5a17c956,8214ae71,80322b0e,574529c4,dd7d951c,872809c6,b33ece6d,8cd7cd0d,ba4b0cdc,7d7e6ff9,5a97e4c2,6af714ae,f00c9142,5e562ffa,16942fe2,852a3e06) +,S(6d564251,5edd2987,568dc237,b5b98fa8,de9b86a3,e7176e62,f2609dfd,65810920,a99a0d1a,12534f64,fa97227,825b094a,22fc16bb,e8777669,d5aedc4d,58e81ff0) +,S(e3687c75,c0689381,22f60fc5,b346e8dd,17b2dff9,cd7fbea,94aa54b7,ba1f6de9,4dfd4537,1f62a968,399cfaba,87a0b985,cb333510,dfca666d,395e0f8e,2b7f473e) +,S(1a3d974b,49e7e68e,bb2851c9,c9f22d9a,5929ccde,9d635e8d,61aff93f,f7244472,f6c9e7e2,98815ef8,d53a7bd7,9f10275e,ea74ccd8,5d97cc3d,cf2e97b1,83c97c86) +,S(8e0dba73,12c4afe,8e1bc508,4d9f4944,654a5693,81a64158,d7db7007,3f897cb3,560eb34a,2451905f,2e9daeaa,63dff50f,761bd68a,2321a714,45930de0,4801875) +,S(35d9eaef,6c4ded5c,371a655f,2fdbac45,35471c32,b369955b,f8f30d95,21cd5817,c5a084ba,7b2ea4c2,e3c3d081,dab53c9a,ee40e10f,607ce88c,899f0e3f,5850d75a) +,S(44d1dd16,c42b7811,f78374d8,2ec9983,7fbee7ce,4b3a8ccf,81ae4ed6,3b7d2c73,6a7bd35c,b10c4e89,60e3eba1,8f658510,3be8d1a8,5c4932f9,f1e48d81,e3f66604) +,S(4b7a54a5,e7153a54,e4400ef,9311d6,cc16f641,6695fd92,5fcae9ed,6b2738d5,43a7bf76,ac2f663e,daf0036d,b665291f,cf983c0,791a8a6d,a5ee1956,2dc18850) +,S(add4a15d,d1a350e9,e5df62b5,4a6638d,76ee221a,4007a19e,db5bc93e,87f11ea6,c26d6fcb,3a8bc1fc,f1474c26,31a4216d,740cf94b,a9d7e48c,8f01be28,885ee849) +,S(9b52aafa,119ada49,ce33340d,ff75ac50,ac9a9d87,775e8e45,da58452f,228a23c2,67640253,503b5e3f,89f7ad07,b9379bfe,77c946d,4f61b83d,3fced91b,69e850af) +,S(965916f5,89854944,26c1efb7,88079a55,f8109cb3,8bb111b8,42ef7f00,2d4a45d6,9aa2ef4e,61902148,aea7769c,a561d04b,cbe1b340,a231388,e332c30b,8488e531) +,S(3af7890d,c045aaa4,2f7a8f26,5fcff9ea,41bae0f9,87c75c22,3ae3311d,e09b6ffc,dbb31417,27adbd5d,e34202b7,f7a880a2,41f18b0f,b1a40a25,376c4a30,ec607152) +,S(dc465cfe,c07f839b,46406f4d,9a0078d7,57c2fe0,e62aa4e2,212ed33d,5b2026a,1ef12aff,a98868bf,b51901f7,2693f868,5ba2248d,91440380,53bd137b,24b3bc8) +,S(5ae92f8a,cb9e2ca7,2f4d4c70,f4daaf96,bd237bab,2a83c0de,693d8207,baaa0f4b,54e266f7,aa1b7f22,8f24ab91,5e3f0a92,3220512a,de239da3,1069bbf2,35d63049) +,S(38134bb,c6c5a4b3,63421af6,ae573ce7,20421d36,1f4966c7,b9e7f125,f49659ac,5d42678c,d6f89848,72399321,fa86318f,7a4e3f05,4c3bc6f4,6782be35,4ac4aa16) +,S(f2b807a1,3fd603b4,111ac02d,5c646f6e,eb819a4f,7893992b,9132aa83,76892a57,6f1beea1,a315c000,3c957d85,bc5171d0,ccb8ff06,446f4748,738a3c78,f9ec2d4b) +,S(debe05cb,b308a6da,a1eb55bd,73c3f1ba,248ade5d,ceb1ef3a,baecc6ac,7a5e8c09,f4fb16b1,44beb4ca,789aff58,9374e476,efccbbbe,b74e2693,a4d05ba5,a809ff05) +,S(15cbbf1,2720f8f5,fa1a7752,b6f33333,91cf3d0e,c40f0292,24f5b7b2,c966c099,be3b1573,fe38200,a464f4f0,c3c2f9d6,24bd59bc,9412110f,6eca2ada,2f1c7294) +,S(e4fadc29,2f0cf77e,4b14c3cd,b567f5c9,be82fc93,dcdf2b50,bdf20fdb,f5984769,2858e2ba,c9834a2f,942ea7fe,2e339d8e,b384c255,6a48d688,a9510808,a1235452) +,S(b0a8c6dd,f57434e8,a8bee1a9,530cb9d,3d4ac31e,edd17653,3d84780c,6909554a,4f7467d3,62185e38,f6d6c30,e4c3e4ac,e167f3cb,aefcab8b,eac754eb,c76ea3dd) +,S(a4398869,26e4d06e,5337e61d,dcc6f491,4f40c04,eb3ec752,47d9d058,9dfea2af,ac1fdc5b,70d792c0,7bf7e55a,b07ea1ce,477dcef6,cce8585,84cc90ad,c62b6272) +,S(84b362fb,1597f179,f30b7e2c,b516153,94619081,1131d45c,ba55fd1,94f369be,d2a80ffa,44965152,78c2ee3b,122b5c3f,e6d27f9d,6ed6ba94,9258c2fd,94eed4dc) +,S(75182684,96e2d037,24c11192,e9112501,f7c27d19,8b92fa1c,3b0e931c,2b85d32d,eddd2a6d,d884f93a,b6f8d225,c9fb32b8,9f396f1c,2613be98,d866b713,14a00d70) +,S(aa96e0b8,104884cd,7e22211b,8b12e6e6,b3f3e3f7,fdff04fc,202d8946,838fe15f,d8a9b5c3,9739fae3,dd3b2483,4fd2981d,ea529097,2ba52541,56905664,f289e3e0) +,S(ada17e80,82a0a15f,366f3d6e,6775b5ef,35c980f7,12ea7522,1aa796f4,2454988e,7df4c1e3,191214b6,e40fdae,2f5dabaa,b6e9837b,f53eb10b,dd28e674,230cf2e5) +,S(322a0524,20f0fdbc,85f35fc2,de6690e5,a61260f1,428ec662,4185ee8c,d2385caa,fc81cabd,789995e7,d36d3de0,1b650a20,1befd7a7,a415d250,697114e3,c95e096d) +,S(5082ad62,3bf2ff8c,b4571b9b,86303032,ecd137bc,86c5514d,b9f218c,4f091153,b29d3823,eb4ed958,9b0fbfc9,2d006fb3,698ab596,d3e60360,e435bbdc,be4c80b3) +,S(de9e45fc,e9e0dee8,3bc806ae,286a2c5a,a7978608,42ddf02,d29a6ac3,9fbec470,bcda9466,e7207f7b,7d986e,36b3f238,d5bc51ac,90ec35bc,56e0949b,334ef964) +,S(95cbc3a5,61ff4cfa,278678a5,6f8b16a1,efe2d286,c7103047,310454cf,a1a822bc,8720fda5,58d23b5f,af9b80eb,dd5fa625,93325a6b,eb5ffbd8,f333cd9d,9c8b7366) +,S(fa0e59a0,969de9fa,aaf7be60,24136559,cb384b76,26d3bdec,f70f3e55,696a0632,2e8af3c2,a54e837,ddbfc32d,8a47f342,a856b854,7ec4b0ea,6fb3695,48b8b588) +,S(56aadb8,2056ff5b,3337aa5d,337671a8,77168b0c,f0330e8d,8f5445a0,cdd75075,d6c4cd4f,db81d8df,b095f681,f7349fdc,c2cc80d9,399fc16e,5fa3e86,9460a5f0) +,S(7da6a13c,11d5b063,8132254f,c064ff3f,d3818a5c,e07168eb,ed5b7345,53bbc19,26e912dc,5b03258a,f914cd86,88d6a068,266eef77,7d4f45f1,7c47cf92,16d00c4c) +,S(4004b235,d58417a0,ea1a2071,32b30a8,1dcd6a9c,3ea875a3,6d2a6225,e2b56917,1c960bd1,443c22fa,96f06eff,a717b5bd,efe8b105,7402cd93,7a6aa909,5775e226) +,S(b12c4d85,6ec6c85f,3553bfee,c7dacbf4,f742ccc1,356fbc8d,ab3d25b7,52bdfe93,a8a11692,49dba87,8c8e6c56,ff8f699f,d7e69c6,f994d05d,4e0643a9,7f9cd2e2) +,S(a78d9a2e,8b74ccdf,97c6ea9c,aada2644,8b560287,7d7b0970,41d24840,91490970,39cdd434,1d1e16dc,b89fe937,665e70da,ea80a174,5ae7b99d,dcad04e0,efe841a6) +,S(c8233855,b1f242bf,59b86372,ae49a985,2528440f,e3aa8e,28d594e0,114d2ae8,6f515202,a14738ee,ae4b430c,27391144,c551bfe6,bf24005b,81f92900,bda92b7e) +,S(6da24dec,9d6ec569,8dda9655,672a9b79,4923f595,9157af10,64cb53cd,5e5e8f6d,59517e76,8b0d39d0,2c075a46,c1e653f8,cf876fe,cfb10746,a8c248cf,4c73fcba) +,S(d0c55dca,ab79e0c,84ef08ad,57ff67c5,b36336f,2f6231d6,8efa2fac,54558ef0,d4365ebb,4096888f,c9a74d90,1adc4c5e,16f5dddb,442cb5d6,b5e22b32,99aa573) +,S(d76f084f,237dedd,ac8a1936,319d198e,baef2c4a,3b81ae42,e92f96b6,e222490c,c7737563,9639b7c8,32e4bf45,efc8da2f,53e20e25,641ea714,85674a40,1dd5f14) +,S(6a1f6920,9196c02e,6919abd2,c8fc835b,889c5ca1,6bb25e3d,ef7d0c4b,9f4e6d29,84371bc2,7bd206d7,389534ef,f2a49c6,cca4c9c9,874f59b1,ccc8b5b,bd5df3b) +,S(693b3520,85e1ea36,bc5c8ce8,3fa49843,369300c5,170010c1,b11a3c76,4deb12d6,4441c9b7,808b1ba9,8199349b,243f08db,6cdf5326,d7453828,16f008d9,45c1251e) +,S(5ee94c65,70953f27,37c16a59,590f7cd7,87143bab,405f6b23,718878c7,bc95741d,8578d18e,a49f9204,e51513a8,94920224,70837b2b,ee480929,5e4c4f0d,cf5c7794) +,S(30c174b0,e7b0cec7,e6da6a5d,335f48ee,6f59ef16,984e8912,32e874d6,2e51fe2e,af7f955a,8807444,56b2c965,5c4ad915,e040a360,eef0c4c7,891db1ae,6983867) +,S(3121068a,eb60a54f,dd427eb0,92e30895,92335900,cf191eea,79118442,67b7f4ca,d9e8f74,b8d9c0e7,c35e314b,51a52a95,bf672adb,9c6fb104,8d2ea489,5135aeae) +,S(a06f5e3,6513a659,106ec301,cf1f2df5,6093e690,38daaebd,4b17ea45,9e977ff1,eb19f18a,15630965,d2bd8bce,9e350374,1ab35f0e,4b442f12,9c9d831f,3811cffa) +,S(a26af0b6,50967dba,1c4a33b5,5226c2a,ad445f43,84567580,3b97ca1c,f3d217c7,22c8aba1,604df49,abe16949,59b33cce,db11c241,cbdb171c,50b0fb0a,399e6839) +,S(8e4471cb,b650097e,d3b0e938,18b8ec5,a86fedd1,addc6ed1,8703a99b,4128919b,fa5457bb,4068bf35,7b050244,6eef2507,c1d87051,28770161,ef0e92dd,d2308495) +,S(e9116ea3,24650463,fde960ed,eb7d5dd1,f5754915,62c99f48,31b553ba,2663ba1b,e30d7323,fc29e388,94244422,63434cdb,aebc5895,8a6fb350,33141e96,46a4529b) +,S(8b2267e6,9052f769,833b0fb0,ffe413f3,4b8edb93,9a2009b8,59d6673c,4ca6ec37,97f80a18,ac047152,178432b3,d445a0e9,84755d9b,7ad43165,8707185d,d573fc5e) +,S(79947669,d7bc732d,ca08e0cd,d3e601f3,c4344532,e35aa7a7,12271b12,339ee2b8,55906cbf,e782d32c,13cea8e,83812e8c,84c76d38,472ee59e,134994b4,b7b92897) +,S(ca6d40aa,2f863c02,b6444727,d00f8923,ec58afec,3b4a4e51,f4be232a,4b4c7c7d,ec73856,b0529f1d,9d2ed892,b22b059f,35e4a91b,b60c6a6d,e919d611,d9bd90e9) +,S(7ba23bca,5f9a88c4,588dec37,3861b699,ddfc9f5a,5b277bc5,e6e16f54,513fe7d4,25f10a4f,eeb77ff0,e24170af,dea0e2d2,3f2289a3,e53ad674,1640cc69,c042dcf5) +,S(186da622,d0e8a9ba,e26d43e0,b601c68b,311d2046,4eb36f2b,f86c3e0e,5d4ffcf7,53a6f54a,dd11af9d,50bd82d9,70825bcc,fe9da1d5,ab55e64,bbe4582b,f5248d37) +,S(e9601474,568cfe7e,6cdbf488,63f11f12,fa17ecdd,c623cb11,4818eb52,cafcdf8b,96d51b2,7b5e4fd8,1bbb009a,2ce40fc7,65fc6a3,7f8bda60,c4927766,a52267da) +,S(811f5957,accf9f32,3e48ac3a,33fbaeaf,c5120858,943e7065,9c0da185,71d1d4e9,ede77562,cc8ac601,e3dbdfb5,944d59af,63bd1aa2,ffb35bf4,1f79c418,d1d67937) +,S(77424acd,1d55424a,edb0149,a6ea0349,afcf44c6,667caa51,302b70f9,5fddf277,70e15309,989a2512,422a5bff,221c0e0e,df608746,7a34dbaa,99e77f9c,62b56c3f) +,S(e9e139fd,73c2c50,375d3966,ed4af6f0,4bd80bb,439121,d61bfe66,99dabd2e,260efa55,805918e,d45c98b9,c119bed4,21483d88,722e0f87,de7a31b5,e4b541fb) +,S(a9a5313b,e634813a,b10b9b3,6b38ed1d,a971c0de,5b6d1010,4cbe426d,544e7d79,ef7b3203,2a95144f,17803f09,72f6e2cb,80e6a099,5196911f,916225ac,e97bbb97) +,S(ff29a1dc,b5c97b7c,c5e2b73d,7a0e0244,bef71dfc,765127f5,f7e0f38b,f8a099db,b8334f11,682b9a22,ec08a376,dc3994c2,7d235d5b,a4a77803,79ec0fb6,7b4d0345) +,S(c98df4d2,da452118,852c096c,bb34c8ca,a2ebcb6a,e9a3420d,a4fd3eec,cc31c5f,f4f9c618,44cea236,edef80a1,4634159c,72663322,7372cbda,4b2680,b5dbbf7) +,S(66126139,77cfafb2,283e1a92,d6327174,86add807,b88cf793,12fef2b7,197289a8,504387f6,70caf906,2db248c3,ed5faee0,269d0190,70dd5acc,c8599f5f,5e01d1d0) +,S(efa8bcf,281ad4da,2f083e6e,182765cd,ab0e66f2,e8411007,e216a69b,d73d5e94,6e1afd7,e97061c6,cd0794f6,837aefe6,e8ab76b6,53d80846,98747ed4,64e20a) +,S(d4f9fa7e,6e385f02,c068ce7a,1b80343c,20f85b7a,4699c126,575915bf,69a2f6e7,a6496004,f280f970,c1028b3c,e0d94187,34dece11,3f9fc737,2ef0125c,851de143) +,S(5980a5c,456f383e,f0add523,13fe37a8,874059ee,497b0a23,c6dfbb2f,9f6c494,e1da9a59,c8e3d482,ece7972,9c77308,e47bcd90,cdff915c,32a94908,db1651fd) +,S(988ca976,ac6bcfb0,b42125c0,939a1207,2eb13565,29da3e72,6b70b2b9,5c310e12,97368d81,79a76a51,7c7d063a,179a2941,fe5df19f,25f1e1fd,42a32af9,d5de16cc) +,S(ca49ad0d,25b36130,cc878861,f4b72a4f,e945bc0b,dbae2f4c,629a6375,3d88037f,5ad2c0b7,2e084bb3,95b9268f,22ba1774,c6e423e2,4a5191d5,b940c89c,e1039f0e) +,S(ec18622f,b9771723,c8e6e6e3,5096e517,38c4dafb,82b10317,1f55f900,b24c2e06,5803ea86,c839ddad,6c288b8c,b382a1cf,76a790c5,6f99df9a,fc9915e,eac6dd61) +,S(c53aa261,60e627bf,bd905ff2,6b50a171,18062ebc,af9d9ca0,c486430f,b6de5da2,7d6298e0,f17a515,529fc5bd,2b85c7ef,d183710b,96d62a2c,5a0195cd,ea561790) +,S(ad138110,f9161559,229ead18,4b7ea7b2,846384e9,dc22b8eb,5b771027,8c8913d2,135a3ed1,d9df6a0e,105c7c,e6ce625a,f8173d76,60ea04b4,9ee781a8,90595eef) +,S(46946390,304df8d9,15705fc4,5714f3b4,233a5ec1,afdaf145,b6c09717,9c6b43e1,aef28d5f,88f62a7,e3ecb978,6efc97f1,1123fde3,88ec1bed,bbeee3c9,f9d3e014) +,S(d464a300,df9de2ee,220ae23,4d59b6cf,44f4d280,7ab4f588,aa21dd1e,eeb80819,89988349,b1ab280,8b829754,7e5b36cb,e66ddd16,4d7542d1,cb0cf210,44a8be1c) +,S(5e99ed21,9ade424e,25b807c5,bcbeb05,9b638b7a,4ffb3c6d,d3bd054b,b7af9f41,a373ab0c,4aba0b04,878451bb,96807604,7d811fd3,605e8e46,57574efb,21681aae) +,S(805edc92,6fddf92,d33db068,9334d778,4b30f73e,4e65517,42e62c50,fc6ff2a3,170e4317,4361275c,2102aa8f,5406ff9e,7bd35523,8bf1e946,1a6f16c0,38beecdf) +,S(ec6e5a3f,bb96f0af,dd700701,8c046998,49a879ef,5ebcaf67,456748f2,f25fd18a,9401937d,cf584df5,a9399fa7,bb309ffe,80ae015,20933d63,df1fc181,b2979fbf) +,S(94f226aa,a25c710e,2cc68683,2b9124a,ffc5c3fa,179ace52,327c6866,cfdbb3ca,b92762c3,a4c56d95,1ef16db7,b3992e9e,aa2f9c3,ec48f077,62a379f8,408f94a) +,S(8d2668fd,5d46bd4a,fc84183f,4fc31dac,964358b,fa6b03f9,16ac5bec,a619a92d,c24f6815,3e49048c,a461eea8,ce50c8db,7794b10d,d8080236,2af6677b,45e45f95) +,S(2a3ef112,d00514a,c562de17,a68bc4de,c4c04db7,8266892d,b645ac6b,ced47f67,6e93173d,64333933,c3db0f56,8c05410d,8a1dc73b,6a30c6bc,2b0d5493,d9f9fe1f) +,S(6eaa1185,19d6cdff,45d88426,6fac5867,790faca7,4ccc31bd,6eb19551,8f752dd,affb02eb,277a2bdc,db79d91,10ee8a7d,58c9662,22cfac03,b3d26cd6,3c678f9b) +,S(d17802d0,1944d9f7,aab2b542,fac985ce,e56172b9,e5629e53,ddf57e0a,8dd07137,485ae7ac,34d13d9c,9ade04f2,b3fb8cc7,d0cff406,97abbe2d,4961e753,b8de013) +,S(9e4cd82,67c121f8,96c8104f,988a140a,71f0cf18,782b574d,407a4840,607f5804,c05f08,3fb5c4d3,9d3e237b,101f46e0,6547828e,f05040ae,87db7874,9d7f3bf6) +,S(927758c2,12452995,886e97b4,b1d16c53,4603c,7362e190,dd2558a8,43521a41,30e4d5df,c5ff4b5a,5f4f757a,3483234d,4c658b7b,f24dd509,7968627a,a2a86d56) +,S(589906c5,90a1e143,ae7ea4fb,84edc7a,9f00bc90,dfeadfba,1933c36b,57f2bd25,e9d1d51d,92223636,cab62cab,362b79b2,12a18be6,6468f06b,a543921e,bc9b1c61) +,S(5b516216,1171c076,b10d4987,3aff89b,c080d2b1,9e3ebc3a,de8dcfd1,734e2f35,572c40fd,24965ce8,a78c3402,381bfd90,b683d6a0,d379d7ca,21e66804,31b8ffe8) +,S(1603bb4b,3dced105,b1a2b748,21080a5c,2629a52b,56823524,84deb617,2f6a9694,2dc4243d,fd20fd16,d1f2798f,23e43be5,f88d5feb,1f6fecca,6fadd5c3,f5a63c37) +,S(7bbf7555,4c14bf1a,63ef9f38,ae3ec279,5cf0aa1f,335c816e,580bdeee,10d95ed2,d2e12648,81ba6d5e,e8cf389e,84e37ee1,7c178b8,dda63756,32d9330c,beeeac53) +,S(b2d3aee,d083787,eb4e14f,328640a3,c557724c,e06a62b9,17134ebd,fe576073,68cd90be,2df0fa6b,da2693b0,f18357b7,ea5205e,2a1f5fd7,5a1413b4,fd9ce0d6) +,S(dd10759e,86121fd,6296f171,57a90f2d,bc217238,53969f85,4a71461b,27df81be,713442b0,65546c39,1b71ef30,3bb6ebc0,659471be,fc165a3a,686aae0b,270f13c9) +,S(54229d57,3a274ca,6eda6194,62dce4b9,35ed143d,16e470f1,239f1045,6dd2de16,a6739dc0,916112b7,4fd6ab7a,134093fd,55541758,5b3fb39f,da647bc6,5cde08b3) +,S(141f3cdc,124460ea,15fc80fa,dbba8fce,d89c4426,74e9a3dc,55f74f69,66bb8ff,f0c8d7d4,dac4ba66,1768514f,c9bb9e2b,319645da,735e5be1,51790483,d7b477ac) +,S(e9795743,efacb0d0,4c91c74d,33837b61,8d08acc1,cc2603ac,f02b1610,16fd1363,9f1c8ab6,735f3161,811f710a,1b5703d6,aac65c23,35fc1af1,32ba005b,bbe66d7c) +,S(e5e8c40e,c6c9475d,d4cff6a9,c9db5cb3,f8202bf1,bf60ed41,3e213d6f,2c860797,a9570e76,482a8177,b1adf9a0,1a7716f4,b1e754ef,864d2deb,354a96dc,ea1decb) +,S(5292362e,a095d145,c002f027,be53a28e,d5244982,bcea97c,b56d9ab6,162f7ae9,e7f00a61,8e63664,4555170d,9f13420e,fe1849dd,641bbabd,d3648250,81934e37) +,S(a6772998,3d6a765a,67e9e3a7,45e7de0e,1e42f34e,46b7cdde,8ab20262,ad246822,53281b0b,bb45bbf6,a1e804e4,cb6f443,537b4bb,d551c9d0,8976d53c,1020407f) +,S(7ed3bc8a,8a68ea64,c9dd316f,48f012ed,229e5f9,1a294666,4546ef68,bb48959a,238e6696,a7cac135,ac551927,fef28c04,5bbf23ac,9d24ef52,3d69aaef,27312e69) +,S(96702aaf,a9e17a9b,5fa4fe87,d3b45633,b59779ba,57002679,63a3a5,7e7442c8,53deadec,73ed54d4,db98093f,9e269442,d9a4a955,f9b18878,8be2c410,84014a4) +,S(bd3e9c04,42a9b0db,b063aa20,b09e7e0b,4ea18ecc,55a5794e,14108aea,1ffdea66,b5e43b5,fd8cfa37,dfd49f34,1ef14b0b,c2cc571e,cf9f7511,f2f11e15,825a57dd) +,S(d95c6dde,f07abe75,215e14ba,e76a3be1,6dc514f1,7542a246,e48a2a35,108c0833,e49d6c1b,baaf6f7e,44fa7389,31767757,76d6756b,ce8353ab,ca6e648a,cd2e8fdd) +,S(86f7406,7a86227b,2f5414cd,12c9907a,b78464be,8a5c2284,7d8442ea,d585fe8a,53c73db9,3ebd3340,2856a7e3,d91d29e2,e9439a3d,c43120e2,1fb5bb04,384a8e68) +,S(bdd92d35,ba51344e,4deb6b77,126fde21,9e7030e6,5e1d96fd,4987f1ec,bc5ee6ca,a49915dc,b4f29eb5,af9d643a,6c6f581d,94a205de,3a8bf3f6,a26d294a,be11cebb) +,S(dd4b5fdd,3ca88300,74f19532,728a31e4,152be230,2e6ef55d,a6ef9209,fc70b65e,fed2978a,3cc4c8d8,2012cd5,7e06ea37,4ac5f802,a0032e8a,21d58239,860856bf) +,S(fab1a71f,f8a64cb5,14c94e0d,1c67fb23,70998570,ebbb0e25,9e09df03,e82aaeed,6208c3fe,3fd0d9c,640a1908,1a6a6db4,cdeaf7f2,ede4835d,46549734,c1c50035) +,S(4d6fcaff,167a869e,311e8dd3,f736230e,78634ebc,c4470b91,686018c,7b529509,e860a3b9,28927956,1cd132de,a1de3456,576c4cc6,138bb079,a166b9a6,79555751) +,S(502caf19,5004fb43,75b13ca5,16583e1b,3f60b32f,d9769832,b42423a,f7ec78c3,c0aadc3,36019a17,ebf7f2f0,5afc036e,e807df5a,c2869bcd,19c2aca0,1b5ccec8) +,S(35727dc6,ebe8f38b,1a84d201,2fb24a2e,9ddaedbc,63e8de82,e18de4a3,c4d021ac,8eaca26b,3b88adf2,d19d9d52,c84d83ff,89451750,6a77b4fa,fd717b07,4b414322) +,S(7ced897a,47b5b0d5,f4db6d9a,ecd9c5d,54b35789,91902324,6f270d7e,7ac4b377,1c6ce993,fb84c89,ef5dbdfe,68dad70d,ca39a4ce,29cbc658,d5332d1a,6f6cb157) +,S(60d1d74f,660a5f6d,bac1ee84,5aa43dd8,889c9e4c,6b0ce1ab,e9952ea2,7146972d,dc4291c7,db1dcde0,8e618261,b8d177aa,77b5b0f,2aa8f341,8afc9eeb,dbf068b) +,S(a8b28606,e7040dac,7941cca0,b9cec031,31db3f95,bee7d6a9,8d60c3a,1091f81c,3fbac401,61c81632,ac8655c6,d5c02744,7c836244,e228b9a5,bf5d799f,1fb810ea) +,S(6418a48d,2705a27d,5fe68188,58a61a21,4e4dd39e,4151aa89,9fc6d414,95f975c5,21abfd32,14d98ff7,5b154250,8480b32d,ea8c50c2,3400235b,be800520,1609c7a4) +,S(b46f6f80,c71cb354,3058372b,9ba5e6d5,2617728c,54c10cf6,6ead7ca1,de2700bc,2008111e,c4b86ec4,26bde7ab,f52bf201,10787bed,d7b2e922,e3a5a60f,e68a0f4e) +,S(a0ef81c3,c9f78950,41a8d90,69cc22e9,22bc0cac,4e61a030,495ddf48,eaa6dcfe,8617df0,b32975a1,6666f86c,136e8c99,c07ff948,ff8d8176,9d968544,aee5eaa8) +,S(c03cfcd4,21cc7095,5a3e10e4,a4ed12f0,d31abe86,506da6e9,c83cf6e1,df73d093,8d6f0b3,c0d6edf4,b5d2041a,94d13f89,91adbb03,22ba9f,a56b31cb,63d4400f) +,S(4085a2aa,95e4e8f,11b0e94e,2673c48d,d42506a1,81d93a19,b5f79d45,ab88b688,cc769f7d,f45cece,d3cddf9f,c75c4dc9,bb7018cb,f54986da,434128af,b26c0f28) +,S(a485186a,b21c4650,e9f7375b,2ba644db,f22e2db2,20933cce,2bf0ca7a,c404fcb,2d227efb,68649a60,bee9461e,9390ba02,eb133cb0,eb8388e3,f64d23a4,332ec903) +,S(9faa3103,b212c2ba,9a454898,fb451d17,c3632b7f,c9368452,3ddb88a,7599f14f,9dcb34ce,51f7c4db,7cebb0a2,1b50ff2a,d67c6bd9,7066e505,60132168,3be236e9) +,S(1bb9ddd4,804edffd,78d00b86,ccf6a07d,a798d91e,5d88f2a9,37575d96,81187564,6577e8f3,ac22184b,d46339b8,25a426cf,2dc8cc86,78767d87,999a8e63,5789dfe0) +,S(7b32d099,c78bb658,24868172,1b375689,b91f0650,45fe3d9c,8af4a331,2acfdf58,a4c92e67,f4bc53c5,aa84cef5,908a36ab,afcbaf66,a946d98d,4254271a,b4f088a5) +,S(daf23c72,c67145d5,e2a55109,f95742d9,28cc16da,e53d0453,c8dc22fe,a9eec7f4,205dac83,6614ebe2,a55c04a5,970d4ae5,a9ba4b1d,d8d51f52,50de622d,2a2a472a) +,S(6f156518,addc53c9,76a16944,a059a465,8c49f6c8,6ac4339e,82a2f69f,a3599279,50a277ea,6650fd6a,4a5e4c2e,fb09bfe2,78fe8fc2,c7a86089,b4bb0fa5,fa7262d8) +,S(17661b7b,5b5a8a4c,f700397a,1f819c7d,a6c44cf9,a7d28bcc,df6e7fdb,efe50580,dc1d7f84,841d8ee9,3a9f9fa4,6a03b2a8,365398c3,f94b57d6,77ad4238,264c7868) +,S(c3042389,1483fe1b,12f16146,f48ffe67,3a1ca3ea,ea330d54,db5f7c95,fbfce6b2,131d108c,14a4fda7,77d323f3,f717fdd0,a422acfd,20b9db1e,2b2c4039,a330ce3b) +,S(654da43f,70e4c85f,c9aa2d5a,12ce1a51,d4364a09,5c230ce4,f8ae61b3,cde7fa4c,f82cfe9d,bec57ffa,4109e9fc,c9d79135,49817f50,9fde8195,79190d38,f0afd2f2) +,S(c17be24f,d7d2535a,c4eb722b,bbc4444c,fa529cb1,283585c0,730813de,7219b481,2d35a0b2,27582d2c,b8155b92,680f6651,c0040508,ae3de034,cac87591,654c0c86) +,S(fcb1fa46,f8178153,fe5f10b8,a91a411b,cdc4cfc5,61b5eb2d,29446a79,8deb14fb,29c75252,4cb13054,2b9c1a26,b4606eae,6f40ba1a,f73d006f,5bac65e9,3821f0f0) +,S(7b86452,e43ae1f7,177c131d,999b5fa,a6e4a107,e0a06f6f,4305a8ff,d1ead9d8,3e7cd53b,b2f27d89,829e331b,8236f92e,fcf674c6,478846c2,c18307c6,e82691f5) +,S(8271b58b,67a27540,c1d8305a,840475f5,3faa0031,4e779e2b,9e578c07,366a342b,5cf145f8,6fdff832,6712be08,ca1f3a27,d3e58fc0,baee76f7,a052f7df,450dbed2) +,S(3f027c76,4ebf933b,50df3d37,77f60210,4b997d1d,4b9cee19,cb549c58,b5d0fa23,cb44dc89,c533abb3,e255fbd2,6dace4aa,836caf4b,2589113d,82ad1886,7eee5d80) +,S(fbeadb62,ffe218e5,d0245d5c,4bce7334,cbbfbe91,610e8bd9,f0b89953,bf472bf6,7e824c09,9727cd33,1aafba9c,6776815e,3f954fb,539efa5c,fc4ce034,db602c09) +,S(ee2807ab,44643652,12b021b0,dbe94618,5d22fae2,f500a740,127f4dfe,32ee4c60,d958ade6,cb9d3a,ae21602e,d25556b3,b3869202,beab0910,1a1d97e4,8e360e1) +,S(94ab159f,2448f865,f3d38d65,12273da4,ff476289,3dbf74d2,ef889807,81d6802,88739de5,da331b70,87c58bd0,d734bd75,5853753d,1d3b97fe,39c68555,8868576d) +,S(98d2e8e5,a41a0bf4,a880a510,b4b65321,7b9a62f0,c466c589,d0c1634f,557666cf,aa24bed8,a5cacda,bc3c950f,d56bbd1f,f156efb2,4632e073,ac822875,2617d1f6) +,S(64efcff2,76cda1b7,c8e5ab1b,12c73a48,5a25113,eb9a5be,496e52b,ec6ad16,ac29e2d7,18bbf63a,16003992,d85a9090,98ae89,834dcb24,293d6bf1,b8130e3a) +,S(6a8e3376,1636ef4d,b1116d54,34f3fa05,d8cde7e5,31b260ee,6aa9ee61,1c4cf5ed,5161b5ef,4bafa1af,f76a1e21,bdad444a,2526cf5c,c81636cc,36f18400,b8dc47af) +,S(4786ac32,6312dcbf,a1386ca8,c505715f,2bc7f85c,22b6049a,e4386bec,11648013,67c80d39,bfb6cc58,7fb312c3,8fea53cf,6937216e,8e7f3b3b,4a2290e,6d6df687) +,S(b87d2d08,ee206c18,646713e,8af6bfad,c77754c9,59158fac,c31928af,c66bf596,6110c98f,bafaffc1,7b40277c,17ad9650,15de7069,705019c6,b7a74cae,eec6e65b) +,S(ea9f310b,d088429e,236d565f,d1b3129c,7ca8573c,191d1893,c1c157d2,a0867d4e,61c95d39,c1893c68,fdc60ddb,27909f2d,98c9ddd6,efc67ccc,7482c0e4,3c05b144) +,S(abf862bb,9db85d51,5d6a37f5,5f3942b4,5404238e,d49d3124,59f9ab38,29b34ebb,30d13c26,2157c1f,1ffc8a46,a3679e65,35be1981,c202e7de,10de5386,db863739) +,S(80767b75,df3e69dd,757b4c4b,fd0b4be,f75fecc6,ae22b488,214b0035,a276e492,ceea1fbd,bcce30be,2d88b601,895a8fd2,92f61b61,cafa5589,f9eb9652,8a78fbce) +,S(8b7a47e7,dfc35093,77771622,482e45fc,84708ab2,c9c734d4,fdc9e8d2,499dd950,dbbd399a,d62e8309,14bd0ba6,19a9963b,8aacc765,cad19734,e2526af4,2b2013d4) +,S(13700ef1,f1e82cab,7e9a7d79,d76fcfb0,b6e8c18,ec1e6546,d27eb919,bd871f2c,97488000,f96aa2a1,5913502b,30ae5bd5,f9edc84a,f97dac7d,c79be68d,a0f7f4e0) +,S(51f9a79a,991fe61e,c5b7c93b,d0905bf1,2fea0e0c,bb9e9a7b,d5d99188,f42c8a16,a3ffae0e,92e3bde2,51c9a8c4,1a6d05ef,2fa2ed53,d7a21402,e759c102,65d96000) +,S(ec7c6892,644bcff,715b027b,be48936b,26dde18c,bb4a1a9c,fa1628ba,84d5b456,51bc2b69,b76646df,51644c28,8570bac5,d51a0e9d,6e9f0ce7,1abf6812,650b18bd) +,S(efb8249f,bed3299f,7715b3fa,b6a23bf2,86560ad3,72e31e6c,ec725522,227f5c2,f36f4624,59a7fced,3c621158,8eac73c5,54593c4e,b7c82fe7,b0951bfc,8987bba0) +,S(4efe94a4,c34083dd,49762ea,eaf58feb,72f6e283,9931b706,56427bc,e9913bd,5c8b9448,5c687c16,76605dc2,d414f37c,da98a562,c71e7e72,fb2b8d5e,6ae0d60d) +,S(ecc5864,fd6a1f7e,1e20a84c,d9dc7090,9775446e,2e0bf6cc,bf896bf7,97f9dd73,49eefb1,981d4b87,ff21ca80,5471770e,8e063541,58e9c1fd,9995718b,14d9d6f) +,S(133f3710,9bcf5655,48d03c90,b82d55de,cfae1cf8,a5f3e117,5eaee107,aa7eb121,1af96963,e9113d2c,588ab083,58df45cc,8b68312c,9aaed504,3f17fffa,b29bdd7f) +,S(a8b1b9f3,971667be,2a65072c,efe8b1e5,e64f652a,4758f51b,4888087d,4fb489b4,556d9a3e,c2861fdc,da258a1f,8c6e81d8,1df43669,e64e3daa,90dad4c7,c6c0b662) +,S(104889df,dd81534b,655921ae,5483db4b,b3227f2,fc3563fc,4af46e1e,2c4fa88c,a70984a0,ce97af36,b827aaa5,218a9743,73feb2e6,fd7e2a02,408590,47323ee1) +,S(4603c58f,4fbc4575,7e9e165f,8a4b41e6,b0d2bf09,b1124998,3881ecef,2a8852d7,37e5990d,7c50bed3,2b72a43a,2e6a0ac7,5676cc82,113e3196,d6569e21,3adcd0c) +,S(5d1ddb75,774d6419,9f07f578,21786ad5,9fd7119c,f895196f,deec090f,1240748e,519140b0,1b340a4,a7aa2864,fef5a066,feb59c6,3355c222,6805e45e,160bcd9d) +,S(c9f86104,62644b3a,ec4daa3e,bac656b9,de816cc3,a5aff1a3,633f90af,8401a97f,405087e8,80403629,516d485,f17590a,1277e058,840b3fac,4e02d3bd,7be92954) +,S(b774b1e9,9f42b296,dab0e371,6d4ee04f,8bd517e6,7846d0b3,3ef5e0f2,569e97ae,ec78bffc,d6cfa76e,513a2b4b,db638f73,519b570f,f423936,ec0a54f7,9ceb5f9) +,S(d7a1e238,ad3eddf5,29002e8e,87476ae3,6668d656,595b3d10,2486f1a5,c30e6a28,5c9fdd1b,e132b9eb,4d7b935c,2209e105,55cb28e6,c4616be5,7b248607,697ef6e2) +,S(832b146a,cd002cb8,199e800c,47b2a0cf,d96591e9,91f1b406,b2db981f,c0aff924,f64632de,b99254ce,9d60b026,76551e8c,e21b300c,86fa5bd,8bd7c32a,4a81a18c) +,S(635f97ae,1785487f,437fee89,9ec21d13,dd8228f2,e209637e,18c85ecd,6cf50202,b53fec65,1a1af1ab,2f51eaf8,8a3af104,e1a40e82,691da03d,9a179c6a,3b30e5f9) +,S(f882f983,99891dcb,d58b931d,c215ca05,a232aa9a,7cfe5acb,5226ebe4,f4a598de,3d0313cd,aa36668,5422a6e0,2dd7c560,11fef0ce,3c268a42,3509991a,97cb4562) +,S(5b16de8e,3f8b8670,a98099a5,250e3102,51107cd5,d04bb804,e2a7175f,48183594,33c3d3f9,e3099917,e707a429,3c83205,4a26cf2b,2a9e3118,fa64f441,e7561fcb) +,S(b47e085e,c7a7977c,be3e2329,ea417e98,e86eea9b,aa23fc93,67cc06db,cf06647,cf6f1cc3,f564879a,f9515604,4b7b856b,827335af,5cdcd55d,1f8bde5b,d3f539e5) +,S(afd1a856,e0624d6c,16a876c1,2f78ba44,303460f4,d3cc793b,5dd32a98,d8aca9b7,3b334e53,83301f24,df0e2df6,12cbd7fe,3e1b6650,d5355bb6,c9d3873d,f42d73b8) +,S(454316e,69f558ff,6e19057c,9c754b2b,83eab233,f696ccd1,b80bbb42,3c81ae57,ebbbce3d,4e1cf2a7,315a394d,d03bfb64,300ac0f5,11627d06,7a5341b,43a4ace9) +,S(a51f1d61,dc60b34c,65345205,b2a316ec,766560b9,c50d72a2,330f828a,ec978d05,d4e9b10a,58bfcc59,ef24379f,532784a7,ccc4c077,8aa11bd8,bf008846,44175faf) +,S(771329ba,3ae1f814,764fb9c9,ebe68f37,26b8260a,90d4e49a,7dfbfd30,80cc6128,128479e4,bbcd5b06,ddf46f49,614f6ae1,bb8914a0,7a0a5bc7,34b69b39,caf71b1d) +,S(aaa59016,d18bc9e6,2716bdb8,6d0c6bcc,e04f74f1,98f17675,c021d078,166c9fee,36cd35fd,53be5c17,84dec1ce,80ab3ff4,95abf363,17824a12,71cef620,2784f91) +,S(be187d0,b3afc0,bcbf98ec,bf31bfcb,f4121265,c4b815d6,9403d9ef,926cd254,a3aa0d55,8b5f6720,9d8a6514,fe22026e,66e8d972,912a6503,5faaecf0,ac2d9b25) +,S(228afb7,a9564fd3,641bd417,20a0e44c,d2ab5d99,844fa61e,264ca823,e197da88,24457982,391e3209,88cc44fe,e42cd242,80fe1f64,b87814b9,bb485d2,ed0d7757) +,S(dd55db40,e3333379,7b8ae013,297b477e,bca2f586,16f29300,6625aab4,6c367ee9,836a69d6,603fd34f,92d3f775,d25ce89d,b92d2803,48a21178,44f9273f,1a97a9e9) +,S(f82dfaf2,5113d8d5,728c53de,3b43f2b9,d2aac0f2,f90b762f,390f745d,7e10093a,1097ff80,ef2f5dc,88873c1,2b5acf0c,a8a803cb,ba3624d,4a036649,ffa07bcb) +,S(666f1006,57ebb1b,f05f50c1,2bfa7fe7,cdf11e0d,6cb37c99,4b39df89,acefc7e1,3e3ceb4b,eb292e5,3c00e4bf,ab6dd9d3,becfab1f,19880c3e,cbb93a4c,415f67a7) +,S(9769b542,3b098d8c,18871a53,8403ba2c,d32f556a,7ca7b089,ceb9134a,5d983e73,536e7c80,5c71c49,9d9acbed,c6fd94a8,3e64a2c,8afd8721,12f6848d,60851084) +,S(26081d34,3771ce6e,39ba59dd,2c2e15c2,4c6903eb,b6c157fd,b1c51dc4,e5343bf,82f6d675,39d04825,4cda5bea,e4879547,9570f86c,9ccbe1a2,ee0deb39,afcf5efb) +,S(feef7b4a,dbb0e287,a0762b14,445a8fae,b860e08b,19600b41,45d92447,be732bde,44e79fff,55aed478,f8d951e7,f4a327f6,c4a1e282,ce617a3b,5128f528,33851e5) +,S(ffb8488d,f26d306b,70b5b1be,4b6f2e4e,b6d6b2b,4cf05d3e,9502f3f9,81406cef,f2891496,f5affbf0,bc60c46e,b96baf7,2a4e6797,3297a28a,948adb92,1cfd5dcb) +,S(fd1ec3c1,736f2edc,5c080981,fdd99fca,9e301851,cbe8d840,38f03a6,59f21ea2,86755e0c,7b01dbff,ed701a7e,b5deb21,3566f331,d707888f,4f658879,cfbf3bf0) +,S(addbda08,d536486c,b9d0b4f1,5ffc9104,ff75be96,739d4641,a405e2c4,2775fa4d,4d70179e,1237e2d4,61a0a0b3,c3bf9df7,9483afcc,1b8fe02f,47d4b312,2f339089) +,S(fb5e9c09,8ff0520d,b162e57c,19b80ced,7c63ea68,1c7a2c56,2557a1ea,d2d7a46b,c4d9cfa0,d31cfac0,78c187dd,2ccea738,4667776f,b8eb0935,9330fab4,b9f67e2c) +,S(28c33364,1762626a,c9e4d2d0,53a1e5f0,771449e7,a0977f2c,63db4681,1c675b45,239e717,a76b80f6,2b11c6f2,c459d516,bf81dbb1,4dabba88,9f1e627b,5fcb525f) +,S(68e783ee,84fea44c,59c46bbb,170d7751,c47fb05b,602e9995,2469def7,cd061c9b,7054cae8,31dcb37f,ae8d8298,859b4e56,772f8a6c,d079918d,b49c7bbe,cde61f16) +,S(1526613f,fda17eea,1a7930da,c1be4a6a,4ddffaa5,1adf3c92,73f3a2da,44d69c46,c9c3d04c,996c4d40,b906bbcf,5b0ac89,f541ae4,81b7c5c1,8f9b5762,7b9796af) +,S(263e6099,2adc9f24,1cd1c16c,de291760,babe6e41,d4e3d064,f1a8768b,94bc5439,3ba3eade,1c5b8225,7559c0d7,97c47e5c,41f60195,463b2eac,74801439,b3a6663) +,S(ce58e7e0,73c871b2,673e18e3,c9ebbb8e,e6bbb2d6,226e3d0f,4bbe6bb6,73e72816,85ba41f4,13158058,fe8d068d,df70f97c,acd4f512,cdcded1d,ff9c3c39,eb1ce1f3) +,S(47c3eb29,1402d2d5,25a95ee6,fc54d1f9,721f29c1,e5b51cb9,d82d234b,94de6594,beb5da30,3383e0d1,4d13eca0,8eb8af0,14f8220a,81b1e8f6,47c1f95c,4503380e) +,S(8f5e8092,c71ce97e,af578fa,52f174d,ad0133f3,94bf2ca,ef5c7adb,bbb37ad,1ca41380,ac714a5d,3c6be070,117b10b2,dcff62d1,bef220e2,4063c971,89f6ffa5) +,S(edefd606,5883e90c,31215558,b05f297c,45c64fcd,34cb864e,3f0265e5,7e7d5a4,924502b3,1d0e8df2,2a54ae07,edf1b0bb,f2ad1df4,7de805a,43ae11ae,8cf3d628) +,S(31516a47,50773473,6e691ec4,e6891eef,601d6e42,d7f4ea4a,1e5008cb,b77e151e,7f243d73,6ec9d71c,d2047cd8,d97c159d,345003d8,72556e94,4f7aaa74,acb8562e) +,S(9049e0ee,149d379b,77963972,1027627f,5cf68f7a,9b1c81fd,189ae6dd,eea5c552,ecd60031,71dd9199,77ef92b4,262388a0,7aec9cbe,65d80882,1847a5b8,c758ad26) +,S(977ac11,98214ec6,eb92699c,aaa9c219,6246df82,85a6afd2,fbef31,a5a93b8c,27e01787,d6e29c74,f6308e21,24f9fa99,6a5b78b5,4f45fc95,b71430a,abfb964c) +,S(bd7ead55,e8ebc96e,5429f59,52427ca3,8dad3d9d,649676c5,52a01099,3c359a26,9e596b26,8c90186f,8cf38e1b,f47d6d6a,d7204c78,b557b3bd,25125bdd,c3ef7824) +,S(90c82d89,9178857e,e2563cdf,d822b872,2901b53d,3b93a6f9,2905a4a2,163be70d,3779d0d,c99fc814,8b2f58c9,fab70952,373365d6,1adb6e5d,9ac3f761,9f27e943) +,S(a312a0c,3111faf7,2cea8b7c,3e2786a1,65362caf,11919687,3368c77f,117ac42f,1b78c42e,af0e6219,ccbe3ed2,384f5529,dff57894,b9c82566,255fc4d0,fc798b6a) +,S(7cd723db,c046d3f4,5b0fa248,1197790f,688632b4,5f57569e,2f7754c0,9fc9bcca,eb5fb704,a5cc0b22,979bd64a,790f428,b57bcc79,3bde8fc4,4d6bc9b1,8c21e495) +,S(2b24dc16,59324483,3851815c,1675d051,60713a5,7dff00f8,9e72df7b,d1c7352a,ab05061c,224fb577,a72f5d2a,38a9e59d,18c52645,9564afca,a9539d0,c64c8fc6) +,S(955ffe05,c4653033,c2b4afa1,fcf8d3f1,3b55c9ba,80d67c37,598f6d87,97f11b1f,d3502a31,bb37b950,93b3e594,944d4bac,3314d490,d375e118,4e8c5a7f,2346e6a5) +,S(699392f3,c2baba31,1bfa8aea,180283c1,9036ea92,f287fc08,adb32fa,6785fefa,242acb3f,fcbce5f5,9dba097f,3d358862,11232403,2730700d,724488e,8bee3478) +,S(193d04f3,61eeec14,633c702a,f8e7eb22,2c3de17c,a0130e9b,cbfb3daa,94674d24,39b68a32,79e62533,8bfda780,9f0f8264,ed2ba2b5,ea9c0035,6459882a,a943e088) +,S(564387e1,ed778e70,baf9f876,2a0171a2,6a4e660a,bc6eaf1c,7ef9f00,69794817,7cf553f9,128d0716,e3c81039,3d1ca83f,1cf0fd82,7f7d4ff0,ff538637,34ef42cf) +,S(f0eba12f,b282171f,d20aef8e,192741e5,4469c5c7,bab13f51,7084d293,c3c294cf,bb0211fd,18229247,5238ba93,f6992d34,a41a7ae6,78750b04,fd34f3cf,af61f90e) +,S(a54b91bd,b09d29ab,f4cb354d,283c436f,a8e9cb20,d3a7fd35,e59f59c4,200bc13f,bae1af42,3459a852,bc16d45c,cd35fd94,c0033d89,5c86fdfc,f4fad5e6,3bec2cd2) +,S(a9294788,b2c9d997,18193553,403350af,78008113,ed58cbcf,a2816c80,46f75d47,dea8059,c24c1c84,44a0263b,2896725b,79c2c8a2,6d425479,f44bb7ad,225bed8f) +,S(b6967b59,ea3d2899,c14fd2,cdd4590e,68dce683,de275313,ec94d5d6,1bee65d1,67eb4a27,8813f69f,e5bbc586,15dcab17,11bca30,77327665,2fc333d0,52fd2a0c) +,S(ffc0f3fd,241ebede,ddb0c43a,a9b8fc2a,9e778963,1af8d54b,bf99c64,add0cd7f,203e3aec,321e40fd,414c002c,e5c6cf90,2f3e75d8,ae0e3604,61028ca1,e21da260) +,S(d8f86220,c390bcfc,f714ec3,8b6f6ee3,d37b41da,4026805d,6fbbc798,8a936ab2,7c0ad863,31ab776f,c22b2539,fd65086,2cfd2ba6,2f5d67a1,6eb957b1,8d812bf7) +,S(11295381,19a146b,442c3447,400b6e7e,9b2190ba,dd42a75e,24460ca6,45a3cb88,44950501,75662a98,793416c5,3c55febc,7babcd29,398d6099,23e1c3e1,92dac1ab) +,S(d7cf3779,236c4a8f,d592525,d30dc0a9,a3318c05,1823e0b0,43a6542d,f38d92d4,1f866df2,429a3dcf,1a285265,18308c25,262c1ea7,2aa2267c,39a315c6,dcd22ac) +,S(d2bb0f89,a0897404,25fc85ce,4d8fe24c,ca061808,e426b08f,ff49a525,137449b0,fc4c4bfa,2bf202e,4d10969a,2c4ca383,17a8c179,20dcb965,7de7aaa9,6b97ff33) +,S(832d95a0,cfb91494,5b43d9a0,4f037266,2ad4453d,353f6e78,47d4aefc,449dabc2,6ec0aabd,3c3981b,8ff55747,63bfb800,453f302a,8161de79,b6b623d9,253124f0) +,S(3a224983,f83c41d,33d3aa2a,c9d29ca9,55850388,a968407,664b2830,3967f25c,7cc31841,96c4fb8a,953602ec,3c79ac75,69e1fd1,7a263946,27826a88,7d651f79) +,S(81197d87,1452332c,2fb18793,c0ebeca,3d1b8a4c,f161b709,e3da21f,3917917b,56a0980d,1ed1f77,3c960de3,1ce4aad3,90a5ea76,fc410a2b,107ed82d,b8bdbef9) +,S(b8204012,c77ebdcf,790f48fc,4acb23f0,b03e5d40,6fdcf212,81545200,faa2b4b6,b8718e0,12ed5a02,16485561,8a5fb6c4,ee4db08e,dc9c1842,881287c7,dc7191b3) +,S(766d82f3,b602c418,d020596a,58e61400,20f58fd1,52448443,2f816dc4,8d437750,d17969a3,c71ea79a,3854b526,efd56f8,148b2d79,3ea3c76e,eb14ab7e,de5841d4) +,S(35fe7655,5d4c88c,dacad9ac,1bf125d9,924276c7,8c2ea9c6,a9c1ae87,52d1e323,9ce2d43,ef8fdb37,82a38d69,972229df,9b9c0c98,abad263,1df192f7,e0e75324) +,S(a29581d2,55efc206,4d1d1839,621daef2,ab049724,167ced73,7566f4cc,3a81f5ad,7eced1c0,575b6152,38db2928,964f7713,f65edd4d,c31a4b34,ae20b6a2,babaa8b1) +,S(d7787fd3,75473801,2370e71f,4d2575a5,b9f89e11,aee370ca,2660dff9,dc6a807e,2875ab09,bb1b2a7e,cc6cb39a,939e4a91,2ddb1dbd,5ca43ca7,93ac663,552ae91c) +,S(1fb6cf61,e8be4d39,b36578cd,8853da6a,1e62cc7f,29426838,a7ecf0a2,77395288,1c018114,2dfbefaa,6bfc2957,6b79c91b,16cf03d3,81285e2e,b74f71db,1986e43f) +,S(511e9c97,866e651b,c4e32e41,92f75019,42316ead,6a0cd78d,fa61e0f1,e76aab8a,2e8cd531,d55bb19e,886b86cf,f7105591,68a9507c,7d78d34b,9ec50f92,5485931f) +,S(74afe7a5,6387bd58,d5996a9a,9650730,44141ca3,1f5236e9,da977289,73c9d434,be7311c2,b4566819,12d13546,8ac1e26f,6113b960,3039c24c,5e77edcf,de452567) +,S(5b545191,25d5f8e,cfbae2ed,bb724782,d07ff380,10eca9a9,29ccc9c1,ecd0f04d,21126f87,a0cf1824,1040d707,4d37e8a3,f035471,63de669b,9f502fd8,92322dfb) +,S(5286fb50,1a525e82,a944d1ba,eab49572,52d86693,19af1367,eaa8d5c3,e73ee8d9,f2abec43,68f3800b,30da81de,5b81e564,f94942a4,9409bcb,a9faffd2,51daa0ec) +,S(7b01eb86,c102438,4be1f023,90a5ed7d,beea652d,cf3ef77f,92fd883c,f2993069,becae52a,915d1393,15435d9d,edb72e2f,fb9bda33,4b2e39ed,6e698344,9e1ef819) +,S(3955e911,874fd6d6,74e04ed1,ea3b43a4,486a0ac4,19735114,3b451c3b,3028a674,3552c619,a845adea,64951c82,75994959,8609a3d,2f691d0d,5947b474,4636e06c) +,S(b67801c6,d96aca89,22d8e7a9,96e95729,c4c29d63,180e4f73,dcf013f1,98eb0d29,876e3361,d82f58f3,f1292315,1509ed62,2e2a73af,d063466d,4af5cf1c,1ffbb150) +,S(1efe4004,1c7ddbba,1aade160,cec007e9,8abfcba4,7d292839,4598b5c0,1b763b10,d9f00f5e,d0868390,230168e7,c5839be7,cef8ebe0,b3b70d73,ebd92931,678dadac) +,S(2083d5be,389e4bd0,23f7685f,2ad00b23,e3687672,72183afb,d5d02384,36d122fb,11b6176c,c7554617,935304d0,4e12e8a7,4bacc20d,d438bf77,a1729a15,b424937e) +,S(8a9420d3,93ff0ba0,25bcbb4f,eaaf715e,4ab14281,85b2dd91,f8eede56,f3006e46,f48edd10,dff93031,2b5df63d,ec9c7a2f,ca373d77,65033de3,8a54d37b,2ab1f4c8) +,S(64a2e8bf,b42de0b4,b2dc8fd5,9e3b2c18,753b43dc,e914fbc1,478818f8,145891c5,82583660,40ebc62f,d5526ecb,9f952091,47f7048a,4004a0a4,7b08905,12ac098) +,S(eb97193,28c44e0a,3f2568bc,b99815a7,c5c2e7b7,90e7fcb5,a2e7f7d9,920404f,cfd26c16,e6709873,1219fdc4,aa8ed998,c6fef955,78d7908c,c72c04a4,4bcf305) +,S(cea3219c,e03a2433,f9ad8d93,73a6bef6,c1f30b3f,fa79d7cc,6ced36be,9abc9c03,13ea8ed6,a0dd8fa3,29bd7563,a34f3499,6442b03a,f2eb703b,d8d5228c,cc4c4e7f) +,S(2e1675b4,f00a0843,89b0587b,f0cb723e,1a833539,c024caed,36101cb2,bc4c4774,ec1d76d2,2752a662,5dafb3c9,6235eb94,f9af1286,2b3eff6d,2a0fb965,ad3173c7) +,S(b0eb3277,7c8d1b09,e22c9b9f,1c37e8ab,74be3c49,7ab6d73e,7fb6ec11,10602438,6d44054e,a4cb4a22,3811bbf6,6d2ab2dc,f7263d7d,6421a368,9a9ca4f,97fac66) +,S(48254bd4,8df24e2a,759c5ef9,cee30855,1c1f79da,b0a32695,2196ea1f,987b6d70,9c12a458,f39f4880,ff04b96c,72b8877f,b4ad0020,495626f4,1d9b32a8,84f7a36) +,S(e3c6dc6,cfd0b94a,57b3d34b,3a77f4f4,45328a12,764e4619,efef75f9,f49fe8e9,5c229420,500f2fa2,888d834f,a517188a,207d8f88,c98b7b7d,31484a49,c4d43a31) +,S(a8d9d9cd,def3362c,b260ad0f,3de51aa5,db066c74,4166d9ac,57db782f,656be9e4,bc696df,80eaccdd,bccc9ac8,960325bf,1a0e9aa6,100908b3,cd0c0ce3,43205db2) +,S(38281034,a34cd153,34b6fdc3,26fdc558,555147cb,534a1c31,89beec74,5a2eca97,f4371a13,a65de538,f31ecc5b,50ce4b92,d5dc5645,9e523851,f6fcdac6,5994b5e0) +,S(b745114b,449f0d7a,4521d7e6,728c89ff,54131e6d,8add9f3b,bf18edff,bebc6ca1,18678d66,781a9120,ba33e01c,ee3fb1ac,b7790f18,b30a651a,99b913c,e621eb67) +,S(5987629f,9c26a8cf,ff39955c,3144f4ab,c4d094c8,8270f3de,620fcdaf,93a7fa9,a554b7be,24e49819,f1256c9e,72b8d981,2aa5984a,c942bd81,5709ee03,67894a07) +,S(8fc9dd0,d84cf297,75ece75e,8cfd7c38,dc9f602a,b0152b01,982be4a1,f29b7290,ed128f96,2cf60503,7acdf6d5,9578ca8,9a232a0c,c432364f,2b661ac9,2a3176b5) +,S(c8b5b1af,90d64379,f2c02ac9,51ff715b,2978ef0,bc87f721,3edfd09,983ecc35,c295c0d4,964ef85a,59490ae,dbfd98bb,f6096217,d7633f0,44470b6c,a1816b55) +,S(b4eabf60,c44d78fc,298b2c90,6cdcf7da,a23d095d,867fd304,513f90c5,437775c5,82d906a1,2d10d6d8,e4c843b5,48ab645b,e6f32104,f07d8fd8,c128351b,e7b526bd) +,S(b19350e8,a5163076,bba0b2e7,2159865f,59a8ea83,b0154fb7,64308bc7,4d0bcfa5,29e4ca7a,554269c3,21a12b37,a4fd0fb2,d3e57ed5,4e79423d,f715bd2,ecda9907) +,S(fecf1ff7,663c7921,40f4deac,ced92484,8c66bec6,f4a5550d,c340896c,5543b886,b2621f65,d52538e2,92a50808,9008efa0,8f530fd9,a321bf30,6dd24f26,c9a1208d) +,S(ab70fe2,355d6d6b,5c5a3f5,a6bdb605,86372165,b8f07d2b,ccfd61f4,798dcb7,7adfb6d3,dd44adff,87ce3727,efef0bc,6fdf9f49,44fbd238,822974d6,dd57e8ea) +,S(5ae5d60a,efd1dae2,43df9d7e,ca025c3f,452b6c62,216c1c1e,8b315ceb,b94769b,d90d73b9,6e33cbe3,6d96c45,656f098b,e7e57d25,dd03be95,8b9cb2a1,d00bb434) +,S(fc51f965,bf8dbdde,b5fa4af8,7abee8a9,a380918d,4d8524e6,73f8501a,291eb96b,ceebbb7e,35eda612,47ad8c8a,5d54af8c,9dbc9bd1,194ba5a9,5844fae4,b658496f) +,S(368b51e3,778f8ddc,2d09e9b7,fc2808c8,ac793edd,244fe177,fe3229a,e5a6d919,5b3ff9e5,af4c6ae0,575b553c,c0ce17cf,fc4da66e,e19fc3f6,2d047007,e1716db) +,S(ac9c4efa,5f63ca07,35fafa0e,9612b459,1a764955,d435c14f,91717e42,26ec0186,5d4d3ebf,9a064670,e09f1d48,79bc9e3e,22198188,5610731,29aa403e,73d7777a) +,S(2b5f951f,360dbecb,9eb1d31d,b414aa13,9d9a7d7c,ed952a72,c0f93a61,d52fbc08,8d46f1b9,cb8883e4,cb504715,eae4326f,11187e46,de477dec,2108ccbc,2b3ddd35) +,S(25a3593f,9670924a,a35c2008,bd8278a9,a78d22d6,572841c,98c4399e,26f67cfa,3b07ab0b,8d400f1,af88561d,af8bb7c6,a6e4b7c6,a8bf5915,4cd85291,66ecd965) +,S(3f03be51,b35e265d,d9cb974c,4ac021d9,d22b2291,40016bb4,e9edf52,36193eca,a17df05d,e4b0e5bf,c7ecac3e,e3253017,cc1d47b2,9fd3d1d5,411f2660,c34932f9) +,S(edbe9bd6,f16782a5,a00d7003,488b9291,faa4f22c,9602c736,a3698587,995d25d,64569751,212d2f6e,c2e7a6a8,973be7fb,c49d7a0c,8857fe76,f9c48011,735179ed) +,S(1f477d33,1fb16ac7,45c29e48,77df8c17,83f69e85,5a111a30,e4717fc8,ebf85377,64c947cf,64a66ad,8a417bae,1bbc1cff,56826349,e024d3bc,bc4a9078,f4bda708) +,S(b8ef8b11,901602cc,9fd1559f,c4bd6bdb,22f9bb7d,8b289c6b,fdae85c3,e9aa3e9a,60b3594a,7349c920,33d816fb,295f41b2,7c4d1d86,b4c9d2e2,2cc3f4f,e603f582) +,S(eb6b31eb,198741f7,49e4b69f,85c23e4b,58e3223b,df8537cf,60a94411,f03e0071,576746c8,ba579896,969c228d,67a57cd8,8501e27c,773a3444,35b7e860,bec9f471) +,S(47193aec,aeae207,ad675228,f4506db8,40a316a2,6cdb328c,2af6c24b,bd5e9a8b,dc67bbbd,ca7cfeb5,981571f5,7022986a,4ec3e408,b641c34a,57b7cfd5,5139a1ad) +,S(ae3c9591,c2768a02,f99b0076,9c56fdf3,1a98fae,1eca3680,38698abb,1d44f961,ba9b0c42,90c2fb0a,ad84754b,e1c3fa0d,7e34f737,f3874af0,4ed2824a,46efdb24) +,S(178ef542,8c4cc38f,f088c383,71f0ead1,4e7b4423,6d90bc7e,9ffc3db2,fdbe9b9d,a5f01afd,74aa9324,b10f6041,27ccae19,24da7b23,72269ef,ab984fe6,ba1b347b) +,S(2df7e5c1,3d0fdda3,3ef8f69b,f0ebe1d0,8649b106,8c965d97,37a7e9b3,c13f4c92,eddbf5c6,324853c3,7d478864,a68d0b40,2c28ac46,295c00c2,2359e10d,d0693d94) +,S(671abd13,fe274da6,a5cb6119,f33fc88e,37ee1b75,59adf215,e08fcead,ee946b8,49d7cd3f,3b8162f4,a85787c6,91bc29fd,69eaccb7,1354bbc2,8ba17227,8a8689fc) +,S(b69fbdbe,e72b1418,6fab59f0,6b57d940,fb8cb5cd,92c53727,a0eed42e,532ed39e,71f488d2,e104d21f,c816631e,d774a714,94c0c609,c86ee052,210113d,672ea302) +,S(1d5b8e6a,25fcc50e,a4a5429b,6233e276,47d978d1,28a5f495,a66b1b12,d7cd8714,8428efab,d2bd23c3,2de8da3b,cb630ee7,ebe84541,ec3eff60,645ec4fa,3978a6) +,S(4844a10e,ffce265b,1a5338e6,a10c4f18,b95b0681,bd702e30,9a376e23,7fcefa22,9018e1d0,34bf225,b4826e42,565a76d9,43c868c3,168d74b9,33b34596,98b5192b) +,S(9567ea6e,231a9c9c,3ea5bd83,59b7340c,dff96e3f,d1fa7a5b,c56c88a1,a57d951c,507e21e0,cc59bab1,f2c38cb3,42b9f83b,f291992,a0c83edb,4cb62b49,6c54759b) +,S(60f2f714,71258f56,6de74774,eda196e,46a30d66,3dc0b308,1cbad662,72f07bcc,12588be3,f62dd2c8,1e485efc,76c754d2,de642f53,d3937c68,f058c61b,ed7b6c22) +,S(4276ad32,b33ba53,ef2ab0af,9fc42af6,6c7bb23d,c7b7a9df,9c00e1dd,f76b6283,9c477729,c61fccfc,a2dc0c3,c3a9ac89,b98f437f,bb221be1,268a6f17,5d0dcd9b) +,S(fa3ec157,f8186c36,3419d818,4473745b,fdd2d054,e0c16e1e,fccd514e,95c9336,a7864a68,91aec12c,fe8104a0,eb3cbec4,4a907380,11a3acbb,d5fb6680,289cfa2a) +,S(7d7d2728,b1db5fdc,38ad6a75,3f39df22,88d50838,b106475e,28ba6eb7,5248b600,25d9d454,8b505739,16ec7bcc,877f6aef,e2641eee,8f78f1b1,a7f74c11,40173e1c) +,S(8cb9cc7e,4ec87013,b6994670,aae06b1a,a4785c06,614ca24d,cb6534,6592ffb9,728c4a8b,36bf36b2,a0bedad9,144c3261,71df8448,e87d151b,d8bee067,769113c1) +,S(8a9aadfc,84aa81d4,46442635,d47a9a4e,988e64de,6fe8836,79b8de44,f57c0169,60f39bce,be18abd,10afefa0,2d076d49,73d9615,10017a1f,469eab8a,c15eab60) +,S(3ea01e46,3a9bfcfa,39125216,7b6ce771,5fb309e4,37d495b7,852be3c1,af2a0b5f,2b756a06,75da2633,b8d2650a,a2102738,d5918420,9c57dd64,7b4c6c2c,c5250252) +,S(a0683395,c5245bdc,24b2b275,e8c2a196,5068fda,253343f7,49ab56e8,93672c4c,7f25a7ca,92d25547,975ddfab,fe50c247,6b4855cb,8f9ec4b8,ecbe9271,779431ea) +,S(b8293e68,1e33b654,7d2902ce,3addaeed,2fcc021a,cf7ee396,9be12661,b2abfb5e,7943e6b6,fd0c90fa,824b1e8d,25d63a1b,c01f16fd,3c9e2254,e1dc35fe,416a5afb) +,S(412722e8,ba1809cf,2df25d5a,49c7648d,b19e42c7,3cc30b7e,1107ee4b,f0aabaa1,557a299c,38ef6a75,61d79a10,ea052a52,818ce67e,1b341c1a,d70b984e,8e41fa39) +,S(7a62c6fa,f4a1f6fe,4a45aa48,a854a16d,a2fb19a1,a5647e3e,28a35d0f,619b2844,dab31641,6241ad42,3e7ee774,acb52a96,26b4b6ca,a4ea0b4a,67a513fd,9637dfd4) +,S(c3915b0c,19df99,ac0ef05,3a07b36d,62643630,201073b2,8e3ec588,6714a695,8f21f136,3cb4ff42,a52f74b4,b10f1dc3,5bcd782d,b477ecf6,38866d79,541de3bf) +,S(2a373fd3,ddd12547,3e30efe2,5533316f,355dd52a,6854d7f4,8144d19b,648f4b59,2ba90aa0,b3de3887,c1ba231f,49b28294,677adcb3,2e81c2f0,3c563e0d,221260a3) +,S(d8729e12,46cc8a52,a5c9b7ee,dcdf4d3b,3d0ff8aa,6efafdc5,ddf37480,2dda4476,1966d7a8,7e527a7a,bc1e829f,90e4e3e8,f4a7df30,48f098c0,df8a5eb0,2a8bc40) +,S(ce45fb7d,2ccb83af,dd1662e0,3ffec83b,5173dd2e,448eaa87,edc980f9,10a20dfa,5973238,531c5a84,1388c656,3d4f3579,41283e31,44d84ea3,31374d8d,e2122244) +,S(230a69,f0fff585,a1163702,4b16481f,65bf27a5,3ad7992d,47ec8ff5,edfe073e,61ae3fbd,90f157ba,6332de25,a571777c,30d8144b,e12d9a25,42bc1877,1b6abedd) +,S(d7f91496,1bdd4fe4,7b538429,df2bee94,cc4d66d9,270da392,a85e8c62,1527700b,67ee9184,bb2cb2b,9671aaec,57634814,b6a1a9f5,dd0430e6,6c5e2774,5afa9f13) +,S(4f2e459b,3eac7349,41cb81d9,2d8b3942,ee7b0ded,b2d9d8c1,90ff390c,aff7e4c3,4188f6be,c3526afa,2b29f953,f5044bf3,8e583c27,395c9f8c,979ff539,b4198e17) +,S(8a4a7b6c,3b598e42,851b0913,209a95fd,edf0f8be,6f152b33,1dac61a2,6f9b6997,53c457a9,f8926415,63e85b0c,b39ac9ee,69b31c65,5e3bc200,d37d86ae,d4291997) +,S(a48f69c2,9dbbc922,78a5f8b4,4a2fa2be,f432a4d1,e6fcfda3,8ad60dbe,6d157990,f251873,152f4ec8,fe5fc88b,cdf28ae,acef895b,1d0f0ce4,44105e14,7ac0ff22) +,S(fc0ec54e,20f7e8b1,fed5cc89,d18a5004,b7aa55ba,7520dc18,c9cbd935,7c78eb4c,17374d8d,36116ef6,49b723af,62a48350,4bd47bd4,c17c7990,fb0e119b,47f21ba8) +,S(8203924d,9fc7e5d7,6e3c593,ad439d3f,8512c0fe,5c298163,c8caaa3d,f7b39755,a224b743,258a82ac,2dec871a,dca1dafc,2bfa8e33,b2217785,2b97e57,2e1344f7) +,S(c4f66a17,a595217d,58d5b5b5,da997a7c,79b870c0,f5fa9dde,e146fa5d,c21f9380,13bc8ef7,ce6f915e,fd7a3522,f5fb9c3b,ac603d0e,343d344c,74565eb9,e8e3c777) +,S(4341f0a1,efdd7d68,435f1998,559e43b7,7d1c6780,d3d3e7e6,212efd96,5b30cb47,1777a450,1a693970,c2bf759b,a253e716,b17cd5eb,9a247d47,cc382424,48ae90a1) +,S(865d8a50,ad3b8c21,f8ff0e92,8e853789,a607abe6,e155b04b,3b81d80,c97c29d4,2a506b83,c4166a1e,fdc32c2f,b2d027e4,837d9989,a82d08ee,a31a46c9,dc72b272) +,S(d8d95cfa,ac50b79f,3189093d,50b03b38,3b798532,3f01ba52,d76f033c,83c832e2,cddf6560,d9942228,5a3c0f18,58a7c27d,fd7b8bac,9b23477d,8677a1a3,c01a8454) +,S(d09fa59,8ae65883,60247b05,519aef86,2b1c5196,d38aed11,e8350fe0,5bfd6cd0,45f51a97,67445680,37b1bde9,86696834,6dfaca49,719c5174,a9f9eea2,92ed4ab8) +,S(e19796c9,c9b48a5e,59556b72,9d9b8073,71cd7267,812b044d,637aae50,d6d3d1d3,1b86acc0,d904a31a,b5637e18,872eb31d,32617930,2f3d6bb9,36016653,9f218d89) +,S(6a88899f,be0c3c82,96fd27f8,6f89283a,f83df13c,a273217c,fef69d8,b048afb8,68ba38cc,bee044a7,a026ada9,d51e8d49,97083dfd,f65bd483,a45eb58d,5cc774b0) +,S(e5082ab6,a112848f,9f5f3362,8be3e267,87e24cbc,6d5563c0,7addeed7,ee44662,c3c1727c,d0c09130,8323326d,210a68d3,68bcbf81,bb3814f,dcfe6631,d42968da) +,S(795f456f,5d0cc15c,72ea286c,c881d8a0,21294e05,cf80ef7f,4497caea,92235487,bea99154,424f54d1,e91322cc,c52d3a51,4627fb1b,2fe9062d,91d90177,20530ccd) +,S(6e9e5f96,8c233f4d,8d2bcb8f,25d9232b,f2230e9e,fbafc89c,dca17498,8d7909ba,3f8b0b0f,e60aaf3a,89f5de79,35f9979a,ac3f3fc6,fb161d3f,29ab2ad5,d50411e2) +,S(72ef1e88,89cb7f22,19b4a7ac,92d5678e,a04c898c,5b83128a,1f7fa8a1,63772f28,dffb88e5,3f348c29,411e4d47,3ccd7d41,8a0617a2,6a640a9c,4b03aa08,15ab10d3) +,S(4a91fcd4,32f6d2e7,ad20787d,749524b2,e3e1c348,31b41041,c311421c,1aff04f1,bcd9108e,6e8c6da6,a15156c5,5c9d60be,e4aecad3,b0756cd5,81b1eaf0,ad300b9f) +,S(5f5255d9,8c7465d6,63fb4507,ac985629,8a434d5d,429d5a9,7b645256,e2cebab2,7c38536c,31e7331a,362fc944,38510aed,bad4cf29,bf0e7cab,c995ac6c,1fec04ec) +,S(866b5f8d,a735ab93,e84f7811,a33f1604,40a51373,7b52e675,7f212c8d,65c9eb05,af2cfb6f,9e32f412,5f1c66ac,61393756,b8c6016f,9d45a58b,43e16c6,d3549be5) +,S(636aca,387e767f,4702fb3a,d7b50b4c,4b40fb78,2c8c44b3,a298051d,bb3a71f1,70e580b,6993c9ac,5a48c2f7,558773c1,f5c4ff3f,aa929635,a2a44e97,c0eacae9) +,S(31a28d8c,2205f5c5,75ddd861,df94bfa,5b6b6e38,83797d1c,7d4a487,5fcf7f7,a790eae6,788407dc,89df860a,9ac25011,8b8c65f5,f47e0bae,6aae95ee,2d733698) +,S(c7f36e08,bcea178f,7acb0b92,fdb32411,a028ce88,be5e3480,a47c2c88,891827c8,5c285010,4742764e,7df86e80,e6e2d975,472abeb1,bd5664d3,a994289c,112a9e9d) +,S(85a82c69,2a5e248f,42a3f0d3,e092840c,de52e31f,19a2a161,85b2ad10,6afd92d3,eeec281e,55c79f17,332c4ce0,7ac4edc4,a3d75e67,558b4b3e,4dc86532,6132155c) +,S(e67482d2,4c2e3a75,3c1fa968,bf120a4b,7883d00,950bb0bd,ef5472e0,dfb09287,f9801b51,e0450fcb,9e405ebf,cb535355,24db5e9,91bf1572,6f446aad,34ae4194) +,S(c6ba17e7,81fad656,c9c93e54,36409414,c58e2761,b0297b8e,1811dd68,62779f1a,92583a9c,515a096e,8691b384,4104419d,c4e86966,4da70b3,afcfceb4,b9d74c92) +,S(67cf02c5,a616b59a,ddd421dd,15812e95,f36e6d16,af501663,9e60dd4,a8706b24,7856ad72,8a5f0d18,bf4bc3d3,75468f85,7bbdb1c1,206fcbc4,7ae66b5,6ac91b29) +,S(72bb64a0,aa8c690e,7bb6ed99,847488b9,f37490cb,a7fa120e,a7b5df10,8fce4b61,6057c37e,198f6428,3b9481f0,53441e97,dc827cde,edc55410,5108fdba,a14d81bb) +,S(1b132067,209e179a,5b77977b,eb81aea1,c480b32d,81729c5,32d100df,310575cb,67482a94,b5ddae4f,cfd613eb,68680dd6,c8172553,18478bf,79b5c07a,b0cd817b) +,S(96f5f126,4b68fd7e,f633330e,f32951c0,3716b62,7d1f3368,703447,f9dbb5a0,941fa02f,c6262bcf,dccb1cdd,1637c9cf,719077c8,1b26e7e7,2bb8fe4a,4d530e19) +,S(95335907,9c15cfa4,a674ce65,113127f7,a1ce740a,ecceef55,da5ceed8,e4e56a51,57ee067a,5f506b14,5c1c20ad,6e5d6b11,9bca103a,60c2e6e3,b5049b4d,db15baa) +,S(72ca7d41,76c687b2,1125c290,e737075a,3281ce7d,76b72725,c7680956,e0463f23,1e6a85aa,246b0f1b,324365fd,19809840,242fef0e,6d658cae,cc84bbc3,ad56af44) +,S(d5376a10,2cf819b3,a439feec,b04d9fa3,c90d76c3,b9bb749f,bcd6aa26,39ed5ea,3659d2df,266a0ff9,c2854f6e,f5a5ab04,1c0d8547,77fd4f75,320e064c,c4d0a4da) +,S(664a26cf,a965b59d,10c05dd6,e0aa4e6b,c66f356f,bb61b699,113a83d9,e0a2b4ff,fd191a92,c88d577e,47e725eb,a3c38b3b,9074bc42,16c5d6b,4edb3af7,2c4e20f9) +,S(7729abf,ecf9ca40,e8867936,7fef2d84,29bd877a,56f36780,1e677273,8e8cba7e,d5cb7517,42c9de11,84dcbfb7,5c9e139b,a59b6255,b59c7ef8,539de55e,7a709d36) +,S(c6d5f50f,e8e784db,630bc589,b4df5810,a2001482,9ca1608a,cd3e3634,7bd8141,eedd06e7,95d063ef,3d1627f0,bc7ef37d,a4846580,61e472b8,89679d3c,d88ab294) +,S(baa60dda,3cf83a11,82dc2ef4,f79d362e,6b32304f,896d30a5,b363c639,56ec70d9,cc9e6274,75feba44,b93451d2,753e94a2,85315277,7674b3fb,c67490e5,3627043b) +,S(370243c0,92b957c4,74df755f,e0951321,49dd3669,1a89fa84,e43a0668,8ca235ff,bbe8ff04,6600f245,349fbf3b,1c8ff04d,8d51185,3e35d13b,30deba91,84383ba2) +,S(1182291,92b1e768,2abe56b1,9f90e41a,c882edb2,27b25559,ce4448cb,dd19ff06,24271274,e6156ea9,e3f82ba2,8a72d476,8509dfad,b985c200,244687d5,8a11c1be) +,S(dd134e0,e4fe672,38716aa4,edba1ad7,6879be6,8b5bb029,b32704b7,9edfb2b6,7aed5398,40cd7dd4,7e94c224,151627a5,62f6a519,2f0d0b5c,416e6f1e,5e8a337f) +,S(ab7e722f,458d3acb,ad28a29,2f90cd8f,c2e09b2a,2beff3f8,f08517dc,e673e3a3,522a2227,c724f9bf,1ae08d93,c4c6ffc2,f5434173,7fbfa502,d6e49b1c,2ec4c792) +,S(2fa16842,ebebd6fa,e6c67327,bd5fdcdc,7e985b1c,22dfe307,23a9e2dc,ec43df8d,f027937c,9624aaf1,ccbf7c58,66bdd9d4,5bbb279,c2a37813,9166b720,32030773) +,S(adf5e014,e1f18c38,fd1863cf,76a6dcfe,65827107,fbe0eb99,117a859b,c5268bc5,c9cb3584,728b1771,16985b28,f5259aa5,279e15a8,1c1cc6b9,2b9e5f8a,6206961d) +,S(d939322b,a9b2cff2,6a2b1c4b,5ffcd96d,822dde66,ad0aca31,c24a8260,c9fc6d26,162fb654,6118a68d,7fb88bdb,3e3ab784,9278a5eb,13a940e3,3228580a,2258c8f5) +,S(18fb2621,71f79e5f,46c0087c,ac8e55d9,66f29a49,e2c91363,58900787,3d7e3a6d,cac82dd2,4a0f75ee,adfe906e,ccafd36c,5b0c97d9,cb150fcf,d08b28cb,83787a05) +,S(b8c0ac07,5d009e4b,5ee44298,89864cf6,fd54092,df835ec2,6658c902,57b670d3,2dbc6d4b,6ff28cc1,14e1f34d,2b6cbe52,7ca7dead,24f84681,4407c4e,a0df0bdb) +,S(6477536e,43a3ba01,8988c8ba,753d732f,9ec061a3,49f7826e,2c426ae5,3f2232bc,ede465d7,6b7798de,832e5f68,512cf3c4,d17282a5,ef88725b,36d8af1,5c5d2679) +,S(55b052a6,52008a83,41135e55,ef7de2b1,33eca8b9,ea0c4800,ce4f8019,5f7067db,a823cc05,63efbc19,d47c2c92,5771497a,ef6377a3,8be0d23c,81a56f06,25c43e56) +,S(c86a02fd,becc3647,16c58f5d,f3f150da,6ba86499,2df09dd5,82b9653f,10cc9289,263d1b5e,eff52a27,1a9c46ee,8adf1194,1da9d3bf,e69f62b7,262099af,43d6fe3a) +,S(23c659e0,3a59381b,3d47beea,60f0244f,66af0596,5f903297,c53aeeaa,d143e90a,1c14650e,3aa16bd5,b67e6077,be307cac,2bd2cd39,b246d6f7,216d73dd,dacbaf64) +,S(2f6d8482,734aff4e,21094c39,2c5fe833,1c8f9756,4de252c2,f6f690ad,8b2fa9d,8b143db3,7e14b40,3fa98a74,a81adc79,c34f17ce,5c9e6f21,68770957,1eb639ae) +,S(6d58e265,d6b08c0b,b050ee18,5175a9ed,51b5c64f,d523ab35,ed1457d2,f9caf153,d0675517,eb71ed0c,4fbb86c6,a2b4a7df,259a7795,3293777f,3a87f620,2265edee) +,S(4af09f2f,69d7b9,6676f472,d7f2009b,f0bb6f0,986f502f,322afacb,7e9d570f,1f93342b,ddfe5896,52e8b64f,a348f333,5396012d,3e870885,5b31024,f14f8e7f) +,S(813e446f,87d923ab,ad8b8649,71b1ca39,d00217f8,232a71cc,d6346798,3a9a0e9b,8ce9f4b3,541a8029,f1476728,2bedf1f4,367ff257,60f2ccce,7b273b2c,dccff418) +,S(53c4fd57,ca0b1eb8,7f5ca0f2,3ecae8eb,c44e9c19,aee3477a,3ca8524e,dcdefaf7,b3db3613,aa916430,a3227d73,35bd0532,74c122b8,18e4ac52,858e513f,c3ab95a4) +,S(e0f8afc2,ec89411,d926355,2c33af71,328331dc,9c9452fe,b0665c39,ae90121f,13523c16,1a00784b,f15d2867,15cc05ec,227248ff,80082e73,ecb139e8,f229eb4e) +,S(fe3efcee,6b82a5b5,a8c9a51d,ccc11f01,ef8f1a7e,588ec4b,17ba1369,cc6bb80b,be17246a,4d8660ca,98d57f07,ddbabc29,650f9a89,9da60a53,d21c6c96,dfdee15e) +,S(8a5182ea,591089a5,11ba9f19,ce4fe062,31b7e2ce,ec4cf75e,5c11094b,9ddc8de5,73688cc,f13d97eb,19a86c2d,8b010406,1c69ca94,fc9ec90d,8ada10ae,37503600) +,S(2d95aecf,72501ef8,e20bc117,22dbcc09,38c552f8,f4e0596c,9974d62b,a99fc884,7d9c418e,e1745ac9,e8f5e4c3,9ada4400,e65acb22,d336bcc9,fa2cdbe9,97f7de88) +,S(7908e4f6,ede4d311,3dfaf114,9bf6e40f,e1f8e33d,72094448,5105a113,21d18b80,11d92d74,9b011e83,5e06d7e6,1103cbe,bf958d8d,bd47d0b0,1ac2ad22,2f7d275) +,S(2c6dc24a,687d8437,44baf725,c75e7524,c0e6571,f32817f4,40183b6e,cbaa9f95,9692bdaa,775b832b,48584ccf,713421e7,5074f1b7,ed5477f1,4335db2,7abf03bc) +,S(a019d9a0,4a9780c9,43dd65fb,b87534cb,ab7c0831,f845e724,d663578,ec7bc090,38de35e6,faa2a1ae,e0649333,898a6ca9,264dcdd5,ad9f289d,ef750110,9bc99d4d) +,S(ced934dd,5c15335d,d050af1d,a8295d2e,bd9b8272,58d689ac,f4a48d85,5ef8a0d9,bc0c9237,1ee7fe7b,69c7c100,e5258c9f,1d68b6dc,309736e4,e05718dc,3a49cb6b) +,S(65e5ffe6,502ea7a1,47fe9c98,9cc745a3,b5262bd3,888069c3,92d1d1f0,a08dbb83,c80ee080,84dc5e65,de8df271,c1132cab,b8be293b,69a390a6,fb3932e8,51ffaf38) +,S(f4466d47,2365b665,6d1947b0,6e67e393,4c0e4f3b,91d52ea6,1f4588f2,4d217655,17afe3f7,2d384ccd,9beb59c3,d64353ba,57713f03,b8644e3c,eef45db,c74ae84e) +,S(66a80bd8,ec0d08ef,3d9aca5b,4329198c,b949ce84,7933ef2a,10baac28,dc98cea,7457685c,600a707d,5fd5d527,9f309b9d,5b14e668,1656869d,b041ba77,97029537) +,S(240e3632,7c3f4c63,afdb84d0,8586bf90,9b359c8d,7012f9ff,aec81986,4c44d597,a701b76c,d369e013,7b627216,f75d0ec9,fa208b66,2d7075bb,a6b6d39c,6a1cbb30) +,S(137f0df8,cafdb26d,36e1b57,c427ce08,444516da,ad1ca806,9dd60e2f,2ee23f92,c2922219,9e4e7bf2,f9159138,13e68273,6bb6a998,6c015caa,43cd30a5,aec74a49) +,S(965fef87,a63bedda,fd4b2e35,e1d0baf9,17d5850b,1f6beca4,64d4fae1,997d3a41,5f19603,369108a5,c599ce56,22bbf02b,cf541867,a57cff2d,8b527148,30124ed3) +,S(1e2ca98e,519c60e6,cf7ff3c9,51cde109,209188e0,6c68f4dc,c22eacf1,34a4125e,edaf4c8d,8bb97032,89f9fb0d,d0023783,fd35e779,41773a00,fb4289cd,ef8411bb) +,S(e8e0e2f0,378595db,68f96e6a,882752bf,df039778,e261375a,47fd4394,2b68006d,75b42822,1e2fbf9c,42772d35,e4bf1e0e,8d3b1ad7,92ff25ca,a488b51d,4ef7186f) +,S(a405f5b0,28e89d81,79e7fa9c,2ebac86c,ffd20ade,60dc5226,cfe6c91e,5c2f6634,c27ea4e3,b0da9e58,665f507,84225107,7893d6cf,5225d5d8,a06f68d1,1d863550) +,S(bcbc3c77,7367168e,169f3fcf,dd2340cf,9e6af955,d6038a0c,b763f036,6f4564cd,c7c120cf,99138201,40ec5339,ec23f5c,1ac0dd73,c9f947dc,e19c034f,7e7a502d) +,S(fd569bd5,14843a2d,e86ab2c0,475e0c67,4959c04f,bc230255,db3e82d1,15cb0758,aea9c73b,bc083366,fc5e31fc,90a1da72,66a9c43a,9d16f6ee,67bd56b7,9c354cc9) +,S(c2fdf561,eca2e3b8,f1107475,9cc43b9a,789ef592,e8afe885,d88b9dba,469c616b,678f57fa,fb2e42fb,bd1482d1,e22c866e,683e4fa7,6c1d2714,6540610d,9cbd1360) +,S(50f20965,510b3317,2836e1e2,d6e00ea6,160a9c71,2aa30bbf,ac527c62,9d8f4088,fd9852c6,974c603,7e88bf45,a279b565,d1246924,e3c4a0f4,8877b716,69b68141) +,S(3f293417,1e371e20,cbe0a858,e5984175,ba465906,fd64a7e6,161c8a7e,5847764c,763e8dbe,571ac3dc,1e803f32,7e2f4585,7268774f,1a45c50,9390dfd4,96bd374b) +,S(8276d399,fe32e931,65f2ef6a,2f4198e7,944bb9a3,226b1a55,fff52dce,d2b92b3d,e955a591,5c496a1,623466be,88c45a3,f545527b,4edd4283,582c03f7,2a2d897b) +,S(e77e7701,f4b405c3,5c8b7a6e,ee7d0637,fa1f566f,d2a2cb64,531dbcc6,19a9e474,23fae4c0,7661e588,365ddde2,63b97f2,cca2023b,c70633a1,41a2eb,1d3799cb) +,S(7ae8112a,732d6428,25aa2eef,10298300,42939628,69e7eea9,3fbc7b3d,2c5210a2,3590e349,f878af6,7f7754f9,abf4ffdc,4d4f4442,48c1e039,6071271f,be5971ce) +,S(f9fe96f6,8e20a422,5b563483,c1d2389a,ebd8a97,b1b9accb,ed7bc51,8077771e,cf3802de,20b5ae42,b1d1db65,b033f2e3,602ca08d,972eed63,9234e1c1,48542478) +,S(b9c5eb6d,ab28292e,49a76b34,49cf903c,dfe79b85,f7797623,924a4295,bf0cd171,adc0a5d8,18926d8d,7bdc83fc,72b2ed11,19b87592,900ae961,ffbb165c,4d5bced1) +,S(b7e25a76,3f3b8bd6,1c57da51,bd90ab57,1df3fcab,28003104,30c44fa5,4a6a5765,c471aa74,babc3fb7,dc80138c,83940e42,961f80a3,23e9741c,c44607a8,258141d) +,S(5808e4f3,e01937f0,e9c887ff,8ea3a34f,8fca4d8d,7868a9d5,7de6d854,a0582d71,fee8cfef,2d78896,55dc9560,68e1a23a,4308a8f7,7962c2e4,f90b2ddc,87f011bd) +,S(92ac7dd9,8da0a4e6,60964943,3887974c,5ec4b32f,875c02ba,1163d06c,b424793b,857b2046,8104a986,a0030596,62039e60,71c8f950,b7f7f746,16fcacbf,b8eee5fa) +,S(5c38092f,fba5798d,48d0068d,d1037563,1f40a693,194584fb,7199c409,b85d52b2,32b1d628,15ee2555,f582f16d,d59c4658,67691e1b,389d1fe3,222b5444,294ab391) +,S(ad7beb62,cec8aa9a,b619693,eb40c477,53e22897,a0007693,f10ce664,21d5c15e,49f98176,a360297,42402a93,26e34a38,cc837278,3873b076,f887c811,e2bd98db) +,S(aa335f87,c61f2e9,7d87355e,2a1c2e51,f2a0ac92,1cfd3cb7,5189f256,386ef185,b39741b2,fc158d6a,435bfa8e,1a68eedf,13deab27,388032fa,fa22d649,c9c9a8a0) +,S(854ef509,24fa2fb4,9b7b7b49,44ad8c9d,87627883,60ce8bd9,36e64f12,a550356d,c5af2246,96c7e32c,a385f7e,3eb8326b,7d9e3537,43a95c8f,3010a160,1d6f534b) +,S(71b6366e,42a8e2c5,31ad6770,ff01481f,5a39c54a,d38e0ac6,f068117d,8d5c9d5c,d6684df5,92f085cd,aee8313,59bbceb0,1a357edf,b36f8e14,706245ef,f01db334) +,S(3a4d1869,55b698d0,5e760d75,8842bd1f,cd869e84,c2c29e44,4ca83bd0,3408d6b4,5ddd1b14,15ff793a,80fc196a,83ff2736,e9791418,fba7eb98,71b51269,170d9904) +,S(f596d242,7e51e5ce,403d673,cbdd71b,75550271,dd2d7d93,79883258,9d3c5739,cb9ef0ea,f6326a5f,83e40428,79675f81,188763b1,ec06fa26,3d7793cb,82b4ceb0) +,S(4bb25028,b5598090,15286b2a,a8858e52,227f3b11,9075077b,3083fe16,77efd4ef,cb63c7c6,9de6503a,d33ee35f,95d4533e,1e978f30,2762b478,e88d18aa,5c4ff098) +,S(77c7c018,4c89f974,df648e0d,ea57ee40,73acd63f,c6e22a55,6269ca4e,a5dc1c99,978faba,232a2b0a,9cf3de55,976ca950,ce3f197e,e774b2e0,d4bd1e5f,e65a1b41) +,S(834d038,926b1ff6,13dc9001,7d021bf4,5bae5,d3741460,db681332,61975c30,f5624b83,614f5e82,10190b34,9f966fde,cd4eeefb,e3e6b046,b3028d6c,3807b475) +,S(370045a0,a7f8a64c,a2b9c64e,85a07fe8,9a7f725b,2cdec8db,258b3d3a,d9cf379e,cbec192c,cfc58b62,6b89d6d3,9b4bf622,81e308b2,2aa3ddf,51d45561,37b1811c) +,S(61302164,6103ee82,1c3103d5,f4d2aba4,645816cf,a67d94d8,ca53dcc2,92ca36d2,935e3db4,5ee1789d,ed8f0ded,ac0430e2,7317f38a,87682850,9568feb8,15e20a1d) +,S(4d6868cd,4df5b1eb,8d27e045,ef04209b,c1dd0bd7,aa712937,8f7bc025,e569d90f,dc0079be,850ab0ab,ef9881ac,740140c6,958e12ad,edfcbd79,2f446d78,7157780a) +,S(43413ee9,a35c7c44,bc95369d,38d9e7ed,53175f17,6f9eb54,6df98540,93105549,9eaef64f,45b421d1,ee80731f,ed61f658,861feb4c,72b5b2b0,ec659825,63172f7b) +,S(1e728340,95183b28,a443e00d,6ae01921,75844d9b,ffb1c77f,c00d388a,80a6b76,d1931ac7,fccf26d3,a2ef72ec,e8c7ecef,c51ad264,ecca5748,7e9cfe5e,d798428c) +,S(7b5995f0,fb0b8246,c588e393,4499404,415f0d03,c9174317,6cb2f4ae,b06960c0,716c7849,b6963a9,f1a7998f,49cfac4c,42a329f8,77d7c8fe,5b35f958,ceb9c0eb) +,S(9c5efff9,2be6057,f5223d41,87fbafd1,a59c364b,239120a2,fa1c4596,4fdad960,4f4aa66e,e42548c9,4d6cafa0,81e59ce7,ab65cbd,78027de6,b1edaa,25e6d7dd) +,S(46970472,192c3690,3c7bd061,dee19fee,5f3a973b,a70430f3,581abae1,3a61e55d,4d232a77,62e04a36,c62894d3,41665ff9,ad8ba55d,353d52cf,44f392cf,7787922b) +,S(add62a3e,583dce2c,55e97257,b64c26bf,5e86b0db,92962b3f,a54e7c52,ac00b32e,3c700f82,c5365611,f3cb1ca9,cb6b0c2a,dda80e04,617142ef,eccfabee,178d3dae) +,S(526115b5,34b212fd,9836a98f,853ab3c1,24bb68bf,afc1d641,b47d08d7,39566c4f,29c983e6,2a4de19,4efa5b2a,9cd4971d,6a86c8e9,f535d599,ee04db95,120fdf4b) +,S(87908ac3,ee8f4e5f,31aa08c0,ac97e93b,81ac75fe,33bfbff0,7d4f0934,7c911f45,b756def7,52c71c51,3f69235e,8d515d6b,f3289a5,a579b999,a695a2f6,49586ba8) +,S(2d6e6ed5,d2ea8912,6797b396,8ac1b0e,f876904b,acbace80,a2613b35,d9bbdd11,b1b66613,50ee7a2b,d149ec9b,25a502a1,6ba6143d,32da00f3,13cc389a,7c0e480b) +,S(f076c9e9,8590180d,dfd36cd6,160c21fb,7dc60263,77435e74,30f74cc3,c46533f9,2c9decd8,6da7b49b,1b4d0a8f,47aaaf9d,19d9e8bb,365c383b,63726f64,ae56fb98) +,S(fb52489b,6d101de1,2f51720a,60a78207,84ab4dd8,39d05c9d,a3b9c349,a74452d6,f1a967ae,deb5329e,faac7381,f3f0bc76,9eb8cc89,78d5d56e,f382a17d,4c3baf4b) +,S(dc1e911,53b3435a,8f23cb08,a7b52f64,a5e2870c,9345896d,ab4ab880,9710241c,3468d632,eb3a51fe,133381ce,2b5dc9a1,64f8eb68,9c019b0b,7e48d504,50e85630) +,S(2d8c6759,6c7856d,b7062c63,2aaffbee,46779bdc,777f0be2,a64093d,41d4000,c7006eca,b64904f2,9cd7baaa,14a5226a,e5c4b3fa,68c62cf,65789066,2eb8e8ca) +,S(31e9d361,fa0041fd,bb73665f,2e1541f6,c41764e7,78023272,478cd7f8,e9552f06,62fdf441,4effb45c,5408a0dc,c0a78041,cbe39cac,562659c,ab8c2b89,1a940c11) +,S(792f50cf,66aa0f00,68bd7fb,ee12bf44,e1fa6662,41c43d2f,275a248c,29459830,633cf86a,a3f10f31,40aaffe1,d04ee094,aad1cc56,129149c3,2702c33e,40d91e3f) +,S(be4f52ab,8f6ad1f0,664e4d28,b67be76b,c3d318f3,9f455708,94060e03,2f8547b3,22ffbfca,44482e40,19ef36d9,209b4262,48d62591,7d81b6a1,57ad945a,1878b4c1) +,S(bb693c4f,7110d2d3,8bdcd6af,d8b29b43,80d003a7,d0f6420b,e8d02cec,3e7cf385,3bdfb9c3,948034e9,31904f13,e3dcfa78,13d3413f,5c2daebc,744bac87,9e4314b2) +,S(56e8a65d,2eb188d4,64dd4280,b987b5f9,8b92b8e4,34b6bb1d,1800fc4a,f8f2deb5,11cd5d14,63777189,f8c7d19a,c692461b,d21fa20f,f12d1976,3b915fa4,33006cbc) +,S(f09d5cee,514e56e5,9566953d,f8600a94,cbad003e,9c898261,5bb998f6,a5b8cbb4,d07ee0a9,a0e88f5d,6da3d918,d5f309ca,7234373b,d528cd8c,21ee9ca5,3d1bafd0) +,S(58671c9f,687ab0a6,f6b7c687,ef546765,7f29ecd9,d6250088,d588742,7b96fa6c,70355403,abefa39a,72d89348,9a8251c2,10d59df,80b4d284,f3f02246,f3f6c60c) +,S(e47ec1f,8a7169d2,9c05cb96,42ba126c,aff841f8,c2edfcf,25ec9303,772eea78,ce97644c,ca60474,4c269973,fdfbf169,bf0fa377,61737dd3,77692b9b,ac775c9d) +,S(ed95cc7a,a24a4ed4,1dfb019e,31abc80d,93ca5c04,b0515f2c,492e9105,efdb12cc,1602bbfa,f17e8c16,30ab470f,bd8fd829,b4a466ca,9f210904,7e0903c4,e012d789) +,S(b6fa3ced,a07a9cf4,db717242,9de8069,216a7b51,4145470d,d811755d,a2908a2e,64f695ae,7f19c7d1,17af6ca9,36dcb2df,8715ff96,c8134313,c111da69,7a354dfe) +,S(2e3047cb,4d210007,39b8d5ce,e4884a5f,ae969eef,898a600c,2202da33,239b3627,197f37c0,7c11943e,40328e3a,3c7c11d8,f2d77d16,84532631,53b7cbd7,69808c9d) +,S(df9c446,7a691cae,b8a01ec1,a4a8ebc,fbbacfc,ca347aa5,39d56853,c14ecd3e,acf9554e,906e86ba,8459c108,d49f7aa1,e1e4b2ee,9957101a,f16d43f7,7dfaf6aa) +,S(d452f3bb,2e3e54c4,1f68267b,f846f504,99f39f28,5edb86cd,68330ed9,510aff54,52c5d16b,41eb1029,7f86a30,28d1b610,6f6c5aad,61b63bd3,53d95b2b,fd214755) +,S(cc196d06,9ad60096,c4ba1057,fa4fcd9c,4a50b28b,78227074,22d531b9,dd85a5be,bd930456,14388283,b28cb67,758c792e,5f9d6c0e,2d4c1a86,745e0504,ec902b24) +,S(4974252f,9c246a45,1187b1b6,546cbf27,af9c21cc,d03c7b37,df7a604b,a3b6859c,276e69e5,b85e3241,33f9ec76,d628fee8,3af37bd8,def6e677,bba19739,9da14305) +,S(311548d2,d9f880a7,17e77608,8574ff4c,185cb0f0,a9660ef6,7a94d090,3e2fd845,82b2dfdc,2d0ca2e1,d403c1db,7593dc01,2043122a,fb50961e,d5f86174,18a3d7b7) +,S(30068568,4497d5d3,2c98d3ee,1136a9af,d5bbc79e,340528cc,4e0b3c55,74e867f4,57c141af,fd650050,79ea563b,e9ebb161,a7725bb8,e41e3c13,ec528b2d,df23430f) +,S(1c223f58,1f03b4fc,68024db4,876b743d,8a2b635f,988340f0,d22c389c,43d130a1,9d99aaea,d3bd3b1a,9891dae7,4a3dd857,3a86b643,6c623c00,6604b211,4e27c133) +,S(a675c89a,5d453821,429109cf,45cac77a,880e0e6,396a0b4f,16053ff9,eabfe4c1,8cda99bf,c3426739,c4888767,113b7f4c,9b321a61,1b63b4d1,2dd50a79,d80b90f7) +,S(e990a236,d7854ca7,3e40c661,93dbf3ab,74198351,1236988b,cca29eef,772b32c3,a3d42c05,851b8138,ef1bbb7b,41510bb6,fc893baa,928c98ac,91127b3b,a100aa12) +,S(2a6eff8,af4b8049,2c3d31ed,f6672d1c,d0b231d7,6deeb590,a8d0c4c0,83586027,2a7427d6,951e07fc,4d5cd4f3,ca8a3415,8f0d03c2,3cd2f250,541c0f11,8013a623) +,S(7dad1061,9c4a7bd5,1edf6813,daa8fb4a,2a9e494f,9835db8a,42f4b0ca,827df50a,3e3b2b7b,a44500d0,277b792c,8a529fb3,41667560,1c4e443c,9c2fb2e0,dd17f1ee) +,S(39d5b162,fd48725,1bb42303,b7b8887b,92180fa,ddbdfb7b,a14ef2e0,3cc32aa0,3a8bafa4,5645e4e9,bf4e0175,69fad346,210e65ea,fa92b971,413a2190,b64b6f09) +,S(f9ac329c,ba09d60b,5aa62bed,81e9ca15,7a3bc53d,acd83836,89742ef3,cfcfd795,9c2fff50,aad80c18,2e6593ae,796ada7a,e0a42a4,17ce77bd,ea7be927,161be4ff) +,S(19adeabb,6e9aea9c,fe245329,623b8bcb,3554eff3,999b0b0b,8e035450,14cd964f,c570d99,99e9c62d,a3321f3f,a548d43b,99f05df3,e17273cc,2a45a3d9,20654cf8) +,S(978f705b,eb9b6009,22285468,521eddae,e71f6521,1ae79567,3b122090,fd4eb3c3,8eaa7bc6,1ae92adb,506f9e32,c66f5457,4e1d929b,ef4953cd,a1cd3f8d,c98ff8ef) +,S(e29b57d8,f6808d6b,ec982a12,ac70afca,1c9c19ff,a7b0c724,4fcc5b0e,3dc2fcf1,f7d60b14,133721c3,471fd91a,864e576d,84e5a06e,b031b1fb,3a2947b2,a33b159b) +,S(72073aee,f39510e2,81cca2d9,7831e533,56cc6016,9462a9f0,45100dae,3443bca8,bd761539,177458ee,dff87628,d155c9a2,d6a00e26,51158def,6ce72c35,84d56a3c) +,S(c949cbc9,48db844d,2cd04810,433f982a,680b6a95,e3461ff2,108492f9,247fefb3,162ca70c,c9f19d2,d3da47b,3b0a2361,f5c21492,a12828ae,9c0ff9c7,ef1d7b20) +,S(9acb7d8c,e958f7e5,189676c3,e7248ad7,9f717a67,2d4c80b5,9c425663,e078810d,112dc86f,1b241c26,30d87412,2faad000,473bce32,95bd6989,8b6a4521,7773284a) +,S(e468a13c,e5ad4c24,4df9aaa5,e13987f9,50900b4,a32ba33f,430935c2,1250e4bf,61e3e755,a91bb2a5,3fc2ac70,bb232b2,c1aa356,d494656c,5df93232,a866e400) +,S(26779f67,75d8caf1,46638c17,71e33b02,b41c61df,325acbd4,506199c1,bea8310,e9de26b5,c076eb9,cf3436dd,d9bc7f8e,5772720a,a8401227,7af573eb,65a769) +,S(8c408da9,a816c7ba,ae2846ed,bd923211,926e5e5c,ad595a5f,f2dbb190,f48857a9,89373ca7,e9f3f96c,1f0bc7ee,d427dea,99808bd3,b943964e,f0db4bc4,a7a1256b) +,S(9ccbac95,d80bafbc,b7e699c,aaccea8d,3169db5e,328e1519,825a3f4b,adee6a19,5a8d6936,a2859d57,6accb35a,5e80c944,4d71612e,76cd755e,aa3465b0,dcad8aee) +,S(34c7b7ed,6fe88bc9,803567ae,71ea7c28,c9511f60,e2ebfa8,fffeba31,dbbce2d7,31a3bfbd,c42cffa6,c77aa417,955c671a,426497e6,b35efaee,83a58bf,84de02c8) +,S(7940ca7f,c3bc810b,5679456b,88a73cae,4b2abed8,47260052,ffcb33de,edef6155,8923cf73,9285b368,d32d690c,488d8b38,5d3285aa,c399fdf,6e263daf,4e0b35c5) +,S(2cb10da7,104ff7d8,d8f1742,43425c2c,5e8773ed,71e62e4d,cc0c2d4a,56ac3a08,610cb16f,53ddfd28,7a7ff301,a8047555,801c13b4,81033c94,4e145b1f,98458520) +,S(ced78e5e,58e2893c,3910bd9d,d43fc362,ce06dcea,f44c5aec,ca17eb0e,cdc1fc53,c66050cb,835c97cb,c08ae0df,242895c8,f0f0085d,85a020b5,122e041f,8fb09607) +,S(5e83a4f7,7c4cc672,a7a381f3,e527c8fb,331e8d75,f8578a85,39ae1007,51903f24,545cda31,25c29fca,b343c22f,824c86e8,89f2cd3c,d2a6f3b8,9e3308fa,2968b8fb) +,S(c62958f8,33217811,cb099492,fb8c13a4,5b3d04b8,12a0c1f1,68cac595,e7efcfa0,e179e98,1b92f1be,25c9f892,d6a71ef4,62f3e1c5,43127fe1,f2b711f1,bf61aba2) +,S(7eba00b2,f151282b,83c7fa9b,5df6d9a7,b764e7f,42ca29a9,2734859f,a2f0f016,9e3162bf,a619123e,8e87728d,da825814,4b760c2a,3d05fc2f,1fc25565,1d72a7cb) +,S(8f68c1f4,83ce557b,98d96444,4a2a7d2c,a05d8f25,e6f9f909,cb44b58d,a030cd90,30f15dc2,17e7ce70,a6fae901,70930130,8f7d8706,80c43840,765ee89a,5f864e00) +,S(393d5b72,a9bbc392,4f712195,51ba7f65,4bc4df18,cf93dcaa,bace126f,c4262b5b,976cf232,fe59a3eb,c6514242,19128395,2945cfb,f792e4c8,19248346,37f16e9c) +,S(e1648650,d0d4ca1e,8fac2522,cda2a042,bc93b879,2d6f870,29c6d888,a11312ca,4d919105,9ea261fd,9470ffb9,e60c703,6d21da3a,ce975880,39e1a820,c636f269) +,S(efc7519f,4676989a,a12d823e,8e49b1de,96397ca2,11fe729c,cf0fd67b,bc6d6a74,3f304e50,be6dc6f1,b7c79979,4ae38ff,ed11a253,778d0294,13a98547,e3b889d5) +,S(85726e3e,aa8f7016,1c3629c2,84b7a7ef,79259de0,84f8bbf6,9358f66d,a439133f,756800a8,11a472ec,a72604e4,c2eea080,94971b58,3738e7eb,2c817250,2595e47f) +,S(2e238f2f,de3c39e1,19119541,9eccde3e,b0c4fee3,e432fcf3,f58c4f77,4ba070b1,7ce6b671,c0c79a82,2fdcb88a,a10a8033,bcd0e1a9,2cfab941,d052c09e,4e5e4c81) +,S(9cdc6aac,41e79b7b,ae77a7b9,bc027e99,1d4f8c1c,2b4913a3,1eaaf1a0,9bd87f24,9d666c3c,3503b9ab,d609b074,743f8a3f,460c0122,ad7a0cc5,a22a6d17,9d948ba1) +,S(360dd1e4,608c9215,287936b6,97e5e819,390629a0,7bec616f,7fc713fc,5ef8ec3f,7628d770,5c744125,d5885c2b,de25693c,5afaf8a,3d5739a5,deeeb5e9,ac1c62da) +,S(8657fbee,524c5f5e,25aecdf7,7306c97b,78119e0a,5f155c4f,37918e87,12302d35,242172c2,f90ea26d,b1f7d2cd,dbb9af4d,78a1660a,32402a83,6e598c92,df9e999f) +,S(3ae7e8db,7b069528,acea3e0a,dc005d52,7ca9e1ca,dd3d3cdd,5564ea86,5e1a453,ac203ebf,98b7e46b,bcad5156,cc058857,f32a8d62,2114acc4,55cde626,591fc5c9) +,S(81bdb0a1,9852adc7,afcd9775,54143362,c7e724df,884f1a2e,796d88bd,1c1696cd,2f189af1,a90f9445,353d0549,4d5562f7,4a3d37cd,1362d92a,aefe0393,9b46ef0d) +,S(e95b0171,dd117d45,263141e6,95ceaa52,3498a8d9,d1f09ae6,855fad1c,5e5c3e8,dc8bf907,ea6a4824,9cf930b0,bad3e3a6,c179fda4,107a0812,76f02a9b,9c689416) +,S(20e3979,e95fb62e,ecfa4ff1,3aa3fd46,94b24ab,c814f560,ce180262,11b70bc8,c9d01545,50f1d7be,da471272,822522dd,d6924a98,f6331fd1,cf6837d7,db91da1f) +,S(e0405598,cda639ec,6c058a61,4c39d56,f71c43ea,693f9b86,c9df1bf9,e4fef30b,9df9b561,a7bb2ebd,67b67031,a92dda6e,12550d0f,5cc2368a,603ae64f,ed20ef3b) +,S(faea8667,646d1600,2dbbdfd8,74a59ddc,a2b8024,b2f7f6f0,f2c2036d,ab5c5e9,8112167f,ed386f1,d1e02307,de202bd2,363cd1f5,fefe0621,1c4564fe,eb0220a9) +,S(f01d6b90,18ab421d,d410404c,b8690720,65522bf8,5734008f,105cf385,a023a80f,eba29d0,f0c5408e,d681984d,c525982a,befccd9f,7ff01dd2,6da4999c,f3f6a295) +,S(5906b143,9b994465,c9f3d4fd,f7f09a4a,b9ae0864,262b0140,def21014,8b097533,2917b92b,d0368fff,6e6a98d9,18cfeda4,d039c73,a3cb865a,5d77abff,9fe7970b) +,S(d6443bcf,53ba252e,925f5ae3,5d508732,a3289059,308fa67c,7b051ed9,66b6cc92,e0155fa0,366a2d1c,af8d2c17,a4ad9cf7,f4fc0102,f1e1ec13,7f1b2b51,1af0e7dc) +,S(b95a72a1,dbcfa0eb,ed2200ad,b57d71f0,b96a9703,8bd3cba5,78eff5f4,e9454196,f89c7cd9,783a4c34,1bdd05d8,241ec4eb,d8815463,4d05cc84,d5601f4a,6f3fac0d) +,S(50b287b4,d8b41f03,88804ae2,2b56abc7,be632cb8,a20629b5,3a00fd3d,9a879b6,67c3bbfa,4d8307c0,bd32106,57f5c0b4,78bc070e,53a3024e,1ffe103e,e5397076) +,S(64feb83a,5a81f6d8,8218e2a0,4e6f97b4,6efb89a,6f394264,d905c93a,cb7e5493,3fa224d4,eda77580,4d6ba88e,63df4c3b,5d9fab1e,519eca92,1ada5f44,741d5035) +,S(9434b5f9,2d63c2c,c90ee2fd,b7f7289f,b6277c69,3076d73e,cc38b032,bc8b5cd6,c940b3a6,4c04e6b7,1de7f727,d6fc0883,29443276,6d2ccd51,6d24dc22,3998aee9) +,S(a6db8e98,6d1bda8,995015e4,807b900d,704f8d3b,8ac5fc49,aa16bc61,82390724,3277c29e,bf27d0b5,ef8af507,5e295f23,92c41f29,3803a8b1,6ce601eb,2abedbd0) +,S(50733cc1,dd80ddbd,b254ea6f,14d0679c,6839e6b1,73aa0bc0,9d0ef5bb,bc5c2f9c,246e1742,a5a9172a,ed4e1e0a,9c0d623a,5233334e,47bcb68a,aec41101,92771eaa) +,S(4252122d,5a89f621,2c7b0a99,5ebfa8c3,b980e142,f7a89e07,d4788d91,1163ad99,bc63b87b,fda041bd,f9ac11c,e2e8ab3d,a1368cd0,2e276b55,6419e0ee,3d7fe284) +,S(6bc86411,d3f9d25,bad0a922,21f0146c,9173cc99,d00470ba,a41897fe,b5678f5,e2c1cd75,3915e977,c20d4508,1af1946b,1d8c5926,cca74ab5,c4ec0bd7,921c4cda) +,S(c786df9c,6b2e656d,a30146cb,14da5372,64683e46,5569b1dc,df4c1541,580d40a0,b8d229d1,d8773d5,dedde14a,dcf8816e,acaa274a,1f4ebd01,2086159d,1feb32f) +,S(f42032f7,dc6dc676,5b1a9453,74ee45f8,486e9b94,6a57e651,7dfefb0f,9ea3164c,ad2d7a22,e477f5ce,ad0fbcc1,fe2c2533,78920fd6,cd9ed4ec,1095fa88,2189131a) +,S(3c2fb5d9,a5bc7ad2,d4ce0970,5090a5fe,ef54a6ad,7f8d827b,2ce51785,b29ba5f3,3ec2d878,a4d836c1,71f68648,f8cac869,472847f3,4c267139,5f38e0b5,e96b653d) +,S(b182d837,dbb1e47c,bdbe559e,f30f03e9,ae1efc93,a5a165e3,10285bfd,ffe47303,c40cbcdb,d7f1fd56,c486a35,67420a7f,e4ed4ca8,43a68bdc,81eccbdd,213d7c5e) +,S(75a35130,cea9cec2,81792d7f,ffe84375,a4aec378,57496122,9a77270b,43b12391,988821ee,b6ee31c9,8201a90e,853c4afb,8e330592,6349d405,90c4840d,fdf3fb5c) +,S(a97b9c85,97362b4b,aab43b64,db7e5e0f,3e4cfea9,82939289,e5266f09,87fc8503,ccb75937,fd647eb6,7da4aa7b,72e8d873,c9f035a5,cfa120fd,4d4881f0,9924d8a7) +,S(d129bad3,4c7674ca,60a6f07e,1c1ee8b4,aa3dce4e,82ff890b,cd256324,13a56fe7,b3c8d404,7c8610a1,a56af634,b54dc568,6af075a0,a0cdd4f1,75855fa6,d22cc4c5) +,S(d8a0aed3,cf37542e,a0f06c6e,754503d7,3bd693cf,c3c357f2,7445989e,137f73e2,ba4ad8e6,3bde0d8c,42172a7b,59e1f4f4,581f48e,cffc45bf,929d815f,8133e6a9) +,S(9f905bc0,a5f479ee,6162ed38,24d74a1b,d6d48bd5,4611f840,ab1ac55b,7b84be18,5babdad,4248a4ef,4606dd26,1807e25f,6206dc81,6eeaddda,fd8b5082,52e3da53) +,S(d51c86e1,4519166d,c2aa7604,c88670c6,ca44a84c,6735f692,ee4dda79,e957b85d,fcee6753,29130c5,f4b260a9,cc7efb73,d51e6ec,8ac1ec52,28ca0ab6,51d5b8f0) +,S(ce251fde,ffdf0f59,5a563941,179f6f8a,86402b2c,6bddd1ea,7b37b89,bc649102,5b26a79,882b2f89,79610eb6,5de06e02,b09412e8,bbff66c5,cc650211,d1b9ccf5) +,S(6168ac7b,101fbe73,5b9339b6,9c459fbe,44a6f6c7,bd488beb,bf0b81da,ce511f3,65b6e531,f350983a,2f55db14,588e92db,436f7068,5117255f,ed474aa2,53b5c9ff) +,S(aab2deff,7e77f414,59d4361d,2722b448,6530f0c9,46b93d96,975f5a96,eb4bd091,b416562d,c5b057ef,7e63ec2d,daf0aed4,84320d7b,60695809,c6fa3aa9,e4eaa431) +,S(9ebed934,ca30351f,44b7ea4f,f3f6453f,6d0c7f81,869226c,c8f4312f,d413056,766a6f8c,311550eb,a8500ab6,f3466ca3,52e6b960,c4a52cb9,870ff784,4191a2aa) +,S(a2e78d35,d51970c3,42d03a09,bf3286c2,3a131ff9,abc4bea6,352826d4,5fe2da0e,fcb844e0,4bdf8d96,f423c499,44275ac5,8885c384,57975268,ec8cd880,dc640346) +,S(1a49f352,5203a773,9c7cce34,d21c51fe,dfeba5e5,c0f21622,eb954621,e3d6726d,e617de36,7c6a9283,8d4bcfd2,bf2fd21c,15b53007,6a0367b7,6d6ea65b,af032213) +,S(be65c6c,de6c54b6,c0c4d306,65cb4d61,211c97dc,a74c57b7,13f41028,e2d14832,d7875fb7,5cce3a40,9a74e48a,9b577a04,4c09a43a,989606b5,b44fbade,89e6c03f) +,S(a1572e58,60b10c96,bb3e0b6,7a047d4a,9957448d,74bd8a44,823de9cb,50aaa639,5ae37e0d,88c9f6d,173026ac,58ef45fd,17b0a0da,40304954,f9671c56,93946d1b) +,S(21917639,b6ef2333,378bafe5,fed1780b,24d9fa82,17ee49e7,369099a8,8c9baee5,fee39df,4bcb318b,4dcc4017,7f1af605,f22c44ec,d67a15cc,297f02fc,dfec4eb7) +,S(ac2a8d9b,b2219c98,444d03a0,36db728,ffa182d0,d31831ad,f2643010,bb76d3fe,adec7f18,c9474dc8,d0741d1a,5e72e479,c8b86f74,327fc5d3,cd79cf86,869310ab) +,S(c540463f,bf62ef36,a972d797,2bf79054,80b8e67,415f1895,d42d261c,165d1b86,f04a3516,83039c2e,8bac5ef5,1db4e105,95a27e25,cfe680ed,e7d840e4,f70e50b3) +,S(df63238c,77e75ec9,b844431b,d15007d6,56b849eb,4b6902b4,e79f0d6e,9527ef29,63846f3f,dfba6f2e,46bc7f2f,17af5067,a953cd0b,dbe2fef2,52e73be,b8a17330) +,S(43dd347a,1bf0ee84,ad774d4f,70c67cea,594946c2,94cbc330,15bbdd21,890998d4,b6f58d9e,e6e13c1d,b65dbd28,2343d8d2,3f73035a,b4399672,15b0300c,f7dfb48) +,S(5af8e3e7,f5ba9d80,73c5c1e3,c8d0a62,52eef1c1,17043e01,7d610f20,8b5eff0,246c7a4c,6f6e75aa,eb60e256,756e6365,711e98a6,aefa5345,adefb632,321d39da) +,S(60e7513a,b327df8e,e3d44222,95e0d886,b264f560,1c4e3d03,3b405d37,f6ae8518,4c58466e,b68d6c81,33fa6639,12f4a12c,a4a9f3e3,d4e0f6e2,7e92a85d,4d541cd3) +,S(126520ec,f3129775,786c4d64,7226174d,3ccaf5ae,2e4a1514,90e1b691,f07946a0,d5a2544c,efec281f,e70f05e8,2494085c,133fb918,6416435d,4b7fe673,88c440) +,S(b588e8a0,2396bfa7,8512585b,cd0d0e4a,7d14b5e9,f76e1426,b4591c9,6602c585,d7c6a7d0,827852f9,e34942f9,a6f5eae9,cd0a7f29,d30057cc,46d13e2d,4ec04caa) +,S(257f90fe,4409ef7d,30730e37,d7358c7b,60a1cc21,57acedd0,355d7a1c,89b5750b,b14da56d,9aa8fb67,b2d1260d,8de63c00,a9a7aafc,6fb890a0,e1a148ed,5e371201) +,S(8072b8cb,47c71331,9ed2ce85,cf913c87,85955c84,d338daed,58528427,3f3a4a56,6d7a0ed6,bf3383be,8953b47,d93ac5a5,e40e8547,2fc6d3d7,71f89007,f8d20d39) +,S(fab935ba,b2b72a27,b338ef89,509b3830,b7800817,19c2b3ec,8467c736,24ca2640,2a610c06,77fb514c,b224dcd6,56c5136d,88f87f34,86fa0699,eb71319d,c85a103a) +,S(7c6364c6,4906b7c2,e1ca0d87,6c163932,7e8e146b,afd94c83,2330f990,f979ae52,c97e7b44,26b91f6c,88ab7e39,d57f7b7d,4a5e0f9c,ff15aad5,e58e7017,d51c5317) +,S(98beb1ac,48c8824d,447a10cb,43b51167,b8e7cf0d,9eb4e4c8,43403b03,2208570c,1712c13e,ddff8fd5,191fdb28,717efb74,ed52a9f,f47bc21e,b15838d,fcf00af3) +,S(f683a667,31241c44,4adcf062,156f3fdc,d04e8450,911908e1,95bbea2d,8c5bf918,460eac53,48ea1e78,9fdef168,a150065e,1e4a2f83,85268385,3355586c,87453f1c) +,S(38f065a7,165e5d4,d31238de,8dc38f43,4dd024c6,6eca026d,de03c4cb,b43639a5,790bacf5,d35a688b,130bdb38,29073b8,28837b9c,9357544e,1e44d766,e401d044) +,S(cee8a218,2b3004fe,76714511,30340b0,7cf10241,d9e933c4,97ae84e9,a1d525f2,ed373709,3e0eb05d,3ee2823b,25bbbb11,ec943848,1a3ceae1,89573d71,7a596b3d) +,S(164c6ee5,620f4582,35520eb0,8276d85,9a14e266,b7b59576,d0a3e0a6,636f124a,fe92dd66,139f02c8,76ff6e57,8c769a4d,63484072,5c909bc9,481d4a52,f60565f3) +,S(d4606a18,1a0bd363,eb63849a,81c77d0b,942ff14e,7f885c61,d1fb772,78ef1008,81e7b2cd,e7c5d9,29e1d69a,309a334f,2c01b084,e82b789a,835a7aa8,5d7e93a4) +,S(905f5725,1df1651e,83aa8b3,dec2d96b,a32155eb,90d7f985,b3ce5213,2092be07,e4acfdaa,9eb8995a,a4ac8a0a,2b66cbbb,d561fe6b,389c56f,3af6f62a,d7579632) +,S(2e3ab14c,d3aa69de,a35a8ad4,99130302,b16f3d3,9df06b77,7c30e404,91eb6dda,ade534e7,ea0217a8,88c50bf4,ef81dddb,a5c7ffbe,bc0f90e7,110df2a8,e0c7c2c0) +,S(98207cc0,23f50a6e,5f5ce8a5,68c5b24,d4f4f741,94de76a6,d1e6f44e,72619a9b,fdacc236,bd424684,52508806,b08fabdd,98a15b15,6751953b,95b4c5f1,40bce374) +,S(b6d8bc0f,894863a2,3a793c3d,a33a5e66,cafe8696,f9cdd40e,777a40ea,aa203ee2,7e9b246c,8555b4c2,47c45fe1,d1e5d160,c7ed7d37,a3a43440,deee6ef4,15dc092c) +,S(56d030ad,eb30f1b4,7f806276,651a56d8,7f0d8b6c,458092e1,61351368,8cd0f6c3,bb3a1513,155c5885,e084180a,1728902b,33e1a61b,364c8d9c,94d67ca2,e386f131) +,S(77251aac,f919aa4e,b7610a77,ba27d94,c85b973c,af04c885,92fe5272,a48ec088,ef27aac0,593cc67b,93535bc8,4d0a04a3,e8a865a1,bdf65312,85beac2b,d58e149d) +,S(cb7b6a,cbbbdc23,64711585,6d80df3,2ec9aaa0,c6380b3e,677299d0,13658121,1f818bab,72575e35,a60ce7f1,c720e9ce,2f59b086,63cba841,ea288920,16a40ca4) +,S(4a18eb1c,bddb4c3f,ed44fdfc,6242959c,29720142,21d10154,c7fbca68,5c475d0,bb24f347,ebdcdc0a,6429f8ba,49065475,9cce87aa,8df10496,6d2ebcf2,97e70ffd) +,S(384286ca,1003c97d,7d151032,97d81cfb,e3e3dbbe,5dc70c76,6a8dbdc7,c1e625c,7201deb,638d2ec,6cbb4db4,e955ee1b,a3015cee,e06d2ddc,f024daab,8f07a277) +,S(84b6d6ae,d5e00e31,73c24d39,80f05cd6,f61625e3,11439a55,e03ae2db,d79a7d55,a3da9e1a,4c32e4f9,a1d326c3,6670296d,3ffb18fc,266e169,a99d4d00,4de383b1) +,S(aa1cab51,f7239cd4,dd27a4c4,805e614c,5d972cbe,c2830ebe,7daf6ed8,781c37e9,cf8bb72e,535fc8cd,12a2f4d5,e8f9e257,38a28812,1c93b061,5fd4fdeb,368be5bf) +,S(7c4f183a,f4abbe43,d7fa6d5,77ea6c14,83302f2d,b863a7c5,bf072e51,3d2140bc,1eb08c67,a417c0b,58fe8185,1a66902a,a608db07,24dc38c6,706bb80f,5956c808) +,S(dc30f68e,58ff30a,4bf2f6b,28b30708,506140a2,1a971c04,8afe04cf,94b54d31,6f996e08,8d4f7f53,aa1c2050,644a47ed,bcc1da4f,519978f8,6496ba1e,c7be2688) +,S(145185a9,ac6b036f,d0d3cd25,c904b3b7,c8f1d0ad,3ffe5f89,d87b7804,8b017426,d7f6acb2,828ccbc0,db0708e2,79db6313,fc955d2b,cf9e2754,1a7535e3,24c7bc90) +,S(e8700138,5c0bc4e2,9911f29a,e39a5ae3,ad3cf1cf,d690cbef,32f313ea,fd190fa9,92d83708,2e5139d0,f8084001,8ebf8703,da250361,466caa96,717edd0d,6e7ada7f) +,S(5fac0aa7,9963a1e4,5e1c668e,3512d0fe,2eb2c709,d5ecc71f,c862d5dd,523f864,9c7bfd73,445e7d9e,139b96e6,813f1f80,2ec632c6,a76e9dfb,8afecf40,2788d16a) +,S(441f40f6,f3ca4dde,5a085c15,57f14cf3,fbb7c3f2,5716c33c,63ee90f,45c564e2,c81f1205,1179c2a6,f2614495,322cf40a,34cab55d,c90d61b4,d1bc3787,ec3baeae) +,S(a4068c1f,c63d8f21,203cb6af,b37d796a,3c454bd9,db974ab8,e8bfba8b,b832b043,b5318b99,e9354250,a837f8cb,cf8d9cde,d95bb1d,1db0becb,1e887535,4ddb96ca) +,S(44563417,c647b097,d0238a57,74998fce,3c809a26,f6d2b71c,eeecebfb,134cfad3,3f417680,1c15172c,ef636dc3,12742429,13d59079,73ad09c3,9fd8c6a,8a95104) +,S(d57a5fde,47873327,728f5706,d2f0d64,1c5386a9,fdc41808,a2c062ab,942acb6a,cffcd62a,c0c85aae,4a6b7881,f3be170d,9836abda,baa47d60,8c0b8f60,f9aaedd1) +,S(9dcedd10,d495fa2b,6f4b4387,57cb38be,d6f09949,17e7ece,7de913f7,8cb111fd,73196e22,59d4ae9,950725dc,77321567,167d7761,29cc32e9,d92b6dcd,4c056223) +,S(aea290f3,a4ffd405,d51f1c8b,5f11cf74,60f05300,a1e24c08,25b96910,b24e32c1,f6c100a6,3c918f8,f64ffe8a,95840421,dc384635,e3465cf8,65034bde,17ca8eb9) +,S(bbfcd317,5091846f,181696f6,35fb1b05,802e7659,7ca97040,31339381,46812234,2a0a4ebb,1f09b31e,aab4478,89000fbb,5876d7e2,dd889393,3001a977,8aaa3a15) +,S(2a3b4e65,d9d7661c,addfe1e1,96beaca3,ccbc0348,dff6d2df,21f394c7,a7f4594d,74c6f171,1a2c0c01,78bb6a27,b6e17cda,bddb7260,acbc533,a49b19d1,e0b4a110) +,S(d8e47e32,15cbe145,aaa9efec,ada428f1,8d8c599e,98d2f9d7,8177215c,c85dc2ae,5c4d4f6b,aadcd87c,7ac76eb8,22e1c0db,e7c81342,702bfd98,e193df1,809e0511) +,S(5b5954d1,25d77778,f3c1514c,6256ef65,2ae0ab97,151f8856,dda6c87d,1e04a34f,1c5ddf3f,b185edb9,14769482,95e687e4,40497582,26b36fc6,3502922f,cd1bf81e) +,S(e8097e1a,12c6837,a8f29eec,31ccbd16,f191e7a7,d7b199dd,d6d9ee6b,7f26ef55,84ab3d24,e2c4407b,53e4299b,8de1aa8a,22dab9be,b6efa5c,5715a943,65174b9a) +,S(495ebcc5,b0573416,f2b3e705,fe4a4bfe,1e756211,5f37b8a2,dec57688,dedbdd45,3bc65725,6783970c,7696d5a7,b04ac7ca,8c627ce9,251844e9,e7cca774,4d385be7) +,S(4ffc69af,b9cf40ff,c94beac6,aa020109,b7855e0,a993984f,5e59ba16,fc78ad51,6d43d1f9,e3283528,494c9783,cdcbe9ae,2ede071b,ed494c57,2539df6e,b185ca1) +,S(b047e0d1,afc92251,7eaf5c0d,a9d0a093,fde5e829,84c8483e,d256640d,166dfc75,dca2ef00,a282972,d4bf67cb,74fb31af,da5b8145,ec1b7a65,6636376c,504a70df) +,S(ea7b0b93,48e0b3e2,be800ed,6ca4b121,277a496e,84fb6680,2658f68,37b1d530,cef40d2c,e1cf820b,19b435bb,a541ff1c,fa572b1,ca3693d0,cfeb3b32,8ddf918) +,S(e35a53cc,ad74738a,bde75a3e,e2b10d7a,d4ec39bf,e32e1daa,ecc151f3,bef1966b,ad06a8ab,a0296c17,fb24eff3,b27284c5,6ebca204,f6eee752,276ab9a8,1f1bce13) +,S(70334511,ae9acd50,e094f034,17dbba05,4a104c84,ea8d6250,13e1f8f6,907261a3,d1f603e0,5af2e1df,4b8eac69,b4067810,c302ed18,f02bc964,2eba34f6,bc67e84a) +,S(13adc074,c3ea8877,4598d0b9,ad653285,c81bd98d,d4bb6a43,c126db2c,d1f08d7,4bbda9d3,c83c7a64,fcccf3e2,c4251a7e,f61966b7,ec48e89,c991d44b,9588c83b) +,S(4a2a5fa0,71702fa0,934b66ae,7c003f00,306f07b8,625d92f2,d2276efd,18ce5f0c,f9c2f4ac,d8c594a4,117a836,7fa5224e,a7ccbe60,2475e3ed,b19a317c,5feff6e9) +,S(e2f7dc14,79bac0e,a95b5a2,1a9f4e,8c42a23b,8f25d09d,dacb9a3b,fe3ec638,ae6c82,c4f3dc5,41f140a5,2eb6b0c,dd0e200e,d0d951b,e85efd4b,b9b086ad) +,S(eb1d6d07,8f6b74f5,c48a913b,8510e8d0,5cfeb954,856f3ebc,628d0db1,a253963a,f3d73300,e216d14f,d5a67c35,91b362be,f13818c3,36a93784,875ce9b4,2cd8c7d2) +,S(a22c6d71,1d79ae71,403feb96,6dc11adf,253a5d3f,d3d74b44,5f7268bd,84b52277,86d5212,bf37db8b,4e873476,36201714,3f295f0b,d69d2187,8904a53c,831af06) +,S(42f7eb02,797cc76a,21c95db3,c9a0014,4ec5defe,553a45b5,1b701c0b,6f5ed3d0,60525877,3cb86452,928e37d,ce19e2ad,4da63174,2f049214,9f9823ed,ba679519) +,S(f5250698,b37da26,20a3a80d,a9c1c88f,792677a2,6d2b9fa5,49065339,ecc1e95c,b0826c,66edbd2c,5562bb14,d6f8df25,a5d0bc54,7a1163dd,4a8dc1e3,7d140266) +,S(b845d4a0,bc8db805,43526506,cac5c093,cece5c5a,85750d54,317dd78c,7bc10832,e38db2fa,207ce0b4,d9b01ee8,b174a24e,f28591c9,9d203ca5,7d90080,807279b) +,S(4955d281,746b8c9,4bac7d53,26aa28c3,9fba7149,7b4fc036,f9971f7a,870a67cd,ce72ebf4,aef6e987,3fa5cf3,e66ec918,911885ae,848aff22,eeef12e2,e50e6cee) +,S(20fdca2a,a03d6105,50f2eab8,d5e7d47d,c4e2e9ed,e6d2c7b,bfe64d75,176b9e9,1e077683,2c44d6d2,19d19c7b,aec0a303,f4d3d5f6,4ad8ca35,83f87325,6aee262f) +,S(418de9de,9adbec78,769eba7a,cab3853a,9a85ebc7,2bdffc86,844d0f32,15de4877,20d521c9,974c8ee0,f817ee37,a0fa14d2,eefc4e05,2c93ce87,ee665898,9e49c5a2) +,S(135b5a4a,f64eaa0f,d288bee5,c1bb7846,30df305b,5d3b13da,d8c446d3,6e13485f,3e571c3c,fe32fe42,669b08c9,14a655ce,828f41cb,12b9c18,9234f4eb,1aac0437) +,S(7eb64f50,5e26671d,21d3b2c9,fefbe094,c6300348,25248e86,5daa8939,f8b7e90d,be847834,f303ae8a,55ebaf3b,5bccfd61,6284e836,13eecdae,ab43bb6e,d4d4e986) +,S(9ee1ccd1,670be914,f9b7a070,962f7ac5,ac9d069c,eb3e0748,72db2e08,32870fd6,7d3d9dd4,9e71fd68,4271b17a,a8203ab6,1d2bf6d5,2fe3773c,78a8ccbe,d256cfed) +,S(a256c06a,796cffbc,5c90d91e,93ded565,b9755b7c,b760794e,e3060b33,3c217e71,e9ef8b6d,7731c262,6c93fb06,b7a6b3fb,fbbe0e0f,54682409,e5218a74,d4a064fd) +,S(dde8a9af,ec32c1fb,be9470d7,a435b4fb,bd34416d,e703a1ab,5188fe8f,f721aa4b,e7dbb850,aced2fb2,fcf5ea6b,edeaf383,e4ae0fe7,98badf41,66e58f13,6a87f3ae) +,S(fe88599,811d0e9,f780d359,2e8106fa,2f54fb6b,ba1df66a,b7b0b41,2c130c49,b3b0b8b3,c7f36d43,86f30438,1989d885,31edab91,f25251b4,e01b3d3a,6ec97f2d) +,S(d7da001e,8a606b37,ca65ae71,32214cf8,258dd422,efe0fc83,adabd56d,64b0467d,97f503ce,8eee1873,7e422bdf,91f051f7,1025353b,3a1f6f1,545206f8,2a32aa5d) +,S(65237583,e3e1a640,c2c16a9,a49d09c1,f5dbe2d7,a3845989,574abe33,397e747b,2296a1b1,e2350d8f,14a6fed3,afe30fac,a45ff345,9f8f515a,370aa260,d435f7a3) +,S(419a8e03,2d8fd27c,afda6538,9b757550,313307d,12fd185b,4d2f026a,40ae1de4,2932ea7d,3421d738,d821030,f75b0343,fffe9d25,8b605cf7,e20f6b48,1a94db03) +,S(275d261f,7ae2ab4a,4ad1fd66,1621a223,7ce08787,beaeeee1,a537b103,c0a44023,da955bd0,4ef1256c,9e184615,c4ee666d,c9ae14c7,d95caa7a,5dca6f11,1e5e2e58) +,S(3ac6681b,d0a2968,290ad83,cb0e00c6,6a9962cb,4c082366,953e294,58ff3651,28348b56,38ede228,7578cf14,ae385066,4595a2a8,d86282a0,edcc389a,346066d4) +,S(d4ba242d,9407df55,a9f672b7,e01cb1db,99ef744b,d24d3e47,9b1841af,a6c1f05b,9e395144,aa1fe50,9d72d086,4a1673c5,24c4ad65,fb7bdb16,cbd52053,1c6f11a3) +,S(c6525077,2bd399d9,901d57b5,7e8fc941,cae0f5fb,6d47ee3f,5b3a7cea,3fba2e83,629f7edc,a6ec6b0c,579cf9f1,867e1bef,e3bf9bea,8d8e64b7,2b18532a,47280efa) +,S(f12daac6,d38fcb00,c2425a79,2c52225c,a94d544,c6b96076,7ec9c885,d6d4430d,1764feee,2584dee3,abf2aaf,737a068f,fa6aec89,6c02e2fd,cf0ccad2,7ee8f210) +,S(db858a7f,4a84d88f,236b5994,dca409b3,d7111df4,f7e5c009,4ad1decd,82036673,c0606c89,e4b13042,9e0a63f5,1c93b3bc,95d98832,d89a9515,2e5c1874,f2c94a53) +,S(237f5f80,4d4c50eb,d611b079,5cbc6567,101ec8ba,1a265976,64472f7f,5a725ed3,b558d31b,7647c4c9,1367d696,a67e5d88,76454900,f340cd,5b8d7490,9fdd5993) +,S(e962e9c7,7c97cf36,32bf0a88,d6e939d2,68af9fc6,ebca96b8,6fb679a2,d953eb20,931395ff,a50a854f,5aa29314,c50c253c,c3175739,9c2eb20,600b0217,9f8ef48a) +,S(890514d2,14b57796,85c0cd66,818d182c,3d285af9,771c7c48,92ea2ac,115a8c3a,47c5a,a4d76cfb,2a62993b,b499df86,fbe7e130,d4758235,7decd72c,b61aee8) +,S(8b058976,295a316e,65da1774,da78722d,8d729f88,5ea4402b,f20dc67b,bab7f815,aeed497f,57d52480,23b94a3b,5fbe9c0,e34d0039,2d57b34b,377bda9e,b8703335) +,S(6a4685e0,7d96a793,d55a6416,6b089623,755fe549,3a879fbf,fc9a5a74,7ee7991f,313ffb6d,98044c92,f37b3f66,81f1b4b2,d9b2e42a,7c34a5bb,db45b9c,6063aad) +,S(65157530,e4ffeeda,41064bf1,f8d85174,2b9b8f64,87a05ea9,3d2198bb,3f33fc26,5b0e76a,8f96facf,9d492232,95a0c6f5,6a609504,b9b07c38,a72b6f15,4cb8c9f1) +,S(9f6c288c,1e04703,46b02d47,8fc0a40c,dfc0229d,928639cc,6ad2ac88,96e55085,2af7c1c1,7210b552,4ae2083b,b45e9749,c9452776,c12d5e83,ce265c98,51266c8c) +,S(c566e04f,e5ef7062,7d914a04,40731caf,3a7dccbd,5415cc1a,a2d81328,b8a6da75,a3fa5263,a7f66158,67f43270,77d3b2df,8db1befd,552249ad,e96db0d2,8c439282) +,S(6963ffcc,cb62ca7e,565fa9e7,99db54c3,dcaad601,95bd2dd8,df70d447,c443ba4f,96c715c6,84bed531,27c28e3d,6d6a0214,883aa214,25c4626b,4c11cf17,36b8f134) +,S(50db27a9,8e0328e2,81139df7,5376bec6,37e9272c,f7c23333,510bf5cc,c4f46b2a,b5221242,9eec82,1e9143fe,af9e7813,c135be82,bfc153f5,2ac061dc,c1302d92) +,S(7badba3,8f23f854,2404e636,b96e86a6,84557310,2bceb7c0,241e71c6,1ae22ad5,bd000395,b5d0ba4c,a76ac682,5191fbeb,f6066d8a,81c4a210,56ceda82,e13459e4) +,S(147667bd,5591aa83,26fa497f,c60f8e7,a5ceda47,9d4b2f7d,93bdab3d,81bcbd0e,bcdbbbc4,2adac6ea,413fc3f3,6cd2089f,420a6183,a918bf98,fff27aee,3e870849) +,S(ee576c33,e8404e1e,11e1b5d8,6ea52335,cf8b0ade,49dd16a3,7a61fc10,cd3eefd8,722bad17,6e083868,b3c14ee9,a70013d9,89c01b5f,44188ec6,7db7bc3d,ca26fe2a) +,S(8e3cfa71,f3b7d3cb,fe59d8e0,b579b76e,d33d318f,41d3b76,121b02d3,2acdec80,86be156d,b76429cb,ff2c67e0,c015b7d,d0007c7e,33f6041a,d817ae9d,ed5dc4fc) +,S(e220362f,2df8a485,51dbb7ad,634c4bb3,714151fc,db3cc2f8,e483aac,50d88768,acb8e001,a81eb6ac,99dca40,2d62fed3,8891fe2,eeb8e023,6d8f2447,6f4fd200) +,S(1777fc26,9bd7aebf,c014c785,25dcd40c,f93db012,31541cac,448c44f4,89628808,641bdcb2,b87e04ad,3ea3a3d4,c364e93,1171b2a2,cf3c0205,77552b7e,594c649f) +,S(ddfb5269,fcbac0bf,a855d2c4,c9062c77,836af1d1,145b4df5,688b6a5,24c11651,c353674b,9520ea9e,eac3bbce,a85b0709,d0284c37,a7faf78,8b573ebd,67bac8be) +,S(b01ea11,d4704bb4,24cb11d8,b42411a7,3f227c84,dc10eb13,c2b20a1b,bf23258a,240844e,9ea3edfd,948d2df4,51538cba,ed57f157,d0632f2b,8b644570,5f9ccaf9) +,S(934e20a,46fbb416,fbe829d1,46bebdf5,2220c0db,958c2a9c,64244713,4509cabe,76b7a1cf,79ebb5fa,58f77e64,4395d33e,bf90c0be,37e7439,c3d29013,25b0dd76) +,S(15bfe959,5ee58bec,791981dd,13ac5380,6615ff53,95dd4661,28c23f59,ea236967,d6dd460b,d3d36bdc,eb7d3ba7,745fe6c2,fddba241,fadcbdee,44f377f,bd43ee00) +,S(5e1a723f,403cf56f,8019797e,6f8191f6,6e7ccf15,dfb1965e,590490b6,224ecd24,97342532,36c48696,645a7e60,552eeacd,4cba990d,6d73117a,dc6f2967,a6a0fdbd) +,S(1485fddc,85c819da,8894c1b3,8be82eee,762a052f,3830dbb3,7d21ee74,868c778c,d779373d,d503731b,52f9e689,805988c0,b916a579,921c637b,286c580,93343d5d) +,S(6f4b7385,f881c9ed,202ab6ec,c8302626,668a1296,36274f3c,ac4296e9,1eece7db,fcf6f192,c6c80fff,3f5c2bbc,7c6c4a5b,b0ea2e3,70799827,440e998,cf6b26a4) +,S(bc27cb29,33ca44d3,b56280d7,7d69af2f,9220f4aa,49aa0fab,685c7c54,62adaf76,7607d5b7,a02c5e21,cfafccc1,26e8439,88c10942,aae6333d,b5262426,1ed4da98) +,S(76f86b25,2530d87a,b04e64c2,4cd1e05a,e8324bf0,a717280d,3845cc5f,a6a1a733,2db7ce38,33bd24b3,55e95b89,ae6d8a54,19124761,e382745f,2a7347ce,fd7c382c) +,S(5615175d,2ec968f8,81dacc1d,1bd6c06b,df87c9ab,53fdef11,335818f,bafa918b,5f755638,6154cee9,e71d21b9,cee3971c,7d41e3e0,ca2c1ff,f66982b4,d66fec25) +,S(6390f1af,1ef24aae,20e2ce29,dfe9a0d1,50b2826b,f5cb3629,8e0dc16d,ee2bdf8,cf3e2b98,4f120d10,16f82e1b,8916928c,263f3323,52bbedb3,c29ae1ed,b0d49b1d) +,S(bc5df46b,4fbcb83f,7aa53579,ac8d5c3e,8482941e,cf848810,f9239138,b57e9378,d4d15516,624e72d5,9002dca8,3c8b5914,b224d4c3,75260dbd,cda88f9f,2f772627) +,S(3d069f1d,dd52177f,cd802195,c7c8b2ef,1e43c34,9bd88b41,43bc2d54,6a2b8d33,2ba48861,14218d67,1b1fa4e4,2aae97fd,66164e94,af1e3026,8dfe9dfa,7155fde9) +,S(fa657492,fab9ab23,f1a49c17,40079d7e,abafd7a8,72e481b8,7b30cb63,8a47757c,89d2c7b9,2f1ad11b,d2808968,c426a00f,e584ad83,86dff03c,1a047804,a2e98630) +,S(e2318d84,61f85ac0,7db07d08,aacbed7c,5f5a45fd,7e505bb7,ac86b417,6b3eb46d,3b0170a3,b6f466e0,380ab984,e5bf4b34,89cbc479,cb2808cb,445614bd,8ab012e9) +,S(defa0810,91d1db16,fc2f86b4,fa5a7331,f0c15682,55855134,10f41a6d,a2bfa6a5,8429db90,fbb25354,3e77ca0f,e7a731d7,f1a481bb,f1c997e8,5f585844,423ace4a) +,S(fbaa7567,7306fdd4,8c85514c,bcb78e04,ef4d693a,dc7c356e,f95ad34a,cc880db0,45c4972a,161f4a23,cd71f726,d5617b71,421b68f,b0611097,3edf11b3,8a391909) +,S(5dd76e24,e3cc0c5b,ded55d15,858f1c19,dfff7e43,b299df43,3ee77b46,2122205e,992de68b,87bd6760,a75d6b90,89dcb2b5,5f0b39c8,eb079ba0,e4451fb,dee8f2d3) +,S(890c7a78,d0f1db95,75b53e98,a0a63d81,8096422a,3ee18403,ede8ffa6,3af9418f,7a362df8,7430b479,11e8d310,558195c8,fed28b05,531b68a9,1631ef97,ac008085) +,S(4914f692,f88e858c,b6174e6a,9d4bbdf9,87f0e373,1bf6e69b,8bf3531a,43a37e6c,8751e02b,fa9e0384,2ff3e4aa,307cb7c5,fe4f7941,1069249b,c8b19866,b6169cf5) +,S(a5f97745,ddc25117,81693df1,bd15203f,9d23bc93,9015be73,c6b4e256,d1d05416,57a99674,cf64bff9,7b9ba0c5,69d253dd,52aa188e,3ec645aa,89466c79,5d0f0370) +,S(62da0bf9,8d32519c,16fac809,95869f09,b570b953,e0a7bd83,9623a9c9,bebbdf84,9b9ec74a,c960fa8c,2ea8bd4d,93ff624a,9ce54fa2,4a1822a2,37d962d5,64e9121d) +,S(5caa2062,c25d7df2,23718f9d,ff29a403,e5200d22,bf064b44,c9519742,4c448a5f,6063bf93,1f72f65b,9ca76400,de5f5204,a8a0bdc4,b19cfd12,2664aa33,79a7a27b) +,S(4a81083c,c18dcec3,5825415b,2854250c,9dc651fd,5d897610,2ceb7691,576ebe60,850f48f8,7ffbf26d,eaad1f8b,2c0b8272,5f7c313f,55811b98,408f8f34,8421f241) +,S(ba8baaf4,9d0c194a,4814070c,786fd9f,4b8dc012,c42ed667,7b39f67d,da7fccaa,ceaa8874,10bbe854,9e87af6a,15ae1326,d85bb995,19a8c4d5,dd3a8599,d9ae0ff2) +,S(4c780a0b,886fdcbc,a30f239e,21495f9d,5ea38a6a,7960ecb,ea4dd2dc,9266103e,7e50e1d5,b6c811fc,f86ee651,5d64e06b,26827ba3,656dfd51,1fa64124,224e182a) +,S(50a433f7,f528d66a,961d7123,7e6d2bf6,7321896,5ec6599d,b1f34b0c,db21524c,6bca1083,9ef8d450,e56829d0,cb23ddcc,81e2e7df,e79b53f3,2f8aab9f,e2eec15b) +,S(b98e05de,573e37c2,80d6de1b,fd479bf9,bd23a6b7,2f6ab34f,caf03236,c67ec5fa,d86f07e0,8a4c3d61,f087dff3,a2af2d98,58787d2f,424b49da,de0c584f,4d8756b3) +,S(d0cb5279,e76b8be9,b2e9cdd7,b0c841b3,33398541,24923224,db54a91a,81995433,11fcafb7,28a3307d,2d87f2ae,d107b0b,d64f6030,b89e845e,1f67ce7,4cf7ee6d) +,S(90c89963,619b1593,d5fd7eb6,751ef03f,aa7c6802,46e36bcc,5d0bbae6,25376720,6e8f2a86,75b803f2,c3c87f9a,98318cbc,61b99073,2b8b33b6,62197ec5,73f64a71) +,S(bd3ad39b,989c3a08,e45007d9,116b0d4e,2dcb6a14,26a44dc2,29bff230,6c1a89be,7e633d7,de03e6d6,a7a4a833,f338160b,cb914997,6dc2080,28c3e2dd,b1c1b11a) +,S(1da5082d,a6e4721a,499d5559,91e8d216,f26167b7,d6de224d,17bc4e5b,ac94093f,5f864511,4b89eb63,60ef865e,6eb887c2,bb0b97e3,9a0b7078,888049c1,29f63c77) +,S(19320416,52e24197,d195a0f1,99818925,35c19790,99d15992,8999073b,4028d659,2cf34c91,2d1666fe,1abd3b0,49b12dcc,f7086e58,b7700b23,497bec18,e057059) +,S(79a7b5e0,482523d0,85bf574f,2e6e431d,b3bd6ae8,4e921b87,fff0f683,976efa9a,f713e011,70de0de8,a8cbe229,b147cf82,efc7fe3c,d7171785,c85bbbfa,ef935755) +,S(c2e16cc6,8559a160,9fe16d0a,9be4016d,55fccdc4,2d22ee62,895e0eea,a64436b,22399345,d40c11bb,79b9f036,5fdf6a91,4e1f43e9,bb1f0a87,81d2ede9,fdb6a118) +,S(f76c0f67,bd3c648d,c320125,5c34a93f,ed656378,8c9f61a9,c60933d4,e2d55d7,205c9c5b,83bbf922,8e99191d,e7ef0feb,429050e8,2b9fb3ca,1dbd2d5,cd35f612) +,S(24a3af8f,ee393ae3,2c30230d,ed6f96f2,9797d591,1cc3d934,b16e1304,de7bd75a,302041e9,2ce00cb5,d4a667ea,90df7f90,576865d3,7f462126,400c77a0,a44259b9) +,S(2e8bf897,5f29a6ba,636e6ddc,1e2dcd6a,1373f123,c6f155b3,3c8f46dd,b18baf7c,a93f0c91,258ec64b,d6e18761,872cf0e2,c89f9713,b9008605,b0378f8,1ec867ae) +,S(a5d35483,7f90d71c,8d829897,b3a8fa36,7c38b41c,879a3e6d,52f2988a,b88dcf68,853a586d,9661cd50,12d1ae6a,1501b874,739405c4,c7e32bd4,23ab7c1,62382bfa) +,S(51a6c879,ba6f75d9,4480aa71,2a343be1,bb9aebc6,bb4ca3be,de16d33e,992659c7,3e636d28,f8b0a4fa,a3ecd585,80d46253,61f496b0,344382b3,5742fcc9,403e7e05) +,S(a1d34e3c,aba45bf,1772d2f4,bcacd17e,342b66ec,97dadbd6,780cc453,ff2449d5,6c3a3b8e,9717365d,2f21e2ef,d72308b3,45008ebb,10ca02e,969d14c9,1aaf677c) +,S(fce0f1a1,69034370,33de7e6d,b2364b0d,4441c5f2,ee405e68,5dc546c2,58adc2ad,c018bc7c,fc5ad1f1,36103729,e1a177a7,495a6195,915ca5ae,c086804b,8c107865) +,S(e380e6af,c47b11c5,1ba0c8c3,9b796179,39b07cd9,988896c,38011e73,a4f98a81,60ecd299,c22fbed9,132bd455,1f44022e,151927e4,7ad93f1a,a0539c37,2680f6cc) +,S(6382fb8b,2f4179e3,191d863b,a0ec4cd,94b52103,f24a0377,8f6ee27c,7c81115c,6e8d4181,9621bf4e,3c04c5ea,2b4c0146,dd0ed973,bd4530df,d671f39a,e54db63a) +,S(c488650f,d66629fb,927dcb0b,9f5d0771,1caaa3f7,ad6df39f,7d8f98d9,65490aed,b395d9fa,46475b16,6beed01e,90c9cfd7,83e6138a,7bbc6d5d,f919d41f,3e512c) +,S(5cf1f5be,462dd02d,f8d1e9b,6cb1540a,4f1e5be,de9c8d29,954bfb0,217e494a,5e8727bc,2429c9a7,5123967b,b598207c,46105822,5402bfcd,c3d070b9,b2351d20) +,S(9644ace5,9dba2b1a,f3f3a4af,da130ba3,c3bdefd9,39c3b52e,670ead47,54407b9c,5e83dd4a,e338fc0b,8c501f98,72295400,4b2465f8,4f1c272d,20e3a2bf,300b1b79) +,S(728e6659,f0bb9bd5,916846ff,3aab6f10,85517ad2,c17254e4,c2ce908,c7934781,7df32327,354020,319e9cb7,696b0384,6b8e5bf6,691cc73f,829abd42,44e674b9) +,S(80e68c8a,31d715a7,5068091a,142d4a60,ff30d2c9,42f625c5,d234bb78,31009e8e,fe04addb,b9c47f69,3dc0b126,67b0960c,1b4a7bf2,882aa626,b1888e5e,e4157fd9) +,S(e655129e,90211425,558cbf1a,4eeeb630,df68a4e4,f96a176b,db55500a,89f5af02,d5e3a471,ba698897,9f747ae1,a1aa87e,e10c5069,3df12ed3,ed52307d,a0202a69) +,S(30a9e289,f6ab5edd,7b56f48c,e7373a6a,97dc698b,511343c2,8c5c217c,de67ab6a,f4016c18,c4f75d52,927127bf,c403a83d,4ce304d2,8a4fb965,beef9fda,4e9d3f4e) +,S(8a6a4557,2c1dba29,c9499ecf,d59ea43b,1ebec5a8,78a3e2c5,2de09aa7,c0288e69,56e4aceb,e8315c2f,b9271519,80a21d,c17ebad,63223380,b24a7237,33ec205b) +,S(647d3443,9f4e4f50,cee5b0d6,8047f130,965f8abf,482f6166,8859c86e,326c1bd1,f951b5a0,b180894c,f74c5235,cc625888,fb830382,3b0d085a,dbe857ad,dbc22088) +,S(6d143d17,9f0a42a6,85031c6c,f62ef32,2cde46b3,978b04ba,bc37bd3,34de5634,925d0fd9,11c7863d,b0ed42c1,76591307,72b456fe,83bb8063,3afe5340,cab4b5a7) +,S(f21cebe2,7ce8dd3e,fa30428a,cee881b4,d65eddd1,30f9fa62,9d78291c,a4f4b0bb,4a6d7f43,f2ed3d26,330e58c9,27a87c55,850620fe,1edc6e36,c9a3978,8f922ea9) +,S(37883073,e227a5de,452c7706,a4a06594,5a891c06,e594fd4e,191d36f6,79117c35,224bb4cb,389f3d25,42411fd6,594ad6ec,bf4f1c9,11f723e1,53dbb420,33ae8ec5) +,S(c21520ae,e6cb0358,53a7da78,919c88ec,84c17d10,3ac13ec8,6a412d9b,96e57c54,56720dfc,f748ca09,e27e8aa6,e29ea591,c0205290,3d38bc35,3b0b0155,113a5bbd) +,S(96cdb3f0,d6194675,7346b2a2,1767fc01,2e6d1ca6,f5e788d2,f89e2fd8,89a57924,9f5fda94,e0455b28,1cccc531,7118b175,edd6c93,c212e7c9,fe845f0b,cac5a592) +,S(7b5e5f5e,564606bb,a71b8f1a,7d410b1e,6482f508,879e1bd,38ecdc44,b7effee4,92a3f1b4,84ddc60b,4b005282,89984241,4f91b9bb,fd55eaba,37dddd0a,dcc1c6e) +,S(541fd344,c9d553fa,1e87c9cb,72150cae,a69a9a10,771ac96d,fb292be7,261912f5,80ef7a00,6ce5ac0e,975ecd69,601fd059,a9860e07,77f6f31f,365187b1,f6c9b392) +,S(2b2b3929,50b07da0,5c20b72e,4101e36a,bdfccb6a,2a7f36d5,b57f58dd,1403035c,ff6c1ba2,caee889c,14414086,456f096f,d065a7d,d2f9c7b0,9ed4eb71,3b4002a0) +,S(23acbca3,4754dffa,8cb3176f,d1435d6,4cba0deb,84e12ae7,adaafe88,497aa60c,5d95b3de,26f703a4,fe9efaf,cb273921,56a49687,a71433f6,9a2813ab,5fdb35d2) +,S(5fdfa393,6bf9c699,24417a2a,f36054d5,95640b6e,3ae30807,5ef51bb6,cd63fe34,97fdd994,bf74c959,2a5435fe,f1baea41,8a79c5fc,1243fedb,5fbb0466,4d599d04) +,S(177cf8ef,58aeefed,2832d53,417c7025,c6b56fb3,8122ccc5,2b33f79c,71c461fd,d8a12d8c,69da9b31,832cc10b,55b57a60,b900c19d,f8f38c92,f6bccfdb,98d3acf8) +,S(14f90282,e5a3121d,a59e919a,fcd146a1,9251cf5d,c0d805bb,bd013eef,4ab78bd3,74a504be,928ed13c,f29032e,5c3dcb3,a18a1df8,aad26b4c,a64ebabe,6afb4244) +,S(31099221,e6ceaf16,81b22b33,dd8ee3ef,1c2a95f7,2bed88e8,15333f69,f91867b3,772e45f0,930ebd2b,7f5b7ca0,640467a0,8ab5472b,f6bd347c,903cfecf,8f80176a) +,S(a6a0a416,d8eb22be,49036f4b,dfc79c6e,6cd167cb,38813269,70e199ad,c5d1b5de,54d036de,6b84f308,84faebee,4f944375,fed61a6e,7763bb40,a283ab52,3335af10) +,S(c7c5cb1d,ce484477,82e7da9b,55bb8482,4f715a80,d844294a,3c05dfd8,3dde77cb,bb66731,1bb0c2a4,e493e257,d289a42d,3630ee24,ba0f7f86,134a7c6a,72dbc3df) +,S(f1bdcb49,43267948,fe1c9b7b,51afcc79,7027e4fe,f98c2175,d7d1b8de,770328b,271f57bb,a9249cd7,dc510173,5a2168c6,ea97b341,b44cacc5,4083d115,6de8e728) +,S(2815f09a,8f0e2dfa,d21f50c4,60b8f69d,3aad54d8,aaa99226,86050582,b954d912,dec68871,752d862b,32ffdf2b,482ce1c0,6a659bcd,3a2931a6,29bda260,cb3cbf35) +,S(622619ba,8b74a0d0,5f8fa899,aaddd272,c9e6d43c,49bb6708,367155ec,4907d0c2,aab9b1ad,10201d50,7bea05bb,5b20453b,6474154d,ebe3ddc0,c86535ad,7c701954) +,S(a0390604,a40611cc,6e36c81d,30cc3e75,d162e695,1ae0515c,75417744,c093b997,60428c28,8d32d229,7417b6d9,b1003522,8190a83,66cae58,f7887037,9fb99641) +,S(422c7d1e,b0498cc4,dbba0135,ababc80e,5416f187,11f0dff3,80f1e1dc,23bedf0e,9c47d3b7,eb5713dd,cbb9ec8a,60d931c6,3382452,a4c0861a,847a354b,ba57d9f1) +,S(982844d4,7f572298,afd6734d,98064369,d81e4851,4b176059,6d3a1e85,6f043f5d,9b86f6a7,678cb5f9,a4304f1a,a8d3458d,fa85e65a,ffc79da3,faa1fc8e,a2b7ed2f) +,S(993385f,a76b9373,422e4411,b9e8a85d,3ac0e09a,f9598570,63d50a8,67b67ed2,3e7a9a3b,222a66d2,f55fce7f,e33effbb,bce8cfc2,8991d8aa,376a8ce2,4e9b8460) +,S(15b05ee3,179d1dfa,61bfb0d0,1903f93a,f7e04f98,cfd40be3,2ec094d,1bd5a4a1,ed1301a1,451cecad,30e8fadd,801c9db5,5acfd697,3ed36621,2f2e3032,adddd939) +,S(6062aed5,7d6312fc,433bf7f4,9c10772e,829e294f,e7ad07db,177c75cc,9fe5e52e,96aa4495,c6eb07da,9a5a0e19,8771dce5,23a5d7ff,de314562,3b704f44,c4ffcd24) +,S(ef45dd6c,1213ac0a,5df18426,9491cb3e,bb5312d3,fb55c7f2,8351c98a,1ba564e3,91541d32,43e032f9,450f3605,cab238f2,703a9eea,8e429824,7a6ef63a,45540e68) +,S(a1e32dcb,c3a13a46,166ebb73,7e09041c,3487120a,6ec46987,6befb2a9,94f4a69a,ba88b7b1,8cdb2088,b5998b34,461b8a5,d85a57c6,31aa10f8,6ff808e6,3186e5ed) +,S(817e6c2,6d4ae706,f43ddd7a,cfa4eeed,6498ea2b,86aa661,9a0b45f4,e22ea33d,8aeed38,bccea5e3,4923b959,53bc9629,d9348442,4f33b06b,b02c882,25e47bf6) +,S(e734f5a7,736014fe,2ac9137f,d025f914,7574d67b,3696596,9f89b5e1,aeebf88d,74fe8220,7c83d3ba,ec54f032,f11f9309,9be25f53,565f0d60,5f2ab406,5287c997) +,S(87b2d307,414c314f,184eef07,6e9809d8,ea19c002,390b5047,38eb7bbe,ba1ae7d1,37f5c369,f5dd54b6,87729036,b88dbf37,45f33da,8c2bc9b2,64213468,f1c56841) +,S(dda23ad9,6c51604e,602b8e6e,9f08a67f,981bfa98,93194369,269c56b7,7986b772,6de02623,5ef973da,13e2577a,bbcde720,aa8fbe12,23c5288c,5724bbc0,228074a2) +,S(8d56a723,6adfe6a1,46182431,da5ff846,aee78931,27564954,f14172f5,27048fb9,c7cd6bfb,fdc51a83,252d4e4a,2c978cd7,67fa3809,521678cf,7dc5e514,eaf0b418) +,S(9da30ccf,f147de11,de528d14,863a4fcb,a2ef228f,506aee98,eabee895,eb618def,a4ab41eb,a16b4733,34a818f4,b6bd3c43,de4a9392,c15c9e19,a8b4e961,7fd4bbe7) +,S(e3339c3a,b14145e5,40c08544,eaa631c4,7be6c09e,563ec93d,2a05f219,f4afdf2e,fd586d7f,3a668a0b,f888083a,9ea84f48,43598417,f55dfea9,790ee89a,c412fed7) +,S(a6e08d07,66274337,f3b139a8,d6fc3f61,4dde9ef7,2e03fc52,45f7dfcb,1c0ab41e,d9620b61,116af945,708a610,c78f0b52,8abd97c0,21ee34fa,10d289cb,f3c06d4b) +,S(f8ffa0d3,b463fc5d,44e6eaad,caecaa85,8515bc4,69fe76e1,4ecdb25d,e503a040,e80dd6f8,934fa405,fd4d74b1,1da0d09c,dd723df,daf46221,796cd7e2,4bb83f1c) +,S(22a212a4,3c00408c,b4b94e2a,45a6a999,917c0fc7,aaa565d,c6f982cc,64b0d0d4,663d8ed0,3128ada4,f421853d,8ffd8201,1ec8b997,4b0d827c,ed318551,ff9930de) +,S(8d33b62,f162963a,f6636f18,ef33a83c,e9a17fb6,b1fc58de,6d271d,472a9d82,cf0092e6,60311726,e0856ff7,1893555b,625b117d,4698e4f3,f31611eb,21a56f5e) +,S(3bbf59cc,5b4aa31d,dfa0ce94,1853ff69,9db29cc7,a0021cb2,11ba28d0,1dc61d3f,d54beb79,d1edb94c,d6bd5ae7,11a3ff22,9f2baa0b,efaa139a,e4724ae3,624d8318) +,S(4cc9c2ed,3a7266ca,faffb517,d3ad4aea,2d4d877,d9b08433,a4fca2a3,691aec68,70ac52d6,1094da70,5f714f60,854a5656,8c25cb13,1502171,7bd4085e,8b489756) +,S(a997cf82,50d7ec36,125189bf,eb6b8631,cec31fdc,f156d34b,186f29c6,5d0b30cb,ca73d95b,93b43983,b2c51518,b4e419f8,415f14fc,b6356287,cd65d49f,92929d5e) +,S(5fae92aa,7c43ac60,b4bb4f90,ae2ac462,a6f88681,9aeada99,4d0694a3,a6dc1722,6b7ebdc4,dbe15dd0,9c1e4587,c7f297c1,74d5c933,6bc91511,f31e0cae,2e51b280) +,S(cf541216,323a9591,13561470,2b187b35,fffaff7d,8cf1993a,5144c7d4,aa836308,9d955733,feaab81c,4b03fe4d,25fe36a2,5075357c,b6ebf8dc,1822cee9,7f585f80) +,S(9c2c8607,bad80760,efb4ba73,442a359a,c1cb9b45,f81e54be,28f3f6f4,4699773e,7848812f,f3101eed,137b4dd1,4f503a42,9d71c157,449767c6,a5850204,869a9817) +,S(2f3bca36,fe504b7e,93f70176,2e65dacd,250b3789,541076ac,86352481,c896f77e,5af55f5d,b2e84dfa,38bdd0eb,fde7ea68,33471d28,add88dd2,a7e7c63f,dfe513a) +,S(f2fa3afc,fe4e5da,385f26d8,1848f801,7401b06f,652121d6,9468d2ee,f640260f,54cea12a,b4ced3ee,2ca351df,4310e96a,d3ca0d80,c3a3c86b,267c4620,bd0f69a2) +,S(82559cc9,ead1465f,a910b781,cb2a50ed,9a2b6ff5,d8513182,425b7dfd,983afa50,db5dd99e,242287bb,c94cd149,6e4aff70,7232e2bc,1fa4c440,5cd9f22c,fc4d239d) +,S(954079af,1494e324,fb707e7c,e9f1fc2a,751e194e,4ee058a6,e55e26d8,34901f5,2f90eb0f,43bfff96,c3b0f3a1,bd48c00b,85d3650e,52d1f614,ed65ce70,4fa19e99) +,S(c913a980,b1aca09a,19654428,6edfed20,dce31676,1fbff05c,1c05fa70,7eced342,17d2864e,df39460f,99b5b51c,91752c57,10ca7af9,a6e10c4e,c2b3e9e1,7317d3c1) +,S(815b7dfd,3b97ad9f,cf6ce427,ffe4a91f,2b541e2a,11305b17,2fd7b63b,82272db0,f0b958eb,fbf32959,dbc407bd,5290ca66,6f28bcec,2fa69d1a,7108a2ea,19d58484) +,S(7f7c1689,e93b7c77,20ab5b74,572e87b5,d2a907bd,624fb6ff,d5f29f3f,c64795d5,691a2f46,430c53c,375829fb,46ed4030,b5bc4dd6,70646523,45fbadbe,e6f8a1f9) +,S(8911275c,106e5a48,1c3dc5be,b9b42e2,3be8cf2a,5a76198e,e6749b24,bd9c5e7,747cb0c2,16d899c0,da5a8ed8,f279a650,f4537e7d,ca51bf56,b3ca8c43,92b5e99d) +,S(24cc2552,c907e757,9e85bf7f,fc868ebe,53e44b97,102b31f2,38678bb7,ad8c244a,a152808f,7d615060,ba9e78ae,720c2fca,a67772b7,fd99ed6,ffd5fbe7,ed114567) +,S(b0fc5873,68795dc8,55e3e19d,9236244a,812d1920,afef4c9,7f1e6c79,25395f85,f8b46879,5a0e40ba,2029538a,fb7cef58,9bde7b3f,fcc010a4,4ac962b0,afb8d7e4) +,S(cd6f4558,d634fc66,6dce566d,f94397f,d3ab9178,affd3707,55852679,adc6565f,d34d7be0,ea40586e,4f9007d7,4aca55e9,edb4b31d,8ad4f344,1f611a9d,94161b8a) +,S(fc5e8a3b,ada62f0b,6453f445,7dd4aff3,993005d6,de7b94d7,19fd487e,b88fb7a4,46041321,f7fed84d,2266d4a4,d86d836f,12f12296,d62ed296,6a7d5507,d6717130) +,S(dc72a540,55c962ed,90e64916,bdfaf6ea,aaaacbe2,fc180a7b,7e7bda98,f45488d9,e3b46394,41a2063e,59c4cb06,1a0a7e5a,a171fe39,812922f8,c04df63f,41c8e588) +,S(7d135c33,88bd5896,47f4cc3d,67fc7809,a7a4c530,e96fb5c,7dabe3b4,32a4fd90,79dd3834,8a61b642,9eb7a837,4e9c2176,95cff14a,3596a18d,19f84360,8aa0922e) +,S(7a56712d,b72ac3a6,353dad9a,15cfc9d2,7d9ff67e,9a35936a,e38e1c01,5980980f,6eda856b,9b5d4019,d0efb2f4,9f1af933,8969872c,126b2682,f56a8b08,97a83696) +,S(d3495480,25c7f966,d59b40d9,6ccb9831,2948c992,fcbe2f6a,7a7feb6a,946125a9,b346f8bb,532da4de,96908618,b0f85a10,fe9a87a8,d612e4ac,53bdbaf,9dfdb3c) +,S(22175a8b,d0a51763,d1818054,60951698,14af196c,df8648f5,29d27a9a,825e60b3,756d5713,81b5ce71,e23c0190,a1062fd0,645eddd1,7dc84c9b,b1c7d810,c13db63d) +,S(f557e381,37a1c6e0,a19e4207,4a1dd59b,17c5137d,97a58fc2,55d18be1,bf63877f,6cf0bb41,577ea3bb,7c9945d5,db33a862,3c1cce5e,d6fc13b9,b0739ea9,9af10381) +,S(8ddbadb9,c6a78978,2540d3e1,9ada3ed0,5ef35f45,a38be470,7083dff,75d501cd,75b4c5f9,51f70fb8,a89fec5,d52ea0b1,dbfc5709,3c1ee5eb,ff2ab0bf,f5854644) +,S(53f0892,cac79f48,2194dd9f,fc076305,a8ecdd4,977ac278,92e2d454,965a2aee,b39f7a9c,ecdd4ed6,d0fb1608,3b86d1af,68aa85b8,c733617e,5e97ecda,269ef97e) +,S(2712110,8fe28f55,c746525d,e7cfd4c2,f3a11b8e,3c6329db,a57a7b32,5a7edb40,cf6732b3,74681ab7,3448bad0,ae54b953,ee5d7bb2,5a8658d,3b366a78,dae5fa69) +,S(e7627b26,ff0448bb,cb45a538,2ff8ec9f,9376127a,b8425213,46e899b4,41cb5660,79842f72,e02820b1,e6b6843f,3a0c23dd,c0941ac2,b6fd30a4,39397ede,c78bc40d) +,S(37c48874,f07ce0c6,cf5be181,9ba31bfd,9a19aac,97b27011,1de59fcf,559fcb57,34dcc405,6a6dfa3f,283e0dd1,8b1722e,bad0e367,c30d9f1a,d552f394,9ce19b22) +,S(316868fa,33cf5544,1e9b9bc0,9f74fa1f,8daa9058,3fb8b3cf,8d339971,311eddfc,89fa5c82,9d9f4687,f7cb6b8f,ae20d6a8,cf872ded,a7f9b6e0,6e168c1e,45db4e73) +,S(d34a83f3,7b7673b9,6c8695f1,81ce837f,ce2f15b8,72664d3b,1a045c7a,bceadd44,e4f2cefd,59198808,15692950,19b9120b,495a44d3,4862323f,808b11b3,a8698081) +,S(687a48cd,4142060a,171a1efd,c41dce8f,8127ab64,ebd7c22c,7803f077,19168799,c082e152,41f7db05,ae6c1e15,e4ccc340,f4a7c8c2,cfd8bfb1,6bcd04e7,e635726f) +,S(70d2cd79,1d2d1418,9cf67e48,519aecb4,d58be2af,164d0605,2132517e,87f444e5,73b4c12b,edda1a70,89ae9db8,f105059a,2a558475,f5cf4796,1042c470,c9e190a7) +,S(2a6f2786,a191130e,dba1307f,f1bb0f61,c3d7b8ad,c02286f6,44871cc,170dd2c1,28a0c85b,8ec93fcd,1b9a0617,780da654,e5448475,a02a6222,f7065132,5ad64b2a) +,S(3f482e12,8d5bfc4e,d2f359cd,b4244db7,ec7edf92,f3fc5dde,5367d125,dde8c772,d41be140,cc4b4217,cdfaed4e,b09ce5d4,d3e95b52,ed6689ed,3f6dfde7,3c581cd4) +,S(96673e27,fb0f8a46,8fcc53de,12876045,77786d93,5afbca99,35545363,6614a5d7,f6a4eee7,1c4249c6,ef850090,59c12f6a,44adb8a9,cefe7a8c,ff2ac0a0,da28884f) +,S(be7a886e,499a9c2b,c05e5f64,77bcbb4f,26772e58,4565897,408eb36a,e25a9c58,24457eb7,802810f4,de64516f,24718b06,d61b0adc,bcf0d279,d883b2bb,45363a40) +,S(123985af,a3253837,e51f933f,8f25591a,823b2442,88cf8ba5,a0247ec9,94eecee4,a952096,21f7a9a4,3867c6a1,987dd661,1d3cf996,2aebfadc,dee0a5b8,6df196b7) +,S(75887ee8,c28bd2f6,a96086d9,aef71b7b,5a5fce50,80c3963,787089ed,e39b0214,47386fd9,a9216193,3bb500d9,a1ee8207,dc3edbc,17d3ccc7,32d9c90b,8995eb48) +,S(4f7642fb,12376864,29104657,2a2fffe5,2322df39,7cc097e8,f7a57816,e6709fe2,4f2ff70f,2e99354a,60cc5b2b,c3ef33d3,7e3e9ee7,16766018,e3a0ba39,efe5f971) +,S(8117d4fd,551c9ae7,4c9fdac4,5d87bb66,9bc7dc35,4b08de03,7c4a1378,734653b,13633743,d1ee8fd7,8482e3a,3a9e39e9,75b0f6a7,efb227fa,84feb897,693c5c10) +,S(8afabdf9,acd49723,d73c0deb,1016ddce,571abaa1,a71ae3e9,a20bcecc,ade5782b,2b66e3fa,ee86dde2,23dcc7b6,10ea8ed2,dd42124a,247b7937,9e190098,2580c71e) +,S(c4819cb5,b5af7aa2,895b81c9,31dc6bd1,de4a1434,daaa4fbf,abfca6d9,28c9965c,ae4db5d5,e1a09a03,67df8c9f,fbd2ae07,9f79ff96,410a9a5c,17229fe,5575c22d) +,S(dae02e8f,5d106f77,c8a1e1f5,4366daee,d312da83,1f86dce2,3e846e30,737d49f7,6d666cf4,73d269bf,aa7c3eac,4e5a2868,57df3661,c949b5ea,7f9a7a0d,11206bb8) +,S(a8762d34,c6f8317f,cba5c64c,68e25d55,e5bf7e4,5caadb65,a5468d2e,f9d779f0,6accd443,bb181cd4,591f8fca,210f9996,86460bcc,89dc06a0,2edd7bf3,d4b75533) +,S(bf503c35,fc8a0c55,fdf4149e,96b2d218,d29e4b9,1f703e7a,9b0d4da5,4153d99,7e1c09ab,a1437e02,a2be3d4d,7a444753,e475acd6,e3a42056,94e68ea3,cb7d1847) +,S(7898067,48cc0ad5,ab3a3449,ac82a1c7,d51f2b96,791ee038,dfceae58,ea0c5cc0,66b59634,96eb4a69,b87aa0da,2905449f,ffd2ae3f,ba1555f6,5c9b8ec0,e94ad922) +,S(25833d28,addd8172,c2a323d7,cf498482,732a0be2,c10d1895,8d097cc0,ff4c9a19,74708306,d01258d9,bac99a69,58ce1117,f245d6f1,4a1f92d0,dd48ca9a,4c7b7da6) +,S(6800bb8a,9dffe170,9ceac95d,7d066461,88c2cb65,6c09cd2e,717ec674,87ce1be3,d5228e3a,1e0bce22,c2d85b44,e670e78e,ffb1ec69,6c01a722,2cd1e62a,dc4e63d4) +,S(3d7d5874,42e4816d,af2f0897,dbb06cea,f6c673da,445a5342,c61a8793,420d107b,422b212c,93ab83e5,d6323ad0,35a55321,b7441835,b83f180f,c3803ccb,46fa4ba4) +,S(3c44084f,aeee2803,34db27ea,63339db3,9e8359b5,c9cc9a85,7ea49740,32d063e,36493b7f,1a732a87,db4703bd,61a76825,4a82846f,31d8920f,2cba7ecc,1d744491) +,S(cefffb5e,d26cf721,a51bfb2d,460b91a,a0b40a81,52073da2,cb75050d,f7fe8d19,b4e40e1,1eac7572,efefac2f,a97e5cb2,a0d042c,3ae8c541,e51be4bc,f6d33f4e) +,S(63add0db,5f5099a3,2f274c38,780cc215,bfd58753,144bd464,e75b0da2,dde97938,bbed5231,fe6d5b4,9679a13c,c3c6c382,5c300fb8,42b5eafb,13355c41,120c6848) +,S(ba5d1f34,63130cfc,425cc6db,dfe08329,4d7aef4d,cb207e3f,d1cefebc,7c791920,70df29d7,8030a8ba,56514df4,b6ecbd2f,ebfaa1b3,df7b23ea,ed16458f,f2f18786) +,S(7d363dd1,c6dd28da,94a7f850,ee753327,8b735dbf,f43e9456,67fc26e7,af75d6e1,46026468,2bd00bad,a5be02aa,5034e762,fe50d02d,6cb8dcdc,5aafa21e,423267da) +,S(e2dc0164,c9060646,904206ff,37f912ce,2d50458a,3ca186ee,fdda8d53,4184070,de5267d1,354d12ad,8d9a5930,443dbef9,65947f2a,5efa206e,146e7b1e,df7f5a2d) +,S(2e53caa6,35f0ad1c,7bc4c2ee,1e29b39a,972edbd0,7d3c0feb,9ab0d945,45815ee5,1bb33d23,ad85b572,130e93d2,fe366e49,8371c49b,b47ceebe,de3c1286,3f443b23) +,S(5dbefdc4,9fabdf50,e6bc1464,13d59940,cb36551e,5a6607bb,13213ffe,b56eba1,893fd0a6,1797abe2,fceb4054,c4f540a4,ed644ed3,13a2200b,e1d532db,44d0374) +,S(5ff207e4,2b52b004,6ab8bede,6bd26f5,316ae52c,d148965d,8a21e8d9,63374a2b,1b778704,daa94eb7,a36ad0e7,22a6d56e,c0b43c7b,a739985a,538bcc22,b9181bb4) +,S(da260b,ff4bfb8c,a54261ed,c96493d3,ffa90273,a55538dc,c9b237ec,e775fb3c,c7c744c1,dbe1cd19,20edbe3,c13f7631,1378140d,9ee64c3e,ab072401,86c067dc) +,S(b1985ca2,e7103268,f18d1063,c59d8d78,2250f450,c467d7b2,f4e41c28,1714421,16357630,3970159a,99a34c0f,e114b95c,f115d9d7,dc9b09ad,7c81d769,aeee6898) +,S(bf98e773,fe93f15a,ced03ac8,368e4276,1cf3821b,461cd844,2426d2d,cd1f7d7c,f4fe02f5,f45a9cbb,b67ef626,f239bad6,e5108c28,d783d70f,6bd889b8,6331185a) +,S(5dd657a9,ff99f15b,56c5143e,86ba7bc4,b0f34957,71d91805,71a3d003,ff008fa0,8da0b780,f644b14d,2b661b9b,484225b9,86b13038,a8a9bdf6,6999144a,4f5c212e) +,S(53b42d75,bccf2203,7252ee9d,25830f3e,36e7ed8d,8e1b6d4c,b2371e14,fd4fdba9,7791453a,dda2ca19,a775d684,9ee60c18,ca495808,6f8b56e5,1bf2b216,9690cd73) +,S(a3f43f6d,eb178109,cf4aaeed,a0666bec,481a1894,c25a4fc7,f4a87e82,680d63b2,d0331e73,7dc25db7,35625621,85073240,3a69a474,d5f78e54,93486b5b,3d1c067a) +,S(b83bea86,b07b217d,ddac9cde,9b42b334,c994cd1f,92beaa87,57a7e7cd,2c71b1eb,b68f8fd,66b45aa0,dd568458,73eb7829,1e613569,58345fba,7dcef9ee,dab957ca) +,S(16ce1de,573b3654,a0c00212,e878811b,25832f36,373da91b,9d9d7c89,d06ff12,264031fc,7441fe5d,4ce8ebc9,232d1837,7fa810a0,a0e19ba7,5ab16ae5,e93d5763) +,S(18fdf98e,93a7e380,8762e819,2b6e634e,f255b2ee,51c65b58,1ab799ff,52409e15,2d71afd6,c6298868,52ea0a1,943dbcc8,ff844ba3,80b177e8,62f92852,97868dad) +,S(3d5f8af4,ff89de18,866f596b,91300a32,a7aedcb2,a9423f4f,e364cf26,e2f53e96,46e9bc8c,ddc56d4d,ba25a2f6,e77a6a70,2e712496,7591725f,1d240e7f,9836548) +,S(69dc1e7c,11516a15,9edfa4bb,1afe0ea3,5be5b7a4,7695df8e,728a8dac,e2997db2,71be8ddd,d4c51c1d,5c13704,3aee6129,9541e929,799f7b6f,da08aee4,52f4ce8f) +,S(4e8278ed,ce9b340,1ddb1c3c,6b208539,164e1ad0,3adc082a,8d9dd5a0,9c63f737,13e6a5ea,7b2e8ebe,babd812f,2579b8bf,56b476ce,dd23c418,9be7b85a,940c5d79) +,S(91157569,7aed20df,771c1f4e,78b73dea,c89b2781,9b8a5ae7,5e2dc12,e6e7d148,e7114d60,218eb1bd,73074957,5b96fd10,50fa2d09,f37c0fe6,2887042,24ca1a28) +,S(3a37e743,bd2fe2f1,3f667abc,b6c03077,fd82722b,859d7bcc,ebeaf1bb,a6087d93,4192a6b7,eef51034,64040fb2,6b8d9928,21e321b8,cd611b4c,8d3e0186,646f5dad) +,S(d45b5787,9e4732ad,ad0996d5,879980a1,fc8dda5c,b628435e,96c3b44b,faf98f09,e4d4f5ac,1e4b039e,731143d7,60e2ef35,dc243097,d2e2382d,b86dc82d,eba0554a) +,S(ae5ff450,aa607a9b,bf4549d8,4d96adbc,6041cb0d,719793f9,2ec53b96,14522a00,2f061b20,e9bca3af,358e8d14,a04f1d82,97d1e1dd,a406d60a,d15727d0,66b2b8fa) +,S(befd3684,32785d19,7709ec42,e3b6407c,7a539b55,d97c8fe7,afd4f96f,d2050e17,65691153,b2efb4af,ebd2dae1,a50fd3aa,b648c7af,f5804d99,5270cc22,c02e151f) +,S(d13626c,bc00cd,36c776c7,8bdb17c8,18a2bc14,9612e0fc,7ab7888b,eab48382,ea4c3fc9,fe2238f7,1023ab83,fe0e09a1,dc167c0e,6aa05933,8f177cbd,241bdd45) +,S(9730fd42,fa9ffdc,414f90dd,ac790110,9619c01b,f43bfcab,e65a341e,2434435e,de61024,6152fb04,c997fd62,961209f9,44badeb3,6ea7774e,30e8c8a0,8bb0b496) +,S(a27e09ee,9dd4e34c,6a92f4be,aa1b8c0b,2a60b33e,99fa981d,afaac623,9f616d15,33e6d8f7,bcaaa24,b6008e44,377b4892,5f88e884,5fe73807,8cd4f405,a2747f14) +,S(d2dc7884,31e5a497,3905876d,bd6ceac7,8246c9d0,73d68872,f54685eb,5970763c,85f96d40,e31ecc47,dc07fea4,4856068d,15d2a999,735aeb3a,4959e4f9,9ecf5fc8) +,S(38fe7a6c,c401daba,981875a0,f0c2f528,30ce31d8,816a1d3d,47a3d96a,664a02f7,e9893a1a,87034596,9d95e644,313d9b65,5896a931,81d36f6c,7e390102,3cb28c74) +,S(f2d38ff,14100172,d117dff6,1522c61c,3a590eb7,ee9fca77,dc264e60,32291d78,94eb4046,ab31eda3,7593e705,792fdfee,2e3df8f3,655befa9,ef0ef392,4b02dab) +,S(9e23c290,94b6b8e7,4e112b11,69c5c775,4b690d0e,141b74f8,2988bd84,78d42021,e2528717,28fc8d9a,283bdfa3,a011d28a,f531f392,b5da6da7,1834a29f,203e747f) +,S(3054117c,33c15a,504156e0,97e9a0f7,d76be8a9,c1c88fba,e1d9d2c5,4e1c9185,998844e2,b73e9468,1b0b09d7,4ca48dc2,f29c6df5,f3c38f7f,b6846178,d4ccae2e) +,S(65d1e830,3421444b,7d5f8600,2c6de12c,16f15a88,504c6876,b9e94cfd,a206810a,71c9cca1,6e066545,b11e2c29,edbac8f4,8533ec41,1e331e15,a2bed53f,1b1878db) +,S(124b78b8,948c4374,7c5b32de,50cbb055,ebf9fe7c,56437573,40723180,131ec0dd,c0fefa74,970829d9,4c1314b3,64a8516e,3a3c7fb8,e1d49f06,b1b9c19f,be18ddd6) +,S(f6d81a5c,395ab698,28e5f1f7,84edc6f6,a55137b1,411baa28,615abdfc,36c18567,3a759acd,4b758dbe,79e22f4b,26774b88,40121768,f655664f,c3f9bbbc,91f564cd) +,S(e76bd19b,fe13dc17,ddd14619,da6b12c9,f2819514,6acef71a,9e7bc32a,7abbea8a,68cee27f,152177e3,afa7d47,903801cb,b20ba02a,c48fefd6,e23fc102,e6456bc7) +,S(7356c0d,ff8f26eb,7df215c5,cf923c4e,237fd7ad,cbe58f7f,d5c745be,6451a830,16a0d86f,ebcf42d2,e89e9a1a,803838d3,1dd7debc,527d49e4,a7db799c,e1eeee6) +,S(b8d00a56,43fdc57b,dd949193,c5df30d,8ecf5b4d,8b3a13e2,64ba3ef7,c8bfacc9,f05acf53,9343641c,3feac336,28e9b08b,9a4e3c49,94c029aa,470fde03,d5d8cf8a) +,S(f555e29d,4dd3e0eb,d03f3866,596be43c,677d1ac4,1a1a3a8,1936ca6c,89618880,171d88d1,9abf05a6,981eddea,8f030e53,117a2e2a,97c2f352,255038fe,32ecf95a) +,S(172e6167,6e7755f3,c6a59c40,97a8a870,cdc09d73,2064d24c,3db8ada,7ca50ec1,7c1e58e0,38f322d3,e147b3db,e9b8f311,135d688a,98458da9,f6f8a6d5,4d4e2a96) +,S(f8f5fee7,d4e8eb51,92cb7ad3,9ee26cfb,44724b7b,f9c74fcd,61f95e3a,f33fabc5,607fd05e,361bfd66,519b5e11,d00d22af,8b0ce85c,11b16cd8,eaba71e1,2ebe6bbf) +,S(6fc770f3,f6169350,bb8b247d,16088031,4348ef73,cee49e5,c0f56a19,d2d66491,47708f10,80e755f1,2b1b0d9b,3439312b,dca07d85,fe94fda8,414dbdc6,ed9353de) +,S(2b8c0b49,94d3f78,79776d8f,bd2980c8,7840df15,82427cc4,f07ac806,eb7f7e3,3a335552,ccb38312,92a71376,9c7994e4,19a7919d,b776ce6c,db2ff092,92e4d798) +,S(e473c99b,dffad22b,72b6fcb0,d741179e,afb78aa0,de4b5d42,dd19d7d7,72ab1a60,2d0f795c,61ed1ac8,b5691d5e,9d52b19a,42c368fb,9d0787fa,8ef3b275,2a3d9d26) +,S(f389dc2d,b76a47af,f9d7a380,ab49274b,1a40c4f7,970bfa63,729da698,b4afdc4e,b15c2100,b63f7f5f,911a6474,25866d79,5a57dd97,74c21cd1,4907dec0,f5f3afab) +,S(df6e3625,8fdefe31,dffa19ff,2416f8b4,9fbc09c5,e86569e4,4b7330fa,56cb6e1c,4b5fedbe,835f0b8f,ae20f627,c8e74f41,a5443c1,a764c466,65f673f9,f62dfc7b) +,S(27e40da1,a5d7cabc,ce586e33,a4ace757,da972cf6,17c3781f,3fb0e0c4,e6f0a70e,ffc4b339,9cc0b701,36d871ea,a7c3a6ab,fa9dc92,72625fb5,b8bde8d8,be55904d) +,S(71b6f20e,e558ac12,829362ae,53900a59,ae29cc70,77dd1001,d9d7eae,36b95618,e765adc,1125219b,316beb88,4c0434eb,a6f62499,b8b2d217,c209c7cd,622d0597) +,S(535d5fc6,1eef1a92,50ceaef8,e09e1797,8debd360,8b03f72c,bfe265a2,633332e2,f8453dc2,4ad1ef7b,819d4329,a4752757,26c98e55,65440cc5,b5d509d8,61c98a38) +,S(d1e2222a,26817cd3,a537f2fb,7437ce06,ce9fa651,9d3c1967,71aac21b,97de68bd,a131cb69,cbd27e62,cb65ab48,a7f3035f,a78ef40c,6c42e94e,da326ccd,2b452849) +,S(5aba9590,2b5062c1,59b9639e,f08912b8,e7eacda9,759a4e98,b0e21d96,c2597b07,896a74fe,e2596e46,1e93f4ca,178646cb,4bc5454,227a2dce,1bb5d532,e558b334) +,S(9f07bed8,4449bf9a,815a546e,ffcbd0af,f22c9016,188d15ad,7c353e2e,5cf84343,6fa14d01,ba16dd07,15f3e68,d57738f7,1cb56d95,61eb84cb,ad63bbd2,d9ba439b) +,S(80a1920b,14723439,cc2090b7,189f96e0,20e6eba5,5f8964ad,2f0be013,b4925515,fdb63791,6d074376,8e32f983,f2ff1754,43136323,50b98674,2ccb9ae2,7997a020) +,S(dbb37c16,202dfd9e,914f2922,e8930789,a70d4de0,9fe7eb25,7d9a2b83,aec2b4c2,f6bcb8a,2c7bfa20,491d3fff,bd36e82d,91a7228,9e4fb6f8,9e167803,a17b7932) +,S(f03035f2,f0ad31ac,59e64a6c,f46e9ee2,a2243ee7,de5ccb0d,cb30083,97551b4c,1a1aacb9,798651c1,2bdc6ce7,4146e259,4263474e,d7b9d42d,78026331,60748722) +,S(1886fa45,e7447e89,b0873362,605beafc,4e05965e,53fabe41,41e1c42,4fb234d5,eb5374d,a4a198cd,d9027311,6b4331ed,f0f6a7a2,fc52aa44,8a9274b9,ee3d7743) +,S(46a262a2,5b76baf8,ae0ba3f4,ed8f86fe,e4854272,cbd0ed41,313c4e0a,357471b4,c08ee494,66d7dc12,a8e08880,732574e6,f6fedbf2,71d6dc37,eec3c324,33d8070e) +,S(d521c6c4,a0db2668,5a36b61c,b73d3504,ea7b7488,e3d75410,494e89e4,ab404d37,41f334e7,6a28cb9e,25e6efd4,fe3eee2d,17480189,b921d726,aa027b3f,75f94bfa) +,S(8f44a4e3,c18d714f,62054e54,6e9ca86e,818fcf39,fdde40c8,3044ddbe,be3b951f,210ec152,f8c90d7b,8486d1f9,c5c49a48,68249795,bf7d0171,34d9573a,d5b22aaf) +,S(d5a74098,eb20aaf7,b664fb8d,63e08b0,430733f1,466552db,417ec648,36a31dd7,7eedeaca,97f1c85a,98496159,eb024564,1c8ef0dc,21c31ff8,9d06012a,3387647e) +,S(d2a63a99,d6ab9e57,a2a6d39d,3738c3bc,94505332,2a34d3d2,4cabd1ce,5111bb08,e50f6c3e,796ac830,e276fac9,ab6738b4,722fc87,880f2e93,7417198d,9c6c1323) +,S(a1b826f2,1f7abe38,c622b93a,7510114d,dffe4cb6,d3fe0627,dcc0465c,bc82ad9a,c9cec051,a253ab24,a8507b07,d24ee4a,c1d5a5c7,33f0c3d5,611e8a9a,e4aa9667) +,S(40719ba6,89926b5b,ca99a4,161a1bc,d999d40,2311fc5b,e2f5260a,c3c10208,9edb353a,73e9fdad,96ca6b77,b467dd9,c7d6d2c8,e041d8f2,19448ea4,c603bcd0) +,S(c0ee8dda,80fed10,721e7cd8,9dbd237,216f4e84,bb8f7138,11f8ca16,1e3a0977,6a786e53,2a0f49cf,eabf0338,1d64de56,1a1973c9,36d6a5ca,4aaf4cba,b8fbe1e7) +,S(9c75860,ecdeaf1b,c598a530,48a22158,8099afbe,20cb08c1,3afbb133,b2681809,d7019eb3,5fb61aee,56a1afaf,2675a028,b8735dcc,b3f5d93b,c3e29672,9203321b) +,S(e39df640,6dbf2584,fecea5bf,aae78b5d,bca93ef0,9054c754,d8b235c2,c5463657,33ab2fce,3a2e3e7d,e2ab230b,e69bcb7a,4d71c87e,a1ff5d34,eb8b78f2,d5c61a55) +,S(22480e,4a7cadd0,d17a418a,78074f80,c4731ce5,d9f1268b,1ca50204,1ff8282a,993591da,11ea4445,8ccf8bc,2cd55fae,69e96a77,89d006dd,b85a22ae,85316200) +,S(c613fa66,231d38b3,359c3b94,132a2337,e2a8c608,3c88b41e,58434c19,48a6a1ca,8087377b,c3d6ca30,8c932dc6,ff82430f,3fce21c0,1a8b8b6,c28bab78,d3ddab43) +,S(c0a94837,c2fb86ad,ca791fb,bb0838c1,3bb0c981,e23c4ff7,94dfa5fa,c663e5,1f81050e,d21fcd5a,471657fe,abe6fccf,a391f1e1,9a88c143,4644bfb5,e1f69f9e) +,S(87ab257a,cc2296af,d921bebc,8e52fab1,c9c21f08,ae09faab,18858a06,1e408ccf,d5dd88e7,89d2f2d4,3773854f,ca980411,3dd69475,a56864d,3c869205,d682027c) +,S(10d14c28,cf44c5d8,fbf5caf6,b307f6f,ee203968,eea1be3e,b3697515,2edf45b6,46926a1e,dd4f79ad,74fd506e,4443375,23ec76fa,e09d216d,3ef3ed4c,73b635fa) +,S(2eb78fea,63035a3d,db64149b,612832b0,c9ab7880,539c67e9,d722e252,f7e23166,4f72ef76,d3dd59c0,a4e1be46,6ca5a3ce,fd84d207,f7d671b,240fd41b,20e72af3) +,S(14d8ab11,402af341,dc5cbb6e,1116b858,14decf11,e6761b09,31b449b0,20b6f56d,91bf8c4d,cc717657,990e0e3b,3558a01f,ebbe534e,897d1204,8a7d978c,3a1d735d) +,S(cebc042f,2e7bd361,934da5e6,dd2dc8a,9e73537f,5d5e3e46,3a88bcc3,ff6d5552,baa841c8,5e0a7287,b1f16c89,8ef03f22,3097e92c,44952c32,45f2fab1,dcd988c5) +,S(4f28e546,ef539c7e,8f33191b,897b7245,8f48a01d,79f65b8e,a8f672f7,d0ab027b,b1c1db0d,55be796d,2b415259,89088a7,d86c41f8,cd8ccdff,2bda49f2,407123d5) +,S(c4d31178,b73cf9ab,b0e1d554,a2cf93db,ed9a7b9e,8f49c9c5,4d63c815,6e111505,f5e4528,7089cd96,3118e279,bfc6661c,1e77ab67,b81a71bb,4ec14fe0,ef0c13f) +,S(8e260505,bf045c43,f3fd972e,d4189725,a4db0774,52f94eb9,51e42eb5,6131f0f0,4afee681,c6069893,5ce21991,208457b0,11548d97,9a33a0be,cf3c840f,77c4b4d8) +,S(982818ce,69b4c6f7,631daac,868af6a6,79fa6631,8c9da2c4,bac994ba,f9c95d81,f5b13c91,e7593e5b,69c85957,6398b186,8c503b6c,25179270,7e602f52,f30ca9c9) +,S(75c2f2b3,53720779,8737488d,16a5ca6e,dade382b,78f2b2b3,226fd5ed,6ac6c855,95aec19f,b97734cb,8426e530,afda15e4,c3c3dedb,2aaa24f,7ca73b4b,af475960) +,S(606ed5f1,8e4dc1e5,3b6f5ae3,896433c2,a904cb84,1ea021fb,84537f6a,9dd45ed,3165cf75,26f277f5,b9bf22e7,36291513,10158d63,b97b7c88,d49d88d2,d63dde9d) +,S(a33e07b,c2934f5e,f02ae143,6b3ef5ae,d2d633f4,2b40e35b,d365fe2e,b8c72d51,e93cfd7d,f2e98817,9eb9c348,73530504,bc5cd8e5,d8393f0e,844073ee,df6d6511) +,S(5ee1d077,735a4a18,533b36d1,eb484f14,98b220eb,cd41746,b0947403,d6b4644e,7d4e1233,46a6ba1d,8a862514,4d4bc5be,72e23d,f25287c7,3512817d,e632f8ef) +,S(7485b837,2bb28a8f,d496f6a0,33b92ba5,96202661,8adef933,d6aadc56,55765b0b,a58defb8,deb4445d,80016c9f,5c04c2f6,e06986c8,cc95da94,3105d8fb,d0fe84ed) +,S(3a321f94,2268584c,cac5d8ce,5d6011b1,22169e73,d9093b2c,e3e0bdf9,ad680d21,99fb13c0,ecb6c544,1347a4fb,842a7269,1492219,f9bb7c25,1916f837,7d4e2cc0) +,S(c115a2e8,265c6005,10bf7108,ee30bee1,77893d5b,ab0a8cc1,754810c3,3f112585,e2f0a636,5836a24c,7a5c6997,45022e8d,e0b88afd,37737c84,d1ae437d,eaf0b3d3) +,S(d8895b97,cd390ca2,cf8e6093,c125541,1602fd98,97074a8e,aa11bd3f,5b0f3c1e,af8c594b,bd2308e0,12a632b3,1d05a25e,23247f75,6d7a22f6,fcf48cde,28056ad) +,S(4ad1fd48,e77fe497,b4a15e7e,869377bb,163d760e,105e46a9,a5477d69,fa944eb5,a96cce4f,e2f5f590,17af2359,1dcbda3,b640271e,95290d59,1fdcbd8d,ecf39703) +,S(62ffcf4b,7ce6c5cb,76766893,bd0a6f2a,e33ef821,d953c001,51c4be3e,67f2cd8b,d6b1d025,152db954,968ea1bb,dd2a89db,16103f55,47cdd042,9b7380f7,c4c985f8) +,S(e71343c3,cec5e49f,60fea970,6d256a4d,ba499e86,6f9ab33d,6045a1be,cac40a,ee1fe3df,df226027,78228bba,91afd126,a96fc10b,f5d2cad1,26091119,3a92b426) +,S(31766ef2,f3531ead,2c7bbaa3,279e81e0,b040182,ab78065f,d193061,2792035b,87b93ca8,91151ee9,775669bd,df2e5bf7,9f728d52,efabf584,352ba4db,8cd6f6d7) +,S(1e8764f1,982a97d8,b65a0a60,53a2fb5d,39f1221e,dd4f532,b007b2c8,c52d39f,8ed84e0a,de68b789,5ecf8c07,80ba0b26,53faeb49,3d23a453,cc23987a,b51f3a18) +,S(e249cd91,4e35f97c,92a07f4d,6f9961bc,d7f6efe5,ccdfd44,cb3bb698,9939fe43,9ee2fb47,4abdac66,5bb0178f,d8ff3bef,6381a90d,bfab05e4,a9e5566c,cc362ffd) +,S(b9a28764,d21db971,f7cb0c1e,87c9db64,ee6a1acc,485a02e4,5d5ffafe,ea1012b9,1b55a989,43ff4fb,25db6aa1,12d5c459,b1ee0fa3,aea913cc,54878682,f625e882) +,S(5d042803,9f8c37b4,dc92a9ba,43bf7213,971488df,be699901,31820bda,c0b6ff03,1ffd5348,88796c6c,a631c3a1,4773f89a,ea6d5914,bcdf27c,38949147,cab8ac1d) +,S(6d817b42,52986e2e,8ecb908e,99011265,df0cff59,61a82b2c,baf0c61e,c8b22326,55cac99a,d6a70b96,5559af1f,c5b67469,5d653662,bce7594e,22916fa,7c4b826c) +,S(9b069431,297f0d35,91451039,df8a382c,1eba93c2,f62f4e98,90e54559,39916ae8,70bf9138,a04b9f14,2841a2e6,bdc3600f,1b22c81c,ba27f308,19a763b6,e64fef71) +,S(dbf5e41e,d83110a0,5dce4bbb,bee05f0b,f9700ef8,273b4bbd,57099bc9,460050f6,e3e8f5e1,697b05b1,23632b89,28c3b34a,6cf1e6f,327b4252,c3009046,c8406404) +,S(c8ef12ee,22aaefbe,9ca024bf,ba8fd744,d7c5d489,663cde66,a3ff1dee,8174ef33,db64c2c,db21415,fc552968,fbef01ed,131db2f0,1ec8372d,1b9da98f,4792e8e5) +,S(3d086c8f,af84b66d,bb9212f1,512663b1,793d6893,23f45af,9bdd17ba,fed8d7ce,2d6a47fa,9e1b6c20,a2cf30dd,a99547a,b9ab9c13,5ef86ebc,280ac62d,2ce7847c) +,S(e173d58,714db8bc,cfff3ab8,8cf1be0b,547e03f9,db60c97b,ba5a6735,cbf4bf4a,44b8f991,6764f393,68b36b56,9033e304,7fe90662,70758fb6,85cc3f6d,e31b2fc) +,S(31ef8faa,90826125,66e739cf,299de928,68c6027,b882978e,f72d014c,4aa4f379,9fb9e021,fafac237,8d21caf,f1262d7f,bd9b8333,eaab0fe8,8a3499b3,d153a2e5) +,S(5e112e52,2997b67e,146b998d,781bc528,7e2ad47c,b2c5863d,eccb0873,fa088b3b,19cf3f06,d3c1fdeb,8147e074,a42fe178,c0b14135,2dda5274,50a7d5ce,58d3d441) +,S(9ba2cddb,c1a5153f,89e9144,e862acfe,c624095b,8cf8b7a5,b15edd6e,c7b70eae,f032469b,9527911a,92dcff6b,5847fbb8,9f4ce42e,f20b40d4,80b3a58c,72fc805b) +,S(9ff7e46a,4e2c6e9a,d5843f4c,c5e112c6,557babe,723203de,d75be7eb,179e814,ec890ac0,2ece651a,6614bab2,1e4944a7,d248c886,bebb33c3,36c28df0,69be91ff) +,S(2a13752a,1aea6e21,d25ea21d,b644ab0b,fb84b130,8d3f2083,be26098f,fc4978f1,18f4936e,65ab66db,11bf53e5,7eb7d114,4820fd01,ed827f96,652514fc,d8ce910f) +,S(a0647c4f,2b4f271,97f3fbc3,bd81bc7f,f72d964c,1bcc131e,caf9bda6,57b356d7,5e023102,9a8eafe8,9466181a,80440196,e850390f,d42dfbc2,1d3fbf6d,6373a56c) +,S(6abaff96,aeaca928,ba9a0503,dcff7a51,420feffc,33b1ad53,b1a7bd57,8c641ede,ab59c03f,7ad47f73,df424882,dc3ac2bc,dc2ae6ed,3eaae48e,b807b010,98dc0de2) +,S(442abb18,54161ba2,47fd366e,52d40d56,65293573,c339aa2b,28dc67c6,70f4ee99,c3f44b44,d13ee3ed,4ffe5188,c5134d60,a28806b0,687b5652,99924655,342a5898) +,S(9f54f23b,45f632c1,f05245f6,c5d1c433,9e18671f,da494eb4,3bd22be7,b1610096,25c9e532,1a5563f1,f47a1e4c,99d6def8,541601ac,8420de96,190157ed,aa17445) +,S(50296c0c,185abbc4,1c86f578,8dad10f2,7f76074e,24e931db,53944b48,6ddee613,81a02b32,b1edd539,37ee1c78,ab630f2b,45336e16,cfc560f0,adeb464,fb71b9f8) +,S(39c2d099,e2892b2b,1b6abb1,a198305c,ed59d94,f7022cd6,d521b510,9a8fc219,8900f6e6,3fe1a7c7,27728b92,aea4d70c,1316570f,edba940c,e626e94e,f03dddff) +,S(3581e30b,17067e44,664201ba,d7a6ada3,e0648516,260b760f,b406dc48,11c9d0f4,c8bac129,83e49250,bc478ee5,fcfc0660,37d68f9f,fda1acc3,6861743e,d7a794b5) +,S(72b67dfe,d341824b,9fa09057,b8362d1,38287eac,7292610,1169e41f,19dce477,be527b0e,52ce07a6,99065bbd,ebd360fb,72c6dc77,88030aa9,45fbbabe,7f038524) +,S(805af91,4a973e36,43712cd4,4a1da4a8,3d1237e5,9c991387,17175aec,4a8667c4,f6a7beea,205810ff,5d1f0e8f,5818854a,bb730c7a,1ddf02c0,968b1b05,92ed8a15) +,S(44794289,4b297a87,e3cdeead,5cb2dc42,9fdeeed5,b8038189,331874ac,88e67536,d67efdbe,8d7ab8e8,1e25c340,77687b94,d22d8ec,b89d7f5d,46ca212f,abcc1b5) +,S(b73347c9,baa967a7,5e5c8ac3,14f3c6cf,275cc893,72b26bee,731693cb,48d36df4,307f8fa1,98f1ba57,7ba330d5,816cb8de,d9ec3f13,6bec0586,53c64675,753f1542) +,S(ec6d499a,efd540e9,357f100,4a136049,d1f7df5a,d99c44c4,6e3ed416,9e40acb6,21e8082c,df4fa2a8,38327e80,aac15ee4,40549109,aaf6ea01,ccbfb95d,3f7a47c4) +,S(7607b7ff,8bd8369a,67d22545,c40a1588,aa2e50c1,b5be6115,cbb8794e,2085f283,6c4a9aa2,1dd2ad4f,7d6c4f02,23885803,ac3b06fa,6c0772ec,bfb610b6,a1d25ea5) +,S(dec4b7ae,42e8a25,2c414458,d4e0d7fa,4bf4d0,c9432754,13d3b770,8fb53839,bc54d902,6d035b64,35796475,67805bdf,af6cdda4,d0177206,384c4ca9,8edb5898) +,S(a7be1017,82bf48e8,37c2e0ec,821e37b3,eab03607,36561152,a95a06a7,fbb7ae2b,dfd27057,dfaae0a9,b9523a9e,dc28a2bc,3631e84d,5fdf8c3d,e1e65055,805fe0bb) +,S(cb398b20,29e55994,741b87cb,592e9099,926229a,aea60bd6,30eaa528,726a04a7,263e89b5,85475a8a,50723568,d3328fdf,56c8fa8a,f0f796fe,7b4d2fc5,9aafe2fc) +,S(438a6d60,c289dab2,e8933153,5c2e09b7,a677cfcc,a605ea72,8815bdd2,615c852c,109ed19a,51e01f3b,a9dbea30,f652676b,b3a8afd3,5ab5178c,ae557793,13025f) +,S(4db8d4d,882fe513,e5738be2,347a05e9,2c97816c,b39339b,adeef99,7b682e50,88280370,d13551a8,a9803a28,c56bac47,70feb07f,56a1a0eb,d132262a,f1ea574f) +,S(ae2ad953,bf13c4c5,c3fd5ba3,389323fc,260de722,e36bdbae,6db77b2,1c0df210,a5866bb1,7580958,df07c171,80606be1,25b3ee73,9c3bae92,8fa35e9d,8efc7364) +,S(85b3809a,3f772b20,dc526b9c,19de8cd4,9c2d9814,df4a9b60,1aadd016,64c66c9d,984a8061,2ce95364,b9819440,551ab1b6,4028f61d,3028b725,74dfbeb6,8c174cd8) +,S(7e2ddaec,e443396a,7c7eede7,ad96c2b,63faaef1,66109949,e7431b06,309259e4,3aeb7f92,14fd37f2,aeec1921,e64e7a8f,e6a4c704,dfbbaf62,779d0eb3,3b1e81cd) +,S(4565a74,6cd1d26e,962bebb4,447985ed,7b1622f3,faade84,1291d694,17c3ea84,7215d7b9,6362fcd2,320c0c29,e0b304d0,ab174103,bfd372ef,e6e4534c,64ff3708) +,S(aa8c5a11,712aa04d,a870bad1,606c9549,bbf676d3,1ea5b260,27bd1055,ed56f996,11ec28a5,a7435436,3d302f23,24eba092,68028664,f0ebd323,cb7bc587,7d92aac5) +,S(d9d5c0d4,b5a3305c,9f057dc9,8ecf7482,f6d825e4,69a641f2,caff9180,b7096e0d,d2b0eae9,cdf57651,bd296ad2,f4403e77,d643db66,fadd7a84,27a150f3,6d547ec) +,S(2ab2e7ea,1e1bf61a,8bedaa4f,e8fe3a7a,db66c25,ed1b7ebc,536efc7f,8de22777,28806bd1,fc7dca1b,a0cdc177,908e0588,605f8c1e,e76cbc07,ea05b6ad,80c0e5) +,S(2da97d42,a9d064d7,38bc7fc2,f2db39a9,588d57f9,8094903d,cdaf5054,238c1568,fff93946,e789b902,8694ff95,a68a7fb2,981ca0d5,d2b6de3a,b3112381,b8360f1a) +,S(470fd28f,31418f2d,70367e4e,961da5cd,af8d0255,5bf6bcf5,e7db8967,6dbb174c,59a49444,2a250264,3faf843a,cd242640,e3622df9,da6bb1cc,6c956b7e,5a26078b) +,S(e41bbdd4,6b78fad7,ee62c33,9664fbc7,e884f88e,dc184e12,715e8368,160a7ef5,40252593,7979b92c,f72bfa7d,b3f378f0,cb4de758,a6348c7b,2b1d73d,57ac9faf) +,S(9761799a,7e155a4d,e6aefab,963b23fb,1f17d8a9,cc5f8c64,6d4dd638,2359c553,493bb00,3ab38aab,cb4d4491,b6b9e8ec,ef068c9b,933fbb32,6e0e1c75,ca44bf1c) +,S(d59fe2e0,5fcdcc2f,dcc22cb,b9220051,2c936bc8,2205f5df,75267a5d,b45b1245,68af556f,949df3fb,d8299f05,f5e85874,57d109bb,4d395634,89d3ac77,3d4b7b2e) +,S(f8bf168b,8a03f3c4,8e7568ab,ef613bf9,3f515f71,93a24b62,827455a6,c6bdf142,434f350e,8eeba6f6,d8f07137,a33199b8,88907744,eb547384,dcd96aad,5f9f3911) +,S(65298ff,636b442c,8c45e748,c3cd2d1b,94770ff3,3bde1d63,21135bc0,89ed81d9,d0aca445,cf460f5f,47090202,2c84fe1d,ac0a81e0,b7458e4c,9b21dc34,8c223ceb) +,S(d1ac0d0e,25dd02d6,fea02b6c,c98f4b17,38046416,93258208,f04a81d3,450aeaa5,be491f07,1833efce,56197dd4,d3471eba,2a23491d,f09a87f9,8a4ff14,257d1dda) +,S(be876d37,fc1605e9,ea0923c4,e53497a3,8d51190b,dfc3dbbb,3191a483,949cae1a,8499ad31,ca5acd99,4a98caa9,2a91a321,5fd1f1f6,cd70c463,afb91673,ab6b3a72) +,S(7c440cd,aff0d8da,6fb5e2c8,fe27a301,c2906a63,7d9b1bf2,db848f13,175de738,7dd6cf71,cb013a8e,9494cca6,b418fb,e99e9c80,3ff34d35,e586fe25,8ffc4fef) +,S(25086ee5,f0037c83,e38abbaa,e0e3356f,c49020d6,f9006edb,235937a0,4d7074fb,35c21eff,8cb888db,d3271a5c,4dc1db52,2072e58d,974af68b,4d6cecd5,d13e582c) +,S(b1a7584b,6f43a593,363d6e62,edade636,55ffc711,48e6c9b4,2915d0d5,ebf4dbe9,f418f23a,9dde8808,59816098,ea06d2e4,dbad3385,737b7bff,a1b339e,1b556718) +,S(87e1c0c6,aece59e9,1118829d,ba8e0271,db30409f,c08dd790,4296b91,43fb7aae,4694c5cc,176cf309,e4bd4935,b88e2fb0,e7e1b63c,28c5bab5,d3356733,184ef152) +,S(19f43d3f,4bf0f2b1,9a157f3,3f71c5a1,20e2135,3187b508,e568dc5d,8131a2ea,3ff130d9,835e0eab,2744cdb2,5607fa63,edcf9648,d910e25f,b885ba9f,b340860) +,S(a7f9239c,5e8e371d,7d175c8b,120816be,2e543d89,a22c3f7c,5478ae1a,14f8f6b8,75711a87,561fc767,93510d5,47abe6f1,678d0cd7,335e7bbf,b87abbc2,cc3089e4) +,S(9f3598e8,f80cee53,969a79a6,d3b655c0,66283a8e,f2c5d7b7,8ce89e67,5d06446d,d9cbf50d,c2aedfd4,51fcd93a,46245bc0,772e9f9d,fe5a25f6,3af027b2,ea1edf79) +,S(cc00a72a,66dfc8a9,e7a4edd6,699764ca,c15140e7,216daa59,cadf0edf,d1e3267f,91b10836,c8ebd031,2f72cf2c,cf26c89e,1489c100,c72a04cc,71c0d08,45c27d94) +,S(2dc7758d,b176a48f,f3117aa9,671f7b6b,f0b2128a,4bc60fc3,f907eb1f,d20ff347,afc82704,39787ab6,bec0d4f0,7b7f2896,43073cfb,65e9d3ce,db8ff7b,791f2f59) +,S(2502f7f5,8dba7c37,bc4637ab,8c77c047,700dea3f,5b760ec7,9b68121,9cee008e,f6fea3d6,4e776f5c,cd293dd9,4109d6f0,1e55c039,c30438eb,6e626489,c92f078b) +,S(70d39d43,d7f2092,53967479,de620ed2,bcf963de,6ceae3b1,a80fd275,1801382,fef8bea6,45807be0,e1c5c3e2,4d391d8,bf0a6b33,564749d1,4fcf4ef,a8aa7133) +,S(a09962fe,9a934004,bc31f92f,526ff444,da7889e1,79453a55,b0fee769,34c69c2,dd717079,8cf19b8,1f55fdcf,86cd3755,f708256e,694fdaf5,f929c967,eff687b5) +,S(355a2555,4590dcf2,84ca548f,9ec9f40b,22482773,cf122a40,25ed416b,9d29c692,549ed0bf,db861bb7,4684ebef,7d70ac56,3703997e,c59b1f86,bb4b5dfa,574a2f64) +,S(4c145d2c,a165a5a8,b66f7fdf,c16bcd5c,c22304f2,f0ec3145,9b9fb0fc,797c9b9a,7cc14054,948caa4f,be04b54f,1b60a51d,cc482fc8,c94825f7,8de4f4a9,a63f8d5e) +,S(b5ac199b,fa591300,6d635fc6,86d87cb2,52c5c67a,6b897a09,bee578f4,9c57f8f3,41e164ae,d3d967da,94f0cd06,91cb3ec0,79c5712c,279b3a8a,d75affda,2879b234) +,S(ad619913,f00f620,38321c3,59931a9e,fd26941a,aa02a812,8d9f3bf4,8818185,d7b5a033,9e4b8ab2,bf66a597,45c0b496,b5825886,9084d306,660670f3,a9de912) +,S(f8314cdf,d7659ce,e8377abe,f4c80b00,9c99c1b2,f2bee37d,a726c6d2,a1deea90,db5a45c9,a7ea22cb,dba3a784,131ee81c,2a1d9edf,d9ccb9f9,6fc93d35,a332eab7) +,S(1fe1bfca,5df9c482,68e88661,89e238e3,7915957b,aa1e0c3e,af317d12,c2f84650,dbe03060,745396b6,fb22d6cf,a6b27329,3b3ed08b,a24ddb38,8942199a,765d7414) +,S(c414da43,814bcc43,31269d58,1c0a8c14,9e304f5c,13614a89,7f414725,9ed39070,ca194f90,dac3f722,6090b94a,3b94db7c,5c68931c,7461619d,8b912692,4fd90a4c) +,S(81a098c3,d1ebf427,69f621b8,3eced558,9dc0faaf,24206f97,480e40d1,25faba3,fffac91a,3b729698,b0b26f8a,e6391b1c,8f8327f4,7978b011,d7d1cebb,6b0ad8bc) +,S(f99441dd,e4332003,b6421463,b4bf6595,172121d3,f000763b,a40cccdf,be2cf439,231fa7c3,fffcee74,bd111f18,3689062e,1b6b366b,2fe14440,2061de8e,4688b3b9) +,S(2f930e6d,e3586768,792e565c,211e1abf,99e05fe8,79c01083,3e6e5121,7abdcc60,2d51a776,209a3da9,ca4dda22,7beea48,a93a90db,b51f0721,2864f36,a56424e7) +,S(9f8e96d5,99fd07bb,e9e0010f,90802d25,4b30e359,bf0fdcaa,d6e782da,62c6d25e,baeaf150,de04c7ae,d8d34278,aba6eeb4,9b3f213b,fd56585d,41890632,d6b64e02) +,S(57f186f6,fa5f4aee,e3e8b44a,d775301b,66d7fedc,4ab8c827,cb138386,64727f10,5a65c0c4,a69b16e0,1c32a95e,77c8f99d,53bc15af,5c168457,19bc8220,d7baf849) +,S(d344361d,dd0b764c,be16f46f,5efe166c,10a88bfe,bf532a8f,a1fe138a,78e0e1ac,dc1afcbb,a84b8524,a5d985ac,5506f15f,d0b92f85,875c2c4a,4144a93e,e455792) +,S(444163a7,58095900,e5c8fda4,88ecae95,24fe54ae,2592ae53,7e6db41e,8019344f,bae54b91,e69ddcb2,c1bf22e0,bdd721b7,a9ca51b,dad93b28,59e09509,77c26488) +,S(5ce2e1d6,46f10fe7,e4196414,37fa2c16,48029fd5,5340d2e5,f32d467,e0c4e222,6e95f538,cadb1b56,8313429f,35fb925d,d9ba571d,bc6f3970,ff4fd276,4228e82b) +,S(8b7226b0,8525a07a,84ee858b,58c418d3,1d4acdaf,9b081761,56b83a8b,fde6d773,684e6dc,37a2ba2d,89c0b01a,b4e1fcc2,1734eed8,2f7b1509,6724acab,5e276006) +,S(6aa5e306,36046384,ac8e3da3,f2f00713,8acaa0b,b0d12ee2,1e69018a,4d0554a3,2144dece,31a7453d,3a07e290,cef1b694,f393e5d3,f6cb07b7,a8c991b5,2a788029) +,S(8537990b,dd59836d,da16ccee,3871a232,3bd841f,6128f845,b0369857,66c7e0e2,beda6acb,946a6e08,43ec2890,c2d11ee2,404cadec,afb3f1c0,37cfb9fb,7b733fb) +,S(85a8cf21,1de57c,9c0ba88d,2f9a773,61041619,639c9de3,e2f2bc71,cb9e66d6,80d1d1cc,3c757338,f5a6aecd,815cd5aa,1d772aeb,5c1efa05,d5b64886,97ff6de7) +,S(d4f18d05,cb183c54,7594ea93,9330c174,37870e7d,48a613ab,4a920e38,18068267,32fc3b50,394bfc8f,a2a3f912,b35ebb69,d388c87b,198c3619,b04b6b3c,36b6190a) +,S(123e8bc5,65ceba86,d4c1726d,5e7e2a32,ac6f628e,940aa97f,c96ff72c,ec79e637,e54b4332,975774e0,748fb58f,3ddc5a14,8c3eb1cd,824bab83,edc76c28,e991d2c5) +,S(ac26cf03,c5a95e3,9a975746,a26bde6,8eddd6b1,6c83a3c5,81fa0a79,e93d0cdb,73ebeeed,b96d879b,882ae503,2f400142,5c8ed97f,98daa225,346a5b7e,9abc4832) +,S(54f2cc5a,a4d81daf,6600e921,441f5aa1,5bb51a42,7479e123,b9561d0c,8c71299e,3ff4e7f0,83f85039,d238a740,b7fd16a1,e313cbb5,b0c6fe5d,ad99f221,da4aa27e) +,S(8bd785,b73cca1c,6c405ca9,1ed4833b,428b7ddc,1a61c8d9,b0d1dea8,ef133586,fc5b65e2,5c3fde0f,3239ab96,625a9751,27a30cbe,f98e1ee,735c1f71,c86cf292) +,S(bd4218be,af5f92dd,f96a54fa,fe873cf2,171c2e30,a13c866e,e830bb2f,abb17d5c,86097c6f,91024f4f,8900853b,d17dbede,e2674e36,9f3fc69f,a2578eab,174e783f) +,S(a4006630,1b63e757,fce2f5d2,a7444e5a,1f2d7509,b7f59476,6951f38c,1755b497,87aef8b3,eb160df9,4b46a56a,337b6400,c724658c,a49c1162,c418e900,29efde08) +,S(5c5af5f5,65b2870d,6fd08f95,b4146379,15cda056,e18ef682,4cbbbcf8,adca740a,c7c6de6c,e679f0dc,84e28027,86ea726b,8eb0ad04,af4b9a5e,de516f11,583607cc) +,S(b5c3629,b86e9235,478aa7e2,d2e5b539,b70765b7,79ace9ec,ae76a659,80f0ebd3,86a8a06,84fef80,7a081bf0,3f08c078,7ad04420,76f5e1d4,521cffec,8b2dc96d) +,S(1784e06a,cd25fa66,72d1fc08,9219cdb4,54f5c711,4237bfe4,a2143eb3,20a0bedc,11feb0a7,d8d43ebd,5bfde5fd,21fcaa5e,7f091da6,3acf4b91,956172b3,5d3af378) +,S(39266c28,48f58af4,47e5ce4f,61cb3ba6,9c3bfdad,7e5742fb,ba4ca3f4,f175a291,7be4b872,9d1e2fa8,fee16e5,bfcdf4ef,2cff2872,e9c7fea2,c1997d6c,5d7f1efe) +,S(d6fbeb8c,72214cee,58b33bbf,2eb04924,f96e9b63,d104aa92,fbb09c8f,c2e4b1a7,cd9bbb10,a800d777,9d4cda4,561a2b8,759b4dde,45dfa2c,319e4e59,39938c8) +,S(42ee0a83,85464cbf,cd4a9ac2,73001bb8,592f2a74,b28ab7c,2eb7055e,2a471b76,d22c6ec9,d5499b4f,26947233,a5589aeb,14c94376,9a6166c2,af9d323b,e1adea4f) +,S(8cd2a043,4de9b238,f4dbc3b7,e56ffbea,4f025e2d,6c73a68a,4aa62bb4,9e9057f2,abfe69a9,986ae1db,52a807c7,c08a1116,a2dc7aa2,ec3b649d,7326bafa,ca74d21e) +,S(14c35089,62dcb50,d01750a9,441eda38,1a95abe3,72c501bf,a99f953a,5c94da3b,bc57dbf6,bba79503,f33be20f,96a54fda,fcd7be9,cb064410,3db11e3e,2034a3ae) +,S(2cddb646,76717e44,86fbe0a7,f7d6d853,7c3fff9,465e31e6,8da22abd,b3eedee6,136346f0,cf5fd102,932036c,3605179d,1429a706,71d95524,a14869a3,d1cae8f4) +,S(d806ee3,b5702d23,50c3f179,a00c3701,9c055103,318594c5,8f10b100,1b705aeb,79201749,21e69cac,a0ad5902,42e39a04,c3af8cc4,c665587c,cc0c89b8,3744b9b2) +,S(534f24,715e9b8f,f5f76a4f,a617839f,6fe2f175,3cbc3d80,331d12e,98f6ec30,e26ebaf6,4affe9d7,1ba2cd55,421c33ef,2e4a3fb1,c59a72b5,93ececec,65a40e1c) +,S(f33af0ef,4e23c8ae,7f3de5c5,22e8bd9a,6e527c8a,23242c8,4ae6677e,ec90b8f5,8510bee6,bacb5633,45f38075,8d85dd0f,493d179c,b9250d25,fe88134a,6055aefe) +,S(3cad4725,12a745f6,7e36fb92,1a2926d6,ae294278,8004386b,272d8520,f5a9aa61,d12ccf97,27da84fd,317116e4,9d45d741,776c8278,4b2c9f1a,e3773e1f,57b8934a) +,S(4b7fcc39,5f50944d,5cf3b3f6,2b1bbc3e,3aca20e6,d259e931,d3398d08,cb6fcdf1,99acfb05,a106a389,b7ad644c,cd275396,d76b046e,9992e573,dcead5c6,c7da96ff) +,S(9b5c0e8b,22a62110,bca2770b,778f0a2d,6d67e908,c57f806d,7470f5c6,abbb27f6,da52c77f,ea3056fa,dae674e6,daff8b21,100d007d,8bdefb12,fd56efe8,13c15a02) +,S(ee7b7f5c,e79eac13,d9b500ed,ee0b65d8,e7c93203,aaad71a6,9a935e31,20722361,e77ccd78,bf6380e0,5e5e8de2,20448a00,cabe7d6c,6b7ac318,56c09e2a,9a390778) +,S(b4774237,d36a59f0,e39a133,756bebf7,4df43365,2a4505c8,b0b84833,dd5b3a1d,5a5a03a9,e3463ce2,fa8bbfc9,afde9c25,763f4874,3cf0b2ca,7dc42c3f,9bf3accb) +,S(5827142,c69944cb,a066a985,79acdc02,83e1df82,8935ba82,5aa55047,5a52271e,c05c5805,6bcb6cce,ed5e8c8a,beac78b9,69c3b482,7ef5b402,c94fe1fa,f7fc81a7) +,S(ba06eb6c,a54fe697,9be9e9c0,f8c77be5,ada7bd7f,43894d1d,1705cc18,9c9b0ed,176be0,b5d3db28,7f235e2f,a9531fba,65f5ff8d,55b784dc,bf7271bf,864e3d5) +,S(ed84c2b6,11c1208f,2f059d37,a3d2ddc9,c3a0196c,9b9dee3a,5f2cbb0d,9383625b,6dff970e,b08bb4c5,4dd6ad6e,df25bbb4,621a5ea9,3869de76,2524dd2c,af1c6f6b) +,S(158b136,86fbdcb6,ad8ea001,9005405,b5cfc0d8,f614592b,d9e76b1d,8cdd568a,8c576136,634af4e7,9034b450,1bae33e0,9b5712f8,642cbeb,2b7c8910,cb28fab2) +,S(687d52da,10df8013,7232821a,990adf74,c54711de,110027f0,68464c9d,162c2410,dad3819f,8071b3cd,dd84fde,550d24e6,31785e1c,e137e115,8b5cc687,8cd09f10) +,S(32e8617d,de77c33c,a1d317db,d350298,50dc7fb7,148913cf,413e04b,384dc81c,9cb2fdd5,15231e83,21a3feef,804d62e9,2b8b9c0f,dfb73dd9,c3323017,b29f2ff7) +,S(a53a659f,7cc90421,21d96a90,3801753c,ea43b363,405af6,16d50b4e,fff054df,96734742,ecb3c201,742f8f64,df22569c,92212928,ca0d5453,d706f905,33c345cf) +,S(8a9e4990,b9b1a2b1,32ca9507,16170713,bcbf5719,2dca9d71,7fc9c4fd,a3993fe5,9542de81,f66098dc,c0bb0f89,44ea56bb,bb7e86f,9c63222c,80620c7d,2fac20d) +,S(5966c5b0,f92c5906,b9bda0a,7b3f10f8,e4c29796,f953db1d,35976175,dcb431d4,539665b9,90bc3810,4b7938f3,47ac94dd,7b9228cf,7270284,a825a202,ac62d135) +,S(2170d9c7,4ca5e85,305d159e,697fd1d,d32d6f6c,a2806992,f082ce00,9139c34f,b5cbf529,66f71e55,8015c90b,ea2b95fb,4a0fed8d,ef1f9af4,518789e7,39076c64) +,S(86e9b03c,2497519d,615f83f9,d0f9bf9b,101b75cc,50059e19,4d7b58a2,9b6fdf76,215d042d,7976ea35,a3dd586c,f5b286ba,a30e013,966fbb45,99845111,db8b56ed) +,S(2cc7d91,ba630172,ae56cf60,9a5d3c05,e27c2e68,7d607c85,ffcbf6c9,a467028a,9404f869,32385290,dff3f8fa,1a085661,5855aa6d,e9742d8f,9e2777f9,472ab5c5) +,S(84a89b0b,304ed760,c3a3d972,5a65764a,11d59ebc,25249f69,1d3b8711,10d3cc73,b7200408,fb1ab866,53b61321,10b6bc53,c8a0805e,568f8a0a,80a65678,c54c5829) +,S(4e9c88e,d10be9ea,a34bae15,8ba3093b,42ad9cb7,356f34dd,33eada3b,1937b4a7,b92050dc,95423a8c,759222ea,c09593c1,342c2dde,5fe382d5,6838df0a,877dbd9b) +,S(fe2883e6,6db454d5,31f2aaec,96f4f3f2,868ef393,d09c7685,a65d476,c6c97a99,1ac28015,1bc7c0a1,cc4be80,c6eff3a2,b8ae70b1,180c6a15,7c89dd3e,3e78568d) +,S(c74df902,ba66c205,e49f25c5,62d1eb18,f4f4f697,3cf49135,16000924,80f3f68f,17f7bbc9,59dd7e6d,9043ad38,7c0097b,403c8d1f,e676b8db,d7f2c63,1fa1ecd9) +,S(e7e7a72a,41f95b51,2ea42d1c,76da24bf,67059e,c27d5313,55c30e60,69a72c16,a20c2f51,6e9ba9b1,fd3a8473,8309ace7,da6006bf,bc42d4ed,657da6eb,6efedb8c) +,S(5a93859e,dc4ee632,9d36536e,1bf1008b,603d6a8,859ac6c3,a098748b,d6e18bce,489326a0,1e05c331,d97db6cb,68f098c4,6712d7d2,994e6c8d,be892138,e2106220) +,S(6161b293,71353343,a46d0917,4f6467ea,25a0f77f,fe614133,7fd3bf77,71062de8,57c439d9,a1682d4f,773c8260,6ee65e88,473544ae,64194ab2,3fafc2dd,7612b385) +,S(c35b16b5,a3808dd9,553c7644,400d6fe8,ca48c8ae,49c78018,4a71eff6,b94ce4ee,6c3baede,4925766f,3a7c59e6,d6c1c966,c3348b1f,5883498e,9956f3e6,6d8fe13f) +,S(fbdae49,32baf904,1d295378,2d227dce,4e2af60a,86796a69,86b777ce,bd2cd134,9ed9b5fb,df42e755,a9cd761a,cbb92877,6c66d299,35dc526c,f6950ba3,d63d0c95) +,S(6c5bdede,17ce2007,a3a1c18f,af8a846a,ce67b751,3d8bd602,23610ae4,b01b720b,6492873c,26a22bc6,39d4614a,202cbb2f,2a08b78a,753592f4,10c855d8,12f8d39b) +,S(eba4e62a,bf52b379,9305bfc0,eecc63c0,5221a0b8,b554432c,15e460d4,21dddeb1,e378e6c8,d6ddc7a6,72d83c3c,9d863c53,32b1cdc8,21ed458c,b817c49b,6dbdc519) +,S(5a79ee4a,1aab7803,23ced132,f9c67d5a,c740900e,cf71a0b0,ddb1d6c9,794cd90e,9f608713,47b3a231,548909fc,812624ef,26eb26fa,98630512,2b1466f2,665176cd) +,S(78b702ed,6d816c15,eb31dc27,619d5bf0,6ad646b2,e39750f0,73c31d03,e50d9385,9f1cc224,91befaa4,fbe9721f,86bebcb0,11024a08,4380e46d,bf11ce99,f157fd24) +,S(494e82e4,1c24936e,c291f69e,791979ae,3e2a6696,c8f68601,b57942a8,fe6b98eb,59f3af2f,c720847c,19fceea6,e3d2a918,ff7f564b,2e3bd7a4,beda6415,65bf5da2) +,S(28b3ff40,467a8c68,69fdc61c,33f002f9,73705468,4fc707ab,c0b495e9,a5c0b401,46a44995,b2c8f0ca,a32d8e33,b8e38465,4cfbaf1d,addc4d1b,852b2a04,58f84e34) +,S(4e4cf4f4,38a40e8a,aea162d9,dac13531,f5730d96,59c436fe,d8acd06a,c4c46be,4fb4bf3f,bc394c7b,57f81a59,2ea14c30,1e9ca990,5f48ee7a,5db08ea5,eb6dfd7f) +,S(e2ace7b1,3a9e3e22,a9b8ee66,c56e80f1,9370cda9,eb3ffb6,2d20805c,7f4c34be,1c8fcde1,2a653492,6428319a,981e1602,44aa823e,a82831b4,d0eafd9a,2159318e) +,S(e090ff27,e42469c9,91dab9a8,dc9a3a41,d46b7482,a59ba9b,cf4de93b,c95c7e78,d070752,c5679b45,4e1b617e,8315a48,1cd9d24e,eb53a671,3b4160ac,64e6f824) +,S(705c8790,7b976b8d,c8ccd3aa,897b2ed9,ea091c37,e285c37b,aa321c89,15ce089e,edccb405,5ae9f933,973950f7,eb79657f,e94fe286,27f6cb2e,784d667c,21ad4d3c) +,S(4aefb3df,663a28f0,d531e390,339a56a0,4da1c64d,4692c086,de232740,6d386d57,167af97b,43a36a18,1dfde22e,633547e0,eaac2f16,84e8753e,1ba1741c,2a18fe3f) +,S(ea909685,ee8c283d,1d7dfc4d,6ec8910b,b8d821d3,3997f24c,db5f5ee3,bb7bd72b,685b64,d3e02ee2,be2045ba,c3bb428,636258db,33177da3,17f6de0c,f8c805f8) +,S(5987cd59,ecccc129,b3498331,f20cbfef,f377cacb,dea76ce,2e221aac,d3aace8c,3427cdb4,f7367d60,44ba21b8,adfd5863,bae2981b,340c9bff,d0d7e93b,ee4d6140) +,S(e23845ea,e6ed3d33,14fd6f6e,f6d6e9f5,92f921c9,f448eb93,edb49869,97837eb2,89eb22d6,455cc139,e42c6263,b65233c5,4b1a3b45,34ec3d7e,58b788f2,6b11b131) +,S(cac7dbd9,7dcd353f,fbf60696,d325bf14,2e3920ce,26570b59,ff9aa65a,a6993199,6e81a4e,cd60a26c,90f890fd,6de2d159,50bb70e8,92eed375,25a48f3,31307620) +,S(9dab063,3a5952fe,f168d6c0,3ebb226d,de3e591b,4ad0c9dc,96b247ae,49a317de,846d87d2,7662b958,b3422b3c,a3410ffd,1ae549d0,c6757bf4,f96d2d77,168cc83c) +,S(bce277d9,ed439b09,f255cee8,af5363a1,12ec2d5e,b111196d,be30fb21,43f501e4,63f472d5,2649843c,42e8f900,5adfa50,d6a938ef,8f4f04d8,897a68d8,8c213328) +,S(df9f8700,2a6baec7,8b79cded,bb501dfd,54f376f4,5756501e,f03a6c7e,ac5f1d7a,2a1c5c92,789fa6e2,84105f4c,74b0a108,27ea2f05,5560bec0,5d0000be,b9b6c4d5) +,S(6211dcc9,307c40ac,3c7be1c7,5553511c,15d3224e,3b305c5a,39653d83,f134dbb8,545c00d9,f02b8833,5fe4851a,88cbde99,f7f02d05,ac674f5a,6559ac9b,d03febb1) +,S(d739aa30,8d9022fc,45735eed,3ff92f38,545f6c9b,b70994fc,b5f41f78,772c9378,d3c3fbb,9077dd53,d023838a,5c35b728,af4a90c0,1f16739d,12870e1b,15e1e6ac) +,S(9d85e55e,8ed84471,b6822c68,3268c35b,fa314b72,470e51c1,a7ac9f25,f8bceb6,8b01f444,e84436ee,ae159a32,7026d279,5c4116b3,b2e78f90,99f1035,1511ac88) +,S(25d39bff,22c40a94,b194c38f,be9d001d,4a632407,237fb091,163e463d,7c5c70f,33381905,11368982,445ad7f6,608be022,209466c7,98b9abe4,f4fca781,2c0c398e) +,S(67553ed3,f14c28d5,2abc36c9,3f15d0c4,7f6fe1dd,628b652f,36b29225,ef8ff51c,da5d42d5,9d41893d,10ed28d,569c0cbe,1cc077e3,36bb5c21,e3712bbb,9c480383) +,S(ea3e80f8,c800b52c,a6dcbd2d,399ec5db,65057477,8852a73d,68af22d6,f1abbefb,5cd8f55d,b5330919,377b48d0,8ac1bce0,dfb8c3ea,2b97a5bf,547b7beb,ea64a4d7) +,S(7cf11aaf,638b1fe7,3b8c5753,48bcc01a,41c61ee8,f2eb3279,c2ad21b7,f6f60780,579d9a90,3a8a77a5,6bef3ce0,53ffb3c3,cf969f9a,39ea5bad,b1fa075b,e918f048) +,S(ed377aa8,42897f6d,1092caa7,42c29285,2349bd7c,a0e0cbce,d3cda58e,ffaf5e17,44d1e8bb,6491dfea,cde53662,5e5d7b52,1ca11a47,1eeda260,647f6f0,f0c5f917) +,S(fcafcd82,dfc87415,6e0db5ab,2fa2b56f,dd488032,d22ddc1a,b7a0ec8,1f1c4083,42f88e6a,cf851a7e,ca3fc28d,f771cce2,bef0d7ce,3d26da45,a2d9c307,e9e7e040) +,S(4d372865,7fde43e1,68744112,26b34713,9c1ca4ac,c2905858,de50def8,5515339c,5dc438eb,7091eecd,a4868c48,a7933b71,7ba99d8d,5e8a946d,ca9605a4,7421df39) +,S(aea6fc55,47faaa10,a898f21a,f63249ac,a0625f78,ea819629,8bca035d,7639e470,4d20c80f,173980d2,8e6bf433,bd1dacc3,1882e283,35fa9993,ef808464,a5568d42) +,S(f0ce04bd,bfa81a58,e157a49a,11695baf,7233470e,baa7ae76,3a07f0b7,f71cfce,f9e4d701,baa6f197,d9912b57,d9df016a,b789e60e,d731afeb,f2e5f920,b4eef9f6) +,S(cc476e63,130a950b,b8284c8f,fe74a059,8d9d44d4,c0372a9d,bbabca17,517523f6,d2cd50d2,e2cae10c,df744ff6,61a6c96b,64e17368,5f81027a,c937a292,3ad7476e) +,S(90e0477e,8dacfda2,7a563448,65947a05,d0afe9ea,60634473,143508fc,6abfc73a,d117be49,166bb010,afb0b82,a46a4204,c18ffa42,e3c89764,3eaae0f3,303dcd9b) +,S(522a6781,951f6ec7,76b6cf9f,cd20287d,6977764c,517d4ebc,7209d55,5714b5d4,a109c149,6318d481,4cb22199,3567e5f4,5147b64f,c1f9216b,922d653,7637031) +,S(b0a4c701,725326e5,611ea140,325b0536,b22406bc,c1e7eef2,1f874ff4,e02ec2a5,df44faa2,8a60eb90,3974649d,54cf340e,293fbd09,66b7b7d8,884e4c8d,dc1ec875) +,S(9e874924,90f8d4ca,2ada28a3,2bccfdaa,51ead138,3421d7d3,482af7f6,6df47c51,a58a577d,d03a719d,1bbb64,6ec3051b,44535da0,5e7e04d9,fca42716,2e335fd7) +,S(650a307,7b8007ed,f0441dfb,b7103d3c,d5146ecb,b949f9d9,c8c99e2f,25df7324,aa05b394,8c909957,ed1bd7e2,720286d7,56c7e413,8aa202be,b08bc446,2fdf86e8) +,S(f891ea99,2a3ef255,6feafa4d,7dd3f7eb,1f1401c2,b75d65d2,6ab81372,bab6f932,f7002bf5,821837f5,8df109f7,2ba5eea5,6c767a4e,198a7594,21467d64,df5e0bd3) +,S(d35e82bd,44fe54b,5d2c0543,91260c04,a5ce8d47,32e83ccc,2f3035e5,56bf2626,b002495,99705173,e0a45f97,196b9e41,1a7f5d1e,33f1b39,100b511c,e51f6953) +,S(7dd56d5,1f139070,a382af7a,2db135bf,854c8e98,2a325b41,ed869de4,349323bc,a23a473a,7f263bf4,944ab5bc,2d82e20e,8e9256fd,b11dbc17,bc0e6bfa,a8325f5e) +,S(afed2eb3,c5a95b4a,e88ee73d,b57594c4,7013cf13,a48431b0,f7930d5c,27f5c3f2,26b49096,da666097,3403eabe,342ab065,78c8ec6f,bc3ac7d7,2b3c95dd,54735dbd) +,S(13826776,74f36fe9,ca81cea,ac65c2b5,51e9fad3,af246f,4cdc65cb,cec534c5,a78e8139,760a94e8,3b3f5ff2,a65fbc7b,6b2b55fc,978b8399,df2d7947,18b496f1) +,S(99200c12,6fed5ec,1fc849f7,e9769a7b,aae3178,bd6b59ef,2563ed6c,5342b80f,7a7f1713,38a84536,e73f358f,91eb80b1,6ce8ef27,ea55795d,16aa7f05,577fc13f) +,S(159febb0,27e04f1c,321b852a,3cca550,28aac30a,8bc27caa,73a069e4,df7029cb,6bc7e080,8834b880,c590d249,241b709,e7280a05,7cbc1897,9b8cc9b3,cc21a821) +,S(2add9be1,a3acdd9f,efebdc0d,a4272ca9,311567e4,61db8eb7,3519c1c,6473bbc4,357ae640,a88c55e0,d3559faf,b0775d78,2373537c,c25e595f,f21ed1ff,b36b5925) +,S(8e2d4265,1742837b,b077fcd1,488e73e,5dccd6ba,6401c6c1,8d36fe9c,c428b664,ee9a5b1e,a04ab8d9,6430ef39,7756f62f,a1dcf35f,fff314a1,c3eb1dc8,d9a1e5e7) +,S(79dd7d76,5b4d7db0,537a69d9,b94210e3,8e7a11f8,cb9cdd8c,6aed6a15,748a3ac9,868c4b6,26dc49fd,de693201,3b89cf13,e1dfa1eb,56fb4de8,9e5467dd,86e449d9) +,S(552c2ba9,96a13b57,32c3b2fe,d4e9579d,365e03d9,2bcb231d,f14d1d1c,288a963,118e11e8,646a0335,6834379c,bc93c1d1,3ad80145,dee0a51c,49b10e17,f6952f79) +,S(fcfde18,a53b5a68,9d33bbf7,79d0b699,2faee8ec,243e72c0,7ca09185,d997e581,6709b56f,43013d47,23f15969,ee01b0b9,ff0d9d95,5e2b98eb,7e78e1ad,49cf3d80) +,S(e9e9d7a7,4ad279c5,691367dc,9c4b7bda,b27451b6,a8e4ed47,afae1883,96d8d82c,292bca82,e6d1c88e,8869f33a,7a6df2ec,ad812dca,4c46eab4,5c56c3b9,15f79497) +,S(514054e1,3e7ceee9,3a19dce9,96256b5b,5876a55c,6cab3c48,74b15547,4a58f285,f9ea80de,80403f34,2866dc40,cb0a9aa,4b38b98c,c4c38e3b,37f4da03,fdf7f5e7) +,S(ac0364,eeb9e7b9,b9589051,635de6c9,447b327e,8c820272,f04a4750,6cc5f290,ccde3ebf,13b5a291,a73b0c8b,9a69414,4b217661,7b0a7735,3a6e92eb,4af21b7e) +,S(cf558594,4a73a11a,ef500dc9,60cde799,ffb4983d,ae76826a,a027fd77,811058ba,369ed987,eac1683c,4e8874c6,40049a33,867fa0a,520e5204,df328d89,f197bfaf) +,S(ee216b85,62eaf12c,9189055e,32cc55c8,2ba5e3e0,237de083,a6e77878,63c56291,2a8bad1d,a697832c,856f6adb,e1cc5058,77e543c3,429b090a,1d3cf0,d2df6248) +,S(89903a70,55dfcb5d,175acd28,f7161862,c9fe22dc,ab752d88,3f52801f,92ab1892,e89c4f9b,7954c2b8,cd3b4868,ae171331,871a2693,9355d88b,8d37d4f6,b90c143f) +,S(f9830f50,66b1b44a,89231a81,1192a284,9ac94ec4,13f5223d,51d1e75c,a7727884,18ac8170,58795d51,cb9a5c2c,c249bcfb,ff3fe3b9,1506b721,763c8fcd,7e2ae44c) +,S(326be8c8,55c9f742,19228eae,f7d79c48,b02c2e04,3bc28e9f,275d6754,31afa8e0,293647f8,76b00450,b223e715,5faefac5,990322bd,eef964c7,185acec7,7c105d06) +,S(6117b67e,bbd6b120,906da047,88ad7dde,3549bc5f,c4f80e04,9b216b00,d441dc9,7ebe5576,17dabcd9,f41aa34e,1443e12e,715c9a7,ccfa04f7,ec6a9a25,74c1e540) +,S(1fa858e8,aed841c0,902db240,aa0e4c80,f26927dd,94e0e404,7e8ecc25,216dafce,26566614,2111086b,caff0e12,e4b38940,ecf05a5b,58f3e705,d7011b49,413a52fc) +,S(dd77d202,96a15eda,eef79ced,9b59e77c,1483b936,6e9949ef,ba3298a0,efac4886,b1914a11,80cb154a,f791a934,8c89bb0,70f2ac9b,acc50c5,f75b425a,df6bf125) +,S(e5fdfb45,1e7ac947,ece4e8c0,5b87b9a9,2d49aae3,5ef95f5d,1d18bcad,18053337,841d054a,47b4998d,d3ad8dd3,d2a1ee68,406a195b,1975bd1a,d4194417,fdc4cad5) +,S(decd87d4,6fb74380,56a83258,bee67d9b,1a49e170,bb1b549a,a5c2a2bd,cbc050ef,5ccd1cd3,614fad6f,601a4ad6,e964ee69,a1e06e8a,2e29edbc,7d19562,a4aebc5a) +,S(1a94991b,939bf699,468c465b,5aa4b064,520222,c0ccfcff,193a8484,6f6e4b8e,31b1e6f5,30147e1d,ec0199ae,1830a36c,bcf4fce1,e1258441,3e89eed6,889b9d1) +,S(f32874f,d0f18d03,7f0ae5f2,ddba8f16,fe7ca4f0,d694e803,b9216c59,91bb456a,1dd8f5ed,f228a9d,53cf881e,a4e3c479,6017be43,e613ac30,690435b7,84a4056) +,S(1c5991ef,154b79dc,df2ceafb,3f7fd7b0,7ce7563a,9312ee6f,1dbe5960,f91ba569,497d2a93,28ddb18,221b0075,3432f510,bbf042a5,ebc44cf9,3090d064,4a252a7b) +,S(3c88095e,dce54996,3bf6e312,4dfc14ff,4ed4ecc9,d6240af1,6ecd5984,5f01de9a,499a17ee,e13c81b9,bb7b297,5e7ed1a1,231d9094,348d22fb,9254c520,a65be01c) +,S(c849c359,1c4fdb68,55971840,c0b78bd3,59d1de02,130adf7,e277cb4e,f6eb7748,6add7151,b2640b78,b8fcfdc,fee4310a,4c4c97c8,bb0cdc2e,3bbdf802,750a7920) +,S(f53017aa,a5f79e34,5a0cc318,f40115f2,52ba5401,614b9eb8,ac9245cb,3ca5680d,2d8b8c24,ad89361b,6d77bc72,fb0c7da8,ff129a5f,2bc00e26,e635483e,c4c44b1f) +,S(b3657e9f,84975313,640b7302,a288ef4d,2dbf36ca,651c0189,b39fc10c,87d7c4b0,d821329c,a2f18f94,7a71f5f7,51ac1b2c,e56aa432,992e7a3d,ef84e631,db61fa14) +,S(79942dcf,a834e013,77bb3eec,b7fa31a7,b4eabe7a,578c46d9,3a0dd17c,b3455f61,4c08fe53,c3afcbd1,7fa0a809,bd4ff7af,88713a3e,d7713f82,18c4d4d5,2a757ac4) +,S(e5f14474,619e3acf,905da5c2,3d1bc311,7f1d58ff,8c63ed2e,fe939a22,5fd9d9a8,d4d225b5,85b6b319,431939a6,8e2dafbf,8ed90a6e,5fb559c0,70779d67,7c03028c) +,S(bc5ca503,3ca4398d,5f3c6240,946c5d7,c9102996,e302b9bb,640aaeed,8c9b54d2,ac15cc8,51e59843,fbb2956f,55d39f24,200922bb,6cbf1e86,68ed3ecd,6fae2627) +,S(2f3abe56,d63a2afd,35e35d4f,9e964c61,a5483402,5fea8cfa,66ba9aed,f75947b2,7adeb38c,e14ebe73,8dceae8c,77903b24,3066aed9,bc4886c1,356449a8,27496d5b) +,S(704bf0b5,f564ccef,4d6e5f8b,eb2e90c2,4b46d581,93cc0a41,5bfee2fe,95021b75,44618d17,c54684e,ea1ffe1,53892090,b74201d8,ab3f9312,e7359ed6,5ca94c27) +,S(a898e473,d4b59956,2a905ede,afc78bcc,9f374c6a,f524fc37,86a91375,83d749dd,5452e556,7d72dab5,e085ab72,1168b5e9,c96a0fce,f9d5862b,9c5a0daf,3769395b) +,S(fc4f83da,817b1648,a8a1be3f,dbd0f309,db712225,2988ac8f,64774c29,e8d9d573,57876e31,6a0ea473,3e34f34c,b0df75b1,1194017b,258cc944,7ccded35,19edd00b) +,S(63e97e30,82c36634,d151f0a8,837956d6,16d5d4,64c66373,253bb94,ed5c8236,af68f06a,e045e5be,88242af4,2e314ecc,d719f76e,33092e6d,8b69f791,446c2acf) +,S(4c06073,5107e9fe,f27dfbfd,5df447c,16f1c911,8ec5cfc,8083a588,9dd82b23,8c8508d4,b86e9eac,2058a912,f2581ae7,fe81647e,e27075d4,fd01b051,fe0ab636) +,S(667f609,7b6af1f,cff58520,83175f85,ea01a1d3,c508b12d,a2e19281,c8d8e443,ff9fd0d7,4a0cb42f,3d7ff6d1,67e5a65f,23c34679,caf3f94,ed5d1073,af31607c) +,S(e01e169e,7fbb4365,58e07dce,8f8dead,e2ec2e27,7d18db95,ef8e9f85,ce800fd7,f49f594b,9d60c59d,155ea702,a1b5e3a7,b26aeec6,71b275e7,10d0139a,21041960) +,S(ed10fbe2,565f80a7,65fc90ef,224c7893,cf9df84d,aa0a3b2,9089f7f1,c014ca50,ffc44137,c3ac6fc6,fddc65d1,87d6b456,819ab1b2,df461ecf,899c70fc,59387031) +,S(4563833d,d0052218,5a43bfaf,7e55c2d2,62a12feb,b76254bb,e8310687,e917cc36,fac05d5c,c781d49e,9bab4cbe,384b511d,1c8c1fe4,f68cdc2c,8c576be0,1c669e63) +,S(bf5907b0,1d05136c,b0a1b514,73682fa1,68772a1b,9f5db994,3bdacb3a,1e8c47db,fc69b036,4559f5d3,f9e0c1a3,e4da38ac,b9968e9,17311288,69da2158,2e334cbd) +,S(be106d73,d01ce0fc,5555d4f2,379c906,1ea6ca18,ef8ef8fa,754ecf64,cfc27fd5,9c84f04,947687e,f7d641ba,ff89a11b,da9e9769,8f8ceefe,54e2a4ca,267956e) +,S(5bceda4,2e94ac3e,68f6a3e4,e4509872,4724e9fa,59ee0918,859884e2,2c98f15f,4b19d70b,e1471e3c,7907f797,7311f5e2,ba78c6f5,6f2ccaf1,cb6b684f,7d048934) +,S(e0831b14,fcb2d4f7,3d17b6c7,f6d16803,304cbb32,2bffcd6c,84bdb891,9d7cc9d7,b474a715,5520cd3f,65b64d08,b8e92ca2,4b2238b3,11d91db2,48720a6b,65444038) +,S(df818b88,2300aaf8,41cb3962,2f0c9166,468c1ad1,3aa284f5,89dc354f,bb1fe97f,40f571f9,f63fb358,231c204b,3b9707f0,c5cf11c6,d7ffb93c,991cf7f8,dcfb3895) +,S(d9fdd569,bfc89237,4bc56a1e,e56bab5a,cb5e0ce9,85939b85,c929fde5,82a07bcb,5c56b150,4cf3767e,e22e4b00,fa467b75,4c9ccec4,c1364216,d34ee210,aa5b56ce) +,S(11a93998,d031bc3e,d55e74c9,ab327945,cbace727,647bfcd7,5ed04a2e,4836ba,4aa311b0,6fc8fc86,b67e8eb2,1e75d997,189fa22b,a33e7e99,b07d610b,1c94655) +,S(7c4fc747,7319464e,2d71f787,80aeb385,aebb0420,d8f8588,9652d5de,aaad580d,31d6d7fc,2cae58f7,b3e4804e,f615d7e1,edf9d06c,d1035b30,ee9b55b,21b06eae) +,S(83704a5f,4ef8ca9e,a3d5b163,2bb3df98,acd774d6,4e07b219,b9a36a9,ce88e1b7,52976995,faeb6179,bde4c123,1437dc73,b53b6f90,f0cce08,1e3e1644,e1ebeb18) +,S(5de15f19,21258b5c,f12f240d,147bd38e,fd5e3c3d,dbf148c5,9e541c01,ca7d724c,c0e18562,1500f0,e3fbbdef,45550e16,5fc2a2a,adc72558,e49f1e3b,f5f4fb00) +,S(f5d1fb46,e3288419,1f2cc8e8,2ba81ba7,5bf1d7b5,97ff82ae,8731d27b,7f059938,3d5118fc,9acc8394,9e0bcba5,c7c79fec,2f0cad64,7910976b,e4e8f9ff,43d8baa0) +,S(8ebe619a,985f720b,9381a99c,db63d089,6a787dc9,7d007354,fa83b931,223f8596,7968b6fd,e3dcc13c,512aae25,d9a8127f,313e2d9c,34489606,864732b4,c3b5ca1f) +,S(5b14482d,f96cb0a0,5664bcdf,e4ff7b87,6169db9e,8107b0b5,78baba9e,b1f8fcdf,19a4ed84,cd2ab376,b1e0c2c9,ecded5cf,2e874f09,6d84d946,22be5806,9f8a5e82) +,S(ae810d52,7f94dad0,d140877e,ddc5e0e6,cb636325,f4c926a,1a263f1f,beb9a8b8,c94f0c8a,f5ceca8f,ea29dbe6,c8afa649,f813744d,39e303b,c1f0c135,867658f) +,S(38853d15,d74060fc,7eb2a56a,b8772f6,855aaf83,b731d853,b99fde93,e7c06e7b,ade73ce5,4f513c89,531b5bad,7f47ce7e,a498da85,e378639a,5ae0507e,1f27fa7d) +,S(837a1d99,db477c6c,da832700,37f111f6,eec5402,2bf74773,4c18bbab,35b503b4,ce852762,ed9b36cf,65602da,cfd3a250,c547a971,1977ba86,64f72cb3,89ac1f8c) +,S(3136acd5,a1460d8d,717e452b,a2069b88,4eb6fa81,756f8768,932c210e,df08173f,42ad61fb,edf97b53,f59ed7b6,afaeaadb,831134ef,73e33b1e,26b2816c,99fc330) +,S(a9609269,c3ef7f09,2a43e394,e482483c,119d94df,10bcce43,6691230b,b77d3201,8c580df7,9147069a,5c84abb,73e28b6b,ab9c7c0f,7803d6f1,d9fa86c8,f324be1f) +,S(3cb613e1,1ce19ea4,a8a90eda,cb182c09,5b1601c4,92822974,6ec22fda,be699e08,f05a18f5,aef9dfe6,87e69a9f,287fd868,4c975765,284f578,50294598,51538b05) +,S(b41c56a7,47232950,7777847e,178eaa67,ce61f561,21c7f21,2c525bd3,e7adc359,b0026b4b,6f9dc954,7efedd80,d914a3e9,65b17378,e6e0055e,527f6754,c5c589fb) +,S(f44724a1,3cdcf9fe,5b4a8f3a,f0d3e076,4559c14d,87eb8ea3,803a41da,9ee9dbf5,355b54b0,7ae7c477,9eaa314c,953340f2,f5583ae2,ba730339,acd231e5,c3d64627) +,S(6fceab96,d5851eea,b5db9caa,9a0ff7e7,86c2e097,5c2207d4,67f343e3,cb36ae1a,83f2b505,20094ad6,cb8443aa,69b8af96,b531341b,81cadc21,565d28e7,43bf2c47) +,S(2acc57ff,ff168361,9275273e,9a821fae,54947539,7f6b1936,13917af0,ef83cab5,764b04bc,9068fae5,75a202c1,f01f87,f3650358,3f5d3042,1e246020,9fdcb94e) +,S(2ac302a,28126e57,5e6aee8b,2b12ad19,f5e1c056,2d63d73e,80204b1d,1d4227d2,74494cb4,1e7828f6,9d2dd529,a70f2e52,9bf4b524,26a2a3c1,ab10a974,99624589) +,S(c5de085e,4dcf8dab,497a645,c7abd513,4054b225,32ce8405,f6e5134c,515d9de3,d1da7171,31a859a,a2c90816,386f0318,9759326a,6cef86f9,f3425bf2,390bed7c) +,S(54729254,5f78e410,db85d01a,182bc5ed,84bf6843,3b5784cc,852d3e70,acbfe90b,618b0f0a,7919751f,46c0ec61,1dddd798,cd89d4dd,32d1acac,31432308,d1a615ba) +,S(c6fc6b5d,84bd05b1,ec8b0ed8,fd4eceb9,dda38669,3859d90a,a0853c3,7f75e8a6,d3d8ffb4,988f7e47,2c26bd4b,83f95453,149d1534,bfafa97c,39a1e8d2,70c53582) +,S(1e325c1,ef4a976e,77d6e76e,f9a6dc51,175175bf,23e2c46d,7203d6bf,86ea05ca,60f35511,510aad52,e156e265,6e7ec137,c319b8c1,a1591258,590186ee,be4c1471) +,S(bbca6232,ed8c6093,7ad123f6,87af56db,28947e01,99340510,95850d38,6ac1d89c,d1257327,269836af,2793a1ea,21106bb7,ec95885f,de541f66,1a4a7c38,39c222a1) +,S(c55b1ec1,1f7aff98,710c3b80,34021aa1,83645a14,edfc6926,cd56eeb,f1e5332b,e541bc98,7ecd2b66,d10ce29c,572272ec,28c26b1b,1703919f,d0b28e76,4ffa87df) +,S(f026dc49,feb91051,68f76b0e,7abcb9a3,cc78a5c4,e520c2,57d2f688,5f1c49df,2471f06b,5dc74f9f,6cca7d72,86571c1b,54ab3813,d30bfb57,53274a4b,4257f5c5) +,S(3f721c3c,605169fe,dee4a4f2,b07865be,e1f0838c,669f7eb0,f234e700,f2fb16f5,9691b1cc,ead5fba9,9d9f1feb,fae6baa3,cc7717ab,c5a671f3,8def1556,e27e100) +,S(65bccdce,bb7e968c,a1c5dd12,2d5440b,97b07014,9838f4ae,95962044,b822b0ae,bd594952,f8424625,91375009,3cc6716f,cf7bae14,a6fbab35,4a962282,ee0b3fdb) +,S(6c155658,7020a902,c225d721,7b1a5f2c,5646179,df5613d9,b95826ff,7723f42f,1ee346cb,5841939e,42aa41ed,84bd24b,33075490,68de1809,8e5f8605,59e9c073) +,S(d2c9f745,8f75b42f,b48dea34,13b2bf9b,dc045542,8c5a3dd4,2a08716b,bfc4367,e2a9be5c,8f06a432,6f148cb3,cf58f767,cfc8f8ea,1ff4656e,ec19a64b,183f650e) +,S(aa11c12f,5fda607,aeb4af7f,8430cae,3f5df00a,43910ff9,e413b3a4,7295a38,e506e63c,a0568d96,2c489851,489fbb62,acb60d9a,fb9dcf1c,7aba7be2,2e02c67e) +,S(a355e383,43937932,21affe2f,843d2541,3faf807a,900bc299,5a201f10,d5748f99,22ce77fc,c627019a,ff0245d3,ef2b31fa,55687ea7,69a4948c,5656945c,c5a5c74) +,S(d8f4e393,8b93f252,da68e1b0,16fe8889,d837ea8e,61e5d3f6,8928bf32,22643cfc,c895006,61003ee5,3d8f739,d6fb7cea,e2f7b414,28a65ca1,bf493a3e,27a2e826) +,S(f69ff0ca,3aa0ee7,122a00a9,4b6ef41e,13945263,96e8c590,84ab2b37,6b899cfe,a5211104,271a3020,d65ca305,c0daa6ac,cbbdb1b1,d349a2ba,1abcfad9,bf63a7d5) +,S(64b1b59d,7415d433,7f5b9a3d,98f06d10,7e647525,b347011d,6d3b423b,2a377592,12ea2814,ac8e0bf,1da8e617,c8f051ad,5799593d,f9ffc1f8,abc963b0,faf202b9) +,S(bac6a7ef,9a3de971,51044204,ddc3a2d3,4668613e,101a7e6a,5f93c25a,6b20dca9,7bc2b764,57620478,321de1fd,8ae8afe9,6047d087,b95390c5,bc69b972,654b97cf) +,S(fddae798,dad79951,a4c3b803,11ced882,903c9dcb,4d4dacca,c4cadceb,b837f688,2e21e1f9,f45ded15,76829823,4892d2ca,26ad5b6d,7b0baa77,c2dfbba,b1dbca19) +,S(3dc783eb,40779120,25b7dfe8,f493f073,b3a8520c,ef0c94b2,1c3a5388,b0a9a01a,b3fd9020,2ca16d20,fbe8cee8,fb8bcbcc,821696c1,15545aae,84c414a0,c4401bb1) +,S(299a187d,299c61cb,6893a5d9,cc8831e3,df92ab13,da2f0048,555d1358,e55e866d,ef0b105e,52a18751,56080cc,cefde2b2,848d43ba,6d650068,2b71fb9d,d34b819c) +,S(b690b4aa,fde43b5b,362de597,100c74d8,97cbc750,688a46b4,cb1093e2,e253dc4b,affd5af2,30e4de4f,9971627e,dac86808,c97bfa30,f051af29,bf91e36f,c3edf0f7) +,S(7217384c,1596318c,2a98db2b,7264c909,f823de21,702f5e64,b19af937,cbb8be39,b125b7aa,1bd67232,df7d2d3a,a671bbc1,bace159f,3ba2fad5,e82a1ae3,965d5c01) +,S(4bb4a86a,58f1248a,11f61599,f420fc69,bc77b7c6,86d2838,f4368971,67013852,29909cb1,3bce655e,88300d78,4f7984de,352c9b9a,960148e,a5b65acd,99b62d4b) +,S(4b3a9328,2e473993,9d7722a,7de44fcd,51658eff,93c3711d,3a8f0193,9a54902f,9a012a8e,7df3b988,204fe0e0,50cc197f,a27618ca,d8d712cf,520c7be4,cf4e0f02) +,S(5488985b,26978af,50099d93,8d7b1aa,c545b07,44938190,e0b880c2,11782b26,b51f749a,76b998c0,83dcdbe7,21d5fa0b,c4aa4392,f81821ab,3436fbf0,37d37bd7) +,S(7f2ff4bc,f270b566,d2d26cbd,ffeb1b9b,31b2cd7,b647d89a,2c86c003,b23f644b,f48749b6,21ed28ae,47223281,fe8e633f,35580bf4,8eea29f,d6aae487,ee8e0588) +,S(3305c475,1d63baa8,18f5bdc0,b4e46c9,acdf1c42,9ff5d177,bdfc214a,b838efbc,491d45be,85ae9675,310ae85d,258c6c9c,8e28d7fc,5239363c,911eb12d,ee68a435) +,S(4195dd13,ae5ea569,179dc64,b07f66dd,4a2e2878,d81a222,304d6a88,4da60b86,bbdb99ff,8d4ce150,543b48ee,9109f127,5234c69e,52293758,d0171ae4,ecd49677) +,S(8dca7466,8ffbf319,7dd9826,cfc7f450,fed841ed,83e1d466,e92470ca,1e2582e0,2b19be5f,69fae0e2,563a3f80,2f9450e0,fc48ebe5,973f542c,4c12fbea,97627e57) +,S(e235d150,3449667e,ba23d119,9b5225db,1b26220f,60f84476,70c6bdaa,f5eb7aa9,3d4d8dd6,b0c8c2e0,c8f54f6b,dffe8dd0,5ae22d5a,b4f9dc18,f17acafb,3fab327) +,S(aa214fc7,23c3c458,8bbfd962,b86cc3b3,e1ed52a,25524ed3,ee5c4933,1748ddf3,9b54e29f,63240e30,434f7a22,2679006c,24593e26,90254978,35a60897,d3578e18) +,S(1c468a51,cc9d2632,860bffba,9ed83e5a,e97dc1d8,c8bc3577,5dfef223,b3ffcc73,fc569e94,8eb20528,98b4cea3,86486afa,cec0188e,44dc4e0,25b34855,f1466e87) +,S(c663e752,ce62dec0,81f8ad57,3e4f5c92,138e6a8b,e6c9d015,d5cd2cf0,ccd1a203,ffc249a7,554fb97,c0f9d96f,4cb06fb7,ce6e868c,e7e60b30,f67a2b9e,919f6f98) +,S(949a84d8,5f68f70,81f379e1,9d673748,bed14bb8,dba2458c,34327c03,c893067f,1b9fe41c,f474e57f,8497f6f6,76472a28,fba6b259,91297f81,474cb6fc,f31380f0) +,S(6a4bf3ea,5798c8ed,4b35c629,c6cfdc0e,d16d0d27,39f8bcb8,c34a9105,fa35fed,6f69e357,d5123305,56d04946,f9265353,77610fee,20667815,e7f3cb01,e8196b24) +,S(d0a99a37,d1df89c0,99b0dc1c,16f325b9,b2ec1455,21d4f80e,ad67da85,4f2a5357,7a75846d,eaf7c4e3,5c0c87f,83732eaa,7f6903f7,b721648a,87e1909b,53d3e9c) +,S(e2a45683,f3781309,b6223a7a,5ca64c4c,cbc5d45f,29c66082,912568ca,3ec6d3c0,8e386acb,63c52ed6,5aaacecb,fab458b9,9585951e,cd0e35a6,19c0fc39,5ce1c0ab) +,S(9527ae80,10ddd443,7237c2b3,c8f3afb9,f31e1696,5b10fedf,f150c296,3cb8e60,6e0843a,87833be4,f882c417,7198d985,5af8b144,11e78c3c,497fc49f,5f728479) +,S(15f15c4a,2cc43062,d4360a8d,dcf8e0f,52bc4741,c7924f6d,e1dd9f12,a06b9b2,66a127e7,2c55db1b,57050f4c,a0d8abf3,9ccb455d,9785a4f3,2ee67a42,3bfe5ccd) +,S(558648bd,64c52dd1,189912b2,67078e8b,d3c68952,47e6c848,d7dc529a,7a24a75b,12332187,62872867,5bc88378,88deadf9,3a8f2c5c,864371dc,6be0be63,44fad7ed) +,S(1e87928a,b6e10b59,6b231b08,87a823f1,3c6b3ff3,2852d35c,d1167244,fea2db0b,4cf60a4,767783a9,1c9747c5,7abbade1,3d7fc02f,e833b474,648038c3,b68d96f5) +,S(7a169de9,1d4c3f0,3296279,2c3ebfe7,f2eb4410,f7b9a34d,c402ae64,ce9231fb,1ca2e8be,7a7603b7,d95820ab,86487a04,c91ab3fc,c88e2f0b,514a1589,3908e463) +,S(65185a2f,bbc8c96f,cf9a6df4,d002128,afff1f2e,5c0182a2,95639a7d,9fecaafb,10b6902e,e83c5683,3d796b99,665cf365,c1e41d63,41fe72a4,72e5ea6e,39dbb9e9) +,S(61c45212,4664432e,8fbcd950,1dbbcd9f,1fb8842d,c8e61758,439b6d5d,bf8dd626,2a9c7c57,48509dca,ebfc5062,4d7a0b0c,21c9f5a,45733f8d,e0441bf7,f2b359c0) +,S(f61aff9e,267b6d91,e3d4ab45,73457987,b1af9a9,38b659f4,1ad5cf57,8cc59d62,51d0b694,e5692be0,6841a3eb,160474cc,6c248213,19c9648,c32ea444,29cb2553) +,S(29f27a51,8fd448cd,73aee0dd,7316e566,c655ca44,afc5daa3,ee359ae5,b96f8bef,d5957a97,a6447a8e,a8301219,5fd53c1b,63784a8,14c29c80,d0061fac,2c6cc1a7) +,S(c656d66a,efc3597a,2ee977ba,bdb7357,a2485a6c,d654c56c,bc58a0ad,598f202d,f8267b3f,f293a5b5,11f4e466,dce0fa88,a37f1603,a3a8092c,934fb824,1427a59f) +,S(f28477cb,efe654fb,ccd3a9ab,e816f950,3749e183,3b1faebd,418c85c9,112a5135,9df0f505,6ad98099,ac0dc723,34af973d,9c98c597,ee26e22f,a0a7a60a,a3b76cb7) +,S(d007a1a8,b6f05046,a66fe0f0,9a02e510,3ca7555a,277c40a8,87a71920,5a429e79,d9a68c51,f17fd51e,b19e4946,694e90f5,2cf664ed,d2d45489,5f880400,b410b8ce) +,S(348f74ca,7e5b1ff9,e6ccf3d9,90ff1f7a,4e3a8296,725075e0,33a85b2f,5ba0f338,1648c7f,32a206a4,e21e7309,f1a68a4b,b2ee116a,f3fab3f5,7455da93,7c4afc7a) +,S(1f54e125,7ff3dbcb,f1b55720,564f0c72,d322b8e1,f14d2b9c,1f6244d9,c85f6f70,34c23405,4a970b58,2cbbcdce,e67cc564,6e187cd9,b3024dfc,731a212c,c53c2861) +,S(a984f8be,33360b3f,a012cb99,65ed10e6,43a8df49,26f8188f,24719a7c,ad6b5238,79a592f9,15c925a0,98406d08,75ec4fa,90b5015c,4001addf,1cab32f7,9f06f213) +,S(2ca5e948,76db7877,fb828609,68e39c8e,a413a057,1a39e20e,a7b98f93,f4cc4887,b1ce7c2f,8380eaff,57299cef,e840c552,53629691,7ed367a3,5c59c3b4,ae67a02d) +,S(65bc7a84,15cdd07,5f493310,de05b7a4,ae7c874d,5b5221d4,7ee556ef,4c21a0d5,ad20620,aa39a14f,dfad58b7,9f1ad70d,2c637119,d9eb33b7,ca9abca1,f5dc3db3) +,S(a0b6b293,a9e25a97,18fa0db1,16362757,6e39cd43,83140822,b2241fa8,c432f276,2cbd88cf,29570778,8a6d79a3,b451833d,c596fa08,8b26c6a9,962880bc,48ae2b19) +,S(b4d308f5,74f7832f,4f402626,5ff81788,91a86724,9df74486,f241baf2,28e130a3,ca82dfe7,4c5768aa,46927fe,70c93227,cc7c30ed,c2fb6303,9a1552db,534019f9) +,S(819b48da,f19c48c1,f6efd0b7,c4ff5996,dcd5e99e,7146bde4,1c83e333,ac891b3e,c15bcf4,c9a630f4,e1489585,e5719746,ac55210e,c9b82da3,898a0d88,4eab0459) +,S(66528e21,adf8c447,526d616c,777dde1,fa7469ec,175facb8,3ac9ed2f,db773f85,c5d38c7,c13449ad,4f346498,1eb7abbc,a98de561,d94f46bc,edf3dd10,1839d91e) +,S(a26e3a0b,6f61c611,28c2afc9,15ddf48b,8d3d3901,df93a2b2,aeb82579,4822e605,41f4e806,787884ec,84716647,ed72f331,126f141,6837a232,e1612ac9,99c7d115) +,S(56623040,c198fbcb,9aa32066,90da22a5,a0496a82,5313a2fd,529fc9b,26647d22,35867158,42a4c950,e67b9033,23c55fe0,3ba3bf92,a9ecc5f8,39708869,7e2e1e98) +,S(acb401f1,b535f181,75ba9cc5,8e32514b,be8b6d19,1401248f,20500dba,23ad4f,f57fbfc7,9bb94ec0,eac7d09e,52b699e6,d8407335,e6dda706,f7d1bfe0,71e09f6a) +,S(9e02a873,fbbeddcf,b760d48e,6e29e6a0,b37cae8d,6348a8d5,bd651be0,59ecdb33,9f926735,cb2f46eb,71005600,56dea853,9fd6d140,2a57d05a,e884e8f1,1a293c39) +,S(3e88f76b,ec410c46,ca20cf7,2d90c66f,476fb966,c46f20b7,facb7f50,17f71617,bbbb4d9,a453277f,a7bb83d2,eb8b2950,3fe51b0,7d4b93fd,5e993663,9b78438b) +,S(cd39870c,a6484a9f,e6d30e47,3a6f5e8b,3ecc1702,e191b5de,3d4d6cbf,dade08e6,234240c2,8f2b2233,9369298e,f22cf32a,7663edb4,2524f02d,6879b4c9,f4ab442d) +,S(5de275c2,69799058,3348c4cf,8c039b44,daf431d2,b7b1f862,98ae24ea,271644c9,adcf9fc3,10ce2d93,8459db47,30273255,cc483342,3f6bd4dc,56593f06,6466b8a9) +,S(2d986200,bd9dbe51,eee40ec1,2730701c,621333db,9e71c232,1a6463e1,f26cb76b,57433deb,d9149b32,37315114,e9747758,228d17be,5f7c54d4,f552e730,1e094329) +,S(654868b7,39d6a72e,75223cac,d0f827d1,789c410c,fe0d5ab7,24cdbc2a,c9bcb269,3d8d4270,63cfe,6724f8d4,77ddbd10,b24899a,3ab0a33d,87683646,9f4806ba) +,S(d97cf5c8,e1a40197,75312099,fb1a2d62,2b3354d0,e524cbe7,bbd3187,506f909d,53c8784c,cfc900a2,f159e98b,76481239,3d883d70,8a953905,44691b5,1c8c97d4) +,S(697707cc,9c74c828,7396d53b,9e5d436b,24b861d0,2fcd9208,dcdcfb54,8ad2d903,bd203dfe,7f4a3484,1f5ec966,f063d251,a89b7da5,468bb2f7,32775a1f,3a62412f) +,S(36b4329f,fbbbd80b,e8eecd1,358c05f3,6616b456,588571da,c23d7752,edf15d65,7c42145,d8774827,a0cbe9e,b9ca7b90,2353c6f6,118291ad,950dfee6,124fef3f) +,S(dad2b02d,a182ef28,5b00b0e3,2af77064,ca6b3c1,41766194,7fae0663,4861e144,ece34dc3,704d0561,f6029366,aa45f192,a2b55b1a,1786e8a2,d84b2361,eb2c2af1) +,S(4cdf386a,c0e7cbc6,e19c5f85,1edb009a,59b0526,f3f4d0ca,3c82f280,dd33531,3f8b3eda,4ae484e0,95916efb,ecf1ed3a,27bcb034,6cbae87c,6a388488,331ddc86) +,S(d4b65a7a,eb74d38f,2a8e9383,2ad27a7,2e2a89f2,2ccb5c24,9e4e55d4,da7a0cf1,a080a32c,ac9e0ee2,6e6538a0,233f2374,3428b2ad,821852fa,bbad2a23,63a7d7e3) +,S(c41cd230,d99c5f66,7d7ea000,53945fed,70a2a807,4893d488,5be2ee46,cadff9bf,4a7faa2,3ea4ab42,5f21e12d,dea7530d,429c64fb,c05e1b24,adc24f55,c34af43) +,S(4c67ce59,9a841ecf,ec147a89,c120619a,227100ab,c5dd0ba8,da6d362,6f687824,aec0ecc4,b65694f,150da4f8,fd514d37,52f4c6d1,aebd8b5c,19846ea3,bf4b13b2) +,S(e765b00d,a067b5cf,a40bf02,dc8ed6bd,4e59b470,ed6eebad,c02b49eb,1d20c37,23e0df00,9ca95773,a91c0805,40b024b8,34c0d7de,4dfd6c43,76c979fd,2665f21d) +,S(18a8cbe4,d7585fe2,3b958cab,a9303d9,505928a5,7ca1058,21a9f192,ea52298c,9d00506,4a1f3406,c3864d73,2ebf3e1d,b6f20234,d0f5a99c,3623ed9d,530d71cc) +,S(2dc043ea,a53c27b6,50e2f1c,b6fb7fd8,26c4fccb,9572bbf5,103356bf,87b3d649,2695f192,af96b031,a41b72e7,a61593cc,30672c07,cedb0908,35ee207a,5cf18271) +,S(71699cbd,e1efa1f2,914bd0ac,9b28111,8053f7ec,d51e79c0,44daa4ac,ded9c9e9,8519592f,a3b05922,86797110,b222231c,fef973bc,d51ea4c4,34998999,63637c05) +,S(23f4668e,40761e37,235dc0cd,41b6c7ff,1951678f,131763b8,7d394e12,6be4c370,1cce4181,2279761d,8753dfaf,8bdd206c,e4cbfc5f,ccfa8826,9d2d4327,431fa689) +,S(92366959,9a173d3e,826233c7,8062863c,2a92b525,106c1159,4885058e,4a7797a6,d1c9f57c,d03c0042,38f898bd,cb45c064,a1f2cc56,222bbc03,a61997fc,877b23d4) +,S(a2dd03bb,a75a7bb2,fc9915df,c66c0b22,76a7347e,6cca3d32,e5727cb8,b54bfb70,9ba4266d,b9c66907,b25c41bd,b96f8a94,a9559830,f171a878,66372067,51c7126e) +,S(79174d3e,2379484a,d3191db7,26073dff,d69a31c8,94314f7b,282ed68e,71395ad7,1cada148,7ded181b,f1a9cd30,21afb04f,4402a171,3a570d7e,9f4928c1,2069315) +,S(874597e3,80449235,af5c10e3,7af7eeb8,f755ebe0,6784d5e3,ba0d1021,fcd3b12c,2ebbde83,58c4f2ed,cc89bd52,e6cd61df,a251bcf5,713858d3,d247750e,266a6129) +,S(f23c1888,c22a764,c85c6328,387e9126,f4ad772c,fa0a6034,914d5f60,7efcddc1,6cd5bdba,cb3c6cd7,4c2c5cf8,1c62e774,560211ac,f1ee8096,be9eee5e,b716881e) +,S(a4c2054c,3a834498,6dcca592,db5fbe06,7f80d32f,8c492436,79c57b76,ae13b96,7ca515b7,8a3d5590,6100ecda,f7066459,db9db34,3bec1b4c,6a57626e,1f560444) +,S(d6880dbf,50d3faa9,835404e5,d723eec8,b1bae88e,b8ca22bb,a85fda5b,6a8cb669,a08c4200,718edd4e,42b775b1,1beb9a6f,eb3bb93,b54c57af,5218eeb9,7aa9fa09) +,S(2dfcf2b0,babd3990,c305cdbf,cae7795b,a2fb3cb6,3ea0cd17,787122ab,5af86bb8,e0e921a,15882601,c151fd93,d7b7c607,cf033633,e6498004,d29cbf76,7fb19f6d) +,S(d1dc82f9,aae7e02e,177680f1,e5d73ae,8a178207,7b5ebddf,45b56bac,fa1f11b1,4c9294c,e3ad0fa0,ceefde5f,fd80905f,ce57a5c7,c6807da4,186c9b4a,7c9d6237) +,S(ff111200,4231109b,d131e7e0,f6434461,ff699d8c,6be3e6bb,7eb9e827,9af4a4b3,2c30b8db,bbe56de5,3d8b3307,9dd741ca,8c7aa596,78a3c75b,a781a77a,e470620e) +,S(9fc4e1ac,28a8f268,c66aec12,f5e795d,f3dc23d5,c515c5ec,11c394c5,e6f2a11b,188bc037,ab114fd6,508627db,12317d0d,fa194cd1,bfd56c1a,4ba25d07,206aaaa9) +,S(bdb0b373,5bcad639,386579e2,aa78fc40,ec2f4700,4b3174b0,1bc2cfdf,f4164f95,45d65b9f,eb1f60f3,29195060,78d5c016,8c6b1820,6afcab34,a2623e1,d2bc70a9) +,S(1386e11f,3950b8d9,e87589da,c3dc9a47,bf36b0c7,8378d2fb,253e5bdf,9f704465,415f50f4,f048413c,7eec4c2d,122a4f7d,f4908265,31f9dec2,313bc7b,b1b2402e) +,S(be246169,75b321a2,edd491be,90b7a11d,75a36c12,ca782d20,732a285c,5a6a1572,ca9109cd,5b041864,5026977,9490edc9,d239778c,25609736,7b52d82d,97f588cc) +,S(baa5965a,c352a017,80b1359,3945030b,32c83b60,805bff01,476ece26,cf89384,c83a9515,dee6663b,b5688d5b,483f0a2e,51c8180e,a130e0ea,48f7a4f0,1d3d06e6) +,S(17dfb33b,957bd5d3,36c918f2,cd1fdc95,23e2980f,20a7666d,bd5e8a7f,8ab1f83e,32ffdb3,db6dfa31,ca67a5b0,27a648be,b978b6cb,7ace4241,a0b6a7d8,ceedda20) +,S(ec5dce25,af07a01d,9dc43a9,e92dfb51,29146307,cef69b48,cb7b6e85,d9cbd91f,1018c449,949bb2cc,e185a9,4a9a06b6,bca4c8b0,1a3079b5,3f86d830,21d46de) +,S(a56b5b4e,d4e4e3a6,29701889,2cf21f67,868ebf37,b8696ebc,83afd980,b5c63817,1cea139e,521c70e3,f0a4b02c,c20345df,90a579b1,20ea5dce,bc1385bd,162adfd7) +,S(2ff27783,681d264b,540df574,b478e3a6,2b919e0a,c4ab1b66,3e279083,25a707b7,3a477dcf,65b233e1,34ddae74,7fa5971c,cc0498e7,be9f17cd,5e34bb0b,480d360) +,S(aea30054,dcc9f7eb,c9dbbd45,cbcea779,49780d59,11edcc19,937e6352,a726b3c0,7ba5e2d8,9f681e00,bb74a353,f37c36c0,7264acc,d6a31529,cd5275ee,94a631fc) +,S(78531772,142432df,81802ec2,84884682,5ae2bc93,aed1fa8b,e345c106,7e23d059,6b8d514c,a0a13c1c,6425e5ad,f808aeff,f88fc6be,dbdfc788,1d174868,efd21063) +,S(c104c683,8448cda2,c94b0303,7b5ddcca,d4db1d7e,e744e70f,5f9275b3,244b8405,ac9e6545,3722e2c9,d7d97aa,767c3235,2a213391,aa2e327d,3884ecd,93f4b133) +,S(d4b02b47,3f851a30,604356c0,e9310d4d,7bd0f9a1,17db0c90,54862b58,969887c5,d451896a,5eba571d,4e55d26,9c3c8082,55c5cf18,f1f2d033,b8d30788,224a68f2) +,S(93d2f6a3,e97e4aa4,10fb6006,f3853f85,65bd14d,aec87192,e61b8f97,93f29b32,a0a840bd,336034f1,a98a0239,c6ab3ecb,eadd69c2,51b2e03c,339dd4bd,7a407308) +,S(7d7d7357,467e23a1,2022788b,2ada9a69,1243fbae,486cc61b,56458e2e,781f8f3b,59d5566d,97bb583b,940de406,44e19530,b1bc7ced,2a00c50,f4bbef30,d899e7e6) +,S(ea80f7b5,8c72080f,f2d83604,ccf6e4d3,28a71914,abf94888,8dc87c42,15fd4a6b,ecc6e626,f01f73b2,5d7e92e0,d1220b82,8f2f8ef3,3cc92111,3d15bfab,179ad8ef) +,S(c74366e7,26949fa0,6913e6ab,c41cb17e,c3837659,253c3038,30d543f6,ac0e4aa6,671ed272,2626ab33,14b6b1d8,1cda24d2,9fc132f9,51f97b95,8e72bc0b,9eb42d3) +,S(6170ed4d,c3dc2218,2b45c1c6,fcee9fc1,3897ac17,fc32fb25,aaf2880f,4cbd11bd,cb40f34e,7e8faa89,71338834,21cb247a,4c938f3e,f6a97cd3,1711f803,c872621) +,S(7dacf9ad,5775fa62,f99e093,5e948526,b94ef22e,912ae95d,8dd4e5ba,744a2ebd,69931690,6c73045,d8530a39,d33a8e21,d5912969,9f7b721c,1dd0c616,725d5778) +,S(b1d113f2,ad7b487,908767a0,b6faa413,6a8b3dad,41dad9d2,b6e8e7c,9f294639,7c802cbf,4596903a,90b1de93,649bff3a,6f63ab85,a9e3529a,7d907b41,7f973b61) +,S(d09d8d8a,17a1b113,aaafc270,db36ed63,4342d90c,64b6ae97,9733391d,eb67f3a4,c48701eb,738c3edc,a4f78313,a56660f5,3da8ebaa,3cd8d469,d1dd5910,c618851f) +,S(c264ffb3,c223e60f,fa34faf9,feb18668,4b05b7e0,6770db1f,9561ed5a,ea0bfef7,e4df501e,ebb4cdce,bbe6c4cc,b966de77,18ac5479,3e403e79,389ac330,92928e6e) +,S(55505edd,605e4299,afb5a69d,81f6df34,c7c2133e,dbc7bb10,ebc49187,857d7c49,ddc19610,7c3bee6d,ad955e1f,76afb31e,93a88e4b,de8aee59,aba50864,c295a487) +,S(9d61801b,a07c358c,f9942bd,d3614d3f,74904b8f,8f8aa8e6,a957eadf,79fe99ef,7d9d5980,2fb5dacd,93ec6c6a,92ef86bb,6079076f,7d964d31,70e3ad3b,7bb854a5) +,S(f1a6cc66,3dbf46da,e1ca98af,610f09e5,e9251a44,f6b9915c,b68c58f7,9038645d,e41bc6cd,747c0390,6d29e29c,4cbc2dec,6817114e,daedf220,b7fce48e,7e6f42ee) +,S(df247558,50b523d6,de15c3ec,38537a3c,af9a90fa,2c0e8b25,35696289,10517a79,bb567ba,e42e9899,85fc478a,4303188c,2da741fe,bbd1742c,818ec1c,e64818a5) +,S(4dc30b60,b174bb78,1f339277,ce3996f7,fe102e13,d80873b1,1a9e6b4d,54247cef,b13e5069,a7344a99,4f9cd284,1d9291a6,50e1d969,dd3061dd,ef34f037,7c85e20f) +,S(e77aac3e,946f7715,b9d0999b,1f3aadfe,de9c31dc,f8eab336,c5bcaa51,f16f64a,9d78c14d,90cb37a3,835d23,fd8d5a37,2b8fa160,1274e5f0,2bae50f1,587a11bd) +,S(24f29bd3,51e62864,3a7d2fa,6c47ab78,a6d0c6f2,c73bdf00,864e8bd0,c3f038d7,4a34c7f0,22e43220,f6d30d59,3d3ccb54,dbbcc50b,4b845712,e72636da,d0cecff3) +,S(ad4b9b47,b9cac9f8,a5f3728c,ec610000,163ac2ec,6a18cc34,b630134d,9fcc9364,afc8726e,e0f988f0,53247177,1efb25ae,e07b70ba,ec7c425c,50e3eae,2898c077) +,S(1d38128d,ce7ede1b,265a4f8c,4e6b911c,d0e28087,87244a60,dd9f646e,2932e509,857a6c8,e4f43cfe,129e11bb,462101d7,9c76e99e,c7b4aed4,efc029be,b1b9c1c5) +,S(c171b7a2,7badcf84,c3c61afd,7568d23,5a14f0f4,fec777b,4a91c92c,61358677,cde264a0,48d2cd4c,d53d7371,8546802f,1ab67815,d6ebb3cf,b6415f4d,5cf4057e) +,S(d50f20d6,f4781aeb,eeca2a8e,85e8b75c,187c6d34,a940266,daa16876,96acef4d,9aa99671,35a1dae1,af29ed05,9fa15eb2,a4aaca27,99d98c64,5ae0ed03,7f08f37a) +,S(6b83cb07,7bfd33d,181fc835,63eabdd3,a50be6d4,abb64a16,e338f18c,c098a977,3e04e660,cfe61fd8,1ec67b2,d20ca9fb,f9c6e038,71f7c838,b261ade0,51b564e9) +,S(2e75abad,dc0501f3,afa90484,e85972b2,679d1d04,62d6d206,42c73830,15213b19,4754077d,a6868edb,a0943397,3c60a581,88a55ced,dee38351,93ce045a,e93517de) +,S(8a322085,d749f63a,38dcfbba,624d0c87,b9bcb66c,e4e3d84a,e97f7781,a0e9a164,3b592b8f,9d8cc10b,58fbdc7e,982e3fa6,7aa67c90,e9ca884a,e1f57291,6d7e2076) +,S(b890b7f9,ba1f1945,2a7bf1bf,944f9949,36bb4ad,5e2e0fb8,15ddc1e,2f30d72b,c1b652c4,f8e9d91c,8a92f76e,f6f72ed3,3357b35a,5ac00d63,a039df78,eb778a46) +,S(cdf33d41,c54c8a0e,dd3a0b1a,12290d13,715de82b,21af5306,a1197444,acfdd5c9,2d7b78f,31d08fc8,afdb3940,ef1afaf7,3bf37029,1e1be3c9,5acdc673,ee2150d) +,S(20b24e10,c0f85631,fb891ae5,c0b0b36e,5a3829df,a5018c1d,8b59fe87,b051b55d,b5b9204,67394039,df0a34f1,308b086a,454c7957,40d31fd8,960f6ab8,33998c41) +,S(61976c23,257b9adc,48147038,ff5ace08,39d88274,9810bc9,25590555,b0e1c709,2b31a4c2,a712edd6,6b2da3f,84447c73,f2e3f652,d22b81d,d37ac4a9,def5390f) +,S(4ff22758,a2a25681,d28fbf09,e4cea5f4,74c00681,d9b4fe6d,ef3227e3,6092b52e,4b0f517a,4e56697b,37341ab0,6fbc92e2,4ae3d03d,392c33d2,377f7432,10a89fdc) +,S(46145b19,639938dd,9c6c84eb,d4180cf9,752cf9fe,a77ca609,5ffc8f7e,ead61f35,5b7b55dd,8a5e7d00,a3b62d20,2f371d42,8eeacc9e,7556547d,f2396c85,9503f6f8) +,S(32464689,a5d7626c,fd02b5fc,da68a8f8,dec32eba,887b523c,4b4e379b,c40bee7,6e9cb8c5,3fb716c0,b583b356,7ba6890d,2cdccd39,646a49c8,132ef061,d89f6710) +,S(56438894,2c9aa575,efbaec77,cbecd9fe,79fb4461,c61ac051,195ae384,dc0d6ddb,663528a4,29696073,f9d47d2c,bb2c256,9bf6c452,c171ca43,7cd3480f,95b69a05) +,S(f04fa37b,9c510bea,ec12fd4a,307b1b0e,d934fa1c,78cbfbe3,bf904b00,91491e4e,19b7da4d,826a314f,586c4c78,457a3075,76f3ada4,61af5bb6,c374178c,23a79326) +,S(36fe4596,b1ca6409,741f7a0c,b899f89f,a727207e,eedc8e57,504847d,2cb304cd,78f11f,4473b124,5772a101,564b6468,43d4bf76,afacf02c,bc45ab39,c7221e19) +,S(ce3e6d1b,f2deae03,8ea4333b,ebfa026,d1954ffd,f50df66,e2899b05,1ee87b0d,4cd4635f,10af69c7,50e96ede,e4f38591,2a14b104,ed9023af,60ac6e93,a9b9bcb0) +,S(33ad3a7f,a6008875,74bd735c,b2ec5dff,10ffc5dc,3163d8d1,62644086,888d29,8c959ba3,2f7b8ed0,4cb2bf2f,2b5e5f56,b29a851c,8d1f6bff,b48fab31,5335b3e0) +,S(7101a2b2,36aa7903,6348006e,cb8f81f6,b481ed8d,8a3081aa,40ed475f,13fde43d,d0a93654,51471aca,80a05745,57b4a24,9d627dd5,c1428ed5,79feac02,5fd2cd2e) +,S(ba3b4042,9c0bb526,c31cf602,3f9abe17,69974344,5e66566c,851501a5,d125471f,7db3e93b,e9944c42,b1654407,6d5bc6a0,99806c67,6cc7415a,9d110661,f4c644e6) +,S(57c6a582,1da61528,dc291aec,3a9f1a86,229594a2,27767583,5687ee91,15acd72,a9e4750b,5580b225,7768ce7a,b2909466,589a1a12,2e54a7af,35f44de,44cd5dce) +,S(c8353ee5,847efb7a,ec03d949,633132b3,9ad898e8,9a367c77,7b4a2ece,c47a7c10,dfce02ff,71060be,5e12d377,524c798e,97bafd6,e9aa9e10,27c07a8d,6f7d3a55) +,S(b0f6ef67,78b4ee99,6d7807ca,9f1f6f44,203eed8e,62584c6d,666e3698,e41c0eb1,b92763af,c9ea095,f757e921,ac0bdb02,605eb66e,d3e1735f,f8f17e63,dee5460e) +,S(f2e4015e,62645bd4,6f858b25,cb636f97,6ccfe5f8,da065b65,1ec170c,ecf5c411,8c05cf9b,19459597,7c1d1b6,4ff6e902,5d78a175,6416e0a,ebf33c21,7b3d5dda) +,S(ffcde722,ad4a2223,24396b52,5a95a233,31dab41d,95a4e19c,1a23c2e3,db7460f9,f7282903,525ac2ed,3f9db21a,92d3fe4e,b1635a8c,77dcbf8b,e671146c,8eca8115) +,S(81dc05b5,2d9a210c,4904bbde,cfb4eacd,8b3f08f1,d667e9f0,a27345a9,7d37b37a,747aad1d,bd0003a6,d89f9d9c,fc00977,719d24a5,b8ebb807,98d1b644,87105f5e) +,S(5b92318d,a267772d,94656087,8d698aaa,7d2c721b,28dfbc20,9e4a3e8d,1b0eef1c,b2d274ec,7aade417,4f2f8766,1b5018bb,47c83d32,b2fed50c,437348a7,93041906) +,S(3eabd0fd,6b5bc51b,c187c943,511c3005,8f86e474,8547fcd6,49595070,26fb805c,95e8bbe,8187398f,fa4ea4cb,b50bae2,19f8cc5a,5f09503b,3edd115f,729b2101) +,S(a64d3807,f92b91e0,717c310,ec799908,43e3a394,a5ece3c8,7c3bb209,8d3123ae,50fbacf8,be11f6b0,ea0e36b3,5c46bdb0,8fb79064,59b52901,9af59b1c,e80ad239) +,S(db9ce153,7cd47f3f,4b08858a,d429c975,9ce6738c,2e6d56f0,fca12e70,777b83a1,a91b2016,9fb1e2f,fd52192d,7030d86f,66358516,5ba32829,6c9aac95,192afbf6) +,S(bea03f49,76ee0a86,e00bfddc,79e52173,1baef841,d751ee47,9a46cfe7,89de2399,feec1fb0,3901a923,862054e6,7024ba7f,4c485c70,2ff22aa4,1620e857,6dcc863) +,S(cda308eb,6975d59,db439e23,32505d29,4ebdca67,5373ed79,25b52a6e,f60a33c9,7d2053c5,414c9bcc,5155f17a,6fc206d8,81cc882,54341778,1c5db51f,3ce4c224) +,S(430bfb3a,802988b3,a68d5595,c989cbe,75d409d2,68dd84b9,a1d4a5b9,42360174,3de4c6e1,3c87338c,8bef6195,6559335e,bec503fa,2025529b,b015cac6,6d8060fc) +,S(b4b1b7c9,932be243,6b06b2c1,e5de312e,4a409498,11a226d8,5bb30c5e,1487c36d,e169a70c,b95988dd,fe1a98df,527fc172,61cc3103,88d41ed3,4bff23bb,31da4dc0) +,S(7a954055,d2d6acda,8dbe81e7,46310113,e26af09b,91cd59dc,92a479c6,d6079ef4,83c6d3ff,4582eea7,becaf8bd,422c0558,a2bc8d6f,cb615c59,7c46982,47cabcb3) +,S(aedd36fa,91a7f95f,2b2f32c9,1be77860,75783bcf,8fcb20b5,f20ca664,dd89474b,c747f32a,174ec6a7,936f13a4,7e80a2e9,324b7f5,e163b396,218c4c35,9391e565) +,S(41052d48,54402d09,a813492a,2f9362ee,9799ffa,3d270200,45a0ae07,9f913f60,97cbdcf9,b60518c9,74ddd987,386d60d1,3d10defc,8fe64511,843d5bf7,13774178) +,S(886e5afb,69f6debc,c1c5be6f,b636eea8,7314ff1f,975cd96,9070e376,c1a9973c,6a8ec4b7,98fec5e,b4a8d645,c7b72663,d6bf4aff,8f4f4b36,c064bf3b,f6e7b5ef) +,S(c93adec2,ddf85ba8,d9147c91,82ee4fbb,5727081e,a6938c0,a4bcfbfe,6856dee8,9ebef5d,2b2253e9,4474331d,b52739c1,71214093,aeab11e4,e51a2be4,e201dfb1) +,S(d97166fa,94a4e51b,ad21e1d9,76e01011,655ce24f,5f5afdb8,feda67bf,8ae65a83,815ac894,57f83bf9,5579fed2,ea470ad2,ac1c83f8,546ef3f8,bc383701,1bc62a48) +,S(c23cf94f,c5a93aa1,719ea8d4,4f426fd3,d48220cc,10ea558e,e4680c1a,dc91b18a,64a4dd89,8f36efa6,efce9354,fa30f506,be3766f3,a31839e,1fba56b,5a07ebd3) +,S(7236b1df,88751e98,2689e049,c5084b71,b8d7979c,2c412a3c,995e61c7,2440929a,67155955,bf5d1916,9e36636e,ba56fe44,f7cef6d1,b0afd3c2,beb59b26,5e3b67a6) +,S(d1890a85,df4f7933,ff72fad6,5b95f5c,c9fd8683,3c1bd2fd,56a3b7c3,e90428d,8b4896ad,4b4469d8,af074eba,ac38563a,ca68888c,5411ce0e,b3701ced,75d4f87e) +,S(41ae85b1,9fcaf4a6,13901d2,3cd2376,62f299c9,7cb306ee,8ffc13fc,75d54e15,20d99cc3,215f0b1c,20922ffc,6e111b53,e88ffb39,bb6e118c,61b9e3ee,fa7d01f1) +,S(d125489c,4e07c44f,35d39008,e4e29c43,c28ca505,3e370570,a7bd34c7,57e673f5,d142e19e,825ff93e,b6661160,b60d4e06,b4393388,43500b29,2d4d62a9,28db2bd2) +,S(8c50b3d3,667b2aa1,a60c425d,1128d389,f2786b3d,656ee126,dd57af96,ebaad9e4,55eb7ca1,c2bb5881,7f82cfc,c8b5ca35,5c2aec5c,68dd479d,948261ee,d342fce1) +,S(3e77a3c8,a2e995b7,582f502f,9bb1230b,35311af4,dc8d0744,9211a13b,444fd42,99c427f5,8365ca18,75272508,7dc57985,d59d72ed,aedfd5f9,d61517c6,1fb8679d) +,S(73ffde64,80547448,658ae5a8,529755d7,2ad7ec84,5711f0b3,20acc53e,a15ab609,786de118,c6a0daee,48f3f585,d10b9f2c,b4947661,b844ed51,59903ce5,f2cc8d18) +,S(8f2ec78b,47c61a39,c2ed1110,902b3a43,4fc9ddfc,b11b1ed,75c675be,5b8a172c,441686b5,c1327f0f,d2bee35c,5d8f2aef,b6da72ac,e6206982,6d6812a0,5b937346) +,S(c36c0376,d360f87d,28069511,7eddf1fc,75ae7118,5fd5a82b,b47d8fcf,519ae4d4,44c31c56,cda1c2d4,41161ab7,45f3c0,25c4ada3,72396658,cca23f93,bdb6a303) +,S(1ff06490,3cc7e686,d408909,4812a7d8,531c4188,ab8aaf4f,f10bcc5a,9cac352c,87af78d5,3122ad89,9a6a1297,fcc87c1f,252bbf9c,d8cfbf57,f64cb6ad,fe77f3a8) +,S(1265a4c0,6e1f1a6,126a9e37,a6e4f90b,290fe449,49b82bca,8ea73759,451e0b25,4f0f7a6c,9bc7f00c,42b90d95,95871176,d723941e,38335581,8f7aacdd,f830d15d) +,S(2595358e,4d45d362,5fa1c89d,a3249cc5,a26ec3d1,e554a863,51b79fc3,4eeea90c,d9b8d147,e4e00450,1baeeb5a,8440235a,88913063,bb1ffa78,9402c3f7,2c603899) +,S(3f432621,7a5f415c,b028f338,40fc226e,5906a09b,d054eb55,45609fee,90135082,a572303a,131fb0f9,c63d88e6,3520ef2e,77bcfea5,1031fa60,fada909,a610c830) +,S(9ee85c9b,4cb0102a,6b21c517,947d798c,c26dd853,7bb5d6c0,46a50144,f3297f45,85b798ab,c2e4fcdd,bf3e17b0,49e2a495,6239ba16,9917ed08,ebe109e0,4ac8016d) +,S(479c2ec0,28e8c83f,d7946f43,8d802ed3,d728179,55d94c55,bdef5050,67774934,c262229e,23eacd99,f9d3fb37,b7b9040,47cdd5a6,6872f4ac,800dbb3,d87fc3fd) +,S(2a52f4d,821cf4ae,758ed477,6cdc3bc9,2d3924fd,97a12f1f,4dd5a646,24766b4b,28500754,6ca8f142,6f3a4a6f,6ccf8437,37c6a917,7ab59b92,728f588,f11509aa) +,S(d89159a6,d5447ab1,bd03d44a,a8db3410,c86305b4,4f06b25,b88c4244,5ab1e929,c539ee3a,e7dec645,810c4a02,e1777977,d98ddba2,281d5701,2ed2a4c5,85057013) +,S(c91267af,4c303e07,ad82c1e6,2ddd45d7,cfae00a8,d27a34f1,eea8d15c,1add920,975967db,347415ae,24b427a1,b8f7229f,8db0758a,7ea13f7c,582c260,c0711b85) +,S(c860be31,18ce92b0,39b27a50,960d3caf,88e24bae,6e45fd8c,5a253a78,e3d0e6cb,15b8374,922f44f3,adaa213d,5e3facdc,9de1ff6,4da677d3,d89f6e0a,a800413f) +,S(eb8b5f4,2fa90313,b3dd7d4b,d47338e2,9861e52c,b492e9dd,6a1897ec,4da14c14,9d1c4d0d,56c570b,8835e188,517fe7db,490aa6b2,bfbe1564,579e7af9,c0647bf) +,S(151e39fd,d5961da7,44ac5871,94081a88,666d3dda,6507404b,607d449f,1b3c005f,476bca6d,6bfc5e2b,2c183794,563d35ac,aa8d38bd,ec3846b0,22831bda,38fa28fe) +,S(b46d2d52,b764f922,7ead0399,c391a9db,1737c9ab,35394951,5a57c76c,c3c05c59,8aeb78db,db1e52bb,a8030a3f,b9f57f6,644332be,6d0ad41c,34b7fbd3,13c6eccf) +,S(a89e77d,30c66dba,a27a2dfd,5af0684f,f6ccc84e,49b8d98,f402a88b,20e5bf7,af45b2da,cffcc49d,4f6db574,29f13971,c74f5321,4dd4af49,2bc7ae5f,10abe1ec) +,S(8d774c5b,eaa0cc57,7479873f,9bf5ff6c,808afa4c,6fa6f2be,88b53841,4cd088c5,6b9461a6,600ae1ac,4e617149,73fa8b48,74dd7cc,9f331eb6,e15bfcc3,2e26eb63) +,S(34ecc029,105f5e19,d6c2471e,eae5b671,cd55f2c1,bfba7dc8,46787c92,ba7de2a3,13e3cd9a,db98a6b2,433dba08,ec7d40c9,c2467878,f6f4bcd0,ce60397,67aca327) +,S(41b10298,6889f83e,e89d4f8,fa50898b,c9bbf650,2d153c36,85064c9b,f3dc3c43,559f5bf4,fb827bc,dd068d3,cdb14d6c,ace08a47,c30e3fc7,8972ceb8,9f88c21f) +,S(4a77505,79ae33e4,55228533,b8856da2,b14f70a8,d13ac2f4,f6bdc5eb,4f5c9aba,d365922e,3a487635,3ee1b02b,511c7926,e5c5edfd,aac153e2,686ce4df,b623ed2f) +,S(173af9bc,efacadf6,c107748f,278adc1b,d42174e6,8fe06d9d,f84fe278,70eda280,7b120d62,2463b94a,57303cfb,2c477f95,49d41a66,d6ee7c2a,4c652284,b8535faa) +,S(f0fa5cfd,ba53a5ba,df707983,134c3459,5ba232b5,7fb67a94,5c5c0f25,a0539be9,ccbc91a9,c0a2efd2,3bffec87,cadd16dd,f4292aef,a59b3d31,6e9c7082,742edb6d) +,S(a5df803f,751c4846,10799c60,db405439,9b1d5bfc,c99fb316,fe884468,e57ab77b,27f8f706,a2f08ff3,249f8b62,ac0d59b6,31fe52fa,7ab08ad5,2d09ff2c,4138dcd4) +,S(d165fa7e,d61c251e,a93e8f16,c9291b09,1f258720,fd303a3d,c573131b,d98628cb,cc0dee9,f01f0dce,aba94461,1e48f9c5,282a7480,eded0794,81d0b8c,a9819a73) +,S(87703371,46a8694e,2bb5cb10,76ffcd94,309c9c8c,be6e8cf6,5a77f4ca,4d31efb1,ee64af6a,5569a205,2cd98c10,871b2ba0,6addae3b,3cec463f,6002d86f,b16e5e9) +,S(1c7e4ec7,c090906,3d98f786,dc22db53,da4d258d,6e75cbae,30d4b99e,f4ca47d4,d2001df7,3297e6ec,c0aec17,e72cfa6f,5951e2bc,f03e4aa5,5f329c77,47cd92d8) +,S(d485ec0a,1a0abc6a,69f308d4,c7f8b8bd,fff5ac6f,ad4ae4ee,271a87ce,973b58fb,68f51764,ee705265,3e2f7d7b,7415847c,3856e3e,1a7f4932,6fbfc9c6,5976cd48) +,S(ae5ab510,48215ea2,3be55d93,4e0dce0b,ff88f09d,10c8953e,390b79f2,da26e43f,9f80d71,36a5da61,7f90d0c8,a6d9aecc,5cf88abf,6bbc2181,5f8320a7,2fa8929f) +,S(cb879f42,4613487c,24aa73a7,36f211ea,96541877,33fd7091,40a824ae,7641a708,d46a4ad5,7f607301,f61648b6,e99891d9,ccc41af1,af29a66b,b894575a,a6b3d5a2) +,S(1e8d6ac8,ec0b543d,1e0aea66,7f35b556,87e30be0,72841fc9,3f599c81,4a750d7e,8965853e,6519ae5d,c523cb52,720b004f,ad2f03e7,aa3e0413,bc68efcc,c0617f85) +,S(dd8e5b0f,be63df6f,5c20e447,778f923,2e1b2c22,4d28cfda,b2c672c6,66d05f8c,d8b75f77,f955219b,d4d95e65,35d5cb0d,23c2a1d1,671b9416,2da9c4c9,b2d4a94a) +,S(78ac44e9,938bf51a,691132e,93ec3a42,22be3185,35209054,a76b87c6,645e0252,c0f66cf0,3c20dd,d136d1f1,cc00eb17,efdf2a4e,72d373a3,99c20da8,8342299d) +,S(d53110b9,5034e916,d904cd15,1170761d,4f3492ad,9e257265,3ef37739,df9bb035,c091177d,796d199e,5c05abeb,29d0df1e,e5ceb93,d272e6d,d254b6d9,a6dd35d8) +,S(868b2732,3debb9aa,60942498,3be71d0b,451ea44b,64c22225,2af3d63c,3eb512b,8951dd34,39774c8d,89cf4b4c,485889e3,df2503a,102ae568,c63fa74d,23ee659f) +,S(672de7f2,34e96153,d83da7fe,3e199099,52ee988d,961620ac,b8c6b4c3,520fc50d,ab02a8b5,2a2d9306,8a83a0dd,23ff882f,b1052f22,72a0ad11,cea13c63,4efa33a2) +,S(4887f473,af8189d9,c46ae22f,c86ba6e0,f03c81a1,490de032,72b07937,b63a7527,a2e7a713,e1e6691a,ce09dc0f,a86c92b0,a0097899,7fbf26d3,98581731,a577a21d) +,S(f97ddd77,38bb419d,ec051fcf,a93753ff,e3dfa122,6cf02e1f,23afb376,7a121440,2fa9c241,f747fcda,dd09139,437eafc8,94e7a47c,ec8a7ffa,1e054ce9,21d73243) +,S(ebe75f9b,2c92af9f,11eefb04,3456f6ef,f616d1ec,b616a9e9,9e7f8960,4f1d62fe,40b5cf37,b06cfb0f,294da3c0,f756c867,af06449f,e2a916c8,a327117e,9a47f74b) +,S(10d376b1,1f0138b3,238deefa,b57dc84,7ef66849,14e9f120,1a9619c6,b1715a13,a216f393,1f398b67,d68a2888,1d5a31f6,e5e0da82,e2b5060,4c6f6322,9cd21748) +,S(69e26679,f103a1f9,8a9a4d88,c973874e,db7c82ca,99e48554,37284445,b55517b,cab62aa5,13b41a9c,56ea455b,6a880b95,9d400bba,74e7a203,7b60ccb0,4a89b8c8) +,S(3acf827d,81e39933,64e99fa5,63f89305,dcc60b62,44ecc0a6,b101c6f6,ecd5bdab,77e3bd28,40a99c45,30ab7767,4d8ed17f,f57a4f1a,4ab91732,7059114c,c06fadbf) +,S(2e5125bf,9e263d80,7a220063,434f928,d9a4907f,68601eb9,829041e1,a7b89bc4,9810022a,d7d3c333,d7c022d9,d0779b9b,5807226c,9fd41e65,c3fc8e1a,a7a0b51f) +,S(7b68da4a,197f6bdf,56948023,d2baf10c,9449d6b0,b18addc,49385125,e62506bf,85a92b7a,190aec87,bdcb9df8,42e93917,9254ae6f,b45e6764,32e410ef,4b28434b) +,S(60d4b53,9a29562e,8fab8ad7,3b699550,3fe7d6c1,e2ba1465,f05c92b1,61dc829f,2c2ad439,8fc7c836,5b2efcf2,1e4d0156,1a753f5e,d945ef2,bb1a3394,203d07eb) +,S(5a3a1bd,30250a40,d22aed42,71892b88,3c03ea0a,baba458,6b65cc50,4c79b107,9bf3bf42,df1637cb,80c1fef2,cb9bfaef,dcbff761,89cf9f5e,d00f0f4a,e551e31b) +,S(9b9d93b5,6b70fc67,5476c6a,6913e173,11ed1ade,6ea7b810,b9c90977,a8f3707,ae01a481,7a9ce6ef,5584a48b,fb96a9c5,21d5bb7e,2bf73cb4,b71f4dfe,aa7da298) +,S(44bdd82,86a3a4d7,6ecad7f1,ef66022c,6a49b916,3d7a8ccd,e54bb017,814d2f70,26d345a0,52034ce8,b4382905,f60f8885,e20afd4c,54df6d6c,ccd1c2e2,5d06adaa) +,S(8de8205f,e44946c8,582dcbe7,152dfe3a,7eb85e7,bc070282,3c972727,54463869,1dd97d78,e12a92f0,cc2145ee,db4ef561,af21d3db,f3cb123,ce0bb582,6791a30b) +,S(c36a713e,3d88ae25,f79b4add,90c6a724,77be7d9e,a62ca0ab,2d5a800d,41f9321f,2df57da8,6cf17f7d,63ebb85e,e7570869,cf90b462,e76af48b,641c07c9,45a638f6) +,S(1ce37a88,f25b8b81,941db8a6,13a7d952,c2cf868f,e979bc0d,5f35410d,147207a8,7fab8cb5,f6611850,e541dce2,315a7833,3999041,5c18ab0a,718dfe32,e0ebe992) +,S(e489744b,dbb11e61,a7e827ca,ad18ba55,41f4c02a,b50b75a0,353f4a2d,f504d575,6abad3b5,3ad97e6d,a301ff7c,7931f37e,55246ab4,c7560,363ff214,2cb9a398) +,S(cb4ec0aa,c1cddaf1,c7a67507,5cad6762,cf8ffce7,6a06f76a,38bb88c4,5181ca3d,7f15e726,5092287c,d2ccf3c5,dfcda0c1,8c63f2ad,21c06a2b,469bba5a,d9e4ff36) +,S(aee1c436,6b923847,40127dc4,150c6dcc,ea62864f,394415ed,9a39d539,adda44e6,2496d2da,97990e6f,5fb1526d,b93e92e7,8a011c33,61218d,c3d3c56d,952f8666) +,S(a099ce61,d950fa1f,19abc21a,79c74021,472c46ab,d8f67798,34df0429,ba785491,c4dc483d,6d61ab1d,7578ee0d,7548e0b4,295891a1,39774c22,7d073232,f2f3ecfb) +,S(6c57db5f,b194dde1,b8cc9686,fdb65fd4,eaf8aba1,84434344,7a770ddc,9055e429,2dfb48f1,58663b3,6a7747e8,4b5a9001,163ea20e,f07649f7,1d7a21b9,b11995e2) +,S(f6efa15f,20b2e91b,cd7323a6,51e5d7b7,a8b323df,924c616f,21a7d6e0,e34d3c76,ed48a439,2bb4d596,58e75757,95a0a4d2,7443415d,7662a535,a6246d64,3804fc1e) +,S(e7983476,a900be4,e9dfed94,42f575e6,4d9af362,1e874a99,576e06e5,d31485f8,9d21080a,8b0534f,6b2dfff8,9eb8172b,cb5388ff,d910fdfa,405ead29,9df779be) +,S(88ffff0d,7b415f76,8c515d80,9c607949,b469b07f,3978caff,1ba64e,ce198ba1,6816bd9,ab0e773c,38b73787,2881e96b,8eaf381,b155b205,79b24a39,eb9e0fad) +,S(e5fd2c3c,a1c85b03,3d93a3c1,261a5c1e,c4adb72a,7700405e,7c0bb108,d8fec1fe,97bdee17,50801ab9,a96e3fd4,ec4860,e59034e5,c02f9168,79b1e654,5a65fd39) +,S(fb010f18,146336ff,30dee37,b25aa384,9588b83a,bf943125,613d2c72,c2f5b3c4,4b0ff7e,7a6f15c4,d377e92e,73c8935b,d2d9f7b3,5be91cec,da891f61,c7631bbb) +,S(9be574b2,c28b1460,a1d67d94,43e4bb85,c46a6bcd,a957499a,179cc8f9,7ed33c2a,16aada1a,367def6e,d4f34409,e0ff5d41,f3854494,6a764040,e1109574,109bb310) +,S(358e97b7,6799ae09,b80b6797,90e34630,3d61fd4e,71733d6b,3c90fdee,2ad44bf1,3eeb5209,175677af,c16a3869,5ff7d3a5,e9704201,b802ec33,50c6c2ba,c0ff4144) +,S(2ed930c1,c941b209,b6e7cf3e,83971e70,9e36bed7,a4d3884a,faaf013d,5b589b59,ff6a5a5,e601377b,9dd974bc,4fe71e36,403f2cc,90b16834,b1beb6a0,98553d2e) +,S(d86110c0,6e8b20a2,e6da1930,fbda70a0,d8c022e3,e68255f7,262168f3,2bd58986,34dd600f,9b7157cb,2ec545e5,c50b3f95,2f422b21,4afe255,b7337815,1f3dc048) +,S(4e7ffdde,305ea002,f7dfadbe,e2da926e,6d2c2714,596fb052,7eddfe92,81d4fefd,fb4dc1e9,476cb2d1,3bef4548,9ab7ca86,6ccbdd71,4cfc937d,bf024f12,ff04eaef) +,S(6ba04fe,47c4c99f,849fbd68,7e1ca6f6,3e00179,3ba3a08f,86acf668,df0afdfd,dad78b7a,9d34c738,31112801,91476b92,b8eff31f,fcaa6d,a0704244,5fe32e37) +,S(bda2c2c4,86029d0d,b804f1ea,e9215150,34276a88,179154dd,d5d9f176,cd7f50ba,a70291fa,47b98bf1,fecd9aa5,b53ca619,41d62c9e,c8b02ea7,91c79482,afc8f1c3) +,S(99801a16,4da92a6b,de6ec7a2,69c2798c,b421af01,5ec24c8f,1b090169,18980a5,3af209c7,de27a683,56f242e3,8805a368,66cf7780,60c2806d,76f9eb06,35c18358) +,S(67fcf955,dba84390,638517f9,5792d09b,64c056aa,ba98acf9,d63c2bbd,df5f021f,96f96080,b5758233,ee15e8c4,7ffdc3ae,bbc752a9,d7697e1c,3ec3d479,4f912d2b) +,S(c15990a0,50c2946a,e4518cf6,84ac9cae,1022a29a,bd88f8c2,c8e724c2,89b954c6,611bc99c,e4ad5b6e,3ac932cd,e2e70e0b,a3690ec,758bdead,5edb3b0f,b5b95d56) +,S(c5261ad4,f6d03a0b,c15ace20,aaf95bf,94d9ab5a,95a45d90,6ce7a622,3b09d59c,5fd1b7a3,b22732c7,4b5dc1ca,fac99882,467bd80,53f2f606,ca5af8fe,6d741448) +,S(b0bec3f4,eae81fd7,2b70027,72a49acf,46a5c50f,48358df5,e174eea3,c0da88a4,13a4cf63,fca873d6,cf1b8c35,ce25f439,4d74a5d2,f2fa2799,d4c3bb98,8b50ab67) +,S(e3d32fa8,9218a38a,c503780b,dfe23dcc,e6a7138,d84668b3,f71b3fdf,891b6256,246ebe20,7ab7c536,8f7c9795,9e7aa1fe,69909d50,f4b24263,c32b8bea,7674b85b) +,S(ebf3bd9c,1920f625,4c32467b,7c1c138d,3ac6a4c2,b185557f,6eeffd7b,2aae0d63,58ed82e1,25fa2241,2bc4397e,73009692,af1d5feb,f640a422,f52e5cb6,42d4bccf) +,S(d062e72b,3dc76d03,5827786d,a9cbcb03,b710ea61,2eac883d,b7f50df3,fc6f7175,cc56b076,dc3cf1b9,e544858c,1a31723,33ba9848,a8c463f2,abf2c6d0,dae14a6a) +,S(97444eb2,32b09240,fc596530,374da035,f5ebd37e,6c74b51c,8158eab7,8ae30f89,fa06190f,d2072bad,b9144f72,db18819,ba76399e,d171d4bb,1293c20d,63d70391) +,S(3e1ffac8,15f68300,4714f302,1ed39460,d5e4d63f,6fdc445f,12d8470f,b273c242,86f0839f,8610c4cc,6ae85d54,b951441e,efb700e9,9ce54aa9,fb6c7988,a8494c25) +,S(deef1e7c,12e498e8,6542acf2,3782ece5,2a02b13e,3b4e71cf,e39e79ba,541d2679,e039a94,f4b169fe,a13ed182,f9e541e5,2b117536,d90024e6,9f3bcc7c,988714cb) +,S(69ed1a62,b3de5c,c5785b27,c7926e52,4ca1527,9f8a00eb,b5e1c247,a6c8265,9c5fce7a,84b79a67,9f3030cf,a179a682,cc22c464,11ffc8b1,ceb885ab,4753de36) +,S(cdb36419,5c3be45a,bc9f58e,e5a499a6,ef58ff2d,296ff989,9fa987c6,b753f82c,34a1a6fb,7a6b6c95,2a604340,d2c30c15,69c46123,e5cc5318,833f3a3f,bd622e47) +,S(c5749ad9,f4583689,f2ed313f,dc35fe8,acb6a85e,dd0498c5,ddcd4842,fa21c555,f22ea47,ba61044b,54ef967e,c8c82167,3d14d710,334784f6,a7b46d48,19f99cf6) +,S(fc86862f,b2fac126,e4341121,c82a9e14,d7a48b9c,988b8458,300dc3a,ba10dffb,42339dc,e304641,f814327b,ca5a611f,3638d610,85826d70,3d94c76b,8297f6f9) +,S(66dd174e,446ae0c6,3ded267a,faa20ba5,62131459,5576d10a,1e44ef18,69e36ca9,d93a449f,6d3fef4e,435f6fa6,3191b625,b883c303,1dd8b380,777b556e,acee9df0) +,S(736a80e9,15b39c21,5e5efbe8,ed6f8fff,7aa826f8,5c940110,3c7ce372,86d952c6,4a9e17d8,9066ecb2,95447058,4dc58c36,c84b3d9a,30ea45cc,e62454fc,ae13e0ba) +,S(7b747f80,f4a324af,e6042edb,d8682d3,1b8fe12e,19936844,b44c3e73,f6b7075e,c2684490,56e7633d,2add97c9,75079594,b9c0d038,cb864331,aebddd3e,18830199) +,S(dfd54b47,e4d2abe1,c40e0a1c,2916469a,7e8a61b3,bd95a1ea,8b5fa182,903d8339,c705b4a6,761d2ca,49f87fa9,ebb4b39,35c3c633,4f6b7643,417c8a29,95515fa9) +,S(992a5fca,521a86e3,dce0ccc5,fd1b2ca3,656f44c1,f4967931,8ccb7a28,7879213d,ca2836c0,496c75b6,4c56c13,641d0402,b64cb2c7,617c9fbb,d820245a,9321217) +,S(38e59093,acc26364,de9cc5f4,de398799,54774d68,ed4b0283,2bde2a26,cfcd23bd,953c21c3,14ad2e0d,511d3f05,678358f9,eec2fa48,d6b24c9,6ed4efd5,da3b3719) +,S(889ea31a,5969b77a,c41c0a39,cc5d006f,6ff14f22,a62a5f26,d736ebcc,f5df8239,4c2fa5d9,c2f0316f,dcd6462b,e7571f4,92aaee96,c3c888e5,21cfabcf,78d2c3f4) +,S(f70e24a1,6807d5a1,8e15fdd,f31301e8,bd210ed,5d3d614d,82eec8b0,326d7b6e,dcf95677,b29a5ae6,15e2e7b6,c370cf69,ccec71e8,9569f0b0,5715963e,da6a34a1) +,S(d6eb7425,9c17d292,e1b1a4ea,624e6876,a78aa774,2b14e94,d3fd1b43,562e35e3,c05013d1,4056ea0f,e5f1fca4,b0c74b5f,776a8564,ac973973,c929707b,b3f078bb) +,S(df7cc5f2,69faf306,6050409a,6a03cdeb,8f33d1d7,4e30658e,e871de09,59701b16,3d8a28f5,f604c765,5f28dcf,b2f3407e,6a63db14,6b879fb5,bc785e65,59319147) +,S(e6bfa4b5,85f6df59,7840119b,6a31d0e,4ad800ea,239bbbbf,a8a1a36c,f8c6b5ba,312b5d55,35402ae1,37f9a02c,aba859a0,22a8ba00,88a2305e,4afe8283,98844dba) +,S(3c762a8b,acb68a13,2e3e022b,35634b3c,1907cdbb,261ff639,9520352d,fd94b3af,2ad358b9,65555cf1,e0027e3a,b93d46c5,b104324e,2c62f9b2,5f70930e,bf49f385) +,S(b4d94e26,9955b213,8025e5a5,bc5ea171,c2ea6d04,9ab60184,88f47f7b,f6a6d3f5,197b20a8,81e9280d,96b5b4d6,ceb3fa20,38a28654,63e76ff,d0b5b401,8b59bd1c) +,S(406e616d,907a0f72,12acdf3f,d5341a79,9b482697,88976615,388064c9,74cd8ed1,72730d26,b2698e29,7f62fd98,2a3955c,da516ebd,642d6619,2d33a915,ba39d0ac) +,S(1762d974,37705ae8,37603446,c8c11568,c7878053,f25baf9e,e3bd23f9,5babdaf1,1db8fe6c,77f41656,1fa4df40,23662039,66a8f891,e5467b55,3a2593a5,1ba796ba) +,S(f5fbeece,aa5386c4,d75c92a9,88ce6bf0,f957a0ed,3f0caff9,42f1f29c,7ad765ee,fa45a4e5,85ccc691,88426bd2,8ae561d,a2f59d10,e4bd63b0,4f8a53ef,1cc3ab28) +,S(7e0d92d0,d12bb892,b87b8bc0,993b4422,cd1e9d95,144602c3,a2aa3c06,bc945ecd,601b1019,746bbd4,ba9bf00b,4ffaccd0,b1bf885f,57ec49d2,9fc91744,8aa70761) +,S(64cfeaa1,4d4e0cda,db6b6a2d,9e2c2820,d2fa7817,43d7b2c2,8211b1fa,e17ee0db,f0b199a6,1a1856b3,360f519a,a6056900,7a0ee623,69e0aece,ea64f0d0,8cf568f8) +,S(c90f70e6,99ba1a75,86073eb4,5540b3e0,80bc78a4,e811069e,f861b048,5f11c88b,7a8257ca,cdc7538a,13b55285,939c614c,14d6a94f,70509900,44b286d6,7eb84e14) +,S(3edbcf0e,b4e5e640,f40afec9,ad370813,426b5488,3090f8d4,b72b1680,6694f42a,ede4512c,c4baf93d,f05c14c9,cb17b1c1,fec46052,c7087306,2214a05d,60743c80) +,S(77adf15b,ae449ae2,f63d7c44,3c56cf9d,64d43840,5154473a,5948cc79,160b64d0,a1bf9aaf,7804cae2,c377f98e,86b75e90,6886d293,21aed43c,77e330dc,df9113d0) +,S(350632ea,23e39962,3daa53d6,5a916f31,b2ca02bb,5bca1f58,35b85165,b430398c,41931339,48282550,bfa1cef9,94c28873,ee0165e2,fa970d04,e51f8ee2,b87916be) +,S(3d6aae93,5ee4ab6d,46de768a,d6938703,262e9fdb,13bade31,d38fbd0,9fade000,62674fcc,6eaddef7,b971e964,5a688e32,14186605,615982ed,a09de4ba,13eaab23) +,S(856e564,a155a29d,c1b739e6,309fbbe8,5ea4debf,f12a9249,347a5435,af674993,a0e6deeb,3777ceb4,6017ee63,caeda231,e616fda3,c105f0cd,6174a3b3,dea84256) +,S(95f8b405,c1ca86fe,d56727ea,eecbcce7,32d2c521,415eff95,b3cb42dc,5230cc7f,c8c66b1f,2637df4e,2a5375e,3a2e5e4a,a89404c,810322ce,c4b2bd1c,91163ccf) +,S(b51de213,54aa18ed,6ea589fa,e3b92d90,732dad07,6c80b842,579d53bd,2089e0e0,8f069737,1baca2db,208f7db4,c43a85fe,d816eca4,e35fe95b,780e2c4,a3f1b948) +,S(e36ac0b2,c4b73783,7a96b372,b8d0779f,41605e99,2a0013a5,3c8eb4eb,d5e2a988,d41ea6e,ef06bd62,7c2acd2f,645acd8a,75e353c2,448aba53,452787b6,670eedd7) +,S(4d08e46b,a3e812b0,67071dc8,b76cbbb2,4effce48,cf4a4c5b,ff4e15af,71c51635,fcbf2dd0,ba055845,b70cc545,5a8658f,39ef2176,9802fbda,2d3ab98,ba914c3d) +,S(31421774,5b1a6b68,918e8afa,4e8dda05,6094a6cb,6024c3e0,c10fdd99,245d7501,7ea6ac19,1c0db139,eafdc961,e8f91f1d,79269f69,cce275f7,abe9598c,2916fbd5) +,S(79bb2dbd,f9afbc9c,f605ad45,4768cad3,14d48241,724b301,7b5abd51,6f8dd4f9,d1c9dce0,30fe1a72,5d100c07,d842a78d,beb689a,606a933,ca865051,49007b8c) +,S(112abf7c,1d5d66d0,cbcbf42,1874bcb8,88d3b3b7,5c2cf36b,1399fc04,17525731,b3d3ee4a,f44b5372,8d0957c5,e388094c,34fe0f5d,c51abfc5,76c1e18a,c920dabb) +,S(f6257a3a,60365e63,471fe77f,893a8ae3,174d30a1,9aa495cf,251812d4,c5040400,293ef8f3,91804cdb,34845404,996a24a9,5554fd24,185ec85c,3a27ef8e,c89938cf) +,S(ee7c8ee8,bec75bae,db32c6f4,3b3b7a04,2c10e903,de9e7d21,5ca08135,d59a682e,e68a0137,398fb186,d5168e64,4421ac4b,30a635fd,c15527f3,e56b21b7,c0008ff6) +,S(e292a4c0,fd63ec7c,c661ee1b,25c9d5c7,dd805a97,fc6e64ce,5d3d18ad,ddc92aa8,ede226,7fa6fe51,1d4a510f,e7f5e14d,8fa29fc8,b77d61ea,2e140739,29644745) +,S(cf914327,85a05d41,2ad06146,6df68649,d3b8e0f6,86a83a70,d32c2fdc,978d8124,f74c1223,7b0899dd,53afaad1,b9b06704,c61c6e97,81456e86,ea55e65,96b0b13d) +,S(88e58d21,95376fcf,b3f0c44c,b013f2ba,3379ba55,2ceca46c,38ed48f1,263fe894,f2f38177,bc673cbd,70853432,6ece1090,5863ad84,1140c59a,2a782af6,ccbaa71a) +,S(90ada18b,df0c62d9,dfa35e14,d1eab9b3,48d09579,f4e82cb3,65dad65b,62ba53c5,2c4e704b,fc9a9b97,7d330d92,602c677a,4a06040,74517775,d441d0ce,6c5e5e2f) +,S(3bdc1eca,a939c8b8,c164e5f3,1a02a6dc,9d2712a4,6c30f54f,e2159934,d492d1e5,e53acd26,28f6e646,edb5f53a,d9e1639e,43b4ee9d,b61a3545,a9874609,9b3c1e94) +,S(54a206cc,48c7d529,c8bd2ca3,91501ca2,1b58f5ed,921ba11a,95eadfab,3a720bf,83f4f820,b9a07ae2,8c5e137b,c9ec4f0c,31c875a4,b055b0bc,8de38f74,c54c06fd) +,S(2754b021,13885a9a,f44cacd5,2999a03b,d16c90e,4e3a7a67,cb3426df,f6abe546,f8969b1e,e955f8e2,dc0d3090,167c0116,66beaa68,35bbb1dd,e721c4cf,768ef566) +,S(ae438153,4cf07fc9,1dd14a40,68b3cfe3,aa6e608a,bf1d1c1e,13ac54ee,e0759165,e7807ae7,395fd072,6f77d7dc,956c58a0,69243b63,32bad336,72d2eebd,662fb99) +,S(cb9d28c5,357165dd,fe18010e,4263e626,65fd6315,60ec8126,c7b60603,6ec067a1,86879039,f3264d1e,511fa8e2,4298c9ed,6f1e7625,897666ad,4db9a43,3338f5c4) +,S(763534f5,52317771,551524ae,7ce33579,41da627f,db77d4e1,a9cf72a5,f182d276,9fd8ae13,b1706cce,ad190066,9b1d2f46,8c177970,b5173f76,55efee54,ec5cd8de) +,S(3990fb8b,39d529d0,b2d38432,3c60ffdd,3b32f7c,278aca88,f49f1523,fa16ded5,e43c977f,427570b5,b238edd0,77db9df8,b1b82e20,b73b8d56,84a2ee37,886edb83) +,S(6b76502a,22280e31,d0b6375d,6dffef0a,94dad7bf,e640a406,2ad696fc,2744cbf6,e667122c,b6861cfc,97fc4ed0,e6193883,c79a896c,79e31603,a67063d2,421845a) +,S(7ac03be7,2ff15233,5ec9c349,98e77ff7,79e5f348,a49fda4a,e52a69cc,6b02c02a,74a9e36f,af0ef72d,b493617e,9474b112,593de375,c845c8dc,c1028ee7,9fd17599) +,S(31a83e18,c03c570f,31c3ecbe,bb787aad,6492cdc2,3e07d3a4,43b56ca2,51c0888f,3cbddf10,9bf08e81,830dfa49,d4d3cf95,224b7a4e,fd6d9997,9dceb64a,a8d7e440) +,S(ec13f2e8,53935ae0,705c2644,d1512bfb,8ea4adaa,d45a454e,f761dc68,c7ace561,54139641,97e2f5c5,5b4b7f5c,5267ea7a,bf36b01d,cbd62765,ff56322,c107f321) +,S(ce8e23cc,aa38e603,70defdd9,37803f02,18ae79a7,3679c363,4dab15a,bd46004a,1ddcf92,92ea77c8,4a1346a,a5f79f13,26c9092f,14ce1992,dfc24bf1,a2da35d5) +,S(77d80689,f7cd8585,fc03cb20,14d02425,3b547962,a282beff,17aee956,88292ee2,466283f6,429248fe,301e18ef,61a89784,47142fd7,fcc5c496,36dca83e,ae8e9f03) +,S(6eed61a1,4e7e7ea5,54a4e43a,61fa7eb8,b8e7fd0d,52de9ad8,e4e9b130,78178a5f,2cb4d228,90af9cb,a3c050ab,12a3dd53,1f1c6d6a,e4393449,219d86e2,6465bbab) +,S(10cb3737,a7916d84,12c955d4,32d1ad46,d8c7a60a,e44936ba,f62b2a26,b698e4f9,35499a5d,11e356ad,fc5960d5,8d6842e8,ea0615f5,e8bf39c1,8c217cc6,7a1faa97) +,S(e866ac84,6040f92b,c52d298a,6ae110da,e16bc797,d6958858,1f63c00f,6cc68211,257803b9,ef7bb5ac,59c6b59d,32a49d53,64c6659a,cb0482e,a9d57530,4e244f90) +,S(5e75ce15,aeb91c2c,e4ce06a2,decf02a1,db85ef5a,a43c42b6,179d4a,2eb4e404,a08d537e,529a6654,a785969c,8d8b0b86,e3a76f91,d9b72d92,992f8215,1b61bd1f) +,S(fa80c52a,12afecf4,7a5b48fd,60fa35b5,ffd122d,8616ca07,1c1271a9,bfe2c104,74487acc,dbe2e60e,e054643c,37cd624b,3dbbc3d3,4aaa6009,9c97cfe4,b3d69e81) +,S(ddec1720,dca13ec0,2eee97cb,445044e8,d6b049f5,694ce5a,efa664d9,d89b6dc,122b68af,feed4f56,b72a4a7e,e20a7f8a,8daa9883,9a797857,8dac0851,1b843872) +,S(85116566,57b70a1a,96c5da0e,fa5d3025,49fcd00d,104a4989,442ff143,a08b5a59,2c96bdcc,430c6c28,9d54806c,9c17961a,8121b10c,5168cfed,a0dc8edc,9f4f551) +,S(7de80b36,89b9dfe9,de2f4fd3,4dbcedba,9ad39842,f105f580,d8d5f6f7,e1eb3e58,43d20653,db727ee6,155998cd,f7bb70b0,9be15c7c,a04593b1,398b4586,baa3c417) +,S(e66179d,366fa7af,a982c480,9578d469,91731ce8,c669d8e6,bdc399c2,a2484b1a,9371d856,28bfb10e,d07c3390,b9f08222,98793229,ca2cf2ee,75d53d2d,e8144441) +,S(1d435048,d7b8bfa9,6df91fa8,f8f6d1ce,913bce85,c2c7a1ad,cc199afa,5da012f1,4e389f26,4f36b2c9,296934ad,5f567eed,30f3179d,6538ef70,f4205219,2c3eac82) +,S(5866c91b,619f53ee,3256772f,56191a35,23696c7e,2b5140a2,89f36c11,c1cdfca7,67090999,33ade86e,3a5d384c,840fc584,2a85087,10085798,913c41b0,e2dc1737) +,S(1e06d768,20c95907,405fc2c6,bd75e1c2,fb9c4d0e,4cee156,94e1a4d7,65a77a01,4aea359f,bd26d7a6,1b1e9f75,5544363,27eea590,fd2d5eb8,87ece7c,41759674) +,S(ee415cb8,5e1ef106,28c149bb,2d2f9e1b,a8083367,60a7b56a,f122cf4c,9b59e5c9,f52aeac6,e2fb8a7e,ca5a629f,b431736a,eec16a06,c1a4b876,94ad8bed,bad88ae0) +,S(42da5368,b60f85c0,9f52c3c,9aa82e66,4868ee37,4b1851e,d37ba6a3,fb717e6d,71f65b16,a3937a5e,b535da,ec530798,d1c91c88,722fadb6,580510bc,5f27ed65) +,S(10bf9254,6300aa51,bb08f849,5acf4e53,b1eb4e57,1328fef8,304189e9,7acb81e5,9b519bf3,482c9516,132388c6,dabced4d,971d033c,52bb5607,6c788a37,a9eb49cb) +,S(2f6456be,5c2c184a,1dbdde7c,2dff16ac,8f504a9b,d86de1a7,d9d3c1b2,bb0688d8,6bcdc62d,4e6184ef,1fd39720,55da6e7d,45cca6d9,4d15c052,8ddfa715,4aa68336) +,S(e68e8fb9,beec6d15,207e7017,c3574e34,102fd7f6,5e5f18f1,e533487e,5bb2fae5,13624e45,da0b6edb,df4ae938,82148590,63094aac,1b25d534,f80ca56c,814a944c) +,S(7d314f19,4b776d00,b946825d,f634f763,e0b5aba9,b1fb0424,833301bc,ab1e94ab,80d402d6,a8dca19e,709b9e23,4dfda4f3,9f9f758c,928c1b9d,842b2d5d,aea3fa54) +,S(fd78e68e,5b5b9522,14b35d5f,a0951f4c,4d5df056,28c5bafb,9c6144e5,c2c33a49,49c62b9,aa91e5f4,be13a209,7f941c9d,cefbb300,eeed9fc4,a12c1e45,37f4535b) +,S(e751f61a,11e0b68b,205fd306,9f4abab0,b2576131,3ac3ffc4,eb4c525b,f2b28f6d,aafd8f6,2fe20722,b180ba67,f9c3b6e8,8ab2b96,956d603c,868a8867,c09ddba5) +,S(6db64d2e,281e6734,a8908de8,554dfa93,d7811f01,2852a306,9e6ed59e,c09a4823,1c1276a9,1de36164,309d83a2,d9fdd003,d889612c,6026817a,cda97f8b,d2cec77a) +,S(4de91b17,fc227eca,652f8d15,8cf0c696,c6902df2,b44a02ea,d05dfd68,e408a17e,130fd485,d59456b1,48458cba,922e9ce7,79968340,d7e5267,b2f288d9,6df924ae) +,S(356ceb61,8c57db92,931a305,4537ddbf,8bad8cb0,c13f447c,1c3fa485,5c0ba01b,6f52d242,ec189e41,d8ca010,cdd645a0,8889206a,4df81651,1e820e0a,74bbaa7) +,S(595d8d68,1ccf61b0,456ec03c,53cc5a93,85e553b5,36033f8,ec56c575,db49cce3,773b50cf,f0718e6a,6a269cd9,65b5001d,f5613238,3e279bc8,fb937580,a76ad035) +,S(b076afb7,234e8fd4,4107caee,8d31338a,5122d785,4707605c,2e5dae93,2e6c935b,a18e661,1921080a,84a74df6,15006847,981b552a,4c3021fc,93967c64,b19d629f) +,S(834a4467,bada612e,2705b0ae,19fc9f1c,b80e6e9f,7c4c01e,5899fba0,1f60cfe9,9215b4e5,f8194645,813f00a8,58f77324,e28522de,16e93e80,93197310,38ed9af8) +,S(d00093b1,ba6eea04,c08df30c,90b2f7de,6e13b42,c645b01b,127003b,5642aae0,87739294,746ec547,4497a951,c26ca6e9,12ae4638,1d0e2804,5363fe26,de088434) +,S(66a33bcc,71bb2f0b,ea36e5d0,f1446ce5,f3d44a9c,b715e6ba,ed00cf70,4c4ce1d1,27d0f5b1,a40fb2f1,e1f9440b,c1c15731,50efa23d,b8997928,cbdc0e03,2824a6bf) +,S(ac65226c,dc40fb92,a9632724,20983b87,9e1a7615,fcbde26,ac9754ab,408211f0,ae633790,687f1c02,52115aff,3a7d5c92,9064bbff,616b5eb0,87d5c1ee,57cf8d3f) +,S(a4b98213,78cb0e23,d46b1359,43b354da,3825e27a,76f33334,147a3ee7,52a81913,2786a9fc,3701a6e7,caf07030,3bb382b2,ce6d7c52,42496130,13382f59,92fec4e5) +,S(6f58e6ad,e4af1dcf,633d3f35,8ac86836,cf0968a,49c2e85f,2434ffb4,2475a34f,70e30dbc,dd567c8d,a6aa970d,3131009a,f5297a36,f80750be,6462f1e8,336db9ee) +,S(9bc7ace7,d55fcd7e,e67a0484,7d0d6902,f053288,ef17b3c2,64072dc0,ae0e94d9,7f57fd70,93f3d09e,53a82818,e5ca4cc1,6b46f73d,2c00e50c,698d5963,8a8f3f7) +,S(248195de,ab1ad52d,fe739d17,a03ab762,927e058b,ae666f2a,4f7e220,3173bb3d,1b1914d,3dc9f584,51ac3346,d05f033a,b793277b,dd80262e,d2ffc219,6965b96) +,S(f6008de0,21c5cd46,d9d811d4,4070a7d6,46105a55,2a68c389,a11161ce,9baaae2d,962cd254,e5b0d724,5ddf7114,32ab2800,16f5583a,b8fa02a8,61b7c3db,eed77d91) +,S(f6dce5a3,a919eab8,c1d850b,4643dd3b,96e5c7e2,a1923b58,202543e5,4ece5b40,c1b88f2a,b3d516e4,7d289ecb,b16b9bb7,4082a6c0,8ccafee1,21abf691,73734c08) +,S(23fd6281,b4958fb3,b94ac9cf,851561ca,415cc979,7ed619bd,15192ca7,7ad39a71,fac12f70,ee38f19,b2dbbd5c,3cfe02e1,b69bbde8,7a45f8d0,bdfc909b,640622b0) +,S(da3a5c2d,7cdeffda,1ff2085f,fcda0ded,eb40bd40,3591395,e4b20b0a,25a1aa8e,e0d90d58,a6cf6038,10bf2891,d51da508,77d3aaad,5ccc971d,944ea960,c943e3be) +,S(22113f6b,8015b2f5,bbff28c2,cd5dc253,c495cc62,88361c27,3e788aa3,58a94554,7b6f7bac,2db4f198,20ca6e90,bab75cd0,983536bb,80051e6b,7da589ee,dd2ae962) +,S(3b59d8f,d59a2e6,89c9d1c8,a4e2515e,73317cf7,41e38108,eaad880a,e3417c72,bb96d412,50614b50,8903c28e,b5d39ed5,b4e735f2,ea10bfa,1265aba7,f21ded5) +,S(3407e5a2,4831b572,abc0eeaf,c587b20e,9339dd05,ebf395d5,378cb151,e0dfe661,49214182,78e4d0be,31cd4e1b,9b0458b7,7e028840,4a0745f0,40960dff,b9022926) +,S(9540e180,47717f7e,f6ce71a8,31368919,e4acbfb6,18c1582d,cb4093f7,caad2601,6fe0f64c,3f0aec37,5b36758a,7f65c7b8,e9329f62,3309900,efdd58f0,7bcf244) +,S(bd02f758,513ef045,af72344,f5d790cc,1c549a23,147a2743,b8c0cb30,891af3a1,3c605d60,13a560d0,d792c5a7,6ae2f739,7631ea13,7347864,4c6bbae6,dde96079) +,S(43b10d72,cf1ba39b,17abb149,884fd00e,56525f61,594f9654,48683c16,88f3e69a,cbce7dc6,1bf71def,95bbf6f2,fb03751b,8a0c6350,9eb9ead3,713366d,8cb71407) +,S(32900344,9ad58567,6ba2607d,c873a8f0,80d9c0eb,2f7314cd,9746008f,3c569642,8c6560c6,9a037d5a,3b2e740c,270ff543,54abb60e,b32ce5cb,4d18ecf8,1ab7ef60) +,S(a1495bc1,91188644,4991e097,5334c9eb,cc277640,f568a7b3,1350e4b7,222b885a,c5a1c341,67cbed14,7f28f794,d9d2867a,9019948e,56f986a0,e69a0d6d,6ae7dd1d) +,S(4640f683,f180cf5a,4929c2ab,5169de2,85861055,67c7c2a3,3db2d01b,c3c8d726,7d6ced33,7e752ab5,c87fb211,903c3a91,e5b0ee78,361a43,b716754f,d0daad8) +,S(91b3f9d2,7e989062,ced571ec,f373ff66,f8775213,95e625db,7d1b5168,e895473a,d7efd35f,56ffd001,bcf0191e,2692e832,99d0715a,edc1a19,2b74d8f3,c0b23b80) +,S(437cb866,aedcc0d5,8d89a41f,95cf5dd0,b355f244,7885843f,c163d54,a3839db3,9d644bce,31992f2f,302c5daf,67e42b78,74bf3f9a,a944e936,aef17203,5ac2bddf) +,S(be8cd347,572e0e46,5c745c83,26799611,a5ebb1ad,3ae74bf,474a6386,6f4a3705,6d39457f,c1010837,eac6bd41,bd4a245e,10bb39f1,77c5633b,92bda8a2,c50a3dd0) +,S(f40a76f2,130d31a8,c560795b,54fa119b,153a9a75,bfe7dd28,cc00ca35,2d258331,f92558a4,69f1055e,251c8814,7a94dd08,44bb2048,31f2d33f,d95858bf,dffd695) +,S(17e01809,b94d294f,c4438a92,6f90a295,5a9ed96f,a201df62,b96b19d1,7e837876,c9506f35,8efcf330,35603c30,880d5625,db15175c,486f3c5,841a14e8,8e5f4e72) +,S(7dbc457d,7ad4752f,8d57a09e,d4e8cf02,6c8b009c,bc29afe5,ce2ee745,61630da9,fea9908b,ca852ed8,3c1b44da,207e8bc9,221b8dbc,7e8b61ba,ab8d29b4,14eb29de) +,S(89fe19a7,6fe2208b,ee4de72,249a503b,88c63e22,71794bcb,9484fd11,1df7902d,8a4853de,c3cd9e1a,713e46eb,e771ee97,b88defe4,7e1106d,88ccd713,4e3a6779) +,S(3753a13f,531da9e3,5569ba37,7db76dcf,b43b5483,1e65fd50,a6ea560e,e70f3eb2,ace8aec3,867312f4,f095b4e0,d08ad314,2005cae8,b1369223,d1301e29,8e51d4c8) +,S(30d76056,384beb45,4c54b4bc,fcdcfe0b,1c1ad5b0,5e693384,8794846e,c93a144f,f79b9c96,8eee678d,b899f349,412bf193,5da9cd,c0ccdec8,2e45ac5e,58f3d3f) +,S(d9864700,7c74872b,40ec273c,59aa149f,8059a1fa,95e5b47e,378ec515,841eb2fe,782a39eb,ea47da96,9361a337,c5e2cc0e,49d43dc,6c6f9da6,6952f347,ca51845d) +,S(40d665ec,53720f95,42ffaf3c,30e8602b,53c52123,e9dd3b91,6a2e9099,8d534fb2,cc420012,490afedb,d840a466,bc27f66d,526a965a,ee653886,8cee46a0,6a58ee30) +,S(f31507a5,516719bb,f07438a8,7b6d6d93,d02a88ca,c18fcec3,9190f358,bab3647c,dbec3898,f884cb2,aedfcdff,402ca4ec,8c8f8727,485060c6,8da0d2e4,edb46eec) +,S(62573f5f,75db743e,7939137b,6b5e1d0d,41468ed6,28d2b76f,ca26ed2d,22532c03,9a4da6c0,d7966d8b,138497df,af25b0cf,2d14215f,ff039065,d42897f0,df33be40) +,S(d0887924,f15c5069,1d7ace01,7eeda410,e8d0a10e,f6091a4a,7b5f368a,42c54416,b2fdc385,527d34f7,a434c1a4,1f9fddc5,add3b1e6,82b63838,da0ecd91,16571c4) +,S(f7585b4b,5f3318b2,2307f34d,3e4bcedb,d4b91eb,180be664,4d031bbe,9b5e3d90,b6fd16dd,49993bd6,4d05398b,9ba7714e,798d3ffe,95393231,395c03da,b3ccc819) +,S(c9cdc99c,198ca8e4,458e5473,3e5cc0c8,100fb0b2,2dc6f07e,b1e99d2f,6a4cdc42,c4c21204,67198733,a845efda,33a5c1b7,67cd8ad3,47a16b6d,4a6f5ac,995dd680) +,S(1a054d1,5c4fcf45,384ead78,e1260eda,dee9e907,84021c99,179a9fc1,c7a3ac49,50ac5d54,d4fad7d1,5fbff150,d70a3ce2,9825e79e,206f4279,f1030d29,2de89a07) +,S(b0796a05,52245e66,56b3ce51,99864d40,aed71b62,3b9d55b0,d99163de,7a8e3455,a061fa65,63a84b15,1ef666d,9f99abcb,f1611e3f,6e26dae2,6be7ac56,c0f2768d) +,S(66fcf877,6ea02717,aca92a3b,5c19387e,72658125,f6e20da0,7595e376,804c3738,9fc66cf2,3195dcdd,7a72225d,96a8c5fd,1c84287d,2189e414,d0deb6b6,76e67518) +,S(3c7caf6e,d3da8c0a,effd832c,f5356114,55646982,3a62dabf,2ccb3de3,452ac96c,e44ca4ee,bb290527,4cf8f554,40c92ad9,6055fe3e,1bb344ab,ace5c4f,80e3b984) +,S(edf616b1,1e7fd6c5,96df3fa,77bfbde,f3f82e7f,93e5addc,53c83933,844e4b73,879982bb,b89ac019,e83f5c,dac1fcf4,fb918e2f,53a5ec35,45be03e1,89bfe152) +,S(7e9af2ac,b3044985,181de5aa,9908259e,77207ab,933c7915,9dcd7aaa,90527eec,e4cc83d9,d29778a5,eb83936d,97bad637,370e74a4,3254eca7,65d0a449,106ee3a5) +,S(32dad830,3bfb015b,6aa6759b,c2e8d4bc,2a9e356d,92d97286,c92dbcf4,53591aaa,ee27e7fa,b36a2450,f04962f2,ee60f9bb,68a1147c,9ecabaf7,e0981564,c1164fd7) +,S(d20720f5,73f1db82,c1a2dc61,d3684d7b,a3943186,cd513a5a,9eecd59a,c9225a82,3b29448e,cac88f13,7dcddeb9,36f02724,6819c6c3,3f03a2f8,cc40a6e6,f8704570) +,S(3a732b5f,5dd6dc77,1d215321,f8cd223d,22f2195,9d45c708,5b000129,94d5f03b,3fc75d80,ea7a0663,c90cc7e8,8a6096f1,b3a8c9c6,9849ea50,f1fd5c94,7928cfc7) +,S(201961f5,412beebb,7e190d75,70977b50,230810bc,b3b69e3a,dfb5e259,d811333c,eaa3f681,3816ca15,dfb9aebc,8888b578,e592825,82dd1b47,ea50cad4,f59b0101) +,S(cb184267,70cd3b68,151f7d82,cf7a12c,dae332,868663ab,4546c119,fe26f4ad,6c395538,eb09c00a,3e973def,8272eed4,27a3ca9b,a77d1a0e,c4e206f8,74591a40) +,S(2c13d3ca,9ddbe3b4,2920f0ed,28622260,2cbc0493,e5156655,30b53da4,7ae3ba59,f7d9f8f0,c58510b2,db28e723,6d9af034,658599dc,fae14274,efbff408,dfd18613) +,S(3ae7b7a3,86ae6c41,90b3a0e1,e5f1a7ce,4fffc405,84f05043,93e716a4,3ec83d41,643043a8,55603964,c46e3ba0,999c73e6,ab34703d,9dcdf9de,1743db7,71591bd9) +,S(b5eea0d4,ac4d0a9d,e37fb1d9,6825233d,a00f26be,86c0b640,f0fb34c3,465bc441,9cb5b93a,56d35b2f,2d921c4f,15b4ce0f,fbb9240d,30754ace,f16b3019,54732e1c) +,S(dc049453,9b8d5200,d513eeed,edc2afdf,e76146db,358a86b4,12ae9e28,e8501e3,6f6f2d25,b331a4b3,686adc14,c26814,96004900,34524b53,8418fe5b,9776a3bd) +,S(821e937d,a6fae1b8,3b6aeb4c,f5315bcf,77b2fb07,d0081889,80478765,cea7f398,41405d00,33224982,2acfc2e7,87be9658,7baca419,14b70315,c1a57843,3f85aa21) +,S(818bdf95,f55a8e51,c0d08d83,29574c28,1ae3397c,f6ac5224,4d82ea53,8f465c60,bfd41438,46dbbf6e,3fc442c9,7a66e8b5,32445d39,fae8c473,51e0ee9,9a9a53f2) +,S(e3bb3262,36533fd7,84fc6d9,84cc5590,2b03a19b,6c956665,322c0bb6,264b6d72,bbe4844e,2be51197,d8d84c75,ab83cee7,c9ed7dff,51eac125,1161e09c,c1078aae) +,S(36e3355b,5f946199,b33dad7f,b42d1245,4cf8126c,568c4be2,cb2abe4a,b83decd2,fbd5d87a,8c012064,3ed3441e,ec686237,1759ccdb,4a7f564e,c2ff9584,ab824833) +,S(bd7fc193,1b06bd7b,c6c274ea,73d33e71,1e1e57f1,e6bf7a8b,6452d979,777aaccc,95b84e3,d8c41224,c74451c5,ec8a23ca,35436798,c2f34ad1,b1cd095,2f0170ce) +,S(b82cb5d5,2e026caf,bc075968,6e1c6c18,206231e4,f25c956c,b3a05690,8c72034a,6417cb0e,f1a18ad5,e1a2a5c6,945f3b38,b0522ac8,70188640,80a0f33e,2796b042) +,S(47d70d51,e97fad87,fa0b1c10,43246c0b,32108c36,734c90ec,9de5a2cb,c6227682,6d5a2cdf,e916fe8e,8b45d5fe,14ce650b,79a3cc9c,e4f99aae,2e9c449a,a79a4a08) +,S(13fa7ee2,5ea49c25,200b40e6,b9232eca,16dc6840,4f76b43f,510c8a12,d520dead,2722287e,35c9f98c,6041cb15,845d515c,870f5943,74a1ebd7,36f973e7,5e6dc30d) +,S(c1350b7b,2a4e73bb,90d36674,771d5537,1fa647ff,c490726a,3748e7d2,e72fa7a,2370f4c9,403ba7,8e950274,bc1f87a7,bc80c1fe,7618169d,5c9bc5c4,81e1badf) +,S(dfe512c6,f884588c,80c1ea7e,1da4b3db,ab8d4beb,60749f40,9402d583,ac793e05,b52da5f0,333b904f,678dcd37,a890b79,e985dbfa,b501e61c,89930678,5a0bdf09) +,S(88da191,2face14,e6f5ded2,30d303fc,867f9b26,d85c2299,bfac1a23,9757b34f,4236025e,f82eab9a,f1fd3c12,42a73cb7,fa305e5c,ef6ad5ab,ea62cb8a,4d74bbc8) +,S(b7a82133,7cad0eb6,c1de7b3c,8aff8798,8ee936c,921a7dee,1434156c,c6505abe,d03b693b,4fbce189,a552a66c,3ef4586,35454006,308c40ed,c7dbbc29,75361b7f) +,S(44971116,c14d80b2,f0f88829,fa1fac44,ac44124,11ac6e92,fb898e72,a0aa7ed3,9171395b,3cac83ba,18e9a0a0,34fec786,986534d,667b0521,801638ec,e19343f9) +,S(95f0aa61,8bd8573c,81b2dc3c,aa16b577,6ee636a5,a8f9c963,b8a45370,7f35a618,7f2300b3,90006ec7,37365423,2b488d72,edf5192a,a1d5afc9,4bc95a18,edf5532f) +,S(e1bd29e8,778a30e7,d9d91da2,3db2da23,bc2e8d08,d5cd170e,8e753e3e,917b728b,592894f2,114c11d5,f04dd5fa,6b341cb8,29c58e1d,a7adb51a,19d881be,39f87eee) +,S(f6110619,208f64ea,8f0e8164,1ffe9f32,8e706427,87dcf8c9,28ca8629,adb99e7e,cff63452,a596744a,75c5e8a6,badc4937,e6f2c860,39196251,30784499,733651a4) +,S(4a3f7c9f,1ba0f01f,d6d42aa4,284e4481,ed1433c9,3248da63,76f25b62,d2d2348b,dcd4c18b,2ee4e447,3515c727,1467e6b3,86b6e640,834598e1,4ce3f679,47f5c2b3) +,S(50fc4d78,3964a68,b26689df,34d996cb,6f229f2a,ed017a98,4e027407,5fd730a,7ccd6964,c6c5ab52,5d31db1b,ccefc3e2,7a0882b5,8586a955,b76c754,9698a7c6) +,S(1bdc6b52,e92022,229cb15a,6436d601,26c640da,bd9697d8,bd0c49bf,606ce554,1ddb0cbd,e7b0816e,b65d7ea3,98da0744,b3ff390b,d2e13cbb,f8fe85eb,8f3d2059) +,S(62dac912,48f29712,c3126524,90db807a,af92d3fb,36117f6a,f5c7f5f,de317000,b3bc4dd8,97a2fcf7,483c0015,f793810,29bf6f01,7be37530,18b55e35,4250ee0d) +,S(ea552caf,1d0810ff,24eb5089,31b57573,d8eca976,2b314f9f,38301b04,ff5e2193,68181368,108c4fab,7c58bcdb,5bac3a3e,31eb1b3b,837c7ead,e691b56d,e24aa832) +,S(7d6132a0,9e2c0af4,9e3359de,a750551d,7addad6,8bdc602f,e65af48b,bc1127a9,5bf6234c,903e5f72,45b46187,9d780ffd,72aef438,c0b65c7c,d0b5fc2f,8ad29d16) +,S(916d0d6a,3d08a94c,604c34ae,8c930edb,5ad57532,4dd5fadf,7a4841b2,775c475d,e3cd9b7f,79572001,a1ad9c19,2921ede7,64b12210,4d4d8796,a435eb13,d883d391) +,S(804128a3,d982b50d,203135a9,c59449ec,c43ebb35,b2bf5266,6b710975,a3847524,bcebda70,4364414,dc269d2,6214968b,95ad5bce,239ca9be,f10fa1bc,d6f31757) +,S(850314b3,4898b572,5898dd9e,f39196f3,cabf4026,8248844b,1c3d2f55,a3346f2a,eb8d17e0,3c9f7fde,29276d95,c20b657f,af2173e3,7c620a0f,d2ea7ab5,f4706b33) +,S(fd879539,8c0ee90b,89aa731,a4ab60b7,be0375fb,59932879,7bd73390,58d7aa8,3fd62aa8,35d10f6f,8bf3338b,b48bbc33,8f235cb0,6bcccbe7,56716129,abe8159e) +,S(51536953,12e7c4db,bb18ecbc,26c51224,8f841792,e557e879,8eda9db2,c9840357,175d3e7f,92ddce9e,5595fc26,725f2c09,fc322b2a,251fc323,ad3c6f08,44badaca) +,S(8783f2c5,f7325f73,e5941ec3,5f91449d,558e31f,28af335b,2fde477,86aa2808,dc602736,ccef3e41,60b100a5,ef99c6e5,c59734c3,42b545e6,21d9b03,daf0030c) +,S(c871ab31,4afd8d5a,a58a0cc1,a5eb49aa,f25b4b3b,6e0ffcf5,38851576,27c0726c,d06b7e2b,f44d36aa,fcf653df,a675bbe1,36a18938,60864df1,fbc9e604,5a3707fc) +,S(40efd5c2,1a9807bc,b34a44,71066619,a2bba48f,c306293a,ab59d9c4,b30e9b23,85cf348,4df34dad,2f7aaee7,b8a6f585,4de1314c,215f6f0f,e5a38e61,f3decad1) +,S(7feb5d9,844798a0,2413cae7,cd791e6f,54250fb8,12f998ed,e0ea6eb1,435986e,d90ca7e,8e800e6f,fd0ea027,b8a379b3,9030a03c,7b111d68,465d2a05,99dd358d) +,S(1b2da7e6,f9fa412c,ec873512,7328f1e9,ea77501,5741a284,12018290,76a79b2d,9fe58682,ba3f6ee0,c7b73933,d14ce656,e3fe49dc,ec7a5643,efa07a3f,1a4f26dc) +,S(d7fc1f3f,7a6bcaed,1a84e8e5,7127a6f6,37d935a4,35500e21,47e8fe03,d3b06066,29938603,d89fb118,14d33850,451f5c1e,bc5a5943,70c2d8f0,1d9bed34,f0b2e940) +,S(45352264,1cd962bf,35d8ab65,3d8d6c97,75782706,1454a2ba,3d957152,e177ee5f,de5005a4,3989b6c0,cee0a71,b534137f,b946b262,bfe353c9,6a217c06,c23826b9) +,S(91733546,dedbbc4,c7c32af7,760e0a4b,c2bdf82a,73e2a91c,2d70afb1,100b84ab,e60a6ca6,f2a5b12a,307cab41,8793b7c8,b7ecbaf5,18166c61,acee16ea,83071a3e) +,S(26bcacdb,bd4cabe3,e7adc5b9,27465ac9,616725b7,dce240e6,37117a5d,80a9ffb,172208e7,6603837e,4a9cfeea,22bc6002,a5cb8f1,36d73dd7,ce30d010,acc05db5) +,S(18b520f3,e997b5d5,46a1d81,ad95c52e,7841f14e,11e9d677,de918fae,7bd408d6,51b0cc1d,4c6ec5ba,e6c587d0,d6489663,dcf74bbc,d93c4839,6e4203a9,caae57e8) +,S(e25c2492,b7b25c37,cb88da91,cd76021f,de8511cd,27188b0f,d4bb4fe3,dd845e8a,244facfc,a7dfe65d,6e1d1d84,9bec4e4d,17af0d6d,2611333d,b8b7498f,96c88bd6) +,S(97e572bd,300d9649,b9de3c8a,b02d4ce3,bfbe4ba2,68844329,85971951,5c34a535,324a34a9,39004c24,b2e55e66,83577259,6c9cb2f,84378bd7,e77806eb,75e77070) +,S(4d31f4b9,42526f1e,769bcf70,85f39523,60475a0c,3f8d0a4b,c1fd6a07,a4765fda,27815d6f,3b083965,8fcbb540,925986d2,bc6d1fed,d1c254e2,9580f413,99afa899) +,S(7344c521,23968b7f,7ee12500,e9efa4c3,859a72fb,cb1cc9d7,af91e6b3,b5bbe152,4794848b,1541a965,b7527533,a6d43398,d619df34,2608021,a26bf9a8,76e0e4f7) +,S(1d099181,8da474dc,38e08fc6,d97ac823,be34f4a9,81adee58,806f68cc,ffe1ce9,f5449d7,c69816bb,6f04b32e,69e46771,c7910f3d,77cee6e2,af75c293,119f729d) +,S(84607e2f,ab205637,4b708486,51e84966,9c386eb7,c6855a1a,837c8fb8,5da8e7c3,975b5227,26e4625d,cc5c55ee,22dc667f,1fff7c4e,417cb4b1,45bcb3a4,53180ac3) +,S(3d2ad8dc,11a9103b,2f03b3b6,24d93114,83f4faee,c4b9bc22,f4f8f559,16bae70c,b4f79cd7,27d433f3,72735afd,64ef4da7,de9ac35f,98b3b6fe,5de956a5,ba93f9c0) +,S(2ad5f6ad,c7fe8540,8b9bf547,a564727f,374e9194,460f6037,ee299f83,e842c883,f613f0b0,8e306fa9,fbf39919,e3040d16,ede4dc6f,9d45ce42,e63f4b02,70832f9) +,S(ca92aa9b,e8893819,e49fc29c,dc98a42f,e23084d1,fcc37d19,3e9c638c,db0f2f93,462a5ee3,2bcdca5e,c6bf6819,32ded511,12ca847f,7e110405,a893b011,874a66a2) +,S(4e435dd7,ce2783f1,5bbded75,e832665,e4b4cb00,b50e2a69,d986d2b6,d3d893af,cddec0e7,1615f7f5,769cf2d,ee649723,1218fd34,91a07fa1,fe619f2,26673042) +,S(b1d936c3,fa1fea01,e3e28332,51f3790e,1e0f0038,58656e8,af53a72,118cbd6b,183b67ca,8039f372,d04b685e,c515466e,8ca1fdc3,7b2ae8c1,ebc5fb02,9c0ced9a) +,S(77282290,d994b6db,10b06247,1b86caab,e4524850,22a1e63a,682f92a1,ae65019c,feff37f,1fee0cb5,569db439,a7697327,1a2e4254,a9125ce6,cd94fbae,110f6363) +,S(acd0184f,18bb7c72,f7b6ac5a,7ba3f617,c40e159b,a3dea242,ed8e6c23,ad89dc82,3ab71793,fdf23305,aaebfb52,982a2603,e56d7b3a,5430585b,557d3406,42fddfba) +,S(933e3401,91e41c37,69b60410,fc0ac56a,e5bb44a2,413921b3,d25a52a7,14015cf4,ad3aa53c,76c106db,6187f4ab,755d077d,c6d878c7,64181565,77bd5d3b,affad12d) +,S(6e02abec,969eb027,bcea0303,6648fe60,da6a7c67,d1e4df3f,a34c1225,36de6fa1,c0283bd0,9fb2bc2b,19bf5086,f1eb5c6a,a7dfa258,64c73647,8a6cf0cf,c5ed5c14) +,S(2b86559e,82e5ea58,423163f4,448327f4,2429f1e3,14097621,667cf1d4,f0af1ab3,35bcfa55,9e2a71aa,4ea25edf,f9e1c59e,2274ade5,9354e22a,9cff37e9,31258107) +,S(1c02f45e,5787587b,9d68df04,66df67c9,552301d1,3b32f50b,8c9a2d5b,c826606,5f5de968,b39e9263,c1624aa8,811a4391,35150e,f8167698,c381388b,18a232f7) +,S(d0a65374,7fdd0c5a,68c55060,dd4ed734,34956730,1997d07e,d333b5a8,79894eed,272fe0be,bb192ec8,9f2f64fb,43f3a3,cceff7d2,cf92cbf4,4ddd8fd7,b104b85f) +,S(bb48b81e,e0dffe05,b6b8d05,5e1d2e5,37481eb8,2ce2bb81,cfdfbcef,bca5c6de,717b99e9,63d59e1d,66c0737b,9843231c,9c5e1bfb,26820215,78e8e01f,9e5a3fa8) +,S(23901c4c,625d77bb,1d390891,6befda04,522c698d,3c4e82c5,227c3975,3d7bc3fc,2434bb8d,98ebf9bc,42459328,464c4a7b,b26f258,2d454209,af66edb7,e84effbf) +,S(2a150d7a,961b5c28,434cf4de,ab9bdd3c,d019f667,67437158,c0f3fc38,54de70ab,e0d4756,9cec0eff,b155d7e7,37ee49d9,863374b2,4c6f4ac,876a80f3,7fdf7461) +,S(d42bd53b,1de9e41d,6e5ada81,3b86370f,ec1cfe1e,cc8ace39,edeccdf4,e16e7111,e3d4de0e,e5cb0d3,e3dcfed5,a09dcc,28c9f1ec,969d70cc,ffbd34fd,d0ceca5c) +,S(2a865f60,413764f0,d50adde6,4825eed1,134c6875,d1712396,938cd8ff,784b743d,4b628cf4,8e2a56b0,2142bf67,8829a388,929a0c0,5784426c,ed114f21,ca1dfade) +,S(2189b2e2,e88054d9,c71c2321,8cd229f8,a0165a15,650d1557,3eccc450,671817fe,6b9e0fbc,f9b9c354,644dd8df,3ec14217,66fb6783,5c698a1f,d598d074,aae79d19) +,S(e619a8d8,d63ce9ec,7f11cde4,1cfd33e9,62884fd7,471a4e67,9b9fd1c6,8537fefd,d819f364,5438c886,915f46b,40fb5c6d,6932077d,6f9726d8,86b9ddc4,d5a552a0) +,S(80c0df21,91bd2fa,2fa21bc7,ea86e54b,ee25d9ad,43893869,1cee20a9,b5792763,b27d7eed,198a695b,405cc3a,9204242e,45833ab,3b9feaea,f81db33f,938dde53) +,S(cb3926e1,eaee7f44,6f2eb390,64d4ced3,cf8bfda7,9c54a25f,6894be15,61c2d02e,35d9e098,6612e1c6,fbc2dcf3,54022f34,5b2220de,139d1ca7,5dbaabe,46c69160) +,S(82e82221,5dae0056,917680ba,a3233d29,23a2a0d0,68939d9d,2e2fe013,9aa2a8b8,f28975c9,b27352f3,f6a2972e,ef33eaf8,5d0d0a4c,673e3495,afb71869,e768bcfe) +,S(6b48f2d2,d756c7f1,77d5d33,cf62e419,b32fe0e7,352e84d4,d3056571,fd837e52,d4741717,3212dad1,b476b8fb,7ace774d,fdd545fd,6f99ba1e,b701018d,f762ad14) +,S(6cc8e1cf,ca1a026d,c1db0d97,46029b6e,b9895d7,61f66549,4f29cafc,1243b56,429b0dfb,ca05d077,d4d87022,d5ab333f,d9068170,5e246fbb,6861bd07,7e85b500) +,S(fe3de551,3fc157b6,e5bfbe45,d88f9339,71ff5ad3,c436ca5f,21794899,33f01e9,a50a9cfd,8aee1546,c422c5e1,494dd42a,db36bf43,89bac501,38211c21,803be0db) +,S(25140d46,a9453d6c,9370c901,6cb163a5,a5faf371,50152526,b01c7454,56b995de,6e00dcdd,82ee197a,3d5ca028,86fd7fee,56319f7a,925a39b3,becba6b4,c806cc11) +,S(4b9c4d2f,bbd879a7,de69e578,a2ffc7c8,8a0c700,f27f2e7d,cb8e0c2,ba3654f2,4c876a6d,7778cd81,bb02c450,5867d448,c78e9884,c72af037,55a66d7b,848e248e) +,S(2c11d305,3eb4b59d,8e8319bc,2b62624d,b97244a4,47326f24,6b83e959,5797c2f8,41e096b6,a1d2082b,c852782c,74a02cea,55dc09c,64b9d19,1265c1ed,9c306340) +,S(9a515c26,394d56b8,77c2b70e,ba1745df,9322810e,63c379ac,1c2320bc,48baa2f7,5ccafbd5,d1dc3d86,4a7ac805,adab05bb,5eb27f8f,dfabfb1f,708b2e8d,42e097e6) +,S(791a6bbc,91321ca3,6e017798,1a611cc0,db9d2600,34d2c26f,5f6fa5c2,ef7a5fcb,4cc5b203,db4459a1,f396cb31,acbaf9ca,18446f1c,cfded245,a3b32100,38417ba4) +,S(ad40b691,d3eb6ee0,e22e6d7e,1e0eafff,7afffe6f,2e0e3b75,103001f2,3a9653ec,ff7b436,47c2e09e,84f90910,2b2abe7c,2d38dc2b,151abd2,4f92d214,5607cdb0) +,S(52eeb361,405a56a1,331e3fa4,b854156e,7c403961,240f6003,135df1fa,8f3e475d,128e88f9,1f089e60,61d3df85,fcb2c50a,b0e67ec3,a7e5b3c7,ef1f53a4,5d5336c3) +,S(fe1a5ff5,162731b9,7b4423d,ad1b5169,5401920a,6b1a07c3,6ae9a25,ec3fbd18,22076aaf,ee720a1d,96e0987a,c7bb8756,b04a6b25,ddf5823e,e2f93ac9,e54c85f9) +,S(4c64f48c,fa628f72,b2897c28,4411684f,c0795753,60b8633a,188a89eb,e7fe1ea0,2eeabfd7,1b976ac2,acff49fb,bd029ef1,a42344c5,489334fd,393cc4a9,c305b4d2) +,S(44cbb9b1,7ec26b5e,3489c17d,1da0776d,539d2efe,d9317987,b86225e8,77b4eef4,f5c58a8,6ef02531,bcffcd80,ce788f5c,e43f5ad0,37e940bc,70d8411d,27c32673) +,S(2a5a456a,99eeea58,761c8802,7a86a310,63cdc681,b4ba0e2d,e5bce690,db8f3e84,7c3a47de,ce538330,49e998b3,4415c46a,2ac5c633,1a074e8a,8b4cdcc2,c6d1770e) +,S(566c0ddf,ebb82deb,bc867f76,e2fc5ce4,71249a9d,1b659237,2bfbf9ed,4eb6bf04,76989cd0,e0ffe1fb,a5992e71,50272abe,8a483f5c,6bff023f,3e5e1265,3598bc80) +,S(6fe42288,6d5d8232,4b229084,b1b2924c,b6c45080,3aa095ba,aeb2dd14,7b6def9f,b3b394b3,fc2682be,6e8c1e5a,ef2c87ce,eebe8d98,31aa60d9,ead74896,d7d9a38) +,S(35b45332,b65703f0,4feeaccc,39e04e1,72e58555,db94f04b,1899d835,9abf996b,6643809e,ae897680,5e37891d,3a241094,27ad6dc5,48429a07,64e2e12f,e89c2d29) +,S(17288055,5c0c5643,bd740b89,bbe47949,58ddb0e0,786cbc80,84d64ff7,838930da,f60cda88,7f85da2,3fa719f1,29aab43b,8b9a1578,53f91836,3fee5bd4,fcd16a2d) +,S(76eb57a6,c2d7bb45,d6faee14,4ba7c798,2d8ab2f0,5240862,aaf32c22,77dbc985,ef7cd7e4,d10ab9ce,4551c6ad,18a3ac6a,bc851768,18fe0805,f1c6107a,5c8c291e) +,S(1e5b38b5,81ad0859,454370f5,2f636726,5987e7b3,981af60f,a987c4c0,2440040b,d9817e99,89af200b,da690446,df5d8681,92808bee,91ba077b,400e8de2,712c2ade) +,S(ee17e98e,12a9efb7,c27aee78,15da31e2,af0d3294,40e7dbe1,9783caa0,2bef5709,a78346df,4d7dded6,9146931b,f1ce1b6f,1aae295,50a877ad,5f2dd0e6,adb43e42) +,S(bd574652,1eec6a76,7c2a14fb,15c85590,f7a19e12,342d09ec,67dd98e1,7739a81e,f26894f2,b8eca34,493bf871,dd6a133f,efbf1ab7,687a15fc,336d885c,6f5698a9) +,S(63852cb9,391a1ee0,23947718,b27c51a,8f9a5d0f,2f707f2,d0afd728,6596aaed,9d7c8c01,102abe28,43a7cff5,a1b15fa8,b56f50ed,1a034963,2e867007,e946d639) +,S(6c3fb2c2,d49c1c29,4eff674,158a3971,f65010ce,93f53614,ac9e0497,e31c296a,ffccd06b,98cb8021,589e833c,9c8b3b38,67850545,7e8dcf2e,775bbc71,47243707) +,S(3c29a60,103f7f0d,6f9a186e,48ac242e,46a525e2,380c4430,609f26d,6c3559bd,9381e8a8,7b4bdf9b,361acf28,cbe43e1f,a8fb073,ae2d1d09,6df7813f,bbdcfe22) +,S(bb76e94f,6f9ceffc,53ee4b3b,e27d99f2,d02eac69,8a4865f,9cb0293,a68c5eff,9ae48507,33f5984f,21726a37,c6ed7a79,e832af6,83afa20c,ee5d117f,63ab7472) +,S(422fcd5e,d2774d45,6d5f6312,c716582b,c142fcd1,342b71a3,d729643a,d022b492,b6d75412,aa9d6ff8,9be3a0b0,17384764,35ad4408,b544b53,acb5ba63,119b6bc1) +,S(328db4a7,9fff0037,c79aedeb,e8895e37,75b1e6b0,4d0a7a32,e2fcabe3,29c60dcb,40a2fab2,622ca3f6,39711923,812d8687,9d92b15e,ceaf5855,a970cf32,854b8970) +,S(4269bd58,abcd5e92,c62b0895,1c5ae948,efa1c96f,39ad3601,5e28d809,74da818f,1d1412ac,57ae762a,c3918ee5,33577c29,a8e63afd,c33b69d5,e6758416,6ff87b65) +,S(6c08ab40,97320e51,f3c571d,3beb7d7e,cfb690b7,af3d449b,50bfd276,290b8830,aba73078,edbed082,2164c850,5ca4bc58,6e53b174,83675f9a,26734cb0,747320b8) +,S(f4929f5d,99d0a5a7,3d20a223,c84261c4,6a085af9,fae2fa8c,4a025489,30174c22,afc89b10,7a38c32c,a24e947a,d8efd761,cad69f7f,ce0d595d,d4cfa849,201f6178) +,S(5cf5baf8,726c125b,e1499cb5,3f33bc0,37c983e3,b03f37af,6b48f3c6,29827611,17bd2e3c,d12adb0,5502a9a3,aa418cb8,c3809868,56d00c5f,319c34e,66074a65) +,S(c4639023,b41d90eb,2b275a2d,b7ab632a,592535ff,b439491c,f0e4e692,8188904f,738e1a93,5ace46a8,fb4f6ee0,b9026314,d8c243a,8fe08f37,b23b9c11,11763de2) +,S(a21b2fc0,2a60cae4,e694f206,1bd083be,5ed681e6,53af9271,a8ef9983,5807ce92,7f80d5e5,5a684392,939d6d1d,537919c4,99e799e3,4bdbb27c,b3d79587,f08d5194) +,S(7841ddd5,80f9f3a6,e702b0f9,3e1a4158,5e2c10c8,fcf98add,2a0f6286,c5d285b9,4dabb8e6,2aef6506,392b0fa9,4e2005a5,ad03c4fa,5fb6de65,2e89b31f,6e5ed166) +,S(5d5fccd1,378e4983,8d8b05d,41f89660,1b3a7c0,58df493e,2a74b55f,d8210356,a7e7b0ad,fba08a37,6fa3cbe2,75dcfbfa,bd0629ec,e8a5830d,d6993ec5,15ccf447) +,S(7fbd50a7,360c09ff,fe55369b,fbf6be2f,70cc5965,340e0489,77e01b68,2ab6c9ea,17ff93bf,4fc95325,26caac54,89e22f4b,265f63c2,cf46ff6e,a5b1d387,98a9b72) +,S(d6c8bc1a,479ea533,e99afda5,95365a32,cb1f3a26,72b4b960,2e039494,5b379061,cbfadb4,a6039cad,67ded1e8,8513dbf4,bb1dd3e3,437c989a,1df98b31,d234975f) +,S(5753de48,683d633c,11103cc5,b1bb04e1,5a935e99,297c73f2,fe851d91,5d5ea18a,10ef5d7e,ca1580b7,31ed4fc,3cd606b9,e6af8b1e,dea8bcc9,b91d522a,af361376) +,S(fc0d0265,b6cfdd0f,6b755a8a,c87f0ad5,b5a19894,5348c719,e9593566,91a638f,c5f31483,3c166c18,8c62415c,e58297fe,157fc6e4,b8e36b16,ce28cc75,df9017a6) +,S(61570f72,5b030b63,def84933,d0d25039,cabc8853,e5185302,d3f2d3ed,2611eea3,b3edb685,379c0068,9e9f522b,a5ad9163,9df723b6,b5c3eb96,3b05e5e0,a4b8fa15) +,S(5fa72a54,36b2b7eb,c15b34a,fefbb908,acbada63,23809159,66785d12,fbb3d6e1,1c027ed3,a34e892d,4b3d56fa,7a93ac18,663e475,a16a3d2,fac0ec90,be6d9ce6) +,S(5296b2b3,9f179516,d3cb85bd,5b86a9fb,274da608,be6e95b6,c44267af,187e2371,728aa26,e5869775,9c392558,34d00992,73eb6986,5db38b3e,df87f394,31c75dbb) +,S(b145c8b4,4c3f3c77,658899f0,a5b97c4b,dc2b195c,aa56b328,e0535217,88c80298,c73d96b6,47c2e764,e36caa26,8ebfe40e,c07b1e0,947e392f,be2a9095,7dba2595) +,S(bb585531,3cd05f8f,7fc96d8b,6e5194fd,2a70ff55,e7a7c067,cfbf54bd,129d87c1,31ed0367,8d24c231,8c4295a7,90d31094,e54ca68e,47b289c8,45b2f638,64812607) +,S(c6ebab34,ab48c0aa,aa5243f,c82a90e1,9a2012ad,74c925f2,e4e22f6b,13d6e5e,8107a95f,28e11f9b,bcef4b22,c4228c0,b530cdac,1c977640,53828b8a,15fc065) +,S(92e6ec9f,83dd27e6,3be3b0bc,8ebc521e,d84219bc,177f15cf,1bc840d5,be2b551b,931aabb1,5b3479bf,994f7eeb,34871b04,81efa404,c40e063e,59aabb77,2553ac79) +,S(280280ef,424f01ec,3fff321a,61dde1c3,4e674a56,7142c8e6,643ad1d7,e2dc4d51,84710eb4,5a88503f,b1078d06,26522501,fc165ebc,ce3b90a2,925ab1be,3c9ebfc4) +,S(6326eb72,abc4017e,c3f55af7,6a50a4a8,d0074ce1,2f5c9e08,146682ea,e406d047,53dcc346,7b61d08a,204a70b8,7658e4b3,c4016c8d,b5f03004,af6b545a,60223871) +,S(6e59dc29,408efda3,1bcd7b05,276b9f8e,bd9caffc,7f22c207,61f9fd0,a281ecb8,81c60999,45a6a834,8f2bc7e8,4ee002af,ec5729dc,aeed8187,87060c68,c2763887) +,S(100b0cdb,ed05ba0a,fcfbedde,94ecb25a,5cacfb8f,bbb80fed,1a9d87ab,72e4b5d6,1ac27087,8d6764fc,ce5f036e,ea50294,cf38c4c9,1ca9c3c2,87718505,491e11b5) +,S(95865771,e313a1f8,5629585,7ab9aafc,68a124b,6ae61f1a,a7b6e9f5,fb5de6b4,1c5195a4,338bfee5,9910935a,f5fa6091,7d06a2ff,3908fecb,b3fbe30,b0b52b41) +,S(6962774c,9035ce5e,fbb8e715,9d381004,a1828d67,38082e1f,45307ea2,d1d60eae,e9c36d21,6a2acbe5,5f9f9535,bea4b38e,7b75a149,3a281e4e,11b19064,e282c036) +,S(8e0fb8c0,d2d7977a,23f19efb,aec886a7,5170cd08,6a035386,ac784b15,9fec90eb,1218a3d7,6306cd4a,b3debd20,9bf9238d,ce00984f,47b5fafc,b715e2a,655ca9d9) +,S(6e9ea5e1,127c4c60,a01cd278,ac1dc091,e768acd,41566200,47aaa32a,e9cdf5e4,bfad3214,9a299887,c74bcb20,33e01704,ace7c646,eb00dc71,fd1e0461,af05a6eb) +,S(60fd55,9198e1ce,86c401a1,d31d04a8,fec7da21,4efd01d7,f2081027,1c49206,4f234575,cf4e6150,16ad551c,2f8e7635,3718b626,70ed30c4,a4c15e9a,488e0755) +,S(d413c7fd,2c2bd34e,2ab3e871,38495543,3b5ceb32,cba0e9e5,1e0ce198,cd5ea806,b585f836,7ef44ee1,8e32dd1d,95d6f8eb,555d8e53,451e5d8d,1cfca993,b23e344d) +,S(e26a95ac,c0855b56,b702cba4,abcf2004,c7343cf4,72056bb6,161ac077,bfecf98b,36a4834e,4532fa30,eb1caa21,c1572c46,efe4f7fa,e3c370b8,3f1fc221,632f8c2f) +,S(f0541a0a,d29e3806,e2812aab,ac185a55,687e058a,eb17157,e00a1cae,5a9e3d9a,40e81917,4473fbbb,58d40f1e,ccb2444e,ca4a616d,b0efc710,8f887c09,dd04b4b6) +,S(db1112bb,394f5e1a,b315f575,e2cfb59,4b83b599,6c82365c,c2095bdb,eb7c3cb9,c53249ca,30eb726e,6dfdb792,4db693da,f9740213,d87c410c,afa3ade9,51f9f688) +,S(2ad80407,9fdb7722,c96abd1d,35e76a7d,30948c7d,7b1e62a5,ab0994fd,667103df,5289aade,9f71ef7b,dce049cd,3052f8f9,653a9b69,3876b607,7bb42d77,9829bbe) +,S(7bcd5085,eea0f429,238c23bd,bc14017a,f8dde478,9d99b2de,325503f1,fcf7e738,7338f8a,7980de0f,404764be,7fb22578,ee820c6,16044f18,ad12d4bb,4b35a2a7) +,S(85819e4b,348ef2b6,d141baaf,3297248,7f34b594,8d834249,df465fc8,29a83188,306e8693,e7e718e6,39f48a1f,7dd5d977,9da12288,ef3edc6b,74afb1a2,906f931d) +,S(8d035a4b,5905b0ef,7fd9b050,ac1c006,2c0a8d84,1ab342bd,9444d101,92ed4a79,1ede85ef,aa83c466,4ac1cc71,c2d4027f,632f7ebe,2a097d98,9278cda6,35e2e0a0) +,S(bdc84795,289c3268,628904fd,5d8ef1f1,a89587f6,652aa883,5e83c47d,c008c282,1d8342d9,e330c123,7e232067,6fec10ab,b19c0d76,744915da,9980a9a5,6459a61b) +,S(75dab97b,d9e6571c,afbd8ce5,ffef58b5,72b6d8ff,838777f9,21834b61,1079c079,d048e6d1,fe2598db,31adfa59,8a445f0f,7f97ea3f,dbf8fe92,f2aa495,ff033bdf) +,S(b2a4a872,4a6ccfaa,8b8bde86,64fef1fd,bf9d4edc,215f9f71,738885a9,af19b42a,9bec2c2e,76be8104,f2dc4ea1,3e1ec916,23baf856,a92863cb,33b2781c,35f9060d) +,S(caeb3a77,35824f9a,b24e364c,789fe66,4729fe9,d6577ab3,f9cc857a,e1c2bdaa,ad96c92e,e91cf44e,8f0480cd,106b115f,23f0a30c,fd6ab638,86ee87cb,ba5ed885) +,S(a897e41a,75e6bfb0,78c272d,ec320e70,13afb506,478d984a,b5532b04,6da0502f,136cff6d,896be55b,5da484b6,15a09e9b,13453973,79fe4157,64ac5b5f,35aab82c) +,S(a33679a2,dc5080d4,a77fee11,5de9eab6,d32e6479,bd4fa795,3e4a03e5,3242412,1840b712,9ae52592,d99ee262,a56ae597,37e2202d,2871681c,6625de82,7c57819e) +,S(3183fdb2,b5ad14cf,9e2ee00c,e23b2c42,dfbeab54,acdbf786,622a83f,4db62fd5,7501e003,2ba129c8,50c0f17d,2a16b3c8,602c5225,1bac7212,6d454cd5,fc35a92c) +,S(aa6ac020,42f80323,ca77289c,88dc702e,e354fe1c,eedc720,2b87601d,7641b00,3ef01b0f,8b396221,8c5118e3,2168a6aa,ac901e02,5610db0e,8cf2ab21,bb06995c) +,S(f952d843,386eeef2,64b1078f,d835308d,514bc162,559c8f3f,c8ab5c18,378b40c7,fab32d0e,850f4bac,9a4af6d4,7d15976f,2e6fcf3c,958a72fa,b8db1817,cbc5dedd) +,S(75b58bbe,a5a1d00b,40f2fa2f,9e2ca8c2,eb568bc1,fe5559c,7e40ab8f,a0148e67,7fd6db81,7359736d,26883e35,727f4b21,2813be05,8d5d2477,1563696c,feaaf021) +,S(504e2324,34a12a8f,a96f64e,d39a7c0d,4168bd75,1e0b6249,6b24ab05,eff49d46,3bbb93f8,3d2ee95e,2e2821be,c3d98f4e,1f2def75,b5f8ed09,6947c4a9,1c933ea7) +,S(563fe95,1482826b,38f21deb,207a30d0,21271292,8b53c790,c33080b5,c4fc14d5,9b875a5c,70ee8bac,9e6d7225,1981c9f6,c3b5bb49,c8772243,14c4b287,e990bba3) +,S(91ed3211,161cf1ee,96499e83,7baa574d,1f56b244,56fc1589,d61f4d40,dea01443,f1664cf2,578f5ff5,8d81c281,514c7f95,56bce3d2,2150db9c,6f4a4df,db73d14) +,S(27526d79,f92c2519,838e3e0,a9ebfd02,f66e857b,d49cd8ec,6deaca31,d6064be2,9e4b644c,5bf8d50c,96892f3d,6843c94,f9afb359,55fb10b8,6a2f166a,6fa17f00) +,S(3ad1833b,df1ab0,effb0dd4,d535285a,900060e0,f38555c,ffd3e7f3,392b5c07,5c37afe3,89bf6e88,b88c9a34,6ab5a0f6,2128828a,22b6f907,8f9bc6ff,ed5c311a) +,S(eeda869c,21a8911b,cf713c68,caf261d1,e7fc58b4,3bdb0fb7,e83e677a,ec3ff6d9,f58e7eb2,3a62a9ec,f7a13dd7,b6b6809f,5cf8bc2d,22af477,e002f2c2,9c44d444) +,S(c7a806e7,bfc982b9,342fd4fc,e8f34786,9509fb0c,f0f54522,98162dc8,ec5a398,ba895fb4,f9084463,3eac5226,e91a08c9,e83281db,c406ab37,fa3ffc38,421a3647) +,S(c59586d4,ecde0cfc,3a1f5744,45cea454,aff18703,720fb4b5,1cd7b0de,de79c9b3,1eefa71d,5e67d9aa,15231b20,966951e1,93ebebf7,ae54ea34,e84b7c98,7cd853ff) +,S(3b259287,5283a78c,5aaebc13,5ba13c5d,4e5a1e6c,cfa196ed,6eb7960,e7eed0be,274d3739,5757e482,1ee56c6a,f56c8acd,f58cb337,6bb5096d,2cff4e33,ebb3c1c1) +,S(d062159c,e511418f,ea6e9853,b1e8d769,96c686dd,eef71443,e994a347,3b90e239,95ca957a,b37c702d,c707a3e6,388532cf,26cd3db2,64e4e9cd,fe0aec9e,77ab27e3) +,S(12a2bd87,c4ca2337,7915bd12,3f39e88a,fd7257e9,9587d70c,a9d8fcd3,2aa7ce4b,85562f37,ac813598,cf59e427,106fe886,aa1a078,1170f14d,3968119a,9ed65e61) +,S(9214dd98,2737e4b1,585b3363,c363ef83,b40a3228,53d6c54a,f5b1bf1a,a21e43a8,dbc49c6d,abe985f,d95202b6,bb925094,8b98bbcf,71486065,9b77c447,396e8eb1) +,S(34439200,b0dd5b6c,4fe8cb57,2e26de38,3311a479,ee39ea47,221a179f,fbbc124e,b8c15197,1ea4149c,d2a77b4d,14cea316,6d70b971,a7f9ef3d,315ce741,2ad43e1c) +,S(396b4410,cb5a59ac,15fa6034,7215ac8e,4ce3490,4dd15b41,46e90679,ca3128d3,ad4eef77,94f0c541,e70fd5be,45652364,c43e91aa,34683525,36c8b1ee,c061cba8) +,S(8ee1b02e,3ddb0913,dc781279,6316fde2,4489c98a,4e4c3cfa,c84b4350,34d53d65,9a4686,a5241a7a,cd4295b4,f1c9f094,3f8991a2,b7edeea8,bc4e9c4e,47956cfb) +,S(78f4da51,26b42e21,1d69c640,4e128c71,cd08fb67,efac0157,3bf128c6,73bbf6e2,b3836f1a,e397d7fd,c88d2089,6731fe04,6a46b2e0,b617117b,161e1e7b,3a2958e6) +,S(ff5c1378,c8a233e0,5edeed70,e23bb9e5,a5eb65a8,4b37c6c4,7c0a4952,e00169b8,a7275aab,c73eaa15,22328118,68de268f,189d3adb,da113553,e3f9d36,7664a0ea) +,S(18ff6e74,87ebb21,dc935fdc,265616bd,d3a4bc2b,35037483,c911f185,596a93c0,34209cf1,2710b007,821ba024,f0491e54,bade44da,5980f505,37869b8,b410d0dd) +,S(3ece6ecd,1c52894d,90043c67,59d158e7,143c9806,658e8e65,5fa53867,6609b0b,4b1bbdb7,7ed6deaf,fba0d241,5f2b7993,89cf7df0,7acfb8a7,a22f42d7,7858c622) +,S(a5356c78,6cdabe6,a1c379a4,ca18acb7,b41fd691,c32c31ac,6cd0edcb,9fdc5694,ab8f37e6,d19af264,58ec5b1c,78f54a4b,877c9416,ad76b646,7e91ca4b,24f988f2) +,S(e5dffa5d,961253d7,f99445b8,f8d8aadc,5415c550,da64a987,ee604278,12de570c,401ebeb4,afacec6e,d41006e9,c60e0ec7,a4840c2b,c64527ad,80d640e9,70800186) +,S(12c46133,4aa32bb8,465c1e9f,afe68d91,63a7a9df,e11940f4,593697d5,fd0c9140,e4fdfe80,be2fa183,4c32598c,a096a5d8,15386dc8,67588354,300018ff,5b2e0c2c) +,S(bd8d9bdc,ebfeaaae,691a19ec,c20cca22,af76db4c,ee54f904,ee5aa8cb,2010ccd8,cd5fca87,4a6cc17,79658266,158066a2,840e61d2,28bdd4cd,f2697e19,7c6c994d) +,S(597d8ca,babc10d5,5402f3a7,48987270,7cd5d3b8,3356ea13,6c8c5135,cefe3fc8,bb21d384,a48ed346,eadc6ba0,2b1e2231,7b2014bc,62d17fa0,9196213,6e12ab88) +,S(3d91a096,24fe1048,dafae0e8,c693226,cb89157b,980aa490,a9a12598,e77d7c19,738fee86,ab5a6e43,753b22cc,d6a28732,65db5dcd,38a6be5a,6635e8f0,136340e9) +,S(44addcb,55d0870a,19682075,116c8fc,d8f49b5c,5ef767ea,aec513fd,8d71841e,5e126cb7,8d13c0d0,55c3363,b236bba1,21cc5618,40e3cc3c,e100722f,1cdbdb63) +,S(5bc89297,4447eb3f,54b7b451,6da3d1a8,f23d6d42,54ec7268,f3e9b2f4,78d88467,6d708655,6b679453,253df54f,68541560,b5e542ea,8f1a4a9d,a023d8bc,6baf9559) +,S(8fe4f040,553ba9ef,47a0086f,a8dbb75a,2362af22,a58e0739,7c62d2dd,2ed2fc40,b2d0c561,5afbbe3a,18fcd594,a8e91e14,ac714af9,e34938f1,74a2c7d4,2028f65d) +,S(e36702c,2af02461,4d5f65a6,b855848c,6d72709b,b3ffbb5d,f08206c0,9c481a27,c5558c45,9cc186be,665a54f,19ed5f67,983bc004,c1c196fe,80c57310,59f1505) +,S(45b0165,d5eb9c2f,22c6f2e6,3f2cfaf3,5d4a71e7,460a41a3,9d3708c3,111387d4,8fcc8dcf,9eba288,f0183ba8,345c4b08,1b44cf73,b9df77cf,3e94c089,1e53cbae) +,S(ad02f6e7,378d62e8,87d651a4,eaec6d75,9b15f4f3,b7e999e5,2e9e493f,7d765205,25090d49,2164feca,33270e1b,3b08ead0,fcbc7ee4,aca4b4b7,7e06d865,5259a63f) +,S(5684c664,de3844ae,90bc93ad,426bbf69,5f349b97,6080193a,710b6125,3d6fcb0a,c5138172,4fb53812,9dffe038,7029b209,946a913a,cbc06370,b3b58f1c,759ac8f2) +,S(cb36c4a0,f6d2beae,282e9783,2148704f,aea7bea8,af0abca,ac670a7b,3808a2d6,d0aaf774,d65b7eff,589afcca,746b02e1,edbd10b3,e2938d6,5a0bd17c,f71de58d) +,S(143e1741,5da8c61a,959643cd,bcbd1eba,169257,2a935eda,1d0e2495,6eeee4d3,c12840f7,7a9fb642,50d19be1,5f35199e,1da83a3a,54fda063,99a6908f,87c9beb2) +,S(b6292192,d471ab52,fee206cb,64bb526e,6b8519c4,3df9ae85,4e4aafca,d53c1509,3d6fb4ea,45ae494a,e2c4c776,29047e33,f73af147,4fd217c9,856d5d1,3b837c56) +,S(d490352c,70551c78,9951a057,cb02eb17,fd710a0f,27dceaa2,ff224ec5,3c566a14,15ef3825,97ee6d88,ed8840f5,9d496c0e,6685349a,f1c62c27,a32eb7b2,bb193fb3) +,S(4797be1f,7ae122c9,2193fda3,80dac3a0,fdc14361,110a2a3f,5beb9f26,f3d85449,9377f25c,591ca377,2ffcdd37,65ef9a3d,6fa7c2,79d18e45,83901795,2e5fa3af) +,S(fcf5b790,98cff1c3,b02be521,76e1c6c6,ac10bcf,f083ae4,5d26ead9,82839614,8d94f596,5b075d45,a8f732dc,9fbe679,dffaf0ea,d2c90d16,b2c7ace1,1de05c45) +,S(d7153203,1e8cf246,683ee529,b2dcf54,1a731397,89e5c354,3bffbf4d,f95f76f6,740af4a,40e7849b,a41c4dea,4b7e0479,ca377fc2,69db00f8,b484c7a8,c4c745bc) +,S(27946ccb,dba75dc2,23663d14,2b56bd9f,2e63cbfa,73290de1,8fb7e988,31b44330,52c0ed5e,abb069e0,84fd8363,dcdb9134,364dcd4d,87b46025,9c3460ed,63e04ad5) +,S(cf3ea523,751eff3c,a785884a,b019199d,2a0ccf3c,1d90679e,141d4e75,74e41f61,b38d0808,936a2920,ece323ac,a707e1e4,914b51e5,e54843c9,63abf292,88ef17af) +,S(d06327e7,917280c5,d8a5c516,7e0d0c1b,e5fd9e25,4c877e9b,9ae6b264,6d9a126f,c3cc3913,9d0d7b8b,6a6b0c7d,b48213ba,eade2202,544dab7f,9ae42e08,fc7c781e) +,S(acfc233f,28f98688,2ac5ea8e,61478f62,505b8b48,38833499,1ccad1ed,5ee2a871,244a188a,64a6aa7,9f74e940,8681b45f,88b5c65f,d120650b,1a25674,eabb338a) +,S(87fb09cd,b3b8a514,f6a02da6,1d9b160b,798fdf7f,3f05d7ed,25c1c4fb,84b19253,586effe8,c4252dd8,c225a6a2,8e515abc,e36568af,107f8c75,a941e936,acbf6e38) +,S(77225acb,8ae251d2,be2f48a3,2eff0c6e,4f558287,13dc8a6d,3c6b7bb5,de9538de,d6eb8501,2aa7fe12,285e28dc,3efe9cf5,b0cc8e91,6fd63f71,c28c3f5,60259a8d) +,S(b03074f3,f2effb45,5caf88ef,e0eca7d5,6f901b18,fd04c01a,f0425c58,1f13dd5a,c8e8c915,fe06d774,8ceb2da1,78816b8a,4db1d082,6df3064e,7a4b0f85,ae99d461) +,S(992278e5,229bad50,82c8c346,8542f91,e2761305,62a34627,b1d97aad,a5999908,56ef7d8,d360d7b8,5af0f210,161ad17d,dacebd13,c45b9c8b,34f1ac73,bd6a1ac4) +,S(b73a2eca,5e9d0e4a,ef4f6ac3,e9610f3,1c72c67b,6a152fb4,82681595,8d44be12,c621ee64,b03b17e1,a25f27c2,aaea43d5,eb2918d9,e0949306,d2ef720e,8975c00c) +,S(7f6dba94,39e3302b,e4f7e0b6,f2363609,eedb30e,dc0b135d,e4aef970,cbcbc607,61685e2a,eb8e8244,175deb0,a006b5c,4292bd73,40b2fa1,3548262a,db98a3d7) +,S(88f0e36d,345aaeab,e8af18a2,d14191c3,8330c5e0,d4e32c5f,c562e549,cfad763c,bd062c83,13e44ed1,891b8048,2ee93ac9,95a0142e,e0543a92,a215735d,1e94ac05) +,S(da3a270a,bc03e6e5,3f572a27,94c8075c,8ce4590,b1b626e0,8a83fba,45dab386,884b46e2,3ab44b4b,c3d09f5b,97994e4b,109f2db4,ee04bc77,6752fdc2,6f0df055) +,S(df346699,77cd82a4,8e3e1b11,6311a5fa,3bb0389c,1c500fd5,15573af6,da0b2cfd,2ecf1fe5,fcec27d6,35c28d58,5fdb01ec,2192c8a3,848a72db,f53b7759,7b8b3735) +,S(11a4dfcb,3a443c3e,259c9f27,e24ca426,6e08fbdf,e4bbedb7,2e6cae42,569b0116,7fc6c4cd,1e3a0e22,d0ee0249,d6940def,bd776bac,9da5a98e,23cb6025,42b3de9e) +,S(2ffd148c,132eba23,e235bbd8,f09be1af,dcfd6e4e,5f2f0b49,6e4fadec,b931706e,6a4def93,52d875c8,31794fb3,6cf0448a,8c9ab5ae,804c6397,cec41b0f,24583acf) +,S(109e1f3b,7043c5d6,fb822b8a,54c6949f,117e829b,4065c0fc,c3ba5e05,a79142f5,c976793,6c034671,e5aceabb,9b08f5fb,af3cea75,a7a4485e,6c08f7fd,a63786fc) +,S(bfeea71a,8bb8ebbd,ca6135c6,26b739bc,eb2ada11,9babf946,6db9f4be,c7406610,44ff78f4,76074ac8,fd7ef860,cab01522,750fec0e,4b86f11d,831eecb5,22d1f682) +,S(4d2b7cd4,6cb01842,46e7846e,d0572489,e306b370,81515cb1,8a7c6cd1,dfb51665,60ebb290,44169e56,1d10a8e0,a2971b69,82276f1c,e7d11f60,ad7decde,e1fe9c95) +,S(66f2068c,e65a1a61,ad95ff3c,a2f15f55,29e0ce3,ad522dd3,d6083d5f,793e0e5c,a95bef60,2bb89e00,98723b4d,7fb421a5,b2cc751c,e8862ed7,439c1b36,efba2f72) +,S(4908ff3a,27aebeca,8697ec,dd7d5483,c6e56427,9d78f013,129e26ae,2ff459df,4c5def88,b60cbb2c,a3430911,aa84e4fa,1055fe1d,921c8fb7,bbb83b45,62b0f5bf) +,S(f9a90175,3a0f4236,dcb612cb,fcbf3f31,d97a8e6c,cc4f9e74,3887407,5d19ecb6,ed3c6f61,259943d0,310208e3,dd8d5a40,a5bfa646,35fca871,a6df79c0,830e24d6) +,S(ffed50c1,2434484c,ae866c1,86b88550,b0bd02e9,db04657f,aa81a672,8e321850,f16e95db,d44bc7c5,66fa0a23,669827e9,9cdf4372,6fba5f4e,a3e28d86,33edaa77) +,S(8061e9b6,2dd9d027,d43d13bd,1361ef3d,ccb4e599,c8d3d015,1d3adccb,6c762eb9,d33a9196,419b283e,5579ac98,8c1b6e60,378fc692,69b18da,a38f362d,20ca6895) +,S(ef8d0e44,e8b6b5e4,857d3d87,c82b01d8,f254c516,fdd139ff,7b8d034b,45698162,8325ccfb,6da9438c,e99dffa2,92afddbc,e1a101a1,20955945,cfb1608c,d35e7065) +,S(a31af5aa,cbc4f6ac,aebb9abf,de164046,1b631b2b,8cc43eb3,edb53185,fc1822e4,c3dbc990,691987e6,a8c318d,e381202e,a0c2297c,f06668c7,a2f027de,e5118a2c) +,S(81e47ea6,b60a3819,2094e7f8,f7bb3f48,a839b26e,d2aee7e3,e159bb39,798cac0f,186a8c4,97ba163e,aa779f6d,a8cf88a2,9f5d79f0,43e6f195,9c14bb1c,b1a53967) +,S(e15af4c7,8c61227,ffbf080b,a3b1dc2a,4966639b,926aae67,f2bec480,5c1fd232,76fd417f,4fe9e7c0,96db39ea,180d38ad,2360eac4,2730186a,b1da32c7,33fe9a63) +,S(3a185818,fb47ffff,640f265d,a2c712eb,f7e022ff,67a21a22,a2e941b3,f72639e0,8d370a41,1f133f43,34534b15,655717f0,73293f59,3bd34c5a,fc5c933e,120e76f1) +,S(18e05d9,2f227564,b572069e,18a271fe,2fef9d81,14eaee28,adb0fd2f,5f078e07,75f390d4,6e8f464a,d71067bf,b0d6596d,a945ea44,c7ede2f8,a9082440,d7e9a263) +,S(7bb788b2,4f4e5d49,2af81fdc,2f3a0274,6eedc5a8,cc74d1cf,ad17c2d5,4e80a107,5b28450f,1cd8c61,2b73038,ae889c39,d33cd64f,d452ab5d,28810177,dbb6a28f) +,S(a156cb3f,e4425b79,3334e19d,2b1208ce,5e6e8fdd,78748c0b,a1116031,912fb9d8,b2571319,c644e959,ba401415,3cba9b3f,cd8ac2f0,f8fa1f04,2d59ecce,5de14d21) +,S(eba23049,f5228794,1651a922,f60bc406,aa15acd1,59eaaf37,d1f2cb31,e7d20b25,ac8f8df,155b2703,d65b33a9,af581a02,8afdbe06,f4927a4c,5546ab7f,b5b2cada) +,S(8203a1da,56c4fb7c,96816507,f99a9a2c,950da51d,af7d21bf,123402ee,a95954a8,913884dc,10a53ab4,6b2be70f,5e2d201b,4c6bb23e,b6644817,b4257664,ed2ece88) +,S(d46609e3,ec19ef57,97ef86b4,ec51b8e5,7a854643,f817e7a0,9be4bc7f,291e7795,e1b3a8fe,3cda0479,11ab8c09,ecbbabd3,ce96974d,8a309ba8,c38c1d04,ef730830) +,S(1ffa9ab5,8eea8682,76849108,9e12ee5a,cb0ea4fc,e6f68436,377e985f,fabe919b,302140c0,7d64e9eb,6ea74636,f9efff59,e907a16f,5c876658,2f4a242c,b52f1236) +,S(4032bf99,32057d1c,8b6a8923,1575d3bc,6e2d6d0e,e1c7aaeb,ffa9ebe3,bcd9a0e3,13ae5217,f9f70a4,5f626295,b30eba49,e9f7c697,e3ed7cde,95442a03,b7916a54) +,S(8d32845a,14575fa5,ea061425,5e48e37b,f3a55bd3,9d924648,209d26ec,b94a20cd,e0416169,8f1e1626,18ce160b,e8b502b0,20a5ab81,7853903d,ad7ea792,b76266fd) +,S(403754d8,1a0dbcb7,1ff4893c,a5551387,b73d64b0,25bb612d,5e2187e6,7acea8b4,134dd3d6,8d642070,cb7778c,7ecc8d78,5c1deeb7,2582e25f,5c58b19f,2f59256e) +,S(4fbe9818,60e5f281,cb1afa62,8e8787d3,28afae7c,fcb73637,e2d64337,bd6e08fc,31a10b4d,78155900,7cec4099,3b5c59f,4bbb2328,b00a7550,572a604e,8d55b6c) +,S(a5414064,747b2ac1,e8868074,3a0fb05e,7ef510a2,a48d4f44,4647663c,b5c48b39,4b3ba626,56cbe6ce,2f228f8e,88d00ddf,135d6b81,979286d9,ec41c81a,f74ef7e2) +,S(5af99ffd,9f27830e,6ba54e05,63b3bd39,4bd8cdb5,764f78ea,b103405a,dbf3a01d,f625b35c,f510f9c3,db948363,3b2951e4,b2209b37,1397bdbf,1d899a7,400a4318) +,S(7fa7dbf0,1b2fd3f9,3ff4ee6e,17115c19,1f663d95,ff446dc9,d53d3e31,c98026af,f8aa82d5,28f2ee61,1a71b432,d553eff,ff1aafcd,8bf18e3d,b6dfa38a,f33eff7c) +,S(4838c0c,ed78e7c1,e3707d85,7311b2ca,6c7a4396,5be4e363,d4a374d3,36324640,4404fc6f,1a6c1751,3354d364,ffd43bdd,61b874f0,714430be,8a5571a1,808b5150) +,S(309c59a9,b42b374d,5c88136b,43310fbd,fccd6ba,e439e7ce,3a9c5e7c,ccb8dda1,fdded8d0,661b8ccd,834e4762,db87640a,fb1e9636,b894dd48,e1b4fb54,863863d0) +,S(1cc76e1d,788111f8,eeaed575,43afecba,548785d,3d66296,223142a4,7be59190,560e4685,6204121e,402c977e,76fac50c,446560a4,9bd2be30,c6dd2c58,62ef357a) +,S(188e8999,b9de6190,a65cc051,f936585,9e7a0498,4452402a,3093b4cb,24116589,aca3c642,dec398db,81fab67c,d05ffa2d,948a430a,e26eaa0b,ec3b2cd1,20b01666) +,S(2fca76ef,b917fadd,88e30d06,d6f398e7,6803307a,b8ac9817,4baa2945,9e9517eb,186c092d,95755005,4292ee1b,986b55c8,ee3be8ad,8adb6387,5e4dc582,c1105078) +,S(41d690fd,b5eb4f10,8aac4bff,26eaf866,86489227,b6e59b89,25440780,10e3eba3,251f34b9,d69611a4,31fe9605,7be2e10,6d058db4,34e0c814,b0b8a0c5,f2e50b63) +,S(282f850d,344e63bd,abc4542c,66cf1f1,a6807b1a,19ed7864,82d06a6f,a03b1e05,de82333,48fc960e,b22f5641,5265c1bc,be290ed9,4ee81fae,248d4676,d38a1a5c) +,S(bdba09b1,c1810ad1,ab2f5da1,b628a44d,a8512221,993c83ee,4a9484fe,6416bd2f,7049aac,e507d6f8,d77587eb,b8759f51,1b7bb2c6,5de0481b,d82a2f82,246d229b) +,S(e7e238af,4639d3f7,e5ec4298,65aade7c,c1127f41,d04b3d11,477456c2,b155a79f,da29edf,1e3c0ede,5546ed8d,cf8fa801,b5bf0dc,720a02dc,d9d706c9,a9c6bdaa) +,S(53a635cc,4e24790f,3ec5c17f,f854e2a1,800b2529,fa882945,50a0d237,58d622f7,ae6bf987,2d3a31a7,4f97299d,2fbae146,58c32dfe,418ee242,2029fff8,166656f8) +,S(10750fa7,df634f7c,7d8bd73d,e056e48a,50c413fc,282748d9,f4d0b485,d0ac5c1b,fdc72a01,883f0ed0,52d97ffa,8e6935b2,3f684f58,5e6c29b3,702f5147,dc645e04) +,S(881e3e57,ed8f639c,5023e45c,4e843bf8,e7d13323,289f92c7,143faf66,a65c3fcd,12f991ee,3390b45b,af1aefa9,dcd20da2,5891ac5d,35073750,47836a0d,e75b4dc) +,S(6be50501,4d72c612,bc0d5df9,13beac50,bafefaf0,aac7d032,824a102f,25bb45f7,4a0e0d0f,f2477287,ebd8c221,5bbf3e33,fff7194b,4217f9c7,57efa361,1b3abfb4) +,S(2ca955ef,23ed3481,615d1f0,db0fe5b3,f0fe5f1f,1b7f96a4,bdf814af,c4a58987,2dffc8f1,ce4ceeaa,d09a7610,7ee08e48,a591a177,9de2c84a,765a53e1,808e3c78) +,S(250da25d,5be3561a,92b56f0a,a7ab8fc2,bf7398d7,aca09237,3d416615,6991a05a,b0e62549,ca492ef2,9ab753e2,62b9c3a0,10df946a,99a982ab,812aa48c,def60c81) +,S(57606839,4791a29f,b66f2314,73b6bc6a,ff383623,c889695a,910c1894,d9c060b3,bac9ea05,7285d6b2,7911b19,b32fec7c,1b25db58,ae39eede,f4aedf09,46c04ae1) +,S(46edba34,d53e958c,c3e4e74a,ba8bb4d7,c6266aa8,9fe804fc,e27bb8eb,cba98e2e,2b85a88f,136b201f,9a1747a6,dc55f59b,41049a69,f824e3e2,f7f00787,f687aa6e) +,S(5d4f6ce9,ac52d698,1a13e73c,3156dff3,918d5b72,5e42f415,a503e573,bd6611fa,4c633703,1de35eed,dfc5e646,e8b0f812,2b951fa5,343d7b59,ceaa5c85,e1ce5c08) +,S(c77db927,f7e637fc,24a38bd7,f605383e,91e4e2de,8ba5b1ca,baed4376,8ae120c7,347f43e9,47b5d13c,c7cb6fc9,fc2caa5,2991a0e1,bbd4bc96,d98ff26f,1a81bc5e) +,S(ebe2ccfd,ce91b78c,95cdd34d,79fc9a28,478c406a,224bfb4,668dd5f,197934f4,d7866df2,d346bd30,84ad837a,a0c65cb4,62cad5cf,3d23b0e4,bd260fbb,f4666ec9) +,S(ddc5f94a,d4420ae4,8ece780e,26940338,294b8929,549fb897,82c06e09,b7935549,25802633,a0127d73,21ef0a12,a2a6eb32,692f2d30,5e7d3cee,f137eac5,8896ff71) +,S(e4000918,46f79f21,71b299ae,6b93108a,9377708a,e7d3f5c3,147a98d0,95e876b4,c8d8c4db,8fdecd8e,fda047f,b92bd9b7,3c999493,27c491ce,df19718b,6152c434) +,S(4add9850,90e16b5c,525de57f,a15a9c38,97527b6d,8683e407,3a978cac,53b29b66,dfa1601,d36d2021,6efe432f,8a335e2f,42b6d645,7fd6f032,d727157,32a85dbf) +,S(8a5536ff,ff9c9dc7,b2a67823,5d60ad10,834c9029,bc243f3a,f10d7e14,4ca0a78f,72ee78e4,e0a618ee,191dc7fb,c1143e4d,70ffd570,bd50ce8f,d368ec29,c22bc926) +,S(9f708795,6233a0e,59757e17,5a87e34b,f7a7485c,94f9aa62,61854b4b,3ac62c05,ff9902b9,6a6cd1cb,6ea35965,3527decc,7827318,97b5c8dc,c24e2399,fb16ff15) +,S(bfa5d3b,e3fd56da,d8e70330,dccb79f5,bcc46cfc,220f4921,4cb8e700,e7cd0ae1,2a4870ce,aa2e001f,567ac21a,79eefe94,8763b5ab,c63fa649,8a5cffa4,126c6d0f) +,S(a965e34,47f07286,b91df55,3e4211af,e6b837ad,a9cc10a4,905975f,1983f2fe,393bb45c,3f6eded,b6de1e70,5a706501,cdd10ea0,2548279e,c75e4dd9,15f0da2b) +,S(e5e38677,c1e4a659,51358301,dbba1e3f,c44f5c23,af7011aa,5ab93ad3,c69b18c1,7939d32,de371524,c3b14f5c,745ea023,34f9222,31f29d8f,c8294802,b334821d) +,S(473453e1,80511622,cbe6df28,46f479c3,b8638efe,9af11beb,21dd093a,24d243e,e2b897f,eec79c08,5afb9daf,c9ead107,57d21019,c655d0a4,e5254a69,941962c7) +,S(fff734d0,e5f24c63,dfbc061b,bac37c88,ec5aeead,4974cefd,77f1eb5e,86219772,ef8a22bb,c29c9756,37c600eb,82ee5873,778d539c,a289a50c,5490b5cd,8ee0bfe2) +,S(d0508f53,85f92779,809a1892,43a58f71,47f643a2,a8f5876,510b191a,fa292dd2,329eae7a,2ee52766,a5a2874c,3912d777,e23c4aee,390aca18,140ced23,b8e82d8) +,S(93170604,98fb43a8,41d09d53,98807f99,23405879,be9f224d,52d21971,130fba89,e84fe72a,cd89fd4f,f7db1817,edab493,5f809b78,6d0c3448,f19505e5,a79e60a) +,S(63634cc3,ce570dfd,8bf90307,f4543528,e26f2637,ce32d690,75cecd2f,63dd127,bd12dd78,7ebe0ea6,661dc389,5bdb6478,7435e9da,5812d06d,d9188b47,e1a31939) +,S(30c7e2a7,925a47a1,5aa1e2a9,6f564e31,61b7a559,3af1a696,91088dc8,9ee64431,5ef4f2d9,cfefe53f,3dc76f96,1a04bd71,6aeca894,73553a0,1faeed0f,6bd2d506) +,S(f7b7e1e,d56b7caa,74f60145,98c18126,d8bf10ad,c37cf1bb,5e6c88ae,f9f6e6e4,a019d45a,7e091a62,8b7125e,d3720f95,dcc091e4,2ff17050,da596fdb,58ebc508) +,S(c6e9b0e1,177dedb1,2e19a0c0,d1167a8d,8095b2fa,1f2dc402,adef0cad,d5d87d3a,64440da5,2b3ec64,4565ad12,6f732ae3,c81276df,5ef15605,3318693c,91c12b43) +,S(653d41dc,e6ae6cb9,45533e54,63b50a4b,72f6efa9,7884d878,52c32eac,fa0f59e,693da28a,13a9cde,d1b7597a,c199e00f,fac2f6f0,6bb0dc58,940b6734,e5eb934a) +,S(b9830b38,f0f8d466,e363fe57,38124fd1,8c9f60f8,cdaf6fd1,a10205b9,5c7212ce,a3e31906,6ace61e4,ad861027,7a12d498,5c35969f,62e5573a,5bf4ac35,277cf444) +,S(94d9457b,eb2bf3db,cd38a667,adda8750,f449af92,6a92fc93,f1dbaa85,457182ec,ff1bd647,8f00626d,1b203da6,992a2366,2ca2b39e,f6c1528e,956d7d81,7e2497c5) +,S(816f295f,1648ccd4,360b1807,bfb9b05e,4a84af7a,140a1f2a,f4016527,1d4b5b80,98217f98,6ff6f38,1987db34,7c6d432b,f24b664a,bb47124e,641d0677,aa4ec143) +,S(3b830637,17254b06,16c1a5e8,999dcdc7,cf3cac91,67284981,75c6909,92e2b2d8,dc2d471c,5323eeeb,611495f9,cb37840c,905eaeac,a85cca33,76d24705,d152acce) +,S(33282bad,f48bba9b,3db3cab7,c3b46c83,867a63b0,db393ed1,2a4bf49f,cd2f7c5b,78733604,b1c94144,ab9a4886,80bc53ec,9d67c4cf,dc77af88,40bc3535,f2c42309) +,S(58e15e93,95c3abc5,2ea68f94,6e3f7943,b1ddcc8c,e258aca2,8cd9f5e3,14b257ca,d7c15bc8,53dedf6b,f7dfad87,bcac6e37,f90d32b8,344d95a6,44879ba1,e170070f) +,S(c9ee3e27,54e8c8a1,e99c39ee,cd3d0b50,f8fcd03f,ccdab94b,e503a1ef,b66d900f,a1ce86c4,7f78400,51c87612,1b26922f,2b4b2358,e302c568,da6310f5,14909db5) +,S(6e2621bf,dcab8898,7d50b5ac,b27eb94,b52cfd9d,29e80d2e,befb5478,a3c5a514,ec4c657f,ebbe25bd,9d6b172,68ada77c,5bc4f32f,57f325db,9556ae0b,4d1adda2) +,S(6e3c35cb,9c86216a,250ae256,f8ab076a,76264ca9,97b1a6e7,41ee96da,5cfb2c9a,d45f0082,46489230,268e5c99,56dcff9c,bf6a0621,f8978be8,f2183920,eef3dd74) +,S(f3b5baab,882e20ae,b0f444e7,47688392,37acdb60,e7c878ff,40ec0aab,7896c278,7d8d6b2f,92addfcf,a248aa96,e8a87e92,4c821c1c,cf7b343a,f588ce7e,93e37260) +,S(b89b2380,110087ce,8c8bfded,7dc98e40,3cada8dd,77b2e68d,120361dd,6beeca0a,616e00aa,4aba8494,9835b0a1,eb0ff955,6268d2cc,91b7672,d0164693,848389b8) +,S(6659b720,1db6e160,58854e12,dd78b89d,40d91a17,b7eac836,ab8453c9,ee3cdbe5,5ac9db66,325b000,1983df0b,6693d93b,adf7e35a,a18f76ea,e2053e34,b1b8908d) +,S(6fc76d79,bf3c34ce,afe73e9d,7a77af23,bcc7e894,dc555f63,8b9d53c6,c15803e6,c366b411,1d6ee57d,52d3938e,f2c0c620,746d636c,92ab73f0,bc812888,ef0b5ac0) +,S(a06b2395,238326ea,20545cd7,b021a5cc,9e21e9e3,26c28b1c,fb50f3d5,e0f6e069,8560335b,a5c16aec,a297f185,ab09e976,dc57934,61170b35,b8a3b6b7,4ff622f1) +,S(bb8064ee,177f3753,19e45c8c,4dcdda70,ddc4bfff,1a866b7a,ae7922e3,13d1515a,a3be84ad,274704ff,e7a76277,d87687ff,572633b,2fb46b4b,40f601a1,ccb98d7d) +,S(27f08788,6a2c0ab,8f26ef15,a85d2d38,f6fb8cba,622acf21,77ac20f2,f05962be,ab2f2929,45163b83,c9cda8e9,4f6d8f7f,167bb589,50d4226f,827c5b5f,a782f8d2) +,S(f51d558,dfd8f74b,7c9c3768,65f82932,65c1bbad,d8aa64d1,ebbc09df,b7f6de1,101c88a8,170355ec,ac23ac98,ab5aac67,7a68a94b,9343012f,74cccfe9,308c039b) +,S(60fed665,a3ba26d,eccd1ab6,c956ed2f,e33da384,dc687f41,6c37b550,123a5441,4bc061b9,b2d7c63a,ac042a7c,efb2b5c6,a43260f6,8bd0f843,fa218cc2,3fc9b5bd) +,S(fdb04aaa,f2958755,ed65f968,ce4fbb81,ccd8c616,32e9494d,510a7b3e,d2564256,afbcece8,c52725ce,c0ef2aaf,a094385a,831afaa6,7c4cdc9,57712bf6,1073990a) +,S(7f45848c,cac04d5a,d9caa28c,e60628c,aea7f076,262689e8,27fc7084,d6b94dbb,51e16503,e044b101,a0d12d73,3a57d8c1,546c1f04,386721d7,a6f9fb15,458e41c9) +,S(b4091018,4c556249,30ec006,95f02723,b9cef749,57996d50,72642d8a,b492c9be,1b3c221c,235e721e,95bdd451,f0f0fc8d,a6a18260,d47b0c09,5f3e1b1e,f6135e5d) +,S(4d5b1a50,d00b83fa,93ab4746,3f84dc21,d0ff4559,2e697fa0,bf8e8f68,5e1c9713,da52a118,24ed00e,6a2434d1,ab383f0f,1e495dac,d08c6a2d,2425e25,a9434af2) +,S(63fb80ea,cb68910f,69700533,8a1769f0,69acdc85,da71618a,9cc03557,1d4bdca4,7f2e51d0,4446763,9cfdc2fb,247c7cb9,5b8e01a5,e27e6bda,6713ba98,1936573e) +,S(f5035d5e,12313edd,b0c31851,266f7e92,6f16c1f5,a6031aae,bd5e14fc,18304faf,7381fc4b,cfb33c18,7bb59e22,be95081c,6f52cefe,dd84bf6c,799f419,453f61fd) +,S(f62c9afc,5a2cfec6,afd54b78,375a73b0,eb5a73b6,f53e24a0,6d1e9111,ff20e835,a5d386e,211845ce,9ffeb917,76a8b91e,27f0773,b2d53fb8,2ac44b8e,83198350) +,S(7477749f,3824c134,c1a91bfd,d1b646f6,43f8109,c2f46887,22799f6d,53e6280b,232b459,2259cff5,99e4af77,1e03c94a,11fc32bf,f2598beb,2316d3aa,d9461c55) +,S(2e2c5f43,5fcf4fcf,72f9629e,ef6ac5f4,31073f2e,7034d6a7,64af194b,1e84b6ca,cb94ef61,c794f44f,2c7d1115,b9dca665,7fd1c184,e30f6f60,caf40e75,142ee26a) +,S(8f7e4f94,fd2a651,86e4624a,93272af8,2d362587,62a0baae,f65cf47a,bcd8214a,9edada6a,d23cf1c0,dd98b1f9,d9a83879,4c21654d,239f1a9b,dbace84e,de6145a2) +,S(e184ae37,4704eed2,b054b667,33544ff5,6ce55a9f,bcd7625f,740b6a67,621c75c3,ea773744,2212bf1d,a26fd119,248b0c51,c413ebaf,75e52de8,97b4383d,b397e144) +,S(fa47fd9b,94cb72b2,60fe208b,c022dfe3,a2bce2f9,ec776313,a497cd91,4166850e,9a12bbf8,a6e0ff91,5176f71b,16327c7,ea5d928d,816de31f,c8de2be4,57b0c185) +,S(98d36e76,a4caf051,e848fa49,64e09bfa,815109f8,63cd5e99,405e64ec,d526c67,706b36aa,6e67352,8fed83b6,8118ae7,1e043964,f444c477,590430aa,8d80d19e) +,S(e7722849,c00c5875,44751cf9,a88fe964,9efc05a3,4d810788,f30a2057,cc1d0c72,d64ba14f,978e1769,51951a4e,8431af78,57e6d97a,f5fc5ba0,2a1fd46b,1c215e7e) +,S(93374edb,547efea,e5f22d56,acd80ce2,80e4d47a,bddd1d9c,9d85afe4,aa6fe6e,e9c40824,cdedb038,9b42e2e7,2e15009b,215d9080,7df6316e,6e81ec9d,40dbbee3) +,S(840eb546,a076bf81,e4954196,6eb8c437,3a055239,8dc4deb8,62a73b76,8b380e28,97b69f93,ac1009d,a3f47ff1,b62ea845,f2900d7c,84e8a1d1,48d96f,df6fdb98) +,S(fdc4ef19,59ca06ae,92587249,e45d456f,d7484278,6f4b3381,676094ab,446c3e8d,c832aa3f,f0ce9f79,1fbe89e1,5511e25c,6a7a4230,401471c3,7b9ab011,1b304366) +,S(42abeb49,83403d4b,5f529eff,16bb991c,ce705250,5a61fd6b,96467a51,f661651e,d815247a,f807af52,b454e83c,9d46327e,d80d3ec3,60f84a3c,dc88b9b2,59efb05e) +,S(176fc9a0,b44a34ff,fd652cc8,bf715a12,a9d5f40b,adef6032,24536660,5e0680af,a47100b7,e0fc557a,f5ca7dc1,c220b5a,770231ac,184f14f,57e554d6,11daba35) +,S(11fa2a03,aba7cdd3,1940923d,37045c99,ff531ba2,a1266fc,26ce7a26,c6495e63,360c9e1c,54fbc823,9878d725,30254bfa,70453c3b,934915e9,5ea4542c,1026b272) +,S(b2dda11e,db5f668b,8d90dc96,9d10f8dc,6c95a16a,a3e2cbb,3a1ccc03,d9acec22,f4d44dc4,8c260995,4fc1316a,2d5bfe6a,18ea754,43bd9a55,2b2f2f08,aa0652c5) +,S(baa1d433,e2adc426,5f87f407,1c8c35ca,423f3e76,5a835a70,2d804593,cfc3f7b,3f55a493,9e25a77,8a9d3ad5,4ccccebb,8a45486e,1aeb817c,dc0a2799,6e70e996) +,S(478f18c,30470c65,b578a6c5,df9c71ac,934e3439,ee5d5d23,21f8f5a1,7adfe55c,c43dccf1,9a9e48c4,41ebdc12,f2876cbe,32852cbf,d3bebc9b,a3708fe,6cfa450e) +,S(18223de3,d62283f6,c440102a,a1769ac6,f5e1a0a2,cf3fdb2d,ec62563f,4e149ebb,57fc95f7,f8e3151b,80fa4e68,45349b7,961fe72a,d6ffe725,e3a0a0f8,907a4555) +,S(2c8c523e,179bc8d2,1e3faa5f,5db5dcf2,cfcb0426,3f138cde,428746d9,94a17276,c3f00baa,69061521,5d512c97,aac1b858,40842fa0,d8bdc773,4e11d370,4f6330f3) +,S(a001d77,af44959f,f1e83be7,d6b16496,2aecd428,3ae2c38d,f3ed3fb6,a0f12460,e68a305b,6f60a1ae,5a01eaa6,7675f0d9,8e6c5baf,75d725bd,d0e2a499,1c323770) +,S(cd8a1d36,2ba4a2db,255ebbab,ede7ab7d,383b641c,515250a5,cf52a2b6,a5b2ea9,20716fe1,e0857b5b,55b836d9,39d3175,188a6f9d,d3cc42ba,8c61a7a8,d9a7a1d1) +,S(7796adbb,7949b234,6df5147e,c3d7e0c2,5b61a874,43fea9f4,b4e742fe,6c1218a5,fc338089,c80c6415,dbb32994,cf5e2af6,b5c3342d,d291d7da,def80628,a904edfb) +,S(3c345146,27eb74dd,88ecbb47,aa9933ba,b7fc8cfc,bd80654a,f96aad51,5c1a7017,cf4318c4,1c021c06,5c100913,dc84259d,2b8d6ee8,102e5c6d,c3f809a5,7f8f2beb) +,S(cb4470d2,d5715339,acf391e6,5e3cc397,eac932d5,5acb65cd,a94538fd,eb684f67,15e6e6f3,383b8bd,1b674497,589ed7cb,e0f41394,e366ec61,b7e1b927,daa6434b) +,S(954a527f,c4496d02,915f0b11,4e95f104,c500be4d,a61eca3,2fadde9d,c1f118f2,96acbc82,d0dd6226,5652b61e,226b7ef1,c6f00491,91bce5cc,fecaebd2,fdd28ed0) +,S(d3be92f5,697a11cb,b8374938,9fe89418,97707ffb,24fcce90,16debabb,a4faa4ec,23d04ff1,e309abd2,aeac3159,ed9acffb,9c5336f5,517531c9,f1cc2dc3,a2d300bb) +,S(7490df7d,5a7ca290,fe029f3e,d92f530a,23a7c983,654bf19d,5c9ee21d,b4f57586,3d7f28c8,81b259e9,f5f735fb,be608154,b80f38d9,b5131bd9,a6e2dabe,7ab2bd54) +,S(992c4a82,1176a784,ba2767ae,a3d39697,5f96ea50,b7bc8947,2356fd98,20aa666f,519d9792,458fd39,7050829b,6ef7449d,da4ebdcf,fecb2a3,8ca0f057,f051c851) +,S(f070e211,b384b497,3d2dac23,3373a3cf,6dc7b9a6,2529af9c,b2fb1e84,b40901e1,175cb1d4,f8339521,26d4b41d,9fe27781,92a2a1d4,7d5faa48,1e96f51,beaad506) +,S(108f6113,c2795472,244db9f2,3a1002b9,349bd34e,f9c9d70f,e146df96,be198ede,2bb9d195,d087015c,253af145,bdd6134a,1845dd92,45d7d8c7,c12ad2ba,2027ba2f) +,S(ceea04f7,9b611056,ed7043f9,707bb318,e3ad332,1da82104,9790b1d9,d264349e,5380e9f,1c52e5ba,6ce18afd,289f49bb,c358bb90,9db23d67,a851dcf,9ba5ec9) +,S(1c74297b,14a4fbf1,2a6421f7,561c549,414147c3,2a683391,c4cc5eb0,79948cd7,581c9642,98232591,bd5469eb,c1a01be8,37bd5d43,cb63e21e,8540ee84,52b12ab1) +,S(14bd0f2a,ebcbdc9,22fe8660,c63bf12,c6db8521,f1f0acf,7406e982,a103bdc2,46c3002b,1e5f25e3,98c8d7af,e340aab7,23ccb0d2,7e24bec4,55d547ff,1df59c96) +,S(32c923a1,526240db,b234ab72,565d6880,b260e7a4,33747aa2,802da713,c30ae9a3,b79bdd74,6ce4ecd4,a554d66e,b787e312,a1ed53e9,c77cd6fc,73b1bfee,8b13d620) +,S(af0ec2cf,21ecdfc6,a71c6edf,6f73ab6c,76600a89,86b62006,8b246008,7cdf168,d229f3c2,7db8019a,eeb8f25d,84f3e341,681de4ab,2173f510,51ef4249,7a9dbb0a) +,S(1d648075,8273a9a9,c970cb10,5ae7e537,b017aadc,8be5044c,a1f6a3ef,4d2cb275,3faae8a6,87925e3c,e9c3482,d34c76a5,702c9bea,a307aa45,f2ee992,efd86387) +,S(160ebccd,b4d5561b,488037ac,25224afd,91c66584,660af970,672d9514,87376568,f510b49c,b58b09f9,46001627,2fe744cf,e6e7abef,8f54552b,41b6158c,2ce2db5) +,S(50867128,704795c1,a190077d,49a87c99,8b10601b,c37b7aa9,908ce92f,28969c30,106fc462,a115f2b3,e83a5474,7a692101,8c73853d,83d8a1b2,2b0bb785,bda8a896) +,S(3ff4aa26,7e8d344c,ac75a46f,7b17af59,5d056078,fe860a96,573a8f0c,164c54ee,2632d1fe,f4b34a45,ac38a80d,236b51ae,de92fb72,47b81f6d,af1b9554,4d426d82) +,S(739f875c,ebe795f0,cbb846c5,88c2b809,21468ec6,4ae09034,6032a97d,fda93c1c,8393a2b0,f3e68c9e,a57d5c8b,f8355d8e,71f4699f,201636da,5451023c,92a1b98f) +,S(717bbfa2,b2c4818,ae620498,3506a421,8cdff59f,2e040521,764b8013,b688c7bf,9229cafb,e99cbcd5,3f73938e,82723d2f,e7187ca2,13d9e0a,57c12254,dbc7f63d) +,S(cc0a808f,2618d1f4,27f165df,4412739a,6ad9af38,e8c25a2b,14bc97aa,1c5b0f7b,3b83d5f2,3d94aa87,9769c3d0,5e921731,17c345a1,3418ec3,2f92d4b2,c1e275ad) +,S(4a0b31f8,8f82abc5,6867fffa,6deb20d2,d8e7613b,aff466db,b260734d,1ef8b1c9,375d7c69,83784dbe,a5bfa8c5,8f8baead,8e94b9b5,95c01d9b,2747a06c,5fb7272e) +,S(52149a1c,53b2da97,f39e9dd0,23443cd2,b21e404e,b6235014,ce04c616,9f5d05a8,a9f9a4cb,ea6d202a,c6b5aa93,28f583c4,45db83e5,8ba7fc25,3eb43e3,df7f542a) +,S(6e294aff,9e9fe4df,9345bd93,1229a7b0,955a3b63,fd19d1ac,57bbed72,50262b8b,abe6fad1,5fe423b,e1a55867,137c485f,85639823,beb6ab2,81dd9e1e,ed447123) +,S(e9a70c2,c5e962c4,dffe24f3,8930e095,c2b0b540,cca2d891,2f6f5b4f,e4592e9d,8d115293,95051750,ccc9369,63b987f3,96bd05a1,49915103,1e47baab,358decf8) +,S(e6c934a,57ec5422,5d42dbca,715e62fc,ae957590,52849f8c,b5f282a9,b82d4adf,6da738b2,40ff3070,bf0c4ac5,50ca5a77,31db8a07,20312e2f,f9de572d,d7b67d4f) +,S(89b46ad7,cbcf1b6e,8741e422,ef53beea,49662d96,bcebbffb,57baf0d2,1441a0a2,b7205431,1798624a,3a1708a8,986ca47e,374d9704,22f7d3fc,57ca7f22,94913e8) +,S(5b949cc2,69f0b0a0,c3b85fd9,e45b737e,7379a4bc,70d926cd,cad87ae3,4e7a686,7e54863,c1efbe6a,a98d6466,65057347,7291b068,a43f1783,9d02b190,9327bac9) +,S(787baad8,9882587a,97b049cb,9906db7d,b909239,aa50e073,d476081b,4a73d7eb,8e3bb416,b57585f9,8b337b72,b23c2b9e,c790ef6c,bd397b18,ab78f8a8,cb662425) +,S(58460ae1,5a204740,c375cef9,e447edc1,2fb6a0ae,2f8d18b2,8e82ba60,729c82be,1bdf3641,d16d89ee,378e83ea,302efb0e,2a9471ac,9bcbf1e1,662885a0,81c7780d) +,S(c9bc29a2,1f7383a3,a90ed3d3,fc5f6d32,1697e354,a77173fd,77899d17,2012f63f,1c850132,db81d86e,e866d9e5,75c4f7b6,270599f,2e48c0b4,94317dc3,97d1043b) +,S(d4c54b66,a1ff77b7,63f8c520,181e4ae2,6b82643d,758f872d,cddef933,36cb84b7,23e64d9b,f7456086,ce8b778a,194f8b8d,f1f0bf38,fbb8454f,d271d062,ddb9b9ce) +,S(a947a90b,b27db3eb,8b4ca4cf,f947e587,54fe6a48,7b922ab1,9ef4b5c2,99eabe3f,c83e7022,f6e12dbb,f95e95dd,2bde8b94,3d72cbb6,5b222f57,94d13251,c9fb975c) +,S(d83f6040,4099d448,8ec6785,131524f7,3e58727e,829b3d58,7d445197,cb367746,6d50285f,831e1173,cfd7de2d,d1c7c29,532a391c,3f450b7,f25e758b,f412a8a7) +,S(75d60448,78902615,467175b4,bc16c936,14bb10e7,c9fae9f4,57d4a210,2d506a0b,885237bd,b4277447,fc7970c2,4e3e7240,ca24a07c,e46b8bac,7a91272c,ad9c5854) +,S(1f96a542,2ea4726b,b639d270,17eadf33,43bfbb7f,f1fe9307,a20fb5c5,f1c4fda,5f80a9b3,ec8b0fde,ee914ae8,e6052100,77701a73,57829803,4cac5d44,91ce0a22) +,S(3c0159ab,4f27b61e,c2599ad0,a79b4228,9000fcb9,ceadb440,24e1527a,f5ebb9b1,77df26bb,659283a,37abc70f,9f465794,ef3fb178,107ccaa7,a5404c88,a67a12ef) +,S(5b250c4a,25293ab5,34f287a4,9f9f966b,7ebc1c93,e5a774f7,c98980fa,7980e07a,dd6c9c36,5c015685,9e1ec5fd,3a740d1d,7eaea301,2311d1,a9cf505e,7e594613) +,S(20a6dfe3,71696c50,c3a7abf9,3341c41d,9d6d2111,729fe45e,f3ceb49e,977151fb,bfdd0224,fff97fd7,ac3eda1e,ec0e6f02,8bf7a3b8,23cb49d1,52d643e8,fef3d820) +,S(915fe7ad,5840d789,b94d1bd3,2d555340,3c9152f0,340a5f87,6862ca40,19825b79,8d2f0ba,3459615a,2036a07,ca57d0e0,f3a4290b,f5fa7327,2431e3e7,bc44255) +,S(d6aefb63,618e2fd0,34e4f17c,eb766d5b,c27c9a15,d796b16b,7cf8ba71,31a2404,f0abb6a6,e862f6e5,d71b062d,e9bb7b9,dfb2e4be,1c5a85a6,dd3e0c25,3617e8cb) +,S(4c804837,7d65a97e,f65a342b,c4549e16,5cb1c50c,cd1549e4,d2d2ec10,c663882d,e1ec6bee,d0bb7243,a384e6ef,100e5180,4de6ac00,b06d7b67,3e445dc5,7b76dc8c) +,S(3a6df802,f372b56,1ebed30b,a4740d03,d257d256,4931422d,fd3c8c1c,619847f4,d168c60c,9a86bea7,e48e58db,d8e6bdcf,b6ea7d31,d57f8996,70f79e33,241bc439) +,S(423eedec,169fa4aa,52588642,a62ec6d3,8acf2ca1,c8098c24,4a56a6b3,169f9932,4887b475,7f27b4b8,d288c05d,3efc1d98,c0428b5d,e4db1cb0,6dcc4782,10cc6f52) +,S(2864f372,8f8c5ca7,5dc56dad,8b968c71,a008eaab,80b8bf28,16bba436,78465be6,14f5e2c3,423f863,64962871,b786c840,50cc07b9,f537ddfe,cf81b95a,a276b813) +,S(cb96234a,985e2ada,d8130ec5,472efca5,7ed7331d,ae7570c4,dd42f4db,9597ff08,69722bbe,5b367ce,5868b30b,31f67c8c,a5f047ba,a7f65202,48041458,66b88d5a) +,S(3be93dc2,99b7e701,ddf0f239,286ac598,bea1ce42,f1e21ae8,1cdf07a7,66c1123e,8a9c69a6,6a475e40,d81b5d0c,7734cec3,40f528f7,4fa0073c,ee92161e,cbb92d00) +,S(9022c43c,7acf3552,fed52d25,d25dd3f2,9aa61fa6,988a5499,6aa3626b,88b7f497,c514a46,f328c9a5,dc2fd03f,81ce3fda,915f1e8f,127348ff,55e4b5ca,2eba0e53) +,S(a24cade9,47a24abc,a050ef7,f62d138b,85c96d0d,2edac403,dad58ff7,8a2a9d3b,a209613b,c05a7b52,41697e24,73fa7fc,412f8fc5,b2fd0447,a2e20e71,949cbc0a) +,S(cb2010d3,94259307,ee3491c5,58efbaaa,203cef1f,8a0a1e99,67a4ff3e,719495f7,1bc5b6a5,b5acd447,baec221,141b601b,a5a3a640,7f84b8f4,319a760a,6226b0c) +,S(fda8c6d7,c6302b27,76172f01,5e59da8e,4af1e96c,3bd05f2e,a393fb7e,1dc1ecbd,87ce1baa,ef24102e,19c7a17e,b267acee,7681d40d,705f7058,c514c9c1,f615e666) +,S(b459fb13,5b9902e1,760286b,b37ffa03,ceabb618,e684823c,17ba97dd,c95ebdf5,6e35fbaf,b5175d3f,ac60f2db,97447cc4,a79c212d,5496ab7e,4b536ddd,797a19d7) +,S(ec137d8f,23b119eb,a286af6c,583ef011,5d21f335,8a1a2df,ba6af216,d03b4a36,344fd1e4,869d68a0,87a1974a,d48b9704,5db2940c,dec017fd,a0605c11,8e5c7bfa) +,S(8e0be401,9f2d3cb8,9ab07348,cae295c5,eb7fd7aa,fa5a83e9,3d68d994,af68e14f,542fcba8,51510baf,6f962401,e8a607c5,34a32971,22645ebe,2dd51867,b26c80d4) +,S(b1dc8611,3cc18708,338542ac,698a6981,a6192261,7c1f71d4,3b72baeb,1c0dab03,f3e61423,5b683727,f1cca8e8,41de0474,e8c4da8,d2bef431,3cc2da5c,c4ccf38d) +,S(d438b027,7f6c7048,c1eba2c,c1d7e554,888a7025,3f513261,3bccad8f,a5a0a9d5,fc419852,23f6ba14,adda0abc,389d2d16,4a910dab,b464232,298c2a1c,50ae64be) +,S(5484d618,5cdf3f21,42235130,62ddf251,1f53a84f,f0fada86,602c4b13,3dea0f70,6e697180,33860802,6ff41cec,cea79f48,b695aa37,2a76d046,47603a67,ccf9615c) +,S(8c1856e7,6842f5ce,82c09a82,4d343a6b,ac67ff27,f6d32de6,7117dd75,59df362c,70f78515,c4bd17c,23f61049,d6ccded4,100234ba,b7e1b9be,16925635,a9aeea2a) +,S(48052022,94350095,8c904f57,54285e1a,7a17ff81,dde1f50,8586273e,40bd531d,7f1ad451,38b44b15,33327a0b,15fba2a3,f70989e9,1c271b1,461750c1,5044294b) +,S(4adae425,86b0b95c,fc26159c,6aa0b1ee,dbbc936c,83fd6056,f2b730ec,14dc17e1,e6d0f9d0,bfec452e,3f2f9b39,4d73c72b,990f9683,b6004fa3,8e8831b4,f46f9d4a) +,S(d296fd2,926eab53,db70b1d8,d5c999c5,7eb36987,62537954,2074ae12,af5844f0,b4472b2,c33661db,50b4370,e0ae7811,b16646bd,3f4771a3,113d677c,7f1c0cba) +,S(1dbf607f,5d1ea26f,ee8e416a,52c8475e,a8363cde,6bebcbb9,bc04cf4d,cd19cd54,832c9d78,60c8acc4,5d00a568,2d28fe07,4952a897,619f8b23,42dee2b5,e20482d3) +,S(12321adb,c5997830,8689b103,ec1552eb,679a3ae9,70ccfc46,f4adab54,f8dcb2b2,92dd316c,bef2864c,bd5002f5,ba052712,3f920db9,44992ccf,1b2f967c,b70d1f1f) +,S(fa2c024b,76460eb7,a64d1e1e,fe059496,c28372c8,1d00cbec,9ea76f62,546642ee,5a848904,a654469b,dc3eec26,736d7677,ceae5fd6,d6f30adf,8c3fb95a,bd8e5d8f) +,S(a77dcc2b,218b5acc,d6172931,91e8ac19,fa4d74ab,4c88b84,775d2f35,3f51e7c3,de872263,4e2ff356,7d9e419f,26ff51b6,c41fbbf,48124d01,8409a516,9735a950) +,S(83d740a8,52a6139b,53b60796,50d64902,9f9fe35f,87689977,66246b2f,91e038a,1c630f32,722468ea,72bfa970,8a27bd9a,97b68e53,12b7799f,66ede01e,9c75b57) +,S(d894b986,d74580bd,84b24a68,eba87e8,32a9c34d,bafc5717,cdc03c22,8758c9a9,f0d68c3d,284574ea,21a357e8,cad5fecb,90a57b52,62f6ee06,1868d970,458d502e) +,S(67b4473b,3f1420f5,a8fcb39c,8671d583,cc1b9f48,e288f311,2af6241c,4190a786,14fb410e,e33f4a6a,3fe5dd9d,c30d581d,a350c756,6b513290,7f3ce97,29310b55) +,S(24522965,87039934,a6927d0b,782988cc,b126b61e,db154f07,18d97d41,6dc8f0c6,538c4e2,a7e180e2,14e36785,6dedb105,f688f1c5,9bf81d30,d92a8a93,d3c5a82) +,S(b47bdb89,b087a27a,663f9884,7ab44a64,43fc43df,bb61f4d2,bc5b7ff9,234644cc,ee508868,402613fa,1a200032,afacf672,9bb3f7f2,43b2f415,383f4067,d0212483) +,S(92eb31b5,79ac7b0f,d32ac278,4f3d2c63,93c285c9,567bf912,584c00af,3be97d8e,518e379b,ea24a823,e725a3a3,3608e62a,7a40aaf5,318c2c,41afefe8,ec9afe7) +,S(a5e06969,cd69f1b6,c30ab55,1028e1c6,1bef12b4,b2c2d1a2,572c3648,fc739332,378a3b33,3db8d289,667bcd98,9a3cbe9f,f20b08de,4047164c,7f4bf9fe,5d1f93b5) +,S(604823c2,f1ab2bf7,eba63c65,610fe0eb,c958e8c4,7f509c8b,42b79934,7fbd9bc6,29f532aa,3707e872,2169a02c,210fa9f6,100c6b1f,926c73e,a3bd0427,a1844733) +,S(1b4bde22,bfef0cb0,ec9e84fc,e3af2e8d,ce7f381c,e9766b1c,c1d5fd90,9a1bc891,ab20347e,3f4c7ba3,2bb773d1,50868756,69865df1,18297657,6c283704,49451f49) +,S(10caa116,2067d668,5371a20d,97313b54,4d79b61b,3bb41a87,980eac97,e82f58ee,7ee4f118,32d9c2bb,1f849731,d779d12,571a084a,4ecbf4d6,128f33f,6af477e4) +,S(71e7f07,513d42fd,5c0ad06c,c96ce17d,3542a4a1,a101e581,f7394c2f,d89e2072,e214ca42,1033650f,e420e574,e2266c23,3897de25,90dc3999,bee41181,db0a81e4) +,S(fcbe392d,82b4859a,2424ecec,dd8cd47d,bbb89d15,ea2b9591,f5ff1067,e2cbadaf,9b06334f,6ae45d74,44b5f09a,995fd91c,a2712ac8,b159126c,8cc0120c,513f0bcf) +,S(a64d9e9b,5c583eed,aa7934ef,a7ad036,8dc9adc1,9437f97a,7a16b645,cf46e262,9357dd,1aef4b07,a376b468,99692754,9ddfe9d6,7982a7fc,d607f02b,8a7158a2) +,S(e634938c,aaa4010f,f4a1e760,d87a253d,5fd645a2,4f85a75f,8eba78bd,d876fcd7,84be5fa9,c11d8c3f,54f757ca,d9ec4e18,86e52db1,4b3cd0d3,97f666fb,f347d24e) +,S(4640245e,23e6eb75,6e0a44f7,698c1faa,33ea4f87,7a52f850,3477ad4f,8ae2f4bc,ca2a72a4,1348d3f2,6a7fb977,d3106710,2494a982,a96c6514,7fbfcca9,1ed2225b) +,S(c2a175c7,badbfe95,cf7db594,626a42d0,1247ebe5,160c58a0,2437fcd5,eed8c59,94814fe3,7692ad4f,ef0f4fd3,41c63f84,b282324e,faafbc59,38d88f4f,eff210e) +,S(b1296159,d0651519,d76bffdd,98013d1a,bb17de49,111e3035,5f7a1d40,3d8d9148,ae3c442c,2dac0847,bd8d9052,a5470b9c,80536fd9,feb5f820,e4c54ac1,78aa44e) +,S(d30b1976,b0867b57,84d5e619,a5a63516,13980093,5a9458ed,59e4a3bc,ab69b7c8,1b1eee49,690de06d,7a71c334,4fc0a647,133f2fc2,99a8f096,a8a445bb,27f5b96f) +,S(fb1c3b4,5b0f6f0e,35b93a5e,ea157e60,134b00c5,38a6e429,301962f8,38fe51ae,cf79bafa,d7c3fb08,49e1c2cd,48a90ae4,af507bba,5a42f3fe,bb1e101d,7f5fb818) +,S(2bc4d2c1,d34c6d41,9d97ddc0,c758fac9,ff6489fd,786065a3,61ef442a,fe37199f,5b932f15,9500ef4e,a331be88,7022f42f,5148c54b,30957b0,424a168c,c6d76ceb) +,S(2744c1af,3459c35f,d8e1b27,668ac653,eb25f017,e4fa15d,6c1a6bae,e50f3a99,12f95a25,a87e482c,c647b1a9,f22286cf,3297a354,4c7b575e,aa888dd5,6db2844a) +,S(6429f3ff,d37b53d4,88024393,d3a9dabf,f84e3974,ef60f446,61ec9da5,efc736ee,e8426421,f15768f0,caf020ec,3999e8d3,a1aafcb8,24339574,fe119500,a168016a) +,S(33c132ef,437e9dd8,ee9c028a,2ad51c9e,5a836eb5,4bd97e5b,4b5b6bcf,38d006af,e2527602,e5e74d67,5a5115cb,9a89c579,c760445c,c70d95f1,9ac82a1e,6ca16c6d) +,S(3ac856f3,7d53e19f,f6ab49e3,94da6ed2,c8645e65,f4666bfb,163778ce,7cd910ab,ef40efa2,55d7a5bf,99e39055,8993f753,8fd203d6,7fdfb7d0,81cf8bc7,947cafcc) +,S(5ec9648d,b58770e0,314217e,f090c776,396f47e8,ba27c30b,98c35955,aab03247,3d3402e0,8fb71448,6ee97fd9,15293e53,b095fe03,9cc3100f,21240a24,d70819b6) +,S(54955c84,3c5dddd,89f60de3,828fe4f7,1666d807,ff88006f,b46c37bb,8a822645,c8745950,64b3c721,9eda8253,633deb6e,ac9a7825,8d1de2e6,c2dee05c,f167405d) +,S(e0e845f9,35054008,fa44cc4f,1f2e538,33b58e73,bc6a04fd,c16faa76,c1a92d3c,edc48f46,2a41dc1b,bc604e0c,82d993,edc2990d,f59fa034,11702d86,46dd1c1d) +,S(bdb43235,19acce9f,b95f83fa,485940c5,69108af1,376cd09c,884e6419,718ed14e,5669c5ac,84bacd6,eb6fa8e7,39da1196,dde69170,f5d4e5c6,2ad528,66b6d9a5) +,S(d208bcfd,f9754dc6,7e099754,983fb58d,e5679bda,96d8404f,266c0e65,9e4160ee,c602f6f,f0f586f6,7ac771d1,fbf9d807,c2edf68c,a2c10cc2,314221fc,cd3007ee) +,S(3cce9096,450e620f,29b2446,39e8809a,39000315,a887d6e3,da141ed3,32b1c30a,db0ee91,b8447860,18289da1,11b3bb62,289d21f5,2aa8f436,562e982d,bab44be1) +,S(6c351350,d0fa9ae6,e1723848,33e654a3,f3f655de,7530d9bb,59d92462,1dcf8253,2e5ea374,7a368904,e4cc663,feaf6f92,4060dd70,95bab9,ca2e0773,4c48df83) +,S(c64b42da,d63cff5a,ec1eb168,41fead6b,3dbcbd97,f6786efb,5336da16,35950d2f,73706863,cfee031e,3fee4be1,9241cd94,42c24f4c,c57faf70,f8ff8b81,f094ccef) +,S(c4b99a41,7b2277a4,159bf3b4,859e36de,399862ac,70ffb482,b92e1b11,99c748d4,6ae88f86,1ff14b38,b545ec86,1a808c5c,cc78c3e7,91b48f29,350afe20,9efdc33f) +,S(eecf955a,f1ae50dc,44b57715,5ea67ae,1ae39cf3,fd306eee,e943908b,a7a42a56,26c9e114,22cd3db4,b278adb0,8e4c16a2,1a4c0a9f,b837a493,6cbdb70c,65fc5be) +,S(454ef33b,402e3a59,d437925a,b62100d0,974abf69,8803c04,436b4d2d,5a5819c9,4a38e398,1e1d9809,72df7faa,b06bfa96,20fe213a,36ca0227,c7c20ca9,2ef31563) +,S(50f11935,c20dd410,7a2cfb65,2c94e39,8df7d985,c183259a,70f6a04c,6ac5734a,aed27454,75f207b5,dc1e9f4d,f8cf1108,c9507b03,d0e889d8,d33ebfb7,3b10e670) +,S(43bfd366,10b67773,a254a077,624c2b53,4d8ded30,bf53e918,4f10e597,e2edd980,fd0655e2,e6b257ee,a249a5d4,299146d0,e08653cc,cef19a88,5ad6b33b,ae8f345c) +,S(7ad3c8d8,85cacf19,ed6aca96,4607f344,91448d7a,651fda8f,2446686e,bd06a9f3,9cb921c2,3e338436,73fa1bd,101dc4f8,a9a714ad,7fb91057,dd5af779,835000a0) +,S(874346d6,9cfbfc7a,2e13c605,baa69c5b,d39bd69,36841594,1cc50cd3,18c17380,35326549,dcc29eba,4d35a559,e8f2f0ba,b4d94ada,f2c18612,a45c9c90,8d99ef4f) +,S(1001f64a,23afdd92,789390a2,bfde9ae1,d85737ce,3e5087cb,b1bf2d5c,fd0e6943,184b6a2d,ebd086eb,6e04db54,2146059,e6ee341d,1c8854e6,e57345fd,5dd237dc) +,S(659607d2,68695906,fe752434,a229c309,60b33825,a41589d8,6e663230,c1610fe3,77005570,df191869,38a56d95,4643d991,486c70cd,3d5c336e,11a9667f,fd8f7862) +,S(eab041d9,67f89c37,c04bc6f5,a9059d69,a53e5fbf,ef7c17e1,7cef48d7,e346abbf,a2c2fe6e,63e38c06,477d2821,d22b4a0e,4edb0b55,cb1d9fdd,6cd01ebb,d8fa51c9) +,S(4ff2394f,377db94f,e96f51da,d7364407,ed6bc1d9,3822f24,91630c3c,abacda99,4a77b936,a42493f0,d739afce,b769c7ec,cc0d4720,93e839a4,330054db,22e93b31) +,S(7952c74d,e0576ddc,c85f42e6,24937e98,1502b2c0,105b69bd,4e35f59f,1c2847b2,e7159304,dbd9183f,3abde60d,5ad65ab,5a4972ba,19739b65,1d50c056,ebdd5b81) +,S(b3149a8e,f602b6a3,c69a769d,893d561d,c7438a74,bf47c2f8,ba07941d,b0dd214c,99e591f2,2f8da0b0,c9d7024b,c82d1031,cc4336e6,bf1436a6,bf03bc11,3f041979) +,S(ac3bf353,ce672165,a7e736dd,632c7018,1e454200,77471380,7b875d3e,c81ead58,78def098,2f0f5936,5f5c6519,1857463f,7376ec93,f15c01c6,980d352d,17a40195) +,S(9edcef9e,d26ac408,61d3fdc6,66e09068,a9b1e05,cc23202e,1d0b6e03,faf546de,b1387281,71de9aeb,b02b5290,d3d56d63,b6c98c00,cecf8b0b,540f70a3,79556f2b) +,S(fd48622e,8dc91972,7ac21c30,c0fb8d02,d8cfdead,dfc39a22,59853e17,5d8e6d26,4bf26514,204912d6,8bca0ce6,71a967d9,921bb882,33099b76,7a056967,3fd42bcf) +,S(e6dc2ea,c28def67,78b0a351,6ef0f4b,104fc7c9,88a03a46,8cfbf207,ca0ae0e8,d1892329,e77d5770,d9a84e59,c2d6f6e1,db6de419,87c5e3a0,ea508ea4,a11b3762) +,S(e8ff8f65,559128fb,3fc52650,ba063717,cd2d140e,ed3fc4a9,10dccaad,bb0503db,f35c361a,8ea9b3a8,139676c,3ff31cdf,5511535,7859e5f9,3590302d,bd21e21d) +,S(2e18c597,d4e4a4c7,d54bee9,215a1ee3,d149dce3,25cdc4af,f62a3da4,1922c2bd,3e8595ae,4b6cd57b,7f685a75,87ed61a3,281b52ff,d76e9126,4a0f0666,701c5354) +,S(589924a1,2cc867c5,b2289f81,2d93f324,c2df420e,3c948bbc,e74b6bb4,6d30f262,f9bf3d02,cd0001c0,bb9558ff,515ee86f,e39d4357,fd39cc3c,8ce73c75,72850466) +,S(ef55eae6,4a07199f,1a3f3463,5007a8c3,8d39db17,48af39cb,584d4471,d3d32e18,9d31abdf,91bfedda,3c1f02a,aceea672,21d347f3,5d355042,75452c91,5f4b19b5) +,S(7a8f75a9,41182eee,49883295,56588c86,3021548,70ecc05b,31b83a1d,74be05d0,bda4d0ac,ac72ccc0,c07270fd,1c2bba00,4cc9ce5a,fc927f,6d4bc0a9,b2fb4a64) +,S(330f8a4a,582dad9c,159e0f9,a47101b9,223fed7f,896679e4,f764b02b,3d1d9eeb,50695f30,f9dc9c75,6df20cd9,aca3a06d,7199c138,4b3ede52,2dfa0816,31fea2f7) +,S(6dd34c6f,b89722cd,182cd5b6,a0d83132,56814bc,7ff147ae,668618e0,30bceab1,8998216e,8ccfeee2,78e5c0dd,e206d3b,1fe058c3,990159f,be3beb2a,2a97cd60) +,S(66c2d4bc,1e1ee63e,75481e23,1e6df60b,82c73758,36d4c9e9,fa99a576,304ceb8,f6871e84,fcb56780,682bb226,a8d2f46b,89cf516a,7aa0de01,2ccd981a,b739244c) +,S(560ac5cb,b9a55c0c,8bd6a36e,9dc90922,9297a452,b83f8db0,e0899577,cdb8d04d,b6255568,4574e609,ab7dff47,938008da,5b11adaa,480becaf,287f2216,cf1c7891) +,S(a2377a79,e597dffe,224988b1,63ca63c6,67827b81,ccc645ea,cc23ddb2,2a1503e8,7663e301,4dcdbd71,620ff660,426581cb,7e723605,72b651a7,103faf36,480834bd) +,S(fac987,e1c77065,bb1eeec0,fdd92f05,5d10e738,befbb155,152bde06,87c7fadb,c6fd2faf,683f4e87,77a6166b,59c4b93,e7f5d803,fec49ef3,29e1a4ee,9981e803) +,S(81ee9f52,9b5c6b11,8fc6ec23,88f3ecac,4120f8ec,d134d22c,f809e2cb,1e88a490,e8bba906,3a3ba848,7bdf4a82,c5014493,40da0e2b,fda93fc2,b6440b50,d24536d8) +,S(e6439a0d,545c7431,cd8321ea,420dd3d1,9932427d,475df712,529bfd17,99dbc4aa,6c86e739,b6d0f23c,d3570bc1,86fd9e1f,e617fc41,8089f2a9,d42d0b91,2b4c8d39) +,S(e08169e0,f7362908,a0d207f,bf49a44f,5839c76e,7ad80a74,44e7d24b,573f0bfd,948ce18f,15ef6e2a,23f2db47,db402d38,2a4a3cc3,a8a3756a,c382cba4,f608283f) +,S(5687e6f5,7b2bacda,eafe58b5,94bc322e,70c7afe7,884ab4fa,4d46467a,7a8ba729,994d9091,e432b4f6,72e7f711,b5e0a7bc,b07fae10,b6e05ca0,5a088cc6,e4d89d80) +,S(6edfc830,82a178b0,d9160f4c,f0b01004,65c29bea,e3c29d31,e3826aad,9fa1979,5f4c6676,3df8ac3c,4490ec9,fcb0695b,e9c0532f,df526e83,f27ad47b,5bfff2d9) +,S(28128135,a17d0e29,4871831d,2542c2e6,80dcd79f,6b4fafc2,722b7db8,4ed449ef,4f7e515e,b5c7eb7e,415d7b02,83ff11c4,8f3f3ce,a724c476,71d02d1,50835702) +,S(f55371f4,2d617023,dd5542fa,db9a9127,c16ac04,1545db5a,a18cdbb0,cca4cacc,d0c795cc,54057d47,5bd080a1,acbe6881,3263f593,917e012c,dc1bdafb,920b3ec2) +,S(10fffd7d,a62de848,c07b50b9,64e3b31,ee6a13ed,996fe92d,565cc54,fd0b7c1b,92107e28,5319ce07,61e5f212,5724f2eb,fc61498,f838717c,6637c7af,8f0fee23) +,S(a6a73f68,bcb103c0,523c8f28,f14fafd7,5b8d399d,617a68d4,6ad0a1c8,6f12a46c,d18efb60,37f40a9f,6567c993,24f3a7a7,543fbc30,feec0252,87dc862e,b22fa279) +,S(2984cd0d,5c4f1c06,3854d233,6cdfdca6,50c94275,975feb2d,1b0b5bb1,c7dda582,41b0a86,8064dfd6,5c2653b0,27dfcc75,50eb755d,7c1f5c78,b0c13493,acbb4db0) +,S(a701d075,7be9ff89,67c67622,dfa8ff9f,82f7d5d7,814f6c29,c73045d0,c5b16589,ada61af5,62851c60,66501019,70953ba6,fca0d99f,42378b8a,5059ceb,2a0835f) +,S(f07463c9,c37479e8,259a32a,a2e8f283,27cc267b,95aec8c1,1242a092,bf4c47b,1ae9bb16,e538ff69,1e9ecc98,838e112a,a2016657,c7af104c,ee92471c,df6cc136) +,S(fdec5a71,21a17f37,b4c2e93f,56d910a1,788d2da,b3cce509,b3e2f3cc,f141043b,a62e32d9,336fcfd1,4bab6cf3,26ee3f31,4d2ad023,430768ae,8f093408,e3505d90) +,S(be32f9cf,9a13d4d2,652d122c,c0ce07b,da21fc85,52c0808c,23dd5a5a,9ffb3599,a4a73b26,2b5f8239,e8c279b,20f79c71,7ea47a64,1c084f52,f1bd4f3d,dbcf9c43) +,S(735a1f6e,2575ee01,9ebee00f,a4acbcc5,93bb6572,c4db9505,bf96a2f,43b66f38,20b1c7a,99c6cfcd,58b3f00a,3f9d7739,f9cb682d,946b33c8,879f041e,15e198f8) +,S(a0b840b0,6d92eb95,4f029204,1229b9f0,f1838bdb,4ead7432,4d8facd,70f7447c,383fa2d6,47d88c1b,fc9b04a8,a27b3a99,1a22b82f,7c99fce5,5cf30855,ed1c22f7) +,S(3e54abd4,36a9763e,52b7f46f,4955a339,6db284cc,77d0b351,fee7a568,e4774c83,1c64ede4,fb372325,dd435f71,e4dc914,391da9f1,ee08a21e,2eb5ec18,2834b0ab) +,S(24675c97,67f69242,4e1d43e3,1c46ecf,b418fe9b,3fcdb495,822362b,2a8adcb8,9e38e08a,4359dd9a,a9ddf4c0,8fd1147e,c70ccf1f,8855cdbd,49f44dcf,1edcc36d) +,S(16e0176,9f5a5c0d,f6db88e7,fc95419a,96f836f4,f8255a96,77ca2710,2330e317,30641d0b,fbf7a1de,24c72692,b7032355,6996bf3f,1b541dae,d6ccfe8a,f847646e) +,S(a2e30015,a53829d7,c95d5704,3d6dac44,bca932b7,d4115826,c602aae6,8e4ef847,33ecf0cf,e81236c4,e8fb76e9,645e4827,9bfa617,f6d2760f,dde2b110,77da6ce3) +,S(cd9bcbcf,b7338c75,3fe393d2,2e2e44f8,45a09b83,fe4ce29e,546f2a58,7d7422c5,7683e5e7,f990e09a,e15902e6,c57b8db9,e2b1d29e,8d3bf33a,f90291a4,616c794d) +,S(77a00bb9,6abb918d,774a2a4c,3828fa5d,c7d40bfe,aee10091,f5d92cae,cdfca277,f3febab5,3310a2dd,5dd7a5e1,33572b3a,83950172,be7e4cd6,fec7575d,10142e02) +,S(be2f342c,ca1f161,d15f98cb,ccac9f2c,806c6d1b,f34656b5,c671c730,bdae8efa,c9c7a70a,88ed250d,6a7c0307,d3dd907f,ca8b399d,4affce18,e988ce5c,e0efb5f8) +,S(538bc08,c3c775bd,33edee48,c96c6fbc,1435b0c,f00aa42c,6c15fc7c,5540dd6e,9d8b1293,14283325,8d676a92,d479ebb2,c5ca171d,a43fefae,74c7740c,7e956eb9) +,S(d5e26827,fc0d8283,ee020376,56e83ae1,3ee306db,92d0bba1,6b3fd99c,7af15578,b41d4816,b9643a41,c4f8c5f,4121cddd,d7eceeea,9f2156ff,676d6d2b,61b7d210) +,S(7d18f6e9,95f9077f,c371fcce,729835bf,aa903ef6,682404da,bff6949,4b7faac,1423bd83,89410b9,a2cd8c3d,3d13b495,d856b103,eeb96e64,8c258ecb,a77d581f) +,S(fcb3cd95,fb0b4940,bdf0bd4c,ff534d94,26489c72,953b19d0,cedce320,6e3eb556,46043aaa,3d1ce85a,3009911f,763f49bf,df3d7fa6,347f5573,4c6c36cf,97f15702) +,S(a0e8413e,f66527ff,12f6de1d,2ed4eca4,6617064c,afcc4e98,495f2694,34492800,ac640fc,e3d5d094,54ee6811,81f8bc5f,3fb1bac6,84c8c572,b24fe3a8,66234d13) +,S(fbf60da6,aecd3cd,9137b28c,f7bfe541,efe60e65,52470f80,e301884c,1e9cf33f,aab83f4c,9d9e5ed9,ee35be7d,33a02bec,ebca4f40,8f6fafaa,6f385a89,8f7d846b) +,S(771c8d7f,73bf2b9f,4f032e7c,daf17c39,c375ce1d,2e180758,fcffd82b,26fe206c,af22f29,ac2ec5a8,ecb69e2,aa954f49,63d4a58c,2d6769b2,5255e9ae,2689f756) +,S(a30bea5b,4a911ae8,de11a310,a9cd3616,54143337,30aa182e,ba75601,3d12ab80,aad0f1fb,a9a8d6a5,71301b1b,dd11f4bb,161c26e5,3d3d5143,ad2678f8,9960029a) +,S(55d93940,b0a76283,6aac5bb8,c04f490d,e7ad8da0,4cee090a,e1f381e8,5c13fd27,f1c58d73,b90819b,bab9933d,60f54370,7a625449,d637f01d,bfcd6b44,bb467937) +,S(f6b03260,ae0373f5,b2ebaf15,1a74369c,22535844,13ec4356,ea4a9a32,f2132f81,4fd750b3,7f377f97,7b62580b,6ee7176e,a720a434,8df7aa86,642cc6b3,963cfdaa) +,S(80f7aad4,3deccf41,cf4540db,97150bd4,f4665ef7,72bf6c4e,e551c566,d11d13c6,20a9b836,67cbb397,aadb1211,fbc9a78e,2e998354,6f263403,1d844e7,b95766aa) +,S(4f574d76,130e2eac,16bd6b64,85bdd2fc,88855c3c,68a232b0,29560509,463f0c90,33dabadd,62ec0192,9fc3ad15,587150e8,ead8518,327207c8,7ad2a7ec,c712d268) +,S(41b6872f,f47a0d4a,764ab086,764e1844,a8b4c775,cb2bb06f,643a7c13,5a633e6c,301d54fd,d55c9204,4d337b83,ff17dec3,3faf0bf7,ddf7b5c0,afc8934f,65d54e17) +,S(9f4c75f0,cb44460,ad14d416,76c8b60a,1ae979cb,1ff6a506,b5523cee,8acb1bbd,253d8a0e,985fdeba,1ced50c7,aa3724ae,79c75c6d,7c82315e,65f3b579,5fcf70ec) +,S(25db3430,667796c3,b5f3ec0a,cf4f11e4,73518ce9,aec19932,3f0c5adf,e32f4a87,cce88dd2,ec02e348,ba569fec,15a3c527,ba580e44,c32f25cb,fa6f99f2,a1eb4250) +,S(fa71cf1c,2312c228,c706a7a0,2dc3b9e2,f571b468,913b9cb,3fc5ed1a,faf730d,156df61d,752533f7,afee2781,30763eb9,45a6198b,a78a8288,f30e381b,a809eb61) +,S(f5d3adb5,6d77855d,8e0d0b71,300e620c,f96a45f1,5948d97b,affc3ad1,7226294b,95fea642,5be2e987,968f54f8,f3fb30f1,e9a1ba5f,57b68b1,101a5981,a47f9f4c) +,S(907eec9,6db952f0,eb7d0436,c47f5980,dcae53fa,ebabe57c,aaca00e0,10361460,1cefe286,19dfb7f1,969c7618,e0ed4775,e23527df,6a214754,4cd066a4,65f92468) +,S(abbcec4,36e06bc7,bb92dd79,bcc5d9d7,73189ef9,2546dfc4,54b5d624,2c96e8cc,d1546a38,1f335077,ef40473d,baac9c37,66aba23b,8040c4c0,60778d13,8603be7d) +,S(42f1594f,b1e088f7,2020b68f,7fdd9027,b9638619,b0320410,fc4bec4f,4fbdda76,9a417cab,515a08fc,9e7a7c64,7029a457,9881caeb,df8430bd,c1712af1,3c6b02ba) +,S(a4aace90,751aafa1,fe3e14b9,ead1d460,e1cf029d,cc82afb2,4d169248,e63f83f,97ec83af,dbf32c34,df9cafe7,de0b6ee0,67460d5a,607e1ea,fd13a96d,51999d54) +,S(ac7ef2c9,56b41a0d,824999ca,550ddce0,83f2aba4,8f2bce5,644a579,c0e248c4,d97b0ee7,f3a109bc,bd308b3,e4d4ce2e,c1a65878,e7e5939a,76c9d8f3,6959c5f1) +,S(e9cb9aa0,ab09aa1c,18daf08f,bbdd0457,25d4ac95,8607a88e,5bb14c1d,61d826bf,a1cc215a,124e31c2,e426e337,89736101,b739a56,b6d4e139,ce65272e,2e4b9a5b) +,S(885de0dc,e9700b34,9e10dc17,68f9fe12,2672ed3b,ff9d20cd,93b98e38,ebcc67a4,f66a36d3,75272f66,cad46fcc,cc5d3df6,8c023da0,1ebcf766,f4dfbb0,60e1eae) +,S(8ad4ade1,ff9a19a4,fdc89e75,e4cb61c9,1485ebce,b1e4c063,ccb8001a,c5038e6b,e02acfc2,19c22881,d38a8232,fae54d82,e0b1fb77,e6b8b741,890357c5,be261ff0) +,S(5b395388,a62979a2,b931f243,7f3f65ab,292ddad7,728e67c0,e753565e,578fa354,7e77c8a9,7c274030,b22e802f,f0fd69f4,da65e54a,b50953f8,b9945b79,20fb89f5) +,S(271982cf,eb593e95,17a8fa5,6f62fd23,ddb6c7b3,8e5a87e3,712793b6,f10a2d14,6661cb55,543414dc,e02b3650,8660d54f,48086cbe,4b517092,564188d,6815d2ad) +,S(458be91f,a61f477e,47d7b997,931c992,86281efd,21445349,af820000,58b2a93f,48725c06,e7dbe303,f0c73d43,a5a62b6e,131d004,2bae9dd9,ec12cf97,8df04c49) +,S(763f00b,348c1cb9,e922c6dd,a7e72e22,8624fae0,158af602,457fffc4,cb0bf3c1,8119c3e5,b190c6d8,7f3d7066,72136a3b,d0f1b198,d9f304b4,cfb383ec,e075de74) +,S(4fd5e9e2,77fdf260,8ece7268,10343542,312773f3,2518b363,7075fe98,dcf7719b,c234141c,d3e83309,539aa906,2b17ee35,99a3246d,86ad20d6,2885cfaf,5a88162f) +,S(c578afee,a7e492e6,30ca55ff,8923d9d0,9a6d0583,5553c61d,fe871b6d,e1d956b0,bc2d5e2f,add48f2a,50e357cd,4d4c120e,e744fd96,dca0a959,c0bf482e,2e081ce5) +,S(df02c64e,7a60b87f,73b4add8,5ad93b40,bb6a862c,18e0fba4,3f722650,c0439107,d86dc018,525efc69,cc7b282,cd145650,3b9bddae,607e14ef,3e380d53,c266fe29) +,S(9471f488,84cff3a9,2a99dcb9,4cad96f9,d4761570,c0bda860,bf1b0a9c,32a27a4f,23471d9f,6b3905a2,6d9481ec,dfa10a2e,7c7a5405,119dc8db,de839140,2e063e13) +,S(6d1b5784,f58e5393,fec90c50,a674278a,cb841f46,97da9eda,12013447,a2e0b863,d052c806,2905ef3f,6302892f,48b20497,e89cf7d4,3c345ba5,94233cf8,2586a17a) +,S(94eef4c8,be627560,17e13634,53f733a7,fd590dc1,294cefb6,4d8965fb,3d2ed1d7,49a1e5e4,d72e6a21,14e7c4d0,eb9c9240,b3b988d3,21d2999b,46a562e6,1a203c97) +,S(3206fc87,582d1267,92c2a68a,7400a29f,61097fdd,3ecf4cda,fe495993,87ec15f7,c9a7af2b,88df18f4,fe453bf,fc4af355,519fdf21,9251bf6f,879f291c,32a38eb2) +,S(fcd215,45f8a36a,a5a81bd7,1fb1804d,b3fa112c,c21542de,27cd34e7,f7309a1,191c6b9a,42b0adda,bacffaa9,89bbebea,3424a3bf,11345ff5,2af9c3fb,6193ad0) +,S(4432309a,40f6c71f,cb7fbe26,d6390778,fe6f816,3ee50264,2b2027c4,86fee04b,550981ec,b4d2f6df,fd25f26e,6d65f62e,5e549c1d,79639c4c,d07b6282,2d075847) +,S(7cbff748,7bed64ba,7d6346f9,18e23992,a3712ed,1b7cb89d,a6c0540a,335b582a,ddf155a2,bfb25607,ee6bca12,f6df2a01,98513445,9b353c60,9806fbbe,2d9fbdef) +,S(f8cd164b,ad3e65e3,63368645,76c49035,a95f7928,350c855c,fa534f6,80709789,25412c86,23bca2e9,8d5531ee,d57c80c3,ab01abfc,498cbef3,deeff0e,ae6912a) +,S(6fad2644,990a231f,c27bd678,36ff84c0,11fdec01,120dcc0d,f114b032,1d60648d,6beaeb65,ddd28481,a23af85a,5a417323,350d057e,1a574b0f,5d994816,844d9d98) +,S(1fbf086e,d0adb5d1,9c49947f,d019046b,289c5703,1cf876d0,8cba81e3,7739dd6,86e3511,3d4593f7,a8142c45,8e915fcd,685efd0b,f8cca8a0,79ebded3,f4453acc) +,S(30cc2cab,fd0a2244,2c8a6e00,5b6220e5,4061dbb1,4f8ceabb,6215bce,f5f5b312,b5a1f70d,4a05fff9,9716ac44,57a4342e,7d4bdef2,6cd07fee,b515c56b,19fe72b2) +,S(156efdd1,901ebad9,70eb167a,bb99ac5c,676a0929,3feb0b37,8ba19ba3,6c2a3935,b1d39453,32f0e107,15d06df2,d784b1c3,bac221a7,f184bfe2,4824a368,9ff33051) +,S(48682e29,6b8e8123,c9fb6246,5e8480d5,54350734,bc763757,f319d40c,87f2ddfe,efa5e5e2,be832508,e71b15f5,3a7f1d77,773129e2,e57b2b86,9545cfc9,a20360f8) +,S(d188747c,968b67b1,88958f37,b9990bb3,1a54e3d3,e3fe9e06,7aa9b1a0,87f5e3d4,6d60a049,25660c21,81efbbd5,6a436409,6bbdfa39,b37f70e6,4d13f3ca,6bc76b92) +,S(d7cfeac2,7fdb5922,a5f534c2,b1d325a2,903217f2,ff41b6ea,1e5d2264,8095d3,19618c66,87bb0d92,52133c84,26fb8aa6,4fe1355c,86aaea97,b9ef49fb,de063e75) +,S(dd795951,27b0ff86,94dd131c,e85ca6ef,9aa2022d,d0c7f053,4c83735c,43096c02,caeb4cdc,2633b01f,1b51f7e6,103ede8c,a0ccef5d,e33a8ece,5ddfba8f,736e2adc) +,S(5b2bf207,9a319707,52496851,68aad1e9,5582408,7e5d361e,87b77900,d9c63939,728df41e,69c939fb,59803668,6c44d0b6,f102dc4d,ee146a33,42e1c04c,9b6e30cc) +,S(d2a26a5c,313aef0d,6ac190cb,11c84771,abf97d8e,c7e6e67,bd3313fd,15c2ba11,84a1fb57,1507d012,9d98ebf5,34fac803,5de7a43e,48868269,d5e9656a,773fe768) +,S(22c22c99,860b2b6c,630487f2,5263e77,91b62450,290e9df,379efa7,1edadb52,d2b227b3,dc85c1a1,ed64a7e5,6dd6b178,ce0ab5e,68647b50,1178ac78,4b7d1c93) +,S(b811b039,d2cf5f3b,95e38e2e,14da67bc,417cfd8,623593ee,1f2e924f,d9a064c4,a860653d,ca39030e,8c1ed7bf,aeab73f2,a68cb8a0,5263aaf2,431b6f8d,9c862a28) +,S(59ee23c9,26b38d6d,d6c091a1,d4adcdca,b3a5a548,a5cdaf92,fee9fe2b,c3cc2957,67462318,96e4f107,67e39d47,b03268af,5b54edb0,9f9e8e0c,3f3f89a3,e9d204cb) +,S(cc79ede7,ca5a9ba5,a7c5114,d2039d5e,c6a54db8,fee6c102,577a20d9,18ba857a,2cdc980,3a06af30,c19b262a,12f54132,933ec985,afbd1598,45c40be3,2e24861a) +,S(1319c7a6,2f3959b4,cfee1223,b225c6e9,9070753,a1ad33d8,8f3a8b78,a886f7da,d8a75f9d,b8266ea4,2b650265,6b6c0ee9,7f3598d6,3d149ad6,9a5829e2,f3c29085) +,S(e4ae90fd,74e9b229,b9100cef,1da59b80,753b4f0a,cd7790f6,34930a92,b1eea356,370f1c98,f72e698,73c8d0a4,e76fb117,d7e5a9a4,d13521f,f4902a1b,ed3688e5) +,S(286a98b7,b0b0527c,310afd37,717b5061,467be24f,8a0b5528,52ff26ee,d658988b,d10699be,f79e800a,519b964a,163cffb9,722c3ba5,b56694a5,c1a9b883,b32965d8) +,S(9b8544b3,79746ba1,8524e084,2d15b853,46577b81,7084e02f,7d0cb820,7448f5d6,8421c0f2,ba15f648,246f9cb7,3b10d6db,1de7aefb,fafd9b52,16234dab,8e70218e) +,S(81efaf7b,50a18c8c,2481299,bbd2adba,f3510ac4,f871c3c0,f849ef6d,4550681a,ea8567a2,9c871ba7,fccea923,fe07e8ba,2071d7db,25d33ce7,a6125c0c,2afacd17) +,S(6680fbdb,dab850c9,115d5765,344f1466,b88cc5dc,8de9fab,549f281e,974ed7b,c7871b4b,2690f4ad,1e67ea81,e2cefac2,988082d8,b1c70e67,4389c79a,bc880368) +,S(4c38ce7b,a8e3d317,6f615d6e,27578edc,746fb80e,4701efae,f7557469,a1dce4bc,f6e73d73,61ff5407,10dc9f1a,4bd5c1eb,a7d8c8d6,45f0427e,a4fc3e45,3990b88c) +,S(767146d6,bc1d5bb9,c73321b5,4cf6bc61,e8209703,fe4dddf7,2b3d6089,da60be69,86df7dc3,6894f88e,fe24a4ee,fc78b1e0,fbb5138d,31666be7,97b8934f,d0b9a37) +,S(bffd4856,360c02ac,ee741a65,486d5a7,44e2a005,9db5ef5f,f87b9e18,3adbed20,c11246aa,3bd4ec3f,71f88d2,cb3b96ba,2c210f90,d8234c21,99bf7781,f96ad781) +,S(ad19b5f7,45556650,eb496450,968d056a,fbcb55b6,8852f510,ac96df54,cdc677c0,f78295f8,59445c52,d6ea285,3fe9baa0,5e453bf0,9b3f4d28,6c99e858,62a04bbe) +,S(5924f679,bb94f6db,d8232b01,ca8dfbcb,37a83d24,d0e7026f,b526162d,c82aaac7,baee6567,6a526460,ec7563ad,42482d37,a42f2fcb,f4a5eb7,b37b515,a6c3f1b9) +,S(dee240ea,c90d5399,89d3b3f5,764e0680,1e601a4d,f2c09226,21eb0b7f,bb53ccc6,12668b,72cc139f,5f9fff4c,ef24b5ec,d0648e03,64c17417,f35bfca8,b819316a) +,S(e288a00b,e18b0987,9765940e,caf8972b,1a09f67b,fdc455c8,8e3b4ed9,dc0dad81,fd81e0a5,adf1df8f,42c64825,6b107d44,887d01da,f4cf89c9,11529124,16a1e4e0) +,S(e747d6c7,3f5366ed,241501a0,ca6dc04a,aca7241d,8effbd94,7d3e6a0d,bb6eadb,9954822b,15f44840,9c9e73d,97722194,1eb6a218,ef1ef4f,269ab118,8f9c773c) +,S(57b8865b,ac78b9a1,c244452e,8057be3b,4fe2c6de,9ca9a295,ded04377,2b61aefa,d0e46172,8828f0d3,f1fa808b,1dea8516,b0c30d93,4acc8c90,6ca2bcad,303f06b7) +,S(abda4b38,47ed5cee,7ace4e8e,e652336f,26a8f4bf,4bd610f6,e87e5936,e4e8339b,8860963b,8f266c30,9c6a00c6,cdb44048,a9a1b76,d0a5a652,b4453f7d,330bdd9f) +,S(7f05f2d9,5621d06a,d344bf91,7fa8b9c4,2ceafa3d,fabd0620,bf7086fd,9539e089,298ec6d,8d5a9506,8d916678,dc8e62b3,7b6fb9ef,7967da8a,8419433f,79922f29) +,S(99e4f06b,b8845bb2,12638573,63f7cfbf,3f15570,44256dab,21b5a8fb,c43e2453,5d76066a,86d5c498,323af928,2c3bf419,acb758c9,7883d236,7d9d9e3f,eb8e1417) +,S(ff994b1f,6447ae81,8bbbf97b,8b6d655d,900b04ad,eec06fc1,f57eab70,95375094,6a63980d,3a9324a1,9339a073,977130de,d0fddc50,5b86ff73,464dae04,c3004a68) +,S(3e9af52,f00d1993,8b6205dc,7b6f8ef3,31d624da,fdb2f09d,fd701b78,ed8b0471,a674914c,ac86037b,f0585de4,d867424a,ab9841dc,83c0ca8f,347e16dc,1407167f) +,S(eece935a,e5cd4afe,baca6998,63c5e8c2,e0b338a3,e2ae7dbf,e34102f6,f1c613f8,be70c210,b925dc66,c8546e65,ae9600b4,21a9f668,c3a09a01,8bc5b88b,91cf4d74) +,S(bf10e625,7d336eb4,a962bd97,4cbd9f10,76787b8b,90575250,7f0cfc2e,121d1276,1d93f629,8ddbce2f,1f670326,265c4ba0,f7f5256b,472412f7,a24f999e,f4e1c64c) +,S(73e43284,c80d4ea5,c992ffe3,cdce4149,d490843e,bbac444b,f47ed5a7,3d6e0bb4,82cab83b,c7d2d2bc,87881618,54034d7b,dab132b0,6340b316,964854b7,f2ee3e6b) +,S(5410340,b614b676,63173725,ecf0b8e1,67c2de61,ce999639,be2051dd,2695f8b8,f191ec95,9d6fd8f4,eca243b7,8d844214,976d97e0,65218487,3366ca25,f2e6a091) +,S(203d28e2,694df7a5,6c9b9d42,907c1e02,192e8030,77ead781,8198b2a9,69b127fe,c06fb7ff,2361ac16,a884f0a7,9e4f5a19,b0b5b207,9901e634,be237643,ba93852c) +,S(f9a1e3dd,f53e41b8,84f7c4e2,c2b47131,8d14705a,4e7362df,3221222e,6b2c1921,cd150a1a,abe8ea0d,853245eb,509c1d4f,e26c54b6,98cf9aad,26849a7d,e63b6264) +,S(e82e5e89,db35aedd,4d63b7e,4d55d637,cd2eafcf,f16ffbd5,b0fd1444,c7c783bb,6701a95d,ccae2272,2a834957,e0a4a3b8,3cf5ff19,2f41e8,1619dc46,b8238cda) +,S(9fb768b7,16032fd7,f21315b7,79776882,767d5d64,c9141267,a0ddedb1,55d4ae08,13474a8f,90fda6a3,43e3ea23,e858327,dc2f4c40,4a445f77,4b39b92d,a312574a) +,S(d0793463,ca7cdb50,3622f1cf,90032794,52af3fa8,1866e536,159fd23e,ba6082d7,35301f6b,66858d6a,3e97480b,ec3d2a53,8dee8465,ff5c15a9,1144ede,a208bd0c) +,S(cf8fc191,273383df,f1d703f7,bb237ea6,cb5d1307,8ce8ae62,67fd20da,4d845e05,efce641,3bb676e5,5c0b64d7,589ad771,23900e0d,60feb71f,93270390,ec66ecc1) +,S(f12aeec7,55a7138e,4e91024a,3006db3d,eff6ec84,ffa73d96,da21ef00,452064fd,f0f0660a,22cd7cda,25206f10,e82ca005,3a40d539,472cf41c,b86ed8ae,3d29abd9) +,S(3c40f94d,ab460ccf,c8e47a1e,d015b074,ebfb6142,fbbf5b4d,e77aca70,be67c57a,998efa4e,26df60a6,f1a466f4,c27b2dce,ce6367b2,e05a5ad9,dd71ed8b,482ce55c) +,S(f2fc6db0,49861d3c,a01a6778,22299264,88184967,3802ed49,503857d2,2860f00c,79f0f245,1cc6c5b8,d36c330a,ef8c9c84,95619911,1d4a01a3,d9363382,8b609576) +,S(35d3e3c0,29fdc9e3,88da1cf3,d52df6bd,9ac0ec9e,e591adde,26d3e414,f4fb92f5,62ba2346,6d19ec1b,64d2a6cc,9822feb8,e03df178,3f526a9a,13d10fa7,72de3219) +,S(5628da0b,cc2c0583,902a56ae,711a2217,455bba47,c7222dfe,d60580c6,461b4ae3,1cee8f17,8ce4c7f9,8cf2a2c5,92bf39aa,57616913,bb66f232,a813904e,7b574ed9) +,S(7ec54044,c3fe53ac,8437a540,968e0b,b725e794,a8c240c6,5dac1f12,4ce21be3,f6290891,af9af62d,5dfe10b,d567af1d,6b4b22f2,8177a14b,44edcd0a,be811c0d) +,S(eef7a7c2,a0224a78,aff7c61b,d2379259,7b307a20,bf1c253d,6f03d57f,a8a84203,5c7d6875,905e26dd,2fa4e5,24f73b00,6f4bd0b6,786639af,5d222411,bf69daf0) +,S(3f1e6459,38e4285d,ed30be98,1d149f68,24b264c7,df920f0c,c5d776df,83228cc3,a6a5df53,856be619,25e42d58,2f705567,39c3d7c7,a6e222b8,6385b63e,d1316916) +,S(c83ff186,ae3f42d5,a2c39b43,7712d607,92b9006a,d8bbcc89,97bb9b35,d1663cc6,2380aa52,44674eae,3d96d65,f484e7a7,62cbfa10,96c5a313,9eb4628e,77b72d40) +,S(41d20761,160125ae,c669b1cd,395110bc,94e09a,ffb52ef4,e7e86e,1f4a61a5,c8509f71,2c20aeef,7399d11e,7c438d0e,9b4dec72,76c1013e,a4c76d31,ee5c7496) +,S(cd358f38,d2cb11f2,9fb54431,dc5adee6,721c444a,8fab5743,1149e504,8ba0dab8,e6ab91a8,79a51f40,cf75e405,e508cad8,ec54dbd8,2dd4115c,fda7b255,b1a6fe1b) +,S(d1e1851d,cc95a94c,a8c77b42,5b4430a1,ac10e526,e3f4c6dc,f20267dd,7c5f2d2f,889de789,43c6674e,6bf28470,3ef8867c,8d827681,d2df8bd7,75384ad7,15730ecb) +,S(89268637,1febc520,14709cc6,b2aeb5dc,32e06b14,cdae3d76,b1bc04e7,b9b5dc8e,46823e42,9c0815e,ff99cd7d,f3712f78,9c102af,173b61f,8de08519,f19a3783) +,S(c7341942,420d4e63,263a144c,8a10d22a,fecb1bef,64f926a7,83951e0f,6490caee,925019a5,212e9de7,2e6e2336,c3e2aa75,9511396c,a171412b,53c8f9ff,3743dcd2) +,S(fdede5f,38d83f9f,a4ba3218,fac6f0aa,7c9f464e,33dc59f9,8a3444e,fc0ed7e7,26e4cd3f,3dcd6a6a,211bc8d0,65564250,49c6db2e,9946dcaf,43cb42f3,b0f20449) +,S(b2b5364a,eaedfe4c,f046193a,6777ec1a,1841436e,3cb17c34,9d27f42e,8e536618,32b886d0,f0f94a7f,1b1d87e7,4f2c7dcb,ba4a5dde,8e93c864,f8f48bb4,50d08ffa) +,S(4c3693f4,52a95b79,85e39982,f316897,93d289cf,66b3326f,3e1cc77e,457f64bc,48d7bdfe,fb8c3abb,584db0b,d3407ed3,3e543715,d4ede995,df0e1b8,52e12123) +,S(5cea23d4,927f0385,57f6bc1f,b926e594,93250b3d,6d934a16,9265ae08,24a35e60,5806886e,b01ca724,8434f2f8,be33287b,d9cb3c3e,b927bc4b,4fefbd51,ba98b5b6) +,S(db0a50f6,b4558c10,61a3ff88,1da60f9a,77b42469,a9713c8f,8339b8a7,b903d93,7afa6cd2,57685f49,9635d15c,bb7defac,d6f94c17,aa19be02,4e2efc70,d84c45be) +,S(b0029adb,25f32b75,8023ced1,632de91b,3e3e55a6,1abb56d5,aada032,f2c01ab5,baadabe2,2ebc5fc6,d5dee65b,262e96c,63c99fc9,13277d84,9ec8a730,e1bbfe91) +,S(c336b077,3ce16975,bc204169,8126a40e,f8cad886,6a52c50,c5081ba7,b878af5,6f46f5e7,b82aec01,ad499340,fb90b81,420b4a3f,977579af,d3eb0ce9,c7d752bb) +,S(f403fde4,7232a9db,9efda1c0,5df49636,2137f5c,aacdfc93,1346dacb,d2501451,ba30815c,197de8f2,258c83d8,dd7ed0cc,cbb5388a,415b8629,2cf5c271,2e75bcbf) +,S(85cd71a2,20beec1,3edd0133,6b0b85e2,da056a1c,4a48a328,f371af1a,ee502c30,d6accbba,491c915e,88474b92,bf23c740,2648085f,88a62d51,b26954b3,f6d2d4c6) +,S(324d65,b3c2bc55,d3b2a125,1b673ecc,d26d2b23,e333849b,7549339f,7f0d9a42,83750e95,32086164,e9aaec58,b6a2f00a,3838d76a,208d6453,14042334,b4af616a) +,S(322033a5,c90d7a31,9439c368,b1301f1b,d088974c,91560063,793b6f2,63b401f3,a61f4714,488bd2bc,84bdb122,c615ac94,a7d05157,e6d961df,4f873f5a,582e4606) +,S(a414ed01,691f2a43,b18dbda2,2d3d009f,f94f8b02,672e49f0,58dc2323,b71f5836,2fa3e483,a12ba874,12d709a9,47cdf22,6b96523a,ac7f4afe,c93f98be,f97ec01f) +,S(774310b1,7752d7bc,d8b3059,f7f4cac9,e661a841,9dcb20fe,355bc7be,3a4c65e9,b3333227,469ec87f,19e14e3c,98148b4b,45bde0f6,698829e9,3bbc9313,56e18b12) +,S(fbb23c7b,5c15bbcc,7ad0118b,6826e385,3f6c4078,5342ea57,11109f8a,27dd11e,b12ec70c,9b4c908e,2538f4c6,b0b3d548,ee199f9a,1e9b6535,f1c78081,41664ad5) +,S(4bf836d7,fa7308c,89b075df,1f336fc8,af3c6ce0,64e1253f,853f623d,c483b400,8b368da,424e5a83,48cfe987,93d47a1e,1e9bbeb7,3f5282af,82e12e4a,c7eac850) +,S(91b4a84a,e521232d,71e3d202,49dd1b3b,d134509f,e3e1ed1a,4e8b5062,a438bdd2,52d30545,4972471e,6900afbe,2471e1c9,16c82ce2,2f955ab8,454f9b65,b70ed759) +,S(9751092f,62147caf,f3953cf4,8a117082,37a78b6,5bf0de56,848da1e9,4c3c3a42,57fd0a15,fe069db5,5fbe870c,96d4280,7b9ebd87,33908bd7,49ba0121,a900b08e) +,S(54439284,6f6d46c9,8ac10a58,ac3c34b7,3cc5569f,8f9fd7f3,4e7ad2be,826bf293,1aff0b85,e5b9033d,7c44e877,57513317,a17734d1,13043cd0,780da032,2dc3ed03) +,S(172704b7,fd7f5560,f17cb6ff,ff9a0144,9a05a113,29b86df0,a8d3256,ce139a9f,a416c0af,b170cdfe,169f894a,b10aa97f,2c068a4f,d70a6878,ec9f359f,e8323bea) +,S(2236799a,a82d4b64,5f412aef,eae944b5,e28e0996,8a243ce5,b8986861,6f735dfb,7f20b2cd,af70cbdc,6aeec02a,dae1535d,4bd919c2,631ed69b,9913771c,2f482c1) +,S(6a52af7f,c6f75636,c33047b8,9f0eec31,66bd97d,8df6579d,2e2a441,6ec4fe8b,4eb0813d,220849bc,e0b948e9,a6efcafd,339f8861,eacb9885,40ff8e1,acf1efdb) +,S(8696e0b4,ae3f0dea,bf6d8dd3,854faa5d,d07b01a8,86f710ad,9b4cd84a,5d61a617,67633be1,a662024f,77931f06,38884175,d2c234cd,c4709637,4711c79f,42a897df) +,S(6c4b727e,3bf9af50,fcae1ed6,163ecb00,142d9a53,b6d3f54c,8aa14064,1358ce7e,c4f2665f,395af262,b30561d1,48bb0f4a,f5603102,80f57f40,1506ec37,2bde79a3) +,S(a51d2296,98aa29a9,6d0e5510,f3e815f9,cfc6d492,dd0b2fd5,bbfdefa4,984a6934,861f0848,7658d4a0,141e9d38,aa0e268f,40bad7c9,e2615a37,7a4b974a,6828d525) +,S(1afc4051,cfb5635f,9c2a8477,7dee5fd9,fc4d40a8,3ebe2f89,f36c0b9d,8327288,61ac4eb9,16567e13,d1b03ae7,ad5c3d8d,ef85bf6f,387c511e,bba6c237,96e95f7a) +,S(f8fcde05,5a2a92de,c65d1842,6607a939,b3475abe,2437c5d3,88387fd4,afdff590,4cb8f7e2,825625ba,e3f179bd,4ef94560,6e186346,61edbf48,8ce51ea8,ce1b0404) +,S(cb3dad82,7e7464cb,5fed0cbf,7e29e6ec,112ea411,706d10e5,c1fe6fbc,a04a3e9,a33abaa7,6c9afe3a,a8ce5add,7a2a056,b396cdda,2a002161,3de97556,a0364629) +,S(39d2cea0,acf8059b,a6275a08,ec3a3664,f09cfc43,f143c317,bed8d751,33d4ba0d,6beb4ca3,d3009ac8,881d6d15,e0a29eda,6738befe,e31707d7,f95eacc5,fbd77192) +,S(90bfc4da,3be2d74b,ff9b5539,d0787bf4,4a1b6d7c,2baa14a1,dc6801d4,42187f96,1254e7ee,c8acb35c,fa0695c5,85f61b69,def3ef5a,6219fa97,e3b09dbb,351152f) +,S(50772bcd,454ae992,f97ac3f8,9d8193d5,ed50b69a,b2e62e04,d6a115a6,6e71c977,f199a8f6,f78b0b97,cc20316f,66177383,64338fda,3eee7f0,f36eb0ff,64accdcc) +,S(afe51284,f033bb43,ac6feaea,9520e83e,f2cc1e42,9e273bc3,1b087161,52ea6926,77ecc481,9ffe6efd,33592907,17d22ceb,f4344c9d,f5f5ea4e,4d443d17,25c8aa1e) +,S(b0caf67c,151b838e,4ecaee09,c7908c95,bd3ef86c,797a5a8d,71cb3bf0,3a46ab17,10ae756,7bd2f6d6,712c448b,34636eea,2c7c3d99,98901308,14825b4e,423284bb) +,S(f2766b4,8cac8f6a,80a7cf39,81725834,d186e88d,735fc7f1,5135ce58,43b3dc8c,63590fcc,a4e21c39,50cd78a0,569c0d2e,959254e1,4bf2ff22,8d8fb216,b53601bb) +,S(80d50e7d,28269280,f8ce0dd3,6afb9f43,38df0403,d5661c99,27ff817a,46f60a0e,22fec5b9,7472824a,9b2ff25a,68d947a5,a8952ae,b763f37f,70228978,514cd22) +,S(18114ad0,7097b5f3,7d788165,e45ca1b8,462da0b5,78e5d37b,e4be3632,35d2fff6,87c5f261,39cb366f,25fb6bfa,fcc8408b,f4c69c81,29df3cfe,9190213f,8c15a66f) +,S(3bd52737,68294cd8,73a48831,8f958e45,85871165,c82cf6a3,9126e378,43975444,8c92d391,e39a50f3,4388510f,c8dbb686,27f29251,92ae8edb,b2613948,c01281ac) +,S(acf47eeb,526208ba,8a3de26e,481a86ac,f17f5f88,81d89d43,ab8a5a26,e00db5a5,b451b4cc,8be8339e,4203c913,98b9a29e,de86a91d,3e347688,53442446,429ace0a) +,S(5e39f375,87a07536,86bcd792,1183c424,20159044,a9f66ecc,2bdd552c,62ec35c2,b7131328,297c6995,7df6783b,d9bc550d,5c553e1,30bfc3e,fffedbd7,5e2d003b) +,S(315b67c3,d980796f,6f0a5505,ff2d25f2,8551615d,12bd73de,b10c4897,580371ba,dfaf812f,7525e087,2d11e10d,612004cb,3e2a7024,8c40416e,5020ef66,82d3bc1f) +,S(8f6764f7,73810396,62537cc5,aed6a8e0,318654cd,a95d8695,89fa471a,edd0d7a0,b91cf5db,2994d207,135c1dbf,b9d9d78f,7e3adea5,8c176630,c09140b7,f5c67e84) +,S(e844b948,118fc6a7,eb2f96e,ece3cab6,def55940,75c7b7af,fcc5603,f2012f96,707668d8,89db03d1,561596da,a831aa92,771a0fb9,e1b21273,d11a3415,82292314) +,S(fbbedfd8,4144785e,fa71e234,59973cb8,87deda88,971eb62a,3007f350,1fd0ae4e,51d23941,cf84f121,ff1e6a5d,651d9528,6ef1d803,819ce64,3aba8d16,67ba7dd9) +,S(a0190399,c692b9a,db172ba8,348b404f,19442b60,4df60142,f6330f36,ca6bf352,6ce7491a,b5329042,25556069,71502da1,601e3a04,f38601d0,80b31654,20fb527f) +,S(d240e135,4b9e6dc9,110a6b25,afcf35e0,74fb02fa,f3dbe484,4f46818a,89bca65a,d704be81,e2597460,6014ffcc,ef12563b,45faf24,3e070727,64f341b8,7dfcdb7d) +,S(39bd84aa,f8a15b0b,809888f,133871f3,c40ea5f,2825582,a35fa9a7,808e5e87,94ad6588,658752fc,ce45ea1b,752ecd02,2b621c5a,26908cf8,69c44584,1d831d33) +,S(2172be6e,dccfd021,a56a553e,53f814c7,c7cdd55f,d181d671,4ade45e7,72093142,b21439df,f7229e61,cd3b7c77,fa750a94,660f60a7,53da96ba,d8ca7e20,69abf76d) +,S(57db209d,a40f30ae,fcca7838,2ba525e2,231343b9,250a1b1f,67fad7f4,d4079594,34ce9bac,bd35557e,2f73c718,4287b493,c524a3a,d6b403f4,ae777026,42fd37e3) +,S(845c2bc3,3683d899,8b90a2d5,ff299064,5214b272,a056ed93,63621406,d3a4cc11,44a46738,839b2e3e,1b6b19bc,56a1ff06,7754126b,20654e51,3a1f13c6,de4c6535) +,S(705af30b,251cc64a,26edc929,e3e9ff3e,32ada2e,69c2cfd0,eefce4cb,a37329d1,c0e693eb,94c0c1f6,cf1a0ed4,8c9b13ae,faba8ebd,926c4fe3,ec9071be,2db463dc) +,S(9b2a64df,9b1f8e,34844e3d,920b1af3,14df1b7,78b863d6,f1a6b94a,869061be,5ff03134,722faad1,ab6f87f0,bc3c6abe,8406bdf3,6506b662,6d066ce1,fa6a7cf7) +,S(494967f0,1a0c07df,e7d9a8b3,e6a4ad13,893a894c,2619238,7384e38a,d514cff3,11ba0803,72bc4ffe,b86e25c8,b69ea450,5f6e3b24,504b5e38,210beff8,5d82e1af) +,S(fd547247,812e4233,55c4a977,4dfecfae,812ef2f8,f3fd832d,a3af2ac9,257d50a4,65ed23c4,d776baf4,53faf3d,d3edf65a,5d9935ef,9e22fef2,53319e22,ca4bf51) +,S(4aa16ea2,68ae95b3,2f405fd9,6fa78478,7c369015,4c124733,a07c1953,874b6246,4306725f,579fc013,2cb8c640,7361c7c4,685a2a49,532fa14a,36010779,7f5104e7) +,S(de6fdd33,8b6eaad1,bec84d55,992a5b74,aaca294a,5f804015,796d69c2,cfe67add,e58564e9,d2cc10e7,184d65b1,7e0271a7,f2e59073,bdca05f,ae664f82,7e6fba13) +,S(c8290adf,d0da5f1d,1805f36f,288a8709,eae0b93b,1a7490da,5ffc29fa,bf834592,ff161787,f096e022,f513afc4,e0b84d73,e7f9f347,798e1026,931271b0,8f1c8a87) +,S(1b95c512,815603a6,19750d6e,463d5a33,55f09c22,56484ae9,8f1c76c1,10ed8fec,93b3750c,3a1272d8,bc9e4c52,b5efb6bc,d794c2c3,939bbea6,1848c9ed,423bb39b) +,S(ac0d9939,104bbaf4,d2eb2560,356f2bd4,f1037ee8,397f0703,b7ebfb49,463a22e3,c6e6d039,d6acc470,c1ee1013,722c4a00,4c59e472,11da3025,49351216,f0bb8985) +,S(d8c8f5b6,366c1d29,b2f28f53,8645b17c,f001ae59,71a19f05,fb6ebb3e,9e36faec,5db24ba,6d78e76b,42262b65,e631390c,8540b72a,746cc5b,edc1b681,8b1a113b) +,S(d42ccf6e,6d1c663a,3dd95fd3,c016d535,c50e394,fd63b353,2949716c,49315737,e7337f22,2d353eda,651087c5,13cfea43,96e9cc5e,22aefb4a,5fb3ea8b,579c7298) +,S(53417fa2,4871adb7,6d875c05,8c46065,681f6372,95d221db,ea76d88d,f687b817,d014e6ea,e00c4ec8,ad931dd2,5cf569d2,efb3068f,7aaf5ded,d4978546,1bb31d76) +,S(202e9476,53b677a8,d7aca305,c52af8b9,d33b1ec4,c5ec94fc,5f7775aa,c478f150,539a24fb,211da532,b378f3e5,cdd688b5,c57343c8,2e03a637,39544c8b,34e3087f) +,S(434f1027,72aa0555,8bcb2f6b,1f64bc8d,72bf1bb2,8b972c3a,f6f342d5,f1493f93,a9db9031,f2d1b8b0,e5840fc2,b4534970,90aee2af,5bbd83d2,c14a5ad8,acbf8c14) +,S(a0e54d1a,f09c47f7,cf56d3a5,725d6777,9fdf920d,3c1dd566,caf71666,de7d5d17,87f5db7f,197185b4,73cfc293,7b0661ce,1ea92099,fbb51151,63c2b26d,47ba97f0) +,S(2d43cada,5455b682,f6430cbd,96a2e316,ac0b4b27,e9fb8777,a94dd2c5,81c0e350,bcf18180,1c1722db,1bd9b8f1,8a1989c0,fb372acf,fecbf9f2,c37ec4b3,b459c916) +,S(e5e6dd12,6340f04,431552e9,903ff4a3,c309ea1e,c498e483,e19b9cc1,37418d4d,58d35fe2,24ab47d,93cd53,fba32252,4a3ea9b6,d96390df,25935a1b,dd12126e) +,S(b112e4d3,ff9adc6f,706cac35,195843cf,302324e5,6aa7305,9c8b5f3a,6dd7dbc7,4fe76714,6529e6f6,b0379366,334595be,efcc7cde,d3596ed8,83e3b30e,780dbccc) +,S(d26b5261,ca7be739,95de1bd4,d75991ef,4d357fa2,5c8d513a,e209ac6f,64ad960,5f3b8e07,74e78bb7,5c395bcc,8512f2c0,1b6c451b,5c8d6ff4,18f9ef35,30c6d046) +,S(e2e4f568,eaf2807e,cf43ce08,3146e961,92271bb8,d6d9b24c,e7315b00,1cf04fbd,56894a02,58093a34,22f2ad5e,548158fa,c55ce47e,d00ede05,40434424,4e204b93) +,S(a62080a4,2d8aa307,32255b2b,a239d9fc,19729eec,1dc24bca,67652705,9b1182cb,ae848a12,893c34f2,260c33c8,ce2bcb7,14fb1438,8e6f3f06,d9192549,6a9ec13e) +,S(684c1647,7771de55,ddea8aec,290c1e25,65120fcb,fc8ce0db,4316dde3,f5ae8d91,ba85dda9,44dcfdf8,cfca86dc,ba902675,3d99e751,5719e579,64e0fa0c,3be1f06) +,S(3d730e7a,afa97950,bee35934,da18648c,d0bd62e6,9a49281c,b63589d0,5efbd2fd,c28545f2,3dceca1a,ad0a9c77,23b61519,44a3c984,d57517a7,cf6702ce,f4dbb630) +,S(337c9584,b49a49d9,29b1212d,dee7ecb6,39f007b8,9ba94180,80c9548,459c48b7,b26db317,3e996893,fe1e0797,f75cd05a,2eb23ddf,4806407e,1f173d29,48bb0bde) +,S(7013edd6,f49ba92f,9c9757d1,d3374229,706078df,c2e9c64c,c2e84cbe,85c6b5b7,e850419,7975353b,2863b577,d6f0c392,a8c5bdb4,2dd557e9,8e971114,5e078de4) +,S(9877cf36,bde592fb,5f4a4581,2bc3c39c,68ac9956,23b3487a,635d6e45,89e26e1c,6207d384,737a0d80,fa9f42e0,57684584,efe1fa4,5cd73eb7,bd50abc3,2722f159) +,S(6d35bf57,1c91a2ca,1765ed62,f9b2f680,cbd0955,bc76332c,c83a7378,4bf3eafd,47a589b5,15a88d78,6f94f64d,674182e9,7dd12450,ab3ec375,a9a31d8a,375e5f7d) +,S(40ebcc0f,be3a2a59,968bf6cb,4d638873,5468b532,80a9c96b,639dede3,171db2b8,c2181816,ab9f0d72,c5cb167c,5bbf7e57,9f17d7f4,484996e6,3a23e0dd,5f5d3a8f) +,S(90de4b6c,3a5ccf14,cb033478,577461af,8c347731,9857ff40,79e6ef27,5e557b87,c534bd97,a4af903b,f307c1ce,549a9976,70edb69b,c76ae827,f277ffe8,133cf394) +,S(54e89b59,b73c76b6,cac52433,305c41b6,8f50df66,9b99f47f,599504ee,93ddb110,d307e828,1e89cba4,86ac125c,1c5d8bc,943394ee,222b4b06,f4e3e5c7,b5da176b) +,S(f2ef67ad,60858ac9,fb03ad25,f75f85e2,e5ac151d,95c96967,93ca080,58756f2d,92c0dfa9,372e1e7b,7363f229,2776c059,56742f60,7b100be3,56dffefb,bcda8cf0) +,S(65b7d935,a71dcb6d,eac70b64,91b9fc50,35c63f21,655a856b,afd00a33,52f5be39,b0773657,cbdd3813,8f50813c,558ddbe0,3f8ad81d,e420401f,175bade7,1429927d) +,S(6e950ff,6471cf66,72ea542f,cf05aea8,2c2e1e0a,c2247021,4c78895e,e291ee22,c0ca0886,f0ac828e,21a5c60,776494fc,a6f19e71,741de92e,c11323e7,e874788) +,S(c3b15f8f,96c0079b,471896ac,89d7d11,8ea1607f,18a20627,fb18e1ff,24ee3c1b,33a033c6,68e3cff6,414835a6,ae3f89f6,643326cc,7e149f56,99ab4fbe,d5f506b9) +,S(9e333d9e,1c022776,da901c19,e6936c3c,1af45491,a93e9405,ae343c54,775f36b4,c6734e91,3d013610,6c77a1d3,ced1babb,a6c6723e,316c3fd,34a7911f,cef616d7) +,S(398d2109,4c0baf8a,ab63ceb,6aa6b64c,678bbe86,f7e01b3b,8c0ff291,450244bd,f1ffb185,112ee219,24a1702,183f9075,471611e9,54fafb4e,36f6acc8,4ac7acf7) +,S(8f99c7d,553ca4ea,b160a07b,6d457058,90634086,80c709c,530aef44,bce43c8a,52a15e23,2e90d233,211d707d,5849e214,1f56e8d,189783ab,3c09f37d,b86a776c) +,S(8d798338,b2774399,487fe227,e2d883c8,39698301,5f01bf00,d154f4f9,296512a9,7cb53de9,9303a6be,9aee01eb,3a5c115d,eff0e18b,2cb5e852,75e9b7ff,53e35666) +,S(c9d6aa,ff6b648d,69416bfc,6e4688c5,cf13b711,29c785e7,3ad1e04f,ba02be57,9fa83446,5405aa0f,332a6aa1,922e3fcb,90de108a,db01796d,9045d423,ca0c2632) +,S(f736cad3,f1264671,f2e79bc9,c21551c4,aaa5da0f,befc1928,b9e7fab1,f59c8c5c,2ceae81d,16206893,b3810abf,d2aedb5c,55b79222,1346cc9c,908346e7,cd3e661a) +,S(7748965,7c1fcd79,60fa4a8,36feef6d,835f960a,d3b85009,7462a71e,8320a34d,cfacdaa1,2906f705,d83212b1,55475160,e02cde20,71fc5c9f,6a6d59b6,8e100aa7) +,S(279f43f1,e26ebe73,34924bae,563a0e34,e5cea7f0,eb9f5702,129fa6cf,8b0c67a5,eb5a49af,bada9830,7ceec508,70a49027,7d1cd6f7,6f332249,b2cf2505,82a2a828) +,S(cfccc083,9bbcc7d3,5ceca575,3b9148e4,ddd4464,5727cf47,26f33d62,d83a6a03,e3cc09a0,9d26889e,c969c734,a3361dcc,d638b17,608baa1c,e7cbb99d,a5bc23fa) +,S(e60b0451,70c2e3bf,dd627fcc,5eab1218,d3d598fe,a41f6bf1,dace1a35,2daeb287,a493847f,4f1d3bf,9e90c022,851bb652,691af15c,f4c6c539,bf2831ae,9cf8f2c8) +,S(11875535,ebc90fb1,eb7a08ce,90dede09,fa8cce24,b3911fa6,44ce8111,8848b433,2fb1757e,38148919,bb197d43,48aa536f,c0f06f9a,859ef737,ea50b1fd,82968ce) +,S(c69559b3,75cdaea3,56003ad2,3edd8ca6,c415868c,a13a30d9,11d4c694,f5822179,a39427b4,914b58fb,dd35408a,67ace872,8c299a39,278335da,9228ac85,24652906) +,S(625ff5c3,1e951b28,40f431fb,4842f510,8b738722,cdd52c4e,fdb495ed,e42f1f7d,a3eb00d7,4eb30337,d3f61ae9,d595996e,c7d5a3f0,ceb39f23,3df0f5ff,43298d7a) +,S(1e2fb107,bbb46666,8c31a927,3ce57baf,fd1df905,3fa28286,196a03da,74327c2a,aa882338,5261bb03,a8d8793b,c8f98330,97c22731,46ded3d8,966b16f,337643e2) +,S(d0cbd747,970ab0f6,19e5e4e7,78709399,b65b3f14,24a084b4,a2dca8ab,10d76ebe,7b5f778a,94d3d75d,57b5e979,3de246bb,f36669df,b7dcc24a,ecf4e153,2025b73b) +,S(ab4c057c,a40b84f9,10142209,a5c173ad,6ef31616,db80bd13,61959f11,b739f9e1,598f12b3,4695bb27,ccb2fdfe,a0911ece,eecf2cc3,1063a3bd,42dd100f,e93c7ced) +,S(f9c11e91,2cd3cf06,d31e4795,40c703a7,4f5f3100,8e6ce299,30d5f08c,7307276d,f873ce74,bab3785,156468ce,3d6a8cbf,c532db23,2a0a92fe,91d290cb,ad08713) +,S(2d95744a,79c4d234,40e2f40c,a83cd89e,61576686,21293dab,6716072b,2089b77f,a25249bb,9dd8a94d,44576a4d,7ed800c1,9adc5e26,82874ea0,5d63bcff,2f6b2704) +,S(3bec0dff,e9a96bb1,f3cbccf,cc96ecf7,e1335b1b,86f13b63,6467fd31,5cc33abb,e31f8a49,dee2408a,2d0b9288,4e381379,9fe404ec,1d8b96ab,39413f82,52b85b5f) +,S(23721d31,616051ab,60287a0c,2b4ada42,1bf00825,127ea0eb,1341beaf,a207fedb,8cafc4b5,40e6f3a8,6fd1b546,87ff8c3a,fa2372e0,24696071,59b6e195,f633b169) +,S(ff8e494c,446cf1c4,bd557615,a4a1ce2,b8d25bac,62a89929,993cfd,51d45099,113e1b98,555ddb77,b8680eff,c57eeb96,4038de04,26a05289,8744f8ca,4f3ef028) +,S(f170cfff,f158e368,81cb677a,c9d9512a,3c1705c4,850d5a85,17a66636,7b0cdf21,49512fe4,3ff0f91d,b9ab918b,808ac11c,b5eeb4cb,ed905f21,adce5e4e,42ebbf7f) +,S(e9ff6261,d6c05d6e,4e35e373,57fca0cd,3c3ea884,4a33e504,df3dfa2b,a524d158,4969683b,9af581c1,963525b4,e8244e5e,6b7e7e48,f85c1fe0,1e9f0dc2,c66e591d) +,S(c1c4879a,b614ad86,cb64d15e,cba92aaf,4d1c7742,76d6aec3,4b59f731,addf6cde,6d7185b8,fc1b99be,383a7a5f,385a08f,d7125e3e,f72f93c,25063bfa,d44abeda) +,S(deb0c036,3818a101,ba38a657,5c0db8e4,a65f824d,57014dea,1c110387,7bf2d9ca,f658d43b,f0c106cf,6b45e552,3fcd066e,e754180e,8510b58,43708b5a,b40dbe32) +,S(c4d4164d,f782df0,f5366667,83e5aa9a,8b05c7c6,91c47a49,14798685,1da3fc9b,6c394d4c,3118c8a1,30bea2,2396562f,6dfcf8cb,8f0a91ec,20a43bd1,548bd80b) +,S(94d83b82,f6db0da3,f1bc24ac,8c5bdd0f,6e89cf2a,bafd33bd,2fb3ca87,9cf63a84,9e8658be,59d64a28,7cc0cfde,1f35b83f,e3e098dc,6212afac,ea234437,2591f2ab) +,S(9de3fae6,e6934304,a84eed5a,58e077b3,76da7310,61859847,d6abecfa,fa650dba,7e4cd395,ea8b90fc,20850be2,4ba8dd83,e79dbc4f,4efed68f,504eec04,f9bcb212) +,S(251869eb,7a567c9b,7866c9b5,a829206d,867f2092,8f3a6fe6,46ebc3d5,2df7d99e,bd87d706,c49690a1,9e0ad77e,4b3b8f0c,5efba7e1,2a448a3b,b4ad3c7d,44e35e7e) +,S(e92e5aef,818b2980,43227673,3d15021d,c84192d5,bc9307fa,1add63a2,8e888a9d,ba3a3157,96ab2051,ad53b5e7,a058f700,ea90e40c,c5855712,d2176a0a,c232f94f) +,S(b6a8a783,c2716ba8,9a37c7,d7022dbc,25fef8f6,76c676b8,267038ae,64a33258,93b09e15,8bf081ab,9e69c4c1,6d965743,cc08ad85,a8eb248c,9c67043f,fe61ebbf) +,S(26e95f26,7ee205ad,50dcc75d,82330877,394c56c,84546cb3,72fecda5,f57c2556,dfc935f8,63840ca4,71bed804,d0c2d14e,c9528a9b,ba1e6f25,6545311e,5cae673a) +,S(6c1ed40d,dd086dd8,2fb00bbe,d969ea90,7e363496,97c350e3,2d0074d3,3e05bc13,854d177b,5593cdc3,ab1e4903,c64be02,2b6b0cb2,25c71390,9316faae,a235b269) +,S(a9286b2e,81030401,c37d69cb,1e73caa,b1c68a4f,4ce1538b,11ed850e,67d11aa9,64ab5453,c3a1166c,18f35115,1f031117,e29b1a31,237cb2ba,51f1a873,529766fb) +,S(a2b862c0,ca02cc3a,e1bc5737,876f81ed,83dffeb2,4e6954c7,3cf97bb2,50050cc0,db3a03cf,d704f98d,dad8f48c,5861988a,1caf439d,b50c196a,32289622,b9a49b3d) +,S(19259392,58c25edd,953117d1,fc7a74a4,a9cc2fad,892255e4,fefdac84,4784c917,b86a1bfc,b7bc8844,abe424a5,b7409abf,26e8ac62,7983fafa,70dbdaef,43a88eba) +,S(6b85864b,194b2cfd,af1d6550,4960370,306ee34f,87c91187,230de0de,42fafd09,54a9ddf3,87458a54,cd305e06,61dd43f8,3911e88a,db6f0256,d19cdf15,3ab4b388) +,S(407cbd77,b88e6d47,60b07e26,f53fefd1,2b98bed3,5403c693,e7ea33b4,cd74b5c3,eb73a1d0,fd122265,dc880cb2,920b4eda,610ff1cd,a74660aa,7cb91323,e5485d60) +,S(f65cd6a4,594299a9,6cdb5f9a,7889cf44,62cca331,d3329f7c,43ecb224,d58c817e,8c906c4a,11925697,9f84722a,9440d2e5,f97e483,542658b6,8538aa0b,f10f5572) +,S(2ea38854,775422db,43eb69b7,bbd47a6a,b8ef1694,28753fa8,8cf49c8,9efc6e63,bf6f2d21,2b21c740,a25dfacb,bd22436b,5118f1a,2004bb90,adf580c9,6f21f1e6) +,S(f2bb4814,94677f3b,6af8aa4e,6a3b1100,c2e0e99e,289536e7,eca3e61,a20793ee,a3a788bb,2a810267,9a3d98f2,6a9a2740,91a3a29c,234043ae,aacc488a,67849762) +,S(e157c4a2,84354b8a,73d5e5ec,58dc1ceb,2396ca3d,7f651e6f,4547aa78,99899daf,f06970d9,5bef3e0b,e2bd4597,a1c96581,275c9719,605f63f,9618816d,669a0bc3) +,S(25aa7f3a,3a14731f,c7fa3b81,31a569e7,4bf32c9e,3492e626,aa4a4316,f263cf12,e5c2e210,a8a75180,31778f4f,4737a0dc,bd1a1312,1dfb40c5,5c435803,4bc3eeee) +,S(73ba2208,8cb96b2a,c23dd2a9,7b3cfd2d,c504ccb6,24c2dfd,5062f8e2,bcc442ee,ab9d3a1c,6bd762b,9cd866ab,7abc0e1,f898c567,61c7071a,d64d5233,caec0ca5) +,S(da94893b,3e73246f,6a72041a,44c7279e,dd8d4d3d,55b20db2,eb0e08df,4c5837f2,6949f652,8601b0fe,e572ac03,89fc3530,6b2d09d7,b59c40c7,a1a607cf,51684006) +,S(908480b2,35c49b11,12bd6504,5b3a8e13,7cbd4820,3046880,1688ed05,abb8b7b5,8a887f57,622a7482,3fd40b26,f58ae7a0,18d2d03c,d5ed31cb,93a529e3,387fec7b) +,S(682d7401,31c966e3,2a8bd150,27fae9f5,4452fce1,360c449b,1b20bbd0,257d58d1,ee7f773f,9d074436,685a2fe7,21b1b829,9369f543,dcac37e9,9adf43b6,4525c19d) +,S(c8661c4e,dbe125bc,a31e7a22,83aa0f9a,b4b3ae70,8512fab2,21bdb4d3,8c89fcb,30299a17,16d3fe04,7f48627e,36195b21,e6800d4d,a26dcc63,96c7fea5,8f25a2a) +,S(5112b1c6,2b88e704,f0d2c731,834019aa,d51a108e,1a8614e4,f6e62f68,d7372b4,1bfb5f8a,ee37bb82,5494c9ce,651d32d8,d47e5a29,4b9123e0,7311f260,9ab4053d) +,S(b9214d34,49e16aac,b90f6704,ee589f6d,8fa45126,be235e9b,61ef3ebf,2150eb99,c9465341,2dbb107b,965d177f,de11bb25,53e8795,69814d17,34ee9ae5,267529bb) +,S(94185601,f959999,1999c919,82e5042f,b7e68583,533f9569,73788d5c,3a087b2,5e51c755,de79b6d2,eb640039,a4268d3a,601750c8,dcd0a942,eafc9339,6fa36c98) +,S(3cdad3b2,2a707d9,90fe4228,adefc934,e8c69a9a,8a4cbd87,844a6ff5,a073f511,f6de425f,26e17045,5589e22e,7824dacc,f8cb8561,832db31a,e8fd2910,558ff9f3) +,S(ca986704,a0d1935e,1611e176,60394d00,7d2aa1cd,cb17357b,b4a557e4,f5a4b5ce,8d527934,a73f2b0d,b3cf571a,ac53b3de,11ac99d4,6ba995b7,5a09195e,b10bb5f0) +,S(f5920156,3ec396c5,82fd6090,2d98ac,2d5dcf5a,cd37e651,a1e80c43,f76940e0,2e821f19,7e27f927,20230f1d,9e26dff,5b3d977e,4b4a6cc6,7482f3ec,3cd5523) +,S(9ced8c1e,bbe0d213,b396fb89,8aa8c24d,870d305d,e9346239,b2cb0315,c883cdc,79367b21,4a2e21fb,1e9b24d9,fed6a0dd,b377534d,4da2b501,6999ebf7,f77de2c) +,S(5b07b283,ca262751,4a10817e,bdfc8044,883f4de3,38cae14f,de955f18,9713dac5,b8d6d9f6,8a71aec6,3b7bb44d,1d2b678c,75ff83c6,37c254c8,3a14be30,a5957b5e) +,S(4c2eb4cf,3fe64ba0,21297b8e,321cac6f,a8245614,45848933,19453052,69337386,35ee2473,1830eea9,85171af0,96b6bc0a,72f3e83c,6d83f8af,8ef1131d,c8b52c8a) +,S(5f24fcf5,f8c0bf43,43b8a0e,b3b6d8f7,2901c902,6d43f8de,4bcb1cdc,6d5019cc,87c2a306,138265bb,59b2b2b5,6992fb37,b2ab28d4,ff4909f,d6067e2b,4f312cfa) +,S(e26bda51,c385a875,5083faf5,6a915944,3eb351a7,88e1597b,f17649b9,b23ab8f5,35d66322,ba25896d,2a14a0a8,a3f5bf91,d3ceab49,9b2683f5,db7f58e,68ca1071) +,S(ae5be06a,b1ae531e,5d2338ca,d929b5a3,4c283035,95282aee,7c3ac259,8196bbd6,f4f486a5,bf11191c,9134d522,62ccd692,cc5c6686,c9013ed2,782b816c,da416d25) +,S(d143463b,4661a173,6b88f274,6b3c20c6,d054683f,9efa5221,ffd3badd,14804880,77b28055,7aa11d3d,b2ac8de2,c9c5757e,d0c9b0cb,af6fca3d,bb295bcb,c3ff8afa) +,S(54804f7,28ff88d0,bf6fb4a8,a24d4eb0,ee5379f9,30f890f7,8e31afca,87f23343,79288e99,a38accc2,c59ff29d,9da5df60,42d63089,45900378,c40dd765,2f0f5626) +,S(68c21fc9,93d41345,484cf5c9,8aa93bf2,25fc2c01,922a0151,cb3e247c,f130ba0d,9c435478,23b9d8bc,2e8ba0f3,8f2b60dc,ca5b6030,eef51c6,cdd20eb5,a02c6245) +,S(2f50b870,96b2e15d,6fb35001,cd8f95a,875cea3a,edf21a2b,c433b254,7798b856,44b09dfc,e0b8d522,17e7d9f2,9bbc5d6f,9886fe9e,3e360688,8d7c4e70,c3bea0ff) +,S(9d054954,f0c22da5,f330b3e0,69310a93,66b72129,2fd3c98e,76464796,847d16df,45962d48,143c94b3,57400130,d3e050a7,4defd464,223ad599,e6aa947b,12679a85) +,S(31980b95,9f51a6bd,4cfd9a11,b86dda39,af66ffb,97713ba7,3edf8c10,462d5685,d0a02979,5b45ba4e,7464fc47,7a09a90b,7265f5aa,e6b0d655,fca5828a,837c2840) +,S(e9c0615,f0444234,1f522d93,eda33b29,8951a267,7c4cdcbd,fa02a63c,a57d1ed9,7aef87dc,7095f483,5ebf2b3,156be9dd,ecedf54b,1b0c739f,c513ebda,5c5f296e) +,S(fec8bd3f,f19fa6fd,17523af6,27384c7c,6c92fa85,aeab8bf,bbdd2178,89b12650,d01a278,6ee8f9db,38b1ceb1,a3fb1df6,b631c0a5,23e92460,d0d51367,1098e414) +,S(2094133c,86322dd7,ee1abf80,2ddde826,e6385342,6bc87510,dff63f3a,b94f54eb,efb2ecd2,13bfda3a,227b791e,c24ff627,17ab559f,1bd289b7,e7db992f,d941e850) +,S(a34c3385,ee882646,b44bfbf0,f64225b2,fb86df27,c616a2ba,6cabbb68,cf36f3bc,e99bbaac,57c9f5ef,c64c6687,6f2bd6d3,b9ec8eb5,f9227c98,9a768f34,23e91422) +,S(df09dbfb,564515f3,a6d86e05,dca59a0a,c353746f,b291d9c,add27d68,6810cbec,90738e50,6bead3aa,c0cc4a2d,cdfb8529,5e752945,a7b2e357,1a99c901,49017c47) +,S(df9817de,89526a26,c61e4294,f245ce06,8b5e22a6,4937d5f9,6898b9ed,74078989,c4db6e86,c6a44091,23227adc,345d6eb7,d2f12acb,f2df3b44,978a1743,94072f15) +,S(2e713387,7a0419b3,7bf77874,b24fd0,7cae9fb1,59919a50,223437b,7746eada,5dcc4c1e,12502573,b0520817,16fa46d1,8ba43ff7,e7f8c8cc,e3c141ca,6176f805) +,S(99826364,f0061305,1ba033ad,63b95884,97158ee6,9542d06a,f2f86d91,3bea7a2,5f109254,24af4592,2ab30701,464d504d,6006969e,30a9ce5d,76a3b115,6158c6ea) +,S(19222e8b,5fec6d2f,33a35fca,83c3b9eb,effb9e3a,f2ca9c53,929fe5f2,a43bcd32,c79b4f98,4621b2c1,d627dade,f01fe761,8af239e6,b80c23ed,a2dd1b1b,e750549b) +,S(e0ea59f8,6b7925d3,ad511280,8b1ae5ed,c0acf6c6,d4ed0846,d870a663,5573970,bbfa69be,ef531b32,5272ee02,8c880178,57ab2a32,65b5a6b5,38ef81db,83b5de52) +,S(7df189b7,c29c06ab,83f7d849,58ba3d1e,7da3ebcb,feeb9dc4,64b60420,3631fdd0,88e00d45,8287fbea,5c14ab33,6a879948,e81d9798,cb82054b,772728a4,4b69e56) +,S(42b9867e,7cde3ef2,b4b73f3,e4df7504,b7f06cb0,67aedabc,16edb276,97bbca58,eab47aa1,df9af0f5,40d1c6d2,ba7edcc6,fd436f56,c944c872,1e1f4958,63144390) +,S(9ffd9a,5535bd30,a697f61e,e6fd0ffe,b1a7e5c1,9459bd3a,708a7112,3a3da54b,79fb0a7a,8334fe38,64fef8a7,60610920,af2741c1,fa41f582,37e92acc,29644011) +,S(13ea8e5d,1116a57f,8b223a5f,79c750de,6c25511d,558e6878,e92cb134,7b81e393,a41efd37,d35ea994,8175d989,cde449d0,e325b40e,a247edd9,e8f4eef,e6a4d283) +,S(110d401b,d7a1a0c,e484fdb2,34cd839d,5e40cad8,6244cdee,5c4f2ba3,ee1e2eb3,cdd91a5,4dfa47d2,98a46f15,c021a38,975ca108,f2653019,46013427,349d7ca) +,S(48a9f1a2,fe29b05e,d419a14e,8ed288de,46affeb2,296522a1,f2407b76,a8f6b040,f1c5ea7,887c029f,67202b41,198113cc,f1ba5617,79afc1eb,db0e10ec,5b5d2a91) +,S(d8c4d9a,feb94e7f,7b831464,77aa4e3e,a48b6af5,35015941,4047cd01,1beb7176,fb8af9c8,da06c2b8,8787793,bd19d7ca,6cc64508,7713af45,4f5fb4c7,eeda3c2a) +,S(34e84417,2f5ff4a2,70a9064c,d5994327,9cefde94,d295f424,2c491efa,bc1f0839,2da40cc0,5120e4e7,8e84435f,895a3ed7,6c507bda,4d16cd14,b602deb4,366ff9fa) +,S(ea802ca2,f07a4348,791b7df8,99639d06,c6db8d15,74ae8441,b29c2d18,18b7a6c8,ea475a0f,5f74e6fe,ccfca44b,ddc38a4e,3cc19c49,e2bffa49,a9572146,6338a155) +,S(d80542c7,a7be8da6,6346d867,4154f65a,b1cc8e94,19299d81,6a5c874,f25ee43f,5e85d69f,b5c72ae,bd94b1e4,67e0d30,df8da61e,4150f4ec,e3efcfae,78d88d25) +,S(bdb35e49,7c1c0d1d,7a120366,cd259e7,31cb253,1bf804ae,f0c82cdf,561d0c0c,2675a4ee,aea6dfed,8597c08a,69fc251b,7bad9869,e83f485a,73dd1638,605915b0) +,S(5174e27a,9a1eeafe,6411f3af,b627223c,db0da11,6bca0ac3,d39a3080,815e22a7,b1223046,5f58d183,fcda2603,e4593398,51ed87ed,6839d9b0,4c845459,daa3d5bb) +,S(c8b1299b,1b2880ee,7720ad03,62588349,44bcc309,6a7081eb,ce10ef20,ab1f6731,ead86be8,85584e4d,34ac18e3,d787031f,72feb217,694a32a0,76f2f88d,a04f3440) +,S(fc1378cb,c42fd6e2,f61be9bf,e60bb2c9,b36c5a0a,4aefef09,c8287a3c,f1310d31,ae4ff85e,5b22d2fc,914192d6,28324d12,51ffc469,1ba8ca13,f8347edb,5a9170d4) +,S(7c0bf943,23e7c1a,8004b23c,c05327a4,d4127c7b,eed27e3c,4a825e41,5f3c3a6e,30ad62ec,bd19f80a,a9dcbb5b,145d18af,3248eeb2,1d14e648,d7fd7217,f1089728) +,S(2ede5f01,232c0409,34b07b70,1ccce3d8,27f85ad,2a56c987,e29cd6ee,d841efdf,24cbe9f4,69f036a7,6e140720,f65817dc,847e9562,4820dbdf,b8a1384c,8d39bdfc) +,S(decd1afe,faf01eee,d2dd89c,bdb9711c,4f1899fd,437d0371,55cf74f5,9aa0858,899d1c8c,49b0b3a1,89a24445,568becb1,d3b1420d,ffb2c7a3,8fc291b,258f8ebd) +,S(1dacbc1,4be6e70c,4043f5be,3f972d36,3cb456a2,2ee1b1ce,3e207578,8233a79f,fc3b04b4,f502affd,37d71c58,d6f1a61e,b126cda0,e156608d,7f2ab786,e0734486) +,S(12ad0f7f,cc7cddd7,60cc6a3,3fd3de83,b1ab0e3d,cca013a5,68d5978b,a176cc19,b4e0cf97,335b374,661f6c21,46aa7315,a2c4f6f2,b839f88d,5376e256,99e6e216) +,S(f649bb96,e477a5f3,f852dd31,65496c07,5e14a85d,fa929794,64f1297b,d56fd1c8,46e37dfa,7eddec82,88fd18eb,9ac200e6,79337296,e2cad24e,d67f98a6,2e61d040) +,S(34f5e5a1,248db96f,a165950,a9b74392,acda22d9,95496808,82760daf,642c600e,a8a6637d,a1cad7d2,f72fe1a,df67eff8,49d0ab0d,7e06d7c1,a11078aa,de9dc733) +,S(26e940f9,ab45caba,adb1e4d3,23e5cf70,575c44dc,dd2f0b10,1540174d,d2aa715a,972aeeed,c5fd01ff,3b04f236,c799039a,9c7fe6f0,db1348e8,b97dc885,c57926e5) +,S(e3ad36a5,132f1067,503498e1,ed4b315d,4d06cc67,3a9207ce,47224497,12f51a4a,4fa719b7,37cdf1b1,cd5b963f,16a47e6a,e43dbe0d,490423de,fe5deecc,5baf9e8f) +,S(413fd0f9,4e231525,1aae9d6f,61aa0038,dbf7cc03,10c81185,394c8cc4,8b721a9d,9281c5b9,ac1f56f1,50776cf4,69e57118,8cc6989c,ae41b950,f72ff25a,d6de836e) +,S(9841a473,600446a5,5ce0ab4f,2e77ad12,bc2abc34,1e607241,c0c61d2a,d87148d5,7d1bb113,ee4b5199,95231834,1e05d87f,f9bb355f,df958410,3d161969,1d786f4c) +,S(1d4cdc2e,3e06c052,69958eba,f00484b3,36594f9b,be1ea98c,2382e608,cf78272d,6cf5d126,766fe5f7,75bfef7d,c2d91b48,66d4bff4,c8eb4e59,230d1903,16ac6bb4) +,S(da74f388,86de9c6e,36227258,758111ce,3b9414cf,cf8d5cfa,bcd9b3f5,44f1262a,d9231255,e3d9189e,a8d0344a,80978b83,3f1afb57,5c799f01,8b4ab73e,866a38fa) +,S(b2ebf119,46e37704,e1e12345,c68f70a9,a031c0b1,e85c0833,c5df9c0a,b836a6b5,c1652832,1666f0f4,19806a4a,86f4aa8e,46fccb4c,f7b6493e,26d9699a,9db2bde4) +,S(9fd899da,eb6f84ac,edfdeb4b,fbf8b521,6b5757e8,10d22d4e,56afc38e,da747cf,2daef35c,7ef36b82,d6158256,2466895b,9656970b,4beee8cc,2e0b12da,83d7af64) +,S(eda65e56,9cf07e84,19d07f6f,4aedd24,3c46df2c,bac92772,bca7edc6,ba17b217,1f394c99,b48348e6,fb709e5c,b4b4b77d,41eac2aa,bea2a4a6,353d1982,a9985281) +,S(78567d1a,1a96df56,299c9ee2,1d916472,303178b6,9b18fb00,a23c10e4,f093ed5b,9321fb0,6c5d2dc8,52e64d6e,453d9923,bff7c626,efaf5e50,245b4ff2,64158f23) +,S(c639e1a5,90f5973f,148e96f9,15c94d8d,7c7ec36c,bdf15150,83503aa9,9ef5636e,3620e7fe,faaf7581,886776e4,f7391599,94ae3e2f,2a59d4e1,ad6d508e,f4db90d4) +,S(73ef6655,c49894,7aa2b63b,89b77f14,3ac096a1,d7333494,d9774ada,5467b60e,c04509b6,2135fa8f,816436e,6ec0f513,ccbb23f8,782e2ca4,d5eebfea,6a5297af) +,S(bfa4506c,dca70a3b,a8fb0188,e0384bf7,3afbaa0,6818d503,df5015f4,f10cf341,9fc7388e,2edd63f7,9a5d328d,1b949a2c,a364075e,f94c8de8,37cda5e1,7d566ba1) +,S(2d594b,814a9e92,7ac9433f,3400c5e5,1a58457,6f47b8f7,f5f0b8d8,f48b2cb2,fa9a1577,d565b906,1acb9efb,4bf415ed,f264b662,594d1ccd,51baf83f,101183a7) +,S(401ae44c,a4039850,4d57390f,66044f6b,cf1e9fe9,f0f2b057,3f64f026,b6d5f3e6,ed947768,36ce65ec,f947b81,9dedd31e,c8ceacd0,16a40a35,78a592bd,4c2626f) +,S(43f9397e,a000ac26,8a315406,fc9cd047,b9cad513,8a7dab38,2717744c,ec6662b9,14d5bbe0,52dd8635,29c0b0b2,dff7379f,3e2ae95,6c5b4920,b36452d9,56085bca) +,S(25036a12,d8eca48a,78cb5e84,41aa5a53,16376e83,e2ac7819,db9895c4,dcf2a22e,14c421de,dcfdf9ec,b69a24fe,1c289ec9,f4d0f9ca,6f4b9409,35ac9815,a4154209) +,S(30e9c9a0,d9b9c92e,65794acf,a2cea34a,8d56e3db,d5b56205,59100128,26bf8991,999e4729,bca75c06,18f0bf9e,8ebf0455,3460031d,4ae47623,5e4ba182,2f62550b) +,S(a8fb641,fe27c40a,8e410831,fe1b0d2,cf74072a,bb626b19,2fa51341,e99ca538,f3832ab3,4eb6917,3e2f3755,366b2bf2,4dbe257e,eb516e39,4bfb91e0,a63cff8) +,S(5e09a349,98a824e2,f3ffe2ae,34a835ce,6b2f0d28,43b765fa,8dee010,49df7867,20ea03e8,4817593b,931d1612,2d01dc7e,52715fb9,36838de9,d2c9fb69,9c935025) +,S(e62a12e9,d02a5a7a,475dbcc8,79850ba8,340b638b,a5c3b505,8d3c7ffb,c90f0dcd,b075d21b,40e5897c,7e849529,bceec7f1,d5f87881,318c115f,acc99680,31d17f55) +,S(45aa5534,530265c1,c358b529,de15487c,b6bef551,5125e835,e027b0a,a69a9cb6,2e56d88c,acb32ed3,24068fc4,4c03ed2b,1b70392c,9facfc2c,2fafc696,fdb8d397) +,S(7fe3d940,50e2f358,31b410ce,e54c7c82,5eb05553,981f1c45,b136a24c,4d4a4b57,97b0cfad,4f6669f6,efb2d35c,42302e10,87c03b3b,1c22e23,24050399,345165a5) +,S(110dd614,85bedfa6,c09a2e5d,5737ab2,4a5b35aa,40129388,c6ce876f,bd3d9c30,7972ec2c,621155fd,12f0a1cc,30927669,13a9165a,7dab66aa,8f8fca53,7411041c) +,S(7427d28c,aecb7a35,a4100c42,9fe03d5e,6d3f2f91,a5067866,c618c4c4,5fc53547,8cf74ed7,1324616d,bf4135d,8f442ba8,b473ebab,fe981f2,3a426eed,bbbcff16) +,S(9779c811,98040c8e,754b9df4,b547c09a,a9f25410,1ca1fdde,365b0ef8,34ed95aa,148280a1,d26c8ff9,51774c55,7590081e,36030a10,a148c322,3c7379,67d036b8) +,S(41113833,f7da3a4a,4736fa62,ad7b4508,74ef5b9a,b0961665,e30f3081,7d861adf,98399ec3,485a984,cdbb6817,783223b6,59884450,881d2f41,3f4e59f0,ed5fbc65) +,S(f9830e6b,9a9a9dbe,50abcae1,d44d4856,3a92e505,aefd52d9,2259c41f,4b8b14bd,12061be8,5a0042ea,1baa46df,b36d6f78,62c11cb5,b8a070aa,6c6a8991,62ea1c0d) +,S(71284b2b,36a4c8a4,40fdd713,6b647482,bc73d680,3d6d0142,833d34bd,f2794077,6e54f5fe,8cff4ebe,bad1b47c,4e5d6407,44be9171,b391492c,df48bc35,10e195df) +,S(524a04d,a1b7ba04,34377531,99178ceb,7ea18f36,2c300aeb,a8daefe8,6e63e9d5,1c71ed93,861c3b1e,41a7fcd6,57225e92,b2ddc507,4d54652e,3898683,8c3688a2) +,S(e1fb70fd,2057dc3b,c545fb80,eb91cc9,479cada2,93c3492e,260b0a75,4bdc0222,aa799a9c,25786c64,d5138ba2,1f801e5e,88fc2602,d4e288f1,96c8d79d,7bad2278) +,S(2bf126e9,8302e8cb,407570f8,c3fe1206,3c91bf2f,63cdd9a9,3dcc403f,a8592d29,6452a6a2,20edbb86,3ed65ed6,cddd70d2,6b4975bc,e843a41a,10ce6ed3,d38591f2) +,S(faa217d0,1d9f0517,5950dd5d,e02972c8,b2c88076,36090d2a,6f17e7df,2a70cd7,73077022,dc1cb45a,f9e9d056,19635760,66ba7b07,bc79601d,ae7dca1c,a6cdc033) +,S(3d184ee0,ed45af08,6a7263b3,47b12449,a7270887,b8460b7c,6428ae4a,6dc4836e,d002efdf,1259dd8e,ab5bb606,97e8892b,4cb5376d,c26d08e,52b7c9a,760e8826) +,S(3c825a76,29890675,bfdcdb73,27f37c4e,43214a91,c6ddb6d0,f31e13d3,cd26eae,45bc7ae4,649d70ba,99df5d07,92e89130,87a272b1,bb2d6043,dcad0fda,a5444fac) +,S(3a8822a8,d5b230ef,62f657ed,31a12d63,2862f22d,eff16f08,8065981b,ed3e926e,ddca63dc,57ea2ecd,b25e8d03,2868b12d,abe8f7ba,8125a4c5,56d80a9f,9784a04) +,S(d0042da6,aa3b60a2,463e3396,98229067,c80f8924,12d8323e,7482ff2c,53ad86cd,40697e7c,4c5d6c,4ba11cee,fdbae25c,e234ece6,7db446df,daa03025,5f8adf35) +,S(a06e32ee,93d70c5f,a45a68e,2a180be4,7d8a7f60,17d035e,47c94d47,6f3838df,f4bc98ee,c7f50d34,4e88ee87,d8705b50,4cc0fd5a,5bfba498,5fe0699a,df811bdd) +,S(21426073,9f41da95,2dcfa74e,dbcc2f22,375fb359,93f83842,99e3735b,e39b45a5,697f2d88,74cd2249,cb84c9aa,16d20956,f5c40358,9d5b7965,ea4b46d1,9cd61249) +,S(84d52769,327646d6,13e3e1ec,2d20791d,76b765eb,fc5fafaa,20097164,dc9cda7e,d87be4b4,2e2e55fc,8f87dab5,c8c64493,f09b3996,87ef8fb,3a6c653a,a2250cf8) +,S(ca48382b,49283747,d433be3f,ee0569ac,7d3714fc,bbd76157,ac5229ee,ee25dd0,b67165e7,60894bf4,3cc80df5,6e3109,db7e370a,bebc7503,ce20836d,3f0ebb2d) +,S(8a6a751f,816c206b,91e67608,58fd7def,8ea70956,598b1c61,8e0699ce,602cda79,617ea6f1,c7f98cb6,41f01862,1f4c8cf,12a556e5,675765cc,c7bb1283,cc8ed073) +,S(1d035f81,fdc7c483,9936692,9bebc7d9,15fd3c0a,380f3348,13c65527,d82344ba,e4203070,f687298d,af8f6d66,6030f3a0,5826b0b9,31f0e55,8c356aea,b3464712) +,S(d28f1a4a,1198f572,a8130bbe,3f25e585,348a33c,2d73053c,ee7e29de,8a3ce79c,2841bd4b,c46c772a,57018c74,8510fc7a,dab16644,f157d51,9c38391c,4470f7b7) +,S(41c71a1e,eafbd926,4a49ba4d,e976e72c,691026a2,b1773d4a,88670b4f,d9c57fb8,c2b198e2,e4557f8,41203c16,b511d61d,b39e8a67,21b776e9,865158e1,91ea5ac) +,S(3f0ae72f,b1a06f84,803ff8ad,fa0e5c76,ed0b596e,d52568e2,6fe4aacf,6cdbc3ee,69a9dc3e,a0ae93b0,6c4650f2,941ebe38,fcd4eba2,fc9cc0b2,3fb9c127,81c53f78) +,S(b59e2f6,2f01449e,d6728b04,e9334f10,54c4c8e2,db4a422f,70566b55,ba4d2e5f,1b6b73a5,7444de3f,4137f2ba,722e70ab,e6a785fe,1ead6fae,9f2ec5db,299f00d3) +,S(42145fda,e72df9aa,fa3c20ff,cbf11a0a,d357515e,ec6846a6,5cc6ffd8,8fcb1347,4a34e518,c9d39736,3c88ad65,62ecc0ea,2652c6f,48955852,99a0de0b,5f42b6) +,S(17a085d7,8d8013f9,b98a8509,aad7553f,bda81df3,33aa6f7b,2457a74b,c83f6739,412d9b80,efeca81b,29619ca6,8bdcdebf,7cd253c5,88793675,6a379655,d10df76a) +,S(f5ec770b,2e0d0afc,7b155abe,bf310270,28bdff39,a08d113f,b0409624,e7049ae0,e9ce5d46,2dc5d255,a09ba37a,a7a5edcc,aad29ce8,6f9c6b58,d2781e81,5d88a25) +,S(45e3976b,749279e4,486d2db6,fbbc7731,168e7311,d7d75f62,b754839c,2fd17918,84f0c079,c0127eb,d1064724,927459d9,ebc22eb3,502a99a0,e5876e15,29c8845e) +,S(df15c304,378da361,7f821d07,d00d1bdc,189fae9b,7aabbc71,51c2117d,8fe0c21a,589daf,cad5cc54,58544b9d,a69dc510,9f8f1e82,866b1076,ff1d229,5942deb4) +,S(c5798ca4,547cea39,75e3b613,911434e4,e5f503bc,9ec6e9a4,8dfe8386,a371494c,2864334d,fb2bff0a,4690f2ce,d1a1d1cd,e3b13f96,325f295a,8e0d4f1b,b13413f6) +,S(773ba0e2,e1a80ca3,9060556e,2fa8d15f,83dfd018,dd226751,9262651c,9765c915,e59a686a,3fd13284,e380188,fa40e9e8,28991374,20c906b9,ae882512,7dc7dc60) +,S(6ed4cac2,e1685eec,16c12251,db5dbceb,90f542e3,854177d9,83ee6024,d6e7a740,2558db33,ab598118,1802a84,e6ed32ae,49c25379,606a3150,6ad03ec0,a5308b98) +,S(21cfc6ee,d98915cc,1bb52da8,e83aae9a,64970d4f,ca3e70d1,6536043e,bfb60fef,8154f487,290cb8ea,73cd147,c1286d5b,9f471665,d9e0ee24,c2be264a,2f1fbc36) +,S(f8db764e,bb8f031c,88921a73,92f75323,7d1f4a22,7bc8cc64,8bcfa9a1,235cdc11,82c25fea,2d0a1e37,e16dc4e1,b6737ee2,281693b0,b48911db,c79c1470,c4e6274f) +,S(d52f4eef,14a5a860,983eb0ac,8e02def9,53f2ba03,604cc60c,80882e56,ad6b3dfa,b34b3131,7e37b973,9559bc2,6f85226e,705bf06e,1fcd818f,d5b88eed,f2d6b7ed) +,S(3e9d0688,b9b67517,e25b526a,4e46be08,4e95a171,f9d99ae3,4cca6c14,66adaf6e,e1938d76,c4349375,1d5b9876,4ada7b7f,57144878,78805540,70b7c27c,9bfa312e) +,S(c74f8dab,54590ad1,3fff217f,b62f43ed,7f42ffe3,6c8fddac,fb6315f4,a3406094,1bd8025b,57dd382,5b5b6896,e90ab5ba,fd31ef46,8f02846f,29f1b1fb,f90302d9) +,S(71f88089,a8e0ac,6cd92e03,b1dafb04,76c0f489,f16def9,75985abd,5dcd02ed,839bb263,7827e6ab,f6941b53,67c9aa09,835c588,3956733c,267fb52b,6be767a9) +,S(983d1cde,7d75d70e,328a8a62,ec82a96d,5174ed4f,c9676e10,7c282be7,bd408b07,5fe2426f,287fd353,173c699a,39407e36,c365c413,76986640,7c12f11c,5dc436a) +,S(3cf9defa,a067fd0f,6b012fe9,8b05aea2,83c332e8,cbc8296d,c777951,9e62519a,3fbffaec,c77d872,7dad2011,aa314690,2806f763,b73b780e,375508a5,c77a613) +,S(f415897a,cf653c3c,26fc5231,f375e28f,c23041aa,af05455a,e81419dc,25546e30,3a9d5669,806ef66b,7a0661dc,cb941531,d81fa7f3,e08fec72,ee6312fc,4a7f59e7) +,S(5bfb64c9,cacbd09,244f3a96,d5a6800c,4a012297,95962fbe,a429b659,8e085eb1,e5c4ecb4,9cc4c685,a4fadc80,77889298,b94e779f,7f462aa2,130ed8b,ccc0604) +,S(61a5a78,a086ccfe,9f54cb0b,750b7c8c,5c8dc4b0,e32f3c69,c65ce4f8,9009587d,50193c13,affe3a34,1ff3b8a0,b37f07f4,b49667c9,f8940311,9ecec58f,a76d8c60) +,S(e74514ed,93784bda,ca6e30e4,da2a9a78,c7c70bf9,42cb4ba6,afdc357a,c694ed1d,ee4a8c9f,7d55dd09,c51117d0,754d301a,cc36dcb,49d437dd,ca46a920,7088440b) +,S(dd9aa58,f2cc4c0a,8d2bf548,6dea653c,b4671e40,c0073df5,352b2a9b,95637617,6478aca1,582a65d2,6c0f42e7,48f06e60,ab85a494,d0129b85,5b5fdc62,7dc7f580) +,S(fd7f2622,665c2005,9bdb8c46,d140ecda,ce013ada,6dcf3503,e28eae44,c2dcd83e,536c948e,5db2978,31e2ab3f,fee860d5,dd7fdd16,645cf561,67e484,f4a62c61) +,S(9635dbcb,b2595930,835598a7,149a8a37,be64f607,c227b307,4d8e8184,c2ae99fe,1b2cb226,bd9f23d,bd243ea3,eb57baac,163f4e49,6272d220,9f436f81,7b6d9442) +,S(642ead1c,c24db5c4,77d798b1,515083a7,7777476b,c3a03993,883a7ab5,e1abf814,185293e9,6e6dcd7c,209fc891,d96f9dfc,4012f756,7d3e2f1c,282eb0fa,5de46eff) +,S(3c5be7eb,3aeab34a,2d982ebf,3a766962,822ddb39,527ab79b,83540818,a4e2931c,a161ecfd,2b906280,46d6d1de,c149eee0,e6c92ccc,5f936a51,e2a4c3,82e555a9) +,S(c1a90946,6c0ea8e4,b60611fd,6c61733a,6d90b0f9,d1b7a761,1f9e3e84,6423bde9,f928d301,b6c27eed,79b8a8a,ba388ef5,24b17220,7ebd7396,5623e60f,f650dcf4) +,S(e49d97c4,2ec1b8f1,43180188,382b265e,4216bdcd,82824a15,3a0e1d73,83207541,8e521e4b,95a1f4b0,934753af,cc3b73b4,7b3eb00a,a9c7af48,7e4e5a02,6234b733) +,S(49f71f26,f0d828be,9e9a70c1,bf768117,ad2fe6b4,6e9f416d,eaf17695,80dccfc1,86f4404a,67e8e6a6,9a901589,d7c09873,eb553aca,41b0cb66,f4767621,76ff0d79) +,S(487d806f,67635c8f,b66afe46,3754a5b4,64afa469,2ca69541,5d91a6cc,8903e853,b610d414,26951e55,46bb7216,6dfb62fc,602b3d20,18c38670,760f55a3,6c45c688) +,S(47af5aaf,cc7b69e4,bc536d57,8f57b958,3fa17666,2d302141,54e3e35b,57357e38,b79a4c34,709d215e,dd3b0fe4,9cde9de5,b45ccdd2,af25bbd3,602a0c90,9834dbee) +,S(84f79cc1,a257fcad,546d8218,5caae7da,8a8d523e,7feabb79,16ad7d8f,5421575,cc84b844,55ef03ea,59913a0a,1919c0d,cde9fd92,ce872029,57a998d3,80ec1986) +,S(550b7e54,3d3accfc,eb488b6f,b2b48d0b,9017a5d4,ed54d55a,72b8ac6f,c83f6d14,91f318dc,ea83ec1f,f43d5172,bba5ab1,7891f3e1,2e162b6b,8c512589,5f2e5141) +,S(f691885b,eece383f,1f56593f,92de0b34,1627cd58,389afaba,f442663,88aa6a32,1e6c920d,2eb76656,63c7586f,7907471f,79e5faa1,b6fbf4a6,c905e422,9a441638) +,S(4e3c52a,96889e52,b99aa469,b5f07dc6,f6720e49,29f3961,fae2c59a,98ffacf9,ba3a3d9f,dccc36fd,a8642167,7f54de2d,4c079b2c,e70b46cc,926d7d9c,ef1978c4) +,S(66720c8e,c638367c,c934347b,d8768338,54eaaa01,a81a876b,d2321e41,40381224,eb595ebd,67c5a08b,24482042,5035ecad,f20fcfe8,9a84a60a,93f3c05,a926d574) +,S(4b01f86f,f9feb661,eb33d7eb,87f940b,74302cb7,449b0bc4,84e97af9,56b79d2c,2680db84,1b233e25,16b74190,fd3a0cdd,b8fce285,ed8577b1,e13c2205,9af0d3a) +,S(dea430d,6a4b5e18,fa04f77b,55f85d36,df9dcd47,87ad5899,c16d2533,74494867,46b1f5b6,307a1c05,f3b42ff,e7a272c8,c63c2a92,19bd2971,d70ea793,5bd508e8) +,S(3f987bbe,d7fe896b,8a8067a6,de49de63,670e7260,f255e5c8,a926b9d1,fb62945b,373b2f51,86d7d9eb,18570d3b,9e48756b,663cab9,df388899,7af923c9,bd79971d) +,S(6cbcf291,56e3cb2a,b0d3c03f,3f4c0283,d953a641,9f7e8655,d8c46566,e3990b70,535c1017,fb40108b,24de2a8,358d217,8e47961,e5f4cca2,aa7e7c2b,339c60b0) +,S(d253488a,5610a541,e4ce2cac,bf4d4901,5fe63dec,94615e80,d795b39d,9885201c,c58ac205,e7323ca8,9bfd284e,9c9bcf3b,89b05571,b84d3afc,d69a9a96,9ae4fcc6) +,S(bb77470d,cf0851b2,29494d6b,e69aeabb,dac44010,17200af6,391cc2d2,352bd9e7,187cc653,b6b56e6e,6c9969ea,705a6d9d,3539d4b8,b8777371,b64deff6,45307942) +,S(438c5a3e,1ede7063,eb928da9,693d7602,809b9e08,e49951f2,6a600eb3,e929ad1d,d2918af0,67d34eeb,d8f179ad,2f3f105e,a5cbfc9e,1f416cec,372a5175,8ae797c5) +,S(35db0905,e28b3e7b,b8c4425b,8d9151b9,9cce6a6f,b6e11561,65b7e356,9191e69c,25963fe,ba45cdbf,5472c046,3da3279a,60a3f1ca,9ace47d0,4c4648b1,52d2e560) +,S(6ef2e9b,79e48447,7532ba0,1b658af1,e27b13b1,f1635317,6b47d994,cf3c6bce,88cc8a3a,aa1f2040,7976ae7a,9bfe09f4,f0c1fb85,72f122f8,4aeee871,b87867ca) +,S(c85fa35,4c064f00,ac39d455,7884f8a6,420c4192,aef2d6af,8afd61ec,2b977b33,3d17f849,6ba4a79a,bcdaf502,87fa5fe6,15d2c24e,58f27ab2,7cfb2d86,140a5f0c) +,S(7f47028b,4e84f4a4,21909f01,85df2743,e3f18f1e,134f90ae,166c4089,a9d44803,4c025c2a,c2a1af49,fd7e1e3d,2ddab9ed,104a0e21,17895fc,36eaf9c,7a550e9d) +,S(6ecc57c0,5c7f6b98,6cad9c94,435664e,3b036ae7,325ea091,234ac216,3dd0e324,67086288,9346eaf7,e6bc8ac5,25d60d5c,41bd9701,f5cc5f58,7995fd6,1c75def6) +,S(46a2a28f,61fbbf15,c3afacaa,e181f527,2b957bb4,7f127465,fc03d021,76359328,88b36e79,2c071ec4,adf1a34f,a3d1114f,f9813f91,39b2db5,83320bef,134ace83) +,S(a2072cb2,e25bc045,fe40dead,8fd3f7d6,449f8d7b,57adeb47,b6ae9b7f,7d6a5b2a,fc019c0d,8c9263f3,aed518e4,44c1e5bd,dcf796fc,7d16cc6e,c90c4c59,7877e36a) +,S(fec203e9,60d4ead8,e3510545,3e73999,1ce5234d,a92a20f1,813414a3,599874c5,118cddc6,fe918be8,d2c5483e,c985aaa8,4d708767,4af70444,1fc0692c,b92a540e) +,S(fd166bf7,a69d80da,6e03c740,2ce6f4,a05f1df4,e2a131a,daef89a5,86f73681,1e3f6791,7f2d3824,ba4ef07,86ed8f08,c65860a7,e6913fd6,8cdd759a,2deabf29) +,S(a479787d,b514baf5,b46a578,6a221d72,2eda896a,a7fc1e43,4817f125,2bbe0d6e,1a6f7857,92bc5fc4,e2fcd87c,6b82ed34,20426f30,a9c6fde,4f09ae14,9ce426a1) +,S(7aeeb17d,f75e9c7,2dab575d,2ad1cf87,b3eedf99,8df4b14d,d42b50e3,7895f041,8060c0fd,5f903934,d47f3886,8731ddfd,a6fc1355,53be9a44,38418174,37b79fbf) +,S(6dd254bb,63c3fcc9,a5d1758e,90c0c6d2,bb1a19ae,788b351d,191d0261,cba75c76,b00b5cff,f3246b0f,ec835345,1d9df948,4fd903d2,e278ac2e,59d8ca20,647c2ba0) +,S(d9e76bea,acd64f55,9a9c2888,5834317f,c24fe5f6,7e540d27,6233c187,76cd7323,4d079fbd,15ab81b4,f3aed0d,663178c4,33f976d4,f69af7dd,ecf61a13,b831e71c) +,S(b57b26a0,55c4f224,865b22,287c9402,4c801618,c50b00df,33ef8509,a94a0f57,5abc4303,1701260a,f41a0e49,a100da19,8d033179,8b26026d,6401654d,39d53670) +,S(e03c71c7,9d902be8,5caf4df6,aa401a6d,18592725,2f10be1,f4190b67,bee3bb8f,e5f16a54,ce5772cb,1390e49f,966a00e6,893ceadd,5a753c7f,9d82a2ec,7324240) +,S(b7f3b64c,980f19f4,e4f46083,c1ca758,70f4313b,3c23c5b8,6acd6c8d,57ec0de4,5fd0d8f9,2a70c9aa,bcc1523f,91fa603b,e17fa73,fce73899,2c1d720d,3d55b1ca) +,S(27b24868,2a1b9186,3a1f5c9b,a5010a37,2349c417,e1d7acaf,dd94c7db,c5e12733,c54c23bc,4e17418b,deface22,b8e527e1,4de1aee9,71c921fa,fb3f58eb,e4778125) +,S(5d4b2b1b,5f9e640,bad96aec,6d3bc5b6,169411e9,5dac7346,d1f7f885,50679a14,80f0e3e7,7e8d6c48,62b1f6c9,c0ee37a3,3b98be7d,e1c6c8ef,12759b73,c20a2e3) +,S(790a4189,63c3ec0,ba6babae,18ddb717,463d3ec7,c0b01852,5e760e96,ac5fc2c1,6db8b456,9f2fed97,783a6e80,413d8ff,cd0ac6e,d512f712,4cdacad4,4845242f) +,S(38dd209d,705c3f63,9cbdb0b4,22160943,4ddf1366,56f2cc8b,22d27479,c5446f99,8b793f60,3621f6b0,1b1ac36b,cfd92c3a,7dffb7fb,fcbf831b,1db077ff,7482c25a) +,S(29c6b2a9,24f95c8,58857951,cea2baa0,bee9866d,77b3f7d6,3cf9debb,16437528,c408f565,cc78e5,15a6e0c1,7a96392d,2952e25b,d067a0f2,d2f10eff,b54c2ce3) +,S(19f1ab5,b54c80a5,a32a1fb8,1bb3f389,ebb53641,6c8a844d,3846c2cd,350420c0,38a56a7d,7eaf4155,4f5b8090,c06fcbba,9f516a23,340617e4,dc5951d3,35b75de0) +,S(fa3d2b8e,d73ab5c3,24980054,27830806,3715c17c,7981db6a,61757048,1e1d780a,7bc0b4e2,4cde1ca3,e30ec601,73121a43,f87f679d,cfac6db5,a9bd132b,d6a89454) +,S(908e538d,730377d9,d3585ae,59b0949,c46a6aca,bb04e725,70b189d5,57c26825,5e108800,6cddf00,39f7d855,64252cfa,d4a37761,2b58b6b,5fb2942,7e274af6) +,S(e57bfd8,f38d456f,2e977090,d9f81673,db11a195,568a85b8,dd8bb725,a30d22ec,b5965e5e,e680e791,e87ceab7,156a3e03,dda7e9a0,9a9dcd76,a72dc838,d9e2e6a1) +,S(aabc514c,b88112c4,6e6e1221,d61e2abf,dd7a3bcb,a2c7cb78,4d57dea6,1950534b,96e3d9b3,f3a4c3cb,1473f61c,e224dcbc,a535c90a,7d993409,ed079d32,3c8facc1) +,S(94a800a4,6eb9506a,8f6dd737,ba45c697,4e563c3e,1df40959,4198d1fc,e499d2d8,627ef26,d39e19d,ab4d6bfd,9d4fcc0f,4bb4d97e,b0886426,40b7ca31,952be814) +,S(1022de3d,6caa7542,ddeb47d2,1f82cc3b,6e04170,ed9d4ef6,81b58b81,efd6c3a9,2317f1e8,37716a0d,842884b,cd77cc3e,d6235dae,9fad5661,9f20a883,af459b5e) +,S(9509f343,17c15f7,a54cafc7,3d4275bb,41e39183,53858724,4031baaf,97bed951,dec71a0c,7f8108b2,5e296361,2d6623b6,7b2f6d9c,69d7b6cf,d7273503,fc72b4ba) +,S(bbf19e9a,efbee2db,fbd5eef8,492f52be,2e2f9072,6b3adc1,d16f0627,f4f19d25,d9e691de,f2ce976,c66d806b,f35a2b13,56f9fc07,7b7bb239,30668081,4b52cea0) +,S(b5997bb4,5b359516,b28ee935,e4d59c39,ae434c29,5e5d98e2,2ddeff57,4afabc5,fb6d36a6,fb2e1aaf,d9b5d89c,39a854f4,a3cec053,1e1a776c,b4267b4a,d2bd8ac7) +,S(fb746cf0,cbf2f56f,6a3a99dc,71e84cc5,af76899a,3a7d02c,fb272391,b77c8384,d1e4cf27,57373ab2,d1ba3f2d,d5bf8b26,a74d6814,23a5b16c,9621b788,a51e9796) +,S(644facf9,e6290462,1a5278c3,f4a2ff8,84600c23,69eeb557,bc412540,c4966655,5b5ee0cb,449423fb,67c9b542,3868f7b7,6d1968b,9d7dd751,75e7dd5,2f994b88) +,S(c41931cc,9c311617,f77faa3f,6b6f6e21,bd030c2d,9778b065,6ca105f,cdb8658c,8a759dda,8db8a8ed,eb1f2972,12858879,bb2f49c7,468d8edd,14d28525,ca3c0746) +,S(e8dd9063,48691527,e4f4fc96,2a0e5608,d151aa68,53257e2b,1acb7d94,56f66aa2,470d108a,4180fbd1,2a377517,c5e472d4,680ec468,52bfa472,cc400ac6,91541a0) +,S(6b48efeb,ea6d0d17,346fba31,8fa33deb,301062d5,94b254bb,db6dd28b,ffe27451,94cbae78,eff2064c,cf91bcc4,fe1ae3ef,3d767b63,6eb4720e,35f2340e,87c1e941) +,S(1cb08c2b,72f069c0,e1e4afb,7ea73e48,a33f23cc,cb89fb08,db1b0919,62bedbd4,64d3500d,5b6577e6,6c18d3be,fc0a7dd0,833d3245,1ad03257,b45a31a4,67c14095) +,S(2150558d,bc64dcb6,55224045,6d943208,7b7c7182,3901f78d,9702a736,998906fc,b49e2adb,321e0c49,ddeaa152,9bf83095,762ea96f,6c1290dd,b6ad29b3,c84b8657) +,S(530f4c16,58284100,55a67001,eebf528c,f9286825,fbb60ae5,da4ecac,e3d7f4c1,80b147ab,1eae8922,50bf82fe,1a9263bb,41573617,7dc02e91,fe7e07b9,66bc6af9) +,S(c5158947,8266dd62,fa495d4f,94bbe77,b1230f44,685ac488,7642576c,8d92e6b8,1705fd37,da813af6,2a799e41,3a45a4e2,4d2121e0,1065e692,ec1de149,43be7c90) +,S(e6963d21,b576da6e,6aa6f1ec,da7674d0,d827d533,31e19d85,83ba0e7,31553f86,d3560d2f,91c7219c,76962a5e,3b2aea76,604b5ad4,82da8f8c,419cf2c8,7cfdbe61) +,S(c5aa5963,a249a9a5,9445c0da,9537d482,dcb6ed9c,8372e455,4d440931,3c3f169,7e7f9c15,4ba213f5,981389d6,22af8694,b1efbdc8,18998923,92c9d654,92ae7fa6) +,S(bd04e3d8,5bffa429,81310c7b,2c885f04,69f01977,2819f6f2,5e69621e,5a32752,dc4da51f,b88ed097,b17358d3,da4fb755,254d8ceb,5b0df72c,9dc995b3,8e145d9d) +,S(f8f55476,4418c668,3390b604,c9f9f452,1ef63756,58000c49,d3b8b1da,80261dd4,9943a6e4,1b928da0,fad12667,cc997ea5,6af49db3,8c499a2f,a2343efb,52ea450f) +,S(77dc24bc,5f32159e,7c3b6a3d,168a6698,43b12253,e403299f,b4fa3db8,74350dec,240d860e,c38457ab,6d741edc,e4fd8c51,67f75733,f12fe892,aece4f9a,578c6bd5) +,S(9f238f7d,588d53f1,52da8118,2691194d,99a56fee,373745c9,aa2a3a7e,58d18825,dff57ffa,c2012315,ad6516d6,92902476,cdb2d3f1,58803c3b,4dc854ed,8ba9b756) +,S(92f95782,a59da5c3,a12401da,34c24ae3,fbf3822e,355ec948,6020ac04,3ebbbb6e,1c6231c4,e09c414c,e0d3cbf,9be73bbe,4f1fdd,b3d65a41,c716f0f9,a39788db) +,S(1b40dd47,f435579,1474b560,66a0efb9,88271a1c,19186bcb,b1715196,84f3130d,9fe6dcec,991d652,c9e13099,66b0aeb3,53869f99,28ebc955,6c64973a,4d983b5a) +,S(473f6b8e,d4162f9a,2f40d48a,8827f79d,180052e1,7b28b240,4772fe1d,64cd82d3,743450df,fc8315db,72c01f1b,21c4eea,9c0a39e4,c1e92e33,91096576,37e97fe2) +,S(40cfc629,a550b437,9e0941ae,fa8abc6c,8b492155,2045a8b7,560262a4,86954932,e627bc57,9c84859b,d2a9ba9c,9d7a69d3,8c8f06d7,ccd9e68e,fbaa0697,655a8a23) +,S(4c91dbc9,8d2d2891,a7861599,ab55fce,943755f,5f7c909b,3f0f85a2,bbb75c95,5e541495,ecf13109,6ac3aeda,5324fe5f,6f761ddd,d2972fe,812242ce,12fd23d5) +,S(1fe3c538,ac185172,44461f82,63961364,c3c74bc6,9a91bb4e,69973971,8e729d23,974c02cb,d7d97c,65f89b90,327e6dde,e627d96a,275c869f,22c14bf9,6be05389) +,S(fbe873db,56579349,4ca9c844,8a6e0dde,226d4e4a,2f210661,30fe1075,bb11dd6e,c91061e4,d03f9f09,21f56d76,eb78640d,4df80464,459fc41d,4ca33d4b,5ebbc5fe) +,S(b58277a8,3a6d6779,82af314f,7a41a69a,b1744e6b,1cfb4803,f52a25e9,8200957d,c8faf7cd,59e43256,33403b90,7abb1b83,d3f0cade,ddb9884d,77c5fa54,b55fc51a) +,S(3949cb,e84b7790,a7a110d7,9c41d548,d379604f,ec567cea,e3aaf0f6,fd0d9b49,cdfe904e,56a9c88a,76292c3a,5da21100,57795a76,fddc1610,e7efab84,750617b3) +,S(6ee9ab2b,537aeea0,bd8332dc,d810cb7d,36f8f7f3,57be2bb3,5d84e236,f1bca531,d75518a4,d975b0d1,e2780851,4b726626,dfc182a3,885900f0,4d82c839,1c64722b) +,S(c2875d78,3e15f959,33bbbd48,8a24c65d,2001f599,3536fa83,8a3e056c,20a2eabe,e5870c25,20adee27,83cbeaaa,cfae7283,538446b,7cfd7ded,12e68ffd,3f66de8b) +,S(88e26c2f,dd475547,8795e8dd,8285f73a,dd9eb9b2,68c1b16,65f1a701,cb3c81e9,d00344e1,9d14b3f,1dcf5c7e,8269237d,a2af90ea,93a9e24f,3a0040ee,d3f171f1) +,S(ca8e8c50,660f3928,3cb72105,43710f56,9a1518a,7948689d,3d7e2ce7,a038bc55,57600213,1892bc9b,5afede4f,e71f5ec1,a1516039,ace088f,9a851278,c52b2487) +,S(ecb6e53f,4330d0ec,b9aa3605,b6e6d209,222d611,72858b1f,d2663797,772e0249,b054af9,4c535d01,bcbd955,61770aa2,e08678ea,cd8de0db,d8efcdf8,623e9eb7) +,S(a011ad64,55123316,9916b20d,ca6efe7d,e78c6b58,feee97fa,7f9e3fc6,8d889cfe,f53b71eb,63f87651,aa0de66e,a51f56f7,c5e3ee26,ed4ccdf4,1978d7b6,f0191277) +,S(3ddda2f4,ec1b4020,31a73abf,ae69dd42,8d801bb3,fc96fd1e,b06334d3,cd7dc27f,eb1b6b4,137ca36f,5b160112,38fba958,32c5e5b0,aa5560dc,39600db0,624b6c1a) +,S(13f5b643,e908dc91,415ff856,76357687,bb777f21,3972cebe,e8157828,53982d8e,bc2d3402,f3af6ee7,bef0ec2b,73c75e53,b70309ec,633d97af,b9ababc0,62d20ec2) +,S(ed9fc1ba,60a7db8,93db8148,48790e52,4a246279,d938a04b,cf168ae5,71618e2e,b241c920,ab995cf9,4ab1b707,b06bbc7e,1cf7b8eb,80325934,d57e9e9c,6ba08459) +,S(89d4f6fa,f6252ba0,d036dcb4,54fa5f1d,311ee828,1cc5ca85,73fe7607,7b16fadc,5f441ff0,56fd4e24,ca4c9efb,859d6e16,2e4daa4b,a7f3fc58,e42a540c,23b6075f) +,S(4acfd390,e8a1b430,9af0c28c,87f51308,a1ec5741,8c194072,45c96c79,30498a3b,dde7b57e,5e5ab271,78f2ae5b,6494a578,2757f508,bafbbe64,30b96bc4,96728d2f) +,S(8320cbe,fa7483dc,4f5e7b7d,d74cf492,b95b7e31,b1bdc651,6595b605,eecc134d,e766291d,13959f5,805de8f2,aa59cd66,8376d93e,4b775010,426db24e,b2ff41f7) +,S(fbfa6a21,deb1d183,cfeda065,687a0b96,6d8e50fe,475a17a,7b690019,6e7c696c,f5901c10,5f30f5d9,75530b0,3f943caf,8de85a12,f54e4c7e,5685184e,8bacae2f) +,S(70695a81,45fad213,aa14a7ec,d3c84f51,53e3906d,5483db4a,c6e8c229,ecd2c3b,febf34ba,9744a37d,6b91335f,c735c426,1208595b,3b8d048a,3fb48e76,2008e90) +,S(89fd8cfa,8fd5bdda,b6a80bb9,96ebcc92,6074a15d,371622b6,1cd772f6,ae1ae9a9,85c2cddd,a8065ee2,244b3d35,61e9e057,87c6cc4e,d4b1ff59,53b736cd,d3876108) +,S(342256b4,cfd8e5b7,5f5d088e,3a919d64,ccf38827,b18bdd00,2ee9a6c3,fb4dad,c54f4704,f3512e55,4d96ef92,3005e4aa,34a157e5,8bd6b180,e219dd51,16c4be16) +,S(cbd38ba1,189a152e,bf78ea23,3eccebc7,16f4c28f,273f5c8b,ec9df397,9dba0dd1,d3df2ea,fa52ad52,9089c7c9,581dccbd,a2a0e060,7fd4b902,cc915f28,717c2d29) +,S(5f7ae38f,61dcf176,45affec8,7514c624,85b880ad,38df28ae,b695cac0,fd1d27ed,9b955855,f74cc040,63cfa4d1,fd098e5d,e0030c4c,6dedee41,71bb5e7b,c0939226) +,S(72e72eac,aef492f2,f3c5ce7d,dca58f40,c919a194,3662adb4,3d855a8b,532d194c,d7b5e558,a0cb091d,3b39407e,1dd58b95,30fe7561,6b4c3352,bfa51320,509d2d7f) +,S(925a19f0,c73d85d5,674a62b0,2d5496c0,5868fd41,a43696ce,eb153a0a,2e5b8051,2ff229b9,6c23cdd8,2bdc56da,37495c29,78fae40c,b429a1c7,3111d392,3c5505c3) +,S(baca4fb3,33bf98dc,165cb9e4,3bec920e,bbded256,e990820c,8f902e84,3f6e02bf,af304697,137728d4,e96a38d7,95b830c0,6c18579a,9b46f4da,a94a13e8,d3a0341) +,S(fbe24c7a,53b90f3f,918b92ea,e58ef633,bb72e695,2eee6c6c,2210f6d8,8da9e0df,1febd844,af3d057e,c9ace544,d5fd57f0,c125c55f,1d9df636,4f6be8fc,bc53e3b5) +,S(73b7de54,ae8a38c6,ccde88c9,3f526c2e,54d823de,a6415488,5e864a2a,1b0574,2cfa6943,634201d8,9438e6c6,fbb7224b,c2e6b313,538523f3,305c75c3,5c68aeb0) +,S(84960402,31a60cd4,cd623d4b,80bc69aa,7cfa7c0b,52cd88b4,2f22ca66,17151dfa,b5324b5c,af293ece,38deafd0,76835e10,469997af,7dcccd89,172ad20e,f36162a6) +,S(b6de647b,98585f7c,61f0712,76c6f62a,40926888,b1bab4fe,ad64098b,4b9434dc,f7180d81,be634f34,d878a645,2c662e8a,db9c18e0,ca7e7c13,8bc51e1c,1a5f5c0a) +,S(e062011f,da416281,bc296718,300a080e,fe7ab89d,8469e8dc,fd50680e,12dd9348,c33030e4,1ec1b1c5,4ad01bb9,8c4e2c48,32b2516b,1b2b3b22,adc4add8,1b690787) +,S(f7c7545,649b4659,49618dea,7fd15a06,1e7ee032,5d955649,b76b66f0,534a5501,2a929b2,a68342c1,81b2f55d,6b543584,ac06077,d95ad8f3,fd3f3ffc,24f56a3f) +,S(bd90ad48,1694f297,6506e2bd,e97d5803,b810f9ab,7479ae90,dc1fb146,38d4d5a0,f973b70d,8dca64e0,c9384b7,ad3b4ab6,4d3c74aa,722f9284,a9da82d5,5c6d02e2) +,S(cb5d91e6,68b3c202,b72a38c2,f98e6e4f,14bb566c,f7996d9c,c08aaa07,210b1b1a,68e9920c,597b633f,9bfdfb8,72814422,4ad69ec1,e435e843,73a9255d,79f52d7e) +,S(d251bb9,83bf849b,8f058ff6,32ac6bea,bcd12649,4fea947a,f943cdf0,6e0c240b,5098026d,b8ec5c54,8e3ae103,f0d172bf,e84281aa,b8c0b131,16295587,ed4500f6) +,S(27235299,c1f8d73c,268bca88,62d2b6d6,635f151a,d148c662,6c0cd5cc,1a3d2234,5b03cc60,f9224aa3,10d8193c,74e70cbb,6513ba73,d6d98ad3,2e1c2d,7f78ad52) +,S(1cf437b,aef8e007,ba02a24e,735d8444,698e5edf,2f9d41d3,cdb28cf3,3dd53851,e3fcdb74,b580b8ce,8f6edfe1,c276c478,da11323b,4e96862b,926ca4c7,f739a8f3) +,S(aa872c85,70e9449d,6cf020c6,77669c8a,7ad408e4,d9fa194,99867c6a,f77df918,572579ea,3d1d9575,e60a79a0,7a2aed83,4fdfba52,61b962ed,42e59322,c02fd873) +,S(b3224a2e,80c3a174,66a9994b,717b4c37,424f12bf,9dd3f17f,6eecd801,3ee2ed56,7ad1cea1,128c1605,552b8be2,a5fb6bb8,907e4290,d76bc82b,e17ecc32,1be6fa43) +,S(29b8f73a,7fdf6032,4c907022,b0107c72,ed951eef,29687feb,a8de56ab,4e47b8ad,19b849d9,bbdcf00,a6bba6b2,f1058695,4f286884,9b5be608,d6b4c357,1098f54c) +,S(3c2f5680,96f946ce,3d048364,dce939b4,a05ae9a7,c31c2a11,d2a29a1a,3fed06e2,47701685,b698de43,ac515062,9c40a15a,bb952a0e,bdd96,ba4a1b4c,5f61658b) +,S(b80f00c1,ec0d059,c9f5c69c,10cfcb26,651716d9,3d0b5702,b2c7b295,85af4c55,aac197db,ab42141d,31f63425,5df908fd,fd026d10,1263aa7,63d99414,adfdd02e) +,S(66af071,6b78b854,16572c86,fb3e51e9,b6d66ebb,bfc2a2f8,dd664010,83c83435,b8b2ce8e,fe794b13,4fcaad05,821dd884,9a8318db,614d858,8dfd4d2d,65314398) +,S(7ce8342a,6ea85f61,559cd2ab,e82debe,82eb5aca,142153e5,320562a7,6ba155c0,8a930243,5ebf4269,d75363c6,93ad4255,59f493e0,e492150a,9f110c90,8d7750a) +,S(cfbc37c5,184fe206,7f7b5c6f,c5e50adc,ed58ae61,d9059bb,4ff64a19,f48483eb,bd567b19,3da2b2fd,bb8941a5,be9fc72f,11d9cfa2,4c4438c6,a4db3091,9c8867cb) +,S(728c27be,52c5a742,859774d3,2d33fbcd,41e997d7,25d6be46,af480c8c,f9ec436c,745c7738,2a833cee,19808d12,9768c213,7500e8b0,b140e3b2,94abe97c,9a7c73e7) +,S(4553277,fbb30c09,a1ac1ac6,cb7d38f5,88cd5f3e,d4ebf6bf,5b5f6e78,12d47d5c,3ea80bc9,dac9f1a5,ac4beedb,d254cc15,728f0ee1,6949ce97,53f1bfbf,98e3c78a) +,S(7b752d90,9fd6d063,f1ac0f22,d8cf1e6c,78a335c6,ed11743,88192fe3,cba54cef,a252376f,e482ec59,2ac440e7,3aac3b46,a149e35,1aac2d51,244ffd93,f51d11ec) +,S(e78e796c,eaba974d,89d344f2,b610e84b,d51443bd,1fea5422,d2bea957,5467a376,13f0797,376bcf76,b6ade4c6,a95b6446,962ff925,b32fef9f,4549aa1d,e64e2b1a) +,S(1b7a8c02,83f25ac4,cd4a841f,4045035f,92a39bd2,c1903c90,4071eb44,5e8d702a,1843f757,7d03b6b2,22bdc28f,47c7fe6,fb83b25a,8d795b46,9e3ee9d1,ccf7623d) +,S(90d06a90,6ad81dae,20cfc2fc,6be85b2d,41dd9f23,63e13423,c557c4c4,bf3e5e4f,6ba7a127,58861784,2d7ee3d5,9b71ec99,86a72ae7,71312739,79544095,1e5237dd) +,S(d7bb4e18,ab61d8f1,de4b5bd9,9a5d03ef,1e0185ca,55ef14fb,be1f0b5,4cc4803f,311f268f,a672975b,acabcab5,1dec5754,48eb5a82,685e339e,e23b41fa,112873e6) +,S(6d5f1808,f17e0b81,a6bf12aa,34032644,b708882,96e99861,fe5ba4c5,5546c44f,8eb304c8,92cee7e0,70649d73,ae76893a,610504d3,fdf37af0,92d5dc7a,9eab1094) +,S(e4f62cf,9835a4e5,c2b7a456,596498df,2973192a,af2c80ef,c036c71,69df470b,874a48df,1a25a003,ada8939b,f727e0ec,b7d2e4d7,1efbec4,7193a2b0,50ecaf28) +,S(7fb31d8d,b3d5b77d,4aa9d0d2,692013ce,c82ccd6,83a2235d,848037b,dc6bf8ee,ed5cfa61,9fb4e350,dc37e2a5,2bb67104,90dcb484,b19af368,8101e59c,f9f0f0a) +,S(8887db9c,e3eddeef,ece414a4,f46ff048,3c4fd25b,14354869,6c60871c,5eaa9ffc,50294d61,1040a466,f826e654,3fb93f94,b4d60b11,d589287d,6ea33df5,a8dcf366) +,S(9d9d224a,595c843d,1f70297c,13b3645f,385eec97,80fa9e50,d27115f7,b677aae7,af9d5f61,24594cd9,a3aa7100,ae6f169d,dfd467c4,1affefe9,c9a0a5e6,6d7f2802) +,S(743d9b40,527b23b8,f165b6fb,9d5c14ef,450e1ce6,94439354,ab501eaa,2f34137c,6aad08c3,bf602b52,7d43e3a6,e7efcfd7,f24222fb,f8213f25,e8195501,9c8f0885) +,S(63c850eb,f0cd6fc3,3bb7a4f5,6d43c389,1f93b11b,5f67e3d2,f9b7537e,e5a951e3,29d214e8,bde33612,a5a160e0,f7cf3acc,3b83686c,ec5d7c36,dd90ebb1,d97c7ab5) +,S(b95608d9,84c13243,63809f82,b42cd16,fcf3c6be,5b19ccd2,249016eb,d93b4a54,41aabb2f,e7083dfb,ea380fff,2467a843,c88ef6b4,9740e73b,33a088a7,649fb0ef) +,S(8361b632,5eeafafa,f01e3624,6bd8f0c7,aab461ef,cb3484e6,c1ee871a,7ef95114,34ac956e,791cef3a,baed24de,7f0f59e0,bf34dc75,edd10159,b3870248,255eef36) +,S(807109d4,931731c0,a94127af,cc98e487,1fb44467,6d8cde89,88dfc252,868bc853,363e3944,be00a734,4c50afc9,cbb43183,f56eb20a,c0a5d9ec,74857484,ed9e1d61) +,S(25ef876e,d1654570,244ec258,e7ebda09,35b11784,bf5afb7c,8652e5f8,bdb34055,63459bb2,b8affcb4,1f6ad9b,9437f3cc,6d8082ac,d400928a,29f11fdf,503c8553) +,S(1aa87b1b,54eb6bd3,5fefb162,b27ad9dc,eee4b5ec,c1b69d4f,1fc6e230,d1848435,e5cd86ac,23c3790,369d7fcb,2189098b,a4fb3007,f82e5090,22e8ce5a,b44258d) +,S(cce2b0fd,9497190d,e6ea068c,98bba7de,a8f50aa,12930b4d,9060808c,b1ce6152,b6aea7ee,becee274,2bd8146,d792a6e9,ae75fd79,bb8882c8,11135d0f,8d5e68c3) +,S(fe421506,955b7cf6,f6a84228,30f7c6fa,95e4576c,da711415,5a49c238,e0bdcd4b,4e4a31d5,9b70b51,f73a4d02,eb09e4cb,7dc74a29,bef959ed,86558fc7,d4c8f401) +,S(cb26c118,264778ef,512f8acc,385e5ac3,10b489dc,88991e15,13665b7d,587d713e,7375bbd0,9fb3051f,a907fee6,80683f93,54403c76,85ca7eb,97a711eb,69033c6) +,S(8f286ae6,171d88d7,d82cdc28,93960bcf,53768c8,9cf1f149,fba0acc6,f5056014,6852d427,a888c5a2,4e748f2e,e482d38a,42879db2,2e824d1c,d72cf15b,8e32b085) +,S(b7af4b6d,7eb4eb03,e827f099,fb8b02f4,bdca366d,811d031b,ae827941,235e75a0,7cea697a,e8cc53ff,8c738ec2,55a64e4,4a499643,4bc5e16,422ebb9c,17d3dd12) +,S(c8471c9f,53eaa3fc,850ae514,dfa1109d,e89c500b,e965682c,6a4bc2f9,105be1e0,7d5f32ce,d1e758ff,e38325b4,778e68b6,f0ae5509,fcf9195,c1a79d41,57dc519) +,S(8d192ced,73629184,ff6db80e,b2c6df4c,a8ad77f6,dfc98c52,9406e7aa,dd506536,3b01ec04,ff45b037,c1444255,9cb2f629,7b4f8cff,e4c3eed6,3b95d4a8,88fb2137) +,S(318aa156,f4912dd9,7b90ae6d,c29b0f8a,99f616a2,5b023f08,ad35a8c5,10ec5015,b398cdd9,5ad52ba1,d7038cdc,67e36c74,5625fb94,f62b1b9f,aa2eb5dd,be6ce52f) +,S(b7fcf98a,6a385f68,a1c6f9ee,c6f069c1,81b0c94,df8c05ef,b59b49e3,aad66f54,912e2098,e3b6e44f,46eb6382,83f554e1,80af035b,16c0eb3a,4e000cb8,d4ea2da7) +,S(599b7a5b,e7a7cc6,3e0b66,38171c0d,41d78efb,92a9bc8a,1d0e8f48,b2b92fc2,afb3343a,1983a867,c8e196c5,92f745c,9060330c,1f0c0509,375e30de,3a214b7c) +,S(c3578705,3221f18f,69dbc241,f927ec48,3280ade6,44c70129,2b30a11,a296db9c,2b75b2e9,fdef6060,29633ae,481ba7dc,8ca52847,d4d0a201,9da74056,40a980bd) +,S(9e2020e7,cc4153b0,adc2b1ef,3cf607ac,305a480e,3a8854d1,1907fca0,4811fa7,19153a83,2c9a0612,dfea182f,a855a039,33035757,2e98e5ef,43f26699,3b8bc6b5) +,S(1e0c4c68,6e5242c0,6645f4ac,6ccb18c0,82c5d5e6,c89322b4,3b6079b6,ccb5a5f3,63c4a4d7,3ab71f2f,c49f5532,b543e381,83ce223a,c8609be9,d6b72981,8b5dedfc) +,S(44b11683,5f922e88,e7ed4328,cfb212f6,aabb6199,64fbdf3a,87dc7f24,faa761e0,a9181b5c,341cd78f,2e1446a9,e99acfee,7aa5b91d,4c7da20a,b7cf200c,f470ffbd) +,S(940baf24,717ccfda,e539064d,f6e4b670,2ad8b60a,c32e38cb,fa4eadf2,6a7bd3e2,bf5ab95d,2cd9b68f,cdf535bb,84b967a3,f4fc44d5,5e6d21af,d09e1de,f5f13ad5) +,S(4191f800,85767106,a9e5fa6,8521366e,a3adbd79,ea315b93,9e63f797,2995e7c5,662791d3,407f50b3,7a68e15f,5ee71991,2e893099,a907db3e,f818938f,9c3bb2cb) +,S(1bb8ec05,76ce9cad,f96b418d,cb5c7d46,9b49ca81,7f253b15,8b26cca1,cb9a472d,762e9c6b,2335769,72396f,36a56efc,f2618754,f1c30923,30b521bc,4e0198b7) +,S(c5216da7,91635b83,e55ec5a2,d9f3f8be,b1a2b0e3,cb097528,654c50a3,315be78,2536358,e58ffcbe,789d34e3,25d9f59a,2210c247,a80eac8,c716214b,9d5e520e) +,S(7b1488fc,83a02d7f,d12b9eea,555922d3,f4a9c42b,52f030d9,bdd39156,f0890225,ae7dba7a,d95420f2,8c8185cf,5aa2b777,b9fc5c14,b6c47048,d8ef071a,77dd4397) +,S(e245e4f9,7d6c69d1,5e244f4a,668afd07,d57fea2c,f8401b2d,8cfb6ada,f01f8891,88a0648a,ed5eab1,d57226e4,63411b9d,3632537d,699f39dc,7d7cbe5,49e76900) +,S(ed78f3d5,1f4fb987,5918a0cd,d6e5280d,6516f5a5,acdee916,d3e7c7a1,d757d188,ebc569ce,9b3cd325,528cde0f,9a2ef54c,d9f920a2,1ba7785f,62ef40dd,9463a81d) +,S(3e8d870f,bf768b41,8264ad34,89026fe7,8870e201,3f98696c,81dc3b7b,c0b1b599,28558e59,a6a6c255,a352cc9a,c20508eb,55af7449,8d75ded,c94fe414,fadeb218) +,S(96125a01,8f901790,fe25b41c,f2f7fc98,50cd30c8,cbd05ffa,cb76bc45,94d5f5a8,125db476,3fc8ccde,492e7eb4,45873147,8f8ddc5b,6c2b588a,b72d9b1b,fcd4c43f) +,S(779d9847,6fd72d41,937fe1e3,e12d4076,5cc61f41,19b37437,3919782,18a3dfa0,75a3aa4b,95523e05,42f38dab,b2d80895,cf3738fe,5152c8d0,96a587d5,90442891) +,S(681e390c,323224a0,7ccd9520,23c9d89f,4069100d,3b275c5a,e773efe6,170f4e4a,a9bff0ee,334bcf6e,a3bc44e7,5d85acc,f753a471,ac008e0d,47b19ac2,476b184a) +,S(d7b8530f,3fa18d18,ed94b938,2906e431,44ad5994,5eef1d53,e3290887,5c4af2b9,2efa5bd1,acc4ce6,73b8c76a,beab2e87,6399f84,94a1450,bd6833dd,debddb92) +,S(1277ad75,6e965ecb,c8c04ea6,c22042a3,ca3e71e0,74334012,7063d3b2,da257a5f,38c90310,ee2bd94e,5f3149f1,f38d065f,8df110f,92f126f1,3a69013c,515134ed) +,S(4e66e596,94c521a1,8114b232,427dfb97,8c7f14ec,7b5e18e8,9c11cb5e,6a2f6f65,47d553c1,8a858b59,f1aa8f4a,51803450,c237fd2e,60b137f6,d13647e7,6683caea) +,S(1fc1e8bf,3eae2dfc,b141be5e,ea612378,209ab1bd,7ccce45c,d51fcfb2,8f192aa3,5632d350,ab6b3da1,599779c9,9cd8d7b5,e317ca9d,ef3245a8,eb62af95,ef769c20) +,S(7eca2d92,8d2bf4fc,ed1a8336,eb87c5f7,b864b842,b3057c8f,97d5dfd3,76771d7f,969da039,7a37997c,c243d448,90d8110e,fa580359,bfb35342,bf69dec7,4bb17337) +,S(2531025f,8fddd665,cf34baec,52733303,28e47e4d,827248ad,9a1e6c4e,be3db9a7,e404fbcd,d180b2ad,931b4f61,5902eb06,cf00f66,6f1323f7,bf0652fa,94dff64d) +,S(dd28941c,bf6e4bd,76b4bad7,88f700a6,8c4937a,67958c3,bf6388a9,d5e26441,cc45f07b,9ea1a81c,8d89af84,8883ad1d,53ee8a52,2416c445,c4963791,7a366909) +,S(d3af9e12,53ffb85,ec7829a,4d41d704,1ea62952,4d7452a8,d9ab6ef0,1d6b509b,9c115e78,91b383ec,20739d37,6450a2e6,6f332e5e,c7a3a97b,2eca8c0,ae819bbf) +,S(2c59063f,13ac98a5,ed196aec,4f2aba11,c8647d78,42be85f4,ab87a007,2b49001,e9738418,cbb6e31c,f588a3b8,70883f90,ed3bd8e4,86e3c77a,37fd1152,c22637d2) +,S(6c0ace3,f182c963,45deeee3,c41c5e51,8dce984d,3d409a89,6d766ea1,b1ff0e0c,17e09dc8,dfc53cb4,952fec4c,92782ce4,3515544f,6181bde1,1d1ba1a,bda709ee) +,S(f161125f,3a229d29,2053fb9f,6f118550,43d80e33,9bd45af8,c1519043,2098c9d9,1b442ffe,a186cf2c,343b90b3,66a3a008,e08edf90,f073e740,abd5d20b,8dfa1327) +,S(fd081f05,6b219fef,56a3fc1b,6dc7873a,fb054b40,1b3ae0b2,414384e0,9080827a,9711912f,4ceb0036,3e5921b5,c2f7ca49,387b78cb,f1b9c2ac,9c5d5d1d,1bd8203) +,S(72c6eecd,d87657bb,ffc3a03d,b6e1f9dc,83252d2d,c73ba3f5,8642fc08,fee42b4e,282180c1,7737b51e,d047cc50,64d53cec,6340eefb,d969525e,a1524f0c,a305e39f) +,S(10df231d,4582143f,1ad7fe00,508cbbfb,3d49775d,f13dcee1,d6155768,c14bfc51,b7743bf4,e7cd49f8,88cd0d26,ac196037,e1da9402,26518e07,407bad1d,20af7dc6) +,S(354e8b0b,e40bd9a0,36620006,744c0913,5bd4bcea,34ab3371,9561e36e,f465956a,3e7407a2,2b9d71eb,a04239fa,600834d7,5f643c8,b4ca6308,475f6c9e,8d35fd4) +,S(2ae99ec0,6a4e080e,879a60fd,a93a47df,9ba7e0f3,b87a6772,be6d7e23,9bf2c42f,3fdfcc57,6a36adbd,52467e01,f3490fbd,82766cea,b956f80c,7b1d29b0,5066c31d) +,S(f47ff09d,5e93e827,72e73c7a,8f1623e0,823b09bf,86ba3023,a223a680,fd849bd9,379ad3a3,cd546d27,35fbe5d9,97c3dd8b,8c45a3d1,ce8e9c49,b23bbaea,e93a08ea) +,S(252c0934,acc3a624,c4d8b409,111b248a,2242dba4,7d57718a,aedc9cfd,20647cdf,17b7a015,a2ea993e,89a7161b,f50124ad,561ef131,609981ac,fc92e495,cd2ec91d) +,S(b7f6bde6,7cdbbf9,4a3e06b7,dc1bea75,d6247197,a8617a6e,a1f65f44,a7459006,6d6ad596,fd3472c,9d7eff56,943c1a03,ee4f540f,29782f77,afe999e6,14f5e316) +,S(210c956f,e0a741a7,edad58d5,d47a2a34,fface7c,5edad0f8,f4953b72,28350b2f,4d4498a0,892a9a9a,4e87ccdf,424d7910,bf90fe95,186653c7,6e6966a5,e7a816b8) +,S(7ab93adf,b8f35eef,8af99e5e,e37aaeee,401a1936,fc0b8c88,518065d,12f4a74,4f0782b1,c78954b,8ce37bdc,7e533145,3b885d92,da1dbf85,940da9a9,b7f0dd8d) +,S(bbe1b787,9c93e7cd,891f628b,c9a655e6,f4c7cde4,fa799596,74978224,9fd05fd0,493d3dd7,be33acf1,38ef5b73,8eb8f8f5,4e270323,8f70078d,5f7bd9e7,177088cd) +,S(61f42d35,ffcc6151,f8c93b21,5df0cab1,fb804cde,f9c68818,fc4f413,b804942d,46ef1e12,d6add082,3917a758,9c137d45,c38ae2ed,eadd847d,aa574e06,18708396) +,S(18542b75,3e78191c,b3dabcf,f9c64a8e,5e4b075d,d600fe60,b830e732,7fbc7b40,6a816e01,41b17e86,65ec280b,f6da9dbf,8061329b,6db9d13a,a9f10c0f,41340118) +,S(ef83d0f4,a3d2963e,d14e708c,6d22017e,aa97b2f5,23b06f1,140b4105,459781d0,5587e5,13725819,1b10bd40,e616e06d,16a50392,7a8b1394,a562c396,973d98b6) +,S(fe73429a,7714dac6,ed0db327,d6949d43,30d2b16e,a513d3b6,7b74452d,78a82a4d,7079088d,fd828815,ae087319,c232817a,4928f743,843a4966,e9411276,d16214b3) +,S(2e8b8a63,3048900c,4b82ff8d,fd86a971,86e3f1b4,6206b252,f06a8c85,82555130,74e10dbd,ca84d796,b3b37ae,b32624c5,2c5aabc5,d4fcc5d2,21c1aed4,71c940b) +,S(9f4164f5,4f34a59f,3a7be378,66a8204,def2fd98,8dae6dbf,5d471e0b,caab7017,4b662fde,bf2615c0,8c7b53d0,b2915d50,ddd2916f,a3599d81,bb2eab6d,80e93f57) +,S(c6f3a26b,adab6699,aa08fcf4,6f0ac900,2be3597c,16133225,6a5e6577,11b16ecc,f29db1d6,579d0e36,4528c297,36019f4b,6e8f060d,ad5effe6,d357d709,882a250a) +,S(76a4f5ef,6a869e28,e6494cbc,ffc6eec0,1ca983ad,1b8219cb,d2b84eca,96f8b910,e1d8bd7d,55a297df,32ee185c,c60db286,a2e46cb1,312a8995,5923a068,cd3318d5) +,S(d2c25c8a,cfaa0b2b,3f6e70d5,bf095700,68102f8b,24867970,ef3c8000,b2212d1a,bc907681,9c7926dc,bf81278f,7dbfc4cb,292a8071,177ce8a4,f4e9346b,a2d9e500) +,S(b2fc2ca,5a30c678,61b0bd22,5bf2c088,26d799a5,9c9a680d,dabac9aa,5cb624fe,d4abc7c9,fab915d0,fe9dcf59,a0f83ca,56b27566,6e9841cb,b5b14874,5f6732ee) +,S(110ef531,7824c321,ba7fa94f,ac98de3a,c6cf44af,db92b7be,1006c751,9b425065,cc3daa20,6c0eb83,6bdfe640,1f7461a,261e7233,c70e615f,db82a991,77b83cb7) +,S(fe21a607,7419ed88,12d16ba7,5485e01e,3c063359,f95a8634,3aab1c84,ba6ac00b,d6e08c98,4b7a5282,bc1857b8,82604fc0,692a2fa6,40cf5a5c,d298f344,54c836b7) +,S(c5e45275,ec85bb32,edd32702,7d7d87ac,8394bc51,722e0bd9,58281e61,c454fcef,9b158ee7,89034035,fec4f06f,2fc81755,59f9f762,38742715,92ca6ff9,e5712a8e) +,S(cc68f3f3,36360481,5583d65,7da51968,a4a44a69,1264bac8,289791aa,dc7a4ef4,9db5cab6,7b31f3fb,f3b5fde2,273496f7,93316358,6d14e80b,bbca4613,319df9aa) +,S(6d33be85,5fe8bade,89109a3a,8c089aa3,f7e9d178,969100b7,eee7a693,d83ace80,9312736,87c08455,c43b4cab,afe71408,333fbd69,d330315a,3fc9a52,a9d473d0) +,S(5aa581c2,fc48c38c,2aa2e176,c12f12b5,4810ff6f,862fa17a,196c06e4,812b9e3c,adbff08b,bf6fd5e9,9f91f9f0,9881cfcc,a7b5c2af,709bf838,6055079b,2f75f3c4) +,S(12eb2dde,dc6ea4e8,dfd43067,9d45052b,b882e4d9,bf516b,61edaf00,305fe883,8f948ee0,f8514f9a,1bd8a71f,20c95e4d,e30caa5b,bb3a383d,9561f027,34bb1950) +,S(3d0d7eda,43045e9f,62dc680a,be47e933,74a95d59,945b69cc,60acb89d,e40dcded,45c53d35,e369af07,eb223a79,1d148ea7,1875cd1,8ca066d3,399743f9,65e184b4) +,S(173d4741,5803d266,7ea94abf,319c5917,204256ca,e217647c,c024a9b3,be7b70c,2da6c348,cb066462,eddfe8bd,3dd00ec1,34a0a060,4b7e17d7,e6cda389,dd4d5463) +,S(10659655,e2f1ba5d,db390184,c2d6d1df,1cd2abfa,4cd4bc18,c89decc9,5b5d6319,5ac2793,3a88870e,d5c7752a,459ced45,69435a09,7cd0e030,25608cf4,ac2ae267) +,S(e462be7c,380d7bbe,cd45c6dd,8fe60219,404b0c9,4c5e0e4d,31a23064,2b5b95,872183ec,1ba5b854,1f3f99d8,ceac80c5,9e84756d,cae2e694,9b43ea7e,d1cf752e) +,S(8200badd,1df41faa,19b20cb8,efa424d2,2f39b1f9,26b692c0,2a0ef6e7,feeed67c,8402fa9a,6ef0f83f,42546b05,360296d3,74db551a,d89be995,f2c11866,5be528b3) +,S(760e2457,a3e1a165,526e9fe2,2b5bcad6,e8107581,337cecac,e2ae87dd,a3c54592,c5111ec3,24158a21,56b897a3,82bee2bd,de0f9df,af9ef611,a7fd3fc7,4a635b3e) +,S(ba6229c7,1729cae6,5275719d,9a35691c,f260a003,168f1a25,1ac00b09,aa17872,7d281600,6bd8981,82126d21,70fa0ab1,d5dd0c7b,cc377a88,c43cbf61,70a633c3) +,S(a2cf1392,571e758e,6ec74708,dc45f70f,90833ad4,135e7a34,9d2810a1,8efb5216,2420ffdd,afe96506,9e6f9266,1e3839ba,c9b1db40,d40149ae,3acc8683,86acd175) +,S(f8822204,27cc4b37,33268925,fb80beb5,a52e5391,b2c8e31e,f6e99592,1775af20,6cf6eb9e,b19825da,6edc5d2a,66f3987d,c9eb01e2,b70e6395,abe2903,d43acee) +,S(eea28950,fb676991,444f96c5,7e42ea16,aa380e3d,dde63111,fac35708,a4e45b3c,34d30722,98a686ec,7e1a8095,4e2911f1,5e11d426,ecacf11c,eb45a5cc,7204114c) +,S(7f252a72,6f9a1497,f61bc4ee,7b194a31,432c0178,2f40b16f,2d36e9c3,7279e25f,8edf25c5,f50c6f0d,f8a17f92,611bf024,14e02d0c,de38aced,e96d5a7f,4467c449) +,S(d3da23fa,56881cf3,a42a50a7,42e1067f,54ec24f,2de19921,b1ae7f15,fb90509f,b4ec4b17,8e555cbd,15210f09,bd1ab43,28e458fe,6aa3e800,44bf0093,ea08f90c) +,S(6752f294,f8ad85e9,60b6a88c,cfca7874,5c80ed7a,93f6f05,3782ac73,d96e31e3,976222ef,a6f6358d,42d6289a,4f11bd65,e7e755a3,845ed49e,3c972b5c,5fdb2418) +,S(4fe21b06,24a45b69,7f42aa54,10e6385d,645a8d49,2a61ece5,c8d5b2ad,1fe74efe,f7666c09,7caeea3a,c4b2993b,64f4c0cb,ac934099,8870ade,b7cee48a,c3c2c413) +,S(15af87cf,6dc1acc5,1d323a36,b2daf163,ccc8c201,a92f0677,6a26ae27,7fb9d766,53fe4566,6a975d35,ed20a5a,7bbe63c4,4cf8011d,45e7a171,d5d72e57,5debefbb) +,S(656f3686,c60039b4,4c39a5d3,ee82cd08,e8aa8ed4,b9a943e,42281407,4ab6821b,9f277baf,2da730b3,dacc2a43,512411c0,13ffca65,7092e695,d49c8d24,a4cda4d5) +,S(a13286fd,2c17a61e,6bf8d209,d64f5879,2534b037,cd854470,a09c8c8d,95aa0564,9322d3d4,c735a485,5d76e5d1,fd27fdbb,a8af2fcf,ddf7bdf3,f9e26f97,7f4cd1df) +,S(3b355928,4ddb285a,1eab73c5,6e6bc554,9f40d83a,2b859e01,a30032f3,a5a7109c,780670b5,67755fa5,10fc3385,7745a69c,bbe73e3f,8186b3c1,8a82c51d,5e1d9be0) +,S(b0b15be8,6c2dbfed,6da6e7c6,51c10b17,504070,7d1747c3,ff2dddbb,256fa495,8d2c438a,42750adf,345332d,f02f6c4,55a07fce,afcc51e4,96c270ff,913546e3) +,S(c754130,bd717ab0,fc17e14d,dd6ec50d,aa6bc02c,a338cd9a,798ee62e,72d517db,fddf938b,28500dd,c9f1fe0e,70104564,d1bad398,d3bee900,ff609c8d,f56d3b26) +,S(ee615579,33d877e4,9bb228e3,62766ada,8615d382,c022c333,39f78ff6,5e5d9ceb,3dd38b15,5ce01a1b,3d5434f1,b2e04a26,6a830f47,fe89263c,b0ad1b5e,18bd8b76) +,S(f830dd7,4d03a39,d7f5ba3d,132b40bf,130b33cb,9b6609e2,12b6479a,14287c9,9183a68c,33c2d25d,c237f8ed,b5a63d44,4dd2bffb,d1255631,221edb9a,4c9e9e91) +,S(544fa477,3aa3589d,9e63c8f0,f30cd189,a8b6658e,ba908212,cb1b4caf,2d5f64ca,bbf57d7d,b5c6b8d6,e202a7b9,8ed06edf,e1a9ad01,381da1d8,11405fcb,8ef717c3) +,S(9b270440,132f5b09,6fec6214,dac1e27f,3e6c6f7f,25eb2cab,680c3fea,e0b41b1e,a7e591d,eb990617,6bc87263,6ea19e04,c9a3aea9,59059078,2a757fd7,6d99c6dd) +,S(bbd69c5f,f0b9228b,cfeebb97,32b3c316,c14d9a54,d5a3e9ca,ebb337e1,e33525e4,78cc6c84,8c246e7b,7636949d,4e3f2b94,989c77c4,812b8189,cb857cd1,3457c403) +,S(a920edc1,4ddf5bda,56719c0c,2adaea7c,9aa8aab9,25a5d6fd,41172725,bc65341d,b8afac74,46e560ce,bcaaf438,69dc9287,2805fc14,122cb19a,bb59e51,8336ff80) +,S(3c6e9595,a201956d,ed27e83,41b22822,445148e6,d00b2fcd,ecfdd66b,2405ae3f,2b8ef9a7,d7c37d0,d2b77309,74718eba,16f221a5,f3074678,317f0b6b,7b0841b1) +,S(c35c9e45,3f487f8f,ae5b6010,e1bc1ac3,ebe4ee53,33666876,13cc4b35,5162ed91,7a8e64d4,9f827631,579421ad,3c7f7ea1,f4866432,a341f955,6741c521,c757addf) +,S(8fc84331,a8f8dffe,28f30d71,b39c105a,ec09aca,4876241c,1c81a223,a1953637,aac7257a,cf0fce3a,ff8fc7ea,e8d19606,2ba6d7ad,9b7987bc,35a92b9b,20360174) +,S(b43ca4ce,f1b4a2d0,1a20fc64,2f3e1456,317f729a,1ee69798,4ed88bfc,1c5a2908,39ae1e51,f352c0c9,8a79cca6,cc859eb7,92bad6ae,5318f99d,d62d3bd4,d8fedad5) +,S(7f29c501,75628aee,5d39db41,cc4d89a6,9f133f00,47500f6b,aa7a90cf,e13159d2,cf17c6f2,f6072b50,257f722b,5756d8ad,c7486cc1,d21a925e,8cd29a15,4b514cd1) +,S(3fb93959,55ea2522,61b0488,212e15d6,b28e975e,5ff5f357,15337538,247f2a54,7c3db409,e06d6980,d834639f,e9e357bf,e6a4e9b0,ae6b4fb8,f5e45143,ff625ddd) +,S(945ad871,18199665,a4078a46,a9596bd3,ec7cab84,b6323a0,7ceefc63,d7ba29f5,6eb6d896,a24d02c0,630c909e,65d13d4c,2eacf1ef,6e600b89,1b171594,aa28c206) +,S(513bfa93,57c827c1,b3c0289b,c4ce443b,cadfbef0,b28b32a9,265ab85e,67efaf4d,645c5b3f,d45030f,1aaea514,baba7069,91def89b,56fdc292,4b684241,6653b6d2) +,S(d41b35bd,421ef7bb,1c03c794,477c2851,dee92831,714180e6,6e57e735,caba5835,beea2116,9cf971a5,ffd83596,d9bd77eb,cb1e0c7d,506a45ae,be8c0c7c,22738f9d) +,S(96006d64,fac8f0de,88f93e05,da8e76e6,40afc1b2,8ee09a7d,5633643b,d89ee3e7,1404173d,e96a97e9,ae9bcad5,c9093d05,cba96479,30bfe6d1,96664d0b,13c93618) +,S(ad528227,12257f87,d1ef82c4,4af5f046,648c2a72,497651bc,2327e971,1170e7bb,2ea908a6,c742f542,324be959,4746ee48,4229d497,cc8bd535,e7989525,aa36f079) +,S(b4709a81,c067f6e3,93ef97ab,c26675da,6f01a2f7,e3f35275,e7089ea8,ad5644d6,f655b89b,d6a83838,ffd23f6a,fb944bc0,57fe7f1,1d321a0d,2152568d,91751d99) +,S(3b7bc8ac,5ba85b40,2080612a,84e0226f,3b43c8de,c0e54b6e,ea779b76,812782f0,8405dedc,a02825f3,5a60333f,190001fd,98ea3995,9dc6e61,c28c5e2e,5213fb0e) +,S(2a76b67,d197e7a3,7a38bb10,d49d523d,c4beb4a3,75336974,7e22e407,9e0310ca,6331389f,b9cf9fee,e89b089a,95abca6b,a3c2aba5,38725c1a,6848fa46,997d0e87) +,S(9938e808,77c2baa4,53e0256e,d250439d,b11732de,1abf7555,949a7574,f62819e3,250b061f,bba0faa4,468a080a,fee8264c,f72fc12f,2ac91dd7,13ed92a1,1b281124) +,S(7366eac0,7e5e4573,333291,3e42f111,e53a78a6,5069898,52db2355,de089230,b8dfda33,31646343,bfb60b2f,25050967,e735861e,1654f0f7,ff42ed9,5dd652a4) +,S(10fc632c,cab22fd3,2583599a,a2efaaf1,6e1b01e6,a5a96c59,50871012,33022152,cf53d9ec,c74aef44,7019150f,ddfde494,c2382a07,b2dfd73b,c628478f,7fbae0eb) +,S(785f4da0,240de52d,bb50b1bd,bc53994a,47318076,9a1fe06e,5a40a8e,e677ce63,9b5759d2,f77bbb9,e40ac169,a01500ca,6dd6bd70,6a003871,e7ba4d66,b32db9e6) +,S(a7f20615,593850c3,27aaa06f,c03e0d46,d3ff20a0,9b849810,1759638d,8cbb9cf,13b9ebb6,f0cd59ef,54e0f935,87a14fe1,2337e346,94f5e8f1,10323fbd,d7604d3c) +,S(cf083e4f,e0ed4444,85dbd99d,8e6823bb,483eb749,b94ce672,8671de8,6105aa4a,36eaa305,37378494,17050dc2,8290c74d,d9ff9df4,cbfa434a,2b89de00,e06f3099) +,S(9fb8c370,bca485d1,dcadc251,ee906f58,6f3e177,be37baec,6912e535,f5c7ab0a,df5cf77e,1ad07532,7150136e,7ebe7f35,1db47415,74444b24,e9cf2f4f,31ec683c) +,S(ff9e2f29,170dd456,2c94d48c,eeb0390d,db783702,c13574f,8a8c6a79,6427adca,784c7b68,3c824603,5077911f,957aa33b,47534180,d70a60d9,f248b860,736a24c2) +,S(802343c3,e07f9f9d,ed2ca436,3e455427,367b852c,d23ffd7f,fd690eab,90b4162a,b093f0c5,f0fc7d01,a5dfb7f6,bf9d90d8,8595140a,a13fbfc0,f7d6af2f,54ff5ce0) +,S(ae74ed87,11a1a684,9e558e05,47ff8f9b,f6337551,1dd3d272,ee0597fb,fc2d6914,c304897c,e5afb5b9,a383cb64,e85071a3,cfbb2981,93ea6ce0,55257ba4,cf15bec6) +,S(c099b05a,dceb601a,14892c97,7b267152,f29ea71e,fed6090e,7267249e,43c2390f,6c3ad3eb,8c95c72f,e0030a7d,34329945,fd1eb71d,8c4aa1f9,8fa4656c,6bef067f) +,S(97c6949,a25581f5,945814e9,9d590dff,67d936d5,94101005,4cac33d0,fb3658a5,cdc7faad,5bc387ce,a16a10f6,6971e5ee,6d32756b,596adc14,57081ad4,1dbd2e4e) +,S(14a19edc,a1ec89e9,524548ef,cf3dbc03,81b14b46,928f7425,87b11df1,7aa721f7,f83c4d0,aca08709,63a017b6,8db3434d,6088015c,2ff1d8bd,739fd620,35d1a19e) +,S(4742af63,c7597424,e6d04a8c,cb43142c,54c5b350,175bf5a7,27c39820,2187d00e,bb1f2f72,b21e15f,ec17af32,2147edfe,1ca80ac8,3e030dfe,8be39fdd,f340c56d) +,S(a6597869,4d168b00,d9df41de,fcd48ae9,68313394,db683407,330ffae9,f2559a11,6bf65c42,13317a5d,fb561e8c,872c8b1b,90bdabc8,8a8d2e1e,39919f8e,5043ced3) +,S(9e62e468,1e22abde,4d7a2fa1,2f7867f6,ecbfc15b,54990e26,821a8cde,fed76985,4877297b,a64fa8ed,c039ab1a,e62ac72d,8d7bbf05,7513d1,4237b8dd,9f1acd37) +,S(d24333b4,de55b0f5,d47c72e4,88cee8ee,8c960903,260a64d2,c89bca45,db7352c5,688b20b0,617ac12d,5be38fa2,ab52e785,69766a83,2d8b44d5,cfd6ee88,b19b9f1d) +,S(d203301a,13d1c8ae,a8c79007,1ef8116c,3916bb3e,dd5110a7,304b9145,465be838,a606dcea,398dc313,e61c8fbb,dbbc3874,3c103297,164e66a1,4412a21a,5319e55c) +,S(d1aa98ab,7010146f,16a9d6b,cd911535,2595bfa5,1bccb3d5,5e3a4a87,62666610,3abafa4,999294e8,80e3fae9,edb4206b,9b9786d,bddcaec,e2d01cf1,ab715690) +,S(1e20823e,81051b2,65535085,9aefed6,3631dbe,23b4e79,abd3c17c,21f053f4,e238adb6,86592008,f7fe34b9,9b934060,15c323ec,55981b27,85feae6e,5fde7186) +,S(d878afb8,8527a861,4b4276d8,fba39300,72196017,6f437014,980b7bbf,d4320ffc,7403107b,fca8ac64,baa94a4b,128e72ee,4a015675,845519ba,d5609331,1680e7) +,S(53f86d45,61deef96,ca88a685,38fd35ec,a95740a4,3a52c601,faaad0c2,aa3ab72f,667a6ece,bfb97682,c5e9e5df,b6d29156,9604f63,d9ab00ab,8cb10000,e6b01514) +,S(20990660,f1055420,b885fb0a,38824740,3b141c37,5aa20dce,8a29191a,e77bbb16,7d434476,9e302e38,9e14c02e,f5fd8a5c,64cfcf3d,e9813f1c,f53bc6d3,4da93559) +,S(1e70619c,381a6adc,e5d925e0,c9c74f97,3c02ff64,ff2662d7,34efc485,d2bce895,c923f771,f543ffed,42935c28,8474aaaf,80a46ad4,3c579ce0,bb5e663d,668b24b3) +#endif +}; +const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)] = { + S(8f68b9d2,f63b5f33,9239c1ad,981f162e,e88c5678,723ea335,1b7b444c,9ec4c0da,662a9f2d,ba063986,de1d90c2,b6be215d,bbea2cfe,95510bfd,f23cbf79,501fff82) +#if WINDOW_G > 2 +,S(38381dbe,2e509f22,8ba93363,f2451f08,fd845cb3,51d954be,18e2b8ed,d23809fa,e4a32d0a,fb917dc,b09405a5,520eb1cc,3681fccb,32d8f24d,bd707518,331fed52) +#endif +#if WINDOW_G > 3 +,S(49262724,e4372ae6,f6921b82,aa4699a1,f186aea5,40122630,3ea42648,97c2a310,1337e773,bca7abf9,5a2cfa56,9714303b,6d163612,a75ff8ce,c41b681,5e27ded0) +,S(e306568c,1a240c90,d5e253b3,e477e2f8,4dcc1a56,ff06db8d,1384b079,cebd2d31,eac6fe3,78934260,888f2b10,7f7d0db6,ffbc8042,be373826,692b4083,92546e44) +#endif +#if WINDOW_G > 4 +,S(3b9e100e,2428cefc,271b0e76,23fbd633,74ebf8d9,aab41dd9,c530c39e,363136b0,fafb9815,2d16bb71,df1533eb,8f475b26,a2ae28a3,3ad31f81,953ec16f,6cdbbc8a) +,S(bb0aad49,712ac9a9,2b76ca80,f5dedef7,17ca0768,8107beee,9608f047,2f485d3f,ea699c53,c5835479,8ecd201f,7297da34,895a5afa,31670bff,e7939250,3ca2f975) +,S(79090ac8,e4eefcc0,d4e8eb19,7afe0113,e1e58b4d,b01123de,4aeed33a,36718dc9,eaab722b,91905b8f,13d816cb,cd9aaa56,dd36afb7,ba9008b,963322b1,1cfae7c5) +,S(e77c81ad,e9f97b55,1c03dbbc,e549ba66,8dd71de7,cd775ad2,a269694c,7f60c7d1,3acf1478,eef81321,c5fc3b32,3ea81543,631470f7,1c2986d3,4ec581f2,82d72449) +#endif +#if WINDOW_G > 5 +,S(de2b5ce9,dbce511c,f2d8878e,3ded87cc,3d633dae,a2d45341,501fb3a4,55ccf6b0,f10576f3,d3c3e0e1,bbf717e9,8b1a3744,65b8c45a,c66318bb,34829eb7,11100666) +,S(d07bddff,d491a2fe,1ea59fbd,7c121217,29659ca5,de46658b,26b1460b,13c03c56,b2ad4708,cd3c97dd,f9c40e2,a1de04d5,61d963ff,8cc2eea7,6be3f60c,2b405ce7) +,S(82403e7c,5d3016af,3765ec4c,396ce8e1,f8da45c,434b8257,10edab41,bb6a4d51,d09661b,e27cb767,4456badd,b3e84051,99ab6ccc,4ec67c1b,11e92ead,7b463b19) +,S(eadc3131,fbd626f5,263faa58,c4caf4d9,930f933d,9541c23f,438cb486,750680cf,d3c977b1,c9b4a897,5c64b36c,972d5d01,a388fb9d,c3791a74,36094ff1,2c87a914) +,S(3903ee5f,6758ff24,c518a4b3,86748f4f,36bdd65c,b77e78ac,609f2909,fc7987d9,e92194e,a15241d6,40915934,bd234749,8d222a18,4927a8da,b0cfe2ae,182be83b) +,S(d0803b78,39ab48a3,8475bdcc,f9a9f219,5759c343,dbbf8e93,23e1f882,5be6a5d9,2cc3b180,ff29c97e,a12ec15f,b38bafa4,4ecf06c,e51d1d24,2894a926,64582f0b) +,S(1f56f096,b18a7499,a153a5ae,acf8be05,8496dd23,da8e6c19,215628fb,c0567ed0,fef22b8a,3b52f490,83004436,b65cd69,c94189f4,1a93c0d5,1fc13cb4,379dff58) +,S(1d9f69b1,a4a47432,e386f525,234aa30,79e947cf,cf203297,4e0fc05b,638e213b,d898ec17,949c0761,b38500c3,a2b1da24,5438d5b3,d3f6f720,41f15d6e,e4d4ccbb) +#endif +#if WINDOW_G > 6 +,S(128c913,4d9dcb78,12fc4361,5c67ad0,55213354,dc8008b1,aeb5a9dc,fb629efd,fee3e54a,dd152610,d9725936,99d662,c160c8e4,ec6f76e4,5ff41818,be67c96) +,S(21ec012f,5a95b94d,244b8d51,9756075c,301f2854,8e2c51fc,49c0e3d9,d1a9685,2def2105,77af497f,4c7fef71,6949f28e,7418eda6,fd5fc162,d128de19,3cde08ae) +,S(688f5202,fb9d8bc0,9e480e89,4c7cfc74,761c3be7,7dafb11c,58422836,3e331cc5,96ba7d59,63b541a7,2ec7cabd,92403434,1a393eaf,89eebd94,62d9c218,c7302cd3) +,S(fb5c9eea,1cb9a8f5,b3314c30,a50d35,744d0ef,e8bbf68,2e4d3ab4,f7f02baf,29fb8844,e18fc551,fb28bd26,95c5e95c,6868e0cc,7e526af0,91157e9d,fb630418) +,S(f1479fe2,2eedae3f,2f5f6a5d,84a9de1d,593168ec,7b52380d,e0b3625c,cac03421,1a642d5d,2fd88b82,13b50d1a,3fbd3419,c0b4630c,48352131,cb856b2e,22764606) +,S(2273edc5,e8199774,93c5b0e0,9fe0effa,f60f7b,2898565a,69f5c7b2,bf1a7950,b3aea238,8fd978d9,29f1a1df,98495358,b64691fc,4f50b530,906ae39e,fe7bda12) +,S(99f8480c,30504378,b47d10b3,2b39da2f,496d59f4,b1462856,56f05ad7,9bef5214,e001d55d,8e224286,8d8bd397,cb5aa99e,d930e437,e4e62151,71da7ae6,6264b2cd) +,S(382257f,e4751280,d74fdfc6,993c8642,9c000d5,87f57635,bc9656ba,996a6f1f,c2dc733d,fe52cb06,265a4f1d,a6b5f1f9,30dbfa39,e3659973,1c672aad,8b51d474) +,S(23a13632,9125386b,e45f4e1b,2acc847a,62e5eaf9,f6d5f452,6e145e7f,ecefb24b,9129777e,643ba22,2bf817a1,af7155f1,413cc370,3734ba6f,49f15f55,996854c0) +,S(6659ea60,58a664de,a35791a1,8c5cded4,8cf5593d,c440b9d4,8a30ac35,79149f0b,2adcc705,a85d836f,b347b69e,742fc6c3,5300d1d8,e534f1ff,c820c6d6,b2f2199d) +,S(52dc3bc6,e1acd3b4,7ece6f6c,89fd2a3e,2899b487,41421033,37a67dd,1ba939fc,5daeb346,32ad107f,bd83d9da,15a3c4ff,1e8f6ba3,ee5193e2,709e89c3,43d05746) +,S(524b2a97,93cd5745,bd9189ba,9c947bc1,693fbceb,75f074f6,17376b10,d5573551,9e8099d6,cb23fb1a,9deb92cc,3e8a2fb5,a6865ac6,3dececa0,2d146e1b,bcc80b71) +,S(732181a8,e2bc5953,923e6c3d,d960e9b7,525b7b95,e5906997,6fe79156,1782756e,2516c6b3,5592eb0a,42ba193c,bae98ab,e3c42d96,148f1d84,edac621a,722e4823) +,S(b8e8942d,926e38fd,f338496a,c2ef6fca,49a7ae3d,f76eb15d,8d570111,e502664b,7990d56e,7dea588e,4d670ba2,2031e6c7,97248641,69e51d77,f792f5ed,befaf8eb) +,S(144e88f6,3e73abff,72cac11e,7ddccf79,19e744e6,278941ae,18d1b797,e098e4e5,63cdbf3,5df3c655,c58197f,ea54633d,158705cf,7dc2eb3b,4e09f83c,3021837c) +,S(9436e3dc,489ecd8e,2d16a739,c9c73e3d,60e5bc93,68157039,75b8efbd,5c3a9081,1460531f,50cb6ebf,d1aa7806,ea84e7f7,8e8d76b2,b3a66d5e,3a0bf60,39a7e59c) +#endif +#if WINDOW_G > 7 +,S(9d3c2561,7a56d10b,46d9b01a,1710d193,e840e005,df669e76,1936c275,20890db9,6bbdc0bc,4c4ae9bc,c2dfee9b,82da9b94,1f89ffcd,e8af2aca,4467ce3,78521ea3) +,S(29f98e50,f51b7f8b,e18c6ae0,b453c4f2,d0aca5a8,b0e61d2d,dda8506,3fdb76c8,daf3bcdc,ae8e031c,73eb8b21,14058063,58a6ec30,ad379186,df80e3c7,f0e5d28f) +,S(d67d30c2,c71daa36,1805e31,1dd6046e,17a89752,94d76e1a,538af074,4dc22c94,48b9b0e7,12c807b0,b92e690a,a2e068cc,e87ebbbe,aaf4bd96,9c1114bb,a54f670c) +,S(f22c2ba8,8ce9c2e4,b772c9b7,6d03a017,59aa7b9,97a78334,83566027,2fc81649,6aa9e710,f190be16,243a4e0f,1570270a,2d92dca9,8cf99a3,cbc06fdd,f9b7028f) +,S(c5e718d,6b94c83,e52533c9,ef3234f,36b722ed,cfc074a5,eff30969,9ac5f894,24961051,ccfc6619,dd64e810,fa9c504b,f7f8ce9e,cc445d7e,642b3166,eeef436) +,S(26a8bcaa,c836eb7d,57618999,ef87ee4e,c291dc8b,333554a2,c1f66f73,7944d611,c20051ba,7236663,ace2da29,c1e0763c,e57192d0,e199e7a6,c69cc65d,bbbcecc9) +,S(388e3570,fb7b1545,9bf01ba1,7a6496d5,6bcf65e1,764e7aa,2c083346,2dfa098c,2d4e0d22,a2eb0ff0,545561e5,ae344be6,99120d12,45db6bde,a9500f5f,a07be798) +,S(68189bab,b5a0783e,23227efa,4eab2c6e,da2d1c,2ea57fca,7a7f8f72,15250709,bd30bd83,3694d3fa,a14954f6,251445f8,3e42d517,30d30855,a0eb834d,3c7ae856) +,S(642e0823,bb347795,967b7aa9,418a25,ea6ff683,fd7b3d42,b88d90d1,292190ab,db73dea7,86ec052f,e3674892,639daf39,286b4690,63b68903,210639c7,f3b4000f) +,S(9ab6ea81,e5bf5505,751addea,5896afab,7f4eff2f,d3986027,f916835c,64924afa,38c06aa7,4870a5e7,2ff29efc,bce4b3e7,dd951c9b,29966f2b,47d007ac,7629bb6c) +,S(b09805ae,e567f69c,71a98248,e89e64f9,e059e015,bde01a62,dd18158e,e94a8ee7,62aea16a,7ec912ef,cc5382eb,6d220ac3,dea885a8,e3da12c,8147b28e,1983d221) +,S(3d632a5b,636ed5a3,4a58bfbc,9831691a,91d6b5f0,975bfb5a,82b4c1bc,107e6e5,577a449e,75bf16d9,2eb6ba0f,9cb4d496,7a7ee09c,f1605aef,682cfa31,cf395a1c) +,S(6b821bf0,f70d5ff2,ceedb69d,d96ac8bb,b51e3635,3a36d50a,b1c1a697,40cef707,5212ce11,993fc120,88028674,5cddea94,6371b4,dfa2f47a,6d83b789,c6d12e5d) +,S(bf294951,4496fe0b,8527740b,5cd9394e,dc33b330,c91d996c,789db854,45728b23,790aede5,da35ce7a,343f745c,410de38f,4c53bc2a,bb41bbae,c13272b1,e912782c) +,S(a55354c3,82bf968a,16668267,c4498946,4906f69b,114f6f06,742b6035,1d75ec80,2809bddc,45661a5f,28b31967,6cdfb5b1,9dd6d296,d1828c88,179a630c,ca5962e8) +,S(fc015036,abcd8311,bbfa1574,ffb4980f,b893f8af,84f519f4,5a6fa344,2649a693,d0f6a278,1946e04b,385cd004,29acd3f6,f5542aca,3e7c789,657f676b,f19db819) +,S(6164410d,9f81f352,272a799f,b4afbe24,59caea6c,511fa4ea,b7578980,d9a7aae,92bc1480,ba19fcd,3cbee69c,95b9396f,4982fff5,d4e7dac0,abec7153,ee5a7966) +,S(ef816535,8de9d737,728f9a9b,3182b4f5,6e25917d,1ec05fc6,faa0fc85,170b5f2d,dc372426,403ca9c4,50649df8,8b6fd32d,f1721dc,cb1c7d7e,155c83ea,747ec595) +,S(428c34b9,89a436dd,dc704e68,170d2c40,178c5646,841eb2e2,642c0a48,8987a8ed,b1f24158,251c4646,ca04dc3e,64369634,3836f97e,71945f4f,51237abd,3aeebe06) +,S(6eb61782,f909157b,415e6243,7bebbd6a,5f19da73,7eda64a5,5acfe206,65417a9e,4fe7c546,baedf2b1,6c92f168,f99c42f6,af03edee,290ecc39,4c4efff,e8577b72) +,S(992e0af1,466d4fec,5ef83009,98ce31df,cb6f9573,d14c1646,e4371c62,a376fa4b,d0e3da69,1e4396b2,eb01e3a9,964365,50d000e6,31d79ae3,871690d5,29f9e825) +,S(fedb564b,adc70078,f20f31d1,12496934,513e9903,8cf5b9c3,1084383,5721d11,1a8e2a49,57e8420c,f2d5d97d,657f1602,ba26ae87,d5408b2f,a9448def,38157a39) +,S(f3f2068a,4dd89d18,1247088d,3c424916,3e683226,6274b575,e54430d0,73b24bd,f2aabd19,a7f462,1426ab1e,e0aa7e33,12381c5f,e1f1cf0e,75c1a7f7,7ba2bfa8) +,S(32b9225e,4217a359,8de4e7c1,476a8581,5b6aa458,d93dae02,b3d30772,3ca13680,7466e804,26856340,12985683,dd071e97,53246214,733808a3,96f35d0e,5a133802) +,S(85008a87,385ed6b0,4ff89979,2eb592f9,ee6c6b93,fa24dc7f,c6299b9f,dae64a8a,1f279e2b,8a5b0576,fb9569f6,c0825876,84b5b38f,a250e362,2ae6e284,a504a2df) +,S(4dac7833,ebbeab0b,ec8edac7,cfc49bfd,b835362,f0130e9,e44452f6,a82effd4,fc9d1970,f230aa68,6114ada5,7b4237dd,133dc3b5,db8ec1f0,ccd09aa,23c740a) +,S(9b755881,45a65d54,19b40226,e535df5b,4b44de41,1b93d71,31f3102,d56dbeeb,d0324171,d6937b7,c9b38290,7dbba3b5,c1516061,59e7ce1f,a1ed9d11,e089a02d) +,S(1bd6ceb9,2592a7d7,a66e6e8b,1b645db5,98b525ca,461dc4bd,b583ed9a,cbbc8bdd,9a59de87,84a98bea,48b7abb1,a5b7055,5a1c4ce5,551cde4e,7b790ac4,9a29944c) +,S(25a8b2b9,3b360941,6525b08a,7fe786e9,6b3a3c7d,8b444637,268f5355,bd5b56ee,3c58ccf7,5734687f,dbd027e6,3ec6c550,45f131ae,df71a40a,c45e4e8b,965f22ec) +,S(244b2833,27c33efb,221a5767,15225d6a,bf5a1caa,8da543c0,d88b21e5,17ed9f5f,220036ac,e48d8953,5aecec92,a29f5012,37f83ce6,44380db,c229f0bf,c1f53d7d) +,S(6f97ac0f,27b87905,6b442d13,e566978e,91f0cc1d,d6ac1e64,e9764a35,325dd1b7,83c6e70c,fac6c707,226ce1cc,691b38a0,7e937f5a,5f2d9c81,4dd0d3ff,9f433d32) +,S(72c5d60f,eb014e2d,ba8265ca,d454f261,2d6abcd4,b2236bad,c94c4801,561dce1f,e3119a19,7ef91963,b3b28216,3c5d3acb,97b281b6,d246cbf0,690b40da,63978fe2) +#endif +#if WINDOW_G > 8 +,S(a96d2da0,1b10186,6998659d,f441a1b0,2af32b94,aae8c6ea,707d9ed0,d5f33825,660d7d83,5da5235,9f7cfd41,28c370aa,5659ea71,16a91690,6c0e8108,a513f9f) +,S(2cce6f63,4d815ecc,1981d200,87616677,d906aa27,990c4875,17314dc5,5be3c4fa,615210dd,bd599e91,1b6f997a,fd05475,b33cb274,c9ecb6e5,d3c23323,beba4b50) +,S(992b0084,525dd399,d98602d9,8b8d53b2,4558fafc,758a2f46,60e89bd6,a645f0c4,83ca98d2,26545a29,8c45f40b,11420602,f5a5c70e,595eea57,2da64d61,a4e2f98d) +,S(434efb45,3089619f,cc761ee4,3fd4b77d,c6b0c69e,b45eb88e,44ef766e,9beb7357,3dbb0d6d,1c0b92e,5965586d,236c0be9,26967ac8,830b9bd0,1e9efc2,2a9291ea) +,S(a2179ad,2c683306,a2e4735,93efe304,f0dbf589,c4dc2b88,4bddc5c7,e3fbc156,ee4539f8,ab980176,a18e6dfa,bdb609d2,88a2d223,86dcb20,19207afa,f6033c1f) +,S(3934081e,d3e1e147,aa52bb40,9221ef6,a445f22a,66718f14,6d63907a,ef05a2e1,bc370656,31391b7a,209e79d4,9f1e959b,d3a9fefe,752c6062,14fab290,a7b5b3c7) +,S(35bc24e1,59a2b939,438354,6cc4255f,f1f3f7e2,105293db,39688e07,df95d8ef,dee1fc70,a9698da,f7abeb5c,56724f8,e87e0cd3,8849edfa,246ed0a8,9223ae15) +,S(f5d1e75c,251fb473,8552a0ee,f05d8e65,63aa14e1,bcae5b48,bc7e5258,b948127d,e260c1bc,7044f058,8f409134,d298528b,e7d586f4,bf7b6fe,92d212a8,6f7170fe) +,S(ee0a76d3,6fed282f,a1170dd,6acb7743,f9617bb3,60350f54,d12da1cc,7eb121c,f8cfc2db,eba6960f,e6135ef,ff9e10ca,4e56c458,4b42b516,6dbf7af1,420ba5b1) +,S(9e3b87cf,78927664,15cab377,f1774d14,4d1879f6,16da5676,f94790d1,9ca689d8,f8f34522,da3ca2ac,b273b0c2,b1b1f26a,7a9c2d96,b4547482,266a8e6d,bab3b577) +,S(e26f256f,d08942c0,3c85b89e,e66b8b50,12f409c7,4f625152,86e5b310,eb4868f0,bab3c4d9,6fea49fa,6d08c656,23c9b127,3552c23f,3c4f12f2,1bbe8bfb,56f210f9) +,S(8ac74046,a5d38398,d14b6763,4f07abc5,a3f5c852,ea8c421c,f0858980,11da6c2,d20ca793,f56e3198,854f5916,35402c2,4a71af95,c84288e,1495d324,7229b3dc) +,S(5b00e095,634694cc,93d531a8,6e81d29e,753928bf,b2c83a83,ac677a92,55932bd0,8d2f267a,8071c48c,616daf18,d587e,42882b33,748032d6,4bc3efd6,60a99656) +,S(162190c4,80c5d7b,ab1ae4ba,7b2a6611,546ffb9a,b4e9ea87,2c0357f8,9e11f0b1,db5e2104,12448a9c,e586d7a3,13bdcc6d,bb84192e,98c5d9d8,79693030,92423525) +,S(f6a84421,b4b383e8,87f8520,e06017db,476774dc,9aff636c,f26a676c,85b145b1,504c71a9,596770ed,7a2da8,2e8fe1ee,93717215,bf88e0a8,ed74a80,4037a3b3) +,S(1f02d142,f0b5d3d8,b3f8937d,a49f908d,83e5919e,55c9c134,55a759a9,932dd6e5,e6a5cb33,8ed36df7,50ec2eae,5db7c9ff,fbc9035f,48ae0348,fb3882da,39863e65) +,S(61f4d96b,c326a1fe,a2ae38c3,73484a56,68e29bf5,12d77a04,34a62278,1d78899f,651ef738,62005ac7,64f97021,6180c25e,2172724b,375e6b38,b3a37ad2,d7b4aab8) +,S(ba7d5c0d,623c5e79,8088a71f,8d2916e0,7c7ebe2b,1afa19c1,9c917cae,31c11616,da409f40,d7e3f6c,78655153,fb35595,a1ec37e7,e66c8958,ce45b07d,bd5f5a51) +,S(8b90a590,eacb977c,6e6a68ee,6dbc3e19,fe5a92a6,9abc43c3,bb16f9d1,925bdb09,a5cf5f42,ef655d59,ae734e1,f746a752,4d01ef75,d829b9a9,2a035180,fb5df718) +,S(87f35227,21914cfd,ce8294a3,cb5ae171,f0d994ff,f55b25b7,1c9e9aac,dff4fe4c,cc71d1af,530bc5e1,eae7c1ef,b9a91335,f26b283f,222a3552,dda24c28,64babb2f) +,S(aeea4d36,ba405159,bf0ffe8a,5530f1f3,83d5509f,187ef58b,6c1eee4a,cb77a15d,db563dea,e7403df8,7d3031c2,48aaa28d,96958f7d,ce36b3f7,8d55607a,60d3ac1a) +,S(300fe98d,3996eb9d,57c6f1ef,8058d4c,d8dda436,5774edb6,2a338a59,afcc7111,d148a017,8fdda40c,f937913c,143b76fd,d2e6e226,d27225e3,a49658b2,38c40e77) +,S(c700af5e,22cd146e,839095a1,f6743e4f,d01e9c1b,76d4c73a,a5005f42,99c19fdb,3fe00181,b1f01c27,27ab1fc6,bb6ea569,d4a3092,c2d511d2,8b5546aa,194b32c0) +,S(d03d08e1,17b94138,1aa147af,38448539,94228f75,f96bb4a5,941c3748,cf50bc60,5b119ffd,2785bcc5,2e0bfbfd,c541da8d,f47dd076,e91440fa,10e071b3,a896e31d) +,S(6c6710fa,17a520b8,56d7fadb,6af81a5f,ea9c983e,c94cf832,b395da5f,c22bd361,db4efd26,36e281ea,419964f3,c0897b05,b036a408,25ed4ad6,4fba393c,f2804941) +,S(d7b5c239,9df47a16,6b6cb900,d08a5d9a,5ea3bfe9,94f861d9,b46f3fbd,a3d91bbb,ed791f4e,4ab1c25e,9c83494d,794ffe1f,a3c8a065,29c0b710,cffd597d,64efe8ba) +,S(90f699ab,8f728152,e2deb8dc,ceaaa3ee,53ff2f23,2341a952,4aba9e8e,50f66c06,8bd0c3a7,7f5312bb,9d46d80e,c36921f8,561558ce,6e63c08e,641c82c9,fefce91d) +,S(4d0eae3e,3d7adc34,c91eaead,6a16f569,37557dce,2b68744a,bb9ae71a,8dfb65cc,816b0806,a9508731,ba99a685,142aa52e,6e874c99,5096a53,52c6e2f2,1fa3de5a) +,S(46cd9edd,ec318498,dfb4f815,3315185d,689a2399,8e06b1d0,2438f7c9,b2f7de62,3b5bc1a3,d5fd7874,8c964a8b,b813388b,e0d5d168,1247d008,10a846fa,561f29bc) +,S(4aac80e,3f6eaab7,1c576297,b4552e40,653748fe,21a580ae,bce4eb83,2ff730b,3d42a00d,8014f46a,80fe2dd5,bac6a046,40d331a9,4f1de050,9e435398,6c8c7954) +,S(59bea661,b73d9c09,131e4573,199937a,e03e96f6,2ecbc637,4bb681a5,582a4114,31a20be8,ee8a2c2e,81d062e7,8e891504,d9f2639a,bd5db5c1,30be3d2c,b1afa47d) +,S(7fe9065,88b2ee92,2b19acd3,fec7a4de,9ee089a4,a4e1c338,5e293567,90ca6037,dfb45d90,c5f43eeb,1f5eb326,20763ff4,2659b763,e7ec72a7,c69e9369,35e5c128) +,S(db390f91,32277889,784b5e4a,cf8f2fd1,f3a5fc47,f2c8262f,19dc9518,95322157,4364955b,241c831f,94fd7d4,da63db19,2aaeb5c0,ade82dc8,d5d61cac,d690bbad) +,S(34dd0266,e5fc19ac,7daa9e61,5ae8f78c,985732a6,1c53c29,e6e5d407,7391ebc8,c2d6b6d8,e73fe00,e6013b1d,2c2b48bc,77a5db6b,45232ddb,6611ea1f,c5dd797b) +,S(eea7f72b,7e31608d,d3dfcfbe,16e2ef95,5e6c7ec5,328f84db,336e3df1,9d1772ab,9662c8f1,ccdea4c3,48ea6d94,739aa747,17219556,c6be9b8,8af0d30d,514004bb) +,S(c6af087a,f1b10eb3,93de412d,de856129,9376d264,36d907fc,10d3e7a3,88c391f2,ba99d62e,31856457,8ad8847a,9cfeaba5,e5ff9824,2c614959,eeeb4ae7,50825144) +,S(eae34735,6c715740,ab73d034,bcb43f5a,aff37fbf,50d35518,1364c999,feccefc7,b9386c75,da8bf645,cd6f15d8,4944f74b,9685256d,b61fda98,79fe6639,92fe4703) +,S(4a548c25,f4d8f54,4f9a27e,64e49626,41b68ae3,1d90461,65c24ff7,fb40438f,ae9f2c85,bd608cf6,ef5e40c6,7e29a63d,4c274215,c2a0d578,38252f28,196f6d10) +,S(61925679,dd6545a8,ea19743d,7cb3c0bf,453318d9,e180da53,f43af2b0,ecf744af,a0682d84,d7215372,e9ec062c,a3e4aa1f,47fc551d,44e3d1a1,7260a44f,2bcb184d) +,S(e1db5e86,9574ab76,d4fa260d,2425ef62,50267ab8,52ff04fe,25f0150,9137ea2a,c8eaf421,9fd5f7a3,6c1a99a1,d0c61250,836e204b,fb496774,83f43c81,511905a8) +,S(3062cbca,73923842,2a0ab862,a1fd84f0,38e63691,cfc204a7,d2f9d263,d248c7f1,8f112e57,e3f2970,dce89eee,1e184310,721a85f1,cc9feb2c,f55c047f,dd9670cb) +,S(67c393cc,aa9736fc,eec7a861,eb53f953,9da74ff2,97764f4e,4e814004,4da4f739,93d329d0,9a165fe2,2f8009d5,ad59b524,33ac24d5,46c7d394,2d147c4d,49853203) +,S(c67471f2,36cf2187,ee5a5619,d581cc7d,ac5bc5b1,e8bb728,f943084f,e899bf5e,75c90c9c,787b318d,943c3247,74cbbcc8,3a533f37,fb684aea,62fe6848,8de2c513) +,S(d5015fef,d5938dd9,2133d7a4,25aaac5,12143acc,6547070,1827e98a,e4ed1b52,44305616,a02236f1,5c37c0d6,51d845dc,e9966860,b798f79f,4006c25d,7cf03d6b) +,S(aebcbf65,aaa89615,cb48ed56,4002ed9a,243ca309,1cf503b7,3c1929ce,8164f2d2,4fc1f25d,1a30ee2b,4220305b,a9c88e86,a6ee7f55,55399ee5,35e7d37f,e4b3f019) +,S(15cb1617,1727deef,49ad6821,932a39d1,bb8f980b,b5370d81,5ef00ff,ebb30e43,64ad8c82,87fc053f,ee35c1b9,9734b34d,2dfff86b,490ead93,b1fe7d2b,f80ebd7a) +,S(d404209e,8530d674,9bb88a5,525211a1,19fb2523,63e2698,6bd03080,4c49c123,3763fd68,fdb85d19,e8506275,3b5a327c,46ef87be,8a3432c5,62bcc622,40a7a128) +,S(f3abf8cf,c232849,58e330c2,fc327ac4,d40b4497,f422aa4e,d42e9381,9bffdd96,50861f05,d831327c,3e907643,2d7a7621,d1dfe9ec,7ccf2061,cc720e9a,7d5b0d5d) +,S(78a32893,2ee9dbfb,3f84755a,651b9d23,5cf92b46,c3e4bb4e,57b7ff6f,7c874dea,925b783a,966721f4,6eaccd87,495eab7d,b3c36eb2,92c1a473,b4617f6b,9ac85895) +,S(8165210f,5d146f8a,1ac1ed91,a7bb678d,1b7d15e4,3ed55e8d,f6503209,a750cd4a,fe390d3a,19e22bdc,cbd45875,e396c713,85954166,a1edb63a,384b8587,915d260d) +,S(75269de8,6c2f3d34,cdf17dd6,f3efa198,ba73431f,cf0072f3,633ca57f,7dfe3f09,b162a65f,d19927ec,4446e3db,d5ee8850,f463f39f,1df1a0b1,f5ed153e,704805bd) +,S(5e36ce8f,b393949e,5b9c4e10,44fb2ff7,c520a7b7,a9016b38,9544e512,427145b0,7c40e718,292f96a4,1d9822ce,d54aea90,22074c5c,c82ba4e,7d39a4e0,7811614c) +,S(c8cc7129,fdebbfc6,c0576edc,6ac983e5,c249d360,76da7d25,b05c0b6b,16632746,48a8cce3,a77e4498,76d1a332,c539feba,2653fbaf,d4f75e68,e4674d78,4c716fb1) +,S(9fe1db36,f1ee3e6d,3924d2a9,ae3ddcaf,fa85798b,7383a1dd,2d6c0c14,ea46973f,1d35b6a8,607045c0,95ed9658,80212b63,43dc55ec,beb3223e,7c2e76ce,2c74f6d2) +,S(4ca8ab8a,3d45748e,6e19e02d,dc351279,e23648db,d26d2465,7c9713f5,bc8ecda2,8a5866ad,9bb7db92,273c9f23,c0876c95,13b8a68d,bb20c5cf,164a9a39,4e3e73da) +,S(c8d0150,e4a989ec,5cdbc724,21b1e29f,f1f30818,1d8117b1,3d376f58,b72060c0,5c5880a4,c5a73a4a,1ae42a9d,f0b20032,7ac4a732,cb26e717,49e63365,5082ebd1) +,S(3d61557b,b4b9fde6,49fe1b7c,981c9883,9e368444,f130bfea,fc1e1a0c,12f2aa31,933167ff,62cd840b,3a960c90,e6b1c37e,1e233695,318ea286,71c87992,de5b56f9) +,S(67569f9f,fd44ca09,5b478dbb,85c3ed1f,feaadaed,cb624552,ccfaf169,24e69e2a,62bb2948,230fbd2c,aa941288,7adfb24b,d16619de,af0fc102,feb1b26d,67eb7fcc) +,S(6313d13e,debf1401,eb7d279,2c66daa8,6e3075d0,3cf0daf7,f3b753e,7372fbc2,44621230,50eb1245,86975455,63e06e2f,2839f874,beaff9c2,f65e26ad,d3573ef3) +,S(6f8ec9e7,fbbe6e8c,d0e3085b,47c6cb2b,88529f2,15f13195,5e2fde24,4dd23968,1fb61e14,523b3fae,b543b215,dc46eeeb,23e1950a,8301c78d,c510c76f,ed36cd79) +,S(56613dac,3c5aa1ac,bd9a0ec2,f839b4c3,36f0ae58,e0e02244,7bec0546,710b7f6c,247263ab,86c398f9,3b23319,4434af8b,530908bd,dd7f716c,f7b73aa9,8eca79e8) +,S(c9de15e7,b4147219,137e6e57,c5a7ddd6,17e91ab0,6859dda0,41eb3c21,87aee08c,c7178ea5,cfa056d0,dfd11c87,715591cc,40cc5db1,f5e4b70f,d8ffbfc4,3f8b0009) +,S(7590a4a,627d5e90,e42a4b0f,6be6497a,f906182d,d2dddc48,a8b6bbfd,f56c0504,d611e21a,b5498760,5c97e878,baa464bc,cc5bd875,353b69f8,1f93ce2a,a6c38587) +,S(94b1da0f,b310e056,db0dff72,81db3362,1fcc555d,bf3c973b,76097908,7fe19d6a,8318893d,d5b41a56,33a2ab4,ae4b953c,45c42e9c,8f2fd159,85286de3,fd4fc217) +#endif +#if WINDOW_G > 9 +,S(b5af4299,bcdacef1,e07d081,daec2cfa,d6f8f821,38e151a5,f20e6d52,84c9a6cb,c0984407,8a7db82d,f572987e,b137dc09,c8cf65fd,aedcb20,43b2479b,ab95448d) +,S(5f49ad43,70744587,3980a153,c851829b,f8ef6141,9889bb0c,3c476847,6939c3e3,5c40d385,20f56c3d,ba08ae1,b40fc24a,2ae25c94,45cae0f7,d01d1800,747e04eb) +,S(f6bb067f,88ccc11c,64e30d1a,e6893942,16bea3bf,26ec9c64,5cde1b9e,487da385,315a476d,7268978c,d89d4ec8,adde4a83,28dbfdd9,f2bf44fe,ad4ed721,78288f55) +,S(7b47cede,c02b19e0,94daea0e,ec000455,52690b49,44b3f10,beeed2bf,f9df6950,1bcda5f4,9beedec9,6ebac5a7,957918af,53b7ccd8,c211330,280ed93b,e0efe9a6) +,S(ba69d7f3,82d56d9,eb65e1ab,2d70f52d,18223621,c0029035,a78fd660,9940876d,5f44a2fd,56d5289c,f36bdb9,50ee2538,1d1cf935,ae1aec76,84b6d11f,975d393d) +,S(a3b70894,d226c195,223713bf,330ba39,fe7ec35f,9743347d,1d3dfdb9,7bd929ff,5d0cbdf,42755aa0,355ad2e1,ab39479,495edf2c,20bb0aa5,93cc04cd,56ae6135) +,S(c756e23e,bb2d81fd,91fe73b5,20eb3bfe,5ae602b3,448cf84f,e8da37d,d1c804e5,89f4b6fa,edf86b9b,ca9f52b2,9864a982,5a4faba9,d4fb35f8,98511210,34df49ff) +,S(36327c35,6fab94ab,f791c234,1c39049c,65410e9c,6cdfaa00,d172ee84,3671822c,fe3588a4,698c8d35,f0e01f04,e94f7039,eb745631,8c25927a,be7d061f,d3ed4c6d) +,S(3b75bfbe,8e372311,f46ecf6f,c5eb2af4,b66051b1,874b0c32,1189e106,37dd21bb,b9144a33,e3c3339a,4595e248,87940b4e,2e42a095,d7d1bc2a,ea50aa29,5a879908) +,S(44a61f10,57b4e88a,c55ed72,1f8f4477,5f0272bd,379a97b4,d92a7f75,f0d3c5e2,e870ea65,80340464,9716ec1f,5b79392,18162306,6dc14086,111de144,82d80141) +,S(11ae02f7,663c0a,24c6fe5,ce9206ed,1ebed2e6,ca294acb,74c9a227,97fefd,635a1b87,a262fb30,5008737a,e70422cd,a4e35766,940e424b,d697d28c,dfd6a36f) +,S(c751310a,dfb25d14,2e6ab1b0,ab31b37c,8e987af2,105d5981,69085ca,3e142f5c,a4630dd8,ed2717a9,f10485a4,be685c5a,ccca851d,4bcc1886,4df943ba,ee821014) +,S(fff4d7c6,4009f39c,41757b17,3eb2536c,a639b72b,e15af7f,790bddb7,efefe46a,694a798e,ffe22d1,1030697a,292a4bb1,4c110d6b,dad7edc6,e8976450,ce5080e5) +,S(7d76ea39,c13c9f46,e931e8bc,1cd43707,932b1a,31254d18,c06c8ce9,c3f90534,bc14b2ba,8f0a3d8f,34c7cf7c,3458c916,4cee438b,39a5a6d4,d2a1c9fe,8be415bb) +,S(b6efcad2,ca6ae4f3,6f080707,530aaaad,625fda5e,825f77e8,a6730e95,5e07ad39,4868d8ef,8a56d327,3f6f4a3,23ea6ad6,4694301a,1f6405f0,a421939,bdb1c765) +,S(1a04b12a,a889c4a6,d37f9050,e75406d3,48e38faa,c0d2ab4a,e30caa6e,3633a32e,f43a0c8f,fad38d90,6c817dca,3e7ea09e,21e1c801,7af86966,c246ebc8,dc75911d) +,S(adaeb0fe,9b345190,4e878b12,6c8edddf,b70e2500,5a4d6a6c,531aad51,83209b7e,2b26b16d,dd4d29a7,8cc6b4e,198e6ede,b1c59def,c6793173,f33cb039,d37522ad) +,S(4e4ca02,3931f3fc,b512121d,2d632764,d97fa125,8460d0d1,9a94eb88,2c6e0679,ef90eecd,3704a6c9,454c6860,928eb332,cc917b17,f2594348,515822d1,84537467) +,S(a1f3c279,df69c13a,711b5ee4,139f603b,5654ecac,adc02a22,a7c2087,c11e2971,57249794,54cb78dd,7ef69916,5efe2326,e8aafad7,a8a923b2,252523ad,b6a16b2d) +,S(aac76f81,488668e6,f4b0c911,bc9675ff,c19424c8,6a6903c4,f4b13e0c,e798c7a5,24ae16df,dd6c7d6c,1391df3f,73609bc2,c3759536,eb277189,588a72d1,84dd2978) +,S(70e94171,e59622f0,de360166,6498e6c9,ddce496,a15e30a2,a5bdb701,d0034769,d6d7c0a7,75a9cbef,2b84d4e8,200f92a,446111bb,cf46a57d,5e244f1a,1103b757) +,S(ca17e5e7,11d44492,496fa849,c6ab1c47,3426706b,5b8282b6,f288e096,8ec78890,b3ddd632,2ce577b8,ddb9f501,e17d32cc,e6c58fee,4e283410,5e32f3e8,8bce2c2e) +,S(1a16a58d,8d70fde8,6ac0700f,3a43ab9c,255ec001,8d5fe571,7ec6324a,2faa62e8,f2cb2eba,65aff0a3,dd7bc137,257c1d30,dc2eb6f3,7a3897e1,16c0eb1d,1a710c27) +,S(8f2dde65,b4ddf10,c29c6bbf,5ab2ac11,2dd3357a,e3e5f01e,98190e32,94b9d4f2,e06b8cf7,e5a736d5,4e954bd,8591f7cd,79df335b,d3279f5d,80493fe4,df4c6afb) +,S(3314b553,f8213e7c,80d4562e,cdb3564,ba1d7285,6c88d8c5,a3adda90,4950162,33e83c5e,e3f7c550,f94a7434,e3cad51e,b4dab462,13acc24,fc4aa1f9,fc43532d) +,S(7c107ef4,65ac0c2f,fc5b11a3,348a7cc3,fa589554,ee2b6606,2af3c5ba,25304000,6b5bcf12,2e8a0705,d067fe78,e56d365e,89b5a979,c23f124b,508e63ee,975702c5) +,S(e918a829,325adf67,511e257e,e5596d08,19be4605,36b20cb9,7b76a54a,5be4f8b3,1a92f0a0,b46152c3,e1ba8f0d,12119c15,b70af0ef,3ff0ebf,a9dc9207,cf2fa8ae) +,S(8770da03,d4f3a4b9,e92dd2e3,be309c81,c346c97d,2cea15d1,e3fc94cf,41b9b079,d025430f,dc633d57,18d372fe,64f57fac,53f96461,1fb5005a,10ce842d,ab123c03) +,S(c6b4ad3f,ae2b2557,b126a57f,6bbc039d,a6589f70,c6283ea1,7314aad5,acd8b22b,e8523dcd,2c1c3412,35df278d,e49c38df,85f2888e,cf3c76fb,46e1affa,d8d29bfe) +,S(9aced948,6ffbf984,373b1e91,ff871619,4622741b,1e1ab968,9c88cb70,37a86e14,d7a7eb1f,1b4c31df,ff43cc32,1949c1d3,16e1e7ec,a6a852cd,e8e7f592,8b352d9) +,S(af51536f,fccbdab4,c4f4015b,1e8aca69,b08bf055,e038b22b,87c54f5f,1b9007f3,b6bb0b4c,95c07ecf,49ffa85b,abb1d308,cbe813b7,703a27ef,cf849e,47130f7b) +,S(ec5306df,3ea0abb5,6fc45a09,25c1c925,56e02ffa,18238c3e,5bb2ee53,11823ce2,c950cdb6,720f65f4,18065352,43c90bd8,9457f4bf,d941c9f6,89812840,2dee8b99) +,S(293b1ca5,be127bc6,1a397ecd,59164363,587f468c,81de4d87,6c5d9bae,e72d90a0,4821030f,238e9f05,e93d81d9,1764863d,443a524,3d18e61b,ae26f74d,ba35d821) +,S(ebe54b7d,99876ab6,b2951f0e,e68bfc10,16877142,22ef83c1,2561f486,b4865488,2a1d651c,caf8802f,fa699d91,b8242f51,58d84fa0,d481bc47,9246eeb8,6d381c07) +,S(88f77523,3ab0d69b,ed220109,b29d0d99,33ac8325,445d19df,d38d9c69,3464acdc,8f915122,fbd95ef5,31ea2cb1,aec6bebf,8e059059,459c0d5b,79a282cb,cb276702) +,S(1d84753d,e7210dd8,9db6cfa0,8ebe9797,c7fa40b9,6e94439f,b8117359,a2b3bb01,f7360b5a,ba53a4d8,7440b6d6,f540c485,2e889c33,9f34260d,abfa7861,f1f41ad6) +,S(19e69df5,176f82c1,cf1ae032,cb388ce3,36f82a3e,5e741e1c,27fcefb5,311d4b2f,c401f4fe,c9ba53be,be175dc8,cc1d17b3,9d9f7af,5bb496e0,b95bba6,cbd5c143) +,S(73189e02,c1f125ff,df1a9399,57f29aa5,19b04f5e,42adf729,53d354cc,aee3f2c9,52b8e88f,1c6e7cf8,621d21b0,1e406038,d901de1c,4101d424,1009c01,a537f704) +,S(c5ebe082,8ff1a8bf,52f8956c,b747f1d3,278fd2b0,a5ae7669,1c256e9,2887a74f,ce58cb9,62e74b98,1ab97dc9,2d736b5e,c506e51d,6c09b382,3eff1cdb,cd259860) +,S(783c1621,f7990e01,4296feed,3bc883d5,1a780867,c83b9166,435a0562,4982da76,370b3e2,c9a189c6,9c565c3e,8eb8019d,f5224574,bd5ffbc6,22f563e1,8a36da30) +,S(555e7e80,ccc6a46,1724cbd6,4a53721d,fad66fcb,2c71d579,4d799f6f,fa2b3305,67bbf165,d39d7042,18f5ed31,28fe6dd6,db9b4809,b3270eb,63bda603,f44e9e41) +,S(40c49a26,ab1cd46c,f1e8467e,242c6b1b,faa40a4,cacdd50a,4b0213a5,40243471,16950b00,5002622f,e0b9fdb4,c34224c3,ad55bf30,67f4e96b,dc2813f6,2fdadf86) +,S(eb6b3be5,db098d18,9c810b9f,5593c746,47306226,d77e162,7c8b62f6,d7935298,3d295584,3f356f5c,1f990231,701cedc8,c84e9671,44be22fb,9bd74f0e,15c5bc8) +,S(177218a4,2b55c169,1ca0a073,4d061b53,a0683536,9a04fca9,3f670ce,5eb26091,9611661a,a8a3bc73,7717f243,e5e8b97a,57e0e72,759f0f4e,cedb690c,b3a5fa42) +,S(841a8fa2,f3bc5f8a,7d028c00,127c267a,ea0c3762,8b07ebe3,7f883a67,8fd2a680,579bf37d,b2fd1f77,a0057712,88dbbdcc,526938c,4f9ba89d,9a42d4f3,452cf1b0) +,S(b01ef554,3a377f1e,c801421d,a399c53c,3585789c,d7e51691,32250a61,6edea82d,28f30ce9,7e29b2f1,3af626a0,7a37f14,82e119d1,e66389eb,9620200b,25a90265) +,S(b93e014e,8e3cc643,17ee70d6,ef8c9918,ba344e7c,b38a9a6,2591b0ac,4f38904,129c185,5bdfd10c,6bf152e1,2ff89b4,d0b368ed,c0ae01f7,2b29fc95,240ac3d3) +,S(e0f426f2,43c50d9a,ff80a1dd,26d63189,a00601c6,8ac81373,5fbf548,7acd522,96d883e0,951adc5e,304bd848,ccf39c2a,1c19382a,eb24ad1e,1430d705,deb749fc) +,S(e11e9c74,40e897ad,2870adda,63b9ec04,d5379f14,b3bbbdf2,147ea9b7,9c73233c,49d6e54b,29197532,3f5a9df0,3e22e359,e125e34d,d9f3d6c5,cb9f0a20,6dc1f019) +,S(91ad584b,c5ef145,3b796eca,20027cc2,ae38ee70,9ac4591c,79cf67a7,a96b2c2b,d815a213,a620c531,11f79e5d,b5d9c3c5,565dfd97,ece841e2,3e9c1ca7,530bac2a) +,S(3e725392,f4fa34f2,7413785,cb322f35,1032971c,2303f3da,bfe40461,4299f8d2,8e323a51,5addeed5,f3548217,6907efa5,4e0c1d57,7895839e,42223e5,7708ae85) +,S(5e87bec2,1a589ab,483c00ac,fa863f35,91d9119b,9a0239bc,ed4f5790,45a98160,a88a3b84,33c75c1f,9eaf3c15,9fc39a6e,33625f1c,d0cd7263,3a825023,f2e7d47b) +,S(c2e08613,2cb93b35,749cb652,44e99909,da18260e,d252cf32,489fa1c8,d268a0ed,d3f2e3ad,1f16365d,d47038d6,854e0773,28e02e64,d05a4764,4ed0d82a,8c8a5761) +,S(99304c5e,ccf09869,7b2193c2,31dd9432,3b9053d0,e4b9025c,74517ba7,f1978af,ee77fa7b,638b1396,6f7e77e3,43dd04a0,ba1324f3,1e0da111,338019aa,209dc789) +,S(40e108c5,59adfb37,651f04f7,9ef895b,25a79f03,650d6b1d,1c21322a,b4c5c6bc,8980ab38,5733e648,84aff3f8,c47fef44,210eb2ab,a094eb2c,fc5e464b,679db653) +,S(98c88257,2d190721,20c31528,7f508df4,6d6276dd,c9711aca,5bbeacdc,88c6a78a,5d1aa976,1f5c5ffb,d12ea7f4,8d0510e8,b57f270e,e08c3256,f3ee676b,41a61c92) +,S(389aba7a,25e92306,b84eeab7,a16c37ae,d7b4cf09,806ff740,c05dab20,60af6fed,673ab0c9,ec48e2e8,d372ed60,812b2990,49c32637,35f61c13,d6f0ecf6,d065707e) +,S(9dc64fba,832c956e,93efda62,e5f11b3a,6619eaaa,e539b732,61453eea,ca53df17,180b38a9,3c56ab10,a4267ad8,d8a358ef,8f60a9c9,9483889f,956bafda,f45990ac) +,S(71118e18,e758c2c3,6203528b,8b6707ab,b3439b0c,d3d508a9,6759c155,fe4921f7,c2f61af1,2c1b4e9c,64908719,f11b52d1,76bf22f7,e1cc800b,5ec79e28,aa104ee0) +,S(33bcedee,11b9f3c4,924e0990,9adc5fd1,46218b23,6531a242,45cbb2a8,3ec3d096,15f4bd1a,6c22c673,941a71f6,f4694fdb,f83b3e8d,5e317e9d,655057d5,acfbad0a) +,S(4b599b3a,4ab5e9f1,f161e5cb,62fdba55,fbd97740,759871d0,e66b20dc,4e13ccb4,635039da,9035272b,8b706411,9b342144,6c96019a,2c6df423,2b18299d,4a3fb523) +,S(19f6bf4c,dae54ca9,41b8f642,95136026,decb8dda,35e97627,5694365b,21269d10,a24c3fdc,90b06dc,264bca48,db27502f,6cb31a6b,609d3f3d,a1c92c64,cf3c95d7) +,S(bc3df1a9,8027d14d,f6629adf,7ad073ae,8a270875,b177a67a,58dd46f,1b01314c,99dd3a91,54f51d07,2ee33e89,8d915189,93445065,770745e7,b6bb30ab,808d1f76) +,S(977a4264,521a70e8,4d25f5b5,ac1ae5f6,c34ef31e,4dda285e,1ea4a9e5,7dd72c3c,f1bfc819,7aab2fe4,d0425b61,cd403fc9,dbf44f68,32e1c41b,4fce9b2a,2b9f5a0c) +,S(5fdfde4a,85fc5a53,3ed4a7f5,8adc7b1c,98b2611,3e271b47,a1c12c69,dc9b339,3edf2baf,bd6a94e6,951bad5,26fb24b9,731c2588,b2f6eb1c,e9744f49,16c6555a) +,S(b8bcd72c,dcd28afc,eeac1ac5,fb7db8c,afc17abf,82268747,6ce01423,e9e9c50d,82633c5,2e6dc057,9bbd9f2f,3771a53f,9cb6d0e3,6a7566db,f2c45125,3c55e9d) +,S(6c20b999,133bc37b,c65d01eb,6e946565,721bc2e9,da735c72,8be8a41c,1f75c77,20caf674,d8ad036e,25f42aa4,7a5ae475,5e36f44a,79c5ff20,cf6df115,40b71e53) +,S(bbe49141,69655f15,39ce4bf2,f2e919df,f877b5fa,163b7a70,22bc91ad,315adb07,8cd3e025,6618d23c,8c6b5ff6,db8fc0a5,a77b847f,ec876ac,40f76e9c,cbf93a1e) +,S(748b3078,e38374bf,7f39bbb,c5641737,bf6dfeae,d3980c75,2fe14c68,65e73786,7f7cae0a,61a7dfa2,471f2c80,217fc847,ea86b6b0,6297aeb2,8f3c94cf,2a811ac8) +,S(fa63c7c5,b89a2559,4615728b,2272cf68,5d39d592,d052c0bc,d23d48be,c764e4b4,c4c32ba2,77519d60,e1e38a50,6d67d041,804724d6,5cb4dd31,fbe7d692,8ca47c8a) +,S(c2ed7197,d014e380,a365ea13,d948314b,86978eb0,70e3e444,6c953871,cc56c91c,5c73c293,e7c1cd18,f7854a09,d8b9b0fb,3404bdb7,737dc070,9bdc01e,466a595e) +,S(2514c1ef,cb1e0bd6,c2f34e84,6f3e8006,6c2b3a04,c0d9fab5,f22fe872,6fc266be,c5a0ac6c,7bbb2d9,ff844346,65f66ec6,507c35dd,8ccf9ad0,69a1ec94,c64e3eb3) +,S(5bc07f05,11647f2,58dd2e28,9a3843c8,e2318bff,c96a081d,f6b6ef94,4e286350,213ce093,1217ef04,8d87d059,f2584db5,7a91c465,1e112c66,a41f85ab,ebbcbea4) +,S(edb56e42,97375b03,8a573f70,67ae464f,db9c1335,f6a03dd8,862a1731,9a3cad8a,d3e61a70,16f8d546,61b8414a,426f3be4,35862053,1d981f2e,5314447f,15ef5fa7) +,S(2925276e,78266481,3bf60998,2e028646,6849088e,d0d77d55,817c8d9d,73d5d732,f53157a6,a97c989d,ceb2d755,dbb0cee1,84b33213,20dd6d22,62213fe4,9a87296f) +,S(2c4579d5,bda0f4a5,37209882,937019e9,91286379,c3afb37f,a69e409e,9bc0a034,e150bf4d,d889c3c4,655acd23,f3107bca,a319d467,b1b9b15c,336ca934,5ef7d99c) +,S(5f260a00,11f9f876,bbe29587,af31832,25f21b8,42698b3d,5688545,a8808904,6ad33a32,164caa1f,7a4d2ce0,6eac3d,736fe64e,d83a3a9b,53473a89,8ee02350) +,S(3bbbbcc6,12095ec9,52fd430,f3fb3d6a,9d1f2c69,e8885100,d65a4d7,b6ac4b8b,328e828,3846a6e7,db5b090f,8c9581da,40d244cb,aa3b5948,7e4f9faa,550b0c97) +,S(4985027b,dd0fd8ef,fec9af44,bc222f4a,343e80ca,662d917d,affb9d81,956acff0,58befd2e,37a36e41,305561b5,f2716a23,460b1014,fe814654,68c16c22,3b8affda) +,S(214638e8,d2e30891,9b5eb2d8,803b3dcc,6e826ecc,e1b59b,92e263d5,67959de7,9dd8921,6f131e29,35ae0454,ff5fc9c2,dc22c0f1,c8de7dd8,ad9d41e4,f632342a) +,S(6ced8705,5ced2d6a,f3e3532b,965e0a31,6876c110,69155f35,444004f6,e6f3cfdd,f51b1aab,c86f556f,8b7ba4e2,a1e6aee7,55b17c01,997fcac0,a83eb56f,7e546ec6) +,S(95016e67,876c936c,e3263498,7859d1ad,7fc3ade4,4219727,30a1c886,c9dcfacb,299e78c4,e6e266ee,ffbd284b,81005bab,4df7232f,2e43f160,742bb392,6af4f660) +,S(4bec66c8,30401c39,c42a8019,fc398cf0,c513d20f,9db30763,51315319,ee6f23f2,f1dffe92,3b7d4609,871aa916,28929c63,4fcdeda1,543fc3d5,8e8b2735,938514fc) +,S(b50513d1,40513b97,6ac0015a,60e53ae5,9088c4ef,5ab27bb2,7f3eda78,848a59c7,9c41cae5,1182e6c2,3fb254c5,1b786ccd,dc9282c9,a6674841,29a5894b,99c36399) +,S(59792653,3989a039,6a69bda3,8a920ac9,d1df3845,26f30c00,3e415593,b690708d,7f2c14b7,274887db,5e656192,19ee6737,4c750cb3,97ae4bab,3a3ed02f,1aba648f) +,S(7ba2b766,cf012a93,478fe2b3,e916d665,251cc7f9,3ec16dd3,4db37056,5eacf6f,14fd8938,f950798c,37121286,5e8bdd14,3dcc7e8c,2c84aa69,3fb311f,856404bb) +,S(3062f2fe,f69c90d9,fc947af8,a9e839cd,7f9e9d22,566bd3a7,1c43df9b,eab5d6bb,db84a833,49916d41,7fde7b71,9d92a716,64047d4,21a36bba,ad9972bc,6f5ee58) +,S(ed5f949d,69dbec8a,77f4d695,cb446700,f6fae687,e327cce3,db38c2fd,54b06e74,4724e060,57b3d50,65104ff9,29950bcb,2a690723,f15999fd,ee62febf,2d8930e3) +,S(4d655e03,30028276,e9312fe,a6acc010,30e12950,9ebd68d3,d7170e46,61b7cdc,90efc122,6c27549b,2f5e046b,69e97f04,4399579e,278ccd0b,7bcee523,10ea99bb) +,S(f6b60756,b888efec,d0a9edf4,a483f95b,68e05e80,c351a60d,bf166faa,eaf1b35d,27bedebd,aa781584,6a896b24,1afaf9b0,cb57e98f,bce5df6,bfd22a3d,38a5fb8c) +,S(cc592caa,942ba237,72c4db94,58d6ea2c,8c81c538,8fc7cb51,6ca30188,a3c55748,36e2f7cd,358e5608,36e77d10,361c3f1,bb6bd2b1,d640307c,63d512d1,db288158) +,S(4acba9dc,a5bb4698,21a3acb8,cedf4304,f9372161,976d0edf,6a7a032f,f6c1a456,b36e983a,b2ab47f3,3e72287e,9bbd02cd,d6fb302a,972f2166,9cae4e85,52262437) +,S(c8a5185e,42279d3,2b50e0c6,1b9ce961,7be3633d,84a9472d,97446ddb,eb061f91,cfaa50b7,445e189b,d64c1df7,4668eeb1,cdb7cbd1,ff65c0ff,3c38d22d,9bd4b5cb) +,S(c1c95567,7f4f611,365168a8,89de10ad,535faf08,65f8d20e,52b1041,d35f18f9,34f7bc3b,3d956b63,9afc1eb,956f4472,543919e1,3708e7eb,537ab941,48033749) +,S(8df4fbb7,36f6736e,b4a09370,33f7d256,8bb68d68,f3e1f8fa,8df1ae51,d236a8f3,3d7185fe,8e9a2d00,3987af26,71bb3850,cef6b0f7,70770c81,22977764,5d02122c) +,S(d635f0,e35c7cb8,f2aa1ec0,c475011d,c2c8bbb6,d1ebc297,c2baa5e6,aa5af3dd,926ebd,c588e8b3,1a990a5b,5907ae5f,441e5a99,1853c643,5e36803c,7ba51a2f) +,S(b58d12d,5f865375,7514ea38,30e38e05,3678b525,e8b51923,d6460720,b46a4bc,f7b59183,5b0ebab3,935d587c,e995c0b4,d77c9e40,ea4837f6,48e44841,7438d3e) +,S(bb7c6a8c,b4013640,ecfad075,578e89ae,12cb4253,6461d780,11ba76db,da9a7f36,7dda0258,3774d618,68995b83,5708295a,3c2f5c40,306dcba7,d1c20da1,4836581c) +,S(14f6f0f7,92cc8cef,9dca990a,7fa5b7aa,f116b819,722cfb91,9683b298,3514a9e6,88c35f92,7a07598c,90ce5aac,4b3fecb5,2261045f,f23800b9,7b96f210,3a4d7055) +,S(4b95e5f4,eb9fa118,5ddad896,457f4aa2,fb60f4d0,496ad4fa,76bbbce7,77448541,1e100787,513acb31,ba087f51,201201ed,502d1f08,f7e2b8f4,d27706d1,45e71d21) +,S(e9a17fc0,67f75b2c,6384aa31,223355a3,a7af5366,4d85dc16,dcecbd2a,364b63ae,420a2388,ad674523,62f8fcf0,12b601ab,a40e06a,1b4dac1,9560c085,de7fb8c7) +,S(39d8536,f320ec81,4ee3d066,c0834130,96d4ff43,8331a81c,f10ad544,43ff9169,70ee89e9,1478e898,60d66a55,6054abd0,c7434535,13a7a3be,7a76e367,c28ca248) +,S(9779a0c8,8624d6c,beb1dc72,f371ce26,9f95b993,c49ff20e,1daa3c,2fb636e8,9d9e27cc,67296c50,9da4b0e,6037920b,369684d8,a64cb907,d230a4ab,a0c2712e) +,S(cd4c584a,1dabb48f,6a5c09de,9caf36ff,4a97471f,d1565586,bd78b4fb,66f0b401,95902ab1,eff06e2,b3e104b0,cad2c28e,6fd60eed,c47657f0,bc433411,273446f1) +,S(46ca11f4,142362cb,513164f7,c72b776e,dbeb3f65,5d527196,88eabeea,2561aba4,8060431a,2a2ad442,dfb6d3cb,d6263c61,bcfd0946,6204e2f5,e832c4d5,a434c9ff) +,S(dfebd179,1ffb63f5,76f5c753,50031a21,eb712de5,7e8f83b4,75ac39d8,8a94a513,cfed6c7e,39b2b54c,206aa0e2,2f7c610c,6576af2d,ecb28f0a,a71cb1ad,c7be75de) +,S(c71c6532,82fd063b,44633d9d,7a3b94f9,43daf1a1,7967ffcf,e1238087,5d2c2469,62fcd7cd,e006a10,38df8aed,33abe940,f18a4736,52adeba8,620d1b54,a9d376d0) +,S(63ebbb4d,dc8ba09a,4e2640fb,f48fb75a,6864ec41,fc1647b1,e9f8aef7,34c0ff37,e59d034b,fe16f4b,41d090e1,97360a85,dbf1ae4f,719c62df,77261205,da4ae28e) +,S(650498c8,cb51bf16,58eeac61,61b5892d,ce6e5c1c,271d40bc,eea14db9,dd12814a,e7e66785,5d8e0193,24457769,bbd5d14a,7a614585,70ad5e6e,e3058af9,64a65279) +,S(14a1e03f,14c00863,81599c07,b816df44,90815a8,40c1032a,c41225a8,47c43fd5,35244a59,bc6ba88f,46f66bac,9bb8ef5e,4926da38,50532ddb,6d6d606f,35fe98de) +,S(1c9f6eb2,f6a8a1e8,ecf9a16,71154fff,a4f14c15,bbd50f08,4d6f5315,b6903c5c,e6bde1f5,2ca4ff63,9b66fc51,150eee99,5386383e,402f987d,d266065d,2a03a033) +,S(1de71eed,bade7b1,7c80966,4b00d56c,b43ea61a,c0e069d9,7cff0218,f970f8bf,8d4b2de,77edeeae,d78d42e1,6b7bc94d,ea99d65d,985769bb,5c67da66,18ee1434) +,S(f4432a80,ce954d2e,baa2f062,8bbab706,479f7a39,838d8c3,5a96eaab,5f5cb4b1,96fe6ead,ac34a40c,3cabf47,6fc09382,91f3d077,29c6302c,c67a189c,bed579bf) +,S(8f71e74d,17964af4,5623d3f9,68424119,cb37e1ca,c1524737,4828b5e9,2519fb21,6990f0df,d7f0ca4b,a77678e4,ebf6946e,5b6b1720,869c91c,ec07854d,604865ab) +,S(22293157,5e3dc25e,665546e2,96a83a0,5a09d052,cef701a1,20019c49,c6a6745e,aad8f887,42585607,c792bfae,8a941caa,83d05082,defea859,86a6ead8,e5c423b0) +,S(6585fe63,2ef3a69a,816bf5f2,9e627650,cc57d069,3ac217c6,3b73aa2a,f248a096,820aa3bb,20281afe,edd9ca57,76ecc55f,dc8a893f,de11f7cc,12f37a83,6cfd9f8b) +,S(22232479,e55c51ca,b2963ce5,abf06281,aaec472f,e610d339,1951e41f,93f67bf8,e192fab,2cf22d7f,e67f0514,bc1329a2,888a8f18,a8d6504b,b7c5a9bb,ebf927d2) +,S(da8d02fd,e4ba069e,bccaba08,2b396c94,4460148b,70e98f60,8267db02,5ddf16fc,1a30213d,e337084a,47d67e7c,17a2e64d,579756d0,8b66f4d0,59a76021,e63fa2bb) +,S(a6f72c62,854e82de,f1b8a006,64c4e8b9,ad49e092,78ee6501,708a9f18,92202ebf,8355972d,b08c8104,b7c56ab,c2318ef4,2e270989,1a83837e,daa35537,1d03ba4) +,S(2074fd3a,309e85a0,5c6f8c35,937dcc56,a15077ce,99f5a8ee,8d55ae2a,3bc7db68,e11c02ea,cb783c94,2e58fc0e,806a9816,3061a4e9,aea9582e,53ae1f08,322cff97) +,S(49ed5666,fae9aa2b,70cd316f,62a4b62e,29aa59f3,1826106c,8611c50c,79a1a5e3,5ca7e49a,ae144e2b,dcc0b19e,f986967a,1477c209,2a8368b6,324bac6c,807643f7) +,S(2289ec7e,a1f7e4e9,85f472a7,13722335,b582c4e9,8e191468,3ed13622,5d6c1b1f,11e2b18,689a0867,517bff6,77fe40f7,b03f898b,d70e8902,61a512ca,d9cbbeb1) +,S(ea852ebe,23f1efbe,d8ac64a5,58ba2ba3,fbed0e52,ffc70635,bc49cebf,85859164,bde2ef41,fe97a639,73266583,c7a4e415,25ef1351,5b25cfaf,c97aa635,41cbb824) +,S(5718f0e6,7cc07d3f,1ac1a954,8fef08a4,290b257d,a4179855,3fe9be1b,d302f0ea,98ec4d5b,fca65d7e,e72d8bd5,3645a6af,a6ffcaa0,a2eb894f,d4e40ecf,69acbe90) +,S(df62a2ab,d77afd7d,ee8f0650,b75458e3,10269c3f,780cdad5,50bebd92,4b810a4c,6a6606cc,e384d27b,80bea2e9,588663e0,8d39fe8e,9fc8a8cd,54c4829b,8e4c034) +,S(1010fc45,4b0c268b,c339bd19,809508e7,9ea7dc0e,efd779aa,4974cdae,805e6668,686a3adb,681b597,2b30a323,c6b6bd2a,d51194f1,9d3d801c,3fa65fab,e96410e1) +,S(8ac79852,75673818,69fe93c9,6141493e,72ca344,790487b,d5425ed6,9f5c5c18,bb314248,fcbfc867,d1972e04,b9ef1f90,775375f9,9d25bcec,684c72c9,bdd1c08e) +,S(560e9711,88cbc7ce,c61f3bf4,45f0ade3,6f3f174d,219a160,5f9c8692,3f848b9d,9e92dace,6775cc67,bfbbf21f,c64e6e9d,4d133f8a,c18ee277,bc80ef6d,d1b9cd2f) +#endif +#if WINDOW_G > 10 +,S(8c464204,4b95eb66,cc95ca08,8469a1c0,28eea52f,7f709fe,e6d90700,f5fb943a,bf10fc5d,7bc25181,301b3a61,5ebea597,a3492025,953c3aa5,1a11271e,689d0223) +,S(d293f74c,f3578b71,35377247,cd8b0367,7f2245da,f87453cb,4d8d1cc2,871eb5aa,86c2013a,61dfea14,63e45931,eb09050f,f080e3d4,ae357423,ba7afbed,a64a6f26) +,S(35997241,ae757b1f,c767611e,c76eb935,fefbf7a7,33666aff,4c6bd744,d7687d35,bcbea61f,246bcd4c,c3c7fd35,7bd393da,2f36e0ef,cca0df9c,5994f96f,c44b2aa0) +,S(d096097,7467197d,3c1a0ef8,44ee35dc,285a17c5,bd9e06de,15f36025,7f6464eb,342af6a5,1e06db96,692954bf,c79cde9e,3dd44869,9e88b03c,d144b70b,bd3e8783) +,S(8e875c99,2aeaead6,7033a375,521b0f85,62125797,23a25470,bfdf898c,ae41a777,24aa273d,2d2f19bb,4e0ba10,13127ad2,a5ee6686,1ec6d0c6,53f7a989,73c0bbd8) +,S(bf51d1f3,2703a4c,d1ef47d8,172c5bb8,d622f444,8569aee,d2de1b9,ae541855,8f81e352,b6c60acf,bbde6e40,99353d84,5918d931,4433c30f,3c60a710,cf9aa484) +,S(6fb6b462,9726856,22b2d141,5083ef56,2ebb115b,6cdcbaee,696a8d4c,8341c26f,9c08f7bf,f9cfcd9e,cca923b3,e578ba45,468f2530,baca2032,a899f060,b83c9c73) +,S(75583ac1,8b5cf78d,7de6a21f,aff045fb,1db56f68,6b2cf89d,678df62,93617438,8259a22c,b08546ff,e237c7d,9c669c96,71fe014,9840082d,f6790340,9b69f900) +,S(42611933,a5d759ac,7ec51c89,31b76e95,4aabc2e3,61010f36,cdd8ff9c,b4c0ef92,88a644ce,6b8acbce,a378e2bd,54eb84c5,58cde403,f99cbf8,7830151d,21ed4261) +,S(243a6dbf,6128f964,bdae776c,a716bdc5,6dff9c95,24baf845,8a43ade3,af520d2,262a2e8a,5ce4db48,d0401850,e92bdfa8,3dda744d,a3d9025d,6091f1a5,201b7e50) +,S(212bd175,1548c6d2,41e9307,a7df15bc,46e57e2c,5a76bd58,82b1291,d8c2ac76,82461bc7,6cc97273,267cc788,a8b24082,57f04ef4,719a9aaa,e33cbd77,79391bc) +,S(da6d030b,21f96d2a,aa0b3e56,28ae0ec8,8ca8a546,10bd61fb,c1a7c16b,4d61177b,5b5bc635,8fab0287,4a2b8596,1b49ec29,2c2aad1e,1eabbd0a,1cebdbe7,2e3f9fde) +,S(dc230af0,55a243b0,a581e101,2eea48fc,4a43137e,cfe80108,86a9f4e3,f6c1f01f,d0f98e1b,e70a458d,7030120d,a3d7feed,2eb5a9ab,601718bb,950fa03e,568180ca) +,S(82c2de3a,c815c686,98ce73b5,6f232684,ee9c5972,f0a44797,dc16d04b,a9089df1,1c847065,c6c2cc18,fa253b8e,c1fe178d,c859844,2c1fa432,54462d97,93b8573d) +,S(6ca2de88,74e4916e,e1965dfa,200af89a,cc439f20,6a4077f6,67076149,e20494a3,6ef0b344,97aa85dd,a43cc1aa,57dc7ce6,cd51119d,ae96ae06,99b5119a,9a662043) +,S(ba2687c4,1728fb65,206448f8,28400efb,cf1149a4,90bd31f8,8d33af53,7851d97f,96ad25f1,1f2ce7aa,e8b803bb,3c62cd32,3345500,243b1de5,d61f20b1,86b4c0c4) +,S(ac362040,1947f301,16032d5a,4b303323,d311f533,e46a1aa5,f1ea2f08,d553e0d,53839f95,fef32884,5a75881f,a17db91c,1d5b981b,7b20937f,df171c3f,2cb30a22) +,S(6780ecee,5b1b7205,68d4241e,c3b35c9e,4158c7c2,2dbba46b,ac769476,79049e13,9ac115f0,31e0888d,2dc90b9f,3562e732,46520d57,ecc7ae4e,e0fbf401,3057d9a8) +,S(95377a47,e7a2d5d5,30510d62,2bbd3439,c0f7653a,ab294254,cbb10390,d2a63732,57ac9110,9dafb62c,fe1abe4d,fc64557b,bb01f76a,36649d7b,91be523,f8195fc0) +,S(4f195bf,98fd83bf,7ee97c5,9bd42af5,486a8507,3327415e,85f17a17,2add8921,a56acf25,1c82323,6327cae3,6b1cadd,1a057bbc,f1ef3b59,a865c7b8,691cf3dc) +,S(eccd1fd1,efe8299f,d2208240,adbaabce,cc0510d2,d7b6f6ba,d9e291b1,4cbcb53f,ec2ff321,6da50fa5,c57d6f2d,3198e019,2d9b6f8b,ffc26b29,13580447,a42c667c) +,S(c757444a,f2c3425c,728ff41c,f7cb7475,502e7601,c1edf2b,1eec84e1,b058f438,e1d481b6,169f143e,29701105,bc8b6657,9cd267fc,685014b8,fd070283,6362e53a) +,S(3562837e,bff50776,58d99662,7a11a367,aef3255c,1c470ac6,36f1b57c,645250b8,cdcf4a0d,97aa58fc,ccd374bb,bcafc00,fa1d0d35,ca7fab9c,f4d72d66,299234d8) +,S(ce9dc245,f62e97ab,d2d339e9,7fac18b7,b1f2f07d,fb654a82,b113317c,86d4a3a1,f6e1e325,342afb8e,64fe8520,ec37abde,fcaf1b30,be6ecb79,27ba5615,f0d184d5) +,S(ac022f3b,48ee44ba,9d271a8c,1a01fa8a,aab4818c,e5383dd5,42d9d6e3,2c858a12,1e0563a8,91f8d11f,1989e091,739611de,191e497e,66055aaf,45db9ba9,72ca76fa) +,S(d1d4f682,cb12cfaa,e46e57e6,db6f2277,55a83782,88cca4ff,3a999c0b,a651d9f9,1b19bfe5,870e1931,4c23b4b0,71672233,1607264,acb8e960,488598e7,85e71a36) +,S(79962171,bbddaf94,45fbacd4,f9bdd1a8,892e754b,2d0052ee,2435303a,ff1c8a37,b8ac27de,2a952beb,45472f77,b34c1354,fe47b6a9,daf0720a,b8515be3,7bb98a7d) +,S(445a17c4,2390b604,bb3c3573,b061a2f1,20ecb3b1,83a0f8d8,cf032e3c,509d3b90,b75f4088,7c07fe5c,a0c057c8,7eff4966,4ea76941,e409a6aa,e34ad4b1,693f97b1) +,S(6166b5f9,63a9f47f,5fac49a7,8d175763,8c39cd49,11d16ccf,b0e83bc3,f402051,ba337661,8302aeb2,213e4620,4ec57492,933d6df5,5a045d7e,5317ddf,e92430b3) +,S(cd666e74,28901afe,8e67d0e4,48de7e3,30b6dbdb,a34db4a9,29315d3f,8b251531,af72d8b9,43cba540,e42398e7,49fc89ed,44095951,f11b24f9,e5451810,3802304b) +,S(c833be8c,fd2f6fe0,46d837a1,1d990355,5a6285bc,d7b8814e,e839cbad,523ac72,7ea8f90b,44112363,a8d75153,150c3b4e,b6c07dbe,fe8c8ed6,3a24984,c9a6af03) +,S(cc185f36,3036d385,d890ac1f,5e95b162,e40e4a4f,e8427613,98200369,f25ea477,e0768836,146d9c98,98aaabe5,a9ce12ef,f66d0775,4055eb42,832eeb9f,26338236) +,S(148e0863,24bbc2ba,b67c9be7,407b809,77ccd910,e92c9770,47943c29,8c9c4a5a,89e83c85,9cddfc80,9de733ae,6138e97d,b706a331,fb7176ee,55dfe3ba,c2408797) +,S(9b1539c1,aba5b583,5c88d9b1,92a3761d,cf8b649,54f53a7e,460e0122,bec95c76,391cde19,45be59da,d4c895f1,3aa1ce24,d8472e42,a232795b,967f21d5,acefdc18) +,S(68a2e6c1,75fb01d3,76a9e575,ff427cc7,a6032774,a974bdd3,e93b8a73,e4495cd,153e6484,c8c30dde,5f269b74,1c599647,666cab7,e273d4f2,5573dc4e,78e00752) +,S(58fe9049,35a5a40c,3b633440,533cccac,7669e9a2,e7c2f0b6,6c36c228,61dfb04e,b36905c5,92450e2d,71d06e2a,2d599a77,71ac1e27,15a79555,b39fbb60,5536e1bb) +,S(823c0f96,dcbdd9b0,bfdaff2a,19b6027d,3e9bca6,e298378,3375a783,5eac7080,d91546cc,f34d9a58,babeb6d5,43bf3c36,8831a2b0,d9043db8,895cd208,f2ad0a7f) +,S(4a56aeae,e908f908,55fe7b71,3013ee7,d6812152,4f7decaf,533cde20,2d14537,7e60c801,33b718d2,119995b3,3790eb9a,3129a7fb,2e030d8d,21af90a,c622b7a2) +,S(6c0f3855,e6c4f5f2,c4594e2b,8881319b,82a64bf4,9fe0968a,71f6ca3b,f9240334,5c8e7b6d,a9efbba8,4b5ade85,305aead3,e1478ad1,b4d56fc8,3acfe34d,23b5203c) +,S(d9cf8f2c,d1704907,15dde21c,f172e648,496e40b,5248f331,3aeba2a3,35ac9632,92a7c251,b440f930,bd98299,c35d57f7,15867e90,b6c3e8e6,b073815c,3c934344) +,S(4bfcb492,8b91dc7b,afa7ed43,d9af3039,77592728,fcf1b9e2,7c6767f7,b993d898,276a06f1,ecd9d410,b34c9a4a,e3aa33b8,1854a4e9,e4703dda,7bfca949,a45d14f7) +,S(abde5893,ac4032f4,4ed93dee,8156596e,7cdcc575,e5928792,944019ac,23c434e8,5e03a809,2b9e6044,e942af7a,7cef02fb,46162cb2,4c19916e,d774b00d,8195c40a) +,S(205d6307,7a98a8e1,178814b4,9281da20,4482f1ae,31be20a8,3b3b0fd,526e1cc5,4bbe295c,943e3560,6b95cb19,d6e64bfc,b9cab7d2,55657614,7a79ff50,6fe4d780) +,S(cb4c4c83,e6673a1c,6c228a42,36e6031d,b59653bc,45bf4b7c,3b98cdd2,441c43bd,142e0276,39267ea0,f7c2ff39,75afe714,62f3340c,1fea5149,cfe4e8ea,e31a2769) +,S(25a1f4b2,7ff5bdfb,3af54a4b,493356ef,92ccf0b2,dec7c4f2,b5abb225,2cca77a7,1b25dd93,153f8341,7df3b3af,c991f2d9,36c32e8b,288a7fe9,3e9ff97b,335c3c38) +,S(222f76a7,7eeca0d6,a511c863,a657cb89,5a1b7154,957b66dc,89ca77aa,2a54237b,a8f2bee0,64eff88d,87a598a,8665d295,a205c884,2f6a3492,7945a02f,2cb0b289) +,S(32d4328d,1ad2651b,41bf1015,6936b406,379f5c26,99f1c2da,ec3cbd8f,3b4dfa8d,9f6de6e2,3294a33b,5f4d4062,3e478096,df5de0a1,d069290d,204ce930,7988261d) +,S(cde9ecbe,6948cd70,3b193790,6662b7d,187d0830,cf991b14,e8265691,81f1d3f0,84887b32,e1218d2,9b77794c,e8ad56c5,f5abe8ff,f95515e2,4bce81b1,5b029720) +,S(bc89f45c,3baaef4c,a8343582,6506a006,509f4e7e,265e4b80,11d53d3,a748947d,eff5bca2,714db146,7a272fce,534f79be,9fa15af,7226ba49,51129f5e,6fe68475) +,S(62678cc0,eea2bbfe,2bd4ba65,5434a9ad,39b409b9,b57efdf0,9940f748,ddb51d4f,8d384f4f,d234d31d,1c161245,ef6dd54e,a5cc8ab9,e7bcc883,6735051c,37a74acf) +,S(15e01d39,c63ae225,63dc89cf,3dfa2736,df7c0ac3,4fe86f8a,f219f933,86bc93d0,1f563532,314fcb81,c1725133,49769861,e7efb999,fa317ef4,2bc75588,10cfb13b) +,S(4f8d2b49,3493258d,ff98e813,e428ae9c,52c60103,1bdbeb9,7b8f364b,2bac10e3,8c7d117b,67955db6,c0058028,3f919f57,1e8c58e4,216ca1bc,d66b264e,169b73f) +,S(d14ce31a,2bf16b60,983e397c,ddd3588c,3b0d77b4,f449136f,1a789276,b56f1d61,9a15f620,b227d83a,3722ca6e,4dd7bbf5,833f24c7,2584f356,11ef3734,ad3f0910) +,S(35221b4e,b8c275f5,c10d656c,9bfea000,24c1aa2,c4130841,9c3e8e3b,66f780f1,3d1c5a02,5274afcb,bd78382b,b2778657,6888d46,1b5dffa0,f8ec5dd9,3bf8e808) +,S(82ed9c3b,1c76c1b8,f44ff6f2,9f443b20,83f68617,7270843c,49eac0aa,34a8ddc8,262e9e6b,c2ab2b86,7342081d,90002690,e81f5a58,aefd6fc4,8a91dc5d,e95f1340) +,S(919e960e,acf2aa36,e86342f7,742e97c4,9c49b64a,ff5c6118,d181e349,10717b85,4b51a94e,a3ea1679,cd9ce9d5,ac329f13,ef530d42,c7821650,5a082fe4,d945b861) +,S(cdacae3e,20ce551a,beeabcaf,a643ce62,edca3de1,acf06c30,65ffd366,5bc3ec7d,aaacbb13,872b076a,e28c326d,fa54f4ee,235df4a4,b341c9b1,3d322071,6eb95bb6) +,S(1a4508e2,1bd05c09,f3d80f82,90726f08,de3a62ff,b663d5a8,f949ce26,92a5f2ab,52780ff0,976eb033,760459bf,4bf02994,c6e672c5,6d25d3e6,2b320f5,2cca97ba) +,S(8e46eeed,5686f25c,a94f73d1,3f26c98a,e9129f77,f3aa18dd,d5214262,803a0b45,ee56d38d,7041eea7,c87f2ed1,e7f0aeb6,7253d556,610e8200,782c9af6,1dedcf4d) +,S(782910fa,3bd6b309,dad797c1,5b618469,68d6171e,7a0a0532,a92e5bb3,697e4031,ff178365,c44c2a28,e84c31b8,946b0a80,717914ff,6d3f22dd,ee409753,44e4b3f4) +,S(2ab9e8c,c5a710ca,6cc2d0a2,94f1d7d2,65c50aa8,f9069041,ae93c91a,e5f64e8a,aabcd0f,a2254bad,67cf23d,a5934947,18536602,a13d81c9,db23afc9,a7f89b9b) +,S(d04667c4,4fb25b22,8320cc53,35252937,a094ddc2,4610f7a5,fcb1bd1d,6382c9e5,7c93613f,8bf048e7,86af436e,cac4fa86,6e5a91d8,3064f5c,e31d4794,b2b0f74e) +,S(b9c476f9,799cdda4,a51b0476,c5838994,f157bd29,c9361252,def4af83,6e86b0f7,2ec7619b,c77948b3,f25cefbc,46845527,d1a9b0da,a90529ef,f13aab4a,ca97932e) +,S(90bdedab,f13f9940,4b9d8c56,5d64739c,4ef765ff,dee2ae0d,64fda841,286eee85,a9f47882,d9a848ab,4be812a4,8187d26c,7f8bb8dd,b94f7725,5c628104,e0cf21f5) +,S(a0c394a8,2177734,c02b8310,74ebf0ff,ff4208cd,dcd59e7b,a680737a,fc485c84,c4f08932,b4c62f34,fc82434f,e9b7b164,e835cab6,2f34ee3f,d640e5d7,d09364b) +,S(1b0319bd,3896e8c6,284f949c,72e7694e,bd3c2923,ebeac273,b9aab50d,30294c3e,15dbfe9b,17c3aae7,e5f8233d,703b7b1a,1401b672,1da32080,53ed52f,a2ee339d) +,S(9914ef0f,e92f16be,a27a9354,518dcc0,1210eb3b,3a90f2ab,6992e3d9,bfdc719d,7a0bd065,cea0b11,e8df3629,faf65a30,5e671d2c,86332b83,98ddc2b1,b3c4086b) +,S(3a68fa19,5599f638,7dafa176,395c9615,5798ad6d,7ace7810,daaedd13,ddf60d3e,74575ae6,a3f569db,394faef1,e0641ca4,de158eee,9a8ac54f,5cd96bf7,d4e71a89) +,S(b7361d41,e2b67e31,f1872b1,b1bffc8e,41193dec,7f012385,9da69c60,5e88b2e5,fa9d6b95,66d49bca,73cf5890,f6e7acd0,315347bd,f10be9c2,9b0907e1,80668344) +,S(341e9987,42d84640,f6fd1354,3fb7ff9e,aa93a4d3,12e99bc6,37b85b83,25174e81,c49608dc,91b46187,611cbcff,762e5fc1,e95b4e9a,6ed747ac,8612b6b9,8bfcfc95) +,S(83d6a445,de34f557,40084909,402c9718,1f6420bf,af87426e,2a0f75da,c483e6f6,7a86db44,58c8fb53,5edcf48a,14a94dd8,e9fbed09,277db0fd,787c121b,a1dddfc1) +,S(4f11235a,14bcae9,89082bf1,c6a499d8,32d17686,2fcffbdd,a40b84b9,26ac351b,b50624f1,5f31269d,168021c8,37739cb7,8678ded,be59e288,6e963339,e94a2acf) +,S(8fbb5727,21cfe12c,ea685907,ab6e3d7e,eafb3892,c082115b,998e9a9c,d3ee2b89,da7fe685,c8148e1a,5cd8de8e,2a5b5aa4,ef1bb1a5,af8bfab7,91c923a3,66906680) +,S(804ca63c,b9243f5f,76605b1f,53f5989d,286023f2,fc672bd6,3f52c59f,5496c3de,372912,eedb1156,a1b8300e,eaeb44f8,865fab6d,49c89fd8,43170b05,d75233c6) +,S(b2795c6a,b83ca824,6b18de87,5660d04,60b48ed7,1de9bbf5,8cc1769c,2d2a5365,66e8c2b5,88530b6b,4d351044,186a8a01,db684157,9bdc041f,90d0935b,2a49d820) +,S(deb5304d,b61bd914,c0939d07,c0464eb4,caf3903b,1903a588,208c5e05,36d9dad3,18d54f43,e7e45e76,6a4b6249,1e48073c,40507dd8,3f7b3b27,762a06a9,4d5777ca) +,S(111bf502,d177ec34,b6c61d69,63366901,eb79d5e8,5749f5cf,7743cebb,9b7714c4,be80d52a,bc38bbcc,f036bad4,5e47a0f1,7d8ba20,fe6780f0,bf8c38d7,696a4e54) +,S(94b10f43,c15c5393,e8d4e71f,db863865,daceeb50,674d0f8b,161bd38,dcbe92a5,ec55af2e,a34e8c36,5b3f7729,110586cf,8d087dd7,f1a0ae9b,d25b9b77,f5be6dc7) +,S(4627abf2,2d447784,c53e529d,62d3036b,fb4a422d,10146248,d3b1f188,e895593,8b341d8d,6110b59b,738172d5,6651e948,cbea9ef4,c7e8dc48,3a560503,eb7b3e4a) +,S(19ce15cf,dfeadcc3,7375727b,5ddc5327,585dcabe,c172aa80,757ba468,297c355f,506555e,ce829141,736ca9ec,886cef26,83853e7e,5b3ba66,25cccfd8,4de60f81) +,S(75a40681,8293fcae,8c3e97d8,e1f916d,2950682e,16d3def0,fe6dcfd0,ab9a3e55,5292d5c0,e02ee24d,8139f2af,495298b7,4526780b,f39f5f22,a047d155,dc8c7930) +,S(a7eb8b8d,ef4b7686,b47a341d,4f4a7333,88cb82ce,8f3226f1,cbbf79bc,1f3bf578,85d98b6f,e238577c,b3b52bf3,94a72589,24407ca2,86865cc8,80cfc93f,bd8199a1) +,S(a5b9a2b5,dcc91d67,b352d14,3c19f6b9,6c9f8344,50e16c00,e8a938de,b3da647a,f12d4fa8,39850471,64335aba,1260cff1,26fc4e13,fd16cc29,63472f28,7b9571c1) +,S(7999c6ed,48d589a6,5df7c20e,e9b0fdf5,df58d831,78ad6171,57c09cc8,44015cca,156f4505,3706c3a1,c54b3fec,bd3f12c8,aaacaf0d,22755014,5bcb731d,418f5756) +,S(88fe81f3,b708edd1,b85baade,6c05c7ad,42202058,6dc2e8e2,fead379,c49829b1,cd62e24f,b04b7d2b,b1434150,260a052c,8972a8cd,daa1db10,d99d40d7,df727c01) +,S(18fb0eb0,cfcc61fe,423192be,b694a77d,91216537,5087a64e,89557d5f,4fe86763,3cf72b1f,dfe8b565,38e88e23,ed871d7,80f4a6e3,55229922,b1f28c5d,38169785) +,S(dadb3231,2be4f2cc,cff171d5,baf18e76,4719fa,eb5fcb66,d919c86,efd38aac,8d67945d,752de8bc,b0740e42,3a154449,50e0b330,c6a73981,3d9f4b30,f98bc0d7) +,S(f0b9a086,7cdd9f64,6b3aa0cb,e3105ba,7b17e09c,6c1c39c2,d8057f06,a39e5c8e,2b534e56,25e6d180,40dcf431,9821cbbc,3ff91303,c14bdc81,370c9e0b,5ef4e9de) +,S(dc0e0b05,2e49c3a7,e5d0e253,672e8d43,1cd60166,648b932d,406fbe8a,c2fcb7e0,ff919786,8e1c651a,4cd39cb5,6921e24a,223e7af3,821fdbea,86547e1,c7b791d9) +,S(e71cae98,fb6ddd47,35ec365b,515c6ca5,6bea748f,11811038,b74aa5a2,32eb91ee,804ae818,396c20f6,e2fc5bc7,5dbd1f41,9ed731a7,2801d06c,e6682bcf,1d600266) +,S(50d1b5b2,f7b2e4ff,3b594d48,6bd2ca6c,6b5d5368,2079bb9f,88d792b4,d4ddfd8c,556cf4c5,18fa0660,86b9b03f,aba18fd,5c554fe7,4020df5b,6e34bc88,4d5cc744) +,S(c087403e,2bd5d954,df8c5e86,f23f6cb4,96634886,b4709747,325321d1,bc2701aa,9db44987,d8517300,6e3a549,eed87e06,258bc14b,e2b00679,3a2252,a3507712) +,S(dd1037f7,f3843422,de8988fd,3f68a299,4d45f8f5,1e9242b3,7980f517,bd6d6894,ca8e6d61,5cfbbcdd,8b1ab8b7,673093a6,1a9c08ce,56b065f2,54fc191b,25cccce1) +,S(de229a19,67ca589b,f4a840c3,d18f764c,424dfda5,6c099d14,73a9cc7d,34b5ceb4,958fc9ca,84ca63a9,4323f4b2,ae46ff44,a1d352c1,1b8e8be7,2d5115b,54122b22) +,S(15e33c9,cc9d84fa,16225f48,70a35a42,f8a3a3dd,67a8dcb1,143c7ee2,4cdfd9c,413c0206,ed48cd5d,36205836,45e4ad6a,a59a1e15,c7f36256,2f89b9b3,660e920) +,S(53422561,ca3c4d87,2d23e317,3b21ae38,dc010b99,b7ab0fc4,394e408c,a3d6bee0,6ee906e5,e505909f,6507c7ab,779ce1c8,20f2c50b,a71bb8b7,8debb3fb,6103048e) +,S(829dcf4f,9b2c4f37,32800bbf,f5cb71ca,308bf0a,9176a74,a031d972,9a82b2fc,47378200,429e538a,4e249d3c,9f58873d,abe3f8c4,615c5d3,3525f6ae,5f8483c4) +,S(ed6f6eb7,3769b1b1,4923b989,acff97f1,c05594ba,1d5f4ebe,450e65c3,8ae911e5,dfee6f2f,3fe584db,8b98cd0b,69ff6219,d52e2d9d,a372ffbe,18e500e1,a2c38eb4) +,S(47e52398,1fbe720e,8fcd1982,df2b184b,70616ebe,cb4913da,30327205,c0455503,afd2dceb,f360c30f,6820cfbd,1de0de70,179f4cb8,6c461251,5eae2f4a,baf3e900) +,S(b02937d5,8f48e1f8,6f3f1170,f5e880e4,ba10e2a8,c13dd0df,49fde04b,a9037312,dcb0a4f,3e4c8456,316de580,5355e17f,8a6c7924,f68cbcf5,347d3c7a,28c18c4f) +,S(9f993cf5,3578c1c3,25c10c2d,c3c066eb,878486eb,dfdc65d4,4ee57fd0,ec1989f8,c6b8d40b,16b8811c,d666ea43,2e61baf9,e83eda6f,d38275d,9143b386,31c8bb52) +,S(943b6cc2,5913ec1d,f12730ed,bdfd1d0d,ce431784,f36fe84e,599f9b89,dd3240e6,e58102ba,cac2ff3f,d42d7ca3,254ef55a,9604d3ff,fab5b16d,9f77482,4fed3fd0) +,S(9b0e67e,69b3f9ec,51843da4,f7b5a7c8,59511dcf,47f58a64,81fbf2f0,19acfe0a,6a4ddc28,17a4ecb4,ce2defc7,d7333ca6,2e074c36,f7e49c67,4a009d30,edc54dd8) +,S(97dcee33,9cd8d18f,8c3b0fd4,48ca6e6,c8246b4,136bacc,72ae8673,a4571651,6163a205,cc20bf39,8aae36cf,c8933dc6,29b95246,48823d51,d82d2d2,74e693e4) +,S(a1e5e6f9,26961eda,7cea9c26,f4a1ba02,798c940f,2b7dc267,2999ff7a,d2292ced,50274b7a,6a710f74,ed138401,36d97657,cfc07af9,3b9e8fbe,ca18d31b,8d5f19d) +,S(473d5fcf,7cdfddfc,52fc9bdc,6fc77180,1c21bdb1,840821a6,1a984296,5b4884a9,348836a7,ad7f550,feb2d703,6c82d95b,89ff95eb,e8be6250,eba7c5b1,8fd856af) +,S(9c187442,7384b2d0,4fcc33b2,70544c98,db8c1e13,2bb149d4,54c51ea1,4796f613,2d6dec43,970f0079,3da12e47,595cefba,c1825d36,c71342b,7913f7f5,fcae0a19) +,S(11ce1c46,9150e2bf,b742d826,be740e4a,ed63c729,5f5bf51e,c7a6aa6,562b154,6e86514f,ea38280f,abdf8b93,be8b7d92,67f3b28c,af2a4271,aa3b6a62,1f4fa33d) +,S(1e037904,e4e2de6f,2893c354,18d1cc6f,dde2fd71,4bacf1cd,4d9a5c56,79656042,1bb759c9,34c26821,2a28aa38,a0af035e,3c81ac85,3c01e21b,462e81a5,8c960755) +,S(52fc9467,23f899aa,f1a94f24,f9e3620,3f8d505e,31cc6800,9951d9a7,c0071d82,4632ae0,75430820,20cdfb99,270b47ba,39c909b3,4b3a39db,92419697,d0bd6dbb) +,S(cb585905,997519cb,214f9e39,496f5386,35069eb4,d78dea4f,f9e9d803,642b20d,1b9f42e7,a5b475a1,e42a0f51,ce2d5e50,7131b2f3,5990ed45,64e3913,ec93ac7d) +,S(382c2857,29f14558,75727584,5d37bcd3,e7ab180d,a11c7a12,cecae00f,b4a69c46,cb27e912,20a70fb3,6e258684,3f128693,495907a3,e0b248e4,a25c1e7e,54039440) +,S(16f086c6,c2850e49,8f8456dc,eb33a692,a4dd613f,b2f9564b,6dcecb88,4f4e5024,2e152a08,88eb1188,3448ca68,25a65034,73cb5ece,c9ad5df3,12deefed,279339a9) +,S(7589bd1b,1f0a3577,5530f0ae,446ea275,4439a51f,66730950,6eed6177,65a02492,2d840e12,d3758153,1e5771bb,14d3634,4076fc3,630c389c,ad9765,98462d49) +,S(18b9ae40,cce63a51,3dedbd2b,c3beee9,a80cc5f5,a26b4446,9a0326f4,d4930890,24b86a4d,d5ed3c44,71b57138,2b270d0b,9e0032d7,8e0ad18a,cf6a4eb9,2a2690e4) +,S(8c1f74a4,acc71ef6,4030db5d,14be8627,94e9ba6e,102c89a4,ccfe8a8a,d3ebb48a,a79f0119,98aea529,1e3ba735,c8b26c86,1af1c119,92d5dc94,16eb1673,9245677a) +,S(8d80592d,36bfaab7,5b557ba0,d03825b4,2c0fca08,8ec7d046,5cd2c203,c2bfb080,3e479487,91f27453,4d0a1bd4,a533fd2a,7671a654,10cd7a51,859b466f,151d3f6) +,S(eab0bb19,f477e158,ec85046c,f2c56777,f36782e9,e0452770,f7125765,670ca248,a27d7081,23093af4,daf55e56,32ba071f,37f0bd64,3f189ebd,70074cca,7cc04640) +,S(ff0d0dc9,ebbb2fa2,6d3b249f,d5260ce9,9647e1d,db48799b,db532c6a,2a0a039c,12b0f6ae,7f161f8b,ce1c3505,5d9b760a,fad5b0f5,66211023,3c43942e,fab31fa9) +,S(d89a3235,71dbbd1b,92340346,8b08b7be,be22b320,3ee6b0ad,42a2aa96,3837d526,25da35b9,9988f167,3108124d,9e6f6f1f,db4a0490,5546fb62,146b7421,36e3cf27) +,S(f150023b,f01cab2c,433cdafa,86751f7f,13ffb315,55d34a22,9ec4c012,925b43fd,31f70e21,26ac896,6dc966b7,17a9e483,8ac37a6a,2072bf34,1a9c3d33,3ac7a9cc) +,S(d98ebd3b,2d580978,72ae9d5e,2c2cd0da,76f442c8,e0b4470d,9b3ee019,c83af2a8,9ed5b6a9,5a061970,34bf9873,da6c7224,930fb358,a514c823,e0017c92,75dba3f5) +,S(55b62d85,833a94ee,dfc2e313,df3ca816,8173533b,fa77d827,583fb01b,cbc3c746,9f848773,cb95af7,b79eb921,19a7a139,1f4dbbbf,44c81897,15bad111,364a835c) +,S(dfaf4d76,fef73f93,44c69de8,f6c1c3fc,ec759c49,a2a7a1ca,2860fecf,bd718de6,ac4af693,44e2c287,f6409f94,c36d93ed,7fba1f15,195bd971,357d3142,725a0671) +,S(84a444a3,4510922c,37420f29,a16ee22b,a7839f3c,5810cbf8,38b7f3e6,c5fe29da,ef733d80,2215c12e,143f420a,673069fe,6e89af70,cbf975f,a1898550,1114f06a) +,S(d7c84e11,46c87008,3ddd24d1,296811a3,2c337749,83892548,6291aa53,a72212af,b187dd58,a3be40bd,c3d357e5,480aec61,9579b2d1,4d79745,f84cd406,10844ac4) +,S(fdedc27f,a70b08be,f3a9f616,575072cc,c7fca4b5,71a2ea06,9ffea788,5598051d,fe9b7b1a,1c575a9e,354d279,ba7f4de2,53f6f54d,e7245fbb,3ec462a4,7b9bf9a) +,S(cfa7478a,d3f2cc6a,92022b35,58437b3,f950c250,4d96b9a5,c2d5c795,ef122e77,f3e48dca,e9592835,354f8eed,ffdd4c2e,2ad7800a,3da863bb,158945b2,261409c4) +,S(8e9157f8,3fd62097,70fb7493,d7678fce,aa1584bc,d8dde3f8,337dce8,ee0eefe2,6079ba89,8c05dfb6,ba4f91df,4b4b229c,3322fb5a,44fa988a,c8d9f3a5,3a05351b) +,S(7bf5efb6,103eac30,ec4eb80a,9bddff22,9d422ffc,6a7f9dfd,bea8b928,3116f75,efadb659,64791edf,e5935554,25796141,2cba4b4c,3553fe67,ba138931,3ba71a3b) +,S(f5ba02b7,b7b2c2d2,68c7b1b5,37697079,690a13fc,89d1d53e,85f27820,d0e8df0b,66316d26,b2640e41,bfc329d1,9d2d4430,a9266b64,c3c793a3,af7f1515,9e465485) +,S(5eaacdf3,dceca4c9,6d2bc3db,f22951fb,87c10da5,f1250828,4a1498bf,ff004475,cb3db3ed,9721ce09,16985d40,4831cd04,b38f5810,977ea106,c8c25194,ad1f122d) +,S(1cfe5c17,b8d61134,53552ba6,ad513371,d1320abf,4fa2de41,77c5a768,a64a5554,53837cf6,4846b887,1e64a2f7,e319f740,99bcabe6,7a0894,5edea46b,fd1dcd5d) +,S(92a83f47,8a2ccc86,1cc91dd2,a1210fbe,286f47bb,44e46880,5e21f0a3,7a5dbc10,fee35c65,fcd45b02,f8270b8b,c198132c,cb69ff9,ec35043,684f54f5,c999de94) +,S(172285ba,d5d539b0,f4d86ea1,35bdb79,73c07ad3,24bf5dd1,4f74ab69,cad277d3,45abf940,cf356364,e0bafa15,cee3e20e,cfc29040,288b4897,314c22f9,aaada654) +,S(ad17bd53,92e19bab,8554ae08,bf9158dd,3126ce81,3a05c32c,7646eb73,cb164762,a129819,1c833987,775d4f47,d9d70d4f,8139c651,896f9b94,e164574c,8d065586) +,S(10421b3e,91a4a89c,1f6ce9e9,13e511c3,c23fd307,c4064a12,5267cb31,2ebdeb1c,539bb5d0,9e49f0fd,186b8a51,73118cb,98569700,dac77cc1,92359286,3aa53319) +,S(c43adcfa,78152a3d,dcb9eba6,6632aa5,2e8476de,1e0e30ff,39735b06,21de5bfd,6ddd09ca,2122580b,847d04f0,5dacbb7b,1e81c6e2,6057d880,1a911a55,9cabdebf) +,S(f7a99ccb,603a58d0,4c6b9e50,d9e7d988,14434f1d,92aae27b,5c8d9006,98bf9a73,ccdfc244,76f4393a,e96d6809,1cb74130,5e62934c,cafc9b08,78a3a77d,a71a7ccb) +,S(9abc95bf,70174ea3,5038f44f,4a2ca9be,f602d516,9d249aac,b3175be7,e09c826,6cfbceed,3e71f8a3,d427d2c9,f8cedaca,22a9fedb,4cab7763,617198e0,d7adfe0c) +,S(8a7ca893,35c84873,ecb4af06,b493c9cf,d7bd08fc,d0535c5,546bb9ed,5c5d8d82,2518b372,90d3c08,72f1ee4e,54144799,209ae3fe,d2f285ba,7b00193,21e31bc1) +,S(70c8e379,8649628d,969182fd,862f8d4a,b39fdbdc,c246fb79,ff1c9227,a64d1c3e,c7931ad5,27ec0a4a,ec297d9e,fd56208f,936c9517,4efdb86f,7f50e321,26ea3cbb) +,S(d783f6b4,6121ee0,71ddcf61,b4808fdc,934a82e7,c185876b,9572d628,31002121,aa92bd84,14226949,9e107c82,b9a64898,28b3ed15,694ba62c,a031d98b,5e9c7fbb) +,S(c1f06a1c,29abb43a,cadffbb8,7ea8e4c6,b7592795,9c778758,1a17e4e7,7b654c18,1dae0de2,f1db42cf,ab9b0e7d,9e5a098f,bc102470,aa418547,6cd1925e,fbecdbf0) +,S(2ad74e11,3205b587,866633ea,32172662,d1498a27,48698724,87b7e62e,52cc5105,c70c7507,de1fa1fd,625aa7d3,755c83a,b5c85159,4b8bee10,5de45da0,d0ff779e) +,S(f490e9ad,72246a46,6eb74e23,371c4f57,a9e32b57,74ac9ac0,3d800978,d77408b6,546f367f,8fdd1687,ba6ef15e,4c258507,77e49a1a,8b449fb9,63a0f01a,a9dc3d6a) +,S(20502891,8357b697,e05788b0,55f8bb32,80c431c5,de07055,3f123373,981d6149,39d040e5,44110e22,58da6771,2852fd09,9489ee5b,5c77a777,7966abd0,468e3b0d) +,S(6e91bb8e,c169a3a3,eef59915,d4de9296,e4b78299,e038c5d1,bb001eb2,f86eae95,d2c21297,88f8c9f1,16434063,a89fac48,45305dd5,d208c887,2ae94ba2,80877dfd) +,S(cf2947c8,39fc40b0,610d0d2f,e1e5ad53,39e7d0ba,9e7dea01,90678bb1,6ba34905,6145a70f,7f0cd53f,d758d7b,172e875d,8db00f6a,131ec7ba,aec140b2,3f37c63d) +,S(b48f8387,ea93a6c8,561c9b01,ad32a28,1c8db1c1,ac3c6864,ad161874,fa2366f1,2cab333,cbe07d3e,26fd971b,3609cfc8,9f46bd81,df84276b,375315d2,7a2d253c) +,S(7c4b5f66,c572d34,e4cae58c,696fd43c,30f6054e,8145715e,f391eda1,42a1f827,3cbe264f,be125af0,3907c5fc,c61232c2,d0adc2ad,5f94f3b0,8ed32ad,99843d97) +,S(e5796368,d4649e19,6227f989,78758d9,8fe24e51,f5d5a567,378a85e0,850d86e8,74bb343,c9a69128,9ae880bf,67a7e4be,1fa111b8,d6608896,46ec354e,f6c9d4a7) +,S(dfa1065e,fe83e9ef,c19b8841,6e3ca5d9,67c1ab26,53c7d650,9f02ba58,fc4d637f,22d2567,eb0237ba,2f270e04,685e5352,e23fdf19,a2aa0a23,1ec83eed,ca5042d) +,S(2ea1d8aa,d436c332,8fda3ce9,8e710b80,8f463844,cf131f2f,2347b37a,928af132,33fa7e0f,b8c2ad10,580a243c,ccf2a4b2,13ff9620,7a034432,8fc61f31,e98dc4c) +,S(12ae1451,8122af3f,a788298b,5e59df37,ab6a976c,f8a931b4,c0a51de5,d567253f,85ff1dd2,b3271d2e,de2fa732,9e3f0a5a,1c3ff9ae,b55555a7,926d31a0,1d24877d) +,S(fd46e1ef,b588af1a,a72b84fe,dec75a3b,125579ef,55ef8270,85645930,95bf6619,d06adc6e,ceb6292f,60c7d477,c73a2aff,342e6b7a,e81c5ea4,f57cb7b,27a51b17) +,S(ed7d93e,b8c0d1ef,1c49e1bf,be22acd,c7a17946,b172de61,4a290d0b,7f32b52b,4d0ec30a,39a81c3a,f8f6668a,742abeb2,b5552284,a68ce246,f368ce9f,b2303ada) +,S(fccfdfa5,cd0e79a6,9febda81,475c06dd,58517913,3624f4dc,9d808b6d,e9619ef,79b9040d,11d09bed,f89959c6,992a9636,ec62324a,d60e1513,9bd2441a,dd0adf49) +,S(831762b8,6a9b9afe,d2a044b2,7bc714cb,16823ea7,22b44010,a57a5564,4b4ac477,147ae062,8ef3bfdc,b48b3f77,f84dfd77,2754c1dc,a626aff6,9c3169e4,9956c708) +,S(33448c01,a84d5303,c8f70adb,bfe0ccf9,f92cc461,f2656fb3,4903b99d,4ef26b01,e5727349,ae8ba61,c8ca8284,ee7f906,208ad03c,6fd7c95f,736ea541,ffb8f2ff) +,S(920a1261,6ddf1304,157ccb8c,50ebaf6d,60df85da,b19b24a2,48254cc2,7d215a6,19e4d4f9,cc91e890,3d2f7a11,ca8c0b97,e2cb671c,e0c4ee36,9f1a3ca0,f28d0f4e) +,S(1df8ce1d,3e370b9c,3f60ac00,cbac25c5,458385a5,c4b926b7,fcafe62e,536b1ba4,344df46e,e3635079,52af6160,2729094e,3fcbabf5,bc701083,533e7e60,5099a92b) +,S(7227847d,abfe26b8,13c18175,c37a0526,2e2243c8,d80d93b6,286b2881,d38b7b72,bede79eb,33da3cdd,95289c93,46165cf9,28b5aa41,c46b364,622988b8,a7973d24) +,S(6defba59,e1218bfa,b02571f8,ccc84104,3caff74f,26d8d995,9729f292,eff7fb8d,4d7baa8e,21f2fbc5,96f770d1,bd34e77c,2c188c05,5921c1a6,95696a8d,4c340a04) +,S(c667f4ef,f5127d24,6b31ae02,2adf53be,8302e1a,b631a0f9,90b16051,e02d6bd3,3d7bce76,ce11bdf6,fd4d822c,37d746a2,f8de283d,527af237,3e80c4a4,dad34cf5) +,S(ed9e8674,441620f5,990dcc24,23a2ab00,6fbca1b8,e6bb3d23,55c2c72f,ce29d866,64d5ed9b,b4289a2b,b81a12f3,30930dee,7c03dd71,1ec361a5,8297c22a,5806ad30) +,S(86a36c57,e6b0cee0,33c00b25,66344ef3,219e57ee,ac452ea0,b0eeb98c,3176fb24,b4f4bdda,9e9b58df,4e103874,89592b5d,b147b43e,79a1af25,135e8db3,eafff739) +,S(2e237784,45396ff3,a0e105ac,ba151e3d,fd02bf82,1de70e04,33792280,bccca913,f736539c,e77983f0,610464c4,3bbcc904,f43726dc,a336304f,c0b716c3,67148551) +,S(ccd3c14c,7790d936,5226dbcf,11a0bc00,9db88a87,ac2d68c1,6899f980,20a1390f,b240b35f,bd6d5dd9,f33bac2a,f1899320,f8a9cba8,7df0a67,81cdfdd7,1c3af907) +,S(7713be7f,988d7b1,c6c6566d,558978d,eba4efad,b82761b2,17bccd87,3637b018,8fb91a6f,a9d62baa,2eeef7c5,15fab341,c75f31e6,64ee7d94,70db34c2,74475781) +,S(5485ad60,35dcb3b,9520acf5,6b0855cd,34c739ff,1c59798b,1ab667ba,a4982b02,1dec6c7b,1e7c14ca,743df62e,589311bf,57cbd455,e7dcbf9f,cd439962,96a90f0f) +,S(a597503a,d3be484d,1d2d1cf,c4e8540c,411bd201,f2b05ed1,89c9a3dc,b0ee0f19,35113e7d,38001199,1e2cee66,4dbcf490,becbd6f0,765c94dc,e2855ee3,b01113cd) +,S(ba91b251,abb130b1,57dd07a3,dbd2fd91,1ae24937,80c8046c,b94de57c,dd91ce4a,cfcc2080,500aedfb,a69f33f5,4f642fbb,8377420f,e1799dcf,e1dc3593,d3e1f6c) +,S(adfb5a58,83cc7bd3,c6fd3386,95c86414,5c6d2f4a,603fb2e2,fb045bff,86d324a4,16574ed7,45d82dfd,c50415a1,8c30da91,3a525753,cc975722,22a5553f,7b0cdc5c) +,S(1084914d,dd710a5c,ac854b14,10a4be35,ba1f13a4,e0fba3e2,9d94edcf,a3561ae8,653ca135,3240ef60,412ac6cd,adf8e664,2f2b74a3,5908c3ba,be6dcf85,49c25e99) +,S(704aa271,9af38b14,17a8abe5,b881efe,81876a6a,f807833f,133cdcd1,6e6c6f7b,a6fee2b3,48c1180b,c48726c9,be2a1a41,11395af4,42ba7b92,63f4f66e,a3769e54) +,S(46048cc1,7f5d2a86,5c1f5734,893c6683,fe68b0e8,942c9080,51d7b836,a8aec289,d85cec30,89a8f77d,75bf9c6,bb4f8a33,2e766834,3841b277,a461a079,8b288efd) +,S(50f1e6be,315d3b21,636781ba,8598d2f9,7d04ccf,5ba1fc76,3d547657,77fce9e9,f7dcb7d6,2057b9f2,8cc24975,9dc9621f,25dd0ce1,47e00db7,d095fb0e,ee6b0b00) +,S(7ed0a244,676655ad,10efa03,7748d49e,944df1f3,5bd46d0,3b7ffcd0,a63501c,a8377a65,593f227b,446eb266,936ae475,e9b3ae65,a60768d8,2690d0f0,5c18c21) +,S(d039ca1,ee66c2cf,611c431d,cff1bd2e,19b29d3b,b1f37342,c29f4632,4febccc7,db0d0d82,14f4c661,629ff5e2,4cfdcc84,6e652ee1,15a6476e,7813104e,696d736f) +,S(c27973a,cc55fe2f,4531768d,94cd4a0e,8e36729c,aad61579,7beed810,a7b092b7,cdc310ea,b36ab246,c56d5402,9b9e3314,878e1f1,ff7520db,43917a14,1f41c99) +,S(36842942,cce3c683,25472e48,de202d15,ac14a180,3a2dd84,6de0c33c,6446e945,5000b3f8,19ab82fa,3589db9a,eed5609b,208d95fa,ddaebcb,57403b96,7b8f2f7) +,S(d1aa195c,338621b5,19ff3a8c,55abb454,74865ef7,85e0fd7b,c4554ae,6d62d0e9,e7e1dd33,dc293859,b4634576,d8840630,832ce773,a9a8bc88,c2e67251,a7b737a8) +,S(4f423d32,607439ec,366bd6ff,5766ec13,a59b2c2a,8cd008b0,489f267f,5c0f00f0,5e3c7e9d,7ee94c15,c048e6aa,272c888c,b6c3e058,4b4f4ee,f5e1d787,a4e7a9f4) +,S(6bb1c680,ff8991ef,17c0859a,9b5fa9b8,ebcb9afa,af7398c5,9101bb99,7f06c4a,318da775,d912ae5,d17c242c,97615c5f,217005fd,535b839f,189ff3c9,8669a253) +,S(14095d4,4713a46a,5fcb251c,9fbee2e6,bc393423,30303b8b,d0f2d09a,c0096f68,647e000b,3660b374,959e632f,6867c7fc,1c7aa4fb,b7f5593,22dcb2ba,e604a2b1) +,S(12112bf0,346e9c6e,4a8f831f,6c087876,8943191a,38e9fb83,8b2613b0,4b5e5323,e4149ac2,cb4533d9,4c3abf62,aee4dab9,faf64065,89cfe10e,30a42986,9657a3d0) +,S(f99360cc,c2ed4810,d80974eb,eaeb59fd,4f2197a7,8459729b,4f75c370,8bca5738,b92a2f5e,86d77a8a,c2c1b9f8,6e1971db,a06e4414,935020db,c0c83a92,ee6f1cb3) +,S(2dee5a4e,c81a3ecc,4872112b,be53f51e,64ae779c,49488567,a654e806,ea809ca4,1e2ea8a1,df6d47c1,c0aa1bcf,ffcf260e,bdea4d63,934ff3b1,bcb1e1a4,c73d4954) +,S(5baa6a2,139eeb78,f49638f7,b0dc5010,b73688d1,bbd746a5,f2382c7b,d461229,72677383,10a352f1,9f2a75cd,9e42509f,b08a0ca9,60154693,cc01d595,25dca81d) +,S(a3f77eb9,321d44d6,b774a6f3,b1319e46,f60d102c,d96e983c,8f8568ba,82913d70,f93d75df,8271e70f,1aa38630,26bec1d0,f6db1765,77470077,d3fceb8e,5c613a05) +,S(46ba66b5,fa1f9274,378fd62d,68ae9f38,8588d766,ebbe97db,72f9084d,c7f2cf08,5473e24,3078b8df,92df9b55,52ad5055,f44bf7e2,ecf0785b,72db5dd9,238897f9) +,S(db6a0246,ddcf0260,b2b415b6,f551fad0,bccb15c,ca196af4,291d21ce,ce80dbf2,396cd446,f93e1c97,a56c6f6f,63cd0966,5f88856f,e75e1c7e,a985917f,28591d3c) +,S(b82f8d1c,a7a298da,3992c4e5,8dba1b0b,38187eb8,66992e8c,5cc1c834,6e6c8fa1,4b0ae76a,f9b0413c,8d4fdbdd,db767c6a,b1b80589,533e3ee0,28eb6036,1483461) +,S(446e96a4,dc9264af,e9cc6348,aa612861,d106fdd7,b7ff94a1,82e0f018,c485f000,32dfe3d9,21593a58,1fe23b7e,ccf677bd,2771c40c,a612a507,c8e33df0,99568440) +,S(c86f10,7bfa6dcc,b9f00ca3,465049de,5c8a3e6c,d85bdfb8,1ada1d39,303a2eb9,e64f7066,7e910814,ae18c6a,7323474d,9dcb277e,4aaa7ed8,88bae4ae,7c34219d) +,S(bed8eb6e,cda14299,e4cd94cc,202be7b8,9201c2ab,302a5cdb,83e5f5ba,db6cd710,15736cfa,b375a40c,5d367b9f,6692746d,16a1f03c,20941256,708489a5,5d411aac) +,S(b3efa7f2,c5f6ad10,41f171b5,ad759480,665e0a52,de82a881,da1926e0,8f64d38f,3df63c84,32761a24,eb0dfa,ae98e034,b6dbd361,3fb53ff,c535fac8,ff1677e6) +,S(b0460da0,cd869b5f,235213a8,49e143e1,8fa9afc1,651ee921,ebdc525d,2715cbd2,c11a3ead,f3541877,ce73b4c0,2b57b299,46b4725e,cf630eee,865bb121,b86fd7ee) +,S(28b09517,a17452be,b2c19187,12d600d4,b4969253,a7d0d52a,49cec3ce,d73bc071,36696708,73c7591,11163518,40af594,40ffd6d0,690ddae7,fce7a43d,e920a326) +,S(521becd8,192acb58,7ae76b7,c0bf17fa,ad86afc,47157753,6b1a51b0,fbb5f136,648a54c6,d7aff13e,cccf399e,15451682,ee06710e,edf32669,1dc7fe83,75ac858d) +,S(b7bc19d0,b7fd9d65,26c9bca1,b587d84e,a2a200a7,76d39082,368b761f,79f6cf67,5adefabe,e0d0c8cf,4252c29a,773163b6,4a1e9ffe,ffbfe3ad,2f796e8d,1f70acae) +,S(e48e3be5,1b6ca8d5,41f0c241,21558cec,66db7b6d,c13e7114,dc931f0d,397aea8b,dbcf6357,5b16e2f1,30f064bf,ff12b465,f6cb3a3e,f9f74431,4bf41e7e,e0f28ac) +,S(395c6de,71c692a6,a3247596,8e28f2a5,4ec795b5,9759e890,9b2f4290,9f455751,ee5e0118,3c7dda2,c1eed4e1,5aca155f,b5b097e4,499bc3c3,fcfc2c85,a669a13d) +,S(28938ac3,b1184399,22741291,9c0fec36,663da3aa,8a4e89a8,1a66052b,ca808d99,4ae8de7a,b1ebc1be,a2beadb1,80cb9a10,da168295,ba1ea5f8,310b986,4f174603) +,S(5c0f618,95e88cf6,205472f2,3e27e853,be3af64f,d0a376f5,8523ee6b,5248f5a4,be5c3c55,cd09ebb3,b7363456,9fdb50fb,8473e3d8,3441e624,b41b1c3d,e44be51b) +,S(abe1f7bf,22d0f733,ed28e125,f7ed05ba,ae2e8f13,1eba2ec0,1554dac,5e3ca1d7,2a5a48db,3de31f6a,9708ffe4,b996cb33,e553e6b5,95aeaffc,918aa2c4,1ab0ab4e) +,S(c3042427,57d370b3,79124907,ea609129,5f1dbeec,442a6349,bccfd29c,e08d8be7,67a64eb3,3e0fda75,535b35e2,f8c9811d,528959c1,29e8f144,8bb75ce9,b1868934) +,S(65a59946,356f219d,77af0b6a,9e1a43f7,3152746,6af41c21,c81532fe,3140f5b8,64e7128d,5d3e4fa0,518cf27f,c070da20,1692b059,3d84641f,2463a61c,74f35918) +,S(6c7d2e3b,48428c87,46b066f2,bb99da10,60311cb7,d4dae19e,de2eb53f,141413e2,4ba47bf,c2e7c670,4de2864d,1ed7b383,286292fe,28f7c7ab,2a664bcb,6cb7e3a1) +,S(dd257bd,b99c89c2,b47798a9,bc93ff57,5655797f,a45399cf,44acf58e,93fdcdd9,f8d670f2,a9207f25,52e7e0d7,14289103,e8194f81,6390e0cc,1af2ae36,c1b3e4af) +,S(2516034e,b8ddc424,42952b8f,acd47c62,6827b87c,b08f263e,b2aab5e6,ecc23d7b,ad8e8879,f5feea07,ad3545bc,a731dd30,bd2ab534,4b486826,433c75a1,6216ac9e) +,S(7e723054,27b591e3,b19834b3,8211edc1,7f075215,6591980b,907dce0a,d934246d,5c91fcbb,d8c184a6,f21671df,1098760b,2506bee8,e32474e3,3b080147,4e63a71f) +,S(1b1f9d16,ac3c0d2a,4b87691,45a6f6bb,8d4fb57f,ef9df33e,72b5d399,6dd1898b,6442bf1e,5ffe450,b14a399e,16241a5a,15e94453,94519bd1,24d0a67,f35b4b1b) +,S(e0f1fa4e,57cdea43,a3b9f671,596631c6,65b5144d,93c51a23,e9006c63,fc872f2b,c83851fb,54890d14,2f605617,151dd47,74f9a3de,cd27d864,a49c176,af32e564) +,S(ae95bbb,697c820a,251a3667,b2a0a078,40efa027,99d7bd0b,3e9a12eb,32728c3a,e0dbba97,280096d,86ea4da9,45ae509d,1140e0dc,7b803f10,e685b148,6baebb41) +,S(fc8ff885,d52ef42c,1fe529ea,853ff8c3,afad1ae,6e7f1b30,69e34076,682aed31,525eced4,b26e8f62,7b904f1b,3356d01a,9cced71,432ac850,433e0a64,b1e3dd14) +,S(6613136a,459d625a,d5b5753,3a965a0c,ed68d63c,13652546,c629cab3,32c8e810,10f29ff8,24d30a94,b3d732b4,3b168bd2,28b4cb01,4012469b,93a9853b,655b65cb) +,S(45085915,7b683327,c76309b3,96ef3b63,19dda841,f6be1b91,f24f5a37,ddea56f0,b9a71446,584a88e4,6a155e34,f08d5a6b,2b6ebbbf,b4b1aa12,bbc7654f,91956821) +,S(168ee3bd,8f10ba0d,deb82576,cd5e1711,be58af4c,2274464f,e32f3f7,7c8a4325,6eef1e63,43ff409f,a916891c,982f8700,465fb184,5820b886,68b74202,6678b34c) +,S(b3191d97,763c2341,4eb4db8d,eb2003e4,fdd86b4c,6077931b,71802714,ef048c04,b4ac3085,59f975ca,be7d53d8,3ebdd5c3,ce6860d6,37710a04,f885a83c,c2152edd) +,S(da9d5c5b,4e73dc93,3c72acca,1e93f4bb,3ec477fc,f201096a,51ea0226,3a2f8738,7fb6a2da,65f966c3,689b93b0,d6366511,400c05d0,8b0a15b5,b4b3209,a812f8aa) +,S(140e55d2,a7e75678,1791730f,c526470,8d1cfaa0,954e215c,1e65bcc,e4b0dd66,4bfba0d8,63ea2597,91e470d8,1ef36318,87e2d5e5,c897918b,ce805941,953d5b3) +,S(15a9ccf6,4b95cc87,cee9bd01,bfe3d8bf,b438f7f8,66344a1c,f3f399eb,16b173d8,4f5472cd,bdebed25,605e51fb,f0b31a93,5d0ba59a,6e51bf90,e0363c8d,9bb33f3b) +,S(e86e364b,6776701d,b7b3d3d8,fad181bc,c7ed5e91,2d0a888f,814caa3d,88af6e06,22fd460,afc040d,3e995518,c6286989,24a466d1,4a624915,f834c357,4dea7b92) +,S(3c261a98,cd25f0db,2321134c,723ebce7,b1f81d3a,a6d5bddb,fc282fae,5a500eb6,2b8d2145,5e498211,8a4b6ed7,ec96a66c,4027a506,deaeecbc,45535fc5,77abd9c1) +,S(49b6a811,4d55b517,6cbb1f6c,177aacfc,368c3b5d,238300b,d66546ed,f4c955c8,d1b124a4,9f0e7c1,6b8e001,7f1b0b2a,ab94411,391d5bca,5b535838,a3815b94) +,S(6ec8e861,f0d3e5a5,3f9deab6,20cc4b81,6cee801f,f7a43f71,f34a8dac,c525f6b9,42e0545b,68ccafbd,3309c4f7,eb6b5eb1,1e01a871,c63fae27,782001ab,a6dcfd6a) +,S(7342b341,59aca5cf,d305a2e2,a8f14da4,4b527e57,4640fe1a,c08898aa,4595b9ac,b5261302,d2442ee2,363969a8,4ea61281,27f64f40,ac86dac1,21b5d234,53160124) +,S(842b30bd,54ef350b,65dcfc43,df26967c,b2747757,a609c54b,687d30b9,5a686fa9,4ffa9e92,2caa36b9,ecf31f63,f5c8de57,7d594f7c,71e7e77b,9cc5ac83,f336ead6) +,S(2dba435d,d589a7c7,bc3fb60d,495757ef,7c13bb0a,3e91a153,9998e04c,19f94862,c440720e,a4b23cb9,d238eca1,6775e500,931d3e5c,7df853ed,55cd4889,5e8cc0a1) +,S(9d1e8524,8f84ce5b,2a75a457,819390be,bb284fbd,3d035c07,998d3c45,c73bec02,8e40ee4c,c935ccac,2338bbc8,4a8063f3,6d62e8cf,849bff40,1298074c,94eb9ead) +,S(d2735ac5,d1fba75b,d4f63912,11549755,9a7f8623,62e25cf4,e76562d2,d8b441af,bd2ac36,19f9f339,77b7cb0e,5b52f3e5,b4ade86d,1c9fb31d,a1d8fb36,7dafc081) +,S(b0130e38,f46cff13,ad1a68d3,15729395,b27c2b96,e0a957cd,ca63adfe,b0a3e11a,3d9f697f,4a61401c,87eff844,3b11776a,610f1516,4366c1b5,535599a0,c6aa3c4) +,S(e0aa062f,15306af8,b662d8f3,3b89de8b,f59faa78,29942caa,ed82e668,35ec76a7,c5f5f0b5,6ea77304,a5dffb8a,cac98387,34305b54,25fc6181,79a4457e,c15e6f2e) +,S(ed1626c1,a8e6d1c9,187e15c4,ae9875ec,2156d685,997ac413,9f44bd0b,19432d5,3c0d895b,9dcb4a3f,4235e531,ee7373f7,7f0fad46,c5938d7e,69d50429,71f0c35d) +,S(a2cccc31,4e18fdaf,8cc25aa6,74c974f8,664744db,86e04be8,431d2ed0,4dc92833,b6410e49,d6d471ee,d20e5536,8672f5e4,2e1b9c88,c06438a8,46c3a74f,c759d71c) +,S(5bfc192f,db15f62c,4af19119,b2d96a88,b3b24e06,3d54b31f,a35f675b,f668bf27,46774374,acb4e140,90431bb3,9f62a38a,dbe0dc62,4021e23b,6099e198,47d99051) +,S(66842a89,da73c404,32a2e553,97efb009,61eb2155,886ac90e,97dab5f0,9227028,3a8e83c3,511ea048,88d2dc9d,f1016cd9,da171bc6,89c9af4e,90b18091,21941de9) +,S(ec823197,3ba95f98,d45f8991,3ee8b92b,e3a4a84d,d59342f7,1810766b,cdc516e8,532d3c79,f5113f4e,1973bc88,2a953b5d,77d5476d,ac9972ae,f1d25e19,ab7206fe) +,S(3b65fe78,bc516176,aed5e5b6,5f3ed39f,e8e8e26c,32ab07ad,1ac2519f,72fc140b,856d36de,5190eb9c,13f7f976,466f95de,566a1fd7,314cec1b,9c9f7adf,98208d98) +,S(3ac0eca,51c43525,e9e545ce,83fdd009,f9f31eb3,2722b945,18262036,d18cc346,dc72018b,c3b2a4cf,3244ef31,340e0944,325bebc8,b134de50,9ab3024a,a213a7e6) +,S(4929658d,6c50ece6,edd2db7c,217d9be0,bcdac8b9,bb50972f,fbe53a04,2ee23508,e5aca42c,61aabbd4,b8555980,a2328741,6dfc8df8,d7a10c3a,7284bd90,aacec38a) +,S(9d16e76f,4bc96492,f0e9e748,8c6d2297,7830e2ab,491a6278,1d60ab5b,153a6291,e6590f00,e4ac6922,5436318,9770aef5,5eaa988a,44e9711,da7266ec,895ac7ab) +,S(b0649c4a,1327e7fa,f52a9bbe,7ff97add,4e13b36a,27c0676d,5e09b2b8,1f5df94d,991c8316,a6f36848,e072a080,77f75a8a,d79fdd08,1a606d12,b355c3c,3891acdd) +,S(8f194a21,f6303ded,2c9ce51c,44a4a16b,eb39a8f6,5fe13c9,6b7c12bd,b052235d,bd1df3d0,c9af82e2,545afb23,e9a2dc85,c635172c,edfe70f1,bd755d26,9730739e) +,S(1da71a97,cc7a4cd9,4777f6c3,dd5e665b,3872b721,c6c2262a,60e87f1d,efe21ff0,78d17a41,39036e1a,7af2b9af,1273afeb,a4d30e8,66a3e6e8,7f0d0468,4be6a06) +,S(9fed363,e493f262,d3efabb1,c52291c7,e04e401b,b181290f,7a37af3c,df86aa45,130cc33e,e164adff,bedb1827,6a5c965f,53a54f36,90dfcd6c,b3fff836,703de729) +,S(d166eccd,221c3568,199ebc38,fcbb6140,7a601a3a,c1e7a98f,ebb75a87,a7a1e49f,262222b7,e7c200bd,5dcec562,85485434,b0628c7c,ce5483c9,93795f76,a072f06e) +,S(e7853cbd,3e3770c1,cc307839,294a2e8e,b998a56e,393435cc,2930920a,8ddbe0fd,7977e6ca,67147cc4,965d2918,1023c3bc,cff1e7b1,8fa4850b,80a140f6,980e5a8e) +,S(a8b0feb1,cb140201,2bea3cd5,6b1a1f02,51036ce7,423f511,480f49c5,6227a17f,ccd7c3db,9d3ab6db,6cceedd6,d3801c8f,67afe792,c8977b5,27c9dcfa,75ba8a9f) +,S(57ce5dd9,e1815755,31e90579,74f58b98,6d02e406,a846ab26,c9059f6c,56d617d7,cc34c090,4399f316,269598f8,aa8f9aed,829f61f2,5efc9bc4,e851ac63,fe142d14) +,S(479790b6,4f60fc6d,befbbc1d,365ab3e4,8077b6c6,cbf02f2d,6c8b986f,d0f9c858,157f4982,e3581925,dd25382a,e3e48fa6,5cff911a,95e9bf43,5df8b356,87f2f9b) +,S(55abc7b,1ffe0a41,2181b622,813be76c,8ee0a0ca,3cb37b1c,cb265087,fff17c68,bd134249,23e94c53,4cf9e603,a1dd259,606272bf,8283f2d6,69bedd4c,a971d99f) +,S(6ca7e032,8bf5d67a,b804d431,e5f709e,bd3156e0,1d4511da,1dc67394,24d2e659,c428b133,f3683909,6551c2ff,2f870d80,d80aaaf4,6d2b1a69,7722057,5eca2647) +,S(60df19a9,83e9086c,4cbd20ba,fbafa8b2,346ae4ee,9c1ad4dd,99959e91,2df530d3,dae7b854,29f817a0,421c2f1e,e4e8e4d,a09d60f8,84701e31,d7a8b7b0,3b79cc48) +#endif +#if WINDOW_G > 11 +,S(6f18d50e,5ef5f2ad,bad80ea1,c59a3847,5c22ff05,6ba52c7,e1d26d6d,d3686bce,d1d7ea0f,a166efd0,facf5c83,bc3786e0,d3f3405d,5b4578f5,13a336ad,f0d7d7a9) +,S(b634dc9d,5ed51336,4ac9569a,8ddee9d9,fcdfe00e,65e59233,b3be8a07,2fd949e0,d72e46e2,c61b2575,f25a505c,bdc3456e,fdf18976,6562a1a7,e86d036,eb31db69) +,S(5a37fcf0,2dba24f3,e6646171,43dbc5ab,40d91983,69f5cf0e,4fc566fd,97445910,a960d1d8,13f8746c,662a9582,614c7847,33e6153d,2975cb59,c3342463,75c69d1e) +,S(8aaf16a7,37318032,c60201b6,b196d8fd,eeeb8f8f,1aab29e1,1b83ae1b,f112661c,c461ef56,66a3a4a7,563cc0c2,845f2ae7,6d03a795,987c615d,611bab48,ab9a8e44) +,S(456f0ba5,a05f15ef,d93e7f49,e0729c45,1d85a693,42c2804d,9cd4b8ae,af5e3434,a680f4a9,99221a8b,7f46da13,13041e16,13f616bd,84b9135b,b0f7ecb2,7311cad5) +,S(f89c36a1,f1905409,75f146d9,31e12cb9,4bfdc90f,a178970a,9d0b34cb,38f5c741,3b562c80,58e31b92,a1186615,9c1ffa3b,4b1df38c,eb4a1646,579d2375,9c44099b) +,S(7f6beb11,2e1d8600,d8c4903,1d69cfb4,e23876e6,32f30428,9d2c2503,41f3f76a,a1937407,c0925afc,be994b9b,51627b98,8d98ed6,e8cf6fb9,cddd0ec,a4ff4a9b) +,S(905ad0aa,b585c7c3,78b7130b,ad1d5001,1010f543,194f40d3,827dc606,12d73511,bfce0701,c3ddcd38,150130ae,e91d16d4,a447821f,a2e098aa,b83b8025,b7177a9) +,S(f559c2d1,62122fca,7201e7a3,b6033d1,e54187f4,7550b2ae,f1d51521,f7408b6c,3f10d622,dfd0eb14,7f6f04dc,43108273,7695ea42,38ced7f2,5dc167ad,34154481) +,S(19b328a4,fa17149c,ccae5830,a8bedf53,7c0d8a0c,c3616345,6f4d91d0,718ce8b4,9a1ce80a,2a4e6923,69925883,8e786779,fdff7f09,25d68855,12644d04,9e582f64) +,S(afab98a0,e75619bc,ebcabc24,c1a6a0bf,2743d4f4,921fe53,3a393648,adad5d4a,bf1b3a87,759139a5,79741c09,21f29a10,7c8e5be3,13d75715,7dfd39be,923a32db) +,S(c2cabf7c,1d86a34d,addb36d9,c83a8ec9,b2dfe0ee,8176d085,cca91fd8,ee4181c7,5b32b724,53f1335c,724465bd,6eceb8f5,159ab150,e9c972ac,f51d27aa,4d91070f) +,S(92839424,8e847452,29a8c534,7c14355e,4f6e9cfa,2c1a2be4,f5ad6cfc,2a89f593,bb9c585d,fd41ee06,99ca7b4a,146faf68,51983b15,d652e996,c888a171,7c8c3a07) +,S(bca2853c,389ef184,208cba64,617bd7ad,55e55f12,d0c9fb4a,a8dc30d0,c73c7dfa,9f41289e,f32aeded,3d45952b,16a62fba,fe9a142e,1e65340,17588d79,e1df63a2) +,S(a4ea7bda,94b565a8,ebf53aea,5ce672c5,5745b7bd,37ca77e4,a0e4f281,71bf56fd,c9507485,1405ea90,9b9e1a28,42c5953e,629eef31,37bb0fb0,970cce6a,893e96bc) +,S(71707d45,af71139e,d7327ced,89a2403,da57c18a,8527bb1f,f754e78c,60d5e169,24b36484,fe4da6f3,a3f4e4a8,55a477dd,3eef0f39,fd3c585f,1b9de9d7,10223ef9) +,S(52c1de03,296f591,9d5cf4d2,36b8ff51,5b1f5ff6,d73228c0,7dda706e,4fdf9a05,db958d59,d73d574,384066e4,fda3b785,c9509714,90607c51,35d1d34d,5a344d0e) +,S(7b09c0b0,7852e845,30691989,cbccbb87,74dc2007,df827120,d8b1ea62,2368912f,4edf5717,ffc52817,d0eebeeb,782ba4d,9545a5c,da979f3b,e9c09e84,f82bd263) +,S(e99870ce,b29ad1a8,2bc08834,3e3b3c03,f26e7062,66b32540,681c689d,ffb8300a,8080ad92,78947d65,bcc12dbc,614d17a8,8ff75e3d,91230fad,c6f785a8,cd597f9f) +,S(c7e2326d,e28b8139,85db4cb9,c3d4c5ee,2dd2c2bd,2b912444,adc3a434,205c38e7,5f2863f9,cdc0cc95,1fb87000,e177cf05,d31adf8c,543d899d,195bf5e1,c6ad940e) +,S(883596c8,4ca7bd78,3c586bfd,28fba489,4c6bb66b,5ea52244,1199b55d,3e3f7965,fb114be8,59255f10,c96d6d4a,72945ac9,47a22f5b,68ecfac6,9406bce2,58e9282e) +,S(7f73a648,a19640f5,b0f029dd,37e56e7f,5cf61659,5e532dcf,7ffeb7e3,f20b42cc,4f76248a,f931aedf,b4e2df3e,ba3b426d,8ef191b,9d59507f,4a94ffa8,80ff4feb) +,S(c89ee34a,3660d03a,ce3b5604,1196a66,18c8739a,8a4795bd,db9c382a,9741aa3d,a4a3b888,35fbac57,f2f79ac9,d0ef292f,6838764,b99de084,684d1b95,12923884) +,S(24be4c56,d7dc0c4e,50050cf4,31d81f19,b5c46889,430563fd,566c4ed3,d941d5bc,e07236e2,4936315d,5f0714a2,af1ad769,f6a5fc7,a56fc1cb,ac09a085,f29e6213) +,S(6c31e71e,caa91c00,798ee5c5,3237a9f2,2866a91d,26936852,c4eb9853,e40b94f5,65aff323,2b5f2cd1,c1117e0a,c30b94e9,34543cd9,480f7922,5723c385,9ccf8cd7) +,S(506c373c,8479693d,3e03c022,9b61839f,e470a574,d31fa286,92601ed7,8e58b7e7,4fd0bfd3,a57c5035,268bd4ae,707fee83,e24f8676,e0ffe3ca,1673faca,1b7ab65) +,S(59d9a5f3,ea1a6cc6,16e7b097,871f731c,57571a09,1dc01b45,b48c5332,c98349a4,94ad373e,ee6496c3,263c348f,a7ee539,53aadf13,1aa6b638,21c16e0d,55fc8447) +,S(a524cfab,65371648,f641912f,a6ce67d5,c6f8929d,366448d6,4de381b3,22d75c69,14c26ff9,87fbd599,17a6ae90,bbe7c79a,ac1b6158,c3f46144,71aa36a9,45782823) +,S(126c986d,f83c6307,87c0d3ac,6a6b2393,8aa3fdd4,df26e76a,92af2c65,7f48c550,808539d3,a56a6f8f,3bcf04dd,31ac72e0,3f74ab1d,5e9afd39,7741656b,3d4c5c5c) +,S(32cabbc0,1aebcfb2,7e1a9d5b,4cd05550,d8ff25d7,b9a81db7,3188474a,ce39722,7d30120a,e08031c4,12c070f,6ee6b52a,be191021,faa9f5bb,9576feb1,8fbccee9) +,S(3fde1cba,f7ded6f8,a98975ab,ad5a64aa,8a9f0864,16dc25da,359e1cf8,22f42c64,e50fcac,61f0f174,b0e93cae,691212cc,44ffeda1,60dcff91,9ee3c960,2f5ac075) +,S(9cad22ca,d6c3dfbc,1d3a08d,6b102727,36e9db37,1ee1f26b,3ce932c7,11462e24,5ae84f1d,873dcd04,7f0781cb,aabbb53,422bb119,4e59d5a6,8824db95,50461c6b) +,S(9859020,aa807626,3a8ca18e,91c1afad,c20cf9f,9249c24e,1c652d19,7d5872ef,454323fd,21ab7d6e,470976f7,2d85fa39,a084e7eb,b332edd6,a3d054b8,d3c73e69) +,S(821699a3,e7cbcbd5,a2b093b6,c825281c,ac00bc53,c44b33a9,d8c31b9e,464eb2b6,f7d59c17,2400cb9b,72b44cbc,bbbd3e9f,e62cf451,bce6f840,23b073ab,66a9726a) +,S(bd06d4be,36423862,795fc7a5,5c48ceb8,440b3cc3,fc286dad,74ea7f6d,8cd370d9,3b09193a,fdcec88,ca4a5663,2cbb808f,61bb1253,fbcd1714,accd508,6183b90e) +,S(2c7112e7,9c8cc78d,f04a4ed0,e043c6ca,bb4b734d,9177f822,5bc41123,4bbdf4d2,c81ccfad,d42e2248,7612884a,d900f61e,bae242ef,65ff1afd,6e03ec42,38391243) +,S(51ae390f,a65d772c,833cbb8c,9ddf9ceb,b7f5236e,f1983905,762b7aaf,e122131e,3d7c9f80,80406b06,282f2a88,87dbb714,f1e96e1,e84eaec8,1256e1a8,ed7ba06e) +,S(c59de112,de237a43,2bcb8348,e3b31356,c7432672,6b9167a1,77d826e4,dacc59ea,36109f16,7c5eb66d,9f09c1d9,c5e1676c,aa33e403,a8e052b0,2854c689,d5903b25) +,S(8b99f23a,b7509d9b,151cb89a,45753026,77ca1e6,9219f0f7,57d01823,f556d978,86a31aad,f53afe44,f533cf0e,4bcd573c,d338e12f,904c8e9a,dc8e0080,f56a4164) +,S(4c670f65,7d6fa9bd,9ee4135a,1ef1882e,61f5fb7c,9deea717,39fe0ab9,78369dd5,531a8226,5d4b5363,12875dc1,7f891d1,b54e0435,1b539dd3,c100b797,efe65417) +,S(8e967e35,9daa0f95,fd7024e6,e57f0640,36aed9dc,9df0f33d,9388cedd,e0f38548,36f8055b,a59afaa5,8c88b833,ba110381,45fa0ab1,f0160d2f,1f1a1765,190d218f) +,S(3f611915,9c45a37d,5c7bfaa,cf0cc959,5e2e097c,8c7bc3e,c82e9e33,3b2ac9e1,c80134a,b7437dc5,23e08757,8eeada53,b9d2f3ee,25b754fa,f6c32e02,d597d7d6) +,S(3f59e49d,7c61412b,53fb203a,c7ebdedf,66bba683,87070745,9f85000c,f47641d9,bedd7088,4243dfe3,d238f101,f5dcd4e,64cd0978,986d50f2,ae3e2563,a43ad5b0) +,S(5b7d84c9,b64836a4,3bc44b5b,fcf170e9,ad46d4da,197a2781,bbbcaf87,5bf6d490,9f55b29c,c7d6b0ff,facb8975,507df04b,f2164e5b,9928156a,7c73fec2,b34d984f) +,S(e1ee74ae,ac3e83c,f73bf1f9,aafc3eab,90decf0d,a071aa88,962c29ea,51744b1c,9e86d2f8,b34e8525,568d674,8839839d,eefbe15b,80c66216,50acc508,f1277030) +,S(fa1ccd5b,8d489448,e3196c22,e96ca7ed,eba721ac,beee200e,5ddc496b,6beea871,e2b7f59a,326a6654,9d6479a8,a7a56d7e,8513504b,fd2a9829,d25e5855,2f9bc469) +,S(ef1e1cd7,f386096,1f6199d1,ab4a63ac,b292316b,f7a5e7a0,4c9f0c3a,7bfdc8bf,4cef9c01,a9de111d,8395dadc,e411e532,5783d377,559dc687,eeb510c2,ba98ef05) +,S(db714eb9,3e75d3ba,dfa5cc4e,d4813db2,fe9c395,95a1ee8e,9b3e468a,e1326120,3dc49a86,b81278f4,84d30311,c8816840,fa3cb701,665c067f,618295aa,6a71a206) +,S(5997f38d,bd572858,43ccf936,ee9d3feb,d70c79c7,9ad1c452,29af32fe,e6ea5d5a,adf7d862,b716011b,b9749e08,965c1ddf,1f44b678,df548eec,45a69a56,97e4a224) +,S(97d6f6d9,a920577,7b08ae66,6fc1fc7a,956654bd,3bc6c039,ea4eec3d,3bbaeb92,b450dc47,ff219854,dad5ab97,13dfbbf7,ce03fedf,4e7ffc68,4bdf1b5c,c20068b9) +,S(4f453fcd,5ec8b72b,69549ae3,c4eef99c,40232bca,1d6b10ab,c4b00d00,5ad307c4,aaded568,c4a8bc87,c7a442ba,f960d9e8,bd61f15e,d668f816,b94c0d2,9683f7f) +,S(5a604a3,50593035,c71c0a6a,caa7946c,ae4c4490,c0db71e6,49972705,949424d6,e578fc12,6d8701a7,a02b92b9,3fa89d09,ae82779e,2f78586a,8937a6f4,133be9c8) +,S(3f3071a2,916832fa,1b64cf0d,5b5fe8ee,2de601c9,34e08498,5d118696,7c635b3,e915b199,baeb233,b22adb6f,69df0e43,8712f25c,1be4470d,53851e4,451ad3a3) +,S(745bc1cd,643189ac,fcf02c5f,bf99c222,f7476a6c,2ede6c45,31849491,901c06e5,59a2bb4a,8703775d,e9a519bd,10e59db4,be16cb41,d0275d21,87291d06,d29933f0) +,S(bbd06e8c,adb3959d,853591a6,6387989,ab396736,8a6c1942,17580911,2637238e,ae0d8296,b484e5f3,dc46cb88,90b86a4,d562b003,a65a0c2a,2b4eded,38b8b690) +,S(fcda8db6,128dbe66,850b7e43,63a3b35e,9f3eb569,b7af97a3,85e53fd4,922cf07c,4bf3ddfc,37a0f9a8,5f758ee1,4c4d5c86,cd11f1e8,2a05ff28,3a0f535f,f9551974) +,S(6325dfdf,fc9c7ded,2a65e113,27210ccb,4ed2da97,4eded570,5ca1add9,9873cce2,89fe4c99,683e6fc7,170ada7e,26179fea,7ce1930f,af1a7358,4d7d56d3,4cf222e1) +,S(77594ca6,93495096,3ab5797a,5279d0a7,513df59b,41a3ad59,245e3f29,22ee0d7f,195eb112,2ccfbfc8,fdeddf45,ef2ef58f,631df03b,ca66a4a9,5818dd83,e5faabb2) +,S(f356ec67,ea9b242f,4f1348fd,c6592772,e2defd7e,308427b,ede15452,baa67867,3d2265b9,e23f8ea4,9a2b7145,9c98b03f,d75a2110,8f104121,e4a2fb4c,d633ba7a) +,S(3360ae12,9b0fa48e,c78e3091,4f8ae6f9,86149f0b,590a12ff,cadfdd2e,f8a205c9,79b37bf2,720d5a11,3ec09872,22b0a626,3d7a2051,e337cb83,dcb52df7,25d18a34) +,S(44e90f52,c703c50d,b331a4c5,fc47613f,b29040ab,9ff0f282,3fc15ad3,f9e8727b,62dfb341,92653e6f,636d013a,718932f6,95c2491e,26d16feb,4009ec05,e2f55f17) +,S(e5d367a9,b5c3ae22,31195876,4b28fe35,c9e04289,518aa09e,e7902b5e,4ec84047,ea1b257f,1abf0fa,6fb37c06,907052e7,fbbc06b4,c2382ace,9c9a98bc,e6f8bcf0) +,S(8478e8fd,7910e5ad,3c061e6d,422806a5,559baab,e083b8de,1005413b,59a63957,4f793418,5193499,13fe38c4,514bd4bf,2f3f1ebd,b492fd5c,fd8c1bc3,1a2df1d6) +,S(c38327c8,587731b,f5b5e224,79c9274,10c97dff,f6855b6d,c2ccf761,2a84b42d,eb03afac,cb1b102e,7e87d61f,5012ce74,a213fefa,b855db22,bc657d52,4dabfcd6) +,S(b9e8a812,5348a672,558f48c9,d17f28a2,4662b4b6,604ee14c,d622b521,bc51f10a,35c2780d,65fcd07b,51ea0224,1771b523,3813e7bb,97a1744c,e3dad732,ef1ccfee) +,S(a54aa2d5,95cfa325,38d2e483,70ba86af,d3c3b53d,2141b0fd,cc68a729,a5cc713e,bf74dc6e,63c02b2e,e676b9c8,6a851a48,7e9552b9,a32eabaf,4e1faa06,8bb8a159) +,S(d45fec3c,e2df54eb,844ad145,fb8884ac,420ce2ad,85cd55ea,4cc19e1f,da9fd956,ed8cfb00,65aecb6a,6901dbf9,b8c208d4,bf6be1e7,ee74a08d,205c48bf,8cb81bd6) +,S(f4b44e98,f728b318,ca959829,d4cd836c,5c0136ab,8e433101,87be24ad,53192172,ef5521b3,960bce49,2c841fd8,8cf7b8dd,2febdd8b,f0aa64e8,4d3c2a09,89ea9fa1) +,S(dec6d1bf,d349110,faa0cd40,e8533078,dcec40c6,e260b9e2,8412d424,353d67e3,73a16f81,3609c901,71efe44f,32ffc90f,9451b0b3,24107b72,54ca2fba,65095895) +,S(1fbcdd53,72e17c41,9310b9c0,2273534d,265f1c24,bc1a6039,238b5b7a,b3ff013e,9cf4ff4a,6a61c11,20c4d14b,97275547,b2358f75,8a2a774f,22bc77f2,4c6c27ca) +,S(d9cef0cb,38c6ed7,7aed53f4,93a31daa,50ea1ff9,aa43b890,357012fb,e2ab593b,32a416fe,246872d5,b68e6654,7f19dda5,e161cd13,ed041486,4d0c2dd,3653303f) +,S(1641b549,88e22a18,45e2135f,88d2386,4e2f607c,ce33fcce,de174a60,1ff03da3,edd3f0d9,ed718767,3664e1b9,540f816d,48e3ffd1,cfad86fb,5b68dfbd,7d94922f) +,S(99ef6c16,3c5d9ffb,1b638b21,1ef60166,37938f83,ac4ef76f,96c5366c,3a243cdd,6b6eef62,d819581d,e1dd7796,df043e02,7f912bbe,6ba1e499,a311769e,d6f66b48) +,S(49358d2d,c24c2e8b,80ff79b0,9c53645e,b9c47fb2,8ea4ffe4,e2f4679f,5b5bc97c,512a14a7,f9df40eb,ef7c1cbf,f8e1caf7,b8c80748,7bee3865,37837cae,dc1cf5b4) +,S(e31d3fcf,b1dedfe9,2549c5e1,a14cf383,c8c122a5,a430aee8,a4eec846,7ceb206b,7bc3c266,69db747b,a3ad1dd,e83464f9,effc4dad,b4de7687,e6c3ae56,a5b0449b) +,S(a82ec9d6,ac86bcad,fbb32e66,a28d7483,ad1fbb7f,979a15d4,4e324ce1,86c64adf,bac87d2b,c28b1ae5,f4ab46f1,ac779936,3a9efad0,b1e1f81,6c4ec6d3,cf74c89) +,S(21650994,2bffa2e2,479ab82b,18cd3aba,dc370c3,18c71c08,1bfb53d4,c8ea113d,97a8246a,2f653450,be513b6f,62419f90,f84511be,9a5f3103,feca77c9,c81fcae3) +,S(735050d8,208d9688,7fdf8070,e448e905,e4e666c6,3db5857f,63ceb362,c6dd4b84,2e3fb438,563661c9,e6fe23f0,7c8219ac,216887cb,ad307918,90001f9e,2ab9e2e9) +,S(1d021861,e679dc08,a34c3813,bb9c3e9b,65f87800,79dc08ba,197b3b66,47afe506,14b6d0b9,2303483d,9e92cd0,e295bf08,4a10e84c,ee0b7c50,ceaa6ba7,a6fd2f1f) +,S(7a7eee74,86ca8973,a858c15d,54eff96f,f91c5577,4985433c,1bdc4f4e,46d7810b,5e83a07f,5d9150e7,a7f5057d,87d19ccf,448fed1b,bc1e2297,c7012cbb,77b498cf) +,S(811c3d4,fe0a3061,47c05cce,32a32ada,48593802,32f24b51,f50e726d,a702beec,a6fcc16c,6c9cf4f9,2e84214e,35ad8577,b28e599d,31ed74ef,c95eb2bc,833d9f0a) +,S(2ca14438,89ea9e8f,24d5b1e,e44b26d3,ca25ed08,30ae950b,4357da49,21ad606c,7b48a6c6,92d8a29f,a82c656,f8e6213,c5e90be3,7413d86f,42e10e63,1026c551) +,S(a980ffe1,61041afc,339566d2,957e6624,5dd3e0a5,deee9c80,d57b1f1f,390277bf,3276f7a2,a139343b,87744079,7a174d99,457d5005,71ce47fd,10e41456,7a1c64c) +,S(e570a3d9,cbccb74f,c582954a,998d9371,fde41d98,e65de6bc,9579d6ea,d9cd80bd,5a749177,6658398e,99d3035,12c168bd,9400bc6b,c7dea2df,2739abe4,16973a52) +,S(f5fbaab8,952cf50e,66d3d985,d9280bad,71bd25fb,662358c9,72b954c3,7bce1110,1aca2123,6179f821,a4f097c9,b48a744f,8010818d,3ac6cf,b02f57f3,1fd77175) +,S(2e5942fb,ecbda8ac,15408d25,84ab7c75,6f9e525e,c4dbf375,5559dea1,718d89be,95106507,d14199a7,8f123d6c,f6b59262,30e12a1a,8c0ca016,40c556fb,14bc790b) +,S(92bd04a9,891c99e9,6c9e7f64,a9bab705,a9fc83f,a739413e,a2f33001,b55dd296,cf5e3733,659bfd9c,e5417ba6,817b6a0f,5cc71c34,22165fbf,13019fad,822ba587) +,S(30ddfd9f,a50feae1,e3cc5426,93ddcd62,4d0e52b0,867248ff,ed7d3041,a7b11083,ff15d0fe,2bb183ef,a18389e3,df4269ca,21bdfa0f,87ac641b,14bdaf66,26eb42ed) +,S(8cf5150b,df8ac68a,af319688,245719e4,67ddddb,72fa7f1c,baf39de7,252a9f4f,4c28497b,a299bb19,83b18bc2,508c98d8,2a9963ab,4145807a,2130fc05,4186cfd5) +,S(1f4b4efd,50974efb,3caed9f7,4f6dd979,4a8e3c09,8decc1b8,69032885,265e46c7,6c4b04c7,f7c6b00d,c38adeb8,a47c7c0a,68535229,26500a76,ee1c6feb,179fd399) +,S(9d524900,979afa33,8d5883ba,d13d038c,3f915cb9,f2e29a2,2a028b18,d091af81,409a113c,37c732d,1104453d,6b161d33,db3257c7,b9a73e1,e0f1679e,6802be38) +,S(52e1e4e4,46eed9d0,fd5c124c,1c23403c,5b03984c,f3fb0734,c627f34b,dda2e3a1,674a5731,7375ffa8,c3c4104f,12c1713a,e2dbc630,75a77e5b,26243217,88320a7) +,S(827b171a,8eef4e31,e6ca8b6e,7c6e36fa,e0a6c93,a77d7148,fd22f7a8,16401c8b,65cd85fd,d9b801cf,7de6d14c,b78ba114,1d58c7fa,129f9f08,8275f364,f7ca7540) +,S(124f45e9,61d89642,6a1abc32,e582e246,3db29954,1bea0383,c83f917b,6cdf2f9b,734e2fe4,110b65b1,2d60626f,c6288f87,e48e7a7d,213a4f83,58bb4d67,978d6c62) +,S(3b71298,18b2b324,10e4f002,899204c4,fb4ac9d6,c08d1169,5f5f5699,9a4d67e2,28b6f78b,cee16b5,5c010c51,ec465609,54ba6368,a18ae218,5607c1fb,42c27c3b) +,S(d271d87e,63b5363,e664485,ea6ae70e,e2b887a1,c7f7e0a4,290033b5,512d8a00,65d43804,7865e280,273122ba,8d8644d0,60ef5927,34971c9b,510238eb,9d6da847) +,S(1d1c6d85,2db35160,67cd2d82,e2ba552c,c5ca0c9,ae7bd661,e8494b25,cdc03a7,bc31f4c5,673a0256,ee9b6840,7aeea035,e19f874c,bdd7aebb,ae8b1005,4e691f62) +,S(8fee89b4,71e394c0,ddad274c,ba07de4,bf8d2ecc,695647fb,1d3756fd,46efdd9d,5d5ed0c3,8479578f,d17ae148,7198f9cf,4ba5cf71,46a9b4c4,34ca62f1,bd2b8c6c) +,S(681fcf09,55a0f351,6026302c,ce3ee475,8ef9385f,908dace5,5d7fbd30,8810a6ec,4307f75b,99927624,80187edb,c4c6575c,aa54e8f4,190f0885,e6d358ca,2a38faa) +,S(717fd6dd,fcb5a71b,6a584a28,904cd3e2,6f6c1a89,7fc32918,90792937,b3a6971b,b403f829,71d4ad04,dfc40553,27f6da8e,1b05e25d,341d6511,d7cd859f,58b17992) +,S(f2b95723,94eb9786,dc1f4998,6ad8c340,d2983279,c7323a34,227013e3,754f2ff6,b553d381,3efdcd41,7189645d,d9917b73,bb69e705,e7a6520d,dbaa497e,7766763b) +,S(58714be6,d7d86c89,65309b52,414135c1,9ab6fed0,1d56d7b1,4237485d,96730b1b,c011f34,3e38ce5b,deab84ab,f0e31537,4039845c,5fa4fcf8,1c9a4d5e,6fe3e533) +,S(d33ce5ab,c828f8c1,b9700d49,e9c6b4fa,b30819fb,b2bea23b,7f915bc0,7a6ff3c3,739b6222,39134988,22372ba6,3fbe22f1,ef59394f,37db956f,caca4c11,75a23395) +,S(82202e32,fc7d0128,4eba58ff,42f7d94a,24904808,d6f920d5,9837b26d,63b55479,fde63954,50aa55e4,fcc4fb0a,8ac2c880,63aa3202,9a00004d,edd033b6,2563b4c8) +,S(25e63218,5bfb4c88,fa300e37,c8b64a,941e6487,a34262b7,419fa7c,2dea7781,ae696b07,4802ab99,4df2d84c,c6731d7e,9caa124,548c2a11,42ddcdbe,f716e640) +,S(e0336a05,b9254e1a,f2468a36,343a0dff,9da8773a,1efdc487,53c1a95b,605c114e,41d75960,377ada38,79b97455,346266c5,5ba05915,9ddad050,d96d9d8b,afb12a18) +,S(843363af,7fd2b1bd,1c9a9253,e42489c1,34ee875a,db57b752,62d731aa,9a996662,e5c0a2d1,dbfcf013,ed4bda36,f153a328,12c4b3b1,66e48473,4d2d3562,ffcde6ca) +,S(adb210b8,1cdb7f18,f97955cf,fa7e5763,abb9f202,9d283c05,26df6332,951178de,2c211f05,d8182aa6,d784721,948afa11,364db5ec,2e1becf0,68eb91a5,74ea0e35) +,S(ab0c5fa1,a2fe2235,ee93854f,59a13792,2034604e,5857b6e0,88b65142,f24d7491,e54725cb,e36d6e15,71ca7384,7383553,b9dc48cd,eca6932b,8d92f785,b80124d2) +,S(3e5de77a,1d2163e4,3f3124b0,af4f5473,868a080b,67acd835,f9cbc88d,7885deda,a6ed34a4,2f9503b8,b83e66b8,377f514a,e1927dc4,c37ef6d2,254e651d,15746630) +,S(60c68b3d,31d1d326,5b71f068,8f32f671,32184815,f83a9ceb,50eaef6,4991ec05,977acc61,9f7d24c8,a95aecbe,987737a5,89886729,500ed32a,9d760fca,7c00d498) +,S(21b052e9,b646e595,b6c04a76,a66b9b25,4a126729,6bea0654,64fc5b31,69c135e2,1029e4cd,2fb3d717,6e87292c,4b0dfd7f,18db6ed4,59aa9285,38f0989c,540779e7) +,S(700caf3,7c664515,ee501e66,60be4cca,f58bb2ef,5b11f79d,c027dba3,7b523d68,7df76b88,f1c346f3,2e32487c,19957830,8eac9b7e,56edc948,e1a934c7,6fa08be1) +,S(c5ab9bd2,1293844a,ce5f1c9f,56458315,5d34aeaf,565a5696,29969664,49541e8d,2d2081c6,c61d6c8a,a0df4467,8ec53a7e,9b34d90c,57db2f29,c0361304,1c422d8) +,S(8afc3f2e,d53f5dc1,448d15af,8c2151d8,5713fbdd,5d46a3df,a4ad376a,16d75a3,11f6393,2627bed9,e015a99d,42193e6b,6767c513,f3457897,64db1a4e,4b9b6c8f) +,S(414ad9c6,bb55eadf,cf4cf729,27ae3682,c0d69867,ede9f4d8,6e173c50,3a5007a7,c4bcd0f8,f4de9b1d,1102306b,667a546d,dafb6f82,edbdffd6,181dd3a0,8f603585) +,S(8211e240,b84b7317,a9c5ec88,fdc426d1,a163a2d3,aaf088fd,b2317247,cb04a1e3,ca76a59b,b268bf51,4f06c4f6,d5961b33,a74f10b1,70a9e9be,4e7942ad,26722bbb) +,S(a54dfd32,363add3c,75ec4452,3094b27a,3f7cd291,43ee52f4,29e59daf,22ba700e,f160822c,59510098,3e38d130,49b44865,3639ac74,6a93ebbb,2798d92e,bad4490b) +,S(77d64c55,52b29b18,a7aee1a8,1e1e9d3f,e2921a43,cfbd95e9,a3ba7cb9,498860f7,e97bb8f9,5ea9c8f4,440ad9d7,36d9a06a,fed03a9,cc96597,8d06f2e7,8208ff10) +,S(485b3814,b33e6bf1,1f47f0f5,f0e5a189,1b57c103,60f13d61,ba7947e1,6e309ca9,e6bb7870,ce607c62,a6050dd0,946c8653,f998576f,2c781b5f,15282632,4e38bdb) +,S(ed2381ec,a90a78c2,def618be,1b6edc51,7ced2ac8,14aee9aa,b0a7068f,72739c,cb0873e0,ba326452,380c291e,c635381e,d6859916,2ca10fbc,3de45ffb,134954c7) +,S(e444af79,d36bc127,c83c7369,a4cba0fe,955b6a66,8f2e7a68,4a65e57c,44ed971d,a7876f03,27b6823a,aaf55ca1,6a48998a,ec50e5de,10d34e9,dd7c554f,d3785fff) +,S(af8c34d7,7de75a2d,5f64296c,152fea4f,b8677b8a,96cb278c,7ed7e50,69fc1fca,48ce5862,ab6ec1a8,ce55899f,24632be2,f3c451cb,8b81ca8c,f9ecc3b2,2984d673) +,S(e999d466,243a44ed,18e745a8,1da04a31,8940c88,760480cb,e315436c,f67efe13,f41e8e70,63a84661,c22ac0e7,5cdedbd0,ef55d3eb,7fa813cb,2f7d1fb0,237fe36) +,S(c40ef8aa,7d8964ff,a3cc923a,2fdebec,72cafaa,58b72d66,e209b644,604bcc72,480e35b5,6549a1e6,f112c3b6,176f3378,ff50ebc7,b3efac2f,696f0627,b7238ce5) +,S(482ee41d,e3f9499c,8992b546,e209aa5d,679e4b8a,22a26615,1bd1b0f3,9a52982f,510e6070,d2131815,2d52eff0,ee10ec6f,563f92ec,a0e549f8,32efee81,dcd3de3d) +,S(4660a468,25a3c1d6,67003c69,4d36f8b7,6df7ca32,c6029fd4,65dcf726,5c58fae5,3d982bf5,46b5c296,988acc72,2dade97,791de8e0,150397c0,700bfa10,ba23f618) +,S(b85e624c,92ba6f0b,3fb1dc03,37589994,d8a3aee1,76314d87,3c8bef0,eb5d8f8d,88936b33,20a55ba4,24bff93e,fb36ef77,e2cdff26,866cd486,88c61868,ad75679b) +,S(a41920b5,361a26bf,bd187eba,b62fd5b3,b3be282f,94ef94c6,b1698754,902683e3,7790a196,29d93b4d,3d27201b,32053e02,c95a8f9f,260647d1,491c7a4a,e15ea98a) +,S(93882da9,79262a60,3252f01b,bf101d89,ed1abf8b,15507937,55979f4,fbb7f86e,938884d,f0a716ef,137450b,ad5f022e,23e570f1,3ed37e02,15a40910,189d7e44) +,S(a10509f8,3efeda60,acf56b64,3709b197,ebfa6a59,e66efb06,79c23225,c8952e00,759083d5,559bde4d,9a37df5,24cae4f8,5a06e7a4,7c0e15fe,830f0677,c24d1ddb) +,S(2b945a97,6ea74278,73d7e587,dfe75eaf,c55de704,8aa26d29,4b3b1ef9,2beb3651,423c07ed,27ccbf6b,9d1cbabc,e00b451b,cb488d10,e5daf752,6980ef65,6893c65) +,S(86f9d9bb,c1a0bfe4,e03da0,13f17017,f6951691,28d51073,b594457b,fcc37f0,f370c624,2e303796,9339cd4b,fbc19e8f,62388f02,649247ed,df3c6c67,464c32bb) +,S(f8995af9,555e044e,6238d895,8bdb4e13,3aa9cc0f,90a9206c,16d0f83,dd61ed91,b2d4d2e3,1bee12c8,3b8bdab8,34fa2e63,1febdb93,4af194bc,d0825921,4ea8a060) +,S(ab55a27f,69eb352d,455eee7f,bbc1c74,fdea2621,63d09dbe,2f554417,819394ce,8ac56493,60f585b5,72373bc1,74a930e2,4d54674a,89789353,4a166200,e31b801a) +,S(4fc106c9,c428df98,916a8906,95e98353,ce84723f,fadae522,e8a89916,a23b9fa6,90d732e8,3d54341e,4f4c88be,3392687d,fdebbc4a,7c19afd1,92531688,9eb92031) +,S(c9c85980,8831cccb,77d87b25,73a894e3,874080db,ba076b2,4626bc82,3149a91,9fad4ccd,8c0949f9,be9a6355,f0bdfa36,c5f99268,780566e6,a6f302e3,b2abf0b8) +,S(c0cb5b7e,2293abba,5ff78c46,aa1422fd,a278eb5c,ddd58cb7,aee77149,1c5209e7,8101f42e,36648586,5db6b572,d0df4ca3,cc72789e,ed8d27d5,1330d733,4e10c47b) +,S(dbfc03c5,16d93f83,472ab60c,391bdd69,af2f70ce,fbce15d,140f1590,d8ce0b63,f838e14d,7228ca2e,9a33ecfe,c376aa4e,4811fa24,debc7b46,4658c153,fed26564) +,S(de260685,eea13ff1,1571d891,35607b0,435140b9,62e3baf3,7cc3f3d3,484f59c8,6bc23ec9,a6025865,e6363335,bb66f1e6,c1f5f54c,aa5f8acc,d7f8fae5,99cfbbcc) +,S(58d78d60,b8cb8fdb,1b62f79,f6c17ebb,1ed8129f,c7819e5f,6f73c58b,faa2e71e,7cbbe4f2,fd6bc671,8c222f5e,16391133,b04d6d3d,bb263531,40aa4053,b44bccc1) +,S(e72b9b1a,eed54fe5,ab0869aa,90014e3b,fde1af12,f646d738,211ebefe,2c00a490,cd92d14d,8f595833,842af020,a2cc82a0,d9465969,77d25d34,8cff3273,90af4fc2) +,S(6a86bae,d55a5be1,8b7cef97,c9dff8a8,b725f614,2221485b,3b9f348d,570fd658,138a2691,4c3b3015,10312140,7709fa87,60a14f14,571a9d40,81c06d67,ef2c5724) +,S(1ca08cf6,7240f244,d6cb0059,564fc283,b17c39e1,b624716e,e100aee,bb0a1fc5,22e24fce,655d09ec,34a36317,c66adf07,deec2743,4e9c016a,b3447b3f,d9ef0a55) +,S(d95dc128,feba49c4,73e1ee30,bcddf76e,b7cf628a,fd495607,f558201,824a0b0f,d5340ab8,fea3e137,d1061274,c69b68e3,633e98ba,ae2fe116,1612c4d6,c7c7e8a1) +,S(2cccd22a,7f4fd501,6c3a14e4,769a88bb,ae7e288b,d9987afc,f3c073f8,ccd83857,ae82663c,aea89fdb,4710f849,ff8e4fb8,c2a7b614,4edb5f3b,f2564dd,73b389e) +,S(ec17b5f6,c8e4de23,937bc003,7dd7b411,ae4a9ac8,1f2801d1,c5eebeb0,95628a43,b3e0d51d,fd5815b0,631fa298,968fe70f,74319620,f0798734,8e66e6e9,6658df83) +,S(a63aaf7e,62907f4e,1a613cdd,ccf1cc98,cee8e12c,8bace3ca,95685889,6c96b6f4,2f953ebc,dc5f9973,e9d44ab1,23255a21,f8bc1a7d,e800cdee,ef754031,aee8216e) +,S(8eb4ff30,318d8d0d,6b45636c,b296d137,90e345af,19a14b2c,550e0169,87ad32f3,4b8e238b,ae7ffc7e,7d600151,c5ebb776,cc01d51,827f171,8f28af77,ca4a3e3) +,S(ab1420af,bb5b4397,f578a6e5,74a63aec,2432fa8c,b4712341,4374add9,8276b8d2,faf6328e,a197e927,65b9df90,a79558b,8f264acd,7f75b574,90ce657f,64b94396) +,S(daa1890e,6b2ba1aa,dcc16f1c,c1d5999d,5102aa6b,348ffb5e,9630bd1a,886f680a,19facb69,5a63eb94,cb6f6005,cf2bbd23,8744f05c,2c220510,94bf6dfa,352fa209) +,S(f199f52e,5398d1b4,899a1b0e,df8ebb73,cb08a642,bd22ff2e,b1cf647,7f2a28e3,3619abab,a5e2131d,4ccf8747,67ef9b75,2d5278ac,5549bd9e,5c1b5985,9ec2f454) +,S(182a9e93,a5f9ecf3,6bf20bc1,497a4a35,e75c86f5,9c9fc046,e2752223,f046ad6a,c6095e88,c39dee18,ca867693,d85617c7,e0924dca,34af07a5,c731e488,ffb8bcfd) +,S(8a4cb53,636fe66,b660a701,64277fb2,5ac21eae,906327c,3b509954,b214abbb,693e5851,4cc6a941,23ee707f,ad25d638,8efcb85c,25500bbf,63fd6926,a1d0ed1c) +,S(4901335a,3b40c33e,115e3105,82c55972,f495178c,813bd8d4,2b208916,5c8c1282,47007176,429d740d,dcac70eb,9e1f0e94,f26a9a0e,4dde0166,24d9d801,c84214e3) +,S(8180e5a7,7c34362b,461b49e1,4b9f2e05,df64f55d,cad82b8f,cdf41232,984e01dd,34cf5621,d4b9f100,aa34b0fd,5ac91d,cb3fb49c,130f3e65,de742ac,af05040b) +,S(8f71227e,fea9f4a8,9dcaeee3,58eaa5d5,a90e1d7c,b7d232a4,b1085fe1,3651ee9f,a4da15bc,bb2b79a0,a27c344f,3b914c7f,e272676a,bc045aae,e90daf4e,9655ad73) +,S(dbeb9b74,cdc9bacb,83592a2,a3cc19a6,d1ea8eaa,5a086a3c,cc68d423,cfb58264,be668792,83f07fb5,830732eb,79e16bbc,18e86df9,b659e2d4,5b1009a3,40576161) +,S(f328e93f,a7f52cac,3c7b09b6,280528dd,7d9ea4df,8317a958,ab0a617d,71591933,41ce8c59,811f9e90,61dc3f3a,7d85d394,2f780c17,d7ebca60,fc042311,f2405547) +,S(56d4f403,416b1bec,49c5f44c,2021c245,d4ca4181,5131cb7d,8fb0cf08,30fea051,cc5f6133,948f77be,934cb637,3d5dce8c,51ae1a92,e3d802a8,d35a3ad8,50bd39ce) +,S(8e22e04b,8bb476b7,ccebecf2,a327fd41,dd90c9fa,67cfc49,e9cf4ebc,39022b8,1f8fa60,3204696d,34d03c02,31d3ef58,934e7992,c2c81d6d,3e4193b3,8286b8b) +,S(341b22e4,b9a77c68,f93624dc,1cfefade,b396eb72,bf9fce1a,51867d7a,ef064f6,95839f87,7bc36957,59562bcf,dbcb2db,af11ed72,7d329e27,cfc8ff8b,92d9441a) +,S(3ea42e93,9f234112,879e8680,94fb8a8c,e6af9799,c000b050,45eb2026,3b324763,44324167,6f5aa6f0,4fe4d51f,fecfa8fd,60a5c0a3,38b16f59,1866bd51,2e01a623) +,S(afe7b44c,ef10514e,f94faa1b,b8cde91c,23d8a660,a71c3173,42f927bf,535d625b,7617a788,51218772,bcd51f18,54b063ee,6cfcdd77,7a388427,51cacfc8,7c8b4b65) +,S(a360ca02,abb40d4c,6e0ac725,f2c035d1,12f69ee3,ff0e1dda,37a3fbe6,a2034d2b,161e7178,3fec3ea0,305d0f72,3a60846f,9d8bbe79,255a3814,fab83269,916b646d) +,S(10484e5f,f7d9fe7d,9b65d989,9b2ecdf7,5984d18c,1199f61e,c914a85b,78011b88,12d1c0e2,1e137357,9ede1086,c2c1449f,e7f4e03d,78f7b184,4f744d6f,9576cdc9) +,S(76c2dce1,5dad9ddc,24276c40,eda7de6a,b11245e6,5b051ba6,7eec39c6,d256b138,d9a601ce,585b0839,92e3fca2,a43739a3,61a8967d,3eb0f605,ed4cef15,fc64ce82) +,S(671a31d4,c3e6ed98,b044fcb1,83dc60c7,d1d83988,3a547356,27b99b75,11d4d2e1,6fdd8d15,2005ef3f,7ef3762f,bf43a849,281f185e,a52c1b3b,8ad371b,e053088) +,S(91d0f565,a2da6903,12b72998,57f71c18,c2343a5b,a6f17243,1bee12b6,6e898a37,9d6a55b9,1956a288,d56906a1,1f7cddd,e6393ad6,7249147a,41eb209d,7f32f681) +,S(7e59f058,1953a2c3,cbd4d0cd,8f4df7b8,6b90d8de,7240b2d4,de9ee9ab,628512ba,33b0d1eb,74cc7d60,ef419b0a,f9f03714,35a012fe,328fbdbd,9d9b69bb,9a42a173) +,S(ef78b65e,b791bed,212652ad,ab1f32ff,f43a285b,e040380d,d3492afe,1f788a26,9f3e2538,96d5afc2,3ea7ab1b,24ffac00,f156cdef,93957910,abb1cd1b,6508d306) +,S(78b978d0,199833ee,417ce2f5,fc12cb01,cb0c0e4c,ee752e1f,50a8cdf9,b56b7cd3,9f9c7dd7,372606bb,e3170141,31591f5d,dd631f91,71460cd0,19709478,c1560dd9) +,S(5f785b31,f9945a20,e992f5e8,80abab72,906ffdfa,7ba7ccef,f1b3d26d,70bfe64a,a3cc480e,b3cb386a,ffa1988d,3227911d,57522413,e5d0846e,a6d0a17,2b881c1c) +,S(9fee7999,7cbb492f,cf3aadfa,44484d71,2c3887d,6375c887,fcee9fe5,7806b3d1,43114327,7e94c760,1fbef25a,60e7d448,c0f0b8f0,c6c64437,a129d4ac,fe24c22e) +,S(12f2dd5d,b75d8885,7b7befd7,cdbd7c76,c0f46213,f9a53102,acd8b0c,4ee3f30b,ce27598b,e85049e,9ad3ecfa,d3864070,f8510570,742dd021,6dcb4aa5,334097d8) +,S(c694aeb4,3ee2b51c,3f0e2bef,bc1b718e,fbb86f9f,1d2a84d5,3178325d,cf997bd7,41481f3e,b6a69311,2cac3e5c,c85a6f83,6fc5190e,ae71f226,bdc887a8,ed050977) +,S(fe266a46,14c5c05c,baf3493f,5af3befa,9bd16100,860bab1,49ad78ca,81047ae9,e2e18ebe,c44694d4,b7c614ad,a772a5c4,f58ca087,4957f20b,741b954,18471e6b) +,S(7975e1dc,926b07c,487abfa5,8c183f21,daff04e7,f67a7250,d2152699,356118dd,c984b97,44e2b300,ca54b779,da94dae5,f943468d,9b9729d8,21cfc709,351409e5) +,S(93573cdb,50183589,a0909e8e,6186d700,7022848e,b7fd6951,a137cf16,a18a2b06,7a957c66,3047f6ae,d9490039,d136cace,caae2d8a,fc9f50f0,26590e62,18bf47d5) +,S(c0bd2e1e,a60f6feb,8e0ac7dd,485fc4fe,6771d80e,e29b4829,fa37faf8,81d77660,685b74fd,9edde1c7,69076267,d9f247e8,2effc83f,e25af065,56aff25b,335bacd) +,S(56bac0e1,93192207,906e5f45,d55d5919,b676852b,daa43253,8c4c6984,9c24bf3e,e3bf51d3,9856b812,d2e480bb,c8b118e5,f5c0ae9,f8d09096,a5d207ec,2fc18ebf) +,S(53b41b13,fe7cddd2,ebfec7c4,a985fded,5225fa0a,b93dfc65,2314d1e5,9142c06c,90fcba57,44e4f565,5d2e038d,ccd2bdff,cb4ecf20,48f2ba98,8f62fe9b,c3b69c4b) +,S(bda05e31,ccc0edb9,47ebaa26,9182ca2c,b1136400,674ce5f5,d55fcf2a,c2e765bb,97275979,31236982,a7459356,7308ea97,2fff08da,ae8f707b,447dc6ba,7acf75e8) +,S(48dd1c6a,8a900820,1fe09f19,a8f65f82,91196e95,1c57189b,21aede15,4b0413d8,79a1f6fb,1a943dca,6517e287,80e72f85,c5a6150d,9c50d7af,78c8b63a,c09b98f5) +,S(75406269,e28c428c,8eeff4e2,ce9a2d48,2be8346f,3446451c,13c04380,292f1f2c,4743b097,211c807e,23cd13d7,692efc44,202c44cd,dde5a89f,9e7cdc5a,133e996a) +,S(1aa55d93,bf318133,8840ae4d,24314ffc,74420002,4ddab165,4018604a,2192ee5f,babac354,92d59e8a,656ac7e9,9b6cb2cd,7a6a8e88,1361118f,41e38f1,2cbc3bfc) +,S(75be4c50,db7bc629,e64fa850,3d89f722,34d214f4,9b176fba,b937120c,477dcf03,b5520bba,8c606db2,833d934,3c860c6b,ed2e5e2a,41a6c3fb,51154c82,94b6f819) +,S(f3604822,e4ed8b2d,d4b2486,b611b95b,6508e10a,1c725c7d,8d638254,3cef6c8c,f405ac79,7404bc6a,25a1a412,f2cbd698,75d99d2c,b23ac105,f9839446,222dc0f5) +,S(6c9216e6,6f9326be,fad5f727,ae0326b1,da54ee91,f041d2bf,2d87dff0,e77cefe8,64a021b9,bc1947c8,df546f92,2f5230df,1ec2f372,50651704,557377fb,39d16517) +,S(ae479bbd,ce97732d,df313861,76807678,988346e2,5b12bb09,e74d474d,6905668a,a3ce0355,c5996087,89936336,64d9bdd2,b33a6f97,ea3f28b3,f4b7c0ac,92612929) +,S(ce92c179,66f74db2,1c6abcf8,36cfd2f7,9ccc05a7,aaaf74ff,4807052d,754898be,f3e3d3f3,530f38c4,ca59cec9,c8e3456b,8adebf80,3f10927c,e44e79ca,601bb978) +,S(8a0bbeb6,815275c1,77553d87,5988c4dd,a96f5ae2,378a3b9f,477cf162,6e6ea68d,958b795e,46f45412,acaa9f77,85a4e34,a7c74eac,228476d6,4e917983,5fe77f4e) +,S(c2a44ee9,975400e2,912a033c,5ed1e7a,7f0e97a7,1c86e8d0,c2e5136,8dd9ccfe,956435ef,7d24a507,dbfb69b2,93b51369,70cd17b8,ebf6bc60,596a9545,3675668f) +,S(b615f625,534ddf61,47b78520,85443bcd,3d3bbe91,c815dc29,3cc891c7,199ea1e1,4cabf4f1,99e21468,62a90876,4f65c624,fe3afd1c,6b399e12,267dc1e7,6ec3ea25) +,S(afccaf8d,fdcf272a,cf56dde9,3980bee7,b64a0c54,f80830b5,5fd0b93b,e8a75a0e,8d8ec5d,6f6fc44f,89f6d9ba,735861af,e7d6a660,7d88e95,54f2c141,1042a63e) +,S(534176a8,c5311b26,1f39395d,f78300b,559d072a,cb3873ac,32833c8a,9b135f53,ab84f84b,5eeea7b4,87ef6639,8fa756fa,b16155d,683ef643,b03c7e6c,8ab2f436) +,S(5f7aa173,97ef95cd,f47651ac,6220f3f2,8705abbc,6531b93e,a65fcd14,1b91f34c,72f7d898,3cddb34f,2ed1b28f,17a77d8e,70cffcbb,e0462ab8,b7548561,9881da22) +,S(d4fb4a4c,c1e2fb72,b301db19,335afd7a,b6a95258,6903f449,aa287fc,ac8f3d3b,76b572e8,4a9db287,19d098cd,5dee787e,f213adf7,9ae90306,8881894,e14154f9) +,S(3dc67563,843b2f3a,f793116c,23db0dd0,dad0975c,5abbf569,4c6d454c,9f7a9ff4,ddf65b9e,4db83b7f,43d0ccf8,49a8088,4894b277,4fb39fbf,78076a60,356753ae) +,S(657912bd,1edd014d,1386c449,50cd1667,9c3e415d,b36e36b1,3bb5c82c,a2f897d6,4e2fdfdb,11bbe240,8fc7fb3a,acd06c69,78205e48,c9f5a143,4300927e,fed505cf) +,S(5a453b3,5f82585c,f64473e5,f3fe937,6f412b5f,c4ade7b8,f9081717,3fd69f99,fc169e11,3448b590,4e1dbf06,f4aba1a3,ec2fb4b5,7f2b4c4f,a29b6617,58097ebe) +,S(c3adf45a,c24b4bc8,69acfaf1,f96a3043,d01c68b2,f4ff689,93b37b3,a4052679,3d923207,cd374b49,d3a85bea,972b8d09,4f0d4b83,cedc97d7,edc2ac68,10ae19cc) +,S(1a32edc8,905ddc84,2756420b,e1f25daf,5bd84f0f,acb046b6,e9040fe9,5e1e1d56,7f467d9d,113a77f8,c1cb73ad,16a62f4f,f1612c80,f8cf859c,ca42164,68eb4c51) +,S(70957d98,62e5977a,c328b7da,2e51024a,f925c142,eb1a46b7,b4a3bf20,a74d6c98,269b56c6,2e42cc34,a0951348,881d2c53,7d7ee231,f2327ec1,441fd273,bef09381) +,S(7e69416,5a02b16c,107ae454,b6cdf25,bf6dd256,d976ab44,bd7edc84,837537a7,ffb874db,38360c11,e2d0d2ce,3e47363,a6aac21d,78a37b24,3e66826b,445185f5) +,S(4f81a159,7b42e9b5,24be7ac6,ff4405d8,3b9d8a75,e37b58b6,eed5525,6ddf9678,b2531207,18676065,ad8ffbe1,6d27df4c,3558eed7,992538b3,77cb8497,86e0a78c) +,S(fa250368,577065af,b60be8d,e9381334,9be6fdd6,1bdd02d9,3591a35d,294fd547,f0b991e3,96c77cbf,5d642f0d,cf5ee10b,3b0a1fa7,7b696f06,d4d61cd4,48e81625) +,S(f4df5ebd,67162bfc,3e3da517,23fec6d8,6b61d6c4,a5876c4d,440f025a,272ba3d4,b23ba279,8bc75fb2,d590e384,c9e375ce,6380dc5b,90970d44,674e32a1,8052212b) +,S(ab5b6b1d,b3725b65,fae28e5c,44460d6c,51b8971a,655541c,4a587076,a1ac5015,16d2c457,ecdc1718,3a9d7876,d785adf0,424f72b8,d08b6a9e,286ea5cb,26ee2ece) +,S(a8a4ec7e,13db5370,40680dcc,470d38a4,2e08d99,3c30f981,ac877ce0,28869e55,4a9ded9c,2cdfee53,897d0874,965878a4,754025d5,babb07bb,2d248151,cb7f60a4) +,S(337f54f6,33bd60db,583d08,165c1011,6f914dd9,e2abcfaa,5f1b1410,b8245f48,9453eb28,696afc4a,40b5452b,d3abae4c,679b58e5,408b0a94,ea456771,8176dbfc) +,S(eee337ab,dc2baaf1,544c767,41a5054c,f6db480d,529d20e4,33b642b5,fd901b53,65ad5b88,2cc00d4,a4ba1d8b,a6956f88,825616cd,5f6c9830,87264247,869c27be) +,S(59f52e18,57cb000a,ec1aaf0c,b43f1274,f56e477c,50f010b8,4513fcef,752f1548,d8ca8f6e,8db03b19,8047006b,a6ec1e29,4f225461,9978ce70,a1ae0f53,9e1698be) +,S(6c200a0c,25fadb2a,8a9618d9,d7d86287,8583ab10,f2b4915e,8f5a5f05,406f3e12,14d4984e,374cf35c,145af24d,a5c0d0f8,504649d,b1793a61,7d6ed949,ef8081f8) +,S(1654a2fd,51dfb6f8,71aad878,239b657a,f8144ff8,98a3c2a0,32cffbc3,8aac07fa,8b6965c3,82d98569,b6cdcc1d,4c71705c,e36d46c5,fa5df714,8d59043d,161a839c) +,S(c48033c9,ab473556,c9982f33,953f96d6,7b3ed1c0,7e98efae,8de232f7,67556d77,af3f48a8,7bc43168,10787382,8dcffaad,abe4a54,828b02b6,f897ab4b,ed968bac) +,S(5dd977fa,a9d228d5,1885aaea,557f7a98,1a95771f,212c3ba,f1a4e428,3c3c6032,3bff9d4a,ba178f6c,d2ce5204,3daa06f2,abb06acd,274beb45,49e72a37,8f2eb656) +,S(2a76dc25,dd9a96c4,bcff1d8a,f3c9aaeb,261e4c69,a5d832ab,efefdf29,ce42a564,493452f2,3ad5cae7,de8c972a,af5c3883,7ff82aa,df616c5b,2fcab4c6,d5244806) +,S(cdbd3506,4c0e7923,822bab4d,b4662b2a,fd3935a9,a49e6d6f,f2db8f4b,d29a4b8d,b2126f2e,b61e274f,a688a84c,386fdb5f,58b84515,1543f143,a8ce0a3c,557a90ce) +,S(983f249b,2cb9d4f6,34d82d6c,e713aff9,2bcfd525,a4146a75,bf6f725d,2b54d978,79cd2406,850be02d,a6c4d25f,5a02dabe,af302e77,238833ef,cff0484,8a8abca2) +,S(88c765b4,a5a0a9f3,a257e21e,ffb23e51,9e128489,fade1383,96fdc18c,38afd4f4,f4d5fe64,729995a3,e505cc03,1d144682,e3336ae3,45c28697,1cf89b7d,595f46c2) +,S(197505ec,d603cb0a,199c7d08,b88d0e63,1d147d07,45603692,6b67a582,b7d52c31,947ec13b,f2d75fc5,af5a746,15a75aec,2f212adf,a234e08f,49a561e4,f9057f15) +,S(98184232,e10f605f,58a700c3,d6bc04d,9a19790f,eb638fec,668320b6,3b2eaaf8,ef3076ed,c0e2fa39,30ea837e,36c31f59,dbbdf192,ab18bd7f,39578e1c,eff9c85b) +,S(50f0db35,cba0134b,790f47a9,e322670e,f0c7d081,6869a764,892f8e23,6c0bc002,1c1b1c13,d98a84ea,e77260f6,58e265d8,9e466b44,b8604edd,83233fcb,68396072) +,S(d9e340ea,1a44bb50,ae4bb19f,3f4228f4,99ac8516,cd6bfa86,80c1dc31,d5665502,128a1688,335a2193,ff805251,b83baee9,341445ad,25048f75,355f4b35,5b4aaad8) +,S(15aa8133,1b84ddd,8c706702,555dc19,d42cb4a9,a9474c9,1e33c0f8,e87c539c,79530720,96586400,ebdd2ba1,7762ccbb,2a14bf47,45f63b1d,e22c6a6d,8942dbc1) +,S(6f708704,53d19a4d,b910d169,c7c7be23,d489dd18,23604242,55e182f8,7a5d34d2,e0531956,7c1c2bf4,a0a9beab,d7c4dbb9,c15246fd,5a6de101,35578aa9,99c7dde2) +,S(31e920df,cddca3a4,89ad97e9,168854f7,867f9a58,fe2d3f1b,f33f8dc3,c7167674,52712c3d,b0c6e58,15157660,ebe27dd,244a9c5f,b12cb8af,dbe82900,c3706f39) +,S(93300e11,708ff01d,96f81fbc,f1888c96,8258dec2,86a315ab,8d01f2da,4c8d51d8,15368647,3b6a208c,8449b53,66584e4c,9e0b7636,1256df46,4c93d4a0,e26c33ff) +,S(8f7ad50b,f62d6702,616cfdf,3712c1ca,30c94632,720797dc,ecd54f65,cfacb3db,5ac10a32,7dc52bc,33290080,a1a194c8,1eff0d71,65f9d34,7e4f8b44,8443c637) +,S(6ed80b82,76270d71,c468f5d7,350c608a,7f5cf51d,c8efbdd7,4458a487,2989f4a9,bcba2bf7,38f6e77b,465e47b7,c687c7e1,77fd3cf2,163b5a2,e00923d0,89826dc0) +,S(ec6c1d7d,b94989e2,962cb85f,777eada2,7c2b11b2,86949e38,eea2bb4b,7ce3714c,add9f9af,6042dfdb,1d4089d0,ebca5755,8ef2664d,52fce516,df3b030e,9ed08fdd) +,S(8f77cb2c,24dcc192,593a82d3,510859b9,c59bca8e,9546735c,1fe26084,4a37f093,51674986,fbf499fa,70b55bd4,f0a70cb8,423fdebd,587e6213,83199b3c,4fe07202) +,S(e2addf74,dae831af,aa4c4ed6,2f4a32dd,1122f2d6,243d049f,1fd78c1d,64b6aca,7dbcb394,1eadfb0b,8a56022,4da66128,a73a1aa0,20a5b23c,cf58118f,e28b2297) +,S(bf7af1bc,614d31c9,9afb7c6d,b8cd45b3,3a22b151,34ba872d,3e845da3,2b1e3eb,108d39e7,8cf88a22,fba9e255,23267bd5,2b850464,f1277239,7542ec2c,50125a21) +,S(88ffc7f,cec6580,5b92c5f6,952d82cc,35b4f068,a7581987,93ebc59,8efe50e4,382dacca,94b42c3e,ba1558c7,82394564,d39193c9,8b9e8cf4,a63dc4da,4d378a4c) +,S(b114a384,ef4ae60,b9c569ae,636eab27,9070e207,34cf83b7,a28353d4,7d3a152b,37c7673c,e58ee20a,6076438c,9bbe5cbf,bb826076,6d8a7001,b188c477,cca3fa70) +,S(e411a42f,e20d23b6,fa768fa1,e310192c,cfb0cd2b,1914c9da,627db3a8,c7e801b0,feb1b79b,43ee7980,7252bbc1,728af29a,8f6828ae,8aec480b,91c85008,959b1039) +,S(191f687e,46432313,c085182a,ede5e7c4,31057ad7,f1f48fd7,cb814fcd,74ee1999,5464b42b,3f77ce2d,59a39efb,83808cd8,43e5c540,3d5081e6,e4f4b1e,926dbc72) +,S(63ff4977,33b0a49e,f618c4ff,1aef537,9837744c,85a19bf0,b2208eb9,506bcd81,6ccaef97,ca835931,f3a87b50,a93f2a4,39535d8c,87e26090,3ae49b29,30593d3b) +,S(efe36425,c37705ba,69e7056c,2e8c628,f4ce72a4,68d85556,4c57e5ad,b7fc2c1c,392b9b5f,27ac49c5,831a5f52,c2e55bb2,8faa7f12,521732d0,8dd910c0,51970ad5) +,S(6d2126b,dd7cc08d,1bd41910,21704a1e,841d4737,4e5a0a99,9880051d,f77e94a5,2e9b823a,cda1be97,52f72ce6,ead42127,efb4d4b0,8daf55f5,5da6f956,84e6e806) +,S(cf7b9ff4,297d9c5b,91c6340d,c1cca93c,6d453ac9,86b4ef54,b20df6a5,4933743,8a57808a,2c07002b,111efec2,bf751b54,c20613c4,1e3612ca,83baa3f,eb670c15) +,S(b160242b,4cbe5ee1,d1dba4e8,e2d55a0,27f5a5bf,f7c023f2,c1524fe6,5f7e83e,ac35795,6cf31260,7ee9f54,fb39d3e,4f1faaf4,67d09567,6075b8c6,3c0fb5a0) +,S(7a86452c,4f8918d9,86d3dce0,22619a72,1744d9c6,dfd0e733,c02cdaa5,6abb050e,30d30b1c,b558b0e0,fbaa1fb3,596cf454,542370fa,43d8a85a,91eb6bc5,c90de179) +,S(a279bc1a,64d206ef,ea96d3a,b97c6770,af41ba40,9381d372,408052ff,582323b9,aefc853d,701ebc44,679a7ab1,fe033182,e96199d3,4b58261d,a1b4a6bc,6ce42046) +,S(e8e28570,5c16016b,608c301a,ac59f868,f7691886,261eb01a,d4e6ec6,a9e5cc76,92350315,f8e78051,b703b7a,49427272,c988ea66,27699eb8,f2fb3eac,9f0a983d) +,S(1fd9cef8,14f3fc81,8055f300,a734f9cc,46da1585,b939be73,459e0ce1,8a9f2bbd,dcc4f73f,a50fcc8e,6ec3c71b,c045f020,c26d79a9,794a25cd,26488c0d,9cabb55e) +,S(321b1afc,70275fd6,fd48942,df364f6f,c609d4b6,cf4e574d,39f1ad06,927e5f11,1368ecef,808bb311,ae9ad36f,8a4c81fb,725a80f8,ed029680,c5b54463,80add33d) +,S(4dff29fb,6518e393,dad0cad9,b0dec257,f9ef1e9c,c50cd741,8108c42e,f6d7bf72,4159786e,5aa4e82,4d7bfd06,713ec8f6,d92f8f8b,48304efd,e4d0f4c2,30dfb70c) +,S(937a84a5,eb63055c,65b162e1,1a3f2e54,c839b972,95a8c1b9,274373f7,5ced1e0b,a03078bb,bf11a351,da7fb3b5,2e3e7a2d,62c122b1,a9cf9954,53294f37,7966afc6) +,S(be3faa9b,7cab73b8,4fb2a87d,25db7fc5,56f07393,b3177c7a,56df0447,e96cc3d2,e7051ee0,1ad794af,571dacc4,4e91f7f6,9276446a,7e348ee1,2998968,afaf77f) +,S(58b39c6b,cc36d506,765d24da,6058d7dd,36928d13,b0fbe1f8,c680df15,756c9b41,449e9691,aaa846d9,a7412b77,73f7ae6f,b4ecd99e,c57863d,ad72d3f0,423d74ff) +,S(9b18a971,b1660b46,720e2100,865742c,8c91282b,1c72c7b2,8192bdc9,c3765798,2812e522,98adf83d,2cc07a93,4a065016,2be28d37,59cfd50,6c792e31,32e0f49f) +,S(a6c44c03,dbacd4bd,7a35e207,61778826,c86740c5,c92942d7,f73a1b3e,dec0f59e,73316b7c,d1fa3410,76b73727,8aaf39c6,2258d29e,c40c80e0,797493cc,7056077f) +,S(1ffb2755,628ff8d5,d837495b,94ad78a0,5dde2043,bbfa3aaa,21a05a3a,21682ee3,4a0478f7,6b8b6c,ffd9962d,f70e2a83,a71243ad,c690efec,5f95aff8,dbb5943b) +,S(aea4c48e,36051144,482538a8,8ee5f72,b67a21e7,8fb425c,3d6f1e78,419b8283,4517cab8,c28eb397,bd89d216,ce711332,82c7b530,6b64499b,2216bba9,41a80b27) +,S(ddc59bfa,5f8c0270,8436fabb,5003ca6f,b972f14,382bf127,f5297990,b4ed3eb,f6c3f19f,b80e75b6,53c370b6,742045e9,ad7dbc80,3a996696,99605345,ebd995c1) +,S(22184fe7,ed301b2d,62bf83ed,64742f6f,94d204c9,866a637d,d03c58b,54c80a8,9db27528,1073a3d5,617a389d,c5698255,3bc55d6a,3b80cab4,ace36140,8179b442) +,S(e58617f4,74e46f4a,74b0ed2d,6bafc3cb,6488c510,87136eea,f98aa37a,f201cef3,cc6a7375,52dde05e,71bf2047,d49a41b0,c6b141e2,e4f519d4,36d4f8e4,f2aa2220) +,S(c1aa4092,5addc5fe,de6c2c5a,ba73b3f2,b7394a0f,1d02846c,5b2a0379,824f8e41,9713af07,e30af560,9516ce73,5083ab53,2475bf26,5713570,28b586c1,d28c687b) +,S(4aa5d88d,89576459,1ccd1c2,3064c718,69e4d320,b0b71b5a,c08d291a,c1df6168,1d0ea41b,915c288e,c6b36cc3,f7806481,c048482,dce586ad,f240d32a,c913e6e6) +,S(93876d91,73137834,dca5e192,fa869a02,738d4171,391df1e7,43296f93,a2a8a977,7948463d,32bad450,24e63d9d,d5786a69,73fc6c8f,9d2a7c3d,e2d6fbad,7a6457a4) +,S(c80cd7d,30268025,b233dd13,f2f2af37,5d18080a,54c406ee,50e4890f,a91b7b28,9f73b58b,1f1d11f9,1648f904,ac7ad275,9e6260c9,27870292,278fe521,b718bc4b) +,S(d2bd24d9,7dd4a345,a8c4e857,97a9c30c,e8e7e7c4,3ce79bb8,fba4250e,a0c8c5cb,330f0cb8,15cb1931,90331055,809eb028,55ae895,ee1a30f7,665166b9,6494b9e) +,S(d4e4a3a2,90deea18,fb15457d,f3ab9815,5d722589,515a38b8,dc303307,5dd7e9f4,4854493e,77d0ecb1,742bdc9b,a5219e9a,71c57a6c,b914b8a5,6eec21dd,3e7d1c21) +,S(f0fb6cf4,810de399,fcd1b246,f0e76e2b,d318f82e,1601ebea,2779be6d,47236d19,e3ad5160,66480239,88b0b197,3eb2a41e,2cc9b4d3,7cf58d07,ad0edde7,ac595daf) +,S(dd4ec58e,3f4c470c,36991740,d02b0fc7,9a4f9df1,98647ab0,ebf73b10,34858939,3a6ecc86,a3b058ce,f278c839,541e92dc,737a6390,94ffa464,17e37da0,40a3bfe3) +,S(ec56910,1d7ed954,d4efe1b6,c4f6ade1,2af12f3a,ddc75a8b,8fdaebb7,ab904e51,3497c67f,5d594f71,4327111a,e22f2621,be7cbaad,b2cc1d6d,be0b7e50,d450c54a) +,S(ca45def8,51856a5,7ca5e1aa,64edc3cb,e25ef6b0,e28abda5,a85d9a19,dbaa35c5,db8b2357,268db9eb,e013fcde,111372c2,6eb4ed69,5a7a3df0,4d1d33db,703521b2) +,S(b44c5388,964521e2,4803c8b6,3dc8a494,40f8ba15,435ce2e6,5f6dc092,15b49a47,2e16435d,f30c4b80,cf125e04,b85166b9,509890a9,c1daf1f5,72462a83,de198d00) +,S(95b735e2,35862f14,e9291a5,4b46d977,33a20ce1,b59b4603,666cfeca,e05dea26,e1281705,5f38be19,9bc9977,b6e80c08,f22ab5b1,286ea553,21145675,264aabb9) +,S(83d9d867,8fbb0263,6ce8d231,3ee4716c,a15c71b2,66c1a7ce,e56928ed,73e5bdfc,e0494c2f,be92f132,effe7d78,499f4a00,c35027c2,37df8545,9918687b,6b949246) +,S(98b7c85,a04c546d,bbf6bad1,6914e247,1d3b478c,f30dd6f0,2e843770,49bbae03,769c3b95,3733dfd9,d9027da4,a10b0a65,ce4106f9,44364972,e569c63d,3b2ace57) +,S(3ce7b677,852d34ec,34358a8f,4da66d53,75019cb1,19a45dfe,864062a,a3b12e45,68d2790f,1838b86,96272c4b,d5e418a9,2cf03d9,de44f218,e42562dd,467e409a) +,S(a0bc28f4,d4da7101,41d0dca7,51542b83,6b50bdc8,997b291,e074727e,cad7836f,6ed7e149,40f2781c,d685a581,99f163d2,177eecbc,ca785224,2a8b4859,97e47c88) +,S(9a571ba3,52b1d62b,4e5d290a,c0d41983,97750fc4,9a18cb68,18fe11ab,1e185c0b,1a91cccd,b2b1f58f,9cfc0dfe,d3464917,f6c2870,9bdd8128,ff61e295,ad1b4ad1) +,S(fba0544f,cdd2de73,d24eca5,55a8c4b0,4e135c1d,8348cb93,d53f647e,2a21b9bf,7a11a425,a4ec6acf,2eafe631,ff83be6a,f71a6cc9,f7dbe3f7,aed57e04,2774568a) +,S(d96b253a,1edbf662,3902bdd7,1c3bad9,ecad1115,45614b48,5f7abca1,d4920a9b,2bc88998,f951b831,2f27d09f,2f331536,1499f1c8,b172f1f2,408d0660,3b18c2e8) +,S(2b3c17ce,1081b825,94ae14da,f9723f9,9823382e,947c1356,13a4b8a6,42267c2b,a4cd589f,2ebd245b,88c7f1fa,427a2ab6,e77205c2,dbbcc74f,dbbdfa69,336048ff) +,S(69698780,fdac522c,69313ea7,2e244d9d,3f6bc5c9,4fd86125,2eb56369,c96439f9,e8eeb3c6,460f475f,c06b5943,9bb9994d,8d6e4314,fe20020e,c1001f77,25a03154) +,S(1e344611,4cb4dc4c,963e172c,9bfc2f4a,d1577efc,ae2ffc6d,76395ef9,a0848c68,debbb8df,e6f59a0e,b96d464,3bbc6d51,a2bb4621,6059de1d,a473436c,404f5b19) +,S(6ccfae02,4c7f2a9a,ba12c191,bd35e287,d5c30284,c4273a1f,c558ae8d,286aa61a,c2014174,c78a2fd,d342ade2,51e4588d,94c4cdf1,ee83ade8,54e48388,b6e7cb11) +,S(5b5fd487,69b6a133,35bf0a2e,61a2128a,db43153f,9497c77e,c32b16e2,ca4c728e,9954353f,b23c9d44,eadf2632,168711b5,5a54c9da,53c41088,50fe77cd,8cf00c77) +,S(6b74a257,27af44dd,61fbbbd2,7323b63f,e6a41d9d,f5412215,65a6a9bc,35d069e,a4e1214,f17b8dff,b5bd689c,5f004c98,39b87a46,15245756,48099d33,f432a34c) +,S(5171a187,8ae9ed01,837408b9,fe08f317,8688606c,aae04b2,63cbf143,b8e372a2,b5e7de6b,964153cc,fe64a472,8a8f20a4,44da8e15,c593b7e8,68140276,b172d06) +,S(df9e86a,4337ef32,3518568c,e52958ab,dbce8a92,840b756c,279e96cd,43c8e80d,5442baee,c72f460a,110e8ff6,1e938132,50b2ccdf,61941df,5f591bb4,73027da7) +,S(ce070279,eb6f1f71,af876ab7,3903fbd0,ac9e4693,7b6d3307,2ec80182,3887c850,de83ddf9,88f9d345,e1ff2a79,e91f8ad9,6ea23097,538dde84,aea0ded4,b6a155eb) +,S(a0255c62,44afc84c,58238936,c9d08d36,96e5789b,ed28c40,7667f348,4c2f35fd,93e2d407,aef898d7,c898293,fb20f222,6cd5017,cd62669f,17ee0d16,773c6f7a) +,S(ae82dead,b76d5dd7,140e1197,a383ff62,138e1840,dc2f7ef0,d5126dca,86f0d86b,239dbbac,caaa0779,a9f6d8ec,2e30b590,72d36b58,199a27c6,5f5815ca,5720964a) +,S(cf0999ce,bee65e2e,d596441e,a8942461,97c597ac,9c090884,44c375d9,16332393,6620cbd2,f074edd5,1ff8cd5,45adcdbd,1c664ad2,6935880,8655ffb3,3a748ca4) +,S(5fb4af74,6404b01b,63bff1b4,1bacbb36,9ec06801,9454622a,76258033,9cd3965c,464cb2e1,2cce697c,d409529f,a48e7448,916a51b4,5954fe93,d99ce392,272abff5) +,S(15af3c0a,46b5232e,55e5687,a2bc4acc,2c7a350f,8114e3a0,1993a0f3,1b3216b4,ae03739b,bdce38b0,4735acd9,3a3ff7ba,86c8189e,56a5bb37,ad83a574,cdd45a83) +,S(5d0035d1,d008ccc5,42cb8b5d,32d973da,32c88787,640d0465,76d33e36,540b4b10,448ed8e5,bffa9f28,6689061f,73a74f17,76db8a8c,d5b4af39,6173e7be,6e54c465) +,S(944c70f3,9cf749df,edb9d322,ffc69e3a,a40b0704,fc4af915,e027bad4,83c95527,b0ac0c3b,bf489332,64a6e95c,e49a669a,df10acfd,48e22fc2,1a18ecbd,b86c6f0c) +,S(fa5219f0,82ec3c4a,3f246754,dad62f04,52e26225,6cd28acc,846bc5d6,151e4402,32ce81e9,d6403132,d7b64f26,a0289031,eb730d2b,dcd0065a,1b4e3f3,a7afae9) +,S(c9f4aa30,ddbee263,509455a,858b8518,85c6a16b,5d9bf032,70443928,38a30ede,5ef717c6,b438af31,9a892799,46b73ba7,add20334,c2fa5bae,a15b7632,34ad7b7c) +,S(2f4cf3ca,7454d569,5b0dd2fd,c72d4ffe,529b362,deeea120,162c178e,7b770319,dcda920e,3566ebcb,f47c1ce0,fb767092,fe7c87c5,ff146042,d5a0ceb7,a2f7d487) +,S(2417f576,2e0cd74a,f07a41a7,51f91b3e,a1cb0a42,2246af4,a0a96b8,79969945,6a96d755,f8dc71bc,adad0a3f,61cb44ed,741ef96d,96baacee,fcfba7ff,1e7807d9) +,S(9ab22f84,305a1c1f,675ca5ba,cbb3dba4,d43d060a,ee9148c6,6cfb61b8,5888852c,af0506fa,a2588e3a,7aeac12a,7acdda3b,b51d996b,2cca9c18,e23b517a,a428a03e) +,S(f7421ea2,24627926,28ed878,7e154724,77a91726,5a162f52,87501d1d,24a72b6c,db0ae665,e4484132,f372ca6d,8cd46115,fe1c72cc,885804dd,8f508900,5743fcf6) +,S(35756af3,548d57e8,dc0bb791,8b9875b1,10a912bb,7d971e35,4963bd7f,df5c6f75,1ca46dba,78a2b4fd,d4ed69ae,bd4e1961,86d94b8e,20b1660f,c517098d,e077a1d2) +,S(a7e9f00c,494cfaf2,16449d9a,b0dae7ff,de4041c2,fe031bc0,241c44db,1bf01837,f2aeb9ae,480b406a,9753d009,3b5fbb74,5a7760de,4ef508b7,d10804c0,161a0280) +,S(69451dba,92872879,7737755b,7655ce70,64838aa2,9084fc1a,c88f5e6f,ca62adb7,26218fa8,d40df091,31d845d4,96c7b950,1071537b,51a3143c,c73f1a7,b02b1cd9) +,S(c49c3b30,15cca66f,ce986a37,588205fc,89a92d0f,c520ad3,5eb6cce3,daabf06d,7afde84a,665b02b0,e0cf9ca9,9d2ad097,6242919c,53e31b5e,6216d67c,580e354c) +,S(e9e181bf,b68e6e38,c5b6ee1d,f11c14f8,90c0c744,8570387,1ab6b624,6b9dae8f,b0bcfedb,3f394317,907e260,c3651aa4,d1af5ca5,e1a34018,fc6c26a2,d5ef5e1b) +,S(a428586f,adf41cf,5b5c9e52,e0d6e1f9,2e7d8738,ab99e8bc,4062e302,de392324,77c3e18b,fe71c937,65b911e8,b49cdee9,a2a7413f,4de831c8,3f967f08,95b8d142) +,S(f5c92ed2,de1d1a25,4b4a4830,b656a674,38077be7,5efed94d,785dd0d9,72712cf,7ee98d3a,497849cd,5b5f6dcb,c51c5119,228fdf7e,1a67f1e,d7c670b9,eb3958fb) +,S(a85707ca,6c85f506,311b6930,767b5571,e18c19c7,ff2574bd,f268f018,b49c3f66,1785fe71,cde2e189,aaf67d10,337b8fb8,53654335,4d5ba73d,77518d9f,5e8aa050) +,S(8866f5f,a4c8d1c2,f2de0cf8,19eca5c4,d084ab60,67a7d97c,f9942fe,c0a7468d,3014226c,3f33907a,2f6c49ad,c762be6e,2915288b,a7ec009a,fe693048,3588336e) +,S(425f6d73,37eb2d68,e17d07c8,bda406cf,92af22b5,6461bd66,f40be14c,ae0688cc,e865526f,7c42e391,1ab73290,e80bd9fc,9643659,5871bdbd,ef8d698f,d04d4980) +,S(f70fc3e,1de3b3fd,55418441,43deb4be,36bfe6af,3bc9d9a2,f8ac823d,68323139,8b47994b,1febb309,e3774a82,d6b18d78,8ae5750b,40aa944a,dae404b5,da24ce03) +,S(1be960f3,38d2a16,703b10c,eafa121c,d59c66d9,439e9067,58a0b363,2a83116c,7fa4ca2f,8218ee04,351549cc,3b0100fb,647e0db,19eea010,62f1c0de,3de29aef) +,S(1f2a2d3,bc5c80a3,8af51e9f,5694a80e,e915eb89,4831ea7e,48472d53,320cf385,a18cea39,174b4c49,f9bcb945,5e6701f9,47053f07,6782ce9f,f55653be,6d3940e5) +,S(61d6b60,70846b0b,b7790861,17cafaa9,9aa67c37,fe77140e,88477f3e,44d04766,c7f4be90,86849ae1,632eb59a,6c96de66,b7c4b1ea,caf724d2,5338c11c,a8f2688f) +,S(2b37093,2d9a6451,79508daf,4be7f26,6d540538,9276fc4f,e6ccf0d4,1ee6cc9c,c002a3f4,2c8998b1,ee16a1d8,616ce0b7,91cdfc44,61839d9f,5ca0090e,295beca7) +,S(48f5c3ef,aba8b7a3,4d7fd136,fe9b01f,64af0e95,6a27663a,87cd6629,f2708858,8cc38cb7,fce46724,7c2f09cc,52f973be,90aefdbf,b52895e2,b88f03e8,fe32b5ab) +,S(e609b597,2e5ec227,6f5cfc87,67b6d534,adfbe9e9,9e60b86,e981dd9b,3e62cfa0,6be9c1ee,ff205fd3,e3b85e3d,bbf1b27a,335ca616,9ae189f,a433e65,f2b43081) +,S(ebe40b1a,5b2c9cc8,46eb8ea8,1ef0c1ce,f19a767b,2da6ab0b,2ab66a01,b16d205a,2f7710e8,e4fecbd1,39899bd,1964f5da,967d6920,d70b2f4,45d6f914,97c67058) +,S(97cd4c39,9391b1ef,653d32f3,9b062bcf,dbc72d45,83d81b3f,f70df659,358e3abd,a05a6184,a175b6de,f9bc35c5,6e9f5cae,263acf2b,a233bfe8,13dd98a7,fbf37968) +,S(826928aa,1d3fd0e8,53cd99fc,e6559ae7,257343aa,378100e,bf64a3c1,bea7e6d9,bc4a2db1,a3bde90a,ff50fddf,cf6f844a,faad7f8a,89bb399b,20b07b2,2e1efc79) +,S(3e754097,f3ac95dd,176e9181,410bae7a,83bd1431,6772e398,967ed39a,5fa19121,746cce99,c6a2cff8,a0907ea1,5cf9436c,ca7f94,7f3f1801,135fe675,a518df32) +,S(ce539464,b49b9947,808a236c,8a027066,82991f46,3bb828fa,44653266,329365db,3578fec2,b8bc4763,61f2fda,29c2c38b,a7bda79c,11b2cd41,a74d4c02,762e5dd9) +,S(c933d9d9,cda615ad,7ac41d6a,e64a77cb,44a2b669,21533669,2c90c3af,53e349dd,4a6da24f,83baebbb,8f2a8ede,298babce,a25b054a,a1c4cc11,f9f0b0db,572c610) +,S(459aa43b,1aa9815f,e9116f2e,78ddddef,a78e2def,28027d51,d081a3bc,800b2ac4,1acedbc3,de995e30,b16900d4,cddcd1f2,5c615156,fc29645,4bd5fc7c,63e993d5) +,S(5f2aa5d9,9862ad29,eb467564,639abfc,ff445334,9a30c4d4,3b27f913,1e3b0a5e,571eca2b,e61d0bf2,d9def9ba,445b39b2,5acfbbb7,dd4e2cfb,ce7541c9,61ace144) +,S(ec66ea1d,e6cc5d59,8c393e68,1a338549,fc2c3d7f,947b40f5,75681e60,88f4fd1d,d711ffdb,3b378435,5894dfa9,d0a5497a,5540739f,a3706597,8ab7dbea,a9280f52) +,S(6ac53df5,aa097f2d,9983f018,bd1cab39,69ad0638,c78547ab,1a481682,ad6105fe,95f69a81,5127b919,9488f224,24307969,3cd51796,bba08578,abfc8e05,6618a598) +,S(a8a3e9e2,9e4ad0fd,c466dcb8,fdc02cf4,16fb5c85,b3454fd,3842f129,9f96c0b0,df86eb3e,3006dea5,ed6d152,f394d7c3,169b8d09,bde3685,ce138a55,6716dc2b) +,S(50a764d2,a0d8741b,95ec84a2,feda6df8,1dbe987c,31861166,32c40c3d,e6db251c,b28203f0,233917c1,4b67632a,ce9b512d,76a8c7e2,430a4a40,85cfb422,7fe41055) +,S(c2c314b1,5ef9df1d,26856c9f,a6e39cf9,1bd9c584,582893a9,423746ca,1ab51ef9,a27f9286,ff7fdfaa,b949a9f5,d59f08b7,a22f1e31,e7175d44,93e219a4,e92ab759) +,S(ba655585,da44c8d1,2b3ce375,e220a4c3,64868b75,370fdb75,dbf6bb92,76a9d3df,3d64e16b,a03a385b,def18f61,432cc49c,bdd9d04e,6fc8873b,e51663bb,ca4fda50) +,S(3d45fa49,d4d100a4,b5a76a65,1a5100e,56bd0d13,b9e141c2,aca5cfef,a46e600e,92953c,38eeee42,e1da93b1,3c75ba48,da30390e,731801ec,ed5bdc2b,58059176) +,S(e464c346,e40dc3e2,40e5d96e,1fb2c10c,83e5ab7f,45138596,4ca46b04,bc8c3a8c,63f14b46,182950bd,282205aa,374cd67b,ca364a4,f57cf90f,c7ac90d6,5204cf4e) +,S(14a7e12f,e235b307,5b0d218,bd3dc720,d56f3fe4,c73841e3,fdf42dd5,aea42688,d79683cc,40cef482,ed6a22d4,8137a4f0,eac31249,9ae13809,9eebf3a3,15e9ff2a) +,S(8e7afbb8,21af73b2,25b34ffa,bb2ff6f4,61d2ee2b,85d5d936,a99fb078,963828be,40e4776,5aa0768c,f055bea0,e20e1062,bb528470,dee61ec1,6cc9ce7d,ae6b1853) +,S(9d641162,3227bd0f,4bcf9f1f,9e5ce829,7d844055,8a7ec246,5b160690,53297573,ed0d83a0,68001be5,70067ea4,70fec09e,1f8630d5,da5d1b2c,126c35c3,9b07fc8d) +,S(6758c6d6,d9e49d9f,4125b52b,e3da74e7,52bb40f1,44af0f0b,7bd80589,7fc83eaf,749ae08e,c2aa2c36,3a229b3d,e9577dbc,5f7d22cc,d46826e3,6a1cb434,184fd292) +,S(b3e11a0,45702d8b,14d93df6,3a4c11f5,32632719,b4a33fb8,da11514,bc61d73a,c6e152b1,2b267ec2,1a23892,8cb97044,9660c6b6,34b22d18,9a86fbd9,a9d562eb) +,S(50a325ea,3b309911,1371b0f,e0b9e276,137bf43c,22108b98,994ed5a0,d66fa5f1,946dad1f,d39e0aa5,8a758527,9b39efea,8a99399c,2750739,dfeae140,3745b70e) +,S(f7c8f249,3befd5a2,cf6802ce,8ac508ee,a97341a6,a46efe39,1214e322,e95e9661,3c072cc4,eec1f370,144b7ec0,598e4d96,573883e7,fa3f3f5d,4e33d88d,1e34cb67) +,S(302d3b50,c1543386,f0b0b94e,9c49ea68,38c7e7bb,86c28cc3,c8965dc8,38f85b6,988047d0,d891aa2f,60b66e5a,96c78c91,3588d128,d4e7f720,5672d25a,88310744) +,S(cb8ee728,2e7e5ba6,d0e8ecb,55ede89a,1d3810fc,b0d8f86a,fbf53b7d,219f0eb7,4b04ea2b,efad1099,8c9a4e3,cf0491c2,bc10bd60,e06a118e,75fe0163,ab8094cd) +,S(645caa2b,4a0cd8aa,20cf6f04,ac73a49d,74f92035,f90bd31b,211572d4,cfd5fd42,793f2996,35f9d7c1,de62b64e,afe516db,b0aa1323,7f51d0a6,b6fc8346,fb7ef5b9) +,S(4d37342f,6148b5e7,5434b8df,6617d64c,f00b1c73,3d85f4f3,e69c4a27,395f5a21,6400092b,d4c5c705,464a7db2,b1b6b667,4eebd7dd,38d05cde,d1577d8a,53a708bd) +,S(e634bf17,24e07b2,b4ac6285,ed28bd39,747a2134,36e76d3d,bd693170,18c0e0d8,cccbcade,4b82a51e,c31d9d8b,6b113876,5e9660fb,e897ca53,20db873,13e9f021) +,S(80a00de6,2767c513,d5bff535,431d259a,64c49006,3bbf992b,a5111005,360cef38,7dceb589,e8d73366,c467e23e,8fdc7e03,b2620df7,9530b6b2,3fcdcdf,628ef572) +,S(606d50e6,d23d50ed,9a5b8409,f11d5c76,baf5b765,f719625d,5b2e2dd,9e8f8a0f,19f55492,45b1b4c2,fcc1d220,6c171200,4cbb41e8,bb7c8cc7,48c4366b,3fb32788) +,S(9c8a0a14,f7d44fb7,4a7ea835,ae4a1932,266c3083,38d66a24,7fdd60ee,e4f0420,42c6c237,31578dd2,31eda621,81aedd29,8737fc7a,3b2be8b4,d0187459,e5d9169a) +,S(d6ccfcf7,81a46f58,ff9a0154,8a417924,1a32d3ca,43a8e59,cebc33db,1e35da1c,a1caba1a,ce846b8d,8b4824e6,1570f832,87cbcfbc,910256d5,68bdf223,861d084f) +,S(8cfaf36a,3e4c3ff2,4556f446,4947c8d0,6eed5ded,a40ec0da,4596bad9,f5f2e3c4,991b6ecc,ede6cdfd,e33f81d1,c1067f22,6b72373b,96ca31fc,c80e0692,d8f3c4d7) +,S(d46c3d81,5b0f3a0b,bcef3973,8c6a6cc7,189849b0,4917fda0,541c08eb,b7e664a0,35524bb6,d053e5d7,c8adc9b6,3a84ed81,58cffe99,4041e642,1fece58a,d967c159) +,S(8ed7f0a5,2f1f8df7,f82dce33,e4637dcf,e2ce9b75,ca02ef04,90c23fec,2b7adfff,f02460c7,b418d10c,96c27225,3dee3b66,4be1aa5d,427759a5,5d90c223,628d99ff) +,S(433ecadc,a8a351bd,52ba4d6c,aeea3ff0,825c46b2,8abd2c2b,cea85f6,6daaa2ca,4d3b71bc,c2d7d177,45cd03c4,86f390e3,f6d396fc,83d0438f,983a142f,162977e5) +,S(c0771ef3,10377f83,7a9bbddd,81f6642b,ba04493b,15c054eb,249b3f9c,bba006e6,3e53ddab,1d816a02,7898c6b4,778d4c48,e1ea2b33,a63955b0,784df258,ef4ccb1e) +,S(dc2e0226,4a6a87b9,53997383,e35c6cd8,92072ba8,a741fd23,8ff3a9c5,f597ad7,898ee746,ecd5f723,440ac0ff,6f597e85,8ddbacc9,cbc80e01,d8a3c1f1,7c12c74d) +,S(16bace34,59ad8cbf,1fc5f781,19cd9e31,d043d7b2,ed839f03,11f0b760,6adab771,f64532,6ec697e3,2ca23979,72b2b834,66e835b1,2bd49243,e896c1df,c02fb1c4) +,S(afb94d8f,3a271439,146539a8,68f00346,9af55eda,839c81a4,725f3a5,7d69c736,afdb294e,a455031d,a70a4eff,7563d764,bdf37fa7,5594c9cb,386e8bd1,a35201d8) +,S(bb31d236,4a98f7f4,1edb0ae7,6018e5ea,ecc33780,5f781dc7,6b15aa9,d0e89b74,1a064c03,1f47cc7e,cd49f032,f4dcd95e,87cbc28a,7b9d9c27,a92a4c1f,da031a9a) +,S(f73b1b6c,4bbf5da8,16604ee3,ef6e83b,241e486e,d727e700,1c3c115,3c4318b8,9a28ad6e,9d64cba,b58ac225,5c01b261,25ba08ef,3b7d5ffb,476f9b8a,6c8c9b17) +,S(63bd212,d0ddc5a0,84f8ea7b,69605b2b,708c8766,f0d3313,b236e921,91afa8a4,ee6f4f6,4824032,afbb0b3,a9fd342d,2fbca8e,ccecdb0f,a3307698,c56c3e67) +,S(6367d22b,36068022,30a416b7,8c689078,967b955d,875fd629,9e007f86,1abc6465,c3ee1f2d,14e6793f,17e444ad,5595f9b3,118d1647,9259e0bb,ec628897,f69417eb) +,S(64e2e543,fbb7f52e,57901e3a,448394c6,c922d0f,b632c4f,2df061a8,9485976e,641a602e,336a68b4,fc447e5a,5863a4e6,89511942,4fce011b,48f937df,fcab2a4c) +,S(2e290afd,18c835c8,d1d79e86,9d9c1322,e16e824a,60e67f38,d6bf3031,e3fee1c6,7f85628e,d2fa6b67,7686b0e,c29a3626,da18ccac,5e373874,96266458,79390f21) +,S(859a208a,c475d3d,f5f22907,988c7774,c0ba2dcc,d80ba42b,17ef1087,2cee401e,a667c645,778e743a,d62ed1e3,cfa12fcf,84b982a5,f1349e31,33627ffa,8b19f5d8) +,S(c9291908,ccc50aae,f19c0b86,829fdc63,b608d3db,d92b0939,b92ac02a,2bcaf21,e5c52bb7,47111f58,c71352c8,b2fc89fb,20cb7d45,77c6231a,17d8d01b,6cd2599) +,S(50359490,42b5b620,78ab0141,1f1a1d4b,64bc42c7,58da4459,b04d41c4,61cefb26,f61e823d,b68c064f,f80d9bd8,f272f817,347c132a,f7bd2af1,e5b451ea,bf4f04e0) +,S(f9bcfae7,d6a3f1fb,612787c3,53b535ec,39f29a01,9f45f43e,7b61f2de,c4a4cbf3,f4d86e6f,273ad7e7,902d5a99,50fc846a,a6565862,aeddc67b,28fc07a1,232ff883) +,S(1c8fe8b,901cf050,e93c0004,b0764715,602ac4e9,7f8d5dba,d7747039,f14a9152,b25ddb34,7c452942,92143b6e,cb19f87f,b42a0f27,f6f74c4c,99d7b80c,7d36769c) +,S(3c50be1,4cbe3a87,d363947c,6eb534e0,8ff676cf,412bc4dd,2c543131,e786f552,4434471c,6e03f600,d8a27775,4466cad0,194f553d,bb653238,8a0ee4a3,9b05a74d) +,S(64cd71b2,555472f8,fa968b4b,4f8c8b24,5b3e91ad,6d9dd409,fe72702e,e70522f5,f1b1cb3a,e9fa4855,2d7fc2a,819bd629,40350a3c,168782af,5bff16d8,89ede304) +,S(c1c00444,c584c346,d1bdded8,7cc40b0e,fd8f69e7,d2ec8bcc,c41e3414,619af7a8,d631b494,3e3febb0,87bb391a,d5810b61,f78dbccc,bc6de38e,ee09005d,3d879436) +,S(fa509582,dad5bb61,c7450fd0,3b7e4ba0,2fbd0c28,af971b96,cbef5956,3fa2a7ed,267c2764,617c2f78,9ab890d7,56be2195,2acdff5b,3490b816,165e2b36,2f3df4e5) +,S(655dcee6,864e926a,a6e05f04,b604c2da,35175e0c,f7d264d0,50920d46,c1a2386c,da2eaeda,bf062cb4,ba2d36c4,67965baa,5f1dc238,b5e22df7,2bbe14f2,cfee19c8) +,S(6ab5e1ac,1b7be624,97c8fbe,fec5c4d4,2cc1de06,d15a1beb,7606fc0a,df3c213e,26f983b2,4eb319c,7443e024,7fecdf58,f833928d,4e809d3c,f36231e4,d0a9e466) +,S(c7da869e,39caa2d,e9f73a0d,3f73ab73,6224e2a5,47ef5af3,5f5a9d51,60c25f3b,e99b1102,49a607d8,12af4cf6,76ae4c4a,cfdc0f89,9ec2175d,c7942b6b,40da579f) +,S(2a6d4ca1,5f1c3ced,ed68091f,af4d149b,e20b6854,bf015084,a9cc0d21,4944ef99,dfc27688,ae9295e9,ab8d9284,6a703ac5,5cb44bf3,13f179b4,ced6b638,e661ae0) +,S(447260b3,bba7224c,aa659f70,b1e7716a,92600a27,18129575,2de62cda,11c846c0,f17e3e0f,33ef2ede,8980c922,613947,8331e2a6,40260996,db8da1e0,dc8999bf) +,S(8cdb1cad,baba7003,8d4b0f44,1b312aed,5a8788a6,6e5356fd,5b994f6f,a7781969,b3a5bd0e,262e673a,ae7be06d,8d56c203,b88750e4,ba06cfa1,7c177edd,74536977) +,S(28be0f50,fb60f905,18323e6c,dcf46c0c,bc3e2c0f,175d8576,85126a85,d5caaefe,5cc058f7,fb188c4c,e1140429,568c3176,8d986fc3,e96409de,21bf9ba3,862b7320) +,S(b6dccba,dd2dfad4,8b69218a,d9cf839e,837e2262,7f8f0eb6,f23484a2,994673a0,e1c14ad7,297f1626,774aa2ab,5dcc730a,49623176,ae81eeaf,b52cfd4c,fa2de992) +,S(e45ebec8,8813f7e5,7a7ecec9,dc5fcda6,b9cbb0f9,19bae1d,be770955,e3766a87,3a62a0bb,4ccf3783,7c384885,7acbaa9f,f915cc7f,13a46856,3ff135eb,dfbb07a) +,S(de926f77,26f39d48,1e0b9e55,22b7c874,59bc9d07,df65f0eb,7b21fea,e8dccdbb,9d190ea9,263d4240,24b618ce,1239f6e1,115be2b1,d721aba0,f5f367f6,304d8e05) +,S(f7621384,20669c04,6d794807,569722b4,91e4272e,1305f091,b54a03f2,ecf2caf0,d0c7e8e5,a227f2a9,5c594528,4590caa3,3088c92b,b4c7cf6d,12d293d0,4b9e4914) +,S(4e795e86,44ffee08,f44d472e,8ba0eb9d,a5cdb1d1,619a437d,4a8bbfe8,565ce751,5292d8e5,478268f9,bb9b4be3,c751e587,65038c55,99cb3549,749e83e2,1590a4e0) +,S(70e64689,a944b03f,32b33a97,c8923531,cdf75e8d,e8577559,bf45d2d2,ddb50b3d,a675c6e5,460b89a4,a2dae263,c71e6edf,925a93bb,a916951a,5364d252,c225586) +,S(21637c2e,682b247e,cb8c1c,8b4bff1f,477ef390,3b9da0fa,b08b5cf2,5b67056b,e357165e,3e761a55,7e4c2b6c,727d8387,c5716b58,e24d0e04,8314979e,4e92d882) +,S(7691a399,8dad2e1,741a4135,18bdbb,d8ae5bb1,7466a949,a40560a3,9c1d1964,225f1404,b05b5bb6,cdbf2296,f76e7f27,257280e,28c68be4,d8c81c47,a422b74) +,S(748316a4,f3950849,9af5a14b,27eabf9,b0d11e91,d8752cb,69899af8,79af9302,cdcdd4d2,6bd709d8,c3d87c12,6dd8a2c4,f600fc1b,9e84461f,1793047b,5bfd7ee2) +,S(af588dab,3839e85c,6dc84aa6,c1e05294,a9708951,8006b390,c2ffe0ef,f6ed9b8a,a3d37640,1b06548f,2794131f,5e002aad,616ca135,8cf0c81d,87015416,37d9cff0) +,S(bd91dc60,31706ffb,19b61796,995728b0,5f869d07,6f0b6537,35c46e10,d9b42dc6,3c963ed1,5a74f5c6,1a28db8e,de070870,cdce2cf7,d6525a6d,16171076,44f153b2) +,S(e625c4a5,91460bbf,5c3aa583,c4cb1e1f,c202c82,7debb82d,985732ed,ede98f47,d026c5f9,a9035396,1de50534,8e4ac600,812a461,c913299d,7fddccc1,5970b72e) +,S(6bd227fe,d4b193af,8b94553c,718357e4,122cd057,d95980e8,ebc8fe5c,7fdaac1c,5f3fe540,a98b044,9ed835d3,b0a2b4e7,c66a0549,e4b7b9f0,22fd5249,c621a9f9) +,S(27707a25,895e6f38,523d3872,c5b34e7c,68a0f0f9,54c6ef49,5cff6664,1edb2609,ef6f4f8e,c893d697,69f34b38,f7f677e9,e5de5c91,48cdf35e,3a18022,3ea777ee) +,S(6052248e,3359414e,bb7770ea,4284d7c,c01770c0,e75466db,1f314e0f,cff0ebde,3d982058,5cf0d546,9fa62e02,aa556fb,1a1ac7d3,1cb9712c,8b118e2a,e3f7b7a2) +,S(f2cb5b53,4fa6124c,16d82506,8b229857,4d4fc666,9b45550e,6c75a114,f370f6bc,5cde5707,63a5cad2,13952def,43cc779f,8ec9dcbb,c5fac8a0,ad7a740b,7241112e) +,S(77ad8215,9fe6b9f9,e08030c7,a75c601f,4989b51,4ef6db20,aa9d0b23,e87a502e,9268a1ee,ffc24932,74856add,2ba1ebb3,c13678,99af932a,87fc680d,ea9b703d) +,S(4418748d,171cf80f,a7f80fd7,c2d7891b,5cc9aa0f,ba4ec1c8,a114cbc9,4a8fd29d,5130285,79f01b7f,72f18322,b279fe7a,9916c16a,a67c6aee,babbb418,fb1835c1) +,S(16af4960,6f89c87b,7e5901b4,d11a826d,126e59ff,df7d0883,1d37d7e6,367355e0,1a138440,537223c9,e8e131ca,8ea3b38c,12c8e8ea,50ee09f6,8ca4c2cd,4cb04c2e) +,S(22d2043c,ab4431b8,cf77ba0c,ad81848c,730a730,35277e4a,ae6392f9,de120f9d,d7795dad,5e5b46d0,9c36520a,c7fccf9f,4d71f9c9,8ed3d45a,432f4f6b,991b8acd) +,S(57e7a8b,34826533,7e203360,2f6244b6,41d92c8b,b2419734,9fbb3271,57676302,4d9238e8,ba4bc8b2,c3abd2eb,6bb2e545,5146afdd,3d1ce2a0,9752803b,4599b83a) +,S(45567f60,2755027e,282b39ed,5ddab1c,7ea19a82,4c0609da,9ab455b0,26acc359,db55ed5a,77a354ed,e4229161,141392dd,82c1ccf7,f726fd4c,2fbba48d,4134f5a7) +,S(968fb554,91059347,9dc1933c,a8453201,798a0be7,1a284c38,3e8fa5a0,f67fa80f,63586b1,6853f550,c36d8394,56718376,1c14101,dd03cbd0,b164cca1,24e8920e) +,S(f366c649,f633cd7,f1fef522,b78f7b85,3d640acd,11af2d17,14c14251,ad873107,5fc396af,38f4988d,82c4cfab,59d415ef,25b260d5,711ad546,e56fb65c,7482c6b9) +,S(aa0c4fd4,4a2e68b2,edc16eff,d2b3c29c,59b19289,1503e6e9,ad068743,fc201d06,614e3224,2fba7977,464b5c4d,b76270d0,2763aca2,54aa5b82,b5ddf8b7,ff3fee33) +,S(6c886cee,19b2cec6,91c57abb,da830e45,da4cbdcf,37484ad2,b4444948,8f2cc876,24cfcbbd,9ab4df87,87eb384,fec64e5a,a197e897,bcf2dcf5,def4b94e,afc16a1) +,S(4d600199,c33f76ee,c81d1686,f116d4e0,fbe5e4ca,df3bee43,9a81785b,c6095554,cb414cce,b769f70e,115d4321,fdfed743,2bf73dc4,9f1628e9,dad15f32,5fae614a) +,S(377dd0a0,196d59e0,e71e8472,4b65bb16,12c3caca,d2f2230a,a675a25a,5d0a4fc2,2c727e7d,8c8e27dc,a5ff7c27,b349752,1159c736,2b51f38f,e0343c74,acfeb560) +,S(9cc0cf8a,23afdf35,1bb1826f,9d900b8a,e8aa5019,8cf36552,9ca928a5,9c820f46,b572f15b,e2aac0a8,c8142c53,ea43a0a0,693e5446,5d5531f8,b068d347,f7e67256) +,S(d55dfaa6,41492b1e,981d154a,2be0441e,4cfb01ea,a51c40ea,d4a4d8ed,19fa3050,2e795dcb,408c74c2,a9898f31,523a1e72,da0c4c77,c2dd2eb,45fb2e51,8f238ac1) +,S(46bf63d7,2d113152,3075efb3,fac6c07e,e3d27e87,279724e8,46306dee,7d210fd5,771bb1f2,30fa3253,7e3b433a,2905c4a2,dc4a2e37,32e282fc,94cb2c88,33b0b199) +,S(4bcfe388,3e77c17,8c6f1826,f75e7c3b,594ef8b8,c1a9ba3a,13f00597,50ca3aad,b5562e93,9dcf4672,fa283cf5,6c05389c,ec5ea923,b47d09b6,2ddaaf54,8a1b0129) +,S(c9681af4,715e69ee,d7cce802,34bb2a49,6255ba39,1df76c57,df9747b8,d8c241db,c8b175cb,b03d5206,5f2bb846,81bdcb04,da530e81,31082e08,28c21f7e,cde038e6) +,S(9fa0a1b,56bd6ac7,f4a2671a,3b4f6ae9,bd5538bd,4c6b4101,790b16bc,c2fbc33c,27f9eabe,785c7cce,e4859959,348b4864,16056f68,6d445fb5,c08fd8b6,33129e63) +,S(15042df0,ca178aac,723e7b9,8677964f,a87203f2,bc0e1fea,a56ec6a4,73d0381e,445db657,dac86b0d,f8f9eb59,a143e75f,e271cbfd,2420b3a1,677ee3bd,8d0183f2) +,S(354f6a63,d4c1877,e0e7da3e,921db767,6b7f9dd0,eaf8b65,eb08b032,1f37e9b2,1000503b,d65b80be,eb72f480,a43efd65,2eb784d8,650bffea,5559aa2b,104ea8fc) +,S(19c36161,7a448fc0,49cd8864,d2707d6e,9e4ba74e,79ae3d8a,c11430c5,99de065c,2f9f9fd8,fd38ee81,94ef570c,1b7299ee,75742d18,1610a2fa,4dd06f30,989acff5) +,S(3739848a,d2ab8a66,b6a7a2d4,add9fa8f,5a50807b,56ce5d39,5bd4c146,7083f88e,6fd71820,611102bd,f4dd2056,92e188cd,68a5409,1036951e,6f58162c,65f0cbc9) +,S(9c22cb45,261c2336,7dce66f1,f84b84f5,2dd7e58f,8ac6dba9,50062eac,1c10aa35,ff84e3f5,8c25be72,910bead6,286dcb9f,605b0017,1996d46e,c8dbee64,52a1116) +,S(572145c8,7f311732,7ecc71e4,5e37c555,5a412785,7513fabb,d0fbdd49,6db4538e,163e63ac,5e3908da,2aed5166,c121548d,5338c6ac,4ea7550,242c7910,8a38871f) +,S(c9f07954,d8413eb5,8ef213b7,51a966c7,4c641ed9,8db8685b,d931e321,2de940ef,9e6844bc,804f3d3c,a065fe7c,b09bcecc,92cf5af3,ede9041d,792c184c,cde17fd0) +,S(ac297f46,b07c8a29,d664a24d,f05a8a51,f7b0e4aa,e8800c3,f9291a13,787f25e3,686e3b7f,78e45ad7,fd1bbca0,54a5d182,b1556c77,753c1858,75e98de8,29b66cbb) +,S(6c5913b,b383a688,390274df,121eda23,5ad55dbc,80bc198c,21897934,98b3e1b5,54b9b83a,e3649f4a,2f11ebf4,61e24a55,53e5b4b5,d0f78dc9,1c35aade,2cb9ccf1) +,S(b9926fa3,f503356b,eca59ee9,2163cbf9,846e3efd,c793db45,cf7ea8e5,af2495df,d6dd7c5,33d4e7a1,ed415c51,1fc15e05,54fd00c,100bf047,bb8f9054,42e2a512) +,S(4325d1d2,f2cabe77,fe0ac758,f6073057,cb36adcc,5357fd5a,31473ad8,74e69556,de437968,2ff6315f,8870562d,560cc48f,818c8fb5,c45ad932,ed5a7d4f,534904a9) +,S(a183e95f,fd84bfca,4afc9059,ce1c40f4,eed924dc,d1bfff11,d38a8c1,14164917,11c57610,c7ffca41,145046d,4cdf95ec,c38d695d,bef057f0,a0d01bb4,41d64b95) +,S(b340d0d9,ad6528f0,d9651414,f48fdbc2,ab7af5fd,3baa8091,84d5e881,6cd07114,85ed726a,9ecd70f7,f964dfbd,40e4b68e,ae2671a9,b6c3d384,919d040e,120dd4e1) +,S(b52daa88,35992fa4,1595f0a4,c9e075d0,b146fae3,6c0d640e,8e6f34c2,16719377,6088b139,9fa83889,a6cb5cba,d478c7a0,4f42f082,24b169df,85ec90e4,7a4ad7ad) +,S(90bbd15,42b0f88e,9f7f82bf,7c2b5fe5,f269ba36,4523a18d,5dc5709a,2ab9d8ad,c9df924a,51af344c,a71461d2,bd3743df,c6958490,caa68743,e06e7348,528fc4e5) +,S(f72ee5a8,1696194f,ed3d4603,f2c9312e,b31c54fb,438b1fd2,2788ea6a,a3aa8365,e2963d82,b6ca0f4b,8ffc1078,cd45a72d,e66f4cc,78567074,4fc1721,e50fde8a) +,S(108aeb71,5bc70525,42f5d6dd,dfd348f3,66a10f4d,d99f9298,c35a8397,e6b9fb53,8388b339,75a58e04,a0f6df47,23728986,97b8d970,ac6bd45b,49b9cf1c,3209f1ce) +,S(dc3daeed,87345ebf,824a5ff5,c7f46268,fe54c901,493e2e86,e2667fb6,ff61d5b0,b5a7e641,238e0467,196c1683,bab47f66,cf001079,932a5d56,da20f89d,d93411e5) +,S(3f96a83c,2be16120,e81e1d26,e3853ef3,a82c5f32,f8d6bef9,38179c06,4265c589,eb8d370e,797cf20f,d5a0d734,9fbd027d,630ba1fa,bafffa0f,2ea37131,6b5c64b3) +,S(27caf86c,e1f423e3,1cca2278,244fbe3,b358357f,af1b7866,1de13b96,eff5c4f3,e8f77718,647acfb4,633ddbc2,3dbdca0f,2187e24a,2f2d45a1,39bfa1b8,a2b30f61) +,S(6681cfb9,e2418786,1887f964,84819645,2d301a1c,7c082361,67a24c62,f74d04f,9c89eb3a,7849e944,2f5f521c,c08d11ef,f1ce4869,98d4d760,8dcb4a37,b815151d) +,S(6711b849,48664639,67274709,2fbbafa2,fcac45dc,1795e80e,67fb0e65,beba8da5,ca12c83f,1c8f5ed9,222d8cec,bbcaa51d,6b986a5f,60d2c118,b812b259,294cfcc6) +,S(5ee9cfd0,b1102cdb,a0fd22b0,569875c5,fdd73467,22769011,8b7843e2,b71dd94d,1dd7a4e5,bd7f9ee4,e17c518f,19b60332,60d2294,8b5f463a,ed9021de,87d7d86) +,S(586dad7b,13390be6,f3d95a46,6d0224de,d7538f1d,2d2d9785,e38a3f2a,edf4924c,c777eda5,a68a3582,1735bd33,7119e58c,bc2fb101,c995f986,7bed9786,cc2b64d0) +,S(5a752d2,fa012c7,1924b6e6,90ddc7e8,867f6ee0,ad8eed91,84f7250d,665091ec,57f2232b,32b36429,f15029fc,5789042f,ec1ace97,5f2cad27,d53ae819,47b95db6) +,S(f93cbeff,22bc577e,a9cfef22,378eb142,426372e0,7be72e60,2a8064,a53e638e,abc772bb,401bdb42,94b16670,2279e4f3,eeadb75d,57190a59,96f34237,83afe50f) +,S(8c272c9e,96130972,2efc34c3,6a6e63ac,76052cfb,856eb8cc,3dd014e9,d2608a9,9987d168,13c57162,3ba7d226,18b54003,731e3716,3495edfd,e85e927e,6e4607b3) +,S(bf78a0d6,1519542b,a54226c4,d386ddc0,38dfd84c,9f9555e2,3e187c11,4d769bc5,6094e1e4,d84ec081,e6014b59,d42959ef,e160587d,315bcfe5,5d26ec98,b1910280) +,S(5b264b76,cd092a1b,ffbab651,f42485fd,497aaa5a,e311eb28,ee1fdb99,32e65caa,944f9359,4b68d7c3,6610fdc8,85695b06,1dd84722,d5d88c84,c8c188e0,69d70d78) +,S(a2473cea,8075a0d1,33bc1459,8d147705,322f7151,274e797,4b7e042a,c082b559,64de830d,b6557b06,d9b09d79,4f6c905b,5168d32a,708484b5,d2c68a89,a2575a18) +,S(3e18d5e6,3dd0c514,4341535d,a7087bd5,f14b0708,a292350,6528a803,609efa45,6e9c71b9,7d007382,f82fd041,be53470c,26dc2f16,26a9f0a6,e1d9ff67,54288c5b) +,S(d1acdbcd,b91e6315,bce96eb0,9c229086,6a767441,4285984b,71af6156,8294dfa5,5e3b0cd8,9872375c,3f807201,73e29d3c,accb67e9,66b99452,2c9e9f88,613da5a4) +,S(3aa999e2,9344e0f2,b5ecc880,a35ecf75,25ddb028,c40f64e1,a210aeb7,d850c90d,cd2ce25c,fbe3a1be,dd2e6fcb,e9e9a881,28c454e,c7ca1951,5673aabf,a543d42b) +,S(98a2361d,7c3815cb,ecd0aa4c,8a3a6ca3,3e1b31e2,5a4b6398,146d6709,61a5017d,1f33df78,3040c13,be821395,8d78e039,516df25d,4d9d0de6,d397128a,2c09f2bc) +,S(528b9d8c,907ab870,6d7a5562,84cb69cb,ff348247,be1b7cc4,61351674,53d98d0,f91eb836,d6665778,7c6d67bb,800a1141,29700d53,194c5051,aba7ead3,ddeafabd) +,S(f1adec8d,3d1b0d20,8bda6a86,6b8cf730,f4be50e6,2c8d993a,3556c1ce,625029b6,478324aa,c3bf6182,25bfb61b,32d47956,57e4a754,e08a978f,964741d4,1bcc7224) +,S(ab2ef133,b1b115ac,41870cf8,d75d4aa0,e0181ca,742a8f10,f74d50a7,3924a099,a2c47b74,c584eeab,57949ef5,38c0af69,2f2baace,70a730a5,75629ab0,566a91ea) +,S(9d4eb41a,f6da6f83,b1d20e2b,f9370868,539a617d,111b8c72,348c9b27,e0576f85,c1c7b00d,b786c84f,a8adfe90,4353305f,73acc3c7,1c2580d7,cc5d6b33,c5f30eea) +,S(30edd57f,7b1b2c81,c886dff0,5d9e9062,a553638f,9e4311d0,18a42229,3fb916d9,6bc4774b,16d257a1,81e20b48,5acfce30,f7449e64,aa288502,d44e7c4a,44842ee7) +,S(28e3eb9d,9a2b855,65c58fc6,a492014c,f10969a7,1e81066a,41d1c574,31306583,fc653b87,80734067,e5245c,8c150ae3,59ad3c15,df4a8e7d,dc93c8fc,dfbb6c2c) +,S(cb984735,e3c842d0,a2fbe578,ff3e8263,5a3a8bb6,749d8e08,c91571a6,9aac75a3,e935a0cc,7181c3f5,3013f977,ad714af4,4c3e257b,e9936268,b481429b,7bea8367) +,S(36186672,7e8307ea,eea83b10,6850dfcd,5e4d665b,20aa37a3,ed0051ab,a40fe170,ec626ed3,2ae6dc01,f5d4c710,ce2cb349,ab27cbf2,da5d924b,e32ef8d1,707a6d) +,S(b1a40d5e,69e9f365,c2accd54,dc8267bf,4260abb2,3b503136,2183b17,4c6b7d2e,76619dab,2a7b41f5,2401ff89,4ef632eb,31eddea8,bae27c3,af04730a,3dc186ec) +,S(abd488b3,dff60a23,e83f0ccb,22620064,b32a8f35,d4c22be2,42eb1427,15660825,6eff80f2,17dae3af,96c7a463,d1848bab,fa994904,91a1105b,e1bf7f23,840b3a89) +,S(ac0cfb04,d91ceb48,2f497974,321bdb10,2a572115,73fe4598,c92510ca,4dd6aa22,6b5f6d87,4a90d0a9,658ae4a,64474d9a,3950314a,4662ade8,1c5e5605,274582d5) +,S(1fa8be0f,476c4b67,697c7541,dd1d8be,a3a0bff3,552948e6,87baf11,afc34432,c6b25084,8038461e,32961d20,181c7187,fe79df6b,8f5c5e54,96ddb5ab,80788d33) +,S(281b43c0,d3738989,a817d313,755c5f0f,f336a4d5,7e8d0ec9,b29fb425,c1f90e56,26b5070e,ba1059c9,b73e3db3,1227a6a7,68683044,7f823689,921a9bbc,bc9f4a9c) +,S(d64e69e9,54e81ec4,7446327f,55e5a82d,3b83eb46,2a92af12,f0b2694,c88f4052,aa7ed55f,284c3ca2,9be75565,f66ea54a,27a8f00d,afaff0d5,8f394797,3dc8622a) +,S(f4cdbaee,d4b01db1,f0b5b0c9,d6178235,483fb58c,5421ba54,17bbcd4f,e4e7b028,66d590eb,29d69904,deb9f48c,5a250089,b2b92447,8ea91302,1ddbab19,6c63b47) +,S(8ff94c4a,6c46e334,feca809,79d21a0,761fc1cd,1de76f4c,7243ff0a,93c9dca5,123ddc33,5f3c68e3,29f42d4f,187fdcc5,77207134,a8bb777c,2ab08dae,f149abf7) +,S(c7869b4,6e34186b,7e87c0e6,23b64fb0,efed70c4,f2af5e70,5c33ecd1,27cf267a,66295439,36620898,2f17d95d,7da2bbd7,29aefa4,69005a59,629720a7,5c11f48a) +,S(e0ea76c6,ad5dc87,bd26ba9e,25b5041b,9836f72,6eec0142,351b2431,6cce1a4,8bd724e6,632049ab,88aa620a,78922b65,6a3a4417,c8af7dbc,5a03d4b8,d4eff928) +,S(2fa63ac7,3e5f8982,36419f1f,4883f52c,e8e357d2,4b4aa7bf,c6aa7eb1,29e30159,57e1601c,d6323fa8,f5a5b314,6b5e5c44,7251db28,6f79d51,7d0b038e,b8d8c3fd) +,S(74ed4038,d4c50930,22e783fc,1bb7a671,49d00877,b202012f,6aa6d32d,c73026a1,5b74f70e,65d009e8,8cc618e4,9f7bfda6,58234f80,38e9835e,80e6fd42,6b28476f) +,S(71d6aca6,e38713dc,6ded1f93,4fdf20fa,16ce75dc,dc405148,eaefd2d8,f0025f97,b4314533,7d48dfc8,278c6c4f,b19f69d2,72ffd4d,a22dabae,dd3e60a,7067e302) +,S(28fb47f1,6e91bc9f,9a2d5720,f40297ae,ee617ec6,897044ac,8a174acc,5bed5292,d04b6961,d72472be,4fcdb605,9943c1b4,ef8e7aed,2ba7859e,bdb84a4,f8b498f7) +,S(68fcd5f5,c8655b5f,5d2fca79,59a7b32f,828c5a5d,e262f6f8,94270ee2,1f47a37a,57480650,33627166,c372bc4e,7a710275,7aa1ad4e,5460dfb6,d3d27f32,778d74ab) +,S(c7617ad2,f423abc4,7ed7f8a8,a7a6002d,17c9744d,1ac6be97,49110685,95aa36da,d9904b67,fba96cad,cbe7a9db,833c614a,69e330fc,a06ca2e8,d597f657,b7121d9d) +,S(a7ef4e9d,2396fe16,c0e78b95,5259a9d1,474fdc21,8b24e8c8,df566192,a6487cdd,d6782604,91c6be04,98c3f7e6,86f22f37,23c1e4dd,4f7655c1,f40509ef,5af67f28) +,S(f3be7846,7ff03676,4ace420f,4091bb2e,71856d18,9e24890,eab6b436,771e2578,f3027657,45cbf3e5,67a6966f,6b27ffc1,dc58f3a,6811f309,434662bb,636dbc5) +,S(5c947f95,5bd9ce29,5214c30,3ebf4f35,6c8d9e2a,4e173470,94d3f755,36f0259c,b6b7b775,3e7552a3,d2dfdf49,8578a24d,90a81d8d,68ef39c4,68fb5ca7,b75e76cc) +,S(236fd960,c3b1735e,279b8702,8c25a074,2c54c189,d1040c13,4e4cf40b,bd8b2c68,9ab59bf7,c0bac18d,d0d9360e,b79a76cd,b44bacbe,b425d181,873ac390,59bbc279) +,S(c92c9f26,17cce2f7,659d0243,8b9d8932,c1a9e9ff,ca8b0d99,cd7613b3,b1947b31,abdea94c,1a5e64eb,65e70769,51ace2b2,e4804ddf,1539d50b,725fe09b,52357a51) +,S(986087c9,142c608c,33783a12,4d22c316,733c2ae8,bc1fbd2,8bd1a142,6da94fc0,14925bf5,fd76b51d,6be82c65,4562cdf,8f5baddc,eb26c68d,3fa6113f,ab42a1cd) +,S(465a1f74,f4f6baad,7c644e21,f35650b6,22424e93,83b421bf,91478621,a48a1d43,26da71e4,179430bd,ee6698d5,7db01553,d41c147b,83247157,9f2fe923,c788cb48) +,S(dd7658cd,f28117c4,4ff3c88b,d0b46adb,c7aa2ed9,1590ca00,785cee6f,5c9796b4,32317c0d,1e10e997,a74935a,8e45d27f,9a9b8ac0,f77dcf37,c1c7b340,cfcc43be) +,S(55bd2abf,a803c49e,b4548b17,725f52fc,6222af8b,dd9aed09,715ceb87,57c72033,34ad33b3,9d7344b3,abfc603b,8dcf2a54,96b991b8,41564e35,53adfc85,3d3ebf43) +,S(77be5c06,d10c226c,8c9616d3,15b1e1c,44006876,4189fc36,db0c88a5,ec12fcde,ccf2cbca,5c474949,88f27ae1,b0361b9c,20e8b55e,d965f7f6,ec8fd9e0,429ba01b) +,S(fab72486,3eb6f261,f0460b19,bea7dbdd,80b890ee,d4bb5618,30db6af2,f52ab21c,914f03a,408a2e2e,aa9174ed,99d80e68,b67f6afa,fa9da5c1,5d22f74c,8876d0b0) +,S(232a2039,fafe8b86,50a671f8,de78314a,510db65d,5cf105a1,9db8082,2a0b2f66,14ca7082,510bc1e3,533b9f6e,e216ec13,3be3a6e2,64d2e218,d95f3ec2,ad78576a) +,S(b3482839,612a4ff7,a0584752,68f13e69,deee9fa2,894a8cfc,64e39054,1b7f58e7,722d02ed,df30025b,eb4e9fa,f7c58de1,653b8224,66b1193a,3f2fb71d,5d26ae44) +,S(d3873a57,b0a7587,cab10871,a9322712,cf6fd84a,226dd7b2,85823996,5a353210,3b7e4984,59c7e706,cdff95b1,c55e3351,f1f45d0c,c9fc11d6,60e5e27f,5160f186) +,S(8828788c,eeebb2b7,71d289a7,147c0a7a,26a049c3,26dcb281,cc9b2dba,162c20ad,e428a195,87425f22,3d798922,b4971c26,5da2fa2d,de4a364c,c8c65f48,c07b71a7) +,S(79fee531,26d0c00d,74986c18,993fa174,52f8dbb4,ea75680a,37f0b3f4,ea7e537d,fde50071,3143f994,b4d7b4a1,43ab3abd,525cebbe,93d5b5a4,560017a8,802cb5b6) +,S(f44f39f0,5a9f5f79,5f0f3a8c,e03ab50b,3672429c,bf699cba,ac1e58a8,66814e91,b95e45d1,e4de1300,950a27af,bab28bba,ff75a246,46ac70e3,fc09da30,d59a1dd4) +,S(1138e209,baf9c9b7,b89d7d78,832cf7be,da45afbf,3c2fa148,50426ec2,80aa9abb,15c28d6a,3965b2af,ea28520,7e67f2eb,ac7d5917,9672f88,3727e499,f06a0d6e) +,S(29d3e942,1b98d78c,60e4685a,aa503130,dcd3d3f1,5afc2620,472b83f9,34912c1e,90a514f8,49680969,215d46b6,db7c53b9,411c8c67,c88bace1,a6d45ca7,d2bf5825) +,S(a8a36a94,5fdd33e0,4f0c18d7,cd2d4709,d6efeb88,a53fa0c7,e90969c0,84ff3eb8,1dd7f905,edbfcd70,26aedbe,1cee1cae,23db1fcd,479f02a9,bb596af5,f56ab564) +,S(5a048ece,b3fa944f,90eab4f0,c3e7a06c,3c35f2ca,81263fd5,3670c212,6a981eff,124f1bae,b70fed65,d53caf7b,5e88077c,8e330d05,692199b2,4b3d6d4b,b7c886ff) +,S(32070282,c5ebc2f,665ee579,c645fac4,fd1eb4ec,d7297158,3dc81288,e932b8ba,8f69662d,d68407e,dafb11ee,8842707,c17eda9a,803cbd55,b86dadf2,85bdaa17) +,S(7c22865b,fb04d3f1,bb988a7b,80a49fe,c7810593,27a19786,db77a47e,57afe787,a02eb26e,30f599d7,d5599734,439f19cb,d0830b72,60e70d53,97f06e1,d036bd3b) +,S(a0ba4c13,30ad8252,c06c8269,a3dcc365,fd842e5a,aaf33a4,22de13cb,b9385cc,58ecab13,5cfdbbf7,f3b6d2ce,277b9e84,940fdb14,47568960,c13290e5,fe239bc8) +,S(42ae6042,c8a2ba5d,c8fe47a4,12e2c0cf,7be448,70e67819,4e31ec23,44f76309,72ad69ac,7ba38bf2,2210a6e7,53c64467,36ea3a23,cbc96c3c,e19f209b,dea1542e) +,S(8f3ae8b6,45507a2e,3ea5d82f,47020739,d8f35f0c,8fc11e7c,6e802d5b,87b2a19,61bb8e35,3028ed54,1b83420e,fb9b1473,60425927,d3f9b6a5,d1d2b80,ee5b4cfe) +,S(3a84ba4b,1e151920,a0e4fb4f,30953e6c,a7ba1e12,62ae44c0,d91b437,b05df32f,b20f6579,43525f14,7b23abe9,c90e1d0f,32c44eeb,cddc6ce7,d3cbad9e,7d3e20c0) +,S(6481fe6c,b04a503,3ecc102b,de462e7d,7b87d181,2bc145b6,2d25fd88,e7316210,bcc1b4ab,f5f32ad0,9176538b,808c9187,d4e88b0e,aef31075,b26e5c27,8f64560d) +,S(5340174,722c583f,af9cd365,1f73b33f,8e4bd1ca,cac0af4d,1ff13064,d551a094,e4902135,448a616d,e435180,f85d0a95,d9e4655b,aebf8a41,a3bbe221,1a66a8e) +,S(c0693eae,a5825c4d,6c24e08b,d57bc32d,6c9ee2a7,90dcb49b,b350f852,4e2867cc,da20fb4b,7627411e,5c6c601,bcb8fb55,f4f6178a,efe0ca04,62c85d86,33b9a05e) +,S(c51d0f73,72fd0502,d17f9200,ca189821,e63e581a,8356735c,a91b6e93,3cfa0d9d,8d10e6b2,7ed7edd,2cfff134,54eb979b,a2797a7d,3c6fb413,b3bad4c2,2e352655) +,S(16811856,4d2d99ae,2daf79f8,58b52ad3,3666008e,d9d2c59d,be3160df,bec3290c,2bebf1a1,45617848,e81dbac3,4522cd0b,3e9cc84a,3c08602d,1adf77ba,292e7460) +,S(7ae94933,e1438525,b2ce1622,5654aa6f,b15999a,57835a09,20a49748,7c0afeb5,91912e37,830a645a,138282a5,1e3331bd,a13b87b6,f443f901,95a2f4f5,bd9b95f5) +,S(e7792d97,d02b76ab,2414c5f6,c2d1bf0a,c27709b0,55b2c36b,179599a1,3019d4ac,9f4d9689,5fceb179,b98c75a0,d5d56cc1,dd274614,a2816e8d,16fb98e0,ed3f2b52) +,S(2ffb9d4,946fd63f,24cff64f,4ac79450,3d97d706,eea6c4f7,69d9e34d,3247bde1,66b1c74,34881531,2bd6907a,6e3608ea,cff18832,5576fa9f,f32257b7,eb81014f) +,S(4544ba32,f90ceeb1,1412aafa,b4ae7351,aeb6f4ba,12e00ea3,c165c8b1,ecbb2fbe,62fbd7b4,c2a5cee8,bfb9ede9,b02dbbfc,2bba538b,834797b3,948887cb,9f8f6736) +,S(250b01b9,25d9ffa2,75eb156d,d8c67b5e,5d981ce7,8824d37a,1b09e3e6,7918980f,ba1d924a,32f0da86,e532bcbe,6766259f,eb185161,4042c0ff,261eb81d,3e09c481) +,S(9cf30e54,1f2a5fdc,73046807,32e962ee,62e0b813,901e30f5,ecbe1fee,abeb4d2,7cb246cd,1281b77b,19601d14,baa8ff62,848259eb,6567c741,c6bd54a3,b5510723) +,S(edc9e8b1,3c61a1e0,8f93be12,495084ed,b5a90eca,4f11dc03,cd217b1a,56285a2c,66c2fd21,7e8fac7,4fd43b1b,58c80661,b0e8df85,a2fddfda,5e9f99fe,621e1f3d) +,S(dd94295f,8388a498,2aaa4164,927b81ba,cae9d002,b3ddb6b6,97082c70,f1e2c66e,838c060c,d409c1ea,9bcd9e8c,b1fac83f,3b08c2b2,482d8f4b,fd3ebc18,8d6706b) +#endif +#if WINDOW_G > 12 +,S(7e068e04,dfc0be48,e5c0d3b3,5bfc734e,96e96ddd,d0ac4876,92f74535,685ab7e,df2cd146,90d225c8,d04052e6,93f14bf,69351e08,79883646,2c88401e,4ec70d0a) +,S(73a9bfcf,d10aac9b,46e659f,76c439a0,b7c2a073,7dec217a,21f43f39,949a5052,73b91529,3ea7b052,682062c,8f86cbf,bf379df6,91a9cec2,4a1424a9,b3be10dd) +,S(efddff84,c8cc754,e6e34678,d85809bc,55cc224b,f69be05a,daa847ec,d408c55b,65dd8f41,8264aab2,efe6ed7e,c45b4ac,8aac218a,3b6713fc,1736dd6d,c2f188d5) +,S(46a94585,7118384d,8d23d6df,a4386dd9,dc264f5b,171a7585,7565688e,bfd73f4b,3de5af7e,a298c18f,4dbf16cb,38e7f617,1e684ee8,e8df2a6d,256c011a,65aaf35c) +,S(6890edb2,7ce3c265,d4afa17b,be160a94,45dd0c8c,9ad6d93b,910ea47f,3821cd3f,60f47c5b,10ef5494,cd8810a7,ca8802ab,7c24beea,eb67b852,dd22040f,77cbd1ab) +,S(8cc9eb6,340b886a,81ec4b32,87a251c1,e33e68c2,1f55688d,952b44b4,2a05f5ae,9b176b0d,90e38290,8911981a,3bc475b9,f0323870,150c9c95,5078bf02,307fb6eb) +,S(2b062f5a,da48de0b,58001cca,e96cde15,227875e0,26c94e0b,fd1fe2a,495b0475,537f1c68,3d5170c5,8097bad,4bf17276,da9de994,8eff6805,48b35390,2f1eab0d) +,S(dd55b91a,84b3d53f,4332ff7f,224e9231,cd358bdf,27f30082,52d7a8be,bb7240f9,e6f1a08,a40b6530,ed737609,4deef969,774d2173,a3ac158b,ff681908,192a5c94) +,S(ac5127e0,40b1a979,46c0cdb1,c782ee2c,8986fd80,d7151e75,16fc964a,f2c59c70,849e2249,323d0539,dda0a82e,1764593f,8afbb097,880af8e2,4765ea01,b7ae5db9) +,S(df2f2eda,f0b6ce9a,3784e9ce,1e1ddae7,9d136423,153174bf,f72212c1,b5311123,b9d98f8e,bd78bc20,316da64f,46644026,fde6ab44,162027be,dbac75f6,e86d46a5) +,S(fd83b387,d630c176,23b85e21,62113610,97bdc5f4,3fb08027,73ff93d7,a373e5f9,9a962a7d,375f35a5,9d7503d4,c0fddc9,115805bc,38438837,d3c670b6,ab6cd2ee) +,S(d8fbdfc1,155ec8ac,8bead443,ba3feaa8,d565ca1e,4206cc95,5feb8e1,32cac4df,f9453c0f,ccb99cb4,739258ed,febf7642,7fb1fcd6,1f963abc,9cb9a5ea,751f73ac) +,S(9fc9749a,20a3e8c0,1b309389,16aaf3d6,85f00872,b82350dd,c89110c0,dfbf86d6,a2f679a7,6c92ac59,5773bca7,8f0f18,75c85cba,e75a6379,1094a799,863e19df) +,S(29e0e346,71a91ce9,bdabcf25,2e2196bb,65b81092,d3728f62,b58c815f,2f476a3f,2f440c61,b82e0ae4,798a35fb,9c66b261,1ce5ad0a,ab42f9d4,174bd698,d4d0c0e6) +,S(e4068a15,398955a0,f27e6f92,9cc3dfb8,7fbee70b,a86ee78f,8736b519,ae102d7,a3f2f2ad,550f9cb6,aed99943,84a9a350,16b91143,747d4e7,7d69e698,8f165086) +,S(51b45e10,bb1bd989,8bb156c8,a4c81978,10f16364,d3d55092,48a42028,726c9f2c,e30719d0,4225de63,281ac479,70010cc0,8a1f1d51,48c57f6b,b478c95b,e3e141a2) +,S(14cd5d29,7b8ab6b5,e92ec2e6,6c63b3d,64dc492f,d5a0c5ac,f6fcbfa5,aaa0b83e,5bf307d7,7cdcc866,349ad1fa,fb1c7d8d,5be19270,2a46b327,9b72bd77,e3666805) +,S(a5a8a711,49d6d146,c32254ca,e9c18288,45e9f2df,419ed68f,8c3cddb5,d22c4da6,9f47d887,7bc3d345,af4ae693,35639bf0,b003f481,7833d2d5,49c0bbad,3cbf6c2e) +,S(359328d2,4baa4232,d75b13dd,d146624d,bda494e5,2cc778f9,99a4c0c4,1f9372cb,d31556b5,71df399e,99084afe,c8f680b,b6695d7d,648f7050,a7881acf,241af6d8) +,S(c9eb81ca,4f2a5a2c,17268a12,d901edb0,c8fdacc1,d26c5e8,91af95bd,e673e7fd,6d4a512f,c974fe9a,711ae19c,d9bfbd6b,5acb73e5,355608df,76ed2942,488adb66) +,S(e26631f8,16f3b308,ac4c9f90,eb6102e2,48e55730,24f41f38,6ccde5e6,c2ca8e2c,16e0b2a8,823aecd0,165e2f10,20518253,96cfb814,bd5a248,58a4615f,eb9306bd) +,S(f76e9af3,65c0e7e5,7807b24,269c4732,677e5af9,a3b0a965,8db8355f,f99110ba,80cbf439,d26f164e,bdaf2542,385f9d65,9d174c62,96ada102,8a0cb013,bd2a9407) +,S(dcc8145b,af891483,295d6ab6,9a88fce0,bc333d54,841e7421,e65f6270,852c5dd9,cedb3770,a620e7a9,b40d6cd1,60363bb0,296155cd,80d89480,ccac619a,f31e2a19) +,S(7645e13a,6a1c4d0f,a56a199e,cae93018,7660bc40,41edb847,ed33fad3,c603e4fd,7c8ea51b,7990e5d5,125eccbb,5da890d2,bcfc5353,b22c42ee,1864c22c,be91e713) +,S(ba26886e,d74cbcef,afe7210d,51c1b6bd,4658225d,45e20fb4,4222b318,9e2f3f25,fd885db2,23ddadee,9e65fa64,abba326d,e0b89627,7359e893,bdf50db8,a2b3409d) +,S(68b500e1,31005b1d,901bda65,4a525e80,fc6578d,5e792c92,299d21a5,19050fe1,71ef7d7a,b3544a94,f3dac8e8,77da5468,8df9b127,83e02022,7e05d5f,6b12f96b) +,S(2ccca7e2,613fa83c,27ff851f,12c6fa07,5b19f7c9,940a5064,b84ea75a,da7996ff,5ab70a22,22dd1ad0,d0db2d2f,c59390b,cf37af8f,bed4570,3c6ae0f3,27d7707f) +,S(6d797d2d,6a56a45a,1b5af718,3cb6dca4,383ad9c0,4d5cf3c1,827f4da6,f7179f14,aae34e5,d203d18d,99e84bee,7d6f5a8b,b80e541e,15a3aea6,7b162551,e80edf3f) +,S(aa6997c4,37be76b1,9553751a,d96a53e4,9a565a58,55f67b5,11605996,e98ee327,6034a421,9cdb40e0,9698a15b,2e2f5f1b,6532e277,a1f4f4cb,3cc0c33c,c684835) +,S(56c40fbf,fb8e1d70,a345d53a,7b0f897e,1e62484,dc01adea,d010c5be,ba2a0f48,e9d06789,78b9290,27ba0e09,173d8ca9,676a4a78,7e299f4c,458cb6aa,46f0bd01) +,S(db6ff6a8,3963ed7b,dc262be0,8b52c3dd,b6e1e237,2a535073,1d2903d5,17918d89,a40112fa,f30fd44,b42f6b18,c144ca0f,e248d65,d757bdc,162b7118,7d951769) +,S(8df55701,a46f63e2,338e730d,4a543013,dcdd1173,754e5de4,151ca180,63402c6d,64cf9c9a,64b63ff0,1396ddaf,b48bbf62,b3e69665,bc89ea93,b9dd12dd,57a1c3df) +,S(9d10bc2c,51018f57,407ae460,e5dd5e45,66485cce,de258af3,7bef48a0,1b0588a1,38ea3c08,b2a4e171,7edebe44,e03dfeb9,726b302e,aea0eac2,fcbc9389,84922c04) +,S(13bbc875,cc07a787,2ca7a706,8201606e,560257b,fce7e66,2e4b9807,37640367,b4cd971a,47c82a66,d8ca19ac,baaf1b1e,d2ea3daf,d6f54769,7fe474b1,c0c2c708) +,S(8f26dc37,f617b174,dc947630,d0da6dc9,1857d9a3,13c92b1e,24ec9cc9,5ea9c3e1,3848a303,1d96bf27,4e423877,6591ac44,f887f2fc,1553375b,d5cf76e0,e73f15ef) +,S(2e1e543d,f290916f,5e55236f,660dbe13,a23e0d9b,11065041,ad3a579a,4c7b5f21,885a4527,626e05da,c10cd9f3,218434b7,947bc083,28fe2d28,ff10ad2f,b5473846) +,S(c83c2ca3,e0509ea8,bb876936,e3eb69b5,8bed8f50,e8c7b85a,1238082c,ee3f3109,2b9602a9,bc808de2,b0b0da10,d09da554,74b75e75,5301cc0e,3b07c331,329cd5ed) +,S(8c7903b4,e2c114e5,3264111a,ee385311,afee8b1c,90606700,578d1fab,d3d29607,dd02dad1,964df94d,1eebea9,a2a343e8,b488c401,88299b25,28d47376,f1025731) +,S(48263c54,dd7575cc,b30adfc6,c1c1eb85,b5185786,654c89bd,a38a681d,a6569cc0,e6f107bd,dacdb528,ed98e49,a25936ea,e223ac5f,55cb7955,ddadfb88,1213167f) +,S(6a7c050a,ea7d1f58,7918644c,63cd5d98,accb7127,c54ee274,95fb2546,16f0d2d3,fad19261,27a2646e,34bf733d,c089b0ca,f80f7383,b4bb1546,28d7256e,d821e232) +,S(e1f0a53f,62fbc202,df9147dc,c31cb09f,ece879a,ccc5a3b,f105a198,7f5c3ea8,3930a10f,b0eea30,c314848,94037780,3968f692,fe2e5d8d,cfe920f1,e5706277) +,S(bc0fb113,cb0fca5b,fd66efca,e8a4c866,da9b6a0a,6d4e613b,48526675,d3182b7b,e11e725e,6993eebb,d2715f69,13ecb148,37892c56,745c601,31ca1c6c,bf090f31) +,S(1fe5a0f4,9c438f48,64bf9ebf,89eae7b7,ee7e6a1,74a134fe,266b0329,cb42f908,db8095ce,f912641c,92b3878b,cfa7b596,694514a,ce9b779b,35ad6109,c675f66c) +,S(5de3fdb4,90167002,fa6e61aa,eabfa53c,ade6ea83,3f3c8f6d,e434320a,aa524cd4,b5cbde88,862ad6ce,b344a1dd,88d1ac29,6d7e9ca3,d5e98535,dc158579,147e08f0) +,S(93b06993,a913dfcf,5eeb0be6,294a645a,b2964f2d,e2196073,8adbfcbc,23da54f,7836782f,856cb744,4187330e,fca3c7e2,9c151ad8,1e8b507c,4d14a14d,492ae0b8) +,S(705740d,27d90741,e685a044,f6b055e0,9c33369b,e3815851,886b7860,8e762f0c,c4a58fbb,738d46c6,9e93193b,529f12ac,b2142b32,1fbb3c55,d3f5dc99,173d956e) +,S(7619a000,fc485526,734a20e1,99530f0a,e5b78767,61040864,34a1a1e1,1d93e296,7f300de1,182f479c,f6fa0afe,a2ceb59,ab26f675,77203201,4f8be86d,46ebed6) +,S(fe20f5a8,ddbb5201,6cd346fc,d281413d,cc0d54b6,384e460d,bec5428a,599ff2fe,5b488ae6,e2604871,afebe551,f9957b0d,338cf47a,b4ecae0b,ae7a92b9,242d879c) +,S(995b9727,ba7e52cf,2dd29e07,73c751f9,70768121,8ab88b84,422e1e3f,42ad11e2,c3c9ddc9,7ee41468,c4ec5e5f,529bd8b8,49c8d585,f905b91f,42af5c6d,2f7fd26e) +,S(cb4f2e4d,2ca94d7c,79e91344,55161921,636d26a0,d84c2a16,e267c242,702b3136,215eb6ee,394940e6,cf00df48,f7e2b8b,1b9b2f71,7a68ee49,bbb879de,803ddb9b) +,S(ca0a2a56,34b49144,bacb1070,7668eb67,4572b69d,5e1a4e6f,c722c256,b9fce397,92079cc9,74ab2fbb,a5098c85,56ada7a7,6e2562a7,bdb5ebf,e958eb82,d3f4841b) +,S(fb82332d,c6c0c0af,d72f27a0,24ef163a,bfadde89,67b4c246,acd6b922,e3af7c7b,1a697119,f21cb690,338beaa5,2e2c4b1b,2b90d399,19ccf0c6,60dc540c,a934c7ee) +,S(d056ee05,d9258def,20e184a4,e2018bd6,d07550a0,63db4673,6afec42a,5c513dd2,af2c1d0,d222e356,67e7cfb6,201ad727,89ab0fc4,d68dc31c,276d998c,bc15bffb) +,S(3fadb222,c6584262,c4046c59,4b778635,c6325712,cd828726,7aea1253,42526f12,da5c8c07,fa6811d3,84ca7e8b,fa1d74b7,d181e0e1,eab86717,58666b7e,c199ae96) +,S(d27ac969,e222e50e,5dd915dd,39d3e453,214b818e,fb67e924,8ab4263b,1d9c4b61,c4857694,baead305,6e6709a3,28403236,9a7c55a,d81e7f6f,9b494a76,cb3a1c7f) +,S(412379b4,8b981ae6,a5fa4324,bffd69ef,99cd3a01,91a1acbc,d9340f01,72c565d4,f24036c9,c7dbe4f0,2ca523e7,ebe6ab57,c755053b,245523ab,ac9d3e87,fcfa280e) +,S(d8234eaa,99374c13,b9a8cc3b,663d00a5,bef7909f,b21243ea,ce9dfaa3,f79336f1,b8cbe8e,c4b465f6,6a3c1593,292babc,1845d8f9,1dc80e5c,b1ff904b,6e755c27) +,S(426f8b35,68c5ff9c,bac0ea34,9d8d3c00,427d323a,3d877bbe,47fbaf2a,5d189009,4e02293d,ce023c7b,9c7a1ba7,27cb82b9,9931f57f,78853bfd,7dc4399c,bd00586d) +,S(f1c706f9,2ee5f2c,2412a7fd,c9ca5c79,8717576e,c780f6cc,fe72760a,4497dfa5,c5e1a1a1,727f55c3,b3978700,51a09b84,9ef75895,d6b9c4d5,9f85cfac,2bb7e740) +,S(84e2e07e,cc1d5987,968d6682,525356b7,5982001e,67598b67,608f1869,36c2c679,41ab1343,8ab5ecdc,cbe75a8a,b7fceba5,2903f4f6,f5b43bb6,28173866,cc28555a) +,S(7935eec2,fe535823,44abb699,3a18cf6a,3d599b0b,ef0f6068,9c689b40,76ad2b54,ce2fc96a,ab978861,b6ced574,fe4f5c85,b77480ad,e3d75b40,6c4cfbd5,53371910) +,S(d542a4a8,319f6d56,b79abbef,9da3a009,3e8c2689,421e3839,27aa6a30,b0dbd9a0,5104a162,65d285ea,8f99f3e9,c1951a06,6badb70c,985877a4,f1979aec,7b8173e1) +,S(bc692619,42289890,4af0157,a038126c,41011b9,26fb232f,d3c27d9a,44ece2be,8e2f10c1,47e2a630,9372e854,3cb8ef77,11e2022e,db25f4f9,847369c7,fe52f3bc) +,S(ebe1b736,bb178c08,deacdd80,b48ab650,ae079a90,95f43e51,f4521bf5,d18d8d03,ad81c659,b1450de,45f78ef4,b2a8126b,782f2061,fc8eebbb,cd0a2ea,cddb7514) +,S(e626b908,49e1853e,4fdf887a,df8f0562,666d094a,9382be7b,de152dec,b9e2774c,90cf55da,a4192a27,caab406,2cfb8758,2dca7342,c59627c3,f513ff9,f4834ea) +,S(fba7a057,ba048792,2313b8b5,ba4514f0,d8f571c,bc7ac0b6,1a987a9c,e4381e67,7d2af7fc,142653ba,bf05133f,958a57eb,7cea5b90,ee5300f7,18cee7ae,d69ec44a) +,S(144cdb95,5b5d5181,5a2e5bdb,57033e67,239735a,456579ea,1e3be689,94c35a54,e6016f89,e896fc59,80150d2b,8135b4b,ed0a108f,8a2eaa83,91987a77,6253f1e6) +,S(538de6e,e7ab1b5e,cd74a2d1,a9599d9f,ad28cd8f,2679eb6,81c25e1f,183c0a24,36c0a747,79611193,5bdbac87,d5b38a05,2482b973,213d0960,1de8404b,14121004) +,S(76914f0f,d28f73ee,20ca3806,263b757c,7876eba7,54bef2e,9d10615a,ebc03794,6de24dca,e16855bf,22355786,1626c62c,59330752,f9f8808e,c3930680,33a12642) +,S(69915e6c,f675f7da,f595f7f9,6c912f29,86bee7bb,aa5800af,27e32baa,9e34e4a7,6094fbc0,2f109855,77b53c91,8dd2da3b,139bc31b,77674d56,df72cf22,2b9513c9) +,S(4ee6c20c,900bd4fd,be942dcf,db91182e,2c37eb35,e4287e5d,859ba847,18ce3015,84ac9769,863d618c,4b738e66,8c293d3d,42e2a9c6,4c47cf75,90ed50f3,2062cd64) +,S(a6813c1a,f57bf8a3,8ece11dc,a4c8c581,aa598211,af9ec6a,d2271796,88a0fa61,6420274d,f4e29631,5b7e2335,e98fb2f1,d415c99b,dc5a00e1,d182e809,5b8edca4) +,S(421003b7,107b2897,24dfc743,275db49e,69d91077,6ee53d6c,fdfe6ab,710fce84,cb955569,7b924395,c31cb149,88bcfea6,a932087,3aa8002a,c218f33c,76f9427f) +,S(9cb19e1,cb8c4fc,4009d362,eacf5f25,5e125298,5b546df8,fc60bdc6,48c8c522,227015d3,2c6ee68b,63e20e70,ed7cff86,8fd286e0,905bf623,1b7e894e,c7d70d12) +,S(c7413596,8193588f,38f412d6,4e2ce0cb,c4a7ac4b,75e33704,36236362,8bb953c2,7bee7fa0,1b7cc4d6,d22dd4c9,ec16b39,5e1d70f2,52778801,9ae75ef4,a908aa6b) +,S(2a8e8a05,321f4926,e8fac1ea,8a97cc64,c2f8e398,e86ecec,9dc2e676,61df22cc,63b86507,4e4fdcaa,acb60c21,c0d3f813,64f0c007,faff7780,9c81fbdb,981fae42) +,S(f3ef2e60,7d403594,48aab014,ea8e2dca,5af1d8c7,c6f66127,3552293e,d497a14d,dfcd5334,214b9f44,bc5d1d96,49d78c15,9e9ce44b,f43dbca9,c637c31d,622cccc9) +,S(6d5c41c8,169c33a5,d1111b36,1b1d6713,a9396424,bbfeb65a,80e40280,4857ead9,4c1f74c4,9f01bc2a,27a91d37,f59bde,3d674220,a521aa4a,6a0c548a,a45e84c8) +,S(5d812a61,c6a986b0,2c5982ce,34fd478d,60822322,47e07c73,488c71f4,4afff85c,37083f7b,16018fc4,25749e16,4c923484,680b1517,8bed41fd,cc8da253,ffa960b8) +,S(e01596ec,b82ff347,c3ba9710,82911855,720177a6,9efa7d5,dc6aa847,7f73093e,a674c832,849884b9,d38da5d0,6a58e4a7,a17acac1,8776577e,5547eb3b,b45b3bdd) +,S(67a5a900,313ff2e,7b32fcae,adcff7f0,ad52b960,ef6b0d0b,8344402c,9980f55,e77efddb,5e8e8865,eb807575,37c41e0c,9fdf928a,eb8b6a03,f41703c9,3c0a4a02) +,S(2b96879c,2e2d0ad8,281c1647,7de62583,53d77db3,57281c21,7df0d7c3,6466b277,dd5d3473,43bac32b,cc72408f,64a9fe7e,7e0dae06,786a7074,3cbbc846,80b62b25) +,S(ab94378d,f08748d7,2df137ae,a3e3e123,639b054b,fb726bad,825e2d9c,310367e9,5785ce24,40037d11,a8331865,c78ddaf5,7f9d769f,f2df11c9,9e3dd018,43a10f03) +,S(70782556,fd6fde3,8c93def6,ca3b6c8d,2f3fd4db,87be4985,fa3aabb0,43e7439f,7913bf65,ecf15020,cc5274b4,8eaf5351,51894bd8,fa236af,8f9b3fb8,178ebec7) +,S(3025d070,138bd507,b338c72c,1024a3f7,6b4d5e80,efcedeb3,e71a018b,77ca3942,3a8a6a0e,175eff95,a94172b5,f2a4ee53,8d503295,63a5b096,f83dd669,eb470ae) +,S(3fe372d0,65e97abb,94069e7b,2a8d01e6,576081a1,93897ac9,901a3d18,b9ab0b6,2efcee92,3154dcc0,377315e4,1d67b5a4,82403552,ce260c2d,4c1020a2,54842e5a) +,S(368c7011,3a9133ee,97ebe8f9,cc06bd7f,c3c373e0,da810164,bce5a30,2af55636,21bd40fa,4870a8e1,6f28b942,bc169712,eb7d70e5,a6faa4a1,35bf86b4,d06162a8) +,S(7df8ffd8,beb45e4e,1e440f23,ad6d713,57682f68,e54fd003,87eeac94,ecd96810,3d9e4cf9,908e5a99,44857d78,94c7ffe7,dc55550d,a07d3c9,ec07667d,982ed0df) +,S(cb6ad939,eb49c7ee,7c216262,49b11276,88269172,504fb8bb,dd2dbf7d,b6f23d4,ec8604db,18f27367,de1319c4,59f8e668,5480ca65,e1789cb3,45e0018e,ea98346d) +,S(5ae526c8,fc319e6,e054e6a7,59d9b205,d8a1e042,e684c53d,39098f28,70f4265a,da1e1281,14c25a90,cff3ef80,d5577c08,a03f4bab,d9e33850,f2488617,d50a9a63) +,S(868d7889,6ddbacc,1bbf2b10,e00456d6,17477767,5b8d3323,a8786ae7,25ff7661,d92d681d,189b0df8,e2be57ba,a9c146f6,46e6ce48,342a0ef2,96fc3093,af22ca1d) +,S(9f2f0b4d,e7b881b6,c4dd1f8a,74106a32,23bd3298,47c325a4,8341d899,d7686b74,6fbbd511,c2974af8,b5729ca6,658562f2,deca285c,b47f16e3,c444fc14,8e440088) +,S(faaf222b,813b0df1,5bf2da98,3ee2eaf6,c522f5eb,e8c08b4f,e6950376,d3fca8a3,bec53e69,2e98dac6,8fb2ae87,44f12abd,47f00e6c,5d6d1469,b2cdb41d,440b472e) +,S(7f5209b9,db4ab9fa,2c2a7ab7,6c5c62f,13c81c80,a4ec4008,fd67d229,a7161475,a13d6cda,f9e8699f,f397d1c7,6f191cd8,a58be40b,9acc4ce4,e69cea0b,4a48d193) +,S(f436156e,80b136f0,8065f395,e2700a14,50c7b492,405a0c04,6834bf4f,12c84c2a,cdd957b0,5684e01b,a760807d,39b007e8,e7aa890b,8882a0e5,9118951b,bd7e60c4) +,S(ef9aa749,5c5b37d8,2060c2bb,3454fa6,88216754,2b24d69f,201f1c31,3cf1d06e,f840da4d,f1d84a8f,ac125750,e4e6cd7c,50003aef,d1f77666,54ccf4ca,f27a4aa9) +,S(7deedc43,e96eb93a,c290809c,25e7936d,6d9e1cc8,a5971d40,b122896f,fb5de05a,e65c0e66,27b9d0e4,e7b349,ccf12fcd,de6683fb,6bc93381,22026b65,26a8e0ce) +,S(5a1bef15,6669795c,47be7495,582f361d,878384f4,f283e15c,e74b3ce,986d6459,ce985a81,1fdb02b2,9e35b97e,1833e380,69b28b81,ddf8cd61,b1179c47,2ccf39ff) +,S(d8123d39,233413c2,b14eeb78,983c6fad,73b8fdcf,84b2383b,fa453558,e525fa8e,ea9d399d,905b7200,46ff78a5,abb3cb56,835e35a3,c958095,ea226947,a633ef73) +,S(62f43dd4,f1f4c310,266a36c3,909afb5f,10d3dfd1,a7a6b5d8,93931334,e4d4bc8,bb7589f1,f83bd647,2e34fe22,53a101f2,75525829,daa2e8ef,89fa1dcb,b590f3ed) +,S(6cf371,d549c045,1415aa75,cf594d4,865f6e44,6f62df4f,cc1cf312,f79d72f7,f8ceb62b,5c979bd2,82a4ce20,682b45a0,2b3dee9d,68ce16a,7581adc5,c9e93af4) +,S(5bd7b780,770be9c3,7c1638dd,8f954086,49aeb371,516bdf3c,509efc5b,47cdd7e7,d46c7848,8a87aaf4,f606b91c,5add0c25,efc12c03,2a28b1e3,2190999,286ba9ff) +,S(c7704954,a319bd4a,e5a08665,3b959ba0,81eecd7f,f15681af,e6bf3db,c36b6a62,373543e8,24784ba8,3f53b9c6,189ccc4b,e508f600,b15c7378,36e3b3ca,516d0fe7) +,S(2b4f27fe,41533a9d,d807da70,7102c1ee,d6e92c8d,9e43958,8fedc6d0,39b19cda,98ba8310,ecd7cb1,c11fadd4,a92f4c30,49ba2180,24015d6b,89e2ad9,f81fb424) +,S(e7d4171,b3dc34d,2600c581,d6931f97,2c920c81,3d7c3db5,4d306c8a,5d4c0e5a,b29581ba,9a825387,99fa97ef,b5a6c4a3,3e75b71,d1cd51f7,5b6144f2,4a9a409a) +,S(6203022c,18f43577,5270043,56a2717f,2face761,e806e84b,2b5660d5,f1c5d52e,18a52f25,5d0a4d75,275fe97,3542b97e,212efd6,aa8864eb,6c80865,136a720d) +,S(bd81c7a2,8c1c80db,a0e327fe,3b0fccca,48987679,791e6630,e81c004,92e43b2b,ca50a84e,a14bbc64,9e0831f0,7f185536,416064ac,e93a8678,db1e2347,803871c0) +,S(9bc43e1a,d3c1390f,cd1385cd,603a6e0d,b875eb4e,6f3a554a,626a9b4,fc4bc29a,857a58bf,9aa54bb5,7acd8b34,b79717b2,64ea39bd,d8f4a22e,6b12e6a6,e0cb2cd4) +,S(3055a68d,194de3c7,9ef0117c,b98bfaa1,5e5bfb71,c656f908,2c8769cc,a7e40f33,183f9ea,dfebe1c4,bf0218cf,b6aba6bc,acbd8c72,a7fe086c,1c9233e4,340d1d10) +,S(4adbf984,ad1fd188,c9271072,43583b80,2cec1231,7d8bbe1b,71079fbb,734b08ac,14527188,9560ceff,3d950766,8e3f2d0b,2192ceb6,f79f5954,7094d5e3,d7ec04e6) +,S(38f72dcc,27e041d9,c7bae397,9cf16d22,83fc6a36,aa074b0c,d00651d1,a56487cc,5238c97c,33a106e4,1370d6f2,c0b6ffc6,49610444,2e51988d,f7160c3a,933dc0bf) +,S(de55bd8a,7bdffde0,a1413828,ac59ff2a,4560647,47c27813,322188c6,655be2d3,477861b0,df5b25f3,75f9d097,97b0afb7,67bf9d51,b996d51c,e65d3bb5,42d9da) +,S(c617bcfd,c47e02b8,918edf98,666fe912,e19340ea,6c567893,8739b89e,5e3bcc66,b90ba117,357e7683,2ae0f4e8,644cfc49,a6e04672,b5b08d47,3b826349,65117072) +,S(4655c196,1b5188c9,4b6402f1,e92b3033,c455f4db,ecadb672,4adab3bb,f1c84758,3ceecc93,a2575f4d,fb202df4,f4bc05ea,714600c0,28389b5c,f2c1c6dd,e6fbc4a0) +,S(fca90f40,dc05e5ad,3693c503,fab43da0,110df431,9c1dc4c9,e5f86e8d,d7726a45,f5822f9b,be3e6604,1af37aeb,19a70a6e,7478edec,68c8e1c3,e6cc86fc,5f5771ca) +,S(3176cc4a,dcb28258,779e88d7,f90d3b3e,a31cbe05,78c7cafb,93ff151b,d27f61e9,3863f2cc,148a0a43,c94fe7bb,afb5ab5b,6a18ce44,56cd06aa,c340c231,42cc0135) +,S(63269f73,d124210a,d070db15,14f82cc5,51d9c19c,d31a54e0,b811e650,ebb2ddc4,bf8ec7dd,8a787a42,4a74114e,5088c387,38246bc,3f6aa188,e300f0db,d85cd0ac) +,S(679a1d32,8d0f53b6,1ae7f544,541326a8,f07e749,34dd2708,dee3ce54,632003d0,83ca1348,8f21eca3,11be341d,5f6ee9a6,c9b3eb55,c9a3485c,349018a,725c350f) +,S(69a27d79,29982c84,d3948568,a54d8933,f7172f9d,e80276fb,846cf399,e0b38b28,f411d207,cb0f0bb8,574b16a1,22f39bd7,69c8b7f5,ac2db4f3,a02163e4,3bb26168) +,S(298d5057,1af5042,cbff2171,6029cef2,abfdabb9,cafebc7f,9dd56c8f,6773ee4d,f4343e71,d271844e,412e62c4,bf6dc36f,4271bda7,9ccfa220,75e3c055,aa97e9e1) +,S(3f2983da,46d1f101,8f8eb984,5bcf3930,e26f66e4,544f63b1,f8f8b979,200c4653,4973a914,c4ad33b1,36d57e6,b326d380,9b2c38bc,79d81b53,b26c5995,9d71db0) +,S(f836fd3e,30ceb88d,942d64b2,a1d2a6f9,54412ea1,ef6a3b13,59faa8bf,7e3538dd,720a3081,53476b5a,709fd29c,158b7720,c8161ee3,6e6aba3,b28e0282,cf7f9367) +,S(dd72eb9b,911e38a2,63bc8ee4,fe991fe9,295ed522,1eef930,b3ae2df2,ef583a,2a0da5a5,688bf7f9,79285d9b,360b53b2,398e86b1,43f10b86,83cb40c9,40c1b2ef) +,S(551e2650,46ab255c,c427bd81,8258b7f3,7cef92a4,496119be,283f033,4968a619,317c33d2,4cd8f35b,9b86a5ec,d1582a6e,e5ca16aa,3c6ea23b,2007a370,e7bc4f30) +,S(6683de92,131de3d0,ecb19a30,47825591,ab28cb61,5c852a90,fbd3ad78,5336c650,49eea58e,7fd95523,f8a9556e,c46fa0e4,b3c3b2c2,8e5d9e4,d636d089,282225f8) +,S(b5b3b1e2,84a6ea65,e0a9b146,e8f895e9,ca99ef3d,31a4bac7,bea49c89,3cf97805,a1720a94,f333e296,f2b91437,e19500be,3cf16cc3,547e9667,ffa4ee88,e5b6fe0d) +,S(a5019773,7c337684,9709a232,9718d463,ccdde43a,55350d10,11a2401f,9bcbf466,9cc069e,ffefc5dd,e8fa5e09,b6b751eb,c51fff8c,fbf3c27e,12efad87,a9d429e2) +,S(9ec3498f,eb2bd861,42841b66,3b1c58b2,e5cb7224,88e2f849,e1236b63,ec1588fb,e00c91a5,e14b97f0,362719bf,2150dfed,e517e585,a807333b,a000652f,c1f5f12) +,S(e10b6cb4,adc13185,750b446b,ab926667,581f97bc,5aaf04b1,f4731abe,f3c5b6b2,53a51213,7db20477,f3a87bba,5b65c01d,d5520b42,f2660ed3,c1f5fdc8,35e2b9c3) +,S(b754a967,e36ea7c7,98c93691,e02b6043,60ace927,13b18d0d,3ff61ce1,dd3ae314,8a9a3963,9aa7ee59,a42f8d5f,bab01e50,d83ee029,933cf59b,e12b82a1,5473d849) +,S(5fefcb61,c10cbf3e,6f8a51e,6bea569d,7999a275,6340ac8d,489183ff,32efa869,d81b3093,cbc4835c,1d88c093,28c20541,dfe49950,9b349207,15bbe1bf,4e881e83) +,S(fe51a3bb,4ac97e1,96009400,b27c8995,f0ed6f0a,b29b9184,70aa442f,27d2d848,8568fce0,a4c39e44,f2b8aaf,59f0b183,d306254f,83cbd6,ec5fd568,c9116a58) +,S(6a3e4629,9fccfedb,c58d5d38,aeb2a420,391df798,e447558d,7b591466,fab7dee3,1bed8fba,7bb15d9d,d42e7b5a,3ab1d9e6,89873eb9,e3161a91,aec3ee9b,22a5e548) +,S(adfdbcb8,3c40d4de,f7d62d97,e16bd32,33db304d,392492ee,7457ffc8,97450c37,7b082bdc,163549ec,2a8b588c,4156ac23,8fde7819,2e1cc195,6be85b87,f4138e0e) +,S(96850fcc,9c202c54,83654c27,2d17011,509ed7dc,6ecc6cb9,f06c3dd5,113bf61,10404432,7f966c49,af0c05da,c7ec18b5,b9fcc455,a01c3b6c,88b8b0,d281aaf7) +,S(2ae21197,8f78ca14,d88151ca,804379a7,1703f514,166f3ac4,f09409b5,5c458bbe,4de74cd9,576035fd,451c7dde,387961ce,2328e327,fa0312c8,6cbc9dc4,19ecf7b1) +,S(edc18742,e1b5c996,2661a332,cd62c426,7e5816e3,c52746cf,b79eac61,1a987e57,80003b3f,c63309bf,3f9d484f,ebabe579,29ba9032,30311bc0,2c021a34,5b4fe5e) +,S(7802aa2a,5fa0f0ae,29a90885,c8b94368,38b35d49,843765aa,1d6a640c,fe43a244,c7f329f,e63239a8,407297e0,416c49bb,7e3dda11,85baa5dd,7f5f7167,9192a803) +,S(fb774579,b124475a,c36ede71,2e3fc5aa,c2173de8,35e72386,bf67bf7f,992335cf,c0e66b51,63c17b7a,e43ebf0e,31a8d641,b6f413a6,b763ac01,cdfcbcc0,47a82c94) +,S(d81a3d8a,43abae9e,32f94881,fe9c1200,695a9c24,a31b6982,51e21b3,fcbc2852,630dd811,e8a8cb6d,7bf51de7,e0a98db5,a693e3a3,c9064dbf,2ccf6bf2,dd12673f) +,S(519fcfd4,97cf068b,804da0c7,e2268cda,7cb2eda0,4be5249f,9bf776b7,c7324cf0,bec6f4cd,198ab3eb,be691646,6e44ab9f,a357c8ec,3bca391d,c20e6ffc,9562fdb9) +,S(cc4ad3e4,8fd66073,5e193853,e0f9b1c2,3e31b284,e2770441,24f9296f,868ef592,88af158d,8583c474,7d5520ac,67b03c75,9b12151e,db25af68,996263ad,d783c27b) +,S(add950ae,6f5186a5,98b40cf9,64ded6ea,c06a57a1,4b85de33,8f709034,78d24117,c59ca4bd,2d69285c,debd6853,a0bec744,111f6dfc,7004d65b,c047bff4,a3affa7d) +,S(dc071b45,43097de7,12bc8173,cb358af,ef0437c6,7c4927dd,d0bc3f6d,bab383e4,793912a9,899b304c,173b2adf,c187dfbf,f28fcaa0,fb11b85f,9e410b40,e95ca8ed) +,S(5dce337e,6db6099d,a9c37da4,a96b7a72,fd97a672,47f6babe,94d79b1a,aec167c7,1b887fba,1f098a43,b6482991,f16ba2a0,eb35bf56,64eb21d5,7549dbd6,4e4377f6) +,S(516eb6ad,8493a662,6d22ead8,e808982,900a83f4,3e6109e5,ba284cf9,e1f5cfcb,ca350ab3,8085b46f,48d8308c,61d3f947,ef6a8511,bb36fe3c,68d30fef,ece05042) +,S(f767c150,3b1f2da1,e5b91211,4e917c87,732b3fb8,8c860a3,35af1c7c,f00e5e75,3ecef8c8,cdbe467b,888f64a2,655ddab5,9ec610e,153cd657,95bb473d,a1aaab54) +,S(f9bbebcf,f792c8c,a7bbc5d8,f177de7a,4185582c,2cc65e75,31f3ac26,73c977f0,290ab4fe,fecb3a26,256f767b,8a19e55f,ac751eaa,acecaf52,b8c99657,49614a85) +,S(c6bfe1fe,be5c8db1,f55bff42,c123df61,6ec3adbc,c9b08e8e,af477fcf,4d47c45f,c595f882,d6d6a2ff,d832eddc,95679890,41c27101,347ea995,c79ad56c,d641792f) +,S(56c2d771,808fb4c8,71dcfe6e,5170bb47,c5559521,8b872425,761829e5,e0d3ce1e,6de72ae6,9e03e626,fdca9188,9e721c61,12ec15af,7163629f,5ee0fc9f,540468ba) +,S(20218b05,ec9f5be5,87a96d8c,3c0cf7d2,da9ecffe,fc604fb5,66a3667,5109d663,2ec1a7c2,c5357e24,1f2ea0aa,7a7321ae,b41bfa3a,88b42e12,e79283bb,ef8f6993) +,S(3a089269,a04ccd9,5bfdb4f3,3494aff3,519035f4,bb3a4f09,e2afcaff,976be4ee,e5680e25,fb0ba1fe,91693757,b3404b32,bbeba22,640da757,ed91ad85,6842d1a2) +,S(8f9f2296,a0cd8b53,db0fd0f2,59860496,dfd3e101,b2975a2e,2856523a,f45b3f07,61c15907,2cacdf31,b229015c,d6290d77,8ab3be0a,57785920,a3fb5722,b5c625b5) +,S(86580be8,695bda97,cd1599b2,6d4b6328,97e2b90,d1ea106c,836f474c,fe88070e,abae68a1,7e19ac58,38a2fe5f,d07dc7ee,2bb220a8,9dba4ac6,166c51ab,b17d7d21) +,S(fb6ac38a,1e69d589,ecc5b4f0,e57aa1e5,eb1f9458,fb187d04,8c72dd29,72b4d762,d601dd16,bec271f3,16f1d3af,2b82b5cb,e5d1806f,b960014,7fb01301,86ac32c1) +,S(7c10606b,c54fea81,bf3aec94,72bb09ce,c5bb7d31,b66e27b4,242b8dbe,7ea5f0b0,12215180,d3d65643,76583987,240b445a,2ea522a,3e0250ab,d14d77db,bdf68f54) +,S(85e6ab94,833593bc,74c7822b,1d9f384a,740a5be6,3b846495,2042b017,2d52a1a6,f5c160d0,68d6f86a,8f651213,8cd28e3e,d6e69fcc,dc75f0f9,81fe5ebe,1fae93a) +,S(7e1e2d3a,99cd1ba0,51b74ea0,e5471f50,5e626aec,b880ca27,f02113ad,ff51cfe5,413ec82e,e9d4fe37,8c232229,136f1ade,c1eb96ce,c0062997,81f4b009,9dad89bc) +,S(589640ad,813735f2,ed7a08dd,6931c61d,6a9490ac,729c2bd2,928ebd01,e87aaacd,89d6b10b,8a89fb4b,3679fc33,96c4cd5,7a1e909b,e343ee15,c1a02719,20485429) +,S(7080cf4f,f3465ce8,fdcdb0ef,3741c19d,91fdd7d4,44118c5d,7b7ad040,5e6e6608,7a3f0da9,5cbc0ba0,b5c6d334,f80db1d8,3033489d,34143d34,7dfad89f,8e2441fe) +,S(bb660b4c,2d400269,2dd96bd4,d7737c31,91deb03,6553e61c,7d59a876,26917c55,b494ad13,a7560497,6068403,15e8b86f,f150af11,18dc02fa,f5ea3f40,c0983c24) +,S(73a241ec,7ebf15b2,4408161c,5d8a5c65,3f4f4fb0,8cddae0c,1e2c506d,9f221b27,80534bb4,33a0a56f,78486504,1d480d8f,64bbe192,a2f6f32b,5e1bc175,d463640a) +,S(fdc1ef51,f08bfdbc,7705741e,6a2b58bf,9e45f202,c3d7ba6f,89a15aaa,78b1fe07,7e9d00dc,dc1e4878,647ac05b,55832540,1684f714,755f4e36,880e5a0e,996c0586) +,S(204842cb,a0ce5cc1,3ab44736,ea0e33df,a15ab13a,912687bc,6d6733d3,a33618af,afc92205,a6e991cb,fad18741,818a94f2,9e1804dc,2145ba35,896f92ac,c96bd521) +,S(a03a9c1e,f82c3151,81009567,50486869,a47c4a99,83bad93e,b2bcb60,157ed768,786f9164,fb9c6980,eef3e5ee,d9a43b8b,2158ba2,dcd8663c,a26cf19f,f6090a65) +,S(5e3b6e5f,6cb41784,6355e3ff,7da813cd,fa18bd42,c54565ba,ee19b15b,dbc00ed2,b9c3a553,42bf2284,fc3b8f9f,88d3e4d9,9d6f358a,c5c8acfd,e340036c,42ee603f) +,S(19b0960e,82d1280,663dfbd6,efb2746c,abf76476,1029a54b,154385c,a05dbc70,f8b28bbc,440112a9,45f35645,135d041d,33df5ded,92116f31,2d2664f4,e5504773) +,S(1061e900,7597bafe,74b9b274,ba1a22cc,6f1c2d1d,b6be8d05,9876638,dff3677e,707ac922,dec592ec,44d7b59e,be2518a5,fe2ffff1,4cf4cfa9,8155c781,21444b21) +,S(c9184c11,60fc7d87,5439b567,69a0e501,cc0e221e,3b155f57,9a71cf1,f3030b85,880b69e3,7c04689f,d6dd30f8,75f23899,8e83e594,9fb1ee30,8c43e982,28327805) +,S(a35fb304,4dec52cd,8fc5af94,e6c26ba5,c8fa2364,2622af12,d37559ff,4374cf04,1544f375,692a3584,ac7adcb9,a3422dcf,8b360471,85326840,42dd755c,112242fd) +,S(ba8c03ad,60ffebe8,118efbe8,eb130f6a,1b2c501a,78000a8c,1b204bd1,b90929ca,e95ef729,a3f341e0,faf73211,2f7800ab,65b88d47,ae137722,f11369c6,e3aaafbe) +,S(d2ba5755,842d8a77,97fba189,f49a010a,fe08495f,5e64bba3,361d1b52,8f30ddb9,da3669b1,cad179f,784bc5f0,c3a55d60,549e72c,390b7d47,7c030bfa,53df7957) +,S(3e04eb58,7ec988b2,77b1d2b2,880ccb24,d3de1579,54ac994a,86db9ae,6c8703f2,fa412113,e6dc85d9,eeb1d650,3df96fbc,ff3c6089,cc5c207b,b98cdb4f,e728dd9c) +,S(efe5bb42,4339a49d,3e19aefa,91f466d6,60c9f120,5df91ca1,7a0da3c2,699fe7f6,98c6212f,fb39640f,cea21db2,97cf9fc5,e3576b0a,7cb4408f,f9e3e9d3,245156e9) +,S(a29442e5,a330336d,eefe6591,5c4e0ea7,bca2dc2d,9816c8a3,2bd66a4,baa0908b,a1bf8829,7320e47c,3b774c13,a6fb9e6,dc5e7789,44666311,2db427a9,dea135e6) +,S(454bccba,6f7225f6,a91f632d,1c9218b1,48e877ff,8018d371,4da8aa88,f08bb792,da0ded31,2d532b01,60a1106b,202ea0dd,8157753d,a07e0e3e,918958b7,45ec713c) +,S(3163940,32c39566,cb0631af,a2505404,56573782,e940dfce,d425834c,dcc2dca9,18c561c4,1b15b0d1,a477464c,6f4d668a,67f0895f,a55544dd,8445a8db,cfcc5fc7) +,S(54b5375f,53f07bf2,f15fced,ffc7132d,5240893a,3bce0a92,bc4fc884,49b07703,31be2b3f,a944251,e52922bd,fa2ea218,f5df11c6,d67226a7,b3f163ee,61abdee7) +,S(283ce31b,745d067,2bfb9b6a,694da3cc,de9033c4,639e8328,d2b7ee6,58b3bd,f6a948a4,d452bb56,e3dc24e7,6e81d2c9,dc1c7aa,67aab38f,f9d20044,d8c0245a) +,S(b5e74f53,117ba754,7b12419c,b0494579,48d5f831,624bb3e3,a60167f2,10e99967,5f635754,d635f9aa,a83c22e8,9f383008,3da8331f,4cfd9b5e,10d48280,718dd3e6) +,S(681e5f32,cfa33183,170dc776,fcd51daf,d587c34b,1cd27134,a856713,cbf83080,c587d8b8,d144e4dd,7b4361d9,b7fcf30a,76f646ef,fbe390e3,8f241a54,7279266a) +,S(1fba5eb7,722f289f,2521ec17,d05df56d,2f28b221,5ff8c621,b925a5fd,29f1d0c,df1140d9,97ecfd4d,fa7f287e,fcacb66a,34283b63,5b2bb7d1,524dcbe9,eb11f5ba) +,S(38bff4b0,df378b3c,ed38fc5a,733f1bce,17855b64,cc254f20,31e1300a,6a0d0a77,6d4f065d,f634296e,64c485ee,32537475,f35a5065,e73bfdc2,520dca1c,6606b1be) +,S(707013c3,59a9264b,be4050d5,27b5798f,779df8a0,77cc95ed,6e08f74e,e57de831,b9f379a0,315386c0,657b8dcc,53cd98ae,582313a7,632e4c3f,da9c9157,14ea422) +,S(ad94ed2f,70282484,e490abbb,320905ab,fc5b8c91,9de6535a,73da3f63,45642ef5,9dbe8813,a554e1f3,e98011fe,c6545216,fdf4973,6d026bd6,cb8702c2,aac88457) +,S(47b56de4,e991876a,499ad155,2443785c,fd174f87,58b881f5,4f545584,ff62612e,a140537,5855beb7,7c56117a,5f753777,383d92d2,d4912d9,86bd59a5,7cefdced) +,S(51bce64e,9291a693,1f24643a,f11f2813,f31f624d,cf336af,3cf7b48,15f431e8,8f743d9,a3012247,ee35d28,4120394f,f40c4c69,d75ae13,a063aaba,ed07e552) +,S(76287cfe,b52c5a0f,ce98e56b,49b4ebe0,83b80bee,3bc7447,a0cb9542,e7f7a43f,736b7e56,fa5744bb,d39d064a,50d98b07,e9e3399b,dc5847ff,13e33eb6,e2a7a7bc) +,S(614d739e,ad01010c,3191aaa2,c1b7771a,8dc29bcc,f1c4d55b,181acdc0,df6b8f5e,5ccd4e8f,e8607b76,c8a96c2c,5000464e,5591efdb,aaf07166,4f4db66d,c2f8085) +,S(c38444c8,ee8c35f2,b339404d,90d53ed0,35cd5889,89663808,3e2d33a,5e4e1bc9,8b4408cd,de5452eb,dc222109,287fa9ab,1d2ffc9a,16b93f44,1f4bfaf6,6ccd29f2) +,S(8a9c9649,c6016f35,d819bf02,852bfde6,56a1c197,2dbb6539,2391df7a,99c8f349,b2dcd957,be2c19fa,6c4a6030,a4cb500b,1797aa5a,339181af,dc6e974a,d769a8ed) +,S(a0f5cd1b,e4449709,25d0ea0a,6cd28d75,96292ab4,1d1766bc,ed6b3311,bea04b03,d270b1e9,291b29b0,ce045d92,3e449ce0,c8d7931a,71cf4b8,68af9594,927ff95b) +,S(a78f2336,87675987,7afbdbaf,28e2590,25c64ddc,a9543a64,709d4c11,1f3a9614,1365fac9,a5d245be,e5245b3a,b1f50d19,de34aa9a,439f5e7e,e241f042,32a6de83) +,S(3bfd37e3,ae482c5b,92baa6f5,a413a46b,af6cae30,9ee3fb51,4a9fc3e4,b391769,2d930818,34bbb0dc,66e424a0,7778c9cf,d0219c06,4dc7fd66,bdc554f0,396d1c59) +,S(92cac49a,261d23,e776ea75,7e796d2a,d426f23d,602ece5d,1b41cd71,d13881a2,8c76ec13,8e0f37c8,99a3e587,a8c0c5d8,c7a43ac8,187a35da,c0d8492e,571521c1) +,S(cf6ede0,ea7dc67,cc370894,1493567b,718944de,7a96dd6b,82940214,b56842a,e2b717d4,e939608b,7ad6128a,53dc8c52,fa070d0,f591842c,a76e8d0f,54627cb7) +,S(6204c998,ba512945,26ecb92b,bb06e218,968c8c2d,11e0435e,3dd1bf82,fa91e17a,1690a15f,e78365c9,c8fae21e,f0af2a3f,d1ed18c7,9a607939,d12d8add,94cd0ea4) +,S(a2c4fb48,cc5500e1,35268d13,a6ac2e16,d8ce0707,f2237f12,ef71affd,e4c0aa5d,3809440e,e608c897,cb7e3906,c58123ab,c403f57a,8d59b950,9e5f2d70,3c0cd839) +,S(d8af7fa1,cc303e4b,c5da36a6,d3b2e309,6acc8ec4,d73224f2,b667873d,eb656f60,9fc7f2bd,5a5533c5,dfb39f9,7045b135,5e14d81b,9edeae5d,dd4ccfff,f0c6de0d) +,S(3e9a00ad,b873291a,604e6bbd,b05304bd,3770733e,d1daf90a,864d775d,76dea0e7,deb49457,f6d1c4ef,53524e37,f19a8d77,20a5cb9b,321b4630,51f8eeb4,901ded0) +,S(bef5ae9,30aa620c,9854346a,ac1b2ac9,760ca8d5,ea189368,9de50e5,d3dc3d7f,20d80c42,f7925f59,b0212b9c,7d4041e5,5da98a3,fe373034,c0fdfad6,48dfc48f) +,S(cd4169fb,cd28d507,6c174308,8f39645a,38215e47,888a435d,5922b490,9155f67f,f9e62ca2,1a5564dd,5a65f274,356c1b68,a170dac6,4b5aa5b9,29dc2f26,35e74674) +,S(a4b691ed,34cd2624,fdda2504,797d76cd,4bd37b11,4cf3921d,538b6042,ed5a4c28,c65374b1,6781b4c1,15b0ca54,53e3397e,5c045a77,72c72d12,c336c205,d26af55d) +,S(5e4e916a,4226b788,197cf68f,aa850c0f,c2b3a615,bf9e847d,c9e55dbd,88aa4818,3f3c3ea2,5c7c52e6,5c9991f4,464f4b2f,f3395d05,3eb27280,8d984a31,b798951e) +,S(dd4782cf,f4d69f72,c951b3ad,50a4c601,f743e6ba,2194d05c,a5f474d5,eba74a7c,97a7bb5e,9854ef7c,5e3dd6ae,8628d8c2,5d3a791,d4db281d,6c7c12c8,20977b99) +,S(a1530ad5,4ab405ec,ddb94543,2669c07c,281aff41,13e4af0b,cc080991,c1adce36,f3d25221,2732842e,5dddda78,1e2aa5b1,b18550b6,fdbb968a,77444958,4a63e756) +,S(51924ef7,b438e4f0,614523f,232af64b,e5ee0d32,ad8e5323,4a2d76ca,9e64719e,87c115a8,11f94db5,6736e82b,8b644bfb,fdfe6e55,8ead8176,26858c77,128a8095) +,S(82cfee68,e137d874,107625d4,be20a9d5,6ac9055c,6b97563,a3bd5568,53fada6e,dd49aa46,c4f5c51c,72a804d7,6dee7a72,a363e978,502a5cc0,6ff67987,30733b7a) +,S(a3738876,f7f1ef44,5a1346b,36c7da6,e02b70fd,2cc3bf30,a4efd7e5,5f2e623a,6596f52b,e1ea52b2,be0de46e,5480331a,b1204d36,581b2edf,368d9611,ea04a21a) +,S(ae4ca6f7,aec818d7,2b624fd6,b2ccf24a,8d8382b3,18b0dd7d,d8203658,2980bcbc,6a7ada03,35ad7c57,1e2a29f2,554c8bbb,34815596,1aa995e9,2378c97a,dd8f1ae2) +,S(be33562b,fa9d762f,9b18d198,4dccb9c8,4d6ac894,2d8506b1,400f7dfa,89d12732,b666efb8,77c666a7,35336cc2,14e874a5,c4f5c956,903048fe,473d2e6e,9475d442) +,S(9d7da6d9,815b3db8,5303b288,8a60ff6b,f382891f,5c45ecf,37cb92da,37c74446,46c29073,72ba5be0,e61f6d73,4b413d44,df3d2c0d,89fcc1ac,5402b68d,755b12a8) +,S(39233d31,e513c2bc,c0602849,8bb7b3be,b5981fb,7c99a366,b62a9df4,3b0d4d3f,fc27857c,92e0ea4f,4d8ac3e1,c61fa774,1ec57d4b,a9affc81,f97e384d,b916dfd8) +,S(5be2d788,db90e83b,58d02dd,7b58f41a,547e6f33,a82d84b4,3f7e5143,db7768be,b8cf3a8,6b2dfa33,e71396f2,e84fb6cf,d585ef6b,9a264875,b9049f2f,6fde1026) +,S(3ff59de8,191fa14c,113600c2,5700479e,7c53a0be,3827f5d6,82f7861e,88f162ac,25d5985,6ab0b6e7,beff5f60,c279a11f,8ae4efb,5e79a4df,d815cc32,2dc77ba2) +,S(81dc9c30,ed221920,98ad9475,da00f8d8,b61a18a4,e6305b58,75f75bc1,719a256f,2970745e,5c44cb27,a6f8f9c9,869a25f8,9cccf024,4d40ffc2,ca678d28,f54682a5) +,S(ba3e1e16,579c4099,1576121b,230d4f4a,ea386943,bb7a8d24,f765a3e4,9b70e9da,a1eeb808,653cfa67,8a9d8d9c,7d30e7b1,54eb0de6,55abaabd,90f82236,32c72f4e) +,S(35ffe81,50faaee1,141f52a5,1b7d1e69,fa66d194,3b96f04c,a0589c48,83f854f8,d66a1822,e83f6dd3,fcca09b8,df1105c0,b4ad3163,6070dc9,b7dd08a8,c9366fad) +,S(398ebc22,1435f972,1c214c0a,e38b9817,8b50d7e3,e5724f68,5b950aad,60763a06,c2df549d,eb2eeab,fccd4da7,fc2c8ce9,15551b87,14903011,6825b804,80811f46) +,S(2ba27f33,e7d0a75d,1d18511a,84e5ce1e,9ca89d2a,a44fda0d,6cfa1389,ca89e96,5023684b,832375c3,8f39946c,c91ca114,45c2ac54,fcc12f19,c6bb662b,997cf4a7) +,S(4257063e,7ec51f92,4ecd485,653182eb,2b54973e,f1ff0144,65cd151e,f9e829c2,47351f41,16dd0515,11c9ab35,b69abd64,919f8b5a,812ad5d7,47c5462b,55232c1c) +,S(77e737c1,b5b3ca56,94218582,d2e56519,80da8195,88ee46eb,e3ef172d,9b4063a8,f7cb5c5,e66798ad,37c8d4f1,1cb912e3,651ae45c,4d7b07b5,e0e20c2,89d1587a) +,S(dfcbb64d,71018c1f,bdef98b8,2a4cb72d,ef027d43,47b5e8c4,4a7eec7a,34cdaa4f,dfc0cdbc,c7207588,8af379e8,751c4f09,bc2f4e58,2dca9a92,e06b0c5d,97972a23) +,S(8eb686d0,a7871e8e,32ac5256,746d7189,b39855e2,2a52ce78,ce6962ad,d355ae8a,ea8b3611,fec52837,fd0afe42,4c22c5fb,89b79675,6e8a6a5e,d71e331c,6ccc30da) +,S(d17d8713,ebaf2dd5,316703ff,8c4c20fe,ee56522d,bea7a987,85a96b1d,36cc3e54,ea70b7e8,6d7862ca,9d8a7a19,bf8941d0,e9fdb872,4e46f8b5,6821d85b,ddc10b54) +,S(7d4c77e6,ae050a1c,856d28e9,c14eeeda,249c471f,82cd6cfa,3ec037e2,30b3ba89,c5a07653,f5fbdf93,4b180f39,327d102d,900ad68c,3da1a7bc,ea773fe9,6265fe60) +,S(96381109,451e5e68,6d61d51b,3b250bcc,3721dced,de39e88,f4f50c1b,4d7ebcab,9498f419,b088ca54,7f17642b,dd6f0fe6,9f06514,a7228394,7f15d165,64801b64) +,S(7400b550,54353d73,7b2da8f2,f8f4e953,85f44e83,fda3cd20,8afaf90a,978c2ba7,9933aca3,ce503677,e2129a04,cdb1d5ca,e36bed1d,275048be,6b18aae7,fd909771) +,S(3d7b0c11,fff7bfd2,71ef5963,9f12ebd8,d1de3bc3,93b51be2,a011e4ba,66ff59f,b6397431,7f7ca0e5,ce1eb57d,8a886144,8bddb12f,75469789,b791c4cf,32404b9d) +,S(4944d9ec,7ebf7f14,e6312545,5c8dd996,45d128dd,fde3743c,5cd6f4cf,65c46328,f0655193,13baaec1,329cd408,c9d1f3d3,5c2f49d9,126c9d1f,5bf271bf,2c589996) +,S(9960432b,4764b1d0,f8607d6d,8e08b355,f37b9933,69bacb51,89ce46d2,79bdecf1,304ebb4c,921d2fa,29200ea9,ec214adf,f7e1a9f8,debab865,78fac56b,7160ebd) +,S(313f535b,63585658,fc3409cc,726b5ded,9196cc59,6331681d,9ca84aa3,bb3de4d6,e511a48a,a55fe0eb,e5f23bcf,d01ff4f1,59b049ff,8c999fb3,dd64092f,c56c9716) +,S(85c4586f,8cd36dc0,db9b9006,ef4f74ec,c99478d6,5c011bcb,3ccf034c,548ed7b2,cd6953c0,45c5d6c,dc632592,3f9b0070,144c8c5a,67639f63,a75b4d10,5b434229) +,S(968bc6d2,a7fc359d,1edb668d,b7381eeb,d489b20d,b64d651d,21d706f9,94671af8,fb0ad6a3,723d707c,c1b2f330,4e59517e,de88bcfc,b52f3ce,d0bdb7c,f0725186) +,S(2325aceb,3722e77e,e6cc7221,56ec0e87,26d343cd,cff6a420,e58c563,bf28985d,601a7f53,dd295978,f2a59683,6f3e9eec,19b9c8fd,e81bba5a,21acc8ff,878d39e1) +,S(8c6e76ab,b2313bea,dc0667f9,9aaf32a6,4b1c9335,87c31dff,5407fdd,67acd2e4,27e3b850,d422df3a,c93b19c4,229b390e,3d7bb92e,340daa46,b3f5112d,1e50c29f) +,S(e31fee31,34468d3e,4d6b2c72,8d538a14,352e7a8,8b9837af,9d8d4230,5e36748f,89b096e1,2d1948f8,937974f6,b9a101e2,37f9df3e,280d4139,e419a1b2,6d0309be) +,S(596b586e,849404b4,7c742fdd,7e5a3398,da748ab0,67ae2981,215c17d4,b0d306c6,e96c5cc5,912cc711,5e4e8f05,edadf219,2ac27760,2b2ce791,ff6e18f8,62a0a16b) +,S(200cc167,5cf500cb,a199c3b7,1195270f,d453d5a3,8313f317,71452486,15aa1c02,780aacc8,7e34429c,6445c133,49240371,1905e24e,c17de4b3,e7b79cf5,5320ce61) +,S(7e4d5432,e10e1fcf,79148f8,77a4f247,70f0e96f,81331767,dfb5e9dd,2ad2025f,35f5dbb2,6ee82837,f37f5fd7,d417982d,fa58f0ca,13e3136e,ec0b5251,63aa432a) +,S(c1ed7508,95c97e6e,7a78f800,b6eb10c0,ff21f879,352870e5,776bb7bd,9c0237b7,90723a06,8dc0aa89,9c31e89f,64ffec3d,a38e8095,97209bb1,d8b1418f,eb418fb9) +,S(e5fd4ae8,a53e809f,83d239b2,a15d8dd2,9948ddae,6956d8de,fc7ce730,b2104770,6a4dda9c,1cbb2197,208e8ebd,35f2ddbb,50c7bf5,df4c112a,de02f0de,f71c4fa2) +,S(3ce75f2,4b33bd88,7ab72cdb,42f9ecef,e3534d15,f6733f2c,a766eac1,da51f30d,9eda315b,51ddf6e2,62ce9b5d,828af559,a43eb48c,d3dc9362,13bf04cb,1a838ed7) +,S(98c04c4f,33a81cd4,e498d8ce,77edf598,527fb9a8,8e19dd34,ad8cef3b,8813391c,fd2bcd67,f853f812,f4371c46,30560957,acb4843a,8ff21949,483f0617,ff8bd3a7) +,S(50e9c88,2906cb06,cbce62f8,413ce43d,f3d2dd28,6e4141b1,fc8a079,a87bbf3,43c713b,b05f19cc,685eefb2,ba04474a,479a615a,2f3c8a9c,e1c6243c,d82fa3fb) +,S(5d41ba17,458bde3b,64faa66,3f21b76c,71bf6564,2a73e3a2,eeb8a831,43adf2d1,17effc54,b3082159,2b39e22b,7ab058f,7f64fa7,68763510,87cc445f,57b6cec5) +,S(4e332cbf,2a02593b,6e83cb8e,1d92e076,6b34cc60,646fe3e7,89d38f9d,24d5b077,50fa745c,3ab90300,95b69985,99e391e1,744ad03d,decd1955,c8b2a859,e79e1f95) +,S(1bbf629d,27ee825b,c357455e,43410507,c83cd47c,dddb53f8,34716ebb,35a2dae9,850908c1,e99753f3,4f40070e,c0bd85e5,8fb72f69,601d3709,71ffa894,3de9bb75) +,S(a9149aef,f9dbd62a,ad0cb3f5,debdcb30,23aece9b,dc79db8a,a25f5b01,b5cde650,a7bb4b46,e6db111f,468a16d0,9df686d6,ae3c148c,61d99a79,918f0bf6,b4c327bd) +,S(801009ee,185d642,19de5b40,6b21dacb,b98ffcdd,75f8037f,fc5e1721,fdb72a71,e8216609,57c7ad6c,1dd36f70,645c75f1,38283905,898650f2,daf2e5af,37e26441) +,S(c070e99a,e466f67a,b234584,66f132ec,96c6b639,3900468a,b7368a86,c0ba6770,883fabdf,358d4f56,8a56f77e,3b291fff,be6f8fcf,9c0f0171,a1544905,50769362) +,S(6be89639,cf612761,78f549a9,ed0af9a1,8e028c53,1dff79da,71c5ff1f,54109f4a,777aed7d,dd379131,26a92f38,ff9970c4,ff2dd6f1,6d766e0d,8215fdb3,9604cf14) +,S(d1fd31d4,1ce71e4a,2052e79,6dbb1a87,10094505,2b9d9009,2195afc5,9624ce8c,f357abd3,78a8029d,eaa796d9,1860e5e5,36d5f2aa,ea2bda2e,5b510949,253fded1) +,S(1c85382d,66fef14b,3cde617c,a426996,614c328a,ead99033,7aed469b,8f169d9e,58c5af1c,b236e6a8,4f58702a,b727d9a5,e2406a4d,fdbf9113,a8f895ef,78a71f9) +,S(2d8fa9ed,d5fd67b7,42e5c2d5,2c128ad7,eec32cb7,43cba12e,272edfd9,4f36b5ea,71b15f39,37eb2a09,f9533af4,bc964c32,23145340,f780731f,aa9ad1d,8f2cd37d) +,S(4f512379,d9f6c596,700d0a15,950ddbde,40ceb1c6,87030c95,4c538122,dfdbafb4,54de9b05,f864df5e,ba861980,c7dd8567,4b320afb,e0381674,c7f7c083,4248c05b) +,S(9a5f91ba,48562c21,58e60949,6d43eca3,2c69995c,ed93e834,168d22c,d9e7cd1c,9f88a3ec,c668eca2,e01b1126,6acf9c51,29bfa33e,e12f7638,2d40d2a9,b722b86b) +,S(dda30502,d417fae4,c4ccc6b6,e833b75d,d84d54fe,d58fcf0,6577dd8,52f9f610,fbb88dda,2e74641e,6d45468d,102e2a42,7f4c57a,6c7fab0c,5d4dbfc1,155469a1) +,S(8d2e9e7c,5586141d,848e50cc,631ce5f4,600dfb1,618d65e8,e88da5e3,5b26e117,989c39ec,ffd67c54,d55ab4fd,85c2a556,bb72fabc,f763c9a9,e33a1ed0,251aa86) +,S(726ce076,e6b63d6c,b071cee1,c3d1da27,10c911cd,e3d59bbf,a27a7ca9,641ee995,4e41baa0,c91ff8d3,4d2d01ac,d8ab5d36,6ea5e81,d489595,1c49622e,610af9c1) +,S(debc91fe,183503d3,fbac0dc2,c9e95062,c0d42971,ed2e97aa,27dbacd9,bea43a1a,13593715,a6fece9a,f33b2ab8,d5f26e6,6dfdf3c8,ff688100,d497a333,be2d2f11) +,S(c5394335,77914ab8,e7039e8c,472ff2d7,237c794e,d6b24f41,c585e910,f0fd4b28,2805359b,628a9c4e,7b304112,80aa2a0d,23c26cf6,9a47310d,1fc6fc54,cd26087b) +,S(9a2892fd,33c300b1,802bf1fb,e8a8faec,72b81810,4bee4e1c,c998bc79,a05f29b0,997f123b,c2fa0136,522ebc53,a5ce37cc,5538705d,f5fa8beb,b37f72ff,45186e33) +,S(d4a22cac,f224fbe,7ed7fe42,7e0bf180,1503bbbf,d73de79f,4c558104,b39a351a,8268fe97,30622e09,2a513349,548e346a,23260311,a82e860,341af6b8,3ace752b) +,S(4a4cf3ff,15adbe1d,8d414963,b0709fb9,11d4d2bb,877dc03c,77594fb,9cc11659,57c84583,36f1952a,62441810,ea64ad3,5109a30b,c39ff36f,c2dedd60,d1ced874) +,S(58c0eced,b580d530,98c836cf,42ca2648,e85e0b27,871caf44,1f69bf0c,158e1539,eaf79c49,1e1dbc94,4e63d36f,702cd1aa,92e54a09,fa11ffd7,4121783e,e842467e) +,S(b0fbd0e8,a60c7e89,38a154f3,fe586a33,26132302,7f4e416f,634cc9bf,724892bb,27ba767d,6757f40d,b54fcb50,104998ba,6dd83f93,137c3d07,9a0330c7,82a5d3c3) +,S(a94ae12a,26b0135a,125fecf3,e4ef1844,ee90c2f7,84cb4081,8c16d8c2,d992f0d3,a37447ba,665e7595,c7816a6f,6bba3d66,e046fe36,8877c95,bbc8a760,218e2050) +,S(8cbdb09b,3eb74fae,32b6c484,4f9004dc,c540e240,7305aeeb,9adbe308,8cdcbeb5,2b863a2,91f6efd2,ff07b14c,4e5a169,912df745,1b49e3b8,10e72cf4,34c932fe) +,S(3f8cfac3,b70eebe1,cc6fb89e,d508abd6,ab3131c,40d37afc,f8f39c87,34cdbac8,dbb02111,846ef25d,794b303d,b48964b5,a68b5287,b443d321,f0c493a1,2d58b65e) +,S(b61604e0,cea3e79c,12fe9a4e,1816630b,31fcaf4d,b3ac84b9,547da60,df15b25b,1aaf2bad,9ea0fa5b,56665b41,ba1264a4,317d5388,9018d92c,ea2e9d98,29b86801) +,S(eb0e7410,3c6ab38e,1c26630a,7fbd68b6,fa51bda3,64d1ca3f,7c86ef0,451327d7,dfa05017,57c4d3c1,9541c9c7,d9fb7438,45cdaacc,2ee377d4,4c36817a,e0e82e6d) +,S(636fc503,be51e64c,8dad2812,6762c04b,1fcfdd7e,4b25544f,4bcd0bf6,9556b7ae,57b83b0f,5104149,7f3b6735,a8b7d886,b633c8dd,5052d1e6,9848703a,313f4cd9) +,S(2fcc70ec,4d42235b,c6afc2bd,1d2de19c,5ba9dc65,4ea3e288,c15c7358,e52ab330,6a356018,2bfa1e22,db64cbbf,cfcdb695,35bde8e8,2519d069,39577e65,256a30ce) +,S(115006c3,8d38b8bf,db8969eb,d6bdfa95,83be81e5,bd5bc7d0,1cd10e22,7ea94b54,6043ad02,16eb3fba,9af39e83,f6e87802,3fac023a,73252780,2505a1d4,2080e08a) +,S(17d565a,15ba1c29,60ca2da8,2fe54d01,3756a986,bedc19a5,15b653f2,8db3aaf1,917bb9dd,42040b3e,4b8b05aa,b9d31252,7a633819,33534c35,f274ad7a,9bc7399c) +,S(dcc2489,88501c43,b8598f7,a3e5bca9,d2af8f8a,b482f30e,2374c6d,6b221ef2,a859757d,d5c6ec52,b1f102a6,ef00decd,cd14cab5,99f1eb0a,57864646,4f652e72) +,S(a68b2b9f,4e9430b7,cdd919db,6e808a7f,ae2cf9c3,d43cba03,d833fa8f,351f0b0f,e34b8a32,d3ad0923,8e95614d,92778021,7f45b14d,f2f9cf66,d6525bc5,94786526) +,S(2f954e5a,938e1198,5d2d11e9,ead59539,fe7e2f17,4702d3c2,3190829f,8d0e9462,b2f0d379,fa8b7d40,ba2fecc8,46a393b1,f6aaa6bf,9f89ac61,e55ab1e7,bb16dd5) +,S(223d3d13,6bca94fd,9b3fcae8,6bb2ddeb,3cc33c8d,3ccff556,fa93938c,c27ffe4f,87e19106,e317187c,c256f7dd,83d6219b,27f6cd8a,53bb4ec0,9c74ca58,51512915) +,S(5591d8e8,291161b6,43df3a3e,9b4f495c,b614432b,a0f3aabf,517834ad,9e8f7b2e,2c8d6a35,f6267e52,d9bd454e,bba4719d,30b3fe7e,c40a1416,673ef594,e6d07c2) +,S(eb2cfc4a,d15d1a14,870cbaec,b9e9aefb,4141841e,2e4e6252,c8e93751,45f29a29,78810e08,10bfd992,b7b04c79,c7650150,e62f210d,6d35cb95,5bc67215,7052e5ac) +,S(6112c3f9,9680a818,5e4b1d4c,539cc436,bdcdb47d,2e19f927,d5e3e9,eca3f74b,6e860bdd,723c8bfa,dac8f9d4,1f6ca96,f2579d7c,6a690f35,3b8da52b,98da4403) +,S(892120d8,d552d8b0,c42c23b,9a0f17c3,b9b32914,d7e31579,7b391ded,a7d58b16,e62523ac,b3c778f2,f913d1f6,4bdcc037,cc4a9496,ccf0cedf,32502316,b5cf7941) +,S(4758b456,217ad3be,2315583,963044a5,60ca4a49,168461c5,ecbd1e91,1fc4dc0a,99e4255a,4f30973f,57eec6a,1c30ac1b,bb74987b,3c4e7ca,9604878c,d9d83679) +,S(ab0422a6,9a207a87,97fa0c6f,978479af,a3b95dc7,d962e143,b99e7575,6e5629da,73398d0f,fc9855,ebc280c3,2b8dfced,84af0f70,4994edfa,7a06e2e3,a5823faa) +,S(1980432a,ccb90b14,30d0b4c3,5829374d,852cc7a6,f0a1b20,ee7ad43e,d545d227,96ae3873,bfbc8ceb,2afd1a0e,9b989bd0,69c919f8,f2e51546,7668da5b,9e8b05c5) +,S(4288137f,e2dffb3a,ca761cd7,2abbef3e,93b8a015,743d50cb,b716252e,e0e93f17,c02c333e,36c366a6,fbd855f1,4da07672,71fddb04,59e788de,456086dd,aa238825) +,S(d65fac35,5bc89da,afc4d16,aa73fa4,77e43276,e0db7d3d,52d9281a,d6b6cde2,e6f4c975,a6c5f337,b4500545,603862d3,8e9f07e4,18886b13,5678478,c007383f) +,S(7029b144,e62dd27a,4fe8b54e,1607936e,beb96784,d1b294c8,43e19978,b98f6ca7,8b10ed66,58056c6e,3a2c90c3,855444f0,9a1af347,c73dd14a,a478f2a6,7140a25c) +,S(4f2760eb,df969bdd,e80ea87d,a5da0c19,fa343e4e,44715711,50295b43,cf9183b2,43e2c17b,f3f9ef09,fa01fd39,b8f69b69,15d8625d,4daff425,d4629677,83e28167) +,S(cc996aad,db4196a8,f355f0d2,3b9fa539,b573ce57,f2ee7e52,14372615,c374a5fc,b1c40f87,18782935,c30a9cb6,6be85d11,44284bad,bfff9923,2c09f2dc,a8ef28d) +,S(c7818ad3,f3e3d905,b2c38e39,85eb7091,cd9b3285,3bdac631,3cf4303c,d54ade42,55574c4e,7bbb850b,14763fb0,fc1443cf,3403a5fd,d1f5f937,8007fbaf,94339eee) +,S(6cd03584,6fc48ebf,f4344d1f,3ae5d258,9a45dbc9,e779445e,52a75737,2589c4fd,afa85b7d,b165e371,adf67dda,8e4d1fa9,4d811c92,8d2d4723,a44e8cc8,93416e34) +,S(d652a205,f716b1ae,632b7235,91152314,f5231b92,474dcfd3,bfaebbad,443b2e0a,d2198421,b78240f7,cb82f0d8,5de03d8b,c4646a23,ec166dcb,a458a06e,b93bedcf) +,S(a807d04d,cd844a1d,f99b3e4f,e3400459,81ff0baf,d34e2d73,a6a052f8,dc52fb54,188a78bb,73939835,3bbe5079,ffbbc718,c385c047,97cfb151,af019e9f,a2e2cd9a) +,S(1efd2bbc,a5d6ad48,e93acd07,d6cb02b9,b8c3a95e,9f4cede2,24efdc17,cc9eb2d7,f951ef88,1b98c7e6,357e191a,1bb357f6,2a9d2ae,a8af1a05,63eef3,66745b39) +,S(5bc5e54,d27d3db5,982bcd04,497fe0e3,ea0ff13,7c3bdf66,6ed0b9ac,2395888f,3555bc02,d4f4eb01,661f8b85,7321b36a,5a22d975,2710375,4c1f65f2,82ec3300) +,S(f600a8d,26b08d0d,e6e2ea80,e8ad2f1e,158cca71,15be6f22,1f5b808f,746a3247,23be5a13,4bc3fa5b,7ef75b2,8e8e11ba,76c753dc,6516caa3,cd5b3ab1,8bca3523) +,S(fc7e4e0b,2ab2a7a8,cc5712a8,be590135,f5119bc3,6c73f81a,e492bd26,90ccaf7b,4bd612f4,1f274690,6ea862b8,a6dd8929,e4a682b5,aa835cdd,b31c90ab,381151a6) +,S(51325f3c,fe12d00b,fac67eec,d79b63e5,41641d58,76aa9700,bcd3b3b5,89442655,d6a894ad,7b7ae6e2,db962360,579657ff,982a35e5,91cc3b33,a4437a4b,133ef941) +,S(2db3ac27,1a55f608,f21bd2d5,717f003a,afee9a6d,b8fefa09,5626e4a,c598aec8,c526bf33,a0c01c60,c1cc9fc9,d66609f5,3c662168,b47cfdd6,e0de0c88,9bf9533e) +,S(9080772,93deb01b,5eb05b55,47de4321,35fbd436,3f391be5,1e1d205d,d5fa7dcc,fe961eac,17243337,653d318,b5c62159,64dfef84,d3cc3f23,e034c102,5ed7442d) +,S(32a1ad81,e5a64fc8,2dacc03f,6790cd4f,45557ad,3d3597cc,e2ec37bc,339ed9d6,87abcf68,18010022,7097b63c,a795cec6,79cb55d8,a9076cf3,d1371062,627cb07a) +,S(f7cba8fa,58689c51,a0f1af76,971d17a9,8c5849d,55b396e9,a3771d17,4d9246f9,f4b0aba9,10d5a9ca,eda4d733,35d5fba2,5309a0c2,fc83072c,ac37b9ec,af58ee45) +,S(cda6b104,2da900d9,d65b6b7b,c0579a43,fab75f55,ae7046d5,8ee8af82,6329ea81,70c86c0e,acfd7401,5a1171a0,1e3601e1,a8ee20e2,9ac7c0fc,68d6f1d,cd1771e3) +,S(a261a640,9c5b1ce,9a8f27b0,544ca0bd,a46f3bca,d11b7f2a,c23878f0,f67ee58b,1e26a71d,4c42dae9,b4e9cda8,fd33d725,85da67c3,52594d4,20c6e410,f3fff888) +,S(bc70c967,fd7f842c,c018e885,d1fb6d34,9435aa3c,682f6884,6b394ba6,e9f4db57,a2b99d3a,837e2de0,c40a0784,7865701,3032efc4,87c47e57,18d84e11,f8bd9468) +,S(364152f7,5dc43149,4cbfdba3,ffaf234a,c7a26567,1051e026,9c60389a,7077a9c2,ac3ac7d9,f4ec8543,3038ae4e,7ede71d5,3c8fa601,25bcd8ea,e084c32a,546d265) +,S(52fea4be,d57d5d58,d92f59d8,e4022df9,d82ca42f,a3d89326,cc36dd96,94f3043d,b7e98328,52f98a75,f738f9a3,7a67b39c,5708c608,5b6ab99b,2495428d,8c4feb35) +,S(34fee910,c8bac880,f973a096,a9ac3ffb,9c32ecc3,d2be3ce6,7b8d6822,863e1a4d,e0f01096,9c9dc446,c78db14b,122e260c,2231f6a0,971d08b2,24355620,689c7a17) +,S(6af28f0b,f4c9d2e8,192424ec,31f076f7,f815ab0,f476a4bb,4019b3bd,db49c65b,2c55fd2f,bb663b31,1a9aa346,917f6064,17d1e1dd,bca45d3,f1350feb,6ea45248) +,S(70b6ab66,39e4b41e,644f1b6b,6ac5d36f,a4f0ad81,3baec03b,8bc74f72,4d320e46,ec6409e6,4f4e4fcc,d19ad5f1,96d3cdd,96f7135d,dfcdec95,23780c18,8a913a14) +,S(ede56f11,4ab975ae,adbeff50,ff7dbbe3,614196a,138600bc,15508481,a065724d,9e7fae4c,11f421ed,26d839dc,61b0684b,71906b63,6efdd73c,2dadfc9,5336ecfc) +,S(83c34c3c,840a7310,3d819d74,66648e66,5de54af9,f1683efe,6857c3e4,556df8a4,9c238041,562dd6c0,eecd9771,9ce2eed2,90aa8137,f109840f,d31d70a4,c86cd10) +,S(aa2afc90,89b98,5228cf03,205e87a4,52cbdb45,24d377c6,1020593d,a0c7e200,3443196a,b382ac19,d3d3bc4f,a3161e00,6d812924,fe8a86af,2db5cc27,96be01f4) +,S(e42ec7dc,4310cc8b,9f2956a0,2fbf71fb,e90eb045,881ee800,e3a75730,4155c520,939ef2cf,a52d91cf,e20324bb,e8da54d9,2d000945,58abe7b6,93c2679c,d625336c) +,S(bc0bdd24,937c5200,fd78de47,a16ef9f4,181617ab,267fddd3,4a3c5606,32ec2b21,db04a4c,10b521f7,986e0e1d,192b0870,4a028511,205d7ac9,df6d2993,52b63035) +,S(dc88c9d8,9b43a733,5e310fbb,3f760e29,55c005d5,640df990,6264ebae,adadc8e7,2d6779e4,6f984794,65bfc677,79feb7b7,3fe37b32,cc23d636,25a3c8d4,fc2fc512) +,S(a7ae0d8a,b0c932c6,2ff0cb02,e05d76ef,5ee3dc50,88c57210,f6f9e349,80111c20,d632abc9,d63162c8,98b9dc94,b321de53,ac8dcc45,69233cdd,1d07da1,92e553a2) +,S(4620236e,e7bd6eab,db203af7,57da6e64,d631ac9b,a5f03215,592a5acc,5cbe0e97,5df4244f,69ea1e2a,6cf30cdf,4fae66a2,707851bc,7028d8c8,8fa97690,28627c6e) +,S(804cb84a,3d8bd930,51f50aca,cf932301,5cd35fff,349d8a38,e2bd991f,27d8f671,4b77b812,9ee0f835,96ab2f19,20362128,cdc39552,bbe6d267,bbc9a8e4,70ae8d3f) +,S(6ea5370f,5382b2f2,b801fcbe,ea463912,b4f6fb4d,e207237,8e71dbbd,b91c2ed2,f5b4f909,d8f3ff08,e92a002,f1959ec8,8b513ee2,d37825b1,a8bbe141,90b2d88d) +,S(d8b8de1c,4ff575a6,12bb0852,af61c6b3,1ee56403,b81a1f47,69fc7072,a2e22ba6,1e3c4190,d37abf89,896ad827,55c256e5,f23cbdcb,47b05892,8d538df4,e2468c0e) +,S(66ac1864,4a0bd6e,9c73f3ea,43a00d6c,80d38467,5080a9e,475c8291,edf1b147,2cc60c0f,7db6b776,1503efd,551e1a36,9be98ec6,73dab0bc,a61881cc,4fa1260e) +,S(47194a2c,4ed223e7,7663cf9,38b5a5ca,f2784435,c375d85b,ef3c5367,3f60e942,b0fde11b,5a64dc13,7bf2738c,75027d57,5808a3ce,abdf7604,5f4484c0,d3d9f920) +,S(1141c859,9af2d983,88274742,88dd768c,9fdc1b2a,c5f06290,10bd3cf4,2a4c6186,7a431f47,61ed4613,3317555a,578d0f8,5392a0d2,ba98ec64,d6b508d3,eef0226e) +,S(f905bdd8,e80afe9e,d65da689,bfb8e549,487002d6,16ac651d,4ba300c3,e7496f79,1ec7bf7f,3bfb5045,d461b03b,a7f05067,cd999fc5,f9f4c0fc,a7e25b19,77bfcf72) +,S(ba54b8e4,fba452ee,23c4faad,b14f0af8,232ea62f,ad47a3e5,573f1fac,f15e9e0,af556ae9,efcabbcd,bbd8e48a,82ac80f3,9c96ed0b,11370b8,da1bd4a0,60f5cda8) +,S(59d3ead0,561f6e24,30e87f3c,f361a2b4,1494a042,3a775e9,c08a28b4,a26a80a,9b26f47d,50a92229,c28a278d,427c7306,f5f1ba1c,c2d095d9,ac51e18f,a9bc8) +,S(2a6e5a3f,ab4cc928,d8f2924b,e7e0f3cf,15520a08,eff00f5b,129d9070,ac865d47,55c0350,58727023,86d19196,4609351c,919913de,e93800cb,38b77183,5ca625a5) +,S(898f50d1,c35bee41,88afe91,842cf659,fff1fb1c,5aaebd84,6828b002,a8907502,b2456e80,c97c2ad0,1ae02e49,6b84c02,fc9bd0f1,4a3c5a79,dafb8f8f,62f3267b) +,S(d1854ab8,b49bf0cb,1f9d2304,e9ee3cd3,bda5d9a3,ac04fbf9,422c4671,d6af85a,4e2500f,d8818180,5b16a077,53eddf34,d7bdeb02,17df7fab,d0afebe9,47155c20) +,S(861fb88a,394db6e1,f03cc787,d968ef7e,4a417df4,2856d303,a3edfc66,feaf4680,a5d7e95a,ab8b0b13,23fff11b,638ce02,68f3c38b,dbc018dd,dc6d2362,a135da6) +,S(9544f768,b9fa9dfc,3c155d90,b676cf7b,ea526903,39fc111c,b0ccf62d,813403d6,cec4d92f,cbde624f,851ed21,bbf5154b,28d87603,5e302902,53e99670,806e047f) +,S(f7722192,f80a66be,23cd7b07,89f3a094,311cd40d,3b7149ba,2cb5cca8,d1db68e9,41d0e9f,3243d64e,73e26661,cc851e5,1c11e320,277f7462,d40efe0f,c81b516e) +,S(876b4c65,1f88729b,dbf9927a,89ea91e5,b6bd8e7c,439f6fc1,be9e07ad,698e14ed,ece2cf81,1cfae9dd,cf787b88,f62f2537,7b573084,86ab84e1,6ad31ddc,f96b49da) +,S(706af4e4,62249924,88461427,8917899c,721be8f6,3353b127,b7ecb03c,7b70b10,c972d972,c65d200,e695bd29,813deb74,cdcf0ee0,e612f545,aa6506e9,7e58a5f3) +,S(ce97a218,c9c96262,b5cdde0b,a27e5f4a,4301b75b,f9d17dde,f1495b7d,f3863c9d,e9398e1a,20fd1426,88916410,d7af68f1,c12900b2,72b03f55,c5770aca,2a1ef10) +,S(fb625b9a,92cf831e,886a1f01,c2db3d53,7dae0feb,e9b3d9bc,a8fe6449,d53be895,7f783e74,ba569e04,a29d68f,12cbf223,1fe2a8c2,a651f44c,30d597de,82599a37) +,S(81ffbf69,7a7d2b8b,51b9098a,8833244a,f126c6f3,b42ddbc4,c6b2c5a5,55f4747d,e2c67357,982eefb7,3213d530,3cdaaa7d,90b4d1de,d0fd4d0a,8b002162,f006f33b) +,S(6dfc0f66,8c30ab7c,af16d4d6,309ca2ec,679d6b77,be695ba8,c0f31b55,6a0ed0e4,a41ed2b2,d9a0aa74,3182d7a6,20f441e9,36772438,bfddfd90,5aeff87d,b15a563c) +,S(1c6bf1d1,b953e56a,ba1a9b5b,f63c328,1d5715df,88bcc23f,e77f94c3,3b501b44,c667214d,b4ca1782,19c368b,f7c2ba4a,8f1e74df,91a22d3a,8e336089,e4e4b0ef) +,S(b69112df,5d999f60,5d863231,9144d2f3,5417b9f0,d1e78ba6,b2afd247,fadef93d,2163cf7a,302886e7,70fafeb,8acaddec,464f115c,89422020,9a034c63,558df4ae) +,S(bc038732,ac230f91,7c58b8fc,f9ef9229,9737a2cd,8e01687c,da464bde,4976b6e0,3392601,796373,603e1d6f,a7e23385,7a7ae0d9,df638ab3,7191c046,a25682d2) +,S(96df3295,1047ad4c,6aa4d9ae,e59bb00c,7489c20c,aded01ae,1833ebda,27e32d81,418f6c2d,74ce633c,181189bb,f5d0f066,cbfaa8f1,e6674466,1818c4ef,e2e2034b) +,S(a3c53227,939e40ab,ec6fcefd,eb6193c1,cb6a65fa,2f3501d2,63cd2fa7,6a304979,4468caa5,498ea6f1,92f29ade,37a2f667,f46798,dc600de8,cafa0ed6,dbc967e4) +,S(93fd8207,3dfd6d6d,6b85f1b3,1e172a61,7a0c7d46,b91d5a92,601af0ad,2545eb2b,601beac1,9a8a6a41,1bfca863,6acfebb3,9611559b,20b8a866,88397d47,d563a847) +,S(ba7d3bef,2e2c63f1,f9acef,2468ad8d,a5bc0d9e,b45e4a2b,ee87a0ba,86ca0a9b,ffff9a67,33129e31,10d33ed0,bc5b6bd9,376f29b1,7bbf2e09,7c6efcae,a55114dc) +,S(e0d955c0,2a4f9c35,97597258,2964d7a4,218898fa,97ef3011,1904290e,36157a8,176fdf9e,7d420bb9,a0782f0f,8707789,b28cbc69,d5a6797b,aa2bb985,1c617f0) +,S(16b2c140,8320cb93,112da689,c690d6ab,6cd226fd,e1752dcd,a444750,bff81ac9,2a2face3,dafd3932,f2617488,faa17b6e,5025f792,53c65edd,2abc7790,d98bb281) +,S(2fbb0432,9c823e2f,645d61d9,795a414e,220db4b8,eb4da0c7,fc22bc10,e9f502da,1adf66ef,15eaddfb,abbcda69,c87068ab,cbfe58e,69f58246,a0ab6259,90ebc31d) +,S(649134da,f42d2579,b6522f2f,404d6456,c178f883,8c9ddccc,e132de4e,67208ebf,4385abfc,3c554bc2,78844648,a9aea5a,e7709b51,fe644e8a,4a756c3b,f09355cb) +,S(b95544b1,dcb81f9c,e0601c17,29c7fdef,128d62b0,b8993023,dbcedf8b,d3991cd,f871fadc,ffbade32,d51f2d45,4f0726f,206fe760,93c0ab0f,33cc5383,769dcd2a) +,S(cd403bfc,5034d0c0,a23df5b4,a4b1b096,ace1ea17,288f89f,d063c0ca,5dd668de,c1296131,aa56f46f,49f59760,f3a4bf0e,3fa92e54,a5d8f160,54ee1fd4,26717742) +,S(a4aaf37,d7f8bdc9,90202074,c9a8f56a,1ad78479,95b4d939,4b6ea478,3c04c581,4cb3b6f2,dc02b61c,fd2594f9,40773d73,1a8cb9cb,388af431,9348d3,af16da34) +,S(57102ff8,ebdf048e,85edd3c5,2864578e,97478fc7,e6e7b937,6c37d9f8,abf438c4,c84f1d9b,eaec1962,e79e308c,251b2f31,915aef16,90ab5128,8331d8ee,f8161d4f) +,S(68fe98e9,3c5c5fe1,108c08c5,8fafc701,12424685,c6809774,832b0623,a3c9b6ac,492ac417,fd956b87,ee8078e2,c46f21e3,cb5ea58f,ee871cd4,d6480cf9,c4df273) +,S(d4bbb6,9ef5e23a,f0932cef,2eea4ab,d97baea2,b0893d43,ec08be40,2a4a5e77,5818e60,9c1dae31,f65e223d,f0cd08c5,9e74884c,2a2dc166,607fa4b0,47c7c98c) +,S(e9627957,a8eb8b72,7f0d872f,28acc53d,23a5c53f,763f3b5d,68c7e690,5a83192a,5da92e7d,dc291696,d9466d17,d4ca6cca,cab1057,4f5a08d6,6e59ba87,cd0d984f) +,S(49f21cad,a83bf2eb,7c508ffb,70f9fe84,1cd547f2,df83f207,6dd2382f,1711caf5,1c7d8129,5f834ed8,ac73afc2,132e6eff,2447611a,4fed8114,ca18925f,39f31931) +,S(58282a9,40f61d53,14d1d110,c18713d4,6c34a8cc,5b0ff64d,fd6d0182,aefa792e,7855e155,d3e0f2d6,52370145,7d83d7dd,2a96ee49,3eac091e,677f0a34,105f6ddd) +,S(c9c97a32,4b07027a,7b5db6f1,d70bec7d,dc3a14e7,43d492e5,f5569199,23ca118d,f601f40f,894ddfe1,c2b1e99f,7c2032b9,15d600d9,e2ec41e8,747d74c6,9664b56d) +,S(9e4dc175,8ed67501,86a7bcdd,a11f9273,9bbbe0cc,aa72862b,8d515a21,159e054e,ca11c31f,2bb866a6,be0736aa,19b7e36f,fcf4f4c8,715ebd3b,c9483813,cfc6c0ab) +,S(fd063789,3ae0030b,cd8c1e5e,8cdfbdda,8e5af1f6,268f552f,7a7f0c6b,8aafe2b5,8c09eb0b,68d744a,20468a8e,4326dc01,f4a35480,df1a0435,b2e21d53,dc8e676) +,S(37dfdf3b,6e7a7651,9ba81c3e,c1377580,d85360b5,b466ec77,b3f2b272,fd4af04e,cc3137b2,7b732758,d78f3b07,80129e77,43dcd85,ec941727,ea3b4f8e,d0fb7844) +,S(45ef106a,c8a5e25c,771a2f18,bd2be0c9,a69cb49,de16d8ff,e72a45d4,6c1dbae0,cad6a40d,742e7db7,3f7bd452,e0163490,60e5681b,31918bf4,2ad8b698,220ab158) +,S(258c52f9,88b9ca25,73cde71,472bf58,99648cdb,c1052d14,be02469c,11fdfca4,4491d88b,26ea5c7c,6a66c9e2,1a5b61fd,d60d0b8,8394cffc,359af9ec,29939dfd) +,S(bc92a4a7,727c4e36,3d0cddb9,d36f1d9,d4f8ff67,de881c83,afd51193,a9e65217,76ff6a08,b18b4795,61f1c024,d464e9c0,331c22b4,ba3779d7,9dd13122,63aa5120) +,S(8a19e8c2,58c04834,f11ceccb,c156bbe,23e4e837,fb5ff353,249c12d1,45f27ebd,15fc6c70,bff48ea2,c56caca,2b978fe1,8f50a9cb,85c19f06,5d65e507,e4e92c1a) +,S(e59b82d1,ab90344d,b113c1a7,a39968bf,e6f3b1a8,c2a44572,d9c911ea,55d70eea,91e33d8c,d58c6a1b,e4df0bc0,12eaa76f,6634d699,814b80,cc22afc8,313b91be) +,S(f994ee5f,88244cd6,bc417db7,2f941bea,f3456d2,5dacbeb3,330031b0,7371a7d0,9026f86a,ecc299b3,302bf9c0,4dae48f7,d9c2689f,42707d40,51440a05,ad9c62e2) +,S(776c4c8c,32d1fa50,27b17bc7,9803d121,8000cccd,565d95ff,c1e3a693,7800410f,40ece234,438e7738,6f8201d5,3d3e319,988b64a6,38413803,165f0bad,c8785149) +,S(393675a5,dd13b001,29caea3d,8bf25730,32c1968a,c5e02620,fb83fae5,b5c9b12e,39e6cfc4,793400ce,ed16ff4c,4b0ebcc3,2e5dc773,4e742dc0,3784a69f,a75a8b00) +,S(d7cdd294,22edc7b6,2cdde130,e90be1fc,94dcfdf2,7bf38eaa,2f09fa8c,c3401b1e,dcb9cb28,73cd18b,b74ca141,dc79eb46,728bdd9,8bf14302,db5c7065,354fb184) +,S(bce3f127,2726449e,3f620671,824949d1,9026137a,9885a1b9,9cb67dcf,6e56bc2c,a4240017,ee92dda4,be968f04,ad125ad,1c33c37d,c52a497d,296d5786,e6e76217) +,S(9df098cd,efe9414a,79adaf44,21e35faf,70080137,74399eb9,738dee97,ff5d6e52,6bf9235f,ef36943c,d0f17bb8,6917d97,f04bf4b4,dbef1baf,3b788eba,51abf15d) +,S(9958582e,e561dc4a,9a4839a8,292713a0,5d88ab4,72222522,e8dcc94d,b3d43f1d,e0958a14,b63af23e,86f76cba,2259b37a,850008b3,43b5cdc7,8cb4e88d,68c226a) +,S(3e7fb8ce,7d7b279e,7d292447,c88c048b,dda93379,5233a871,bad933c4,6dfb1f24,4279d08,34108239,2d77a5dd,906ba4be,e36352aa,9385f09d,2296ecad,648806e5) +,S(1cd05450,f7405a11,cec93ee,7826cf58,97611d69,fcb681c7,1ac0a6a3,75e8ed62,85bbc70,bb52b040,d620a3a0,20b9536e,5759d35c,9931936b,39a203b,af34d0f0) +,S(5047776,32145a3d,f6f87bd0,1b81032f,93cf99ca,fb4c5e3,c76adbf7,d7c9b367,7badf59,919c7771,89eb97ce,6c71f418,a0e67b23,884cbf7a,1ed60804,57d1d2c3) +,S(1ea912c9,49b64ba8,309b8d87,ad1498a4,79fd302b,f7f2f0be,636f7a0e,4470e6ea,9b279fdd,b1211de,8414896d,3502ae8d,4acd50e6,cf83ab4d,29086d0,42b7650) +,S(9b3fa0d3,4b00076b,cb4e0b00,95f03c4b,e1ed329b,d2f4c7ac,8c03028f,21a01628,10117a48,b2a58ef5,2e0d5dcb,cec661f,8cef81d5,50efdf41,26e9527c,27d420de) +,S(65fef7b8,1d39dc4,b3ac7f7f,5bad14c3,6200d128,d0257e22,ff678fc0,824c94eb,3021e1ee,680c4fc2,77373b9b,36ef276e,f2dcd6ec,7a02b2fe,3259af09,2708b475) +,S(3e77b23d,af763a55,644c0f2,bc2bef5b,6ef5e1bb,8fdedd46,c5a2917f,7f85f9ac,55b278e9,5bb07879,9c7f0766,a2db2c79,8d4fc785,10fd021b,415b3e4c,2a4f3221) +,S(2ac4dabf,2fec922b,c4615fba,1cd7d352,f69fbf8a,3232f783,96f8c08b,21de2965,2c33c017,76238bcf,2be6018,7f85a518,6d649425,1eff089f,a92f3eac,219f957f) +,S(febc8a20,67da04d0,855feac7,42b2cebb,748be0f1,97e31558,68d54285,4d62c66e,aee39287,3d45e63f,f9a9d583,e105a771,e3db346d,a262bbd1,a554a8d2,65d96083) +,S(a41174b4,a5982751,88c2d10b,d5c5401a,2654202,dc4e38d3,e1c8f689,8606a569,bc6b63b9,9fb5f85e,c6965337,e82b651d,6b589f2f,8d90f67e,3bd087e9,1f732a00) +,S(122196cf,5d10a3af,3bb97fc6,d12f749a,907c194d,3caf2ae9,3a3a464e,5a5de220,ccf46742,b3c1e213,544e2c7c,59423fdd,674697c5,d405b2b9,46fc6e92,9304e533) +,S(77bad5cb,104dcc7,e1bbfaa0,8c867761,9f93ec61,e8e3b73e,799b663c,2e1eadb3,889747b,ad8bdebf,48e1214d,df2522ed,4023fd8c,5ef08fea,411e8609,c6faa3cc) +,S(1e8d4075,8c49ad41,6ad45163,73327e6e,4e3f6c89,695e15d2,f5517ebb,12d4a98b,1d16ccb0,730a619,c9b379a2,ecbc4f83,98d94aa0,d4881cd1,25968160,e3b09f4) +,S(c87a656b,240241dd,487f4974,afb5b535,880ff2ac,f4a028cf,b1869fa5,fbb6ee42,16f25f3a,6fac9538,5ed74412,fa6a790d,34f694a8,b4c99cb7,6ddaff70,be757beb) +,S(96b01407,482c6e88,e9769944,cce16a05,669adf16,e7393b80,71fbd9c2,4b55a4eb,b32be280,590384f0,e08d68de,38688018,82b786e2,1b178ca4,578bfffb,94b50223) +,S(120f68b3,739562e6,81e72fb7,46d08f54,b2afd162,22e1deff,7ebbf884,6dae4af5,7c1eb74f,2b2376f9,477c6729,bd90e14d,2f4da9d,615c8743,dedc1690,300bcc78) +,S(e64871ec,2789b455,8608be2c,f248fee8,49a4411d,285c0989,b65c5dc4,e6acd157,2980b2d1,4999b0b5,5b79ecfd,45ef91fe,f3dbfae5,d02f2145,84376294,58e10a6b) +,S(608b1009,b20d3e2c,25324adf,c73e5c86,43daa1e2,53a8d266,eb43863,aa6798ad,826e5a03,ad5c9638,51181c68,ccf0e663,a021e13c,43efc38b,3b4fe2c8,8d0e13df) +,S(8c978155,8132e45f,60a61435,36f4c1a8,cdc4dc2b,6850b3e5,7c65f841,a1bb152a,ca3b3098,394d81ef,a9083c5,3864f194,1875d63d,9c31b44b,a6ed4137,db7460fc) +,S(353591a,c73b2482,f8d8e731,ce01106f,10072757,68210627,f80c8f8d,9821bf3e,2b7e3d1a,501ab469,ac6306db,2608eab,70ae8981,9f44bdf9,d4f84c7b,41eb6412) +,S(eb2dfd88,ec357372,ece70a67,178fce32,3c387b7d,a9fda978,b05dc430,9cd78857,6f2bb6ed,1f5a5521,c441a8cf,9852372e,3dd7aa7f,ca0a1f63,18c47ef1,a24b88e4) +,S(a41c0ff6,5db1050e,6998f3b0,7eef66dc,abd72ae9,8672c487,b29ff732,992eb279,56fa7b20,5616ff9d,f619d7f8,65210727,bc0786eb,2aacc244,ba951eee,99a99cd4) +,S(8e748b35,f5bb1500,ca45917e,859df11,615d85ad,861bcea9,41524e57,a2217e92,55413362,e226c6a7,84bf8604,3973bc50,825515a3,96cfe66c,9ef75e3e,fca46df8) +,S(a83f6007,cce70624,73cde2c7,b7ec7bfe,bc506c27,ccce7708,f35d535c,26dd17e5,ad48ed2d,af217e5c,63397a37,9d50d615,5a1ac614,887a2cbb,26c3b74c,626af268) +,S(f9ed7a92,7e451624,9380246e,bfd397de,5cf208dd,b47573ab,f118afed,1282d2fa,c1574616,3a6f30f7,80d5d53c,670d380f,3c84407,b4be5324,87bbb5d,c8237b70) +,S(a2bde78a,175ec7a6,7f917707,8f09f812,c7dff012,46c5255a,f0112672,6c2ea08e,7125698f,e82d4c0b,6d7d2741,9dc503f9,3b5dd62a,a5db9e20,b091323d,c9ca12ec) +,S(ca8c05c7,9dcb6736,905cc0e9,b8e1690b,6b37da42,e1875a56,e62ea231,bf9899b2,504c51ca,1e19adba,66560c1e,3fba9caa,2751259d,71389996,41d0f19f,1487534c) +,S(fc106ee,61db13ac,4137ecdd,15018278,61fd4b21,c979f97c,617b019,54eca02b,6da55a28,4fc26638,2afce9c2,cdc5a2c2,971f2cd7,5c92f08e,6bc99651,7bbef3ee) +,S(2cb21839,f47b1068,5419a321,7ac7846f,504f674b,c2f8f90b,8b9b6a71,6492a8ab,1feb332,ae75044a,f6807feb,965e2fc8,63726433,45a97af,f1081249,f00a5757) +,S(678c50ee,759c07ff,fca2963e,fba55edb,56ba3572,79970224,5d4f2132,5561f3ae,1989b787,abbf04c1,c93afce2,d389e1f9,780b1657,daa77107,c498bff4,aecba96c) +,S(ab63e1ce,aa2e34d9,8215097c,30b2f266,75d407ca,41f3dda4,1b21c910,824aa6fc,ec65be61,1150ff72,715d3da2,c4541ad6,812eb7e5,7d0f4d82,4792556a,6ce2363c) +,S(a69399ca,fad59597,5a639a2a,31264983,ec567279,b052bcc9,f5c919ae,903dd336,b525c659,c30c4f4d,a7a799dc,c93ae348,1c87304b,63491755,1c43e12e,c50d97dd) +,S(32bf4282,507bcf5e,d25cb5ed,439c82d0,bd7a48af,d3be41fb,e13753bd,c0fc5f3e,cd92017a,4336d9fd,25682f90,be347e82,6773c598,1e80033a,c20bb695,e79bff2) +,S(a1fcc983,7e720096,7203e2cc,11450716,f2fe6484,f681b2ec,5e42e9b8,eedfd862,1e16b6c3,17e8fb89,dfffa79a,722de49e,a419affd,bc17fa96,4ba6c316,31ed4fd7) +,S(d85a314e,69617e50,18df1e82,21cf738b,60485cf3,3abe8838,472b32b9,7f0ceae0,71a0ffee,e92dde66,66b4b5da,a88a79b4,fbbcbacf,3308a4e8,6e1aa367,e00a52f1) +,S(189226fa,688c70e,415b20e3,1356eac2,f5a53b5e,8043e24e,4ee03faa,f20c2e7f,d9bfd8ac,40c7d53e,7bcbe575,9987cf62,fc2bba7f,952e4eaa,1a0587de,f1515aa6) +,S(d3542e0a,6a931162,d7a674e6,32cf2135,32465d25,4d2d9241,ff70709a,559e1330,25e8f51,e2664234,34cbe5ed,622bbd83,dbd42784,4b1f2bf,9a079917,4b57c369) +,S(514d9e86,fb2cb612,1ec6e6b8,25875856,9a8c0a5a,adbfe45f,2876be18,753a2bc5,700785c0,be5423c4,341918d9,f65f79d9,1b8370bc,48629791,45ca8418,57cbf261) +,S(c9f86365,12e9ccfd,e1f1db33,5ae606ab,43f9aa62,2d723f6a,d6d684a3,ea3fe495,30d3a631,3868a01c,9c6f9445,ddcbe3b9,b7b80b58,f31f5db3,a3b3beb2,1e30270b) +,S(226f20c,8fc089fe,98cd96f,a0e790db,641200a7,2b908768,357d206f,2c2deb93,2e23fbb8,b43e9362,3fc2045,24b43da9,5e02626f,ee180cff,1c03b95a,aa5f66bc) +,S(a1b27668,d4b6f94c,7219bd9e,6b8a7e61,9fcc79fd,88d9bda0,a38496b6,cb5350bd,3933fc5e,b6e1c16a,e7aa62bc,200fd5ed,c96b5f74,b72b9b94,2644f32d,d6d68a32) +,S(10f13657,87bc31,1f7b7181,808eb0b,57dd4e7c,1590dae3,8c40df7e,afe28887,1a52e487,9bdc3ec,4e6c570d,91d4edce,291338b4,a79a3995,db5c6e85,e3366d84) +,S(8aaa0ee,a984f583,f9f55861,500dc5ec,f613b3d8,8f989884,273e1841,cdbe3e46,52962154,f85277d,c02c46ab,c2f246ed,24e56458,156d97b8,f2197d22,a133260d) +,S(32805a71,24b1b7,9b397ce5,f7a93a98,dc9472ef,a5b8b4aa,3bd66643,f1c89d2e,af525c7c,b7c139f5,cd2d0a85,82a74ed6,9e23c765,c0b882a2,f4d50e58,843091fd) +,S(c72f10cc,909ad449,7fb0835a,4f3a520d,58db0c2,87f6ab12,cde50749,a9412451,a5666e7d,5197ba9e,37d5ff15,b64b60f3,b8e2ca32,67467030,a7a112d6,f2c7c65a) +,S(6ec768c7,870211b2,415a74ad,c203bd41,72c0fa5a,d4c05f97,c0320865,77fc9a22,18394a22,aa2dbb0,925e6710,549c8c3,b51cbf42,db67d4d0,5da260ce,af1b09fb) +,S(de36ebbb,ff99d156,60506143,87045fc9,a846e7d0,eef91e61,dc93a71c,3ca64737,c5817652,f3cb37b,40647dcd,a476c4e0,488208ba,1b4d0c81,b39a4b4e,900f4270) +,S(f534155d,5538fc68,5ac01ef8,6dea6f4c,19bea322,b46a297b,c0c20ab7,3cc00218,4fab7df2,979d98ca,eeeb38a4,9a2d1253,f9d0924f,14dda603,d3d5706,b3b9523c) +,S(dafdb850,a1db9025,80ecb98,155b687c,8db2088,d0dab521,bc7fcc1,3286129d,43965ffc,ae6c4c14,3febe601,f36fbbd2,7d0ccc50,60ffe91a,a2ef2fef,651ada22) +,S(ac9a0a21,1dcabc85,1816893e,e33cc69e,2efe4069,680b3721,2999f9f4,99d705ce,16ebfe40,8281d2bd,ffa1e02c,2d00d712,acf64eb1,39f5ba88,79c3971b,98c728ef) +,S(afb37bd4,b48cf6e9,5e1eb8b9,7b8b69fd,31ae2b2f,3b7aceb,1db81ebe,98503030,1ccf4164,f8d9cdd9,6f231af3,e5fa313d,c47c06de,ce44dd84,d3fcdb16,a4b7929) +,S(1b902ef,6c294f83,3ab18e7f,21d6470c,f553682d,2b1287d5,1a602925,3888e709,7735c5ff,34e49fe7,2385e9fe,40d66a4c,66ca0102,46c724aa,24b1ecee,dcd69ebe) +,S(6e4e5b10,8a202958,7c5b4ec3,d33220fc,c61b41c5,8c3bf0b2,55e4e28b,7c3133e2,b49f8306,5c336af4,469ea410,648915a4,b55ae504,6cea2f66,f14a99d,9a8fcfbe) +,S(87ce3f7f,bb800210,5b853276,d3931b9,12342d98,7d81e80b,5b10d1ab,1b7e9714,56c6a847,79dbf39c,293c386,9c1e3385,6b71f898,dd46ee16,d1e1973a,4cf0f635) +,S(8724329b,b7ba649c,9c019372,45a1e946,d368a706,2747dd0c,9f6667aa,c9426b2d,44458e8,48d7d44b,5dba5a5b,b0fa0479,55b109d5,21d170d8,9d090ff9,650b944c) +,S(b91befa6,4735c091,32db18b6,b64d7d7f,c6338dcc,cec845cd,7d297f62,b6a1a4bc,bb3961ef,8c9b79c6,867f16cf,be4766a0,15e7ca0c,8f9f340b,14cf701d,e0138467) +,S(4321ea59,332e97ea,3bcfbb89,68a3489c,9ae3d6b8,65cd696c,d8de3200,a0d08fb3,97e480d4,c5149d53,d7582e3f,c73a35ea,3f6b023,5ce50f7e,e31cb600,84cd538e) +,S(dc4597b2,836d96a6,431051d2,5a98d421,7950a8d5,e88c2069,5752ca6,f6f1bc6d,c712580d,16ba30ca,e84e3a83,c35725ab,362bb4fd,e4c42ad7,f9b73f20,53df36ff) +,S(ce644ef0,85ff3009,b261750,8de007bb,c5f19b65,2d9f8992,9972d39c,159a009,9a41d0,58db965,baa00c92,f6409ab0,c9402a69,20a66c17,c089906c,d73cc8f7) +,S(ba1e35c,b6c7b4ba,b81aecf4,23cb8ef2,2ec439c2,584682b4,a7444e01,9936b41a,f3b3c652,f91dde46,3e178d6f,7b17a8e4,1098b33,1cead28a,d2fce694,35bd6272) +,S(b9f98ea0,2a331bbf,60fc839f,845d8f43,6988c747,1902d14d,72ed1360,86e3920f,9fb2501,a7f23a16,cc726f5e,8aa17c12,35d9b04f,a94bb27d,318fb292,c60d03d3) +,S(70591746,55f90f81,c478e702,ffcff930,dc10dbf1,16d7aed0,9c1a369e,807e886f,8267a0a4,b9d6f0ca,db1ec92,560aa3f7,d09d3f41,d1f36f8c,64b95509,b205a59f) +,S(efda78bc,c43ca063,a7b6469f,84012161,14cc5a6e,4e31c31e,b76221ac,c25434bf,7b436ff6,ef45f859,f521b13,53193d13,4cdf8064,449af2aa,92be3781,56fa2864) +,S(229a4b0f,5d62095e,3a630988,c8056aeb,35fbd874,1a2f0e,4306d094,750ccc34,170d33af,491c74e3,d2d694ce,f6a519bc,741acf35,dc6a3428,8bea3595,e234de6e) +,S(c770f48e,20a02132,189d44b8,3acd0f93,f91860b4,81a6bf17,8ce8e2ec,6af07100,7e1120d3,8b2a191f,9ed43aca,3325beae,a6d8dbbf,7e0bf8c9,610f8621,c0266eec) +,S(a5db2c63,3901d52,8b60a48a,20b189a9,e89b8998,3d424af8,eb74869a,f286aa44,b9961d92,6a93d5b0,1a74e6ab,d9c37eed,384e186,8051ba14,46fe1a37,24af1e50) +,S(3ec7169e,9f330288,a63897b7,c168db9a,4b447e48,cea2c5ff,77b298,da41db1c,c3fe974d,e8e60eda,22c4aa34,ed34a4d6,4b3be268,12e58b49,e4477835,f3053fb2) +,S(b733de17,c3311184,d5860d4c,f99e48eb,810cff93,ce92eb77,7cf2c114,fb5bf3b3,c75c0dd,72d20ad3,2000d537,ebb61571,57fc4ace,9f26a90a,d28e1a43,480c11b0) +,S(57d6e208,d555bc24,15d49616,a158075c,27db59e,6a821df2,8b450161,6c2ed278,83870a79,d130da5a,3528e353,353b34f6,74b5d02e,6cf2a891,fca34c6c,3746eba8) +,S(9e4234f1,aa69a478,3bf2fd3c,3208f6f2,6f069409,fdb2faab,8d792588,6ad3673d,5f9a4773,7725ebc3,e8bed041,47a05841,9fb42b16,affec29b,d753733e,288d0653) +,S(6fe3ff9d,9fc12ffd,bd896202,fd8ae913,22e4fcf2,76068a75,8d43f1f3,9ab68173,ef0d5682,1d414608,273ef7b5,9208c59,bf94e16,3e7faa3c,2ab3da22,b509fa1b) +,S(2c31e54f,d2586e19,efaaf415,e54cb499,54c49257,d11b161f,ff2aae5b,b45c4631,bedfb0ad,364ab1ac,e7f53c0e,9fb825e4,39af354,1a70708b,d8e0e423,13311346) +,S(51597259,23148c3,478ea2ee,2b933858,4d745b89,49c2f782,3b8660e7,78203ebc,329f6153,f688b743,c4fdc470,25790503,b81ff7ce,5a613362,8a59f3bf,66aa1817) +,S(188b3324,58f7d7b8,dc3fcb3b,df51ccfa,d394684,cde37d60,70d41e46,cdcaf1f4,4dea5da,d112a117,31a6b04c,8999c6a8,3d1ddec2,88aaf104,487656a4,d3901910) +,S(92058e41,a503e158,8ceb0a49,4e13e2a8,85f804cf,7f13c90e,307372d5,cfa6e471,368072d4,449e685e,17e5a230,e2177e95,bcbe177a,58cd1510,68e7255d,84ec108a) +,S(6a6f5226,44e06506,f27a7a68,96eac537,726f79e8,9e83105d,5b647883,34099fcf,cf3edd4b,d8ced83e,b167b664,574987f4,7104e79a,5a4b5321,4c19a32d,a5132586) +,S(7e37cea2,340cdcc3,ca21e0ef,ad548f37,c77c3402,34f0148d,89cf926f,2376bb26,c72d829b,42a27c6a,b062938e,5cbc22a,6b02d42b,d31cb69e,83b9fe9a,cc9a0016) +,S(1e6c2069,cf0f6cf7,bafb4b39,bc97a8dc,800d010c,52c3cc5a,d848fb82,d8d0b667,c181e76,bca1d846,86ecfbdc,2cb09140,49146986,630b7e81,f86c7238,8e60196f) +,S(5566600f,e6eea4f7,b06336c8,d44b47ea,f36ba43c,ca404be3,5203ef5b,6f07e16,6bbbd08f,7adc1979,ed4acb4c,f372eda,69e5ac16,7695a78b,5a7fe1ce,1057e55) +,S(435c634d,ed451c5c,21c5adc,45d94f8c,69045016,d529ba76,19ad07d9,31c791b5,31ede268,8252a50f,2206f959,1953c0ca,85009876,2b6f6c14,24b4e47,c74d4cc1) +,S(6fb8cce6,a66071c7,395c0612,252a414d,f19a0d2a,f855e7e9,dd142342,9c57b9b6,17f94249,e2f05314,d4799fad,68232626,183dadee,abfe34c5,b845d89f,2768e052) +,S(866f3e99,20fc4c94,9496a695,f54ee634,11c711a2,99e05890,148de8c3,2980dc36,e99c55af,4f8dc3c1,d38a11e1,3c00db2d,f5211f02,e837909b,ae188786,d18d62f7) +,S(80c13410,b7164899,a724f723,4dcbe505,62404f0b,7c027c79,4616f618,80468b2d,8631942e,71a01e4f,d7b59281,9dc69d39,bd6e8fe1,c2c41621,6d8df895,280b91aa) +,S(8f85bdee,ef4e9d88,53e68be,c17bb6ec,bf37abc0,a4ba44d2,c3815dc1,82a7da99,36d45bdf,8ae9342c,af0f8ce7,8aa591a3,4e8c295e,49ee6962,b4a9fb7e,ee17897e) +,S(9cd0b2b,3393cda6,ccedaf4,ee8a1b3,17a920e4,826da2aa,4404a01a,49600749,3831d35a,51d9650b,b1901e34,8f0c4ea2,3a00c492,a4960463,414e5dee,aafc5a5a) +,S(a0c5f1af,15c67ffd,6cf832f7,974c779a,3ab7ca,dffa32d3,bdbe0377,d49f33b0,6aff40d4,42de6262,41734412,3620c5ff,3079392b,b8843c57,80029682,1cb91ec) +,S(af396f40,13e217,d7e1fbf0,2ec4039e,c0111370,37cb2d78,90a82313,58edfacc,aaaeb9e2,5a57534a,2dc35d16,705f0e5d,6754c599,e85864bc,936e94f5,9acfb936) +,S(fdac3c57,e3e0ecc5,e7e871b0,dbe35979,87d4c071,f2f89307,cf1e71c4,91ed0eaf,3028a0cc,a22ef096,73c877af,ccfe36d6,b14d14ff,5da10b18,cdee6068,3ca09fc7) +,S(e3aeb123,9587baa9,ae12b6a9,68efaedc,ae745fd6,aac5103e,14a471d9,eefa88b7,7ed1c786,52c1544b,e306833f,bb27d1a5,7b460305,a2c8f6cd,2d33397b,caf769c7) +,S(96baede3,382a0162,fb4cc663,c91acb94,eb83d7a,3e3e0a0e,6055a50c,d78352f5,78722e97,b3ad2824,388c3a80,fb930089,5100d61,ea58f997,2adae059,f0c50cbc) +,S(68704956,16975637,f35e1eda,4db546fe,ba93d122,446a3e40,8de04ee2,3bf5f5b5,6247d2fe,b5f7471f,3a06c7a2,4c4261a,934bd226,772405ff,46e361bc,614ca494) +,S(71ccc634,2ca1f858,8ae02d72,eb0dd2b3,62eaf652,f83edad7,94095e09,f4bcf749,487aebd9,23b10e69,4a8e3f22,2703e5a1,aee17794,42a96c68,6cb9f983,dd2a45fb) +,S(6fda1dd0,65739a2e,58cd183,1e8b6109,713844ba,f249cdff,25d0b3ec,f635d3f0,a2ee44f4,8afccb72,4f8a96c3,2a88a8b0,a232a93d,553713df,60a965f5,2078108e) +,S(d3f27709,ff5ad97b,45e395c1,39947115,65cbfcf5,838e7b64,b1016cc6,d5147f45,f96cac16,cdc8e1c3,54e026ed,29bbd6c7,29006ee1,51d9d61a,4391567,93265077) +,S(27ba1944,a28a6eff,78a7d064,bb8292c6,68f82793,8e2be786,41ee366e,a4a011d6,24bef875,9d216430,e7312fc9,458f0571,fcbe305d,574694d0,a77f7a98,4e7bdcab) +,S(fd37b812,5fd87ce0,82fca9ff,7872e0e9,772f4c44,1870748e,e35e7d00,944fe190,9450a525,d9ae198d,db9b8c43,fb337df2,8ec68a44,60106951,1847b9a0,27dcb453) +,S(d9967cca,92583e0d,8d329b63,f32a8017,4467518a,595d8b80,2c24cc8a,8e071c69,6aca3673,c2c39d69,3bc86dbb,92e5af27,28361cd3,2179eab9,7ed64ae9,73376c25) +,S(8ee82d3c,4a8d01eb,d22798ef,bfd95c16,f53cd45f,e3d044f,3d89ed40,b94a0a3c,e0b0ab7e,9167fb9d,aa71c3a,fd5b9c0b,79c8b6a0,db3ae2f0,36c626c7,791e1b2d) +,S(461ec3d2,817cb549,a9fea029,15029707,8d709ccd,bf22da47,64c8a1db,c562caa,661b2d7d,cb5c9790,510f6e12,61650401,26cdf80d,b086259a,db16af47,af6684af) +,S(3155885c,935caed,469bb7ff,b53ff6b8,59f51780,f3de5890,673101bd,41f5793e,603594e9,92ac108f,8d0bbdfe,8f3576e,8ca6ac2,69c7581e,28d434ce,2043dfff) +,S(5cac93b0,ad9199c1,906267a0,ad8874e4,c68a60a2,b9fb6f0d,cad42758,2a4ea9eb,836faa98,a116dab9,69961fe7,ad7483eb,c48e7295,37e6634a,e423b99,880032ab) +,S(1fb6d3ac,afd5ef56,8b6eea1c,4a8f0179,54d05274,24487904,7e3ec56c,6956cc42,b8ef91f2,f89e4f32,6df6a1ec,50c6362,7431be48,1183c839,3133dafd,2e2a5411) +,S(89c0b1e1,52f0005d,a30618f0,3fdee7b3,69fe0157,f7bb2bdc,d31fc773,d82b28f2,61d6e357,bbf46816,acd05de5,b26c67b5,ad8223d8,ac9f47a9,25477ab1,80b4a507) +,S(7c5d18b,1f9d1afc,d663875a,34193240,7cb968be,f31d751,807ab1b,b79a211e,45fbe7ea,985bda0f,bd23b449,5d4e945f,d136b5b1,296c9b3b,6dcb9c37,bc779ff3) +,S(c827cfc1,9393108c,9b31ad4d,b5eb7f00,b6afdad3,a5e2f792,ddf9dd13,f159f85c,5c5fe07a,3025d401,54fe12fc,89951e2c,330ea3d,d6335a12,9c31aaa6,753a1cb1) +,S(6347b32b,b1f3f7dc,205e2fa4,6b201b4,2e0dfa80,550741e6,57117875,57cc5d9b,f8f30e10,9508d34c,a48d7255,3f8ac26d,a455d3f3,b170ee52,e22be1a3,ae8c3ba4) +,S(d489f595,e822101d,5f6e4283,7db032ae,bfa21f3a,94998130,e0a1d226,67ae1014,8b112e89,8dc4a146,8f64c33d,1261f8c9,2bfa98df,eb9500c2,2b4a66d9,227c66a9) +,S(90cb9c63,fb4afbce,adeb8f98,1e76a645,2200d73,d43bc0b2,76f058dc,b8a6205b,894afdc0,f6ba7f1a,bbaf19c6,720471d8,2611a77b,5bf6c87b,a02324ce,52e74645) +,S(40df68bb,19f121f4,e566a1be,f0a98954,869bb06c,699e818b,bc49a795,6a196af4,70d41c09,d0cedf7c,31c9f830,3610f6b6,e1d6b3d2,a431e69d,a31bdd63,220cec90) +,S(4936fd74,a0ac5045,91c962b6,431f17fc,a888dd1e,b35549d7,8b41143a,83da41bf,33a8e1dd,6517853e,d7c68af8,5b3f1cf5,3fc5b72b,5dd0f392,c5ab5ff2,1bff4f92) +,S(17177538,811075b8,f5baad59,2958074b,c1a0c6e7,b2a3f594,288e82b0,da023557,583d4814,efd8742c,5e7a0c5f,734da121,b163fe28,239a8775,4bbb072,c1b10837) +,S(a126b7fb,ad5145ea,b414c82d,8f21f208,6abb118f,3692bab,586770cf,4f8926a2,79b4ac17,b601b4d2,1a2bfdb7,41f7fec2,88d46594,699e4394,452cb2d1,ae2ec669) +,S(51eccf61,f8840048,d55de51,2d865a52,3485db8d,869844fd,ba30e703,ae871163,594ad253,97bdc9f0,82c0c46a,200ea090,12b2c6a9,57a53dce,e87caed3,2ea8d50f) +,S(97781633,6f1b7131,f55966cc,a79d25af,d8984438,8b516882,5105ba3b,52b3c7a9,f1df3541,b4b08fe0,cdda20e0,a5275eb6,105011ee,f4355516,e47e89d9,3b214c60) +,S(8bc2c43a,72248dab,5c78cf6d,b1a35ce8,64231d3a,870bbf01,cdb79be0,2c93f7fe,d52e2e76,173e9dbf,9e8106a,ffbb9d7b,b428f07,80269b2e,f49bbe0e,14cbb425) +,S(59ed7881,6c7ca119,ca4abd03,34b90b37,6c327175,e899e0d9,79953e50,5aef9f2,239fc027,690c0feb,e4db46a2,8669e0da,20779425,34bc6133,152a606a,16449910) +,S(bec399d1,76714995,d4192390,72a39c59,c8ff8e9a,2cab6520,ca0cf6b,2fc70fda,ffc4bdef,7831208d,23a1ab9a,de52f346,a21a2f7c,efc5ffbf,70999bfd,ad0ba8e7) +,S(93bd25ee,f4cef1db,fa5f9951,7d22a77d,9e3b87db,58c63076,68a35885,9e0c4d34,dd7d1412,97361b84,9a43b1f9,4f89970d,fa008c63,3404860,794e6a87,6735b4dc) +,S(b203a657,fb4e4d51,158b2e70,87455a57,44e553c5,bdea4f8e,3e8e6c92,eddcf58,98246948,c63e182,61f0d4c7,543fba7b,c74ae5a7,a19afa6a,ac80359,5ed8c99c) +,S(af38b53c,1dcd27b5,8118a28d,11da8aaa,3e20ac21,4cff64e7,be683dd,80f6aa69,91e38936,ba8b2b42,34686723,7a3fac67,5ec10179,18f8ac16,acdc32f9,c09fd919) +,S(55e4da5b,b99d805,e2058756,20ab4cee,988ed472,f5e6d86,2f8c574f,6bfd8518,7368be34,75179d32,e15b5976,c34c366e,e7713b25,8f179309,40b16117,aceb2d35) +,S(d3d7e82a,a7ebe240,83e1a15e,1d817d91,a3608c6d,d25a35d9,183a0c9,e42133f5,a5245cc,e89537c6,895080b0,6c5e2772,4b1c6d69,6c1bfbfc,ae6a7d4f,fc5d504b) +,S(8bd14f9f,e6b54437,9761e803,1dcc9907,beab754b,68c6c3f2,2316e5a6,6ee48799,f89dc150,a3876257,51663a26,35633868,ecb2eb27,d9ae8603,89110aff,6978fe19) +,S(b1d72365,3f50f42,cfeb0858,972a5a22,3a7dbc5b,4823704,85c88fd2,22212932,40597dd8,594ee1f9,b74aa52d,385b21dd,6279864e,7d0255,70bf3716,c02143ac) +,S(44d303e1,cb7d920c,93be4763,e045cef5,c22d4403,5e1d3a8,593f4f72,679d3023,79fbdefc,5ed6da2f,31bd6fcc,83e3cee3,e77e41a9,a01b2004,76912c61,5d89a70c) +,S(1655ec54,447aaae9,727bd4b9,60eb996,92558999,83d4aed,3dfeba12,3b0cb3ca,8e90e578,cf96e31e,988f7bf8,a9f06d94,6ea28fa6,b1dad744,3b9ece50,6626fcdf) +,S(b02ae3fb,530566bf,66da9326,18990e6e,7902b104,800cacb1,9717bb7d,845a3f29,c6d32713,f4483031,19bb7631,1b397427,d8c05232,92a61051,62a0307d,7b006876) +,S(13c46566,53a0042b,8755e140,2b12b9ad,8e123699,a153ec6e,65e49cd,10c5bcd3,70f3672c,498f603e,3c521ea4,3ac3e10,7bab13a8,a78b02b0,4492c51,6d41c88) +,S(e7c7562b,3fc37b8,2e9c7bff,c5e97b39,dee483f,141df4c6,361eda3c,4f1483f,734be460,3d2b4958,c1bdce51,57a16d0e,1a937298,1dbb2833,1b12f8e6,c3454066) +,S(de025d2d,fb6cfc75,342b2ed1,ebc7b27f,332f3921,c304b8d2,263d7fba,2959aefc,46c609b1,6ab6f3d0,2dafc30c,38373a30,1a88c31d,80694598,5e676f1c,16de12f1) +,S(21e788b4,fed21c3d,25ddb714,abaf053a,25730af4,83817e4b,6a42c323,3eca2e01,1fe716bd,a7d07592,b66af9b8,32335b9d,b249b1f9,cd413c58,ddd29fda,e5c1c4c6) +,S(a7db27ca,7481d50b,1a458242,c75b28e6,d1bc1a9d,da97e012,e39cff10,7b79edce,c4f8686d,cabde6c1,d3455fc1,795a7cc4,84239d2,3b11e238,85136183,71ae73f8) +,S(c5205173,2790f240,e2161627,5ac894cd,e80a7d3e,bd5bdccf,41af64b6,5e2d477a,e9aa295b,209410a0,f0e8e216,deadc3f8,af87700a,40543cda,463beac9,f62ba20b) +,S(487bf4ad,99d1daeb,f1c25f86,d36ebcd9,38e91eea,8b855d05,ea9371c4,9572846d,81293837,ac6ded0b,ee04b2a5,4c18ae0,32f72970,86de0ffe,791a9576,fcfebf70) +,S(bd6dd2a6,bfcf688b,84fe2d55,e56025d,35567574,20edfcb1,3cd14483,e08cb53,c86a45e1,84c83806,38ea1501,c2851598,c467d2c,d1c51a1a,1b037324,d9ab0fca) +,S(94a417fd,fbf188e4,1334fbb6,906731e8,70dbca18,672bece7,936a4c7c,235ec737,e03c6607,343ec14b,81eaf124,bcfb7d97,564e9f93,546f9765,299a443,d9be8e34) +,S(2a57dac3,3fa13b26,a96d9b73,317a23c0,2ac597d3,3968fa8,ebd88d94,66aba51e,1754a6bf,1db7b3b8,b0a7996e,545f34fd,3b05bfd9,805b50c4,42db2937,e8c13b61) +,S(ba2e4a71,6142a39,67c613e9,93083c32,d1c66da1,2c3f9742,eae90b7f,ec7e7df7,c262f8c1,a704e83b,ed7fc60c,5adec65e,ccc6de35,8247cc97,1da7acfe,834cb07e) +,S(4ae19743,b3132512,d28a12b1,1fbbd824,8bb0b9a,730d5a8,a862ea8,ecc01ca9,67b7267d,48fa3ea1,d1c1ec7c,a6a8ba0,cb27883c,3f9d4193,20b4c8f7,a017eece) +,S(4cfb26c,81823667,f18e6ff9,d77493f0,778b9bf,411b63ad,61850ea7,7706ddcb,10df8a3e,3a8c93df,4d7af16,407c3211,aa6c6079,c397a0c7,78e1e277,24e4028e) +,S(9f9e4566,a014b66f,fbc3ef,b3c05062,15f06102,6f7d6561,934d3db9,5d130349,492b8ba2,76d526bb,98fd0c17,c5a0aa7a,ab6e5c9c,ccfc95fb,a417d25,9396c592) +,S(e36c0513,3641b560,b0f9f4c1,1159e2f,ecf2a194,b55f3bd2,22ecf1f6,ac239301,c7fd74ba,48e7fc40,6322aea8,e9f83a82,20e9a113,ac2b0c7f,aa05a5bd,bb43736c) +,S(91b013b3,b94d4568,78737580,bf1da11a,a0bbe0a4,e3ec65e0,33e9f824,d8480bbf,15e3707e,c13a2529,22a6f824,7e33d172,948790ac,3d367f00,6472f22b,e8cfc5b4) +,S(254d1788,8c676d52,236782de,2d539f2c,41f667a,d75d0107,7d43f723,ea324f56,f7042d2e,93511e5d,13f4aa03,bb2dbf27,9bec3df,97974275,5fd25133,c814094a) +,S(452d6b7e,ce7d0f71,2afabe44,2a22f16e,34fce662,99697f0b,6135678,56f4079a,21ea8ba1,28cffe76,3400d69f,ce13204a,9a39ee59,14132d23,db3315a4,7f776998) +,S(1580b9d0,7888f41,81b86b85,5b1982d2,81783185,5f28c163,1f151479,cc4c508b,4d9d1e9c,78b3d9dd,73bcbbe8,778c1b7f,65b69faa,f6576dc3,ecdd00f5,c1d689ff) +,S(79dda23f,c31694c9,16d1470c,2cf25a02,45a5aa7e,d084af45,c43960a,a2fc2700,7c7bc169,a58b8d8c,c4b74e0f,377031ce,d7158c21,a156fc03,c34f25a3,a95bc978) +,S(866da7a9,bf80cdc2,13e500af,b5f4aa0e,419b4905,44653b5,fe2daee1,4149dbe6,626d38b3,b45d57aa,6867e8ad,c8abc49a,81a282c,6bc6524b,239819ab,766bd3d7) +,S(432bc912,bed271e9,321624cf,c6062b96,cdb502ca,f990522e,1024b80b,9411d374,e645449e,dd7c4d41,41e0cc5a,cc5d45df,4cb341c2,baebb605,bcdce6a3,e411cf01) +,S(ac3d3b28,83ec385a,15297086,525d937b,717f5ad,83a5be4,77b3ec9f,6410518e,d126eefc,c9ed7e75,c10d01b2,c0e790e7,3dde58f9,54185a12,5fcc7268,84b9b8db) +,S(4570834b,2a82385d,6db696d9,56ae2667,fa18b262,960d064a,5c13da43,abd6aa37,1e9d6083,b249bf88,7ba2eb59,a9597e7,d9d15c64,ad6404e1,21a486b0,61236f28) +,S(88e9a6a0,ffaae05b,7c29bf79,2163c0aa,b224b051,36aeffd3,341355d4,b983ef15,ed382a2d,fa2f63ea,dc4ef5e2,579abafc,fe457475,d1ae8413,99969324,718d1e5a) +,S(16810eb4,de3327c6,a505663d,cad7f618,b397033b,d6c9748c,4fd8748,2adff706,352ebd8,91326c9d,2159e84c,40dc29ae,30693b7e,5a9ed119,1fbc2cf,ee60c81b) +,S(d7d03a92,95064981,1cdc6503,588d157c,88c861d9,43fa9cab,e2e3301c,994adf7b,8c820bfe,933c2c05,1ca3042d,5ce781e6,ef419c8f,d9aa83ef,2a915e36,382f9627) +,S(5b2c9504,f645ac90,24e25c4a,e880ce7b,f33aed77,e45518d9,1c6f2652,ddcf11b0,500b37bc,c7764f32,11d681e5,e8f2a407,440e1da2,4eaec354,fc289c76,29296449) +,S(d18e26ed,d2c78bbc,16982675,9d59eec3,bab1a64d,f579dc2d,6284add4,8cfbd761,1a1e0172,37a3e78,8fd8989a,a5bb6944,685915da,1392e1a4,4a6c7ef5,7d0770c3) +,S(5f6b1416,9bbc4795,8ca21e88,df252546,dc9e46bf,85d64772,24f34ce2,8e58222d,3a8e7616,4d5a0501,947ca0bf,163e64bb,3a57918d,e383c600,e02aadaf,4b7fd6a6) +,S(d7a625e8,dcc8b456,69802023,8fe85691,ec2e050a,25421373,39bdbc8a,f762bc7,8f1f9935,a8ce2607,abd7bcbc,fec1fd8c,208683a7,10000806,20d50b4d,36ea3643) +,S(a56a5419,72aea4f7,15dc891b,3a1b34ea,7ffb42c9,5e02a771,6bac663e,8d5913f9,47b3dfcd,ad785671,180f7bbf,a7f5d144,59b44023,640e3897,1e999a90,6bc3f994) +,S(1ebb89d7,e574cbd1,37b1a3cd,4a306b44,30325db3,361b7c3a,d93116fa,baade31e,2039c52f,bd30c84b,4983d118,5422a342,ee020c33,49357e6c,b9550075,38da4dc7) +,S(b5728208,931a6575,4b5cd1a4,a798ec27,e189effa,3ee4f0c5,ad493a88,b49706fe,aba785e7,2da3d301,cb29a612,562078bf,358f680a,317836c2,14ddf7d1,bede9ee) +,S(56661670,d67b7c77,202a00de,effc1ef6,f5162a97,47afca8a,a2457c85,85a775c9,adaf08e1,83bc5107,4c55122,e549d3c1,4de8a893,39f199b2,ea044a25,4d8803f6) +,S(18ab56e1,ecc86b69,77104243,35737b51,c18521d1,b170a3e9,3fd068f0,ddf2704d,cc694c3f,43bfba9b,20c9572c,acb30563,df74f07e,ce1ff9ff,46b8259e,8119e94a) +,S(bc12a874,48270360,1575b754,bf5f50f,6e945185,2e0f27c3,c1aa0f1b,ce0ac357,9c6ce76b,ac175ce1,d667783c,7204ace4,abe12d56,62ff36f9,5de017c6,f1ada1e9) +,S(a4494c26,99b2da0d,6edbdd6c,353eca75,75666796,5ddbe457,2c27ac46,79054584,589804d5,8360a9e7,d3e2a914,61d5b1ba,e8f0cf69,3b8add03,5545386d,5082d621) +,S(1ff846f9,6d0e4e7e,be34de77,d036a027,f1baf9e2,ea3dc9c7,8284ac9c,ce3aea6e,8a0a336b,9f0e3560,31f5d1a8,d4c0b68f,27ba3eef,a52dc974,8d03e12d,653f2e6a) +,S(33181aae,91573ddc,728839e0,4173f716,6862d724,35744099,ffa8f1f2,9510b374,1252129a,8cc8ce4c,1ddaaa0a,4c34c4a5,f01ee26b,3e1a9fed,ad0e7c9f,bdc5223e) +,S(e687832d,fb0e44ae,f7649b15,77274a94,64426406,fe4c6ae5,7028c9e5,78012594,5e5b3897,6b734b7,b65caec8,c77ffb7f,c5de4f98,eecab002,8cac0c4a,a513b7c0) +,S(354bbec3,ed9371ac,58174b5e,2a18c76c,c22951,df4c6aa5,755c72f3,94b37def,40d0c876,9283416d,b3613ac7,37401e3f,3c2f4def,bbaba44b,5c2a83fc,c614c29a) +,S(fa46ac6c,5205b81f,3c9e8aa6,8b5ebef2,a8bc68bf,fa2f4511,ae36f726,7439a485,3853f9fa,b016d2a8,1cde37b,13f91185,f25657a,765fbb35,c1b4d52e,3f67d180) +,S(426f86b7,33255f8e,1e85263c,923fb86e,56a53d77,945f6688,5627ed43,3024328c,92ec0168,5301c89d,5b13c4c4,57b22215,658c6341,6aff9148,6a2efbcd,4e8c4fdf) +,S(5c8d1c9b,f9a72d5b,e15d3f4d,17d48cf1,7685dfec,b5ae1ede,b47b6e58,80bc64e3,6205550e,286c8150,6638a3c7,c20f0dec,b6a26b53,641d2dc4,e18d0f7d,29bda7e5) +,S(3a021dbc,7bf7501f,ddc31356,26a9cb01,be673373,fa663c80,271be570,e683422f,64a89c54,ddadf89,784e508a,d056492a,a7a71b82,485fcfff,54c7b0de,4c1bfa53) +,S(8d82aa49,1d719f00,75d2dd9,11d642da,7c0062c3,2296726f,a504af27,23ba47bb,6e616f50,6d1478f6,988ed10d,6c6d3c50,7c2ae8fd,4760e699,1ff5c62c,53e4e77a) +,S(6feee988,fe488e1a,6ed5d60e,fcac1b3d,bbe5451,6e7aad76,f27f08e5,3c5e536f,ee9f95,839fba96,ba26d848,425b68a0,73dcee61,35e04eef,f482998c,b044c502) +,S(36240979,bafd0d57,72fcadc7,314093c6,3063880a,e895ce5d,2df3e59c,ae16fa1b,619d0376,58ef3d85,a7afe326,77d832cb,eb20820c,157836ca,65f17c61,c84afa48) +,S(4c2b8847,4da56053,c2046fc3,26e81704,b78494c,91877407,9984a3,cf6a18f4,459a9e69,17a4d711,61ca0b43,85c5a823,734286e3,d0cab398,dda1fe21,3b28142c) +,S(f921c9fd,b33211ba,a7f4eb5b,15044c34,d6e54f50,af7b85ad,84e12fba,b1478ac2,38cda9b8,c850483e,48c6b16a,5f7f624d,e31faec3,5cd594f9,3171490f,ae016973) +,S(a57769e6,6181d68f,8f86c8a7,da3fdb4e,850ae07d,f41e78b8,ca42c6b2,1b19b257,212a987e,644bc42b,f757e00d,54d50ba5,1dcd6698,280f8eb3,8829dafc,527cfc6c) +,S(95a78104,37abecad,888c9195,23c9b16b,375a2714,fed74639,1ea949a,c7c11d9f,eae320aa,227b056b,242723df,1f11a494,ec642876,91a22748,9e1ecb2,a2cfdf78) +,S(76a7e034,f7ef3e14,2ada9a64,ce984008,9f034a5d,8584a0e5,d10d40f4,29cfa42a,999dc0e4,9633eb3c,2a4ec931,9bc2eedc,9f2e4996,522a2404,79c9468b,668effa2) +,S(eba89396,47567805,1cddf92,9db7d82d,427010cd,5e94247d,f4e8cd1e,eb5881d6,b92ae1f1,c0885214,3f37d8be,616cc5d6,aebe0f8a,8da4a6a5,d4a69b5,dbbca552) +,S(a53a48d8,59fe156,6b14f872,aaed4735,dc0b7589,713ce8ad,dd3f3e1d,6e23704f,9e738da0,7e85a3a8,3d89403f,3ee7d564,4f463418,676cea0d,2528b515,39387fb6) +,S(8326590b,dba5f8a3,8e39b148,105063a7,c831cdf9,98288fb5,95b4fd5e,a707d3bc,a02cf88,a2a1dd25,2d00d62e,cfa4130f,61b7d4f,297e6b06,cb4661b2,bf768982) +,S(6a492194,ba8c10bf,e31714a2,17a74b2f,b0c35a2c,95c54af,7f5ac6df,17916030,3cf0bd65,8e0c937a,92ee8b4f,b4fc3289,c531cd00,6febd45d,b6b6c522,f8c77b87) +,S(b4ac71c6,ff797eed,61d80c49,46ba221d,3b34bf13,7e3d4747,4b6c3068,33c52a57,46acb2e4,8fb6fefc,ef3d2343,4624e0d6,14ae3b60,df813683,90503506,d52820f7) +,S(8b11711e,65bc29e1,16bf05b4,e557b211,13b19b93,a1c1ef9b,49a19316,c286e0bc,79c4a0cf,cf383538,21ad695e,5b4eae58,faa6bcf5,c722c491,aa9078c,8aaf0dde) +,S(b8b00a76,e86b2579,97603f82,e80fde24,727362c3,6d7a192d,8974f643,4408e098,5db6718,8b0108dd,7cc6fa1c,fead7b2e,9e0b9ffb,78487d0a,5851b6f8,513e56c6) +,S(884c3a1b,fb6b968,53427a8f,69b713c6,bebe8f69,645fa52,c50e2d2d,61d89814,3dacc0e5,94b2eef,3743f821,df54dec0,ff28aa4b,d5b18fbf,14d658ce,7a3749b) +,S(3d0c1dcf,51aabf63,fe04100d,cbf6fb4e,c004dd1a,aeb637d8,496a47f9,74637596,576ebd5b,bf5de2cd,6242a6f,599fbb76,883fe013,3e2ef05d,22843236,a5df51c) +,S(56b3edaf,61539adc,25c57f79,a277b77f,1ae972b6,3d5328fa,13f811e2,dabca8c7,40383900,a2b28602,71ab3d2b,5dda95d0,96bdfbab,79b3d347,dbdac66d,2d2e98eb) +,S(426e29bf,50f34c9f,434eacfa,845485fe,5fbb11d8,319f9457,a74905fb,2bcfd3e2,eac47ee8,eeff40c6,20d10cd5,c3b9df40,eeb60b88,df1f57a3,5d613198,33cb117a) +,S(955737c9,f4e24d7e,c6d419ba,a2edadc7,cf0a91fb,5bfc3ea6,7ed50ca7,62929308,97bbb89d,18fd9040,2fa78314,359bf645,b69831b5,bb82e608,67baceed,481675dd) +,S(5d72a813,d46427a0,f2fae639,fd7e7ad0,704e74a0,83a784a1,cbb85017,e8b3e514,c92f410e,851fc61e,559d6839,a99eb95a,2e8c2636,f51c45ac,9bc1613c,b8876c2f) +,S(c7da9359,e9bc8890,620876d9,170495c2,dda7849c,7852406,22551bb7,e769b6ef,12278168,71508d00,95d90787,24a0c7d9,cb41f6c5,c82f01c6,d3794c3f,5c10653) +,S(67080a26,da7af0fd,c2fee080,f20ae516,d92697d7,fe1adace,9729064f,569ac683,ad9a07ac,fbba708b,30944107,e510eac0,8e08c5ce,79f77714,aa522cfc,2316d94d) +,S(210d5a39,d61428f7,6f878ddc,82e3afae,3947f404,5c155a41,63a00570,5bfc0dbf,617effe6,b0a629c2,ed14cc29,67a9193c,2efa804c,93e997ac,96eb1803,2e8c511c) +,S(5d0b9231,ca1511b9,c53242a9,37837d13,9b8e461c,6ff655fc,59021d04,e334ed98,c8070121,f4794eda,713ae1b4,a9e7d6cd,1a2f58e1,f6f8d986,bd13a66e,bfe924ae) +,S(687bb82c,42101161,ed0c8bd5,44c71975,9013fe2a,fcd10ab6,3ce78a67,e2907392,eaf63d87,758aa3a6,f9fc721c,f8b209cf,fafc8e81,10397e35,6a25e966,100d9eeb) +,S(51a44157,b8048f68,1a2a3931,ff2c3ff3,c63527d1,f4bccda4,e66a6d1,ce5f5d33,6ffc8d16,519c2940,14fdc8f4,20a63890,1a0c5667,2db96a1e,c5127fe9,e847dd31) +,S(b2862572,56f515a3,5624786a,478c3bfc,a5dd7b2,2bd7c4f9,89f70bcb,8de86775,22ae96a8,a5a5396,b7a67e5b,29292ffa,f53b64de,45f17692,abcd932d,4664f3a3) +,S(f76b721e,201078ca,eebd89a5,ca396213,6ee129bc,fb92ae58,4bb7c7fe,835bc30,599c6ab1,8419840,3d6b3d17,161bafff,223a0a38,1e96a4b7,a062f4a3,e6c0d561) +,S(12f24a87,63adee06,e82f20b7,ff696911,d9a3b88b,36dedb97,93b07c34,c4178e9c,59fd7b9f,96f01fb7,b265d939,c2827bee,b2427fdf,8c2e1b7,35178d58,e055b7f1) +,S(9e1b8a90,de6c6bbe,2a082d47,758240cc,bcfaf145,c48f90ce,fa0221e3,1922260a,fa5e86a5,b54bd9e0,7c2a54f4,2097d004,8a71eb06,ea48c0a6,6cda5981,b390f9f) +,S(63f05903,20b73eb7,b01b6a66,e28e31f1,ed4117f8,6c4d20a3,8c109031,2fbaae9c,24b8c9d2,d34a81fe,6e88967,a263877f,40bd68ca,baf5d9c5,1abe8b1,9501d8eb) +,S(447c7409,f5402a3d,a1f569a4,ad9f2855,e5c89b6e,99c743a8,e27992b4,63905999,d44e8d9a,b34a7a09,47b37723,be016c08,716baa73,8b93f28d,b7790370,ad49e154) +,S(74a4406a,4c5340af,ab77db0c,20f197e4,25eed4f4,a3f986df,1bbf10df,f8793254,162d678a,a4ba712,8cd36907,d1c46b16,dc4c07bc,52aa46d,fc7987eb,67742023) +,S(f7035171,31872637,ab0e63cc,841cc7b6,2bf5e076,53a45ff,3a23246e,8f047c07,c84b0391,4f470785,721762a9,5972b59e,b3c7eec9,66718936,ccaee9c1,da1097ef) +,S(ec4fe07b,57b23581,2c53bd70,6b0a4152,2194d168,dca164f6,ac999f6f,72eaae11,af495291,45deb29f,ec2b1dc4,e9b76051,b2f9df79,bdd304d7,b5528f5c,a2fff789) +,S(17156de8,fa96174f,7a0b274e,e168d0d4,c6552047,11f36388,78dbab4a,cdd2ac9d,2ae3ec4,36c1460c,984e37ed,6decb88f,c2de9f84,79e28ca6,abb6803f,1461ac3d) +,S(e41b462b,9c5a47fa,cfa9be56,dd30cd,549cb90c,9506a6a,abfca643,9a1b2ede,108fe2b2,8bda60a,c68fb353,38c6958f,e1b3604c,22215311,d380bf11,17507f4) +,S(ba6c0159,20a67883,d7880051,51a8038f,f357ea78,c53b95ad,38a6f437,7744aa38,da49c0e7,deb6b746,83366aa5,c0e8e710,cda1441b,6686f680,4579b5b9,16002cf3) +,S(26f0186e,883a4b6b,87102ab7,f7e52663,7e8a9553,8495729c,ee283568,f8cbf1ae,eef8de4,bb2197ca,ccd51980,995a18a0,aad78823,75702d3,98b245db,4bd5f47a) +,S(10b93de,80c0cebc,351b5588,c0140e63,e00874e3,da663cdd,c4501ca5,b40c9d22,ed3189dd,f79af36b,e7986b02,7ec495ec,1dfef7f2,14358284,2d05b4d0,1c903258) +,S(e79ec274,337a82c1,c97b32da,8f5a8c55,7a159540,76c94255,8bc9a3e7,77769dde,9f23079f,22dafce3,54a4c175,d888f3ee,e527dad9,83d7502c,3b651762,628a06f6) +,S(fda0175,44f0ad3f,c8b9915e,8e0caa4,2be265e3,92041b0c,1b7d31a1,6fc101e1,424e9a27,85d59c6e,bc7e4298,1a505733,e4d49a76,b84a030d,db2f5c1,858902e7) +,S(681f01cb,5380cdfe,50314725,88bc830c,8327d8a3,cbcfdb31,577cf11b,a099c6bd,bf9d2117,cdc3b05f,9c06cef0,6fc9e757,59c02fad,8e0d98cd,794918,f39002bc) +,S(70c25a6b,2a2d2cc2,dd251f4d,9aca250b,d6fe9f8d,b9eff961,1de2095c,dbd12f64,c9eeaf68,a386b2cf,cd3f4dc4,793ea5b7,134dae04,d991e1f4,6b299a4d,1a966126) +,S(464ded2c,404b42d4,fefd5ea4,5f408666,3b466e85,fe8b304,3b121b8,9fccbb9d,ac113904,6ad3f613,23ad2d3e,a568367,610bb47b,e41a5260,79627122,105d910b) +,S(a32df72,48e79198,5d455109,a8c5dfc1,b7ff8990,1b5ce3f0,2ad2f134,13a103db,6db4b4fb,9d60906b,9aea2d1d,876296c8,cf9ad8d3,3e65e173,8212134a,4b160e72) +,S(fe49ce9e,7ee5d39c,97029774,64ec4fea,3ccb74dc,2a5c7fe9,a7695315,165179a,653f553a,35925dce,eefb9866,26155723,90bfc582,b4c426e6,3f58f0fa,3fe7dc8c) +,S(868b2e55,c895a7c2,4da24750,c126b10d,ec0f1a0a,2add5a87,8aa7316e,3354ad14,5e288874,cdea19fd,71f03594,1a6291bc,776bca82,804324,efb61f24,7ac299ef) +,S(fe0790da,90ae34c6,8ad3f1c0,80fc486b,d267ff7e,fd32d1ae,c63d08b5,8c098461,ad331393,de35b283,471a0244,422c6132,cdbfccdb,5680bef4,16f3beaf,6cf7177e) +,S(fe7fca8d,f4f80dc,ff16b196,167dfefa,42a23bf5,66837955,7f6d8279,6fe9a9d9,bbc4dd8a,d7ee925,dd80cb3d,681476ae,ccc5729c,e1815b1e,71c8f1cb,d8d4eb3b) +,S(a236c270,aa4ce20b,eb51b11b,511cf4c2,ae797598,e9f03fd2,3aa36858,9434cfc2,593599c5,75a7bdeb,41cc3ade,608c210a,8bc37040,fbb69f4c,4863a31f,2088f29b) +,S(d6a04a5,6bb8c27f,3ea8a348,538364e2,800472ea,d9e1f644,565546fc,76519248,4b95470d,50b97629,22b099ab,a5761243,dbf6e466,226e8e07,9b77069a,b542deb9) +,S(d09cd377,d64a045f,e1a76f97,4d701a24,67773228,3261aebd,74e02ea9,f8a30e7f,9f0942b9,2b702b3,d76ed2d0,1caf880d,41a342ea,ee06ae57,b90a924d,6588ffea) +,S(d030c72c,16d01a9d,6c2e5245,61c7e3fd,b9a469bf,ff0a7440,b2ed0ea5,e5d98b8b,c6b1308,dba4f981,16b60ff,eaea843b,fddeee67,ca1406f4,73db0f11,531f2c8e) +,S(56c456c6,d2c04a7d,441980ab,80b39a55,57d0c6f7,5706bba1,100c6bb1,e345a691,c5b2f0dc,2c735d0f,8ef10ffc,2753c2b2,825ce525,a0613189,fae34e64,26084819) +,S(aad5adf3,b505d1f4,28dd1b98,dd4fdde5,29d911c5,e0e5837d,75e51bac,308400c9,e94adf67,4f7994c1,123aa411,b790c68c,f55569f2,1df4b6e4,6afab87e,2777acc6) +,S(ac8cd8b4,dd76b8f7,4886b089,f18b4cb2,ca1d43c3,19ed034e,6b1867a3,5e6a0ef0,71d70894,f9daab15,7413f827,1cadcfc6,ffb71db4,9bcc81f3,c759d4f7,137ba96d) +,S(3964006d,f110fa45,409d7a4d,5996b44,93eb4150,f4217948,41dc5357,dc47ca1d,e4a11c6d,21dbd93a,f922a2bd,23f057e5,c2f24474,36bfd7d6,395a46df,3ad7cdb) +,S(2be10b92,27a312bb,74ea37b1,9bf910b7,723a1ff8,fb43dd55,1a0e1fbf,7bca56ec,19aa8afb,c886dc0d,293ecca9,4290b24b,755b2de8,c1dbc0b4,59052edc,c6df59ab) +,S(379c1556,2bd7f51a,1d219a34,dffc8bab,ccc1e417,1c38d342,a4c6325a,b5ad6ae5,47a1f28f,a6371df5,66dce223,10d95535,e7bc6734,7f20748d,b983fac4,2f185907) +,S(24054dc2,e675459d,2af584a7,d78110e9,30a36290,989dd4f9,914cf7a8,1fce9809,6572ae1d,3e05d0a7,1c4e06d4,820d16a5,3553dc81,a6f02a76,12b584a2,e57ae592) +,S(9812e6a6,f46ca979,ab7cd879,1023b32,913199c8,b850298f,a3bb4c8e,a02420a4,468f6eed,dfecd933,1bbaf36,986f9377,3afd963b,56577151,52a12b9c,88f937f0) +,S(46058644,6a348e4a,d84c928d,62c9de2a,9f6c14fb,95c83c6b,96203a5a,7f13c700,9dc55ee3,ca3d701f,e6759c20,3b18840f,4c873f11,57b21ad,90401e77,622d57ab) +,S(a8dbaf97,2d5b05f2,a44d862f,e4aed0fa,1cb877ca,639ac322,8e909507,bcbe006a,3db54c03,f082937c,4f98d38c,6141d0bf,253e6729,b83c9902,51ac4a97,176fa4bc) +,S(9b8b39f4,f4d91329,13324bcd,44f9846a,8b3019,22671128,74178009,391149fe,490a4f72,1c452e5a,88ffc693,90b0d1b3,4e4cae7f,2e0ab097,6b396a99,1c52c1d3) +,S(334681d5,a7ef46db,196404ea,9e501f81,7406ce24,27a64597,73e358ad,314615eb,2b23603a,1d80cd6a,9f04775a,52069de2,e328fdc1,37fe6b6d,6c165442,53ad6c0d) +,S(feb8e310,c63c6ebd,294639b4,a4cce42,bd5f8372,b7aeaa88,2023f0e0,29c32529,cb6e42ad,6a0cd780,aa57934b,86682260,68a45c63,bdf7e617,fbcbf86d,db43b213) +,S(f4a17bc2,c7334e92,dc923252,3b910a55,a8ca5cb6,2b3d93b3,fcf0f2c4,8705cb67,812b7795,1b24729,4b3d55a3,2f45260a,e7f4a9e3,d5cfa304,bb0471b0,da6e9dfe) +,S(8ec2ac7b,85514349,5496d596,bfcaaf4e,c330a995,f082324c,7e0479ba,4ccf181b,ea1588b6,7811d263,7bcb3bcf,5cf0bc4,70e92797,27b1c258,ce4ebba9,35250130) +,S(b1e6d61b,d9aecdbc,c9c4b6d,9e48c6f7,e4aa9eb7,7da3c001,53443c6c,4d4f19a,43af7b55,b2e2c976,8b1fdb34,48d6f339,1bc20aba,eccb1a3,5aef98af,b28cbf4a) +,S(4d83d2e8,210d47dc,3904a397,4db35433,1a951963,2d4e2e4,b69f2049,2f13b2be,7ed96c83,3874fc97,be45f1d8,8e5842b9,7a0e3bac,95400036,7c8572f6,3d37a6b3) +,S(1448e92e,fd51fc21,d6f5d514,35527f67,25f5c5ee,b0b29c36,b9eb6e8f,2bb20b84,248a338f,c8be83e5,2f91c9a2,2868973c,13336aa6,39e43f4c,ea8bbeb9,96e344ad) +,S(e23b03d6,9c2250ac,2cdcc7d4,4e0a218e,39d928b0,2585fe63,dcf7093c,924e4ead,8c69c7d0,4a8a4b7c,1997ef44,fadb04d7,80b91cba,13dee454,2effb8ae,71b9aea9) +,S(4cd1e35e,21fb3fe6,946a929b,9aebfcb8,78663224,da66af94,e5a722b4,32b5d7cb,6b1112dc,5e865b10,ba688780,32978617,eca892d7,730ca984,cba4ab07,7167e3bc) +,S(f3cebaf8,92cb7b0,27cb9212,3596ece0,bf25c6b0,d8f1dbf5,f2efb204,a0db647,a615ddeb,8418c013,91923b88,7bba5d3e,cf3c7172,efbdaab7,e12582bc,a968d8e0) +,S(4b8acd28,500bf88d,68337c81,33181706,dfe341de,7b1d5736,a3a85a2c,6d655e7d,be93d7c3,825a5675,84d6f76e,52f3b06,7b7c5d87,844f18ac,624c96e0,fd219bb8) +,S(8dc7ac81,d04e0088,63fd2de6,2cc68de8,3e567d81,85aebc53,d4771950,7ceb9fe1,62d4b64a,be7b1931,c47a7755,e25c803f,1eb14c89,2ee100e8,214b94c4,11fa9198) +,S(aa63343f,3078d48d,942bbbe,df4f2c19,a817c257,9003e033,7104e530,c1b89a23,277ef834,23a6730f,69c20f4d,9de94758,13befc6d,ce389bb,fe7958e6,6ea7b524) +,S(37de5061,9f301e40,8e9096c0,1a37df3a,dadeba61,bc217495,5d04d7a1,5121d30,7e7049c,33e40b96,6a136516,c005597c,e3f6aa70,d6db4c31,f5732fbc,e538898a) +,S(6d18cf55,506d59ce,a3e8cd44,f347481c,3ebc6682,2f91445e,11f2c0c,45eb83b4,e930e9c1,ca8b73f4,7fb9818e,5d4db8a0,220f7ba7,ce807854,c8ff2af7,b8a30cdb) +,S(77d85660,6de7dac5,dd4203c4,90152c9c,f70243fd,eb1d1c0a,5b797b39,16caa7d3,3f57cfe3,9b37d550,c9db0fc9,4b3c0e3b,1a2722ec,f920522e,8c37d848,f59c659c) +,S(5c2e69a6,c44b5bb1,c55dc8b5,6f9d4fb8,ea56450b,d69d9229,670e635d,f381bf16,f082049d,a69ca9b,a2821a8c,2fd0b46c,9ec21af2,4c34b049,f1af0126,75a3588d) +,S(329c01f5,66d925b,251944ed,92beb06a,aaacb98d,89b2aaf1,918ce400,b5a393ee,7e29b038,427a0fff,6ad50c80,aa49252e,e21c2c45,3d4c72a9,c3cafedf,faa57abf) +,S(4c2e631f,18b2dfa4,37ebb401,771d7b0e,b670f4fc,8546499d,f62b49bd,629525da,8a95ebfb,87423fa7,4c131432,6b7c204c,50c6c2d,a3f85370,1f789ca3,fe9a6f9c) +,S(fe121b93,d254465,c7f7cf02,ce10a575,d3808ce4,c6133fd9,392fbf1b,63d03fdc,33129b07,7bda4311,94fb997f,9443a0ff,e59438a,f360b635,2a80cbce,a49e0ba6) +,S(323ac27b,1cdbf3f7,74e20521,f1e74b8b,2cf8c5d4,4180316d,a532ae61,2f784c23,21156108,f6a64ac5,888b15fe,834ba9a5,c8489e16,f3d31197,bb296b2d,3fc3dc18) +,S(11478f62,fdfcb1e0,3a5f0ed5,ce0c2101,eeccbca1,e5934d37,41b1a8d2,7afd533,a9f79673,2fd3ecc8,644cdb17,6d11527a,aba8d0b2,985366c,70d96999,ec5f9153) +,S(9f0909b6,c9d3c1ad,eb88acf3,aed5a6a6,bc8d82b5,767896e5,e7343efc,20b9d078,a5161ca6,c5c95d64,dc663e30,b8f65234,61a579d7,b99a57a3,3b0f3844,e47db181) +,S(4960a875,32a9ad42,299d8cd1,a1af80bb,2807acb1,b52f1711,c55957d3,a64a6b9f,578e51f3,f1b46628,eb48f54a,93f82f24,4bfc6202,eef77dd8,cd6b90b4,de976625) +,S(675c29c2,bdb265e,5490951c,bfc9f73d,d142d536,4b5ec668,54b582f0,5d310354,22d1f669,3d82de84,202d4f9a,186bdfa6,8cb8ad5f,9da33a49,83229047,e08bd6d1) +,S(c4096cbd,6c75d0e2,6a922177,916ab32d,a9053adf,ad849d36,f65b7c9b,107ce605,5f236b47,2ae3c979,2ff61efb,9633ae05,b2b97e51,24a3c2,94f5be53,95c2bb46) +,S(9ea0d341,ddd05401,f01205ec,2c754155,b1ddd460,1fa3789,dd80ed9b,3b905c0b,3bf48101,97e7d0b7,6f3692cd,53989764,ba7ce059,953f7b71,7e615c20,da28e69) +,S(bdebbed7,84bffa33,72a6edd2,d9815b0d,637367f2,de3768c7,b4dd75a4,32fb92e4,5ff3437e,b62a9b62,dc16af10,5a20941d,297a431f,ca2b0067,6734c4ae,cfd0b9c0) +,S(a486fa44,b46e34f2,d6aea82c,8f554210,cbfe674,77b560c7,bccc7d6c,9e910932,1ab7e36d,8a15e284,8a3caa0,f54ca555,b8ad5baa,7f47fca8,3231c822,f897317a) +,S(4463a0a5,57a1a926,aa204376,a20aefab,66e7abb1,18c7f769,fbd1a7d1,29cbba08,4a823aa5,ab7b602a,704f01de,20b8ad13,7dc08152,25ceace0,9a9dab69,d034af0d) +,S(d6e08a4f,c45e8dfb,ab713584,d91d1d8,8cbdc5c6,2eeb4b4c,593a73df,4d825ac4,2cd85bb4,77c0d0ba,5071ae8f,c0fe2dbd,8be98d9,622fe506,c59800cb,5eb4c55f) +,S(b626e299,2a69cad4,e6076dca,29bbfd34,546d31d0,a4f8b656,a433fa87,f96a10f1,6df4b2ce,ba919268,f1568632,55e27655,62ac5e3b,8cbbfd34,3c656f43,43cb5bc6) +,S(3619e6eb,74645070,b2dd6196,5fe4d25e,25a4dfeb,619e3b05,7e31a566,947139a5,964b8989,ba156121,9d36c3bf,29467c7b,79940c3b,450c1431,1aa0d725,1282093f) +,S(b3529b5e,6718843f,c40a3a65,d5330961,41e5c060,e326aa84,7ccf7f48,c8bda2e9,49e6e0d3,7ce1bf45,e9c595ac,285becf5,31111e7b,2a67b057,9d4fc552,59c1b935) +,S(e51f0067,5bd7145f,fcf85527,dd247ef1,4a199778,94035598,d42afdf1,2fa9e05b,d59aaf3e,8b4d72eb,4523d5fc,69b047e5,7d2e175f,30eb6c8c,ec729cbf,c1b32666) +,S(8a87f066,f64bc468,d225eb6a,a0a7b54b,91c930e4,d4520720,1705f831,cde79b28,a92a5d95,e0057c95,b219062f,5d0e4277,249c34ac,6255113b,b5eebea5,66800227) +,S(d8a81015,aa878ee5,a69c771e,bf88daad,3a926afb,b8aef632,cd7d987b,fd310b06,af77f7e8,f276ed4e,963e3a26,2f3942c7,ec9f31da,199ead3,d5e5f53f,e20acbdd) +,S(88c3fa19,4f3f4d93,dbe5b8a3,865d28d6,51c9abd,519af4d2,c3b743d4,ce0cc5c1,104caf7a,f9ff822,7b3671a7,e7745bee,26b5deda,9982b9d9,a9d648e0,760d8f8d) +,S(f8738725,3434b0ea,f05e9c76,3c729a8a,22070111,6c5a6484,5532c3d9,41ce648e,a8b5eed1,d4ee7913,b69f6627,d3e1be,4c286e15,78167201,46fc9e21,786f7bd7) +,S(5fca538,5afb021f,94cca826,5689605c,7b35c8f8,dc8fef60,6b18420f,909acc33,1d7fa51,f5c28bfd,eb1f9a52,723eb2bf,c5b4d078,d5d4b639,2b791af5,d5b2b3a8) +,S(47484548,d4b2acd9,bb2cef9d,bed4bd0f,f1fddf4f,e1561a51,891464fa,cf5007db,ea61e154,f011cfe0,46fa2539,7fb444fd,b93e223b,ed882bce,3ddaa3c8,328f44a8) +,S(331f17ff,b14d43f,ec69a6fe,b41a8021,dd8ef56d,2540234a,b466ac85,e6c5b8f1,ba20bca1,8d774731,b6b64a0f,8a19311f,37d8c061,2c4699b,68d569b0,9eec144b) +,S(6aba62d,200bd2c6,4ab88ce9,80530e56,5b8971c,f9c427f1,5e9b146d,dbdc68ce,e4c936d7,d7d98919,acd26ef0,cf071f2d,fcf65fd7,78dd8c5b,ab026,e9f832c8) +,S(c76b6c35,e72fa19c,621022b4,d9ec6ece,c0cfee8d,c73254fc,f52cbc69,23ca19c5,5b0ffa7a,48ee8599,9b74d0a1,d7fa0289,b49dba85,7b21bfb1,ee7ba831,fa13efc9) +,S(c056ea3d,43f33df9,b01590fa,429c14a6,aaa438ed,415254a4,4a93854,ce1bb77a,d5b194e3,2337a9f1,2c479e7f,576a571e,58355a02,8ba0231c,c337b8c7,eb3dca7b) +,S(3d688ccc,8ddf0ef1,137bb897,e6b8f3b7,7df652c4,93cac3a1,47e88b3d,bdac938a,bca94788,4d7ae1f2,960daead,111558f7,38b6bc9a,7af3bb4a,691af22d,4d5879fc) +,S(4faffaf6,69ce1180,a9145f0c,df6fd834,c59d7a9f,5f2e49cf,3924b33d,8d2a179,9e015cac,2dca2ec2,5580c16d,8c910abb,dcbad872,79bcc485,b71f5561,60159d2) +,S(47578e3,7cd7eb78,6b5a44eb,3decc7c4,e8ba0c7,6699ef61,4ac30579,a24aecad,948ac817,a6bee00b,c68eab83,fb628ed8,7fd0066,9ebc8569,45eef8c9,67171651) +,S(9aade275,3eaa646a,24ad1a35,f74887db,8c72fda7,77b59dfe,103e1a95,dc618836,b651c384,8f4625f3,1e6e7a05,c94483f,ceef2fed,dc7f4256,87e0373d,d02bca96) +,S(b1b0c3e0,b1c6ee75,55a81852,447b2bcf,321c9b9f,629caf9a,276133af,63aed711,493accfd,624e6ff3,dfc1d0dc,aff17113,c2c74167,58cbd571,759bab24,300ac827) +,S(c557758f,b192a058,eaec5762,ff391a9b,2a0ce462,7bae01c,156dcf3e,bf2a8ff6,1d4e9b53,d209e195,9f10f671,b1bfdbf3,98921284,a7719766,39947969,6d1bd3b3) +,S(73522ded,5120ed4f,b49b5ca6,df5a1b6,edcc082,48df4d07,cc9ad923,2b7b5e0e,47569d94,cdf0270e,d1d299ce,d5bcfdc7,7f87db4e,c9725a96,e4388cf8,dee08d74) +,S(16571c0d,66328963,2a3ae46d,fc2bee50,fd6fbc0c,f0ec73ad,72bb9c2f,e8323506,65de9d86,9e001c60,ced57911,e7ce6150,a936d684,d759f143,d2224448,4bec68d2) +,S(f5fe5564,2eb630a5,c860cc8d,7c9ef86d,b1810d2e,82dcb343,dbe2f958,98e5f090,5cee7a1f,bea9dac8,ca340dcd,fc2c097a,eec2dabd,d7ed7504,e20c913e,9fadfa87) +,S(ef09db32,70d09043,43da67a0,b87cedaf,7aece017,58d78591,8814e3ca,396e3592,5934f805,ba246e9f,965c6161,cefdf4e3,7df14271,2ae076ea,80ca239a,c7b675e2) +,S(886cdbd7,27d2f099,9852b102,bf201ed2,5e174622,f974b0c1,3edfe523,373a54e8,dacb328a,7fca6e5a,e5351825,564e4f89,5166f687,38d46142,6eea7b09,dca73b2b) +,S(b7d86bcd,4f7bf2e,8529ff84,88d9f3e9,62071308,9bbd91f9,6e4ef82a,ce237cff,c6b0aff1,375a547e,a8546dc4,17574843,3acf2a4,ed0d002e,e32fd88f,3b702f0e) +,S(d7d171b2,8132ab85,30791059,395d94ec,c24f5e99,67bc6c4d,22bfc7ba,eb388c67,983770e0,2421e2b6,55d3c135,1bb39bf7,7be39682,97088744,bfe6543d,dc1a8f8f) +,S(ffe712fd,881e30e7,229f1cfa,833dad90,f01a1896,c1493502,a429080a,9794b1be,f4299e03,75d084a,10b11ae5,8f2fa2be,f18b037a,53165586,cdac18ce,54505da8) +,S(563c92b3,3226951,cd7cd10b,3f7b35c7,dff3f0de,6f03d66,9f664655,57d13f7c,dca1eef4,85bef41,80b0ccfb,2416f948,9bb21094,854f5f43,769cb37,33ec10c1) +,S(b8e76ef3,3a2cebce,614056d7,efa47c15,dd52c228,66a7d3dd,9a0d4d64,68f32437,4454e79d,652ae799,a3a539ba,42619a1c,3076ccc2,109dc4a2,2aa41a28,918651c2) +,S(36db2304,f60703a2,df2e429f,b8a99841,7b4a4f3,e08642d2,c5675460,aaf1c971,a0536e8f,5cc30aa3,d9b859ee,e26b1abb,ecf7f9b4,8c8fef0,f842fc9,a684b5cc) +,S(c5d4e51d,1521637d,d6055e52,9e9ae2a4,d537c1a1,b7c6a314,f9d558a1,88d9a5ab,c841eeed,6a13782c,fbf65b08,c6570994,aaf7093c,4b48ad0d,e04db33a,6feb3f6d) +,S(50c03dc2,985859f6,ffb79ed3,f635e17a,b0561533,600af220,7cd98f9f,71c4bffd,c68c8797,a7ed229a,f59a2bd7,451c748a,5c425528,8b7f6b0a,68b64a77,d7137720) +,S(2806d84b,3e7e6f9a,2e10ae5d,cf5bb0ef,98560691,71d31ff3,3645346d,f08333ef,72f23443,38e34ccb,4ccb5ddb,f3a6b58e,bf8cac26,4243785e,54a9b503,c87b429d) +,S(40d70ddd,1ef58dd1,c43e33c6,29840fee,82bb9c1b,e222b53f,4c58952f,388790a4,9b1a9d57,b6dd9932,338d170e,af4d5516,e654685b,3946930d,96b2a1d7,f70770d5) +,S(8850ec32,4e71213,bd77b193,ee21da82,ac733804,17983905,d0156608,8b87c835,aafff7a0,a9160b91,92df58ea,a65c0716,961480b2,b0cb4d3a,7d637f77,ddc160e2) +,S(54951509,bd7c29f4,77f9d4a6,2be485d7,de291b0,6a308bd2,c240cf71,50ad6e8b,2fdb347c,f2a23b9f,a3a45c76,44cc1fa9,b1d8f79f,77c02f27,f136c732,c7ef2722) +,S(9f5ec355,cdf8eb4f,be5af1ab,70a3e7cf,1c3d3e8b,e643621f,acf8f69f,af7e5d44,b203dd5f,b38b3550,6fda94b,ada1c4bb,12b8be5e,92bf8a58,4886f2ca,19d3c06e) +,S(812e4a9c,1bba9e52,8cb5e606,c8b326fe,8b72f0e2,3062837b,bdf371a2,2ec0b3da,2ba7b5b7,14a9ae39,c62bd36a,1ed00135,5d98d248,9ef90f24,d10d1c58,f8e222a1) +,S(e6035ddb,cf85616b,540ff16e,cd5d7fd1,af52c6f6,2a26ec36,c5c1ca86,2a3d924a,a945389e,f687fcac,6f918718,a1f29f19,173d3104,69c5954a,d6cfb5df,f01eec86) +,S(d788a5e8,d771d471,b7169693,86b2339b,2643f129,a6b50bc6,321e752,6a033446,34b85622,5095783e,fa57fe32,a7d91b65,c0c9a42f,79fe30e0,b2598967,e97d3990) +,S(663733dd,29374f9f,1db5f11,6fa32b56,c8ef42f,706bd802,5615d4a4,77c6f41c,3585d45,3ae0fc59,1614e916,a1400b79,85b59f66,6e2553c1,394ec26d,d078676d) +,S(5ec6e728,5ae1413,3dbad4d1,19e2e3d5,6affda33,356146f0,a5ab023d,b323ad9c,3dd241bf,cfc6301e,29cd609d,b1a0fca3,d35a56e4,668de9f6,45c23d69,c0884579) +,S(f18fc442,1fbb66a2,7c336647,1459717c,87532be5,d4416cee,e4a674a3,2cf8f3c5,d38a0881,3bb33df1,fb4e83,6686c0fa,26847e5,f7580de9,b4f229cd,1359d560) +,S(818f549e,d9bcfe1f,14b8d336,21342465,7dec0dfe,eea1d719,20622442,39f5345a,37ce611f,cca2f448,45c1a8e9,d7f4b3f8,48b24c5c,2b9f5368,8cc2c8df,846602ee) +,S(75e2c791,f98e3fc8,2a74ee3a,532e8796,4f4fa8eb,6421aa64,17a5b00b,1edce942,51f2373b,a4951362,68aa17c7,1160855c,7c4d37be,222a8b26,f2d54cd5,37e5f6b4) +,S(711f8db6,4c0c6d31,daff4ec1,f9937730,9b44de59,9f4b9119,9ca6836e,1e3954d3,485955e3,432ac82d,f3170fcf,7b3519cd,6e4dfbba,170bbeb5,b75e3e7d,70caa4b0) +,S(63502c26,6f755a1e,4be2104e,e8ca9c2c,5216f50f,e21e003a,16071bc8,df3ba6a5,a5c829ea,c8fc3f4a,f55075bd,afe77977,3954b88a,f1f3a8dd,90f28aa1,49bea942) +,S(2a677459,ccfee070,1b5bb82f,d2ee57e6,13f5c3d6,3927938c,92d10954,c2850872,ff6e9798,5c5db0b2,9bb1cbf5,db03e0c4,401bbf28,eb39e053,714d5c5e,ef7cbe71) +,S(68f85f87,78fb69a7,9db4a22,3d7faf95,5b359bd0,5f230d99,f051b008,32b52cbe,dc2e949,f4fc3189,c4f7b771,f8b56b85,ef9c65c0,b3bdf89e,405d5f3c,ffc92210) +,S(7ee9d5b7,3b542036,509fd8b9,de590b24,9e9883c8,6f4bb90e,1c2904f3,d2b74ade,98122413,241cf205,f91c6977,b925ddd7,4920636a,9dd67828,2c30ee,7343e62) +,S(8447b090,cdb19271,db368023,d40e520,102b5d04,79eaf391,3817553e,24aa33c8,25b43fe6,55a27481,c02eacd3,9025a523,121d02a5,78896a78,c14a8c21,f7c0bdb0) +,S(316073b9,3f1550e6,b7951f56,90c5ef3b,e45e622e,77a2f268,c89a8b6f,2816a645,557ca5ac,2fc70ce8,c3e54a4d,b31d5c77,a1a6f38a,18646caf,6a52db31,947624be) +,S(fae2312d,a2ef21ac,358fe949,5c011b18,cdaa8ef1,c99284ae,5fc1eb77,4836d6ac,6f3bf661,2d99e865,b0cee7cb,3fccbf08,aa948ad9,b29b4b8b,54eee8d6,3f0b76c7) +,S(280a2bef,5588dfdf,b1e1691,d3162aec,7d4c72c6,b76f23e1,2f8ce783,54f839f0,f00ded1b,c31a9774,a87be1bc,7e440585,b2b4ba63,cc0d9c73,ca7b4873,93683f72) +,S(3f43e77a,9b7b92c9,92b7e5d2,8c75444f,4d0609b2,8aa65ddb,86bf6ac0,bf7ccdcd,b3117903,bb3c0a54,bc6bd6b9,92b8d85c,ac267855,50075536,6cf70a84,4c72a2d6) +,S(3a0afdc8,387bfa34,87e53929,51e10e,9535500d,f6506296,46df162d,d469f2de,75697cc8,f0f690b6,e1f86dff,3f2ca53d,907d4cf7,c8ff324e,8b4187ac,c9bb29c7) +,S(3f972b64,209f723e,99a6e7c4,a72072a0,2789d0aa,8a23d660,949ea417,7970809d,7a482428,7a6bfd9c,afc26e76,9a02c5ff,9a7c053e,e63f2342,b32a4f84,42e47d15) +,S(938ac0f,fa73364d,11df1ecc,4b84e3d1,c21ff85d,71f404df,e8daf4a,e889b0b4,a1c09ed3,d526b381,dee8820,eda06a10,4e968995,64cb604a,63fba74a,45be0312) +,S(5355ed75,2993e74c,275eb9ed,3bd34575,631c9b5a,64e99071,8311ec8a,f4e28bcc,bbb1007d,680aaaaf,ac10279f,600f1851,c8188547,3091a40,ddf7253c,fc6ad088) +,S(880e32ed,70ba76c6,d83bda46,a4340646,b033696f,ab62e457,4e989311,fbf277b7,76feb2cb,8d10d5e2,406763d5,f696686b,8dcdaaf,330e4e7c,623cc7a8,6e0410bc) +,S(daf778aa,a2755b68,2b8beec1,14b74e9c,857ac503,daad6bee,bd6d11f1,8f11aa8,1ed85c62,710d3017,9f0f3024,d6ed6976,e38325f0,92981c88,fd4982ee,98a5f428) +,S(e5c3e9dd,75633d27,d19c0a4f,f3533f80,9a60b95a,42c8c464,1cf7abda,8fb474dd,f1e56af6,5c5c087e,ab303699,f20bc9f,71b7b7fe,16332afb,2517b241,8dfb0dfc) +,S(5d403f34,ecdfd870,977f3bf2,ffb274c9,6859c20c,8cd7afd,d116837d,c0096973,6b5be47c,70246cc5,9781ba70,71764d72,2335c334,443e5e4a,5ba12939,d8f6aeb1) +,S(50ba053c,25511f71,b35b4caa,c990ab27,993bf034,f3e55f81,3896458b,5e246b12,d2f12a45,5c7a3170,67690399,3063dab0,9f8a22a2,bccbe5b8,8a7fa2bb,f2291f63) +,S(385a80ea,ee4aa9ed,a07898f0,b3658793,9f290622,399c3a00,b38bf02f,66629cf,a543320b,d72ac6e5,d750806d,6a90b8fb,8cfe4902,46991eb1,6e6a6974,befcd50) +,S(98610b9,904ede38,6e69de6c,3d40518e,eaa669a5,23620a9b,276e1996,bdedbef,907755a2,eb6aa100,d0cd0c89,25b5ff8f,b88f72d3,61d83315,c4ad0d94,8a06b581) +,S(83f10807,d9640d3b,dfc7b0d3,dcbbf6a2,19ae215b,4754f29e,d4579999,191b7fe8,f62d231b,5095d6d2,860e69c6,509de2c6,fe719e4a,fbc2b5e2,489a6f9a,7293364) +,S(51d22293,927335c6,2f82b028,52759fd1,e3f287fc,67b6059e,74dca17d,4fb1c246,b9b803a3,b5145b4d,188b909e,23c8b126,f7184bdd,3128587b,e05219df,6c63745d) +,S(be6a6342,e5783d43,d2691945,826c37c5,3e8cc24c,5a09fc70,3689def1,4f465006,81c718fc,3fc15279,da9efc14,13ddcfd8,81bc7e4b,1c36004c,2008dba2,7c7ef000) +,S(f21334d9,c36f1284,a4bb043b,58b27070,448681d9,a82ae81,a4e8f226,bc790036,44851,3a87fd30,453dcc1e,b21e293b,f5f143b8,2cf2708e,428f4753,8816eff2) +,S(1558c4e5,af34463f,810cb1f1,b73bd27e,932a832,9253e2cb,419eafae,c9730508,cb8cc650,25e14132,3663f3f4,1a75085c,6921bb37,428a149e,2dd1fe4d,f4c917f8) +,S(1853a32c,8f6020d8,1b4d3596,a88e3825,b575a4ed,99072e64,2e090a1a,665d71e2,8da2a31c,b170aea0,e364aedb,b1861fff,eaf26888,b29405e8,9e3ed982,a03a8367) +,S(ef585cbc,f0f03bec,21df60db,cfafa9dc,2da679b4,3bdd590b,8cc35388,cccd323d,2bc5e203,aff91f6d,38592e07,82813905,f02ccdba,1daa7acd,d93f6d80,78c2f296) +,S(3f4c2e37,e1ea68eb,befd9971,424b3c7b,1fa45864,e0d13471,a1476808,b2fd5c14,678990ab,3d283b3f,aaa665b0,4f329b51,51b9c17,b54385e3,30de36a4,7e0eeaa5) +,S(2b001b8a,d557ac4a,181cb20a,b3abf2ac,59fc9b10,20b5533b,621b4119,e421693a,fe4f3007,f8d19db1,73e6f8c3,48b2525,310a328d,2ca0c675,8fa29723,82c6b94a) +,S(6589d1dd,7d5a08ff,8deb5b10,81fb0ca3,79c90d27,58ba0bb9,8d05bc93,452cd229,82409480,ed842993,4bc8dca2,3e000fd5,fdc5475b,192bc7fa,a1179165,9a8149a9) +,S(c233fd0d,f5d3835b,8e855316,276a6a90,ab4377e5,a3a3a8a8,3b89f0f5,27950a6f,8fe8e0a8,775a9a43,12cfbac0,85aefe06,31468031,86b8b84f,49422392,b4f6f3e5) +,S(82731a85,2a848eee,d6ee3f57,f75a2bfa,a388670f,89f6f6e7,b65b13d0,764cc14a,c00c509a,307c5e87,f1b09688,38e34a21,1ffacc9b,8a7504c1,2080e4cd,39117583) +,S(e21387a0,e5d8b1b0,5aab5150,122942ec,c9dde3b5,53eac977,7eea6d0,6d2a50d,c74de509,f90d93df,343c920,74ac5dfc,fc81c95,93354349,bb2810dc,8db0ff83) +,S(180871fd,2fa443d9,c5b5c341,4d635b8e,92780fc1,6d04236a,bc9a49,5b9fdc25,d66c7150,6008f37a,422014a8,bbe025c6,1f25e636,e2778146,59985003,ab14d120) +,S(b5a9de7e,ed112a8c,1ef29a9a,31156b90,d64dff93,4d83fab4,b44d30e0,bccb2c42,5675a679,a81c3faf,3b0afe66,ef85721,30315ccf,b0ff3d91,130a71f4,3539db38) +,S(9acce472,61f1e50d,f42baf78,c05a5cf9,8ce5697b,6d3b4d,40d011fd,aee7d6,fb7c413c,40464c69,e5756830,4325a79e,6cb8c831,add29e0a,95f88feb,9507a05c) +,S(f80ab79b,7bef7712,2fc7bc4b,2193deed,916796e3,67d85100,a02cc0eb,8b574e5c,c6d4d03f,842d8b25,d9b5834e,d6cdcacc,3a1ac585,b5d22aa,c77019dd,1d5c8f6d) +,S(b431e355,cdb4230c,3005845e,f60b24d9,25d81448,ec161aee,faea1f98,bc9366a1,ebcdadd4,ae230a14,382ddb98,552b6e69,7aebace5,5cc7390e,f69d176d,da41c1cd) +,S(7aa60b9e,8c93a63,51eb686f,46dca4e6,efe56edf,6c2089c5,93f6a800,6e75f1fb,4c81e2,17700bf1,e053e389,2e33e694,cb424800,b4068c98,328f00ef,5fa0347e) +,S(1a88250b,3aa4243b,7441d1a4,da37b4dd,d304fbef,272f696b,a72e7610,1286b30b,625b9d05,57d3815b,e06d8cb0,f056a9be,b33b7658,f459b3fe,3fd5f4ab,69b7a473) +,S(5b524eeb,49fd558a,2d34db23,cb5dcee1,6c4ca47,1eba9966,82dedbc3,aa2b57c7,2d5c2c97,56b7ce1d,735b163d,56e02bdc,25c8b227,2bca2d5d,bf252906,bb8ae50c) +,S(ae60e777,6d9fbe79,d24cb8b1,f756098,191550d8,433bc7d1,8920584e,7676d2c5,430fe986,73772472,ca11be83,eefc8678,b76c36d4,346a311f,fff926fb,158d7784) +,S(323a5e3d,9e29f668,d460b081,a5dce6fb,53e8d730,9c42f105,ab4f812a,62efb9d4,2b457b3,69483f42,16656d1d,3b5ea9af,da6216a4,47661830,c2fa56be,804776ba) +,S(acd1b5b6,591e552c,864e612e,d69429b2,b3db8649,7a5962a2,a8b36511,7a7c1c9d,e6131fff,56f6900,926ba772,92526348,67544d25,1ebc4fa3,26562190,8e6e88b8) +,S(6b4e2c70,817852e0,2a26286b,155248ce,f2e61e60,84742cf1,14ebf74f,785b36f4,8400951c,7a529bdc,2007130d,1cd5297,7398f7fc,d66e5a1a,1e4e8644,e5b893df) +,S(c2b2c727,d67b0a46,1f44cb91,48c34744,4e6a375f,80a817c7,1517969f,8084ab31,fed64359,ebf37b0f,998aa251,9c281fd3,a52c47d4,89051718,82481fae,c36d5f59) +,S(3385eeda,b5b2bd94,f794609d,978a0f86,2ec56422,bda0ef71,2207ca1b,904f202e,2808d2af,1db8a8ee,1c5975aa,31a9f441,b12a2186,746a474b,4907bb71,603d7443) +,S(800f6cd7,f2cb437b,8470c292,3fab4786,edce15f0,d4c52a82,33519c07,14c803f2,981f2e3e,ad11aa0,cde06ca5,9b26028c,23e0a88c,ec397734,ad0152f4,d4a37056) +,S(73aa0bff,3a9f286f,d3c103c6,d7bb6caa,ebfaf4b7,614f1f32,4741c600,eeaa2f3b,30bc529,81a9b983,cb89fe73,dd8bce7c,a54a2e3c,4fde6846,701f1da5,18c6f7b1) +,S(9280fce6,ab5c13f6,80bfdfa9,c3e7612f,86380498,9bcf29ca,789169fb,a178f2c5,4b96ecdb,c5bc2e3b,2fd397b1,8f7f5bb7,aeb6a7bd,db0a3b23,3e74f7cd,ccae36bb) +,S(72055c4b,bb50b9ef,b589be16,270d12ea,9f438780,e5eccb81,7dbf69d,a66e03ca,aeaa257f,c30a77dd,58574693,51a8623d,985ad705,aa1fe3f9,8915a6c6,f6bc7cb) +,S(f0f3cfd0,c771e3db,ba687c7,3fa827cc,eb8e887,12abc8e0,3085d047,e7c1879f,2c612e7d,8b744c54,f8f0c4b3,24fe10a3,1bf8aa5c,cf6e2e20,eff98153,a4936b33) +,S(97c78b65,70b0f270,6fac8fe8,ea4376ac,d8b61177,e5e7b3ec,67a7af9b,e6f5dcfa,1aeb950c,fea95858,a97da765,c3cb5941,1334609b,347c4daa,1279d58f,3be14c3d) +,S(b39ffa1e,967e6fc3,d493a9de,48b077fa,4b7908f5,33a73eeb,9b5c9efe,9e509e69,f55f3951,81ac72cc,d618c00,71c817e3,f76c302f,11219e16,f3b40e75,ea65dc05) +,S(159b9f7a,5ff27c4d,1bc3fcc4,d91b160a,1b2a972,8b1e7fd1,7351c663,f8e7baaa,b0aaef6d,86c54ffa,eba1c7f0,d789fd41,5e60127d,578c2697,a8380b7c,a4c4360a) +,S(25810fd1,8d4a4b16,c7d07a62,b626fc45,6dff76ab,3c1361aa,f729f7f3,cb85e44c,f4052325,7794bd70,ad295526,ab4b8b00,9252dd5f,33578f44,2fcd2219,2f6a2d9b) +,S(27e20a4d,5860a328,c499864c,9075881,eab36291,2da641d,6e1934df,473352b2,c1598cf2,888cb50f,e270b490,503c11a7,d3822a2b,e86a7b,65cb9499,3b45203) +,S(483f454e,517a94e6,6708f465,ba217b60,6d684a68,4d9472dd,685f3bd1,341448a2,c13b3144,d93b9a36,45d23346,c5dcb70d,d338d06f,f0c22aa8,2ba68a61,7f9ad11f) +,S(4f47b2f6,31734aa6,5ae4c9a3,c1532f2,67ef068f,83a4f266,e2e0a59e,be04e6e5,58f1f34c,f11b9cb4,5d33ebcf,3edab72d,6824392e,dd547a27,c0134d66,58d99d2b) +,S(aa78eb7e,835ce84,b4f1774b,8e810cc0,d6f42a2b,11c44574,24fb6341,7797db07,39640139,d957d47c,59cc7541,d3f72e33,ee9ffc63,2171311b,cf493ea,185e743b) +,S(d2598985,83c00560,11dc0655,c37580b0,31a3f1f6,aa5f5944,17eb0ce8,cc033d49,3641c973,9de8818b,a294622a,2dabe172,b6a83006,4d04ed8b,c841d11a,5af24b08) +,S(4f023ba0,ecccb74f,56f38f87,7435907b,f2d2b85d,59f7ffaf,48712a48,55e26634,f80efc33,b15d5125,b8fc35ea,393b6c3f,a2ae094b,86a6ee95,bc48295f,b1a6a456) +,S(9c86f08b,48abd097,7bfe13cf,a15ac8be,8eda4128,f7c143c6,70bf7e2d,763a1589,11511f87,e9ecb88,39eff453,d29d4db2,17d4eeda,c8468a17,1a152f15,c1c2df45) +,S(3808718b,72e95cc8,fffaffce,cd57e269,c5e6ac77,69d8120e,9130d8b8,ee137576,f40ebdeb,cf5eb722,4dae59cf,8ed8b58c,c614a61a,9e3ccee,db789fd3,31ea728f) +,S(8defd15e,399492fc,71c80a1,3eda0244,eb349f47,5c7dfb42,55dfa752,fcdda3df,d3dfa778,4353d0c3,b4fb0d19,ffc39631,a01786ce,e3b0cc7f,f9e4c5f6,7bf7a771) +,S(8dac8d42,5ac1d07e,3a805248,798fade7,ed99f9d0,c324bd46,6eaa8aa7,dc24bf8a,f232fdb7,923234fc,d8b2f097,d354dd6e,62e9d926,20d28087,d6410b72,aaef8009) +,S(87ce6443,f3bce6de,287178b4,f243c3d1,e45d26fc,6f811d35,329cac04,7fa90e1b,a897019,62414ab4,c582799d,77edf3b0,f0af0d4,8f70e875,fac33e95,39724138) +,S(bfee6bfa,bf2fb77e,9eb60a3f,8b7775ba,124a21c8,741af3b,d22966c6,a8fdf08d,29a1c399,541e4bf1,7f26f215,52fc83ee,cd2e8be8,40b83fa6,9c9ce5d5,fbba76f7) +,S(c30fda5,b553a800,2341a553,7aff72b8,44873af,8381b41d,aef9af2b,5cc2bec1,5ce3eab5,87d88d64,fa44aafc,ce34046,8a96f76e,65dd562e,7d14153b,439fea6d) +,S(5e7151fd,594119d7,c5cadbf,e1b419f5,4d922607,728d70a0,f1dd4d8,3400ed97,6a8ceea5,a51d4a7d,62d36816,ecbdd75e,4c64ec96,6257820d,73bd9531,ea108917) +,S(a9c8eb0a,66cdd5f0,f33d0620,8525225b,e974af7a,b50d47c0,4bf690db,ec86100b,f209cb9d,898731f3,b02a24bc,ff290cd4,a4371e88,f3aeebf3,29c9e1b2,8b8e0a2f) +,S(955e79d7,93669150,471b1659,52ee6121,cb804373,5faf653b,9468511a,e3a2e439,68daafe3,2a9b67a0,10ea3bcc,1a56c7a0,2e82cddf,120e6826,1de0700b,cf930d06) +,S(22d27293,d3c1cc6a,5b3bc70b,3bb7e1d6,bef24805,3c8685fa,c192b409,dfa34a71,c74b44e3,4fc855b7,53c4e42e,740dbb59,4d5d76df,b39de389,e6c837e9,639b3357) +,S(d19fcece,f74b1767,4e9d91f7,1487aebf,70d46e8b,3a037835,b2f4e8c4,2137abc0,5b904bf6,3dca0981,3ce224f7,494ccba3,34ca9fe5,f365ca83,fe9adb6c,4adb7580) +,S(6aa1722a,adc74800,d6609113,6bc6a6a8,1723c36c,524a873f,2a437c91,c2336899,8e97004c,df495b4c,63164058,321549ce,3d9709d9,ed667c36,9a4f1ee2,d6319d07) +,S(79bd3623,9ee4d220,12d07262,e96ad186,b16e3b6b,720d052,f736f851,b0ea6efc,a4b43db,f568cda4,1dc972c7,1c7c92c3,6a31166f,ad6b80fe,42df4dbe,f418729e) +,S(b5e02b2c,146337b5,67583c5d,3690c0cf,a1c7d820,14028c9,e401182f,a4f16ce9,4b9646be,3facaa70,e793516f,a0e8a142,1a819ba6,718d26fb,938e2795,9069e0b2) +,S(8e33e271,de2deb4d,6444d64,387f790d,14a2b685,4b38857d,d05af743,7a7403a,d82d53a2,c7a4a1dc,eaa011bd,3e0ceb0,e08d73ff,fe9d71f,c913d6e2,89ecc429) +,S(4ffef442,77dba780,e5769b73,feda37da,abd6ef6,2f5ec36b,74593ca,4c19c2f5,a8a30857,378aa0ab,9ef6162c,fbb09f9b,796755bd,67bf9d69,4a186813,d392f854) +,S(878b652a,633805c8,b58b0334,11b9246f,f7e42ed6,ecba6bde,fb737126,e9f57368,2cfbeb3e,d691158c,d3ae71f0,b4a41d42,148c9711,d274820a,d541efc1,56e85836) +,S(ef9a6a15,aee2aed1,46b99ee6,a79acbc1,a0aa0b2f,1b082783,dd40b106,9deb415e,9909e2ba,7fd53514,a1bc4480,2b49c7aa,cffd9cda,19c54d82,6d9bd08e,49e97240) +,S(d5c248d4,1551d230,60835885,5db0ce8e,c7814e18,c2d548fc,dcfac207,645bf37,f9c5e89e,7bf01f82,8cb78c88,c14d50a8,3cbeb45f,82daa9cb,3c3804c1,15a36f05) +,S(edbf25cc,a526157d,9676e614,81455682,6dad0c0f,96ec289,f2c5919f,57227d1a,6845488,be056456,4a833c13,70d37257,d0ca701e,f6e574c7,409dae02,ee99554d) +,S(5c12026f,b8e2e376,2521f5cf,cf9286b,14be80b0,dfcf378b,26fe6ea5,4ccf09bb,3d98d5ef,4e2c6528,7950154d,581c9a44,94b81a50,40ba9047,1bfa6758,66daa596) +,S(c27e6243,5056055d,614dcef7,f67338c7,ae728bd4,af3970a0,b434d2b2,e48e2d6d,76b586fc,703cf946,f78839ee,bcd28c56,9e372d97,856333ce,d82137aa,7d8525c9) +,S(a298c704,5140186b,4d424e8a,f98ee604,7f67603f,ab14a7e7,b96daede,51abaf8a,4dc70158,2a1b1935,4a5b430d,b4a0c21c,463b779e,ba72f108,5d7d638d,68108fda) +,S(e1fce957,82dae8b0,ac204fb1,9496a332,fdf40014,88ebaf07,3a62f33e,192013c4,40517ee5,d5786ff9,6aa2b50a,a77a10d5,e8ca6439,44f308a4,a264e367,1dd02f4c) +,S(e719bfc,5f06b800,8e4e49bb,62361544,1a2b0c42,f673f3a2,1e139bfc,b097d6d,f0c83c1d,83f5df68,a1e3929e,e18c4945,d14e2c33,4f9165e1,a0a462c2,aefd7822) +,S(77766a4b,a9d8cd62,840b1127,7e697dba,dc27c50,d9c8e35a,17f4c38b,50ad0a4e,5b3a2ad9,448327ba,22265ac,86c190bc,60b7586e,6f6e4554,b26b69ce,231b6431) +,S(f237721f,6215a855,f8660cda,41063690,4f2c9dd7,6260c292,597f28e4,348514b4,109daa1c,187b9f9c,ecae8c6d,33cb9874,46f5ade9,d57b3651,bccb9338,1acfef79) +,S(9408f5d5,e8891a1a,3cc4e7a8,a50dbc83,97517b3b,6c5af3b9,f1953f09,a67b3e08,1b82f212,c32f1ae9,c95f87b9,5ced2bf,ca33e954,32d9eb90,ed879ec9,59691555) +,S(b2837655,11707926,c9f214f1,3e90675f,883649c8,8f1660f4,c4f9f6c1,552a7064,89553739,15be8962,e6f03ca4,5bd5516f,be6ee041,519c4131,829b0bd7,6d1abfcf) +,S(ce42ba00,36b5f54a,4ed2a9dc,b6c0d29f,98641331,3f92f9c1,43767bfe,4b78f4a9,6e547292,cf35baf4,768c9179,2f706bfb,39b757d8,2452a802,4a7bd37f,e3a048d4) +,S(bb3da2a0,1a063a97,bec9325e,8d4af420,d3942bbc,42f0807d,8e9edce2,eccbcc59,7c28e7aa,bc39907f,ef58a19e,cd6e7b2e,25d6eb00,8da14d9d,5c559d27,fad70b32) +,S(25d84c3c,97f3a074,ea76f620,d6fb2691,dd3e9592,6de8eacf,5392c0de,36c490ee,5e0e7745,88c8a9b,7b91ffb,1ad6fd27,4153096c,9e759540,16f73a43,16d5651a) +,S(8baa3bfd,ca256f18,2e55a01d,e7c07617,7649942b,e743b4a7,faf39446,84d5765b,6147e897,8bbe15cd,171c2816,4730b211,587bfe7d,7e71811,7f308b80,d30506f1) +,S(507d6a0a,5b7d0385,11c65dea,8024c706,4d3b6b9b,287c7192,74c69797,21f5170,139f1647,70ea83ae,47ea8141,c3ae32bb,c12793d0,ce30fb37,2dc3adad,7f7bf5d3) +,S(7c6992f7,a059c5be,99b7354b,10fc217c,e45620f3,b4ff30d6,d640fd3a,26bbd846,964474e,fa63641c,2aa7062d,7139fbec,1f64e6a0,50e1ad03,2741a0e3,b5e0bee6) +,S(f62832b0,1bf65b23,14850750,9ea6f157,3d5e3317,bfb0a38f,cfcc6692,5a698bf2,d7314810,7b8fdfd7,3f6ce6f8,84f375bd,1546cc3b,8c75840d,3668c2a6,54c1ec95) +,S(aed21cab,d8e4ec36,2b4e2091,3be3c7c4,594f628a,cccca657,deff8b9c,6bd1ebad,f800ef3,833c7ffa,a8ade1ac,2f41d456,b880a205,60251dfd,f9cdd672,bb7100f8) +,S(46de78a9,343a9a41,6b91b877,aca94252,9e0ba8ca,b6c01f66,e06cdfdb,714bf405,c1441252,4f3ea73e,e12809c6,f19184d9,81f30b87,8df8bf6,6c89d98b,ed4d2bcf) +,S(2832b5b8,ab82e932,5356ae19,3043b99b,ba4b6591,a750a174,a6303b42,54bd41bc,c0363e03,3f59f149,23ece534,cb86695,a8275224,f490849e,249e63f7,34aba440) +,S(5b57c502,4b5c1621,77cabe39,b0f36bda,d85bd04,2736c7ff,9395f0c4,cbe43f9a,842407,dc0c0473,f1bf57b9,b35d84ed,b282ed4c,7adccc06,8530c8c1,bd20766c) +,S(b384da70,8063758e,825bf821,196b4a9c,814c45d8,a9edbaf3,dac4cbb1,c1c2f103,e6e661df,6400cc40,74f92596,590757fb,aa237515,af30ed13,df30befd,230fa325) +,S(36ffd991,563e448a,9b0a5da9,61a5466a,82a5b672,15ec8f8,e7300c5a,5c9a5e1c,97067835,fc17d47e,94187320,84d722a5,d1a742d6,4b513b6,32aed897,bb961c) +,S(8367e452,57c20367,e4e60ecc,33adcd87,5b9d142c,c6c362e7,f5aab34a,ed89d81c,fc7ff090,3ffab26e,d38a9e74,df43819e,b77ce2d5,bbdcf27a,f1f3bf19,948be121) +,S(f6ce47e4,8cc9296f,b40539e2,41238658,4719fb9,d4b1ad17,9c98969b,dcb0564b,368d2b6a,fe5edc0b,6f159017,5cd192ae,b524a606,7800aa60,930d60a,87950e1c) +,S(438c23e4,bedaa6f0,527d20c2,a725645f,194ccb58,8ff9eac6,5091da7b,f9fae013,54620a30,c7218257,dbdc93b5,3722a213,e28dc6bf,f8e48b45,6d6131a6,92ff15f8) +,S(1cf672f8,cc9434bf,7ace8722,85db5017,a1fa1dab,2eec7fbc,84e8492d,86bee7bd,d6d23d25,8bb4dda5,957ccced,b767cefd,8932b511,e2479018,16734bc5,b5cafdcc) +,S(47464e12,b0fa29b6,6e9cd157,4f7155fd,94305263,8af28bf4,4325a23f,3e1a2861,209a41d5,3bcdf566,5e966e80,84869a83,a2468db0,a1b19e56,81da864d,a2b05141) +,S(a9adfba1,c884c904,e6877a0a,9bbf73ae,c4ee223,e0b02ff8,717c075a,6aa964a2,ab16101d,a7bbc35c,73f371d4,afeb527e,b2d809a0,8487a36c,6cfae404,83f79dc8) +,S(2932fede,10600312,5ac983dd,659ecf95,824421ae,5f417f97,d3101c6f,c58edcbe,8601a743,e666156b,f2e34fe0,6f4cb11d,2df54fe1,7c842176,e1075423,dd76d727) +,S(5abf5528,2f87ad04,202b62c5,8ff7440c,64f9ba39,e6989df3,e31d665a,73a50216,71dc4e16,f2705c02,2ca1b37,edc5ce0,610b6f57,282d69c5,d3269295,5a1fabf) +,S(419495d,9a121cad,41887fc2,82c2c7e6,f359cbc,d24093ec,57399c3d,a801843a,9152e197,40295094,11afefc7,83990732,d5e6617c,d8e389d2,956536aa,f73e0c31) +,S(fca38482,ea2be49c,3c27979a,5acbb158,a902bc4e,226f7eae,4165ab7a,29fbc3af,1260735e,5fe62664,90a35f0f,7296c441,bad50a75,7b00e34f,28856a6d,cf46f5f4) +,S(bcf05123,3d703688,aca13530,55bc3ab2,d499ec40,8c912de1,4b7af456,55065d06,f32657f1,645690b,35484e63,a3456885,c16d4991,7670e71d,5f5cb65f,a5fb8bf9) +,S(4e70b42f,6391b424,b159cf74,f5fc96b2,68bf6cc4,a26658e4,79dd8a4b,8e9a92e1,8ba78811,1af31c06,77b24fa4,4b6ce356,66c595b2,3fe4fd36,591b33f7,e53b3688) +,S(3fe853d7,331c60ea,c213703c,a7628dc1,3cdb83f3,8a25ce6e,1be84f0d,e921742f,fb7dbb77,c2c6dc13,6f596154,f24dd3,f27b5125,9b60476d,b230e54,5ddca5d6) +,S(d803377f,c3cadd40,a2aa810,4e97641,ca42f582,3ccf65f5,ee726349,f648b9be,6357b84f,281a8080,54ab7fbf,ecc113ac,aeed2118,5ad12900,d824719e,8fd6fe99) +,S(5ddfdc7b,6f9e7162,2b7128e,77fa5ed2,90a05114,d6d8b845,94106c9e,70bebe1,23eaced,fa1efb7b,fae74c81,a1d03066,714b6dd9,1198e1e9,d5911ee4,55cd76ad) +,S(5f150243,c964948f,e91353e6,b12d167b,7913b46e,d7214411,5bc4cd4a,3b6f7dd5,36abc949,7a2fd102,14991e2,ba360c4f,b18147cd,955754e5,71cdd4d9,b8af903f) +,S(24b4fc97,5b0c4429,7a4cc89c,2b127eff,539f022,61544e14,97969bac,50942647,bd3e3fdf,54ad07d8,5faf8881,9014a77b,11d96f2c,a43cb8f9,a823a257,9eb5c207) +,S(a020eb35,5556b5fc,9de5ba2b,28644187,f11b18ea,ae61e76e,1dcce55c,e42202e0,9a71ea1f,1ad2f457,16b667c0,a982e2b,9765ac6e,beb71880,27e9059d,56639f66) +,S(60b79064,f7173eac,60531de5,961c47e3,8a224c78,ccd58a0f,86f6afda,e1f37a68,3ad04a4c,f6a47d6d,6b9fcbae,d8b54a7d,3437e4e3,627256de,cfc5f38c,490786b7) +,S(835cf1f2,b57d1e54,4ac2d915,9c8e3fdf,d2e233b5,d1109685,1777b7e3,a1f7d60b,7d23dd35,136edb13,bbbf7733,9e1c6e01,a7112f95,7c929b16,1665ca07,f6a84b31) +,S(faf74350,1f1edad5,2e1d8ad,e4b319bb,606cd7de,3188cdca,b1d39527,837f77ed,dbbeb0bd,bffb580e,4b9a0fa0,39b7acff,fbcd11b,85751476,16d48bdf,fe21bcc9) +,S(396c6fc3,e072bae2,3e7f74ed,f121271d,44091a5,d3b2a762,a39dd77,d2de938,5de522f8,a143544d,4cc49940,96b8f54e,9fb0e076,f46aa479,9e99d162,de6fa667) +,S(f8ab940,ad8df2ca,1c2622f8,8ef20c,ae8e605c,1e43b684,881147ee,d44ab88,99fe5281,fa7427ce,c9857163,f804c429,630d28f5,33e451e0,4063e70d,ddbff796) +,S(a6202868,af6dfffc,1e122219,a829c374,8197af4c,95901e78,75841b46,bd772367,2607a20b,c82a49c1,4fa54eb6,f8d68d8f,fe9c4fc4,d83b0e4d,145f7bab,5e9af45) +,S(b12d1993,49a98616,90764484,23a4fdbc,cfbced5f,b76a2bda,4d7c4984,7067e41e,a66dd4e0,ac6c8ab1,29045eb3,f7014449,73fdd555,7001b7ec,99c33d,c2d75e31) +,S(8dc8f55,b4990f5f,c6cd3b97,b1938304,9ae0a734,5cdc9c64,fd67bdc2,15eb3b3c,1be7457d,62cc8fd8,cbb54cc3,88722f4a,c00ce438,c847c2f5,fa641119,e5435d83) +,S(2c0b7337,d1db9e4b,7d521c4b,36351f65,f128643d,add0c53b,1b6d619c,658feeec,e8a27b9c,eb7c1219,f7bdae62,c07cee15,ef765b95,3b082d9a,d8b99005,b39bad53) +,S(891fb4a2,50100689,a48a0d1d,22414ab2,b17ad692,bb5f0d0e,66d06c93,da3bab35,41685166,cdf43c13,be93c03b,c347f3c8,52d06c0e,661a4c7c,cb53e24,e7260f6) +,S(4a3379b1,511c440f,e7213729,de668ef0,39fbccb6,1f5bbb02,ed99ed3b,69ca1738,b12a3dc2,39e9191d,a89d75ee,db44ce88,17b3bf03,d4172b00,39d1464c,a3ac0f6f) +,S(b8b2a7c8,54936bfa,62da360f,83bf8d65,7dc58e3c,1c8780d2,2c57061a,5f815521,8f922c0b,7719362c,25ac7001,252a89ba,1cd4412c,17c2b021,c065a3d5,f6a2d15b) +,S(9066fe19,d1dc52e5,7a9341d,77cf73a8,2fb56ab6,22c97a7f,f0191247,db9624fb,23d19b43,6ec3c575,d81d4929,eb6789a4,c281f5bc,abbc896,2153e7d4,711baf50) +,S(bf9ab14c,19c9e9b1,ca1a18df,2b5b73ee,9f32c8de,6e6757c2,b0534d75,7cced8ec,ec969923,3c3863de,aa72418,837a3af7,85e79375,d5bc91dd,481f174,e9759c0) +,S(68b2686f,9c654a02,225b7e69,e8eb7aaf,78c65686,e885b1af,10265e35,316f9d03,1d3d7504,846826bd,8554d407,739272ab,b6b407d6,f4f7419a,f284b81b,f14da9c3) +,S(20dc8385,5251a21a,94c989d3,92c9f36a,4d3bf669,bf7bda7d,e0427003,710bf2fa,217e6ff,713d329f,f9080c4b,3608c877,975d6794,5623e24a,974760f0,95aa749f) +,S(f0beb49b,555d998c,a39859bf,8c59184a,5c822e46,9a875568,1689a1ca,b5fd0368,e0e05ae7,a23ddf94,ba33b3b3,a75d3f4,2e8ff7f0,160c32f5,3bd08b40,72664aac) +,S(8f1aa973,270ff9eb,a41ad8ab,f2cf4c44,16ddc1ca,dc8a62cf,aab5a3b5,c4a0ee57,90aa3660,e3409b17,a86a441f,12f6eba0,2bd6bbb0,2b9a0a87,71e30a6,595920ec) +,S(c71eb135,278dc147,60cca847,a934b880,fecd43a8,aac9dfb,41382283,928a9957,41667f77,485281b8,89307ad5,decc7f6f,51d23ac4,7e71b299,a9d8715e,b6003804) +,S(e900726e,50d66a9f,37d09df5,d4965c5c,fa904d3d,bba1d180,b0fed651,bec41c81,d520aa30,db036f40,b34e64f2,cdc7d7b3,117f7725,786e9d5a,921c5f09,71028e39) +,S(940ab0af,a15952a9,ba3a6d6b,720efde6,58d72dd7,4f87cc3b,edae63b6,123fa38,fec6d747,6f788a19,b85e443a,a49116e1,6e5061f0,53c40702,f8765d28,f3bfcbcd) +,S(9a13de6d,643e9866,4df3ce9d,412c5ce6,a03ba46a,640c6be,8b62e70c,a8c76949,42388296,6c2d8d87,8b4c914d,4bc6cbc9,a4601630,2eb6a499,6103953,6926dd5e) +,S(438429b2,b31129d9,4a86b149,7d7f62e9,b76d6a5d,bde09d6f,256f83ba,76c577c3,e4360186,a7229be1,b33cb600,be833bdb,b2398e98,7c46c6cd,2e44f932,5cbc1c7d) +,S(3f63b25d,66d472e5,fac7b524,e4300e97,c8bb59be,6a3a8f01,8c1677c6,96d02605,4587042,158e19cd,2bd19bbe,5cff2c69,d9971aa2,fbdf649d,44c95f3b,50ca39dd) +,S(661fdf7,17c7a520,a384f90b,98dedef0,47afe5ed,6cfbd3d1,e1735c5a,bb8cc0c5,bd9a243a,b43c0e19,2592f00e,a52f820f,b83b7433,b1d96549,d9970293,7da80abd) +,S(b9c1bb26,daac6af7,d0c27c36,7ea2d4c8,c999d7c,75bc58cc,279c5f89,5ab951ce,a4d3bf34,a42b86bb,7c66c5b2,eed5d7f1,b872d17b,b58c938a,767b87eb,1b140f4e) +,S(cf5ac4a0,fc6cd9d8,50aaf473,3efd2bb9,7d9b23ec,bab5d099,9b11bfa0,b127e8fa,44926316,c37f1718,7fa94fe,3a62caf5,ad465d77,fd484287,2caf1605,f91070ec) +,S(aa52b2af,ab8da32e,3b882c57,ff0a34fb,749caaa1,b3c29b74,13c86471,beb3b422,4b562728,4a7be595,1b68df35,e320252f,73326084,16c60244,ac4e3ecc,c0859ce) +,S(610f22e,b3aa08d0,a9f2909c,546896bc,7926b056,7987217a,d347f183,4868211c,a52e190d,f35fc4b3,19571e6,166eda3d,2dbf637b,c27746ea,c1bc3552,4819e6bb) +,S(13f24c3,a485a58c,e0454330,79512796,db65f15a,4265fb44,acc3cc34,c51a6d80,faccbfb6,18e069ff,3cdc4327,cf807366,f07976d,b24fae61,1a44984c,7f3bc3b) +,S(15cebea8,49279b29,cb0112e6,922c5a85,caeb18fb,415cebdf,92285d9d,a0eb0f24,23e5ccfe,158ff9bd,539af7ed,4a77b1c1,c36de452,8d0c0d05,821e89f8,e075d833) +,S(2605a18e,fb7d5367,dc41b1d6,24d61a,cf92e0c8,96f29a5,5f2dc872,4d97f6,8d6a6774,f111b7ec,dc58ae51,80ad6fd2,fd6d674c,9402e2f4,f944bd50,5e66d375) +,S(e588e272,a78756f3,7fa36d6c,d35b362a,25cd0513,3694b56c,33d0b05c,be7f9995,15beb983,20b84296,9b8715c6,ad23e53e,115425c0,d071917,66e56ffd,5472fbb7) +,S(80032522,f264edc5,b6b205cb,f79ca7e,3a02cc39,93458b6c,cb98750d,bd6b46a5,479c92f4,fb4e1eba,98f8b93b,5aa9725e,fd2c1de8,d4c3d043,bca7183b,851a44a8) +,S(950c040e,e1a581b5,70501308,a21287e7,94b525b7,f916d3f3,c166a2fa,1641bfaa,e43db20e,911d70a6,9f171725,f760237a,52441a88,dc385a75,1e4ef1db,b738ea71) +,S(e899ff36,423fee57,2e70aeca,db8bc0f5,a634b9be,282dd875,9db5500a,86c391fa,7ed97b0,dfe6b68e,26710034,f87a911,88611790,cb18a790,a0248c7c,b43a9bd1) +,S(d236688f,c206b7a,8f8ce5c7,66e19fb8,6a7415d2,9c57845e,8332a5cb,d8a1a51b,72f2359f,e3d54a60,fe6d6508,5183b525,d5098887,55219113,adb05c2c,656ec9e9) +,S(8d3d7c71,da4b2f24,83e458c5,85c628f5,430eab5f,ddc2686a,e94e2fa2,119dcccf,33c408e4,7948f20c,bd79c22a,d647ff1e,1f435c03,1f594aad,82778f58,1f61178f) +,S(320f137a,e8918199,51a542ba,5d1063fb,fee4b750,c56168a5,87d7fd9b,b72651a9,b840546a,e2a4e1ef,32275a02,153bf003,8603698,a8c5e232,6795bcf3,d3c402c5) +,S(9e8affce,3fe6b259,f4568607,2d46401a,7546c87f,9a46e0de,8ce577c6,1881352c,d0ea3701,d83b7f7c,260ebaf0,97236525,af8639f6,c53ecf92,73e77bd4,c29d02f1) +,S(5df465b8,1d353987,293c915e,a24121ef,daf70ff4,9ad2bf53,9bec72b3,c61eef64,3206c5ff,5ae4c841,58c193d,40f46083,8b38047c,f33c3e54,38541a7a,d5e690af) +,S(999cd326,a18c350b,f4861d48,826ba3c5,1312bb39,886a064d,6e1465d4,8ef28f58,2cd8ab2a,d6dccdf6,7998e662,99551608,a9fceab0,be884b0d,d418911d,c8b1ef12) +,S(81d8fcee,574d9c16,fa2ba6f4,255460cb,479a6667,4761b4cd,c0ab026b,6bce163b,594e7f34,f5897a6a,3b79a996,f5a69814,3cf771fc,fd7c8ca6,38cb4ac5,98673143) +,S(9e83d724,b9ac73be,f932b42d,56f85183,85839c9e,c953a0dd,4da6d843,d096d278,f8b18cab,fed05acb,89efda95,ac496ec5,d3a000,a4a1d689,a1afa5e2,30c88869) +,S(98ba38b1,3b443c08,aecb1f64,73b2d901,908ec33b,35baa317,64f91144,3e320c3e,343f61d7,fc2232fb,f5d2f972,e6f42f49,d8ece7a,3434a0a4,4df1d602,3f99b84f) +,S(2092ea5a,9adf5eec,5a7a9488,6e970671,5822447b,e6c35285,de704806,52a875ec,ddfb72eb,52382722,a94facc8,e2616661,95a7e9c2,6594228f,304adc7b,ea4e7f35) +,S(f9ee909a,8f45a05e,ac77bce4,ebc97410,c044c639,95a1de76,5b9304c2,2eeb75a,861031ba,93f5b0e8,473e50fd,2aeaf13e,3a39c0d3,7e2e9d51,a41ee4ee,1301705e) +,S(a13878e2,3bc55a7c,b342dfc0,2eea9bf9,5c676e27,c63e8603,c75ce535,35df101c,35c0ced0,3d4bb091,92a2f83,3d3e81a6,233f0585,35c72ed0,1bfff82,7b108427) +,S(e8ec81d2,cd32dfd8,7284cfce,9d80c03,b863a7f8,3a71865d,34f7b1b6,104ae3e4,60be9b77,ee12dd7f,f532b01a,f517bfc9,1d24c4e8,b0865e4e,c6e27227,417648b) +,S(f07cb255,1529dc43,3470b18f,e4e06390,d48e9898,69b9a97a,6642b898,1cf35b60,bd46eb77,6d74633d,59b4b941,2e2355a9,c6e85421,59513d2b,a3297a6,c223b550) +,S(39bce423,dcfda9f0,a97189ae,a60b836,42becd3f,2f2cbdd8,2fe884da,baaf7f51,c1599caa,4b71219e,74490312,7303ec91,f3430be8,14979a2b,2db78bb1,ea2c8e4d) +,S(6da611cb,d51db814,18b3de21,13c9e4ff,58142f67,cf2d8ec8,e0fd105,1e9ad3cf,6bc2f048,3250f654,fdbd494e,bb03480e,f7fe5568,2e19cd70,4d178ff3,41e4b7f) +,S(cedb9c03,8d2e0eb9,8a4a5e8e,fa7e95c5,f4e13a47,79470c70,9a3c9fbb,8b1aed8a,79a2fd31,de42d8bc,820d5d56,ed084f40,46804fa5,f7f5e8fe,eca6ad4d,859a0d40) +,S(7d895498,6d1106d0,32f40458,f6c41fe6,25393f84,d00ded8a,3a07a107,5ae3d82,5d4fb6cf,ff1c594b,61aa117c,7e0ade0e,edd110c2,b2109866,ee7d586a,1a6d0d61) +,S(a4f29162,737043af,eb1e2606,93ecec60,851aaf50,c6e9daa1,75a00c43,d7dc3df7,beebfce8,fb764b15,38fabb20,145aaed3,92265d7b,c4628846,b2726821,c79c4439) +,S(b6389dac,de4ccb08,ec0ce964,e689bbcc,e0ba8165,6680c0a2,9cb162f0,f91cab70,e440c7db,d2d02474,17b2826d,28e31fe7,9ee836a7,eefdacdd,679040ca,50303529) +,S(72ce6dac,f752c36f,978ac2d6,aeef37f5,ae4ee016,999ccb49,27b8aefb,f6fcc9e1,ce6ac297,bbd84403,d60c6d4d,5e01027e,8ad38acd,e796bbc6,7c45f10e,d79bbca6) +,S(efad336f,cfd7425a,560931fa,a6bc50c1,4fb3e5ad,f8ad175,31b13846,6c255f06,3fb784f4,eeee9a11,ec7ab559,71817163,9eab6b09,4419203b,2b422e8f,e15a82c0) +,S(f98d4a2d,4bb2166,7c74bd1f,393ca57,22002c6c,f382b49c,2895deb2,34eaae3,9875e31f,7e3778a8,34750763,c6147cba,97a26f8a,d669e69e,9a36cc45,b56fd148) +,S(768cf74d,2bc24233,2c5eea34,2ac13ed1,2b0d161e,65876eaf,b0b89460,c934183f,42337607,e55b4d7a,f86e9f72,dd06a550,af083b32,e72e6265,4ba00fa7,a2fdc34e) +,S(ac26f3b0,1d05c625,915ec27a,aa916d0b,d34cfb6e,22525c59,9791274d,a5beff7b,e36760ac,89b61681,d1913bcb,1ebeb199,a3005576,b8bde54a,42fcecdf,e94f4045) +,S(dadd4181,741a0be2,e665045e,1b042a3a,fcd9050d,a08d1285,21298f34,1f74fbac,6cf46fe0,da78dd04,261e4e2c,863574e7,f6a4dfbc,a902802b,8056e00c,e4a84f60) +,S(e5651598,ce9e6a86,2fb139ed,143f1b73,2c4e1eea,91a88f82,a6fd0ab9,1a86a3e8,bb421336,69ab6c10,109723d8,ff4d5f6c,770fd8a,d569a21a,9e9efdb2,f1f1ac98) +,S(f26f791e,b4f0f596,39b69b45,401ee3ab,2d47a2b7,dcc3d65,de9e48ae,270f5b02,22e34b25,1fe5bbf2,5183c799,ea45757c,2693c591,633a84fb,e1a9bc0b,470ff699) +,S(a50cf10b,95612f48,7a9da048,a84dd8a3,2d2bec22,9db798ac,19fde68e,623da9da,50107d3c,a76a264,1db9f9f4,7cd60598,ce345ecd,cc3de888,e4c81553,bdcc576) +,S(c74883b9,2736c1b,d5f86a5c,1817cb9b,e917e5ab,5ec5cc10,a1197f1b,a45c13c,e03c43bc,e7393cff,d53e73b,60ea2759,d1c2bd55,c2b7a32e,847f4bd1,2c8beedc) +,S(a3437d0,1741ed88,bb05c00f,629e2c8d,be7cada4,dd002e9c,98dfe800,9e1c0a9,a627e05a,257fcabd,1fda00af,a4d3eef8,fc268e67,bb41c9e,d2160713,847bca1c) +,S(a6cc4988,f179bab4,de98ba89,530686fc,90c00c77,4a3f093,8329ffa3,99c8312d,f4eba473,7db25a79,29bcad7c,11346471,bbba86ef,4f611643,712ff475,9d70b6df) +,S(efb34a8,f5778d57,b3333077,6ca1abe3,9e680183,13936f24,da1aca,70b84dbe,a94a216e,fc53fa98,320878e7,167536ba,7e5845ca,149b2595,2f029878,7f428d3f) +,S(139846d8,1385e6bb,b23914ef,487fb9ab,19ec3b8,3fa45a94,a2c5fbd6,fcdfa07a,4fb7cc4e,599b10cd,a99f6aff,28dfda0b,62d837b2,e8c96aa0,9c34cbc6,acfce099) +,S(660923af,98ba567a,83df6eea,ab53ea62,49c2090a,13299bb7,a538cdab,adf2a101,b28b58ca,b1a29722,699890ee,8462f440,ee2a5686,9715478d,4460f0d8,8c94bd29) +,S(f18092b5,8c7517de,3f389d31,f1a6345a,d2f86bd0,c1dc9a98,d3e03890,f52be3c6,a83e7a04,91484ed7,7dc27697,33b0321c,440ca763,2a36c6d0,7e8a9afd,68f9c906) +,S(e8d0aa0d,1b2c540f,38a6a6e2,5b5fb295,7b700467,648cff74,bfee1138,81d0ab75,a324cbbe,52055c1b,d0cc3f29,88a80982,1abfc0cb,feaa56e9,f19bb8ab,d314409a) +,S(2586a0c0,230a0743,f9613df,51f7463e,1d8ee72d,503025f3,c7d2dfc4,6f526c1a,a29735a1,eb2b470d,43c7b469,4850f5c3,ce9b1da2,47406653,ede03ac0,9816c735) +,S(217cfa88,8d826d46,c31bb2d2,7dd7c8f5,8be68254,e42c0e48,a12cab42,677dffd8,4d5d9c30,9ff0fb15,35f9901,7af91ded,34179c57,f48131a0,6d96b6a,c01ac4ce) +,S(4ea65934,71aa3b8f,9e6791eb,37cfd67,943af3bf,100d7ccb,8203a353,1aedf4c0,feed9ac4,19a302c4,58047403,5c95e997,ded8a534,c88beca5,6c12984,84b7b4c5) +,S(974b828b,51026aa4,ea522150,c497eebc,7d7759f2,c9645f7d,4faac24d,18c7a1ae,c0369da0,c3087336,2566f344,ca81f261,65cd3a03,fcb05093,96d18fed,4faa9d26) +,S(d9815b79,d572d7a5,94dc8ae9,3cf45b36,99bb4544,ed1d5755,529c7096,9c978186,9fcebacb,f5181954,ac4ea24f,508fa67f,5b6c20d8,64ed53ec,d67e358a,e75241fa) +,S(52712597,d9bd4e7,cbd506f1,bd65aac1,478208bd,f9f6ad38,efd2b30e,b8368837,52eca996,ba2cecad,9a0911d1,65368010,68bbf0c1,12d6dd79,aef23262,8b3df18e) +,S(d94231af,d890f5f9,ef70e1fe,e8a8f4e8,ed2fc89e,2b8ad818,6af55de8,449abf6d,26592b6e,f0789218,273475fc,32d865cb,84278ff4,8cd0de27,e0646549,219e2867) +,S(64851231,7a69d956,3b3a99d4,b763eb9a,b661f7b0,714d34bf,e5328a4d,a99a7d90,eb20ba33,515040e3,6fa02088,5a3e9216,1e06d3b3,78122fb4,af4920a3,51d46bc6) +,S(d0a4b11b,ef662f17,98f413a5,fc062567,70df9edf,ee00217,79c3811c,ef68a8c2,d4bb9920,18e16945,c38ef5c9,9ab39eeb,748b7a63,ff4d4dbe,8b329f74,dd70b9cd) +,S(1d89b886,c4b24868,1fbe103d,dcbd76b1,dcf54637,3bd5249b,3dc07f06,985802b6,a339ccca,aacd1057,7e36056b,a3a70c6a,a7885a45,42bcdf30,30d0939f,6369535d) +,S(b6cecdd5,936343e4,f136682f,a38ba0b7,9dbab223,beb0b6c0,10a75cb2,e4dbb256,2935c053,87dd87a2,5bda5d1f,ed813666,5f77d12e,8242dd58,3ba8db03,319f7be8) +,S(84b244e0,a0cad847,35ca6c5f,bf581968,40f1b491,98682c4,28aea50,bf2f8e24,62e28e8c,7df80b11,f5713087,ee3a5d8b,148c8e62,da0de1ba,d8289ac8,861f7a71) +,S(f95eccff,2a908028,39436610,2e377c41,66433159,43feb6d1,638df6c1,cc114d1a,bd0da83f,1a0306cd,b8d1b9ea,189856ee,56d16e81,61b4f9ca,7de38d2b,e558eba2) +,S(7c4cedfd,3e613de4,af2ccd25,59a2dd23,2a1e6335,e410d327,27fef321,d10f55e3,331f2109,d9d00536,c697f73c,672a660d,11d4827d,41306696,cdc224e,e7d7b1d8) +,S(235c2e38,1bf2d829,e4b918de,435e276,f88af866,ed31a1c3,4b9f7203,a0269713,50dcdf0d,2671092e,e7c48614,44eaa87a,815a1304,4600fd0f,f26104ef,a0dbf929) +,S(2a961cd0,9ab50975,517ca488,d1c4a388,cdf2686,c5dde923,76128683,ea07cd73,85c91076,b2ee46d2,3cc0f7fd,e7654723,84f84c2e,edd7552d,d7f93be9,2398abe5) +,S(958bc491,f0afb8cb,8713f591,cbf183f7,e00c4775,93d1b51,a628f40e,4cfd65e3,bf5be339,fa21dfe4,9113e026,af0761a1,b2a09a7a,ae8f6eef,92d50c6a,89a65b3) +,S(6e960ca3,7b5b7abf,99f5a2e2,46b7e953,adb5ccc,6424e73d,dc865bd8,3d5f78fd,53ad4bd1,d5e9643f,5f2df612,ea16fcc8,dcc4b0b2,9ccd5a81,bd659b35,6a5e0e15) +,S(d7ac920e,9272bbad,dd961525,7d91d6a8,e747e4a7,a48ddb5a,8b2ece8f,f0d05871,6381b9fc,c37bac5e,38c0b96d,c098c3,9d4c7620,61b66dc4,adf66e24,f0c87ed8) +,S(9b0803b,1de95706,ec123844,ebe941ae,4481c12f,f2d9c078,b6c1d531,5d730609,160cf3d6,b12afdfc,eac2ed01,fe4b801c,5a5ff0bb,13cc3ef2,f5f0962a,6b3fb1b0) +,S(5d50746e,5b74e006,9dce0153,aba04216,991bd509,f022f3ea,689553bc,a4c5fd88,b0fb205f,d2a14b1b,bdba2e48,429c92b6,99cb336f,b6ed0e58,9276118b,6b259ff8) +,S(e1bc2669,fa27629c,92708748,36008c2d,ef4483ab,c686ecf0,bbd01a85,fcbe04ff,6fb7af71,83c0921,6173fd43,5b3a1b2b,15e8b149,3bed8e78,3d409f84,cd95ecf) +,S(cfc9081c,b5a893db,40c51979,7dfa1cf2,f36ac620,cf7017a2,fe90dccb,d8bfbf78,26a88d23,50772fc3,2f377c15,a9bf817c,db321d1a,55c4d659,b5f29ae6,96a69ac2) +,S(54d9c9d,12bd68c5,3961246d,b98ed78c,cd8ad158,8458d4b0,5fad9df4,2229bb9b,b5e97c31,1dec2259,630c961f,ed33d7d4,f8de7005,849225eb,a4549d76,de1cbff6) +,S(8a914ee6,7e9d6619,d00f1924,8735c7b2,bfb11eaa,61fe42e8,d64b5a53,43057dff,1b91e1da,3374da49,8bc2f018,c2a6fa51,99c51846,a2f59b05,a6311ac3,1bc040c8) +,S(d4b81177,3e641dfa,bc704fba,e9ab0ab8,aa2f4c42,fbd23b03,a0b0595,d0240522,ac30ce3b,1ea4a14f,4a5bd364,20f40df1,cf2e6835,17107b8,ce6fbe05,665cc726) +,S(b810a787,c232357c,bb82c351,79249f64,6f3c8e2e,72e0e004,36226670,14780ba9,54364034,1078dd7f,216bac76,9abc8467,4a422c30,f1b7aef7,6a2dbbb0,158319e2) +,S(d71f88ce,dc738ef7,1ad691ea,c3a7eed0,d29c762d,8ec7ce0d,14e72d3f,f534a833,a47cce83,1aaaadae,a2d9d0d9,7b4c5125,97c1b514,95c3aad9,d2a4e716,cfbcd99) +,S(170cf31d,4cac628e,139d9d89,662ce5e1,1ad7092c,cc6c6174,96c99d71,6d147ffc,4fb3b894,e741f585,15e8baa,addf3119,adf6c4ee,695253a4,6f9a5dec,cc6d77a5) +,S(8e7692a3,b1275e80,38ccbf66,ecb9a55b,bfd48d49,4085b4d3,1729a644,ecc316af,f339c1d3,af07525e,26500665,ce66a91a,4fc0bfa6,b8a46411,34cab540,68c504b1) +,S(5d1ff338,3dda5e81,32c47002,ee2b77ce,a07ca869,e7684d40,a27cbefa,4aca891a,a1adb3ac,b0decbdb,6772e62e,74c4516,fe843833,8d2979cf,5b091801,bf5fbb8b) +,S(d566cfdd,a9dec66b,ddf2605d,a37ad558,375e1c5c,5f5403eb,d75ff6ec,3c2b8af7,13e2232c,78586da9,741598bb,25a90a4c,b6007bd7,bfb75ed8,427ade0e,619c78bd) +,S(cbd708f9,cc713af1,999ae74b,2b9ee3db,3cb85bce,249c5e33,764997d0,2fd96493,f01a1d6c,4ca9b0b8,9337a5af,889d8dd9,c264f4bf,6b8066d6,55cf9267,684cb2cb) +,S(fee1ece4,e8ac73c8,8220bea2,153800f3,e8d049b8,f89053f4,ad4b5ba3,f0ed0fe2,9b5208ea,17c80640,a353354a,7cf42f6a,f9763db0,bdb0954f,53d56a2e,ea26aad6) +,S(c6aafa66,de444853,8d7a6c3a,fcb35a8d,db916f33,14c15dbb,79c48bc9,46ee843f,8a61c6b6,7fc590f7,bc81a761,7a6e24fa,34c49d5b,30b11bfa,7cdaf3bf,d1505b1b) +,S(ac351560,83d91f7e,4898551e,7666bbce,dcbe21ff,f005ef1e,a866781,d9aac415,d709d997,77109afb,28c318fb,eeec8a27,5577410b,8da6d494,5ac7d660,1334483d) +,S(a89c2616,7c024b4,81455d19,93ac04f5,7a212e34,95066ef9,21968f72,3d914e18,551d3662,6127866c,77df092f,5ed8dab1,3569ce68,433de199,ac8219ee,13a3c1ab) +,S(9951831d,b58499ea,e94018d8,cfb9162e,b045b95a,fd246a3a,72e8808d,1ca3f06b,fe39aeec,b9d5f867,d5827146,fb384808,81696ea1,5b0d1188,fd487b16,d9e4d773) +,S(b71e17e0,14564447,955be26c,61ecebc6,8615e2e9,37cd2e8c,78d26922,681fba96,ebcfddf1,d21fb8cb,95e3cb22,4efe9553,1a6c5ba9,cc92bdc4,3011c50b,63b9e3bf) +,S(e170f81e,dbdd9ff6,d460ef6a,1c3d4bcb,2fe89fed,4e6742c2,2d683ffc,15914074,93f110ee,f971cac,8ce206e3,df6f9caf,801fa7eb,c7df14d2,d6f67e72,ab96e67f) +,S(431a5547,318d05c5,5ecf04ed,a1fabbb1,4ac8dd8a,47dccc73,acf5d5c8,1ec104f2,3e3188ad,7b141a36,4afa1f04,57ca827a,7a6f1f70,75ca8dea,6fd08bf2,bfa779e7) +,S(299e6a6e,e1587523,2be26ce4,a1f80cb1,3c193291,7f0b5eec,383ffec2,62203394,5dbb70ed,3ad4a211,bfc8e8bf,4c00a055,23c9b3e4,ed3790c9,3bb2a77e,5301575) +,S(66db488f,f2b58869,b2fb5f78,61e7f825,bc99ac9b,ea02b59f,b0978c9c,c38934ee,ab76e112,b51c83f8,b10e997,2f6866c4,6040e7ef,eb14817f,c316b730,e8ae6a5f) +,S(1259856b,66980d52,bb3912fa,78ad5b70,54c812b5,fed402a1,c3c8247d,26274932,ead7cd3f,c67895c7,edfe0557,d5681bc2,d70dfcbb,870c7c22,45d458c7,f2150383) +,S(502c8614,cbb0f3dc,caa5272f,dd252c7c,4269968c,efebecf9,102745df,fdf1cf00,711bc688,7e4e356,fd9d0695,16af0a38,1b2f4500,6487154c,10b90995,3bc53c3c) +,S(e051193c,323c6403,f69c1073,47b6b7fd,f43acdec,17c00c42,2249bcc7,aa8d6fd,2102c271,ce428ee6,16d1d2bc,f25c2630,c574d9b1,87f8b9f1,c85117e3,8a560455) +,S(c9187bae,d768d32,29fd90c1,5c3b37e7,abe7c58,b538acb8,ae0741,adf1dc46,c130d443,f9ebba4a,197d0252,615ac29d,5714f6dc,f27fc0f8,d7547335,89c92c0f) +,S(5b08567e,b9f3b3ee,2b03ae70,1c6b0641,23dba4d4,4e8297a1,6eaec8d9,e90fe897,ad071c15,9079c91a,cdee9c72,6e8f4cbb,914d4b4b,750fed92,aa81a987,a90c27c9) +,S(ae5b648a,c5817a86,cfb06a26,d62691ab,8a9cc554,d0eaa86f,839f4a51,b43ba7cc,1ea8ab0d,b665c22a,ab0a48c3,da17c629,66e75212,a6fe9983,d5e925d,432db311) +,S(3b9bacd0,a092856d,98eea5c5,ccc9abb4,4f2e0d3,27e578f0,42102148,890178d2,b681e88e,9603ba1c,57b628d7,ea929ae0,b79be447,f181a491,1fdc65df,21bd5052) +,S(524df580,a74066da,d522f827,95e415ab,f6dfbf7a,1c1f6d7e,e8d05a86,4659fef4,3facc728,5f3bc1e1,a6fc210c,ad302ef1,9c72c5f9,e358b9c1,ed2aba72,2652f35f) +,S(2e0637f2,ade775c4,87d09a38,3480b875,599a34ea,7fc70cdf,f6ed309d,450e4363,e3c6eb08,7e2f4e49,cc78e903,e4ad55f3,1aafb7ee,ada72369,6da8a0a0,f764738e) +,S(f7fec6ad,beafbd3b,e413fb33,587b9427,3f785728,226f764b,bda6130b,aa0cc483,f646a974,8eb457c7,fc8fefd8,e63b976b,dd42093a,e59fc544,c66531d1,9e08c68d) +,S(75f94ce0,6af64c43,2b6c95b1,2d892dc8,cd6eb497,4d826299,29ad8bc4,8a3608be,bf8716d0,a2b7906a,69316b32,21ec0076,6e32c892,2c7be6c6,22e8877b,b1958a29) +,S(410296de,5e0df3cb,c4f039f,cc869090,f62e07e9,d3011043,31bdc1cc,f3fb4d85,e963579c,a314dd96,ab8a82ff,86265b82,da74267f,c861f96c,383f72ed,3ffecfa0) +,S(cc824eac,5f5e16b,2f7c1703,d97da67b,69b4e698,16cfbb23,cbdffe00,d73ffa05,17c30da6,9f414ef9,5dc58218,27c7880f,d18c6f1a,92afaaa8,b8cf10a3,353e8abb) +,S(acc1b0ef,4d26ed8c,d78f0b3f,d3177077,d2074b64,fa5d8d03,a83ff113,7e6e5820,6cce44c6,8519ae91,19d2a80,4f8fbeed,4fcd24d0,169e8000,11150c8d,9c3ce6c3) +,S(1cb3076e,ccce1d9b,774bccf,4318b921,583c2b8e,31877825,7c2fc71b,c90da922,2a2f276c,58605d,82a17dfd,3ecdc5a2,a6372df2,cf25bb04,c628748e,4ce373cc) +,S(6efda451,2a22f49b,587ea975,9e5a400,8cb3a521,7a38b978,3d5825aa,84fe13f2,11d44ed5,6dfe2fb3,1ff2a54a,de5a2a5b,60673cfd,bcbd5039,54a94758,878e2424) +,S(47f69619,aef4378b,5cc931ec,da8fd996,e2fcf1cd,17de9cdd,51b30c3b,9dbf0858,149556a1,9776e3d6,da457af2,a4d70d66,d2fa28a,c33abee9,bf890894,7cb5e274) +,S(dd3d8e1e,97f5dd5d,539032c5,13a19e26,8b2eaebc,1a47cd4f,8ff48335,794d28e4,7968bc00,20f6a83a,a973d7c6,382ebf33,c2233bb,34be9c2,e0ff9eaa,4c467e83) +,S(2bd454ee,a19d3a6c,be55737c,d3cb4b32,7de2a2b7,50535f91,97aad2b6,65e16d78,a70b0f0,d6a1278f,34271c66,7ad40feb,9f7c6248,87e3f754,9c1f1fd7,129f7f99) +,S(8cfe75bb,2a7e74b4,4da035b2,9a26784e,915462df,13ac2d91,4733184,f5a5ee0,648ffc56,bdc87c86,4f6226d1,c9245540,b65c2da2,7fdadca1,eeff2e24,6607cd1e) +,S(5eff34ae,19c462cb,c2fdab83,24b57bc8,5e046a68,4f112f6e,665b3255,65724d36,198fb5bb,9db347ff,c2289629,d2e01051,d551e783,47c6a6b0,ccfcde15,a04d68a4) +,S(9aa54554,f3673b08,e36db624,47631774,a2c51bb8,1f18aa61,426639f,78f92b91,8744a3ad,4a6e7404,d2e22faf,272b50bd,1d167b46,5f25c6fa,75c8d784,61384806) +,S(4b837575,8cfb5970,dfc7463c,5df06ebb,ac88a2a8,b9d7565a,955cb53a,5ff259e0,87591d42,bda1a53f,6e474396,a1233df6,ed70766a,ab7aaaa9,9171a5e4,fa8df208) +,S(5d4b74b4,9134f90e,673f5a57,959c7cef,c49dc725,85734428,226cc5ef,76428bb1,1b2a8910,f466ee15,abe6bf3f,100d8da0,cdc2f6bb,f19c3cfc,b1f07a0f,bed89425) +,S(d50be2c0,c55244ce,5d93bafa,f62ee680,2d475441,7ab9c2b2,5702a309,57cad2d8,fe207e4c,6ee89ab4,c0185461,7eaa5de4,5a4dc0f2,bc4544e,f241cd5c,162f583) +,S(bb0f61ce,8e0eb384,64e48915,5bf985aa,f93bbff1,416db2e9,a1da034e,1075bff1,13a715,2ddeb0df,30ea1032,cbcb08ef,4e6b0561,31474412,631f6fbf,b77b7d0e) +,S(3ce6bddb,473f01b2,170e41fb,22fc5efa,63e22b9e,14d9bd22,88632bf8,4ddcb2f5,43086057,f4b3d298,426b7308,110dc52e,9a84268f,1bac1edf,8d47a25a,ace0922e) +,S(ffdfb14a,ef1680bf,c90b5490,c7cdb75e,bbcbbff1,a56c3c85,bd37460b,b38f81aa,f3045def,2f1f19e,232880d0,e948b5a5,24f228c7,3bbcca54,7c216ee1,eaf4af0d) +,S(1ac1f2e1,9ab4264d,8126eb60,a2330aee,c828d102,507ac0fe,d59fa4c0,8223172c,7636a4bc,339486af,b215e3a8,f80d8f02,d8fae063,81b4e7f5,133f1936,d8e18bf8) +,S(52534c0a,740e89a,6142957a,a20f2339,b1a1a6b6,7e6c9a2,2d6661ec,adec228e,cf6fe6ba,fe41c899,c1ec2fa5,d884fafa,e1a31835,ae8022f1,365a97cf,3261b669) +,S(40920285,7cd22c2c,78cdccd6,137d32b1,4f36f2c,964a278d,5b9f6462,651b09eb,40c94f73,a5fa3e3f,66dfef1b,f4f16091,f6b7738e,b8a865fb,3bde12c4,2d031d0d) +,S(8b1d3c33,4b9ccdb2,14aac6e4,e840db16,25a5b3c2,4069d9e7,c81bc51,9b029289,114fd464,2acf9599,1fd65898,57822277,8020769f,145f86e5,630d6db5,5e23e853) +,S(ae14de60,b7c7f13a,59c6bbd2,64162dc,8a6055e6,3d3460fd,7e473979,f4a242bd,8b960489,cdb5a333,a14463e2,376f2113,afccfee7,afa00ef1,6cac6a3e,4c65a412) +,S(f37f1c40,99c95e6c,3e8d4e39,5dfddbaf,b8153948,137de420,788386e,2ed3e3d7,1f290080,82f6ad34,b2283d76,9cf76577,a564411,4f51af5,310c0a3,b3fb3606) +,S(1fb07fae,9636889c,34441c1d,3c2496bc,a13f8933,666d05df,aa53ecb2,1b017a84,128189c9,3931576a,c4b68934,b7ff551b,58e6da46,fa97fcb7,b8df8c9c,637753c0) +,S(44d1eb54,e112eced,480ea2b5,1ba22ba7,2afb0721,d0d6b715,52bd9728,4815f3cc,a6e13b28,574c526f,12673e02,ed7938fa,ea1855b7,d5b6e88e,3c3a9b2a,f2ed7043) +,S(6980972e,5732b875,7fe311cf,f76f7bd0,ec94918a,759a7cbf,d8795645,a103238e,7b9fe832,4ffb9143,21776b24,a92fa09a,ac4a0fce,17c5bc26,2d2eb063,63d26a5e) +,S(6a3a8c9d,405bb1e4,de59639c,4f6406a1,a8566a62,9d85b79b,f7030255,50efcfa3,3e8abae8,7b22d04a,8fdb408e,196b47a4,2e0f59eb,9d51924d,ce8de66,cac038ba) +,S(ff3108d4,1598464a,bf5844c4,dbcfa027,bfb6804c,946c3683,1da390b6,4412ed0b,805565e3,3ee1d089,5c6abe85,77054648,11f5d4d0,219cb515,dc072d47,cbd0a317) +,S(ee4f76a,2f8549ab,3e134e53,335dcb5b,49972750,180491bb,2139324e,95517d73,6bd90167,22402b11,68989e89,9c942767,8307367d,8a29075c,8fe81049,7071a838) +,S(c21175cb,1ca958f,36a3b720,5cbaba0c,230c6305,8cd09966,ac78f51a,4c53e0a4,6a2183a6,7a7ca0af,256a0ecd,2c085d81,585a02eb,2ffe6a44,ea923688,cc72bf51) +,S(2d5e4c08,a9a0b398,34e46e39,e7cab91b,953141c0,c5f2d292,c409cbf3,9a37d6fc,7569b9c5,31a331fa,9234f37,e9005ed0,4b512721,dc4ef054,d6164046,75c6e15e) +,S(6302c041,bfbbeb09,cc012408,631765f1,5d573b67,6b799c26,ef7c2a4c,bb15dbc3,32a8f20f,67ce42a0,ac4ddfed,d0932e91,a1e51488,49e463f,915af082,7e491025) +,S(3e61516c,198de08e,f7dc9cfb,89ef9b94,5b6c67cc,2deab08c,a3b36612,5934e2d,1effbbf7,4d5f7104,f7784944,70f62784,5692f3ed,48e4dbe,e956e063,37520d9) +,S(a008bab2,d7d134d2,4ab35a37,8f330521,b8989219,108b05a7,d8aab0ae,e542fe30,77a377ec,903c06e5,463ec2fd,e9c05e43,f5454aea,82b99de6,be09fe31,51b475a1) +,S(7782ff48,b928962a,950f42b8,2e43017,28711467,16f22f8,c389917e,a624005f,78f23e49,38a03e0c,ad1b766d,b9bafe30,8ad2c9cf,5b22bc18,c78c8898,fb608c15) +,S(233b4a78,c26ab44f,d1019d64,8c896eea,f6ffbe71,8cfefc20,d20676f8,27ddcfc2,de508436,d976df90,487ddc1a,48284cdd,f553d342,2e0977b5,18f3ed9e,773b655c) +,S(8014aa29,6eed493,d83d7aed,2d8c3342,3f7a4623,295f2a07,92c5de0c,71b8bb0e,dc58729d,f2a5bc9b,1170caba,4856a9e1,695f39af,81a1e444,f3e6dd55,f583d92) +,S(8a01e90b,233dae71,1bb050ce,7bc61c8c,60882aea,ebead2c1,b284ab59,dbbbdfce,580ed75d,c9e3693e,92c06cc4,12c95a77,b34b72ef,20a51cf4,ca4ddbad,7691fdb0) +,S(50a2349,24a29158,70e6372d,582ba07f,a569881a,96bd1a4,4cbb9232,1ae733b4,6943c220,a97701d4,a79d8e2f,a446fce3,aa21d00e,2f7cfcde,3edabcda,678cc751) +,S(cbf49357,8c96744f,7ab07bd6,182640ee,b51b8f6d,a8a655ce,cbd2087a,eeaa6d83,4d1b36f4,5711db99,404bdb1c,9484a04d,29e79fa5,87d051d5,e75f07c4,ee8d4bf0) +,S(737b3d75,e4edd296,8d164c2e,828b31d8,7c63d11f,fa4ebd89,ad59ba71,8a8efe38,ec7f7ba1,8aa8e515,4527002e,edc8327a,ff1ebf6d,d3877439,e7c822b5,35f31586) +,S(29cb2864,251939ae,6c7f46d6,9d7b4416,8812e0c5,9aaa8b8b,b7e22ffc,ac38813a,c3ec280a,7c98b2c5,c96d77c8,b410ff1b,b5f1eb51,debd38f0,528bb73a,eca2e6e9) +,S(1858aa59,24282fbd,e44dffa2,5197954f,f3668954,24741d35,2c9594fc,5e28fe9d,a0e891d6,b0a69fab,9fbd7879,a7e4ab4c,be50b1d4,4be76485,96fec281,d2d4bd46) +,S(72ce7c58,1a420eaf,67bae314,d4f092e9,26c1378d,d346c4fc,2a9e9174,862eb75c,2329177a,5a9c3e0c,f6e236ae,30858bbb,8bec121f,f7462ff3,6284bde0,7425ae1c) +,S(34c1ca5e,5dfab6d2,4abdcb83,9ddf9bc,a3f9dcbd,ecc315,17bd6f46,af112903,93f6fead,c931cc97,37c4aeb,6a589a08,80088a24,eb49a1a2,7aca807b,22a1f803) +,S(7c5ac4a,80af5867,f803100c,cee3d676,8d348b47,9ce26243,284ba0dd,24392c36,a4468964,903be647,31fdb23d,1ea7ab84,a3201cfe,ab585b86,3370ea40,66fc5828) +,S(be2ddd13,244c7728,1a98851c,8683ff7d,b57bf3d,a746cb35,e594b7ec,4c363caa,adb75939,af8a2cf,1cf3e5b9,2bc7ba65,8c45ea85,47959f25,7dfe4592,3e580fa2) +,S(6dee1f6a,3b3befdc,a4a44471,d62dfd9f,7f7b222b,819979b7,901a1764,8ec13806,5d9e8501,4fa5f6ff,f8c0356c,eb013122,1a9a2431,f641ab6,af3b9999,5c2e5651) +,S(15f264e6,8e2c8ed7,490355b3,a7b11512,c764386b,f6bafc31,80ee6fe7,9de68c19,90574d26,302bf408,ef9053fd,371cf29b,c41291ab,a76ab74e,ddf3f8c5,70326aba) +,S(3d7cfbe9,4cc890c,ea592b78,5a984c8d,6d4c5e7b,183f3666,df9805e,be9c91a3,d55cddd4,4ea7065a,f8f51694,f6a84b54,42b30b48,e7630d12,6827dfe5,e7f62808) +,S(54388bf9,d7951dc,7ab5dd3e,74971201,1ec637b0,7febee14,45b1dcd9,9c3a1e10,17b36788,25dc2a5f,9bc8738b,3f560d23,725f99c2,a9d6fdcf,6fbeff54,aae5a547) +,S(3c229fdd,9a0080a5,948a0d2c,c9281794,425327c5,52063c94,be5f0197,6a088313,34975795,a84f83b4,af883d12,c373c505,192f0a71,fed21d8d,3a8dbb8d,2a926a1c) +,S(b612bb6e,e14659a6,e1691f36,8fa8d7ad,1974e74e,36f1ab26,15705271,27c63210,5948c5d,d623cdf1,f9477733,dd5e8eaa,5240817,e8e08dc2,23b6072c,a4df5bb4) +,S(ec56e585,54470dd4,28341ed3,e900e33b,ae381e42,2efb3d64,d2edefe0,7b05f613,ecd7f151,acf6e308,dfff2bd6,578bce76,86effe0c,d3b156d9,df8f66cf,295e9c45) +,S(1bef3ca,85ff9f8f,bd80c8ba,f9b15b26,a565eeaf,e4d4f08f,25ee748f,fc11f80d,fe0260bb,96be497b,a194b892,71bc8989,125f0a0a,de88b135,272c5683,f92914f9) +,S(1bdbac4a,522b68e2,a90e4265,3d2bf4ad,c4b27e5,a2ebb251,68a083e9,9107c20a,4d60e326,3ede7fa0,10467b9,d2e8b206,5b09e127,e3fba9e,3d228439,50d63ea1) +,S(e9032f9a,567ab8da,551e0f8b,1b2c2c22,6e601b7f,e894b837,3bd9eaad,3662fc84,ac563e6,47d21af3,a0cb0a49,dafde0f1,21d60994,8dcb4000,64e3196d,74eb70e9) +,S(7ce746ec,44af748,a5508044,f56e3467,a9608deb,c8a051a9,fda907c3,8f79c75,8f0879c1,3166bd23,be7bbb80,46f3c019,2c6b8fa0,52fad7d5,40640fd5,f2aa426a) +,S(e0d52789,19de6d1c,a0929856,46cd3200,68862dcb,ef369fc9,6c6de4c,bb59eecd,98f4679d,b4ebdd90,a4f54791,29740bd5,f46680f1,d3ebfce8,8cda2946,ca886b20) +,S(c6a245cd,cf1f4b58,4400a4d4,82f2088a,e28c8b85,641c1f18,a13aea,7e5ca397,d306dbb9,f8f2cb09,958ff944,ab5e6cd1,cb11eca8,33021bf3,605e6768,961ac628) +,S(ff956c8d,9710f082,a1f34ace,c99987fe,4ade0919,4a0deb06,a1b286e7,3695c910,fabec52b,866afd46,1fe8c832,fd8a9375,a8086aec,b0e2e39f,b7823d0c,13bcc306) +,S(549dda4a,d1a604c,d0f44fe4,5c4dc276,5cef1216,6f4accc7,3ff12152,26c23af0,71e3afc0,e05ba826,36eede7,1abb15e1,166fec97,562c4381,a33f765e,100631ef) +,S(66d3df09,21573cc,e69896e8,2dd91f9d,6070dd12,edc21723,2077e644,9e776416,93981613,59a2ee3e,d9429dd3,eaf058bc,9ccf1c9,ea931ebc,25ff279d,5bb46d5d) +,S(61bd3dbc,9426386,9c53ede5,a5c4f186,8a4d7a82,fae1be7,37b702f5,79e4f8d9,8c056a47,e27d4f49,2c9ddf54,efa48c,502aee81,e2336caa,c1b572b4,e082e780) +,S(8a6d8b46,4a31daa9,2702f784,9148db1c,4ef20c76,fa67c006,47d6f3b9,80178f4e,d1f406ee,e4087601,96c82f9e,38205147,c31309a1,93bf4d8c,cfe67cba,ae8f7407) +,S(e2b60e93,99eb8441,700aa90e,1edd981d,37893b42,5acf6b1b,809fd1e4,922e573e,68a0c65f,e394829a,8ae09dc0,ab35d789,bd8a38ad,800e9ed,63513eea,4e19f7af) +,S(4c76030f,e85cfc92,64f16cad,99dfa541,fc23b8c7,2b558574,ac6f26cd,d4f55e85,44b352d8,9a31b4ec,c8f9a574,51855f7d,e98c63aa,98aec090,2d959be8,a12b7bb6) +,S(dcba96a3,59103c35,aa2c9ef,538c13a0,2f0e8997,3663d580,fe454762,5fbaed2e,af9e205f,727698a,de9f91bd,75bfb73c,b13053d2,db2d83de,b4d14c22,176544b4) +,S(fd0497d8,f75fff9a,cbfd3e03,6c9edc73,e682427f,e9b66a43,3b5b2b31,f2dc7883,d23014b6,9c8d1077,ab3fb2fc,c0bde4a9,44576289,896de135,9c0badf,fcd62d79) +,S(5bb401bb,b38e413,43d1b779,54e83f9e,e705009a,eb8a1077,542cc6ed,edf48040,431fccb5,acec1391,f68ea628,378e3ca8,ca944573,ecfa5e,e7a82bf8,82599c14) +,S(1fa96a4f,f9cc6ad8,b2741c38,b35c377e,3acac704,67bc5d20,a262db5b,48bb283b,c3448c92,ffc65afc,f1eaf7f1,f9e149eb,6404dcc7,1b222ac8,bfca8feb,eeb963eb) +,S(9534aef,1ae551d2,7a638453,171d0a63,697ea420,2fec8f11,61432291,642f86ea,cd0c943c,38837dd0,33d48a4e,ca13e96f,46fd7f21,2cbff849,6432aac0,ef729591) +,S(ea72afed,43300390,bc98d08f,3aa4ff4a,138440bf,1a8f8b7,b57032a0,d01b8ceb,e174dd8c,3692cc2,9ca856a4,4eae7e94,af4fb044,85172809,25ea66d2,d858663e) +,S(39593534,3ca2523a,603801f2,abf3a1d3,16569862,35d79fa9,a01f86d4,5c122327,acd3e3e9,2cd76dc8,551cbf0e,94475125,42a5b887,ac6c975b,45d2e000,9953dd96) +,S(d57b2a2a,375e5a0f,6967d4b5,3dfbb51b,4f74eff8,72742a3f,246e3e09,ec2d4721,12d6f848,4d107ec3,10ec2091,3482781d,c0aeeb94,71ae7b03,6a0d2551,d3ed306) +,S(9f2dfc5,1b99eef6,e6c781a,fe0135d5,fc5def8f,d520119c,59bbaaf6,442f1082,8f20962,fd273048,fa3ca6e4,ea96fe0d,7ad1d758,99e25a77,e0f8b56e,5b20dd0d) +,S(b1c30bc6,f030c913,49b36c1f,9c0deda1,afa58776,58c5a16a,9352c1bd,229884b,f8a459d1,6e77888d,cd5c63d1,8a2e28cb,5563e727,f53b59f1,939390c6,1eecdfc3) +,S(8a663e7,40cad237,12dad6f9,1bb5d266,30542933,853e02eb,665e198d,a5c6e53b,e206b399,51175d15,daccf711,63b0918c,786a8fe,2077812,c0c1eee6,bb5c1e99) +,S(2b0956cb,e0ca91ee,f44fac0a,76cc0b00,5f4a5ae8,27e63696,fe1aa8b4,a92941a1,a31e6fa8,dd454eaf,90ee1e11,62627e3,3f84b8fe,da29f423,ddf2a962,386cffd2) +#endif +#if WINDOW_G > 13 +,S(e0144151,7a2ac970,eb6381df,7e11fb4c,6b009980,6a0d330,d5429126,e662c3bd,8238ce9b,a691c80c,21563934,18d18dbf,aeb3fd34,48863a1e,7f4ba360,408dfcee) +,S(be3213e,8b062f33,caf16c53,5a0b666,f344e0d7,1e28aeba,8b215a3,7ec86c37,552523ba,eaca38a4,cd795683,852a2643,550fb83d,d1db0adc,3f1b29c9,7d51cd1f) +,S(623393b6,bfbfbd64,fc7aa1db,9e58e274,1c18eb6d,b5eb30ab,c4fe167e,a9e8ff2b,7c0e4174,f0fd5bf2,a025e316,fa3b7b97,1339a197,b52b0b50,bad4dfe,34e42cd3) +,S(dadeb702,dd0a1e87,669eb624,b8cf40bd,bffe79aa,8afab26f,bc6215b1,dcfe97a,930890ca,e4c29b41,2d660acb,8cd39bca,5a522599,a1ab0bb4,8fbc38df,17253490) +,S(b528d3b7,83179b82,bb1c9cfe,c26184cd,ac98ad5,8e253c13,627fb778,c9362f33,63203af,1545122a,63940676,ba2d18a1,aa902e08,8bb444f0,47c2bd52,db8babab) +,S(2ff223e0,93986e22,ae418a5c,804e9e81,7a4de562,d7436e0,2d025ab7,11734a6a,c5c8d188,ec9cda19,bda76d8a,97838ab7,81990475,d4a00096,5efa79c0,100f678) +,S(cb8731d5,e1e53c9,ccfd2c39,3c8ab1cd,9ec839f6,99fc712f,f946e74b,99eb1742,cd2f9df8,38fec504,dd125248,92ce8a4,a9db3848,e487076d,8c18e53c,f6d19fb5) +,S(1377ac45,d776a5cb,76ec265a,af272690,6dac52dd,be987799,36bb1271,e0cf4a2e,a4b3330d,d5954932,d5a7a818,7d9493e0,25ab2155,d4ed0d4,f34aca1e,c2a04670) +,S(984b9bf2,f140c75f,e03489bd,88041faa,22fbac73,7ac10724,c511a253,641a5ccd,c474f639,9733eecb,a750ea82,ac4d50c7,d82f4c9a,942a2bb5,90b1431f,c8d14ff3) +,S(4b8fd000,74f57cf9,b135d56a,c002bf99,d5050479,7298cc4d,857960d7,afbdcb06,7c044103,1df0f6f7,721937a4,c60cf76c,95560ee9,4c6d097e,3a8e37b3,34c703bf) +,S(57316653,68412236,619250b2,58bd0ddb,34fc751b,8becc0b6,60585683,218b6079,d1d56e4f,30f01c57,48972898,b8afe142,16f8335b,e3a39c37,da64050a,91652904) +,S(c9a00197,a0ff16f2,fbf2cb59,767d43f4,60737367,4f2bbbd2,53c7220f,db69f286,177c6783,d739117c,1de074b0,c605cabc,6b4dfeed,a531f4e4,9cc518,40142f0b) +,S(e23416da,91df23a9,db161618,579b3008,c87b9ef5,7ee8bff6,45eec6ce,a61881cb,e556417f,84043691,e7ec82e0,e1718296,e42fbcf4,a3de0137,93772dd5,70b8da15) +,S(9f96e3f2,369d753c,e6614c45,77bd8a9,14293eee,8a749c1e,3b0e2955,638e9ad8,f5cd1268,1567a4da,71650d10,e413e0eb,9b01a396,e529cff6,b494b2b9,a21ddff1) +,S(48657ba4,b24b0123,cd54317d,de6a3245,ae488078,5ba43d5f,1d94fbf6,b9301fd2,191edec0,6eb53781,2813ca77,2a9021b0,dd4931a0,929a7e36,a4a8c66f,aef0d890) +,S(67b322e9,d72e864d,8cb15511,11402d7a,c6c858c8,77832d4,e0187e69,6a36f24a,cfeb12c2,6b58bf15,3bf87058,c5faa833,e15c867,f7f9a208,c3dfdf3a,c7f6946a) +,S(42e8068,542bdd98,fcce8925,52002db,c545ba13,16082d40,fbde06f0,a44ded15,1645a9b0,c1f33cf5,27364915,8c4f261d,a1ee814e,7aac6402,bf644451,bfc4aae5) +,S(8ee7dce1,339c50dd,55619107,9bbac005,3e058cca,4a8c8e30,7588c105,fe90d4c7,ffbd0af4,8aae8279,2cda6170,5dbe9fe0,98e102ff,1e6f11d2,b4669a81,6ec9d5f9) +,S(abc9504,12926a71,6adaaaf2,7b209216,37a935f0,cc66eece,55978a82,1fa368e6,72e54935,e9b461e7,9fb75c48,4dae4fd2,155a4a48,d3a467c9,624c5f6d,71f79203) +,S(bd250320,81e0e9b5,3b00568d,40378fcc,fd72fd8d,783f2f3b,433ddd1b,a6976ba8,5adb8bdb,85855498,994ca879,717b8e7a,e8c4c87d,29d6a1ca,4c3c6395,6c3ceb39) +,S(b4fb262,fbeee84e,49ae9167,7e7aa0d9,b31609e0,48888740,c018a5e1,8ae25f71,34df3f86,dc091d51,258ecbe4,1cf616e9,265d6d36,8ea3403b,24cdc7f8,e176e5fc) +,S(d1ba9b67,66f24eaf,a145ad14,81063b5f,e4604817,21b361c4,95de8833,be605c01,e80a6cbd,17de2f1e,663ce7f2,8917e3a9,f871943c,a4b8ba75,68476a3,d9e8400a) +,S(5c98b6b0,3a3e5a8d,2d46652d,5eb9e2ab,a80c6702,69dc5ba8,3732752e,922639b3,81e2f9a,145d0cdd,2c51bd13,f907a04,6a35efb6,635292e0,6b8f6513,c50f4a54) +,S(c1fa4688,f75fb86f,61cb7071,4fb25f2e,908abf0e,a87aa84,c8db5dd,4c2618f8,f2f74a77,6d4bf26d,17f55d0b,1aa913cb,9db869e5,ab861d9b,2043ccb9,ca8397ea) +,S(5e806e9,a644eb32,51c62ba2,f09a755b,96aec78b,4405df76,dc22ba6c,f7227ec1,b88c8118,d6a1829d,6aecaa05,742313a,b871d2eb,72f31bba,9d84f87f,a73e614b) +,S(f9d147fe,fd2c1a7b,f623d965,bc7901bd,968636d,eff54c14,34c6326e,d1c8de9a,c7887249,ab6686c7,93a7d77b,41173060,40de44cb,84980c33,cd548d72,d29caffd) +,S(b98cc956,85f6d11f,a8d38a1f,50799634,9f7020ae,3171023b,abea0fec,a70ccdb1,f074d495,3689e8a3,6ee4cc0d,40882355,3dcbdf21,70975f49,5712adbc,990ecf7f) +,S(f161cad4,100817e7,ef9091dc,714bcba6,18458493,f3bb6b03,4648a649,6817b474,b7eeb92e,396af324,22881eb2,45e62515,c4410af9,fa519ffd,61289f6d,9b740904) +,S(7c8b6c89,2ea4061e,456abac2,46edc08b,fb54aff6,8a2678fb,1b7b1c08,5326914c,f08e1f02,6ea1d2c2,9ff5eacd,2b34682,2960723d,cdab95b1,d69c8af,5e7692f8) +,S(4668c29f,16334658,195b93cc,ef71a076,3ab2078f,724dde5d,d3635eed,24f28729,5db228c9,8391ec52,324c723,39d99514,8fd22f7c,2f61cfa1,29ee7400,4c74ea4f) +,S(3443d0f3,9dd6da5c,19a39f8c,f3672652,96fa6729,c9290b2f,4e21c7e5,3167b65e,4b6db639,9a088ddc,8ed31f63,7c079451,14a4320b,b7ed94b9,2a87c0e8,97429234) +,S(d3ce3501,17a04e95,58281e69,3574c096,458dbca9,afac20e8,ffec7810,8bc227b4,bcfc77b9,628f6ee9,3541e47f,8d556ad0,7696ee6e,90ce384a,9b77fcab,6eb9908) +,S(c4dc6363,ad772452,221f8640,9de0ac28,f2bc1ac3,cd2d7080,23301560,f95127af,78c9ba8f,d789a666,439bc949,38345250,38a79c5,97f6a71b,3e096b8b,752d3038) +,S(c771f94,221a47ec,fcd78d7a,123d2e0e,1bf4edcc,bbcdd075,b23d29da,6d5ac666,4dee3b30,829f5aae,f4471924,65de293f,f2ec526f,5b8f5980,d9155f71,ce8d6091) +,S(bff88ce8,96338f7f,5b6516e6,448a1f25,36a1e9bf,275afd50,e772517d,79e6e199,8f3f0c7a,b62010a4,eb0b6211,7e9761d9,c1552629,bb55bf68,53274158,a788c206) +,S(4afcd064,5d57bf24,e850e7e3,d3cac224,6a467e76,f2ce02da,576a1f2a,9a3b97a,52f23b54,87b2af93,6cc692f6,1876d6c0,ef927d3b,c06df93,984ae54e,4d10f0a2) +,S(c4bc122c,b9bf0e20,57f933fd,94db012f,79e23c34,98007abd,f8a8ba21,32b1f373,e40c47b6,a31d81ba,dc45d427,3ab56d77,1daf76bd,7bdf8ce1,a8778861,66fbfc6d) +,S(487a19b1,d1be7791,ce223d27,bab11aca,837a0f8a,7d34d9dd,b4c68f18,51f821a8,a53cd743,16ff4e9a,8633554,45415e35,5552403,7b25ce67,f519e44a,a5d0ef98) +,S(274a3cec,be06c748,7603516,588ccffd,f4ac3d80,a85887f8,10632cb8,4301a326,17a24be3,afbe8b45,9a72cab,5385cb6f,5d06b47a,63bf19b3,ff4989c4,85a9f40d) +,S(32b31f77,b0cb99ac,3bfc34e,7558f9d3,e82fcc6a,be2c4,8a079106,33afa9e8,447b44c,c191da90,e0eb3f71,db804472,17f422d5,b1732a8,993da80a,5d8f5bc2) +,S(78c39dcf,55561468,dc339d46,ffd09337,945285e1,66dfc29,25d8b85a,24a2752,d691ddbb,4e41ca85,eebdf63d,5c023e62,a6680931,5e1109ce,89088467,7ba3ac55) +,S(5fc75911,a4920777,c4502116,deefc1a8,d2f21f96,2b1e725f,a04d6fb3,9d34e5ff,59f36f7f,18f5885c,dff524d9,6a139749,f3fe1662,4b728d50,7a460bb3,497512f2) +,S(ca1590e9,152b2b49,a6d0fc16,4e346e19,fa62dde6,f693b64a,e38289d3,ad08fa8a,46a7bb3c,1174ed75,49e9eae1,7126455d,535ea744,936947f5,24a8ff30,8046dc8c) +,S(5c715266,5ff0bdeb,a7f6e660,bf66d5ad,743d94bc,5ba9b7f1,f3d50cdd,9d11fa1f,7da23b15,56e995c3,a21ee9dd,ccccca4e,e41684a4,f208c39,b31ffe9c,4473a03e) +,S(c7f71da3,6361c73a,55dc3877,4f2e1033,fa0c09ce,1c9557c8,c29d8684,e4177e82,8d6e47f,b5c2cecb,6b22dbf9,a04f0f95,77c6f50c,3429df92,78edb85,59b0dedf) +,S(6e91bd9f,5264a13e,37925900,433b7536,4130b4cc,e6fa716d,a0101c2b,dc58afab,5baa7455,506b5849,5d820c20,f209aa01,ee0f9434,1df5b449,9ed23a51,b4fd604f) +,S(1f00de8e,69ac7cbf,c75c789d,f3322813,244907a0,35059072,68954196,baef0d33,2892ce90,f32330ed,2800c30b,4482b67a,e65fec8,41ba6fea,b2e83703,dae040f4) +,S(c00133f5,7d8c469,421efa3a,d71d8d58,1a2f5b0b,2324de10,91d79145,7d300638,3c76b182,d3ee982,dd05ea45,59e8e31b,1aa3dc12,fdcb67a2,f86434ed,34f18895) +,S(af639e7,95e8269e,12cef756,4bbf970,cdb172e0,66cde48d,2f8e9083,c60cad49,1bd01179,ce92cd29,e414a74,cd1de487,c479daf,5673b219,8082c474,2426abb4) +,S(e6dbd27d,5447c044,18fa0a5d,8ebcb9a0,ede58538,8b73ccd5,4e979797,31f4c9a1,77f38524,f2848320,3d4c780a,d0cf8bd,a2071037,348db8ee,6b5deabe,3d242153) +,S(f51a8d23,c95b70aa,d02dd904,ec1119ea,8d1e3e1e,e405646e,4c2dfd53,336360a9,426b2c9a,1d703cf6,c748871,4959acda,ae5c6aab,51945138,73e4b1a9,c0f46c57) +,S(e12f11e7,fe437b7,f578d8fc,33ae3a60,a3e4d1ac,1ee45863,42944d50,a0f6bcf4,22d15d58,35fa89ab,563985b1,4114c957,8bfec8d6,6dc7d253,e3c6d900,4419f5d2) +,S(e758860a,8ec762d0,62f51e56,d958a14f,ac619351,9d890bb9,bf6bc7ed,e988e14c,42d9e0ef,10b84f21,fb88d780,dcb4750f,10438682,3b003b23,ec41c297,567ecd78) +,S(3c933fe9,ba21e5c,d822b90c,78a54b7a,d4799882,ef91f2c6,e423a398,20a64163,c1eaa0be,531922e2,ca5b23a5,6700b4ad,7fc16135,11f67f96,b672ddf3,669080df) +,S(4757576a,83c9066c,b6eb6b08,e91a79c0,df828e4e,3c09ce07,939134fd,ea857872,13f22fb2,62d77f15,de3e8388,d9270c45,818248e8,9d950d7b,58ee6c6,c38277a) +,S(35e63903,70085140,b19df903,9a7fff42,46570fcd,8661caa8,129d6b4,31045c7,2855f4bc,aa9d60d8,6a44f022,b3c28e84,53cfb3ad,a58691f1,b0e9cae5,e5b9e8c9) +,S(ad446e01,1f118207,3565f031,6d0a85f6,ad5330dc,6a8be4fe,82be632e,32126fa3,240382f1,decee3f5,1f92b2f8,1ac0eab2,1d8acb54,2f730d43,15c194f6,28e83e39) +,S(fbe9e5f3,eb01ac37,820af752,9c4221a6,89164ef5,d77461af,f82d6400,6a718815,f2f30cad,d85a2e0c,e393e088,44de9215,ba207384,2abf8468,47801ff6,12d088e6) +,S(1e675320,d81ff430,a0549aa2,482cc9b8,b9b585f6,32d32916,6e952f13,3b038135,ca0f1276,c9c7d995,c5baa5de,2988700c,2e2c7f1b,366d1db1,b44b4c9a,f0686aa7) +,S(176dc770,23b0e52b,a2eb8068,ad27924b,94c3f643,30e0e85f,3593917c,d6267718,d2dc6288,5df75b06,f450686f,df660950,548d4f6,85d1a701,d510f3fe,297ca8d9) +,S(3c8536c2,32a02b3a,b36feadb,ccc7c541,7ac83942,3cfc8dd,99a0ab7b,41a9c938,a684eea5,249cd12a,d24dd8f1,73022ad1,8ebc7f52,d6a3bd9d,bdc4f5ad,a25186b5) +,S(48aa73ab,c61a76b6,e54c446f,ba881198,ec6ea003,d63c54a5,605a322d,7af006fd,c28c5eee,ffb20882,2d018506,5cf3ddf3,5977fab7,40e4d4e,cdbf9935,8e403a64) +,S(74732762,abd028d,9dad2b36,38baca49,263d170d,ca7e4cb,d83a3a1b,53cc1ff1,ca11df0c,e8dfa09f,3f2ef7ce,5c023b6c,927a88fe,60ba9f3f,ddfbd69d,e536c2c6) +,S(eb71ab09,520e5915,767dc918,814fe901,a4042725,5247c02e,b8672c5b,95698522,5fad7ae0,a7e95b38,ed6563cb,2023b2a9,c81b6901,c007f1eb,8749f56e,4d48e995) +,S(2b101bf6,c7763df5,72eda74b,eb179cc6,af5e8695,965761ce,f8444371,7ef5be6b,dd16c8,4e1d1a3d,98d4629f,ef258421,f6664719,7f89a597,67fe862,3f140ce9) +,S(a099efa8,2c666552,5332b050,75e81ba2,13976afe,8f3b33eb,ca2a4436,6e0ab337,f883957b,5cf1f2b3,ddd6c7fa,a126acca,fb1e33b5,e5b753ab,dc0a99bd,5d136c07) +,S(f4396856,a61c3ce9,5b72ab6d,470bdeb1,8cc107cd,2f58f15,3d5bc99f,8b62f95d,6e3ead1a,a8edb0b0,67240ca,f3274e63,df81c2f3,e1ef2567,cfd76c01,6e9f6133) +,S(da732197,26aabb18,4a0aabe5,a493d803,53215b7c,49458008,bd5e387f,694050c0,e2075f29,17724b68,6bcb987d,85e954e1,9489af4c,e7ce1b46,66d84604,e9a0eeb6) +,S(99171a1e,19596183,f4259c09,b9740201,8fea44d1,4d0f2f45,75f4d66f,980a6792,522b840c,83e1eef3,e7f2cbd8,e07bec0,66af1bd2,e7607f5f,27a767b1,75219a4f) +,S(353cc684,8a2c4f36,2408997a,944889c0,1db7bcf6,9133323f,8f0d34ca,758cf08f,1865bc62,f4ba0156,7e2b283f,702834c8,97effd14,6e0e5fa2,43d5124d,ce67ebe7) +,S(8b16983b,5053d3d3,8e67c77f,1b6fccc1,b9ed7e3d,d57a26d5,deb242dd,7a312852,49d93f92,fa5953d3,956adeed,cff49ac8,caeb3d2,c72a0e9f,be6c85e5,d85d47c6) +,S(68f5dea4,b1da327c,227b2513,83fb622,efb36730,3bac02ef,505e0464,750cabc9,26740f9c,5d624b9d,aed25774,46c9c742,146de045,71cb750c,4356898f,e3d31782) +,S(faf5207f,c3acf00c,8e19d8bd,7208a6d7,cc936706,98559244,e74bb202,20c699b,fab7b446,17a6c6e5,4ac186ac,971de8e7,d42c1527,8607eeb,b8564a0b,cef1936c) +,S(c3d1aa91,b541c5bd,3da04707,a2f01a16,917c0420,a26604a2,bcaf5081,e8d17630,5b57806e,5a58c405,f06d7ce5,4e5f7b45,c9b631a3,44c92c64,d8cd1435,fcd9ce27) +,S(23278a35,4970b920,450db526,391b30f2,54b5bd5a,fe2c1455,623c99fa,8ac8db1a,864d81da,e8df9e47,1ac93b74,660542df,3570486b,fbd2144d,55dee441,90e1888b) +,S(602f6181,33cbca4d,74de4ab,29dcd101,7c12c32b,ecaed25,485765c5,478c0146,4c42cfb7,279ec350,f77d2da1,599b9c85,9ffab342,ce6a011f,91c9e460,27aa968) +,S(1dc4cfc7,126c3b2,5d82aa46,3dcc8cff,c545a9ab,c7962690,fd4ecaad,25843ee9,a9357982,5c535575,35820f17,25e32afb,6002b1b9,2a9b43ac,18225e61,b3fedeb1) +,S(3694f121,6e02bc79,14cd9910,8ca65fc5,887a95df,8b04e8b3,3c6c23cf,ce35af82,7ffee291,b1c41976,d456e742,88458b9e,c61e57c9,9b8386d1,d1c36424,38555d88) +,S(743ada75,a9596420,7b8725e0,af06c2c4,457be03b,a920c3b4,b65922b2,1df1bdbf,8f2b81b5,5ac4c5d8,9cc23ed,92dc1b43,5629b9f9,39b126c0,b16d7175,b40f908f) +,S(bfe9397,7c7cc4a7,b9cc42d7,f044607c,f047cf2e,26d6f94f,210af7d6,b2420085,625d6059,8f80dc83,1ef2b51,dee53d5,666c3dfe,a02e1d92,1260906f,ae373d64) +,S(86c02c0e,6ee646c8,c2944751,7867a1ad,cb56ebff,c8795f83,73e6d8b9,1b240eb9,659b5e9f,da4b1098,b76af529,f56f809,59d39f48,916477b4,bfa66af,c85be4ed) +,S(3b281045,857f01e9,995d357d,3a84dc66,6c4f8f47,4b82ace5,dc3a9229,387bfda4,9948272c,cdeb1542,47c7c42f,1f313dad,e318a123,3f500f8a,16d80e7f,d2e9fd4c) +,S(cddccdd3,b54d979f,504d33d,46d6ff2a,9859038e,33087a3,da9a5284,fefc47c0,9f2a13f8,369313c1,44d91e5e,807ddd65,196c991,a7eb0321,2133aeb4,56683b8) +,S(98100502,a6023ddb,ee34462b,d0232711,8f8c2e9f,33708088,40352c34,870e16d7,1a8bfef4,69af3b3b,1e381c08,454a84ec,4cf8fb66,bd721a57,47a94e90,1969b9cb) +,S(8b76757d,b2fc179b,9016847,9b82124b,c26092f9,b35de316,c90223e5,99978179,47eaf326,588e65ca,541a71a6,a1167321,ee449268,1e8b4960,6eaf9a73,42b16f05) +,S(e66ed7dc,897fb660,6f44d8a9,46b0c61c,45c83bb2,d55ea771,bf2571d6,7ecc3b43,e536f79b,8a9fff4e,c6cffd47,8a405bd,7f1745f9,9374d810,518cc5a9,f214dcbe) +,S(e0600592,cc9c0b9f,8cead065,6ef5c115,ead63209,6a0a0d2,2626aa13,f2bc88c8,628d94b7,8b84705d,16e55254,4c138416,e7f75f5d,d549ff7c,a42d51cb,7f5a584f) +,S(1b0af242,a9cf25d4,cc758fc7,63e2f07,62db2e42,6b392cfb,ffc5ac07,19152767,33ae8aa5,eec30559,a3d28da0,d9354048,592dec4b,2f975a0,ed043fc3,c856a2be) +,S(e204ffaa,142f7eda,3505beee,db0bcbf0,9b80924d,ce5bced5,439aa4d6,af5acb7d,a2804d9b,98e11519,adeacdd1,aef2c22b,a02f7030,479a559e,6924db49,5d8911ba) +,S(afc40e67,651531f6,214ea1fc,13173d4c,a35431f4,92845964,69cf099a,d515ed5,57ef6ef4,1e480de9,32ae8596,3b04d267,5e629707,cd3bdb45,5896d333,b648e0) +,S(59538bdb,747b641f,800588b0,45c0e3c9,72963406,5ca601d4,690dee22,abe8d226,a030486a,3c919c35,4c26547a,3de96087,52ca7a28,5d378e28,652031dc,ec2d4438) +,S(6a91d34f,c38d4028,c63a4bae,bedb2a76,b964cf44,1804a6f1,efbe469a,a997ed8f,32500c83,6a0b5274,2d2ead10,dd3e73eb,45f221d1,ca6cea00,f2b01d75,d9073260) +,S(9260e687,b11d97ee,97dc44ab,5e21c344,332ae39d,c85c2ee8,f7760cc2,8ac28d61,f47df3d,e8d8654e,f7124f5e,2dcd9d95,c1d13e83,a33e5d18,92ce9851,6223e778) +,S(3490e733,7a66f301,f678561f,4b4f293c,b48820c3,dcf9be06,a0390410,4cfe3cba,49591a79,7edb70ac,74f87636,85bbb22a,a8169536,532886f1,f5ea0721,5e9bbd6c) +,S(9729f4fe,1f47a9a3,7dcb1311,ea9548a1,d71d7a81,27803c8a,6ec0a680,8d07b4a0,56e1a5d4,ccc4fd72,8e7ee569,e22efea5,c8f03d73,fe8ab86c,2dcb8af2,eb17f896) +,S(af63904f,6da423d,1cfd77a6,680044f0,5e694eb5,80ccb4b1,c37d8d83,ae9c2caf,6decdc2f,5fe2b948,d15fa10b,4a7e2edd,b8cfaf0f,7c79a400,f3d1b306,dbe110b2) +,S(96271f72,1f4a1f21,a2274edf,87c294fd,403cf0e0,c7b7b1f2,f242fb7a,2c435a3f,66ffbc73,1fc8cfd5,2bfbbca4,49f6e949,71940077,ae411e79,51cf5b21,ca5adddf) +,S(a42ef215,1f0cc5a0,15827287,eba8d960,dfa5a13c,7ee2696a,95bd94ca,4b717c7d,5e491ed4,5f08a591,32296929,814608ee,e3243172,b523a1b,a4995f6b,50046fec) +,S(193b3ded,e770a757,d859c289,68be2780,fc4ce92b,135bec2f,7fb2c07b,b862e5e4,192c4bba,ffbb735e,a1d5cd1,38de0556,d1d1d740,980c5775,22d19b5e,f0716700) +,S(ccf9a075,da6f44e4,cf3b4fc8,26feef3e,54084b0,e2756029,e290a7ce,8c1e8dc7,d04f844d,ccf2c30b,9020f0a2,308219c6,a5d6491,ffe9ba67,bf6b20c9,9a35a183) +,S(7ebea25b,1d69bb43,f60ec69e,f9853208,d3ddffb9,6dce3831,873e7ace,d25b0140,24540af2,bf87d637,54f1a47d,13a3f38,2a948375,8955dd16,fc83e7ca,4fec3d65) +,S(c9eb4a,c2a31b01,9b7ff038,38478b6,674662eb,d729ae45,d7111c63,84a038c7,7e2ee03d,caed3f4e,bef2b90d,78ae42a3,12f6e8b3,29d116a6,e26bdded,81f32240) +,S(45756e0c,8c84e9e,a7b23bc5,cfd87b4a,cd0b290d,86c547b8,7fed946f,e5acd867,9c3f522c,e577c017,3db984c3,d7dc16d0,31326e2c,85b08413,4611da0a,70acdd1f) +,S(1bd58481,21bed636,c789e341,665e2477,59438de7,10aba25c,e4a0db7f,13e3c0da,cb0eb897,bf905399,63a8a7b7,50787430,ffd4d6d7,9589c8e7,350f4351,4786a90b) +,S(f199562c,8e809ba5,84aa80a9,759dd98c,32eda7e0,ccfa4063,547ced9,d9324dc1,33519ead,76430498,949dbcea,33ca14de,2f7ea811,cdd38f32,4009ac7a,b408d1d0) +,S(7fb4e910,e9e37dc1,f56ac3b9,30589522,975319e9,84dcb559,6743d3d4,f45ea6f3,b74a03c,cdbec9c,f36b59bc,fe3203dc,5f4d94a7,bd54c628,55f0d04e,67c960ee) +,S(503d08fd,19839d78,aca27020,54dc4233,c1a1d68a,6b9cf136,4c6fa9fe,886c03e6,84ad95db,9a09eb87,bd905914,473d23de,698459d5,7c436f77,58937bd1,8e448e0a) +,S(335c9204,e6aed3e2,586d0dea,c87158a5,62db42c8,e42fac25,9196083,51e1e713,15b359bb,10f8bee2,940849d4,212fdd84,49b60c5d,d3419ce6,7ef9f0ac,f4c1c2f9) +,S(ba68e5cb,e0f7159f,821117df,5720bb50,f218c298,9ce3f5ef,30c44134,2834bc9f,2ac25bdd,ff34e4e,ff45a2ed,e412a287,101ff447,71c657f3,ca57bc94,40fa5d72) +,S(93d6e713,311d8430,58c20267,739c494b,446d7943,a1e47a0a,2a5ec20,877e6baa,5997c19c,99a2fd26,e0471041,b509f9d,e10bf615,7cd4f24f,db56a65d,201a0856) +,S(7a94bc1b,5cc77a0a,73a84fbe,c5d1b68,cb8f4626,8ecc0c22,ac7500a4,5f397172,128c1c6e,82a4d52a,719c9f8c,1bedf4d3,32d3695,16decef,34af6b4d,578bee5) +,S(f031eda7,c19383d9,45eec848,f6f3e467,75fbe52d,bacadc54,c213c596,c821b809,b4a78d0d,1c17e4f5,db81e2e7,ee52f195,eb505d36,af96bea0,5170c776,23cabab8) +,S(86ef1acd,5c17e082,dd4cb924,c74d0195,ce9f375,60ca7608,57ab7d70,2039907c,6936a13d,b9078ac9,426d34b1,6d5673d,36c3105c,9cc77de1,ef7e0ec2,4cf3bb3c) +,S(fceb6cc9,c78e3a35,49b9beeb,62a14fb8,6d24eec9,2ab10bc9,40916b60,cbc6d720,7c2e6024,5f561f1c,e0b69701,512ca518,9f8d9292,ea75562f,8b17873,77f7583d) +,S(a1d9ed1b,9a36f348,1f426d83,7afe4380,d475e36e,3b140f3e,cd2213ee,dfa5c8d9,3683c97c,a1273f29,ec02cb77,9e9fee54,78bd5e3b,e6aa8c60,7d5bf07,dfa558a0) +,S(d98de999,6311ed55,e15bbdc7,58affca1,3e8f629a,77eb3dac,844f90e0,51bd48c7,8af6194d,272a8ee7,68d1b810,778e5c2,69394353,969d77cc,7d449f2,84ef2a22) +,S(78328db7,cd6afa29,b6f1ba80,d65f8050,60f4d223,9897a3ed,bee8ba3f,a99aac60,e37e496f,1d143ac4,8123377f,4e136442,629f8185,c4996f01,f35c7a9e,76fc5efb) +,S(3d701493,31faf0b,37c1e1c0,9b29ee6c,5d9747cf,cdb26117,223d1f66,e336db5e,d1e99140,8311b20a,b41f7ce0,ab4e9dd3,414ea3c5,b87f88b6,648cd1d3,e77600ad) +,S(f619acc0,47e0d4ab,bd5ba2a,7a54ecc4,e223986,fdbf7a96,e90f762a,ce288628,f24eb63d,e1545d10,fc96a2d7,e7fc1ee,f9cdccdf,cefb5de6,8fa4eca6,781564f2) +,S(cca809b8,71f85a00,3344a851,4f797fce,91718f35,9e2fb489,a1dbc00c,aad0a2d2,b7d72ab8,35658359,2258f260,a1f62f97,aba642ed,382992f7,12b11c11,6890b037) +,S(bbd19766,ee2c501d,afb4eec0,30fba145,aa26c45b,51c1beea,a7d3ed1c,7dc81958,bc709dff,70b3612e,7cf0a6e8,9724442f,6c1ca4ce,c32efcfe,b98f1acf,df5250fa) +,S(6a6fdca0,e4a58197,267a1938,1644aa5d,ca8f0ee8,3a68a5f7,9c34d4af,ec1cfadd,c28b1236,76585255,cc104298,d7ebcc70,6bd7ff6f,cadb0c36,db6517e9,d2732081) +,S(922e3e1,fd401a22,ee7d693d,e52f0ade,9564af2b,17a4be0,2c553216,df5c8006,a7b10065,aae84a40,b9b79e0c,5ca8a227,696841c7,20b944aa,3b9eb1c4,1488f757) +,S(53ffae4e,3526b553,f92bd9da,e3cbd3b3,aff8a6da,d4895490,38382f98,a676eac8,81fdfcae,b51f80b8,3d23b222,8ce860ec,9e665292,c456fd23,cfde43ed,99f8c6f4) +,S(14a0ddd1,c94596f8,9d3e7028,929cfe4a,7c2e70c6,b55d15b9,77227862,a03d119,2b5dc071,febe1d1d,df7e1483,53dc6558,7e8c94ef,b598ee83,806f1fbe,976dd086) +,S(7368240d,fb74f35b,b51a2542,8caf3b90,bebe272a,739eff4d,c0150f1e,3d68c8f9,95392b17,b4c5e82e,774c7168,7c46469f,21801a72,b15cbcd8,fd2ba85e,e4a7a27f) +,S(4c0a8053,b9eab39d,2396825e,2416885f,5fbdb610,7bc5879e,6400d010,20580560,85a222a7,5b7de532,617f67f6,5408b79e,f5a6f826,6083c2f0,93ca97bb,d7db5427) +,S(ca0d66a8,24a6f8ac,bd9447a4,933dfcb2,6751a26a,f5790a1e,91e32053,3ddabbf8,61cc898d,4f8b0845,11dfd49b,1ef01e43,6f7d7d08,a5f16b2,1550f329,79395d18) +,S(646a0775,e62f6a36,d520763b,5c7fb081,a3d7dff7,355cba76,45358a6e,55e9d6d4,3e528844,e7380a64,20db2366,22c936f9,b1100046,e17c66f7,a6b1a01f,7b7dbbb4) +,S(435565ec,f3d6bc13,142d7c47,7052da71,bac77f3e,a81107f2,30303003,6455d070,4ed52896,89fd8d96,343ca8f6,c9f0c70f,ab6edc5c,1ae96d15,9fa9eb4d,a4c9f6bd) +,S(d8b01896,9328544a,a51f22fe,e605c693,7a014aac,37316f,ff6a760b,93aa8f9d,63f51e42,a2b879ad,36d60719,c1497b5d,dd412782,e4c620ac,989f7259,3a06edf3) +,S(b9475950,4a9b3052,94af6f2b,6f182e5e,83a30abb,47f0799a,21ee5446,d63d48d7,cbc74028,37a899bf,79b89676,9e358ad6,9680277c,34ae1018,4290689,c2fb876) +,S(14317c49,2972d5be,c5a01b5e,34842135,d521b467,1b262f0f,c3e6a271,ff8e0ef0,cc4d2235,d1cecfd2,2e6a476a,7db483d9,d318e79e,4c3486cf,c2090651,c2069381) +,S(8bbdb357,5b6867f4,4f062ab3,38928d52,78c4b873,4e95c5f8,fcddd4e4,9d44f8c6,d38d3387,32424054,c05a67e6,c7d00e62,1279eca2,ee1b59fa,90b97f33,5173a778) +,S(7775fef6,36ecbe78,9279786,b996c0d7,380b00f9,4ed31476,1ab0b190,f06aa685,53152a73,162dd659,dce57d7f,cb885c44,34243153,2b8318e1,2a996ebf,2f55407b) +,S(db5e4bd1,39ebe377,bca64950,29e72fb4,bc9b0ea5,5450e42b,a7491c0c,39693b48,a6468113,a5a796ad,a337ceb3,238827dc,416ca20e,bdbe4e62,14194e66,cc5a0abb) +,S(eab057b0,578c52e2,eac11be3,9f069cf1,6ebf0631,709560fc,2414ff11,f1c619eb,5422023f,cf69b8a8,458e5c6c,3c2de1e8,6fb041ce,180c5f75,cddb455,fd023f67) +,S(e955fcd3,c657d611,7e2d43cc,651333e,c231ba32,418e6fe6,d021183f,e7f5e44c,dd0eaa98,65212f27,2454953a,4c46c5da,973095fc,b2e36369,cfe228f4,828e6b57) +,S(5f5a3c57,58eafc30,c311f596,f1d6605f,ec0f5e73,eafb27a7,2a07f91b,42d8e49,3cde0b0,1d1fb2ea,9d85a04a,aa4536f5,c6d9f55e,84ca890c,cf23ef2a,5dcdf1a2) +,S(fb7a31e4,ff0ade1e,efffbd7a,e04af118,49c82cf2,6ad219c0,7572d924,8b99bab,ea87aa0c,431de57e,ee86bc4e,be463dd7,9e69102c,736345a,5502b07f,31df2a01) +,S(d57b1d6a,a3e87779,4b9f8dd9,683ee3a3,6ec18d3d,e6b22b44,e411778d,4bae1ffb,256ffed6,b85bd2f0,9dadb0e,43ccbaec,9fcb9e57,22d88ca,73f8d7ab,dc0f62ee) +,S(9326fc52,d3a24a38,ef0fc90e,183697b3,f726832,c70bcb5b,bd6ac548,cbb8f1a6,863bd0a0,cc0a2bea,d21176f5,c99fafa8,d7d766c2,54d57308,1a58a6f,12889a2b) +,S(58362cd5,abc9b5e6,57617e94,620ad087,d5d310d5,313ef6da,36079b4b,a93caff4,5f2a404,4e86bbd8,d73b673b,2e432233,d6923cf3,c262e1c0,3da48d42,f62fc52f) +,S(7dd488b9,cd06e68f,e01b3a9,6b318d61,b8c4cd69,7e9a3681,34fce81,841738ee,fd7aa5ed,130c897,cb770846,a3d292a0,d963ded0,5266010f,34a99ebe,99782cf) +,S(9bf78b02,524c1554,3330d7d5,a3b41705,1fa2a324,6ba8061d,f9550640,cfe798d,59f537d6,6d2e6801,d79d5a70,3b4219c8,c7d06385,76964f48,10427548,90cf5a83) +,S(4c816973,743ad5cb,18db4f87,9bbd6d1c,e71513b6,eeebfc39,3663dc36,eb3fc47,1a6dc6ac,37a49400,a933ef09,f00f9650,44c6f8eb,d516c254,ab142d89,d41105f) +,S(60636bc2,c7486343,59296408,40f3a26c,173f4e5a,7f0031a8,35c1c56f,b1051be8,71a78b7a,3aed2bc9,70a4190b,d1be56e,efc2e6b,7cf81b08,541dd8f5,dbe88e8b) +,S(a6e772de,c3e90a70,6c663fc9,4d5e6cd3,12211537,40ca4a2f,47a0f3,7f8d00a,25b8fe1f,5c727181,4a6175a8,10aa1eb8,f1090221,d78c32ca,76ba7c73,d0eed520) +,S(79c6653c,60307215,fabb4b2a,aa8bfbaf,1692f613,166326c9,19324e5,7cb89262,36d5ed12,b6b49496,e2b79da4,c0955cbf,c24eaa3c,204e28f8,db1e7ed2,d2197bcb) +,S(3f556b2e,4530fade,d4774af4,ce4454c3,4a2bdb4e,aabda42e,d4ba8546,d646cb15,bab1d321,1ce84331,3be8996b,f5c5c4e2,c9fd04d8,397cf9e0,58829389,ecfd25c3) +,S(eda59a23,8d21fe9f,5e11e0fb,cf731fe2,d645c52a,f3861dd9,3b7273b7,3fb3913a,22f22f01,4ba320b8,2cc29c06,d75b7eb7,d3cea857,40cb2562,4161b9a8,712bbfee) +,S(7a1ea77,323dfb4f,36958adf,71d4f03,3a2bea2b,a9f62cb0,c42a4279,7de68548,4866ce25,ee7a2b5d,a276f976,6261318c,6d2d7f51,f6f41940,f6cc3f20,264825a0) +,S(ad0fd3a,ad62d6d0,bae7c51d,590876e2,33d1028f,62d5c178,a0ecc3d9,a323de2a,88e024c5,9672469f,54f4a64e,b792d761,d163157d,ed982787,a6d40382,83b0601) +,S(1bf19432,f4044a69,56d6e9d6,7b84a5cb,ee743771,8d634dfd,20706cdc,602729d3,4114b200,afb6a1a0,75ef8e3e,16c37e9b,4f2acd9c,3fa4e922,63d1c430,7c516aa9) +,S(514616f2,bc2dafa,8be3b9d5,f00b694d,2fb1af5f,12d219af,c35204c2,e121d93b,3e5cee53,608a299c,f67f4e0a,65adbf2,57ba8eb7,450058a,74072ccf,922eaf9c) +,S(8e3fece8,5338ed31,93721d18,1cff34e4,fdc42330,6a8e1a1c,3b002da1,6921a661,b095734b,6736486b,676dfc24,9cac99ef,12894543,8b333b2e,77664f8,20f686d2) +,S(46c06820,df101ed2,92842186,7d8a20b9,6db1eb9a,ae63355,916d438c,a7ad4447,fcaa10f4,59bb73f,c48d1b60,1147b535,d7d43958,1bcfe26f,9acc7abc,ddf1afa9) +,S(56334df7,1f9b390a,b001e406,ab37af71,3fff8c69,1c2eedba,fec7dbf,cf722b31,22d04394,340dc156,a73c4b0b,f49a6c93,8a3724c4,4744690,4af420bc,726707dc) +,S(202e246d,89045f8c,9dbe3dc9,7ca52d23,b2fd55fa,1b5cbd37,cb882663,ca67c4f,f4e6cf89,9cbcf023,1c9f661e,c4588072,7a6241e3,513cb365,9a2e7b20,a17a62b1) +,S(c8054ee0,10211c2c,f5bc1ff9,43552eff,c56b635c,d65e409d,ece239e9,9b9bd4d5,f50515af,51601cbc,de6842b4,3b854b05,bf1ebd1,678c46b,46e22827,17f31057) +,S(9c29788c,235eb61a,d2940708,4b9701a1,ea3282ae,56f984f5,1c625538,14438383,32111eec,efdbef2e,236469db,4ad30e30,c116cc42,99dd286c,2ab70ec4,9759ead7) +,S(5854e8d0,b7b5c394,7068dc86,f94c3cd6,72999023,367509e7,4bc1745c,19a57ef8,7e7901c5,c06bebd,f50c4113,4e0d2d3c,edafec05,417d45f2,345b75cb,a63eb98d) +,S(8bb2fff0,f45be789,a0446e1b,3547a44d,1104a5dd,9c8e50b7,4d0fa891,f73fef34,c332e365,a5343ea6,6c571e2b,c383f767,efb979df,72223a79,35da9173,73b182c1) +,S(ea88e65,6ee43387,86165faa,cb643cda,992f5656,dc7333c4,5ad8b561,8ccd209e,c38c40d6,4a7a343d,8ab357ab,845725c6,af9f4f4a,843986f1,fd0a83a2,5df0f909) +,S(c0c1d4df,857c7ea6,13322c2e,e0d4ba2a,a3b18ab8,cc8d9ff6,6981d6a9,4446295a,247115d1,e8eef7d,ce6ae1db,ec9be46a,9a284648,ebb7a918,7292fe05,9d72b981) +,S(91e6a4f9,407d3600,2a808d8d,db723ebe,67b8e212,792ba65d,b74e028c,ec7fc72a,ef6ae560,35f58be8,5cce98f7,b2106e0a,12e57dbb,47a4a995,47ee5041,3c5721ba) +,S(cd749618,9a8c1d36,2995cf61,380d0366,24a7a402,e21cf078,18794e08,fb208454,f3dc92be,15d1f912,a03debcf,88afcaba,2dd6ba2f,1d23a4f6,ba02c5ed,cbaf0bd9) +,S(99f5d12d,2e68e70,c304f3fa,44eb24a6,85f63065,af0a15e9,f71752ff,82943018,59f1921a,d97ebf33,68f962c9,c0a297b1,dff9f980,246d5dfb,61168dc1,da0b8a9e) +,S(63c6cd30,f9c07096,11656b1e,75d17191,a6ac02db,9debadff,7b3d602b,b9f7608f,2e439373,70a41b8f,e0e5f0a1,3ab75be4,6d8b1ef4,ee71723,4b73ffef,461083f0) +,S(b7407f26,90a5ea11,d9b7fc55,17e6c1b1,9e04fe47,180b1e93,94cd5e97,5d184d92,1b953929,47dd4984,7420f727,7a6796e7,828ee880,3e0d701a,aed8cf7d,513de6d2) +,S(24979116,161c8840,dd521e96,27a50056,c29ce48d,d86b6297,150f9a6d,e383fd40,13dd71ab,3dd69cf7,384d3e32,5fb16648,76f99943,f7ba3649,143e09b0,28b9a70b) +,S(f109b6c3,6122b278,8656c80d,4c84150b,b419919,4650d96b,6f2de8f7,f9d73b7d,a7457369,bef8d54d,c0a91d4a,39496f85,bd971f6b,4a13dc77,142ead5d,791c96ac) +,S(59b303f8,2031c370,4f17c929,7fbd0ac1,36be9900,a26b5516,9f0e3b6d,69118df9,30c7c4dd,1666271a,5ac8c936,b35068c1,9830306d,c695e02,d6c65ebd,2fd678c3) +,S(6627359a,eb3910db,4ba54cd6,c7b884c9,a678621a,d2bf6cd6,6023974e,d462fc52,bcbcf9ba,d2de78a7,fc486734,79379778,feab83dd,ea4f50b2,555c457d,a910d487) +,S(76fdad80,c4fb507d,9c9d2305,90e818ac,ec7efc04,1184281e,9212785a,dd51f1d9,cc8cc7cc,349cf307,f34adf7e,f559855b,9b88b70d,7fc9d19a,18cecddb,e3a8c346) +,S(7893406,e99cf08a,52fed9cc,4a9bafdb,7f2380cb,4c288700,b983b791,e1313330,ec15e1af,39eafe5a,d081acd3,fbd5b8ec,d0c2e83b,7a5b8074,50ef80af,2511d149) +,S(c454aa4,e8d02133,ed93c229,d0e834f5,18f16cd,d83a39ff,3bbb1ba0,838c81d5,a98e61cf,89c43808,f4895924,529a6e59,8af57be6,debf5f5c,67e3b3a8,73ac51f0) +,S(ff0bc21c,cbe5c122,dd2ba8f9,64239010,97dac1ee,3957b27b,f990b611,72402880,c34089c,1f7b2181,8d4cd5f8,9e445ec1,ecd634f7,52960da,467cd396,77bca50a) +,S(8e4486e3,49a0423b,d8132e39,812b78f0,3a0e61e9,d3eb7735,86f1e279,3731c301,897b24d4,37cc260d,52e1866f,4dc222ed,16bbf084,c108883c,a8a7b9b2,9a2053a1) +,S(4f4ca57f,84f5c4e9,6aca30d2,351089d,bf7fb6c,13847584,590fa5b4,4dc579e7,d53db7dc,1691556c,36f1cb1f,8a1b91a9,33634975,8f28d0b7,17d250e5,ade63a9e) +,S(fe8924b2,d7a24fa9,5c61830,aed8fba,79b3a96f,388b6423,c760aad8,cfc203bb,bd303e29,c6be0e2b,f4e79df9,cb17e0ac,e92c3784,fa8c26a,7e3cea32,d0b056be) +,S(3099f75c,f6a8c72f,8685895d,152f99b3,8ed9a3,320f3fc5,dcdcd14d,c46abb5d,fbb5bc2a,ec76529c,a278a32c,2a95c2a7,4a939c4,c0e2c0bc,6fc20b2e,a6fc9f1c) +,S(3b939f83,f84126f3,b6632de0,12405c9f,43244322,2ac384b9,7415c2dc,9c72f4eb,843b7353,ec454380,e9d4cc20,23a138b5,c1e602c7,f48be55f,1d3c24ca,f05607fb) +,S(dc7506a0,4a50e345,dca3cbc0,6384a938,b032f197,d6d30932,7b0c646d,95c732d8,fe942311,f6d49d62,99f9559a,3d16f43d,c6a39d4e,b623f9ea,e8dde39d,9bd5772a) +,S(f5a4c596,c6996a35,172fb61a,2721d75c,3dde68fb,4abc9433,f84d20ea,83b30dea,175e0d3e,77d2f63b,bb2ef922,d30b962,fd783b30,ef7dd8e3,5ae680bb,9df26572) +,S(7e9038e2,c499049f,e5d222ae,2f79f4b1,373c2f69,262f133,cb9be1f9,aea4029e,3592e66a,343335bc,e016276,6550a363,1d7dc64b,2223bdfe,7146f32b,8025c737) +,S(80f22f73,d16bfc6f,d6c28e92,1f990eb6,e2cb803a,d920850f,af489ff,f62b1f41,8714a5d3,c5ee74bc,73e11fd,24cf4d80,370e6711,c726ed68,2a1bd77e,7b503b28) +,S(498a2ae9,e86e53f8,43470a58,ab96fe0b,7c3107,d9d23535,fc887bfa,fe0c897d,47aa9eb3,73e841e1,4260f651,6ab3081f,7ec3809d,53b8609e,c3cced3a,6401bb53) +,S(601af64c,d14ce184,ca52c542,7a78c746,8e9c069a,80277b6d,960ddf30,3b3a010e,2900a63f,ca1576d0,11b46c27,32c87ef5,56dd579b,3bcd59,9161cd20,ceb7fa18) +,S(8fb2e0f0,7b2fcbc4,ad58b06a,822aa683,957f2bf1,5dd5984,9a1341ff,2d74a25b,7cd82350,8d797cea,b1b386f7,5d5f82af,6137dc9,9f6d6e6,b7c68cb4,75070aa4) +,S(336d780f,e9d14e8,b55a1498,72c63bc,83468eaf,aef3282c,9bde58af,6a69e6d9,92d1004,be45bee6,b8eeba68,2fd0187a,ac3e6679,f4fe0fb0,b723214,a63d2261) +,S(507ac721,f4d58704,4f8d2cbd,fb03aaea,b0634303,cce3e1a5,e4e47efa,90d5872d,b89a398d,e7db05d7,a1055093,97b83d60,9ba53c95,39caaf0e,917d22c8,307174d9) +,S(c42dcec1,3bb7fb96,29171026,f66c012c,992c604c,bea189a0,46e688a9,473ba343,8aa37731,a53223cb,a021bfe7,c413929d,8fe010ec,353464b,e3c1ce02,e54f7bb5) +,S(b02ea2c3,cd6093a2,d5e6b5c4,5c510848,857eedb6,50038417,d9f41947,2a866a2c,ebb45c50,cea190c6,1bb7c505,8cfce93b,ed1d8ee8,c75a5bf8,6ac9c127,2fa5527c) +,S(f4d193d2,9f20ed2e,273dc2c9,aeab43b5,85626d41,59b7edb1,51e17c45,ef70d84b,bda19a3f,19b834a2,c493f8cf,14cda579,1f84b6c,611ea7e7,280e5196,1add0974) +,S(8740dceb,19eac62b,75859b9e,4d0302d3,cc84f6bb,1ff6e857,eef7fb64,fe5f1bb0,a729eb0,4783205a,2e1d5b6e,7eb5221c,f2f151de,1489d1b,1d98fb68,e7c6ca49) +,S(79ec464a,85a29f08,d910bc94,449ce88,50aec626,3693bf6c,92a5ea23,84fcc9cb,77d170f5,b52ed0b2,9aad476d,85abae3,a1d7c544,c625ba2c,d44e68ea,ef53b39) +,S(4f1018d5,dd54bb71,cbc0e29b,255eafd4,6fb3aac0,45889238,847efcce,3207fceb,c32819e5,d23cc2e7,73a9b2a0,271fbe3b,a64531d9,2d416222,24a2f64e,3be7dd8c) +,S(dfbf1936,2094e85f,ddb25de6,8ca85cd4,e53768ab,81780eb0,33a0607b,fbe969a1,25ea0b59,33ba21c3,2ac5f1e4,932debcc,a2ca3aba,e0b7c671,93d97e1d,af80e563) +,S(184c66c0,2c36883,2c1805f1,8612449,940a371,54174f9,b67bb41a,85226649,cf63fe44,f1cfc791,4fb4a24c,1e0530e4,736f815b,a910b487,ec4fec7d,f8662eaf) +,S(daab3606,d386e04e,e39a8a51,a8242e43,ede9de09,f50322e0,a0f410f5,f043686,c0ba1c4,ebe7d10,6fd0d0ac,4e8f6e8c,fbb2b682,3a9d55e5,dbb7718e,d411718a) +,S(a887f4a,5311f252,ba0219d1,f848d334,26b0e216,69020dfa,89dcc339,7e04530f,5a7c04bd,8c37cac7,f429bff3,eda01dce,a5b4fa44,eecd3195,2878f79f,9dedeace) +,S(1b315664,409feb98,4d5dbfd5,a85afbce,4784a907,b284958d,28123f61,7c2d207a,2972cc7c,ba348e5a,5841d463,4597fd57,84eea5ba,a99bdc37,3119c568,aba205bb) +,S(154adfd4,27c30d56,d5f5de1e,d7e8465,6727e69f,82ec8d1f,19dfa16,b1fe4984,5ba86e8a,324b279e,449f61ba,a7fa52df,882477c4,921f2079,98199775,3e0372b5) +,S(debd69f9,fe55c15f,b28df417,cb1af3c2,585fe89f,b44c2f94,94fec0d5,88480994,98d8cc21,55c16d24,e8b1b831,4fcf616b,2564ff,9345fc9e,f8de3cd7,57f9708d) +,S(9fcd3490,2a7c54f9,a2855fc0,9558c465,e0316c3d,fb72c66b,71d4492a,efbaf9e2,a7ac4160,c2b5a416,89e9e49c,8d5aba67,143e1de8,26498be5,1cfa691f,f7f5d14c) +,S(59cacdf6,fe4bae99,598fb1d2,df3de7e0,586fd792,eee0d9bb,fdabfa73,8943a727,7c730d34,7b3ead16,c74d349e,191c484f,624599c4,d379acf,ed8d2341,160df035) +,S(5ce1abd1,fb291d97,db3a4c9e,c4ace635,34e6b373,407a8821,67722fec,7fb226c,abc24634,b4070973,d8a11025,5ff7a81b,a39de6f,5275d3f,7630de8f,23b7526) +,S(f783628e,bd0a0b4f,6ee68001,5b3014f5,e70897d0,ce159baf,3afb1aa3,207d73c,d06438fd,5b96b88c,94a68b6b,1f5fbf32,6c7a6efb,83b2f1df,2849f809,cc39af61) +,S(7830fabc,cc7229ee,35c7130d,b441d2ea,9a988d47,72ebe00c,6c159658,537ba0b3,49e8b58e,6aead178,3d5c901f,a803a33f,78acc889,27f2d57e,835aaadd,1b38fa7f) +,S(c930390e,a8901286,21a4399e,ef9a4a90,6416d549,c28f7482,6252fab,5fcba9e1,fa0e87da,3d0618a2,f54e8fd,d14b4bca,3bab137c,daab0197,4d110ef,b161cfce) +,S(2a0da867,20571917,6f949876,e5f00ec3,ba0924b0,a5e758b5,2d0c23dc,da9cd28a,96cd04fc,69350959,595b4870,f6df11cf,90c1fa1e,cd04ddd1,975d0bf0,fc907647) +,S(f64881e2,60da581a,f576e92e,3968e24,f2bef6ce,dc1c9c53,256374b3,1446fc83,808a945b,660b67f4,43ef833d,b491fa56,2aacec09,f8a2dac3,863b72f5,e7c8b94) +,S(970bd933,5ec5f0d,3a3cea17,5090f1e0,c181e488,1565c341,33017f99,ab81f052,4d1d270f,e284774a,fcbb6658,d5cc019b,8eb30bdb,39464a79,6ca1431f,1ae9fc48) +,S(dfe94b31,24c4541f,4723ecfd,f5cad197,2c058886,9283073,35415bce,e4c4779a,cc283e53,d547606a,a0fafe8c,5d3403c5,d047aff6,8b194b1c,1855a7ab,9540e23b) +,S(f1813379,673ae594,8fa30bba,d8737d0e,16c8bdd1,8f7047e3,bf33a39e,858df800,acd2c1a6,139a2dbf,9b008d50,d0b4d1f2,20bfb9d8,c24855d2,ed54440b,a87d294a) +,S(f4fbc156,fb631bdf,51192bd0,1c0db0c8,8890ec97,9c368f3e,c2106043,6d423740,3cb08cf0,5b07deff,431faf91,e1874baf,9cfccd3a,df487f4b,4f69026c,1fb7149f) +,S(124da4e8,3b079d72,4a7a9a72,5cc45a80,cb92675e,74541bbe,d36224e2,793de6d,3e700066,f12e0cba,4d6200fb,2a759554,1cd15531,ea065e6a,c6fb4986,548d00e7) +,S(749721c4,455e7826,1de045bb,266b97d0,6c2b112d,2ac8c16,428ce961,b78d1138,27556aed,a3f331c2,fe95b237,d3326c7d,25bc594,39f07b87,86559fc,55a3032) +,S(62cdca49,aa58f55,21c60dfe,d50fbf58,257676bb,fd4c4e97,9ff9a91b,7627a028,8bd49b9a,e16d10ea,7ee1528b,4f433e8f,17c4a688,a7148fbb,d10ed605,595c37b5) +,S(64d650f1,39b13aa6,16d3b227,5ed164b1,1cd3a1e8,81759344,7895a4b1,686478c6,deeee52a,f7572d87,f339595b,79643402,f9e2a065,7b95ba42,6b83d87f,3dfa5c2f) +,S(d08a3e55,66c636ef,3417c17c,d8526df6,37cb935e,db00365a,1ecc9f4a,9ab59d,2db049c7,5eec5176,3fcd3502,33856da4,e9ed32fd,24242a54,9c9ae462,240dc103) +,S(8761705a,35bcc509,afa20d62,61859afe,97154782,49ba47c6,f4b8df0e,30f20d89,b34c25ee,bb029622,4929c3db,78046a09,fd43b9e,be2dbf64,436f0df8,adb726ae) +,S(e3453933,4ce22643,146cc317,54e7ce7e,e35f6f4,e37b307,c4e9e11a,3c6f5f85,73ee178a,941e81be,ff22a0ca,f2bb4513,1afdde7b,336a3bf7,ad05c1,d465d97d) +,S(8389192f,6609a7e7,ac8e6f11,fdbfce8e,246b36bf,95e0de27,fac36082,34ca917b,957073a5,50448ec2,9d67b681,ccfb1aa2,67c88976,e53c99be,c68c378c,f2b636f) +,S(8bfd70c0,67bbe25f,e2e78029,a97fd863,bbf287fb,7a24eb8d,e5a61af4,c3c5d387,e2e6c66b,ee7265cd,5a1b1d64,4f24fcec,8b59001a,6edbb1fd,5d894740,f3f952fb) +,S(a5d0999a,a05f0bb1,59a1582d,980520b,eaf82015,68875269,fdb593e0,e6ff257d,e34d9720,5ef05766,676b62b3,62ce4b34,fe6d27d1,a644050b,f9c65c34,c423635a) +,S(44e479a7,b949c88b,507942e3,89ffd9d,17645185,92d4e544,2827baaa,5d5043ce,7b86ec29,8c12c463,b0a71416,24a570a9,e2b10d77,ae12ee23,2504edde,213a7087) +,S(60dec943,d9797811,706e0251,e0abd0ca,3f37bb8d,559213c4,3176ce3d,352aa558,2dc689f4,a31c59f6,c5181448,d6985335,16b0764f,8cc6fd50,8bc109d6,69fcaab8) +,S(5ca58d38,5b5449e6,f93c5c5,35941b98,d4ab829f,e641bb24,af7e7ab3,1f7709b,82afbae9,80eb6f48,110ce090,7f39ddc0,945d9d84,d5d3feb7,4d96581e,c17cd575) +,S(b775967e,a1b1d60c,9b09cf3d,26bf86c3,b9a23ea3,cd329138,10099048,d18b031c,d2b7169b,ecfa1055,70d885c4,adcfadcf,66f12d8c,846f70b7,12004097,840fef1) +,S(73d8d4f6,7d602f61,3c3595f,b9aa05d7,a23bc4c1,1fa3844e,92e6b79a,40220f96,bf722a2c,ffc9fee5,bea18530,9ecd14ec,bb17fb3d,568fe85d,331575ab,2400ce3d) +,S(e8104df9,f49f7822,152bcce,79c6df0c,8b1e9745,448c24d6,1e7b1180,99182b75,dc2fd539,ec8f2beb,1bfb0da0,f95ffbb,e14fc682,1c5d5023,96b1253f,82137361) +,S(ecd72ef6,fb6c432c,8e1449b6,d16180e5,777e5524,4900f209,e89e995c,546113e6,1671715d,358fba99,e509f518,e1458600,4252913e,268129e0,e00d64eb,7a26e135) +,S(e3b5ccf,be829bd1,6f1fc6b5,fa6d7c35,464bfe10,7e9d6455,a9907050,a4fc36cc,ce7abb9b,5471c1a6,de17a2c9,b5b671fa,296cb5f0,10b5ffa3,31e7a87d,a28044f5) +,S(f3591a02,ffab91d4,eb7e75f7,f4ebd22c,41c1ce4f,25f89c5e,d7ca1ab9,27107734,345a2e11,f2bab926,487c7d53,5314bb6b,cf04746b,be2edc10,18a57c2b,94fa4b3d) +,S(ca4b045d,ae54ad95,37d184f9,ffc5a950,c61349d3,227ae1a6,5501ad97,cb45c635,e30f817e,255ebeca,352f3c24,b441d1e9,4660f456,ce9cd72,eaf4c4b4,d7c1d806) +,S(f7cc5740,54a9ea61,fb8ebdb7,b76a95f6,30094720,675aaa72,dfd29bb6,6f41ea38,9d463d8c,fc5424d9,18275aeb,5e046be3,b3dd7fbf,f52d4990,f52c81e,b2556eac) +,S(f75b5f79,fba3e3f8,ee64bbef,7d34e8a9,b4fd9bfb,27b6a9f8,76b1f70d,ed6ab6c2,220b40bc,5c3fb77b,72c48e36,2745677f,7e0e8266,f85a14f9,d4030ec0,90a43faa) +,S(2aa367a2,5060236a,627d89b6,ad0a398d,89d86a64,735a4fde,e88fa4c,d9cd450,2bfedc25,2491b1a,764a802b,c4d77d86,1e70ecff,e9aef8f6,e829448c,d841fc32) +,S(ff7f49c1,11783cf6,e7da1e22,15827b07,a1078ce7,b1eb3257,65a37c38,a141620f,69550c9e,2e48058e,8bca8b54,21251dfb,a488c585,df644bea,d519acf6,54702733) +,S(31d05358,1164f4ec,a45f7338,fd3ebb90,76d017b4,5e679601,6fd02a0b,5c3aa39f,f124319b,72177ff1,462fa90,2e1f8d23,d4d3ea0e,d1bfd1fe,6bccd92a,9963f575) +,S(6eaf0edd,fd1203ec,a2cbf2f3,8da9ad7,c8a02d3,ab5f06ea,bb88fb5f,7e6a3bd0,d9336d01,2d8e9474,49c521a0,10a3b83a,815a0c74,a31596d4,125909c6,73e05f08) +,S(b95a519,77991ab7,fc3943ac,ff5fa88d,68e759c8,11cb91b9,e9a1ba97,7eda1347,8cf2cb5f,446d448a,5a98fbfe,75a2ffa6,9758bd15,36eea87f,533822bf,6de5ef23) +,S(4e5301d4,8ce5edba,f3b1dc21,2e804e7e,1fd386f5,6b90eeea,da6c1c58,211427e8,f503ec3d,e169fdb2,e1d2f684,cbd9d684,dcabaad9,376d96b7,6fb0a5d8,1b9f0d9) +,S(4fd1a9e5,9031b43,715f92cd,c49c2d0a,fc7c2b54,ad61d7a3,9142033c,3cf49cd2,73ecc11c,ab0165bc,3ab4b43b,ecef694a,2d99c9be,8b877160,2c885a6c,8e4adcb1) +,S(67406865,b32543fa,5ebb7fa4,a8d8fae0,384070fa,2e8a4b86,74510099,20257c84,3fdd9ad5,93a4e0b9,4f4451f5,e3227df7,e829a45c,ef3d271f,3fd85896,bbc62008) +,S(14b955ae,d6ee5be6,ef3dcfa0,edac40a0,de7e8dad,19c8dcb4,e4992a65,a46569e4,d4b920b6,21823f81,8481eff6,761353dd,7d9f31c2,5ea9d1eb,ed60a5d5,fa2daf70) +,S(14f283bc,5608d5fa,dfaa0b3f,fe42fd20,4003e434,c6368fb7,22ca5f22,3339ae42,b2415e3d,c3aefd3f,c644d4bf,b0a87fdb,bf0ba630,2baec8c3,7c1577cf,9edb7397) +,S(3fde0c67,7d3ce20a,6e6275be,7f80cba8,5416a55c,58dfd09,8e733a32,1fbd1c1f,9b8ef7dc,610f192c,949782f9,bea1f08,9a018b25,8926389a,1155d033,1adaaac6) +,S(9c55e669,df5f3d05,f15c74dd,48290540,b993bf4c,41dd9247,df5332a2,ed17267,23db0ce9,30c97665,175abd78,33757fc1,8c6b3c32,2d260810,981b4e0a,6e4979f6) +,S(bde84df,ae141a0d,6e8da60b,30f41746,506d2dc3,4b3faee7,d8568a92,82968d16,45a33214,ff1361df,e724697b,99a6c686,900374f3,6c298dcb,468f38c4,4ab3ab04) +,S(1940294a,b8f3c2ca,45f68f45,4c60c5a1,e5d97085,946b30c0,54939daf,c99546a3,563f9f99,3816c62a,1e60ea76,77c61bb0,848bc926,e76e386a,bfd96bb4,ece3b81e) +,S(dd6ea1e0,d0d13e64,7d0df92e,ad22d838,757a34d6,373ccad6,6829fcce,b32ccb0e,c018e9e3,6bf4e8b2,853ad27f,a49e5ff8,384b557c,aa00c3fd,d8e008f0,ee33c313) +,S(657847e8,c7844562,e26656bf,bbc27b84,dc104737,42c4dffe,c0669616,5b7fbf19,dd90dfb6,58b6ada4,901beda9,a4a9a8a,42c6a4b4,e79a4172,5b5f6ab6,95f2df5) +,S(fb7024b1,40be9d6e,906d26c2,edb781cb,49b8e71f,396b8d3e,352506b3,fe3dea6b,de408ff4,e50b2328,b6ad961e,9dd1ac46,fea36005,1407061c,5a0fca32,eb08efdf) +,S(2d29c008,65a7b279,d3a80179,cd3e8944,b3f2be0c,49a398df,a3113350,d1d8e8e0,caaf127a,ee704a4a,65802748,59649e45,25c55005,f2667ee9,92e9d923,daefcf8f) +,S(db690474,79b7209f,4de8d42b,a3c1be3a,39268589,a7c33632,6d87c1cc,53d5662d,90de8be9,5c3587aa,9913ce32,c83e24e9,c58c1fbf,2922c63c,b777770,fbaa4e00) +,S(9806506f,922e4f0a,afd54ada,258d6fc1,723c7087,ccf13f0a,df247356,c941697b,c07e2018,a8cab841,37698eef,3d31cad1,b97fef49,77b277c9,25245a12,f16bc237) +,S(ab868d3f,e6da25ac,5b11c112,28f14621,661e0ad1,e33d25ea,ae1ae7af,60e40187,ee24b698,334a9850,1a1195ce,d57a7fd9,4b12c488,bbd301d4,d47d5f13,3cbf54ad) +,S(e7561fd1,9d2a8ee6,12056be1,74257e28,3122f366,abf66f49,31fd89ee,fd8dcda2,2052e74b,e3656d8c,5c766ea7,3227b75b,85bcb190,8a07918d,5a8a8001,3e166d5a) +,S(5f19523d,84bbe307,be08f2e0,fa844cb5,7b562f01,39950820,83c2df9b,e8f21e6c,3a96fe16,28ee1dde,2ae9ad2d,5724eb88,33377542,6e91acb9,d9be7c41,7265d7fa) +,S(c9fa4668,3c949b11,2422ec1d,c5501efe,2fdcad17,255c7545,69837d28,d9c10cc1,1aaae75d,18f691ac,cf1dcd8d,9e8e0348,b5b6e734,76d47ffa,b5e23ede,c7fd1dba) +,S(1da90e2a,1e911879,ccfa084c,393b8205,1799b2d4,15a42401,b1ab793b,beb8d8c,3d3f7c69,11ea4d38,46cbae1,53b3fc32,74994ee5,1f4fd332,2da4d28e,c89c0b63) +,S(c6fcf10f,3851e432,6bd504ac,b7847f7,707e4098,d8f66915,3e6f89ad,f31b3186,d0ac89f4,a16a63d8,6e36ea10,8f8ee5c8,4e2705af,a9c98bff,3ea5253,93a50ced) +,S(15057a2e,eb56c67c,cb6b7d4e,f1257ae0,3cf236b,1f9b6588,fefd7f46,16378233,4dbab530,ccc0a7a8,c49543ef,5e3d0a87,6f205a62,2f9a90cf,5054bb0f,dc4930c2) +,S(37eeaee0,72d5ac0e,6ea7337d,d07ddebd,45bf1cb7,8c02dea3,6d1e419f,308b20f,b0c64496,5d9daa14,19c77249,a32a3a3d,a5761adb,bf5a394a,ebb91630,f361d506) +,S(5a207bf8,3a8bd0e3,3c71cd96,d928bdc5,f1d6ce8b,7ad9bebe,61a27362,2557745c,3accb757,fadc9b6a,2a5494ac,15744113,ee878901,323c6138,19ec7666,60f54dad) +,S(fe08dd6a,1a0fe325,5a391271,e81befb6,f6b2ee08,907046d1,642d39bb,fbabd139,42c342d1,3535822e,e4ef1b43,69f204c3,665d2326,1379b0d6,c520c64e,181ef40) +,S(b7d262c9,8dfdbba,6483edcf,38044cad,d6d859e0,3d1ddac,a39cb999,78706111,96086350,b308b397,6a007c8f,5181b5ba,30bb4c11,653d689,ee97fe47,28d798e8) +,S(4b12ab2e,23b33775,3ae97d7c,1badf5a,7d354b57,dcc78407,6836f802,34130c86,419d4e0d,9f708bf4,2e11e73,a1fe5815,2bc9649e,49ae45c0,f52fb8f0,f23c450e) +,S(fc6d2682,a96eccda,4b49570c,8bcc47c4,8f362bab,7750b4f7,4f30cc49,d8e88dac,1af56527,30264580,d1f22612,e90597f8,694aff0,96001848,8a243ac,f4beedbb) +,S(c7b9c3a9,a189eba0,54742c40,c4afdb9e,5e07e6c0,e442cf06,32e9b655,1e607e8b,5bb68277,2f2274db,62084cd1,9c1a545e,ef6b38b8,d4dc3e30,fc58042f,f01822ab) +,S(eba4d342,30dea72f,29a339ba,3ed4306a,46c761c2,bb6f9627,3406fa7,50dfd956,fce17a0f,23d278b2,e3da1747,706840cd,d31b01a5,8793506d,2155cbf5,dd237cee) +,S(a4d36dc0,2177d471,35b4358c,6adec285,3595dcf4,6cd9acc8,944a569f,82c04155,85a29779,63b21be0,e378fd0f,b5a60fdf,65f3e45d,c2fafad1,13377f4,81f00281) +,S(4916d063,ae8bfae1,e3f5bf56,fde73abe,eb165aa,4e6d4a16,9060ac95,76109ba2,a7916703,4a0b40d5,f967a08c,a536b7c8,3b2b0b4f,67638656,4ae9b4d4,4c3f22ee) +,S(761cdb10,b2966030,85f8f1a4,404ab49c,9de01979,85817f97,ecbae412,eedd046,1d115720,763b545d,72f8f50a,b881e7fb,9789f0ea,8dda90cf,2ee2f3a2,2e193db7) +,S(d7a2570,4d718e92,df85541b,490bc13e,860ff014,e8ddd9d2,e05fca2b,8dc64ea3,5e454b9d,21346767,71c0e035,fbc6dec6,6102db85,aa3acace,c158f43e,534cb90c) +,S(2af6004f,7962c52b,b0ebcb06,32975bbe,a6b9a99,4dc5a5df,eb20a43f,3d4d3bbe,6988a9e2,26f8cc15,3108e3e,b68c6596,be1deb1b,53239933,d91e095d,d81a14f3) +,S(a92740e5,3bab0860,1127571e,5d33184f,ca805d18,75ba4959,74108f5c,a9504255,5df2851e,2eb76b71,66dfd3d,3aa84e0,96d49c85,10daa44e,68d75eb6,c6d2379f) +,S(90d0961a,510d8a6b,60a87c44,93a0c8ea,76856770,d076057,bcc7ed98,70014939,74d4753c,1c913088,66b6f7a8,a2386ad3,7c13dc2f,85b4b4d3,f8d7603a,ccaa545d) +,S(ce52bea,f2e3a604,f62bfa27,92e2e083,8dd5c6a6,ca338ded,249be611,4ecd12b,a869de73,738a0a2b,7c824444,925f3d9b,dd08670a,8f8ff1a1,a4988008,2d5c009e) +,S(99ca8dc2,10e3fcd2,ffd39a47,1c06ac49,12215441,6cf16be7,cc3e350f,f3cd05c4,78087a80,131adc2c,6bf26309,ef0720be,4550fbe8,912142,c6ce496a,dfbc4982) +,S(be442cc2,9f5a7bc5,d07ff1f4,322deb90,cbfcc6a1,7d8e611a,b51ec610,a202d1c6,6250f2c4,680ed934,8028f2c0,1acf5bb2,fb3d1f25,e324b734,11156128,77c084a2) +,S(53f5f5f4,37fb010,2130346b,51b9b14f,e75d95f9,b8f80e65,67770bb0,e4ec8e54,8da52b53,c6e733f5,aa0dd2ef,23e2e1c2,24c0d571,328520f9,cb1cc5dd,28c62f93) +,S(206ce565,e90ebff,7d799e3a,134a56f6,a897ab19,186ed554,11de6daa,5c8c4d6c,c2ff5d22,bd2d6dca,7dfec5c2,e79d5320,aaa5d53c,38ae0675,4dca9a96,a6a75804) +,S(d1dcbfbb,87ee2fab,811f2a72,726d2b54,2176a20,cc23f744,faadf2ac,7073f443,106c63b,41800bb7,bcafc27e,3f8337d8,f71da693,e1f4350c,1870f968,edd17db9) +,S(d21aa173,c54376ba,1eb9d432,26ffc9aa,a516fd0,ef17c2f6,db117392,db749328,37cf5df4,e01480d6,604f79de,63a754b0,2326f9a4,ed74cb24,7724c682,6074e424) +,S(5234b024,a22c69a7,569acfbe,2cbb7ce6,15e56383,f8e1e031,78dd54eb,7d1fa3d2,2beae442,651db52d,62bc3b04,2a5b343a,b4103895,a74aeddf,d9189630,8bc000cb) +,S(9e6e9875,9f3e21ab,a709dbd4,f598894d,f5048dcf,5ee6cb6a,50941c13,35412f64,2b670199,e38f2e5a,424dd169,e047189,43111033,a7e4f4a9,2dc26906,31757ea8) +,S(8416e295,9a718e77,10df8a92,72de9bb2,89232c73,832597fc,d28f2928,8743ae45,6ef49202,801b408e,d81b7904,4cd1f002,20732a74,764c44db,4c77121f,1133d139) +,S(852a4fa7,48a3b2f,326405eb,e52ba2dc,27462f72,9ea3429b,b108e27a,d53561a5,3e06c046,ee0d9c23,6b0e441c,2cbeb672,770b99f7,8d062ac6,a81ccaf3,a562e520) +,S(2880dda0,2dbe56be,b93b876d,3c083ced,fa6097a1,cb234c5d,3282942e,3677c1bd,dfb0ea10,92d46bb4,fe95366c,5370dfa2,3d371f78,40e919d3,bf966441,f1bb43a) +,S(cb6fbc02,9e828d7f,c03dbf86,99a676a0,37b53555,275c86f0,7709ff89,f1819c65,fc4e2d9a,36577399,15cd50c2,1cb76cb8,ce9161fb,e05babda,ce516277,86062266) +,S(8087bb5b,ff1c3438,21b24106,606d0ec3,abc76a5,8a872161,5f6305ef,f81afebe,578b287a,a602c02b,8f5c5030,ae9a4632,23a4437e,944f4353,d9bc17de,824ce72) +,S(369f54bc,30f2c90c,7af0def2,2517ce58,f8ae829d,124ed482,653a28fb,42d3a33a,b8f2eaf,35af7e32,c63c97ae,f5962143,61f466bd,c4cc1b40,b4526157,b9b59d16) +,S(87be4c4c,1b2f871,53bb2448,ffdb6ac7,df294628,6be49eb6,edd3d533,1fed8f7d,7ef474bc,6386c0a1,5771ec54,21cd51d0,71fdc8a8,66938a2a,dfe6f4eb,ca0effb1) +,S(7b6678f0,18f75bea,8c310eeb,239edbe2,80393f1b,5eed1cfb,c013fa29,1e14715e,78e8b8e2,666ee69a,7388275d,2aa1bbf3,d985707d,3dd52890,c181a8b1,f38b1fd7) +,S(89ec641,96729e02,2a9608f5,8fba388b,77d2826d,6b37caed,90d27394,b160f135,5def3142,108d7387,19ee5a7,41deb18b,5e3030b0,d919a1f8,ac94157,a4786cff) +,S(2cbec739,3769090b,3aa2acba,b78c3fac,8b83749d,641f9311,99e6d1a6,36177f8e,3140e7e7,57ad2d5a,cb34a007,f4f26aeb,67fea7cc,8902fbad,2ca92083,f3de8886) +,S(678cefcd,a2d6a58b,53e7b116,d03020ae,29d57618,4663fcf0,2ebcf0ee,bd946908,f45be9e0,13298eef,37cd56ee,932b2a41,18834fc4,331c1713,314bd028,e6a3491) +,S(8ddbd278,adcc4ece,4692305a,94cdf011,5073b073,c88c1524,b43f1822,c73ec0df,90510edd,3c52c6c8,caa9ea1a,e28c7784,5d2d675b,a33b1022,68b93b17,80fc5b0c) +,S(972bf082,b162ff5f,22b149c3,d238260c,607d7878,aaf70739,3041d0c0,d7e36626,4685b3ba,f61cbca4,d99b64f4,3e90a442,6eca9f24,d0235324,797505be,4c4087dc) +,S(42af0d52,66604ab9,7de801c5,4514d23d,d8c1f760,bc86280f,540cc57c,bbc97230,5649b89,8c9029ed,4357160b,d97b74d5,cced0668,98de3b89,77192bec,1699ce38) +,S(5366770,87296d1d,8e6138bc,a9a1a0c6,1748ee21,4c0410a9,fa5623f3,d7bb30ac,e0683a60,786ba0d3,52619c2f,672d90ba,7c297b2e,59591f31,fd8b8fd8,ed5cac1d) +,S(a03b6284,e85bb18f,f04308d6,bce40e91,7d5d0ab4,ad920255,9de55c11,fc39fc24,2739ee82,c22cc348,23fe7235,a939db8a,c073005b,e014b564,4cad5a8f,e8785493) +,S(2f394ed7,268a53a6,bd998055,a24f7dd,f5801dc9,99233a63,7332e24f,26b66e97,b52b4f3e,e934ba86,d1bd3714,a26bc4c0,e49d09f,5d055413,8d3f4cdd,73918d88) +,S(91773010,527e537e,3aa0c19a,611ef5fe,7740bced,ef0b56eb,bb35a12c,7133f8ab,68f937b3,28b64809,27e1063a,bbbc36b5,b097ae5c,ccfbb965,f4814f,ea9fb5b6) +,S(2851bdbf,cddc8af1,7a20c1ae,bd529df8,28486bc5,50a00b24,763600d6,904af615,d302c085,702e27ae,6d46c376,33035d6,ee2acfc8,3b731758,5d15b2d6,dccb1356) +,S(e986d7ab,25499f1,45610b79,1b47e597,8be3d363,5a6f29c2,5d34da48,314bdfef,d0638dc,b3b3c150,10ec63b9,61104559,cfdb182d,31c41c16,5f53c331,47de35a6) +,S(bc45db2c,5639b2ce,2dc1c5e0,d831d824,ab44daca,7fbfa099,b2e648e2,8f8bfc03,5d93e3b1,27b289ad,49e32740,a9f53e0,79a80580,82606884,2c1f9b52,7213e32) +,S(4145d67e,47d9809d,2c67b4c8,49e29101,849ef512,ca7b22fd,667498cb,50a8dfc6,5471f4fc,2a4f7f82,9708604d,90daa64f,daeae007,d6290ea9,4922173a,4513f096) +,S(2d157f7f,4cd79d56,bb15314a,a738dcea,427e3087,e7a5afa3,c1ad740f,5c686825,c1c4f318,76159f4b,94e7a29a,2766bb46,962a4e21,3a7234ee,eabf1ea2,296fc1c0) +,S(2f426284,77040b2e,5dfe26cb,c12a81b,d6e89696,8226987b,361d7961,a73933ba,bdce120d,141b2879,effcf601,c75532f8,a384f942,879f24bd,45e483d1,8144075e) +,S(b419cfa7,6cc91302,e683c9c0,eef23ca7,bf9f8f44,37ea220a,b8a1fffc,3bbf527f,bb86954e,290f2419,e4891a70,b48806b4,a911e956,e3cd0dba,3c0251e3,aa929517) +,S(cdb4a6f9,5734164f,c7af2913,f0ded939,2b17bd09,b03698dc,ae2d72d5,4925236f,89eda236,bd1bf5d7,e500c47,d4996451,d57c963c,4f125ff,c9ef8e6e,aac8e7aa) +,S(ed4ea751,a45ac44a,33e6f2f1,50392fe8,a12a8c4c,2233ca3e,321800f8,f408c256,9c7e9da7,4a2b349a,ae9266d4,d04d912c,a296d963,98ace64a,caf40634,970ffef2) +,S(9b06fd38,fdf963c2,830ccfcd,1df08a73,84a74b02,fa79a87c,96decd0a,3cfbf5d3,e866461c,e7ee6015,aec4ba3c,d4dad0d6,3ede27a3,2a1b20d4,eb29de00,6b226416) +,S(df11481e,efc1cd1a,97e13f1e,e0702056,c2b7894b,de1a44ef,5166e521,1af6ae75,a1411856,35429fa1,ebee1f24,de73e2cd,80c76661,717abad4,a8354aba,222b7e02) +,S(f8328d01,b1f3fb3,d07bc65d,e807c619,46e4df15,a518a845,23da032d,12a3c9f5,e29dbc74,7746d478,9ca9a6d0,b5ca9ebe,de174914,7a709df0,d5e0f100,cdca6216) +,S(3e3afbbd,b7fc2301,f9a13590,acc4fb5,ff0d1b7a,92e09e46,1fcf0093,4d3fff86,1fc7f7e1,b9821c51,bd44c8d0,9619aeb1,a5c2af1c,3ec28742,f0f26212,6eb6ebd6) +,S(aad17eea,68348015,9cc19f8b,69d335b4,78ede880,4c551660,74d1ea9b,1ff86125,e993b8c,ebab89db,67cf45bf,361ee910,dfa1749d,26b488e8,ed6cf9df,9d365257) +,S(213fbb19,5515c686,fe8f44b6,fe26a178,286442b8,fb29072d,37ce9972,910ea35c,497b951b,7df7f4bb,2d0ee577,19876203,d68c3958,62781362,18e8969d,ed52a852) +,S(cd7f72a5,78ed819e,3e93321e,c8b8c7a7,eba91b47,92821a2,92493790,370120fa,a3d51c70,99280f2c,fa2c537d,991077e6,ca4eac91,93e97ce2,d8ff5fcf,45bb1148) +,S(70a360c7,a72939,f9a3a28a,1d1a9e2f,8240aec1,878f9b19,68923e0,b67f3b51,a1d9c07c,53a4dbc2,2ea4ae36,b6a0bb8c,dd175c98,6d2f61b7,3eb05552,ad710259) +,S(544a615b,4f8e2b66,fa1dd19,99e9cbe8,eedc35fd,9cda6d33,7a076601,21b5e46a,75d26db9,c76fc8d7,65286aec,bdd9c97f,d7ba7a9a,7308e6bd,75150b35,ba8451e5) +,S(4218d79f,76a073d7,af19b265,74d5b5c8,f8b779f7,36c23c92,a01c3467,8ec8acef,6815f631,49073b5f,e65c05f4,eb284c21,87e60355,e207cbda,f2c01eb9,becfb28e) +,S(6ada2638,1a82acc1,8a333759,8635f83a,3deca5d,9e4dbb38,64a2fc1a,a269b0a9,53d356da,65f7526f,60d05f32,b8b5f841,2e77b6f8,b61533ba,e8ace229,5eda6c08) +,S(5fa99d01,d9f29a59,75518e98,7c382c41,8bd46ea4,7813f579,3366618e,e118b09e,d479d238,38deb81b,dcce381e,4982652a,f15f6602,dbec34cd,6fc0e82d,33fc3b39) +,S(cc6ed576,34cc67ab,6ea676d7,2fef96d3,bbb4a00,b2b7fe44,12d0195b,44d76f6e,b15c15a,d50999b8,aac9e5f1,5834284f,dd801b0d,da4be94,f520af62,f7bf820c) +,S(e4cd0fdb,5323ea3f,deb10bf8,90a26b6d,ff447679,d8747ddf,ec32ee3a,40ffceb4,fbdb40c8,ba9c4357,656af718,db7629c4,e2caa87b,c41f8c48,d5d86a30,d220e1f5) +,S(77fd722a,ba51b929,ac1e3ca1,a2346833,b3c1fec,7a756568,6afb7cd8,9b88a8af,d02519e1,d6e9cb4,4f378ee3,1df4bb74,6b5b555b,2c7b0691,9cf90f5b,3de98505) +,S(4d391fbc,a9dd3d47,9d3ca57b,f299f4f8,6291e523,95ff73e2,665418c2,997a41dd,5cc9ec33,b55e606b,b93e9fcd,593c43f3,e5d4a3c4,39ec6fce,1a9ebf25,b4ce899e) +,S(740bc446,17b17b84,5c99d63c,3c92fe81,2eb232f8,8161a2ba,83f3a445,73084e97,fd8ec6e,f4f9567,71717481,c1301876,fb10742a,99028c67,883254af,f8355464) +,S(c258c21c,adeb8453,5bafd8d6,cced030,c6aa12c4,1bdcc392,b2d10e5b,1b46e5c,7cdf037f,3e60bd7f,739d08af,a20de5f2,b73646a7,5ec3e2af,4cb62139,5d171d31) +,S(8fc88069,733a4d5d,bd80261,c0c9ca65,fac22a5e,1bffd768,dbeffb83,24130d44,4211a94b,f88c042d,54d37ba7,41cee691,ca5bf0a6,38f0ca95,954f4aa0,12fc946e) +,S(cf62ee1a,40321c24,7fbb0e0b,ce99d314,f5152de3,32b827c9,67a61bb9,c96ad4c,6284a7c3,e64f7b8d,4bd978c0,77dc0d22,e6137336,6410d5a1,9bb09640,1ec4a3fe) +,S(53351f8a,4d447760,ecc88443,19b69160,bb00b3ca,fd6fd9d0,6c0040e4,549f8ba7,83844e19,3816e6ff,755c148f,d5488384,c7c1cbb8,8c09ea0a,16352bcd,377f6b83) +,S(a02063ce,ee2c9191,94d0e1f6,2ace9407,baa0157a,d2e600a9,e173348a,1d06bb0c,630461b5,55653f52,da9b40ea,c4448a8b,fcdaeeb0,1007dde0,5f4c186e,9f146339) +,S(70bcbdcc,25de1764,7274f374,196608aa,c360c09e,951b9857,5a6a8d6f,e1d35660,3bd5bd9b,716359ce,80b5e719,a9e1d40c,3a1c7430,94a82b64,a90b0f4e,db461d74) +,S(df8ad77,83cfc3c0,6fbb1fe5,2a515de0,54b161c1,74155fff,13812d19,aadc8fc7,bc4090f6,416db0c,9d34ff20,a0b7cb99,af38401b,1264c604,44ec7355,80069569) +,S(2504e9cc,ef399800,5f2fff3a,452d56fa,8788df47,e05509ed,777a9d9e,540a30f9,73c506a2,c6f48efc,af7f4d2f,ab5fd833,6fd6514e,db690a51,11659f79,7390612a) +,S(24ee0724,1c920334,3a6a6fa5,68979fce,18a9ce0c,819e3a61,571141a3,5bc97025,ee642ecd,605b84e8,68940a6c,cd7f4d93,fa0c6816,2fb0bf6,ba22427c,b0bd7b8a) +,S(1ead5ce0,9665c05a,63cd8eb1,12097f35,4961e12b,25c03093,e1c6d919,7a3929b3,1800df5d,a1abcc4a,b1c32fbe,a1dd7120,7284b5f5,dee7009d,c2f4aa6d,7156fcc3) +,S(47cf2ff2,26084f8f,9020b0dc,d838874b,160c69ef,2e5e89c0,98e7891e,ea05d507,a340d3df,129b5aff,1044d0d2,c3866464,bca2efdc,8dc83516,cf8fa522,d5fb7d48) +,S(4064fb9b,8e2e4952,a218bb8e,ae474a4d,51f050a8,3f9a7e75,b04e39c4,42d6cbdd,ff9cec76,a2ef1930,92d3e02a,aaddce0d,18ea66c0,d1adfd2b,9c7886dd,b835de10) +,S(838ac8d6,e58e20d0,321e0150,ba6d401f,cdd70a40,69d980d2,22de3353,fb81904e,993a6f96,2909dbbf,7b9a6b25,14153331,b1ef24fc,e892710,5f95488a,d95614bc) +,S(a5e36d83,189d43d2,34d6ea26,ecf5943,5aedee72,bc4cf385,5fce9b5e,e202f266,78c02c3c,e25c3b89,9dd2933f,b41435a3,dfc2d1b5,e7ebbfe9,54ab1c94,79822c55) +,S(9e240cbc,d357c4d3,34f31209,58d6f7ad,5ad79e7a,9b51f572,5ddc8fe3,1fba72c9,aea34a5c,ed60a062,ec1476b7,b30b3c9c,68cc5e10,cef9f0eb,6729172c,b511f06b) +,S(ad1b0646,bb315380,5c22b91d,1ee47a26,dfc9ed5a,860be0c7,ea8daec3,b6dc2eba,ee2e61a2,2499c509,1a910c9e,ea159873,a298daa9,6d30d8bb,353b9955,92dd2083) +,S(4f7b0889,11d8f64a,550d8c7f,11ecaa6,fa12df74,a236a0cc,35cb7cd3,5b0ec72b,931af41b,d297e18,b4d9ffac,8d7f8691,29b94250,f1de1d99,3e31525c,4dbb21e3) +,S(dab2a170,e4108f3c,93fba874,70bb12fa,834d0274,35695870,d2d3523c,93d3a7ee,262f12cf,c37f010d,deaecb24,d08ce35b,293a5c6f,1746651e,7bb0b2fb,c573ae4d) +,S(3437257b,784d72e,419e5082,311b5a66,d499f687,c4bcfa31,7abc7484,a3cf39be,ce9bcf07,6da8d68e,8453fa14,3b06d7c0,f38bd0a0,76f1cec2,a49b3bda,a5c398d3) +,S(4594ae9f,82611ab5,bf786024,ea34bfaf,939fa409,34ad155c,9ed5e736,899545b,2255c7f5,62b0ba72,c3834e72,e77b478d,77d3f15e,3ee0cda4,c4b3f928,ead450f5) +,S(7337705,12db06fb,36b21fc,26b585a7,3aebb036,b22743c2,f13212dd,81898819,753ddd59,725fb0a2,561cf461,c587f3f8,848b53ed,29283c51,5150c57f,50307887) +,S(bd915814,4d2afef3,552d81c1,8c74abc,a53f4c2d,654f72e,3f2abd66,d69790ff,1af609e1,7f27e373,b42b3277,a5f4714a,31ae895b,95e0c5b9,50e7ed2d,1827763e) +,S(8a11cd4c,a51dfee2,28c1ced9,3d8870d,67782740,1f49fc73,d4ce56db,915bb557,d30ad7ee,ae9f9c97,eec27822,9f47100e,ca46b3f0,27339719,6be0f619,56f5cf23) +,S(7929b5f0,2802bfeb,6c23e688,65b0272b,cfd058d7,c0a45ea6,97d46d87,6f9bfcfd,f9bbae21,8039783d,4d1e366c,32a890c1,8c80d1cd,41f08b36,963b54e2,f4fde5d0) +,S(80df06ac,1d5b966f,8080e79b,cc9f01f3,d55f8855,9b1a58bc,f6e4c526,3bd89d01,346926d0,a59558a9,2625614b,ac010f36,5ee5c337,2660fa7e,be41aac9,41136538) +,S(74545478,9ff383f2,94a92b4f,383ad13b,ed4b01da,d20f4ac6,efc83315,be5ccaf7,36489f77,81ee77fe,de1ea165,c4cf2b5f,e8217361,9e760cea,fae777cb,c160fa9a) +,S(2c6d35bc,b213a8a0,95c11fdb,42828b7f,e562d7d5,f877de67,de62bcd8,5af8fe85,aa30e370,34094f9f,4502206c,72f23298,2e60139c,2bd35631,44dbe6b4,c75d159b) +,S(8353657a,9d934eb0,2811846a,728cd162,4b43429d,304aa7be,830da70f,b2e338db,f8400438,20ffa5d,28189c5a,ce693c8a,ed4a4caf,3aff83b1,66a9d404,74e02b71) +,S(f216e93a,54ce56d7,c7ef6336,561a6299,2177ca73,4ed867f6,fd1a8ddf,aaae494f,db0a3f13,a0fe8326,63e8fad,b11cc347,8da296b7,2f1b672,3f43ea44,acd30611) +,S(dc371221,9b5d73f9,6562baa4,b62ec7f4,2e9a3dc8,de6e7112,273d0811,a88324fb,eecc9092,ec563e96,3720acaa,929f9bb4,4f1c9015,7c3300fb,581b154f,df57c004) +,S(db34736d,48f0b4f1,e1ef6029,6ef534ae,b10f047b,4256516d,d4499072,36649475,1c29cd6c,f7a8c786,952c34c9,b93e5188,1a116966,164d0fdf,dd1be4fe,ac586bec) +,S(a248457,20468424,f355af53,62f5bcf1,971b09ed,358fbd33,78fc7297,3696add,9a703d61,37d0deb8,a3767a56,c2e24573,baffc931,bc850694,8c9a3776,26547803) +,S(bb7b806f,a9ac753b,bbeaa429,31f68d0e,3eba38b9,8fb25ed2,40c9faa3,124436c4,8f812574,a1a8bbe8,d9b682e3,d9b0150c,7c6ff9c,f9b42e64,6e5836a8,12426752) +,S(6703c476,fc28a023,f6619427,69e0f068,489344aa,74495ad5,17b096ff,c3ecf446,8b48023f,7c9ba723,584211a3,6731e14,f42699ab,522e15e,ed3ac43d,28e2a38c) +,S(bcaaf8e4,bfa4b448,fe23f3b7,a1612b82,14cf0daa,349463b7,1b44ba61,e2dbf6a2,bdff2700,e2cc953f,e9d08835,dbe8793b,b07498ec,68ccd736,d6fe1710,d5c7f404) +,S(906b4fda,1a557220,1dd5b446,d726a2e6,21794517,3ec74f7b,bfed8791,9310cd49,d753f2db,cd2c4d28,d0304bc4,78690871,cf838490,2d7f4f93,441a74d3,892653cf) +,S(9ec09783,18f7d95,5180e326,e1bfdd04,fa5369cd,eb786905,8d726ac3,9ef93d5f,9cca8057,994b1641,53ac6842,4d28fb70,ad22baf8,f894a049,d1794add,97acf205) +,S(53347906,b75440ec,28362a96,f114d2f3,6f823cbe,bb0030f3,a2de3314,12b8209d,ccb38e0,471f8abe,47ef1bf0,29550ec5,59581680,3e19034a,b06a090c,ca0c1fa0) +,S(27c53f29,61b70480,93e24b18,eb357807,a33e5411,15215337,3b98f80d,d23a4870,5a3f4b8d,e18636c4,71fc70e5,9ac8c4e4,703fa5fa,880594fe,2f3b888b,da575601) +,S(921927e3,7a115f9a,12a616ba,cf55c213,22ed51a3,e75caa5b,eaccce75,de59b68f,bdbb7c7b,c1e4c5b5,98afb590,6263d779,55884e71,17864ae2,e0636c4d,727b141) +,S(973b3c87,6eb81ffd,677c692c,ae432751,efb3e609,1a3d9ff8,dde6cd6e,3f3ea8c2,340df771,129510b,a4112c5d,adbcecd9,8684b0ae,3a9683b8,49aebdd9,57bbb0ed) +,S(20b817de,f0533767,9938ef03,69204700,d5972c32,12656ce4,205e9ac,1b01ae71,2ae2fe5b,e2daa016,1c65c352,94a0abc5,c6b1ce64,fea99c12,34a14aa8,8395707b) +,S(63e2544f,7a7e9181,7a347b7,f72eb43d,ca9fc5d6,3d931402,aa6889b4,a3c95876,e62aee6d,20d714ce,5cdf52,18bd5fae,adf49cb1,f86e6067,f91cad71,280d16b1) +,S(2f90de10,71508cf0,b3583abf,c47d762d,a69dd472,e4183421,6ac39753,e22aeb80,5371bebd,4a0dd74,625e5e02,5a118488,880f3a89,9c23e64b,76193abd,3788d389) +,S(8d423ce8,faa96d05,45e37cf7,5e5a351f,7c9359c2,ad1c48a,c9adcf29,d2ed7209,83d4b83d,ee76c401,a18df794,8a655c3f,bb9d23c1,5ac0bd6e,ea80b129,bab40f2) +,S(12fa4142,5e028aff,303111a2,9144242,a9c91d88,55b3ea3,becec110,80181efd,6b95b370,8e792b57,ac10eddb,362eb10f,ee5c3b8b,b2e37d4d,c4d2ac40,e8c3ff57) +,S(923ca95f,2a3bdd7c,d7505632,cdf2d730,ce70196f,ffd0cbbf,f8347882,8a706f73,f8b0c866,c39b6173,b383983b,210cfff3,1903afdb,cad0b2ee,3e541ab5,2746abbc) +,S(844d53e,878240e9,63e3875a,728f4704,64ce3aa1,66209776,a869e0d6,88893646,c60cd291,92bf8c1f,f98c47b4,a713bc75,1c84f9c7,19fb32b2,5b855e73,6feeaca1) +,S(43786fd6,c5471d8d,ba277ff8,1005a5df,8838299f,66636b2a,65e7ac21,f1dc98f3,d292a2c2,9c8c5bbd,8f79109c,b8706fe7,745ff884,f98c127e,9142f52a,56091b51) +,S(6d1bc28d,f5e9ecf6,38783f71,fb98a2ce,bb0dec45,8b07257c,e94736dc,ae36d7ab,c2c54192,bfd80447,86214cf7,a28108dc,e2c00e07,2321638d,a0e80023,88d549e6) +,S(6bc4ef34,7f74ce3c,2ef3f89c,c3e265d5,6c742ccc,ff84b7f6,7d8956ab,16ff86c6,eb4492fd,2d2ab04f,1276be35,c6bde62d,be26a6e4,60c5c66b,8b0fccf1,79b46408) +,S(6af45075,fa810958,d42a756e,d08d5c,d67a62b,cb33cddc,b35fa99b,bf678b38,adbb724f,e7682c7,678ffc3f,ab738666,886c7b93,84960bfd,5287ff9f,ba5bff28) +,S(eb6d8b76,36466365,a96f49cd,355b7460,939f340f,905ad1ca,a24e8a66,55260600,7ae9cefd,aea30b7f,b9ba11ff,603b81d2,41f7a187,33f95c3,3c2bae0d,7fbea3cd) +,S(bd0c2233,2fef7d3f,6738dd69,4bad4cf5,b34d5e9b,ad6500af,11e4575e,91795068,eaba5c4e,2ea0b21c,a9100b6,66823a4d,a91c4d57,3aa9d136,76f820be,9d1cf209) +,S(c5e23bbd,c5049419,3483e083,14249157,aa56d9f,804374b5,54c9879,52b7e392,4caeb8cb,f684217f,bfdcd02e,3aa4ae3f,8d59e766,855b4fe2,f7f8ac7a,6e597751) +,S(b5717631,f3aaab92,5543edb0,3d21c604,17178e98,dea38bd8,10867cf8,8c92d2a3,e74209cc,324a9ef,8b31874,524dbab4,d2bdf0ac,8f1d20e9,a02409f2,8c11942a) +,S(9c456099,49601f2f,caca85d5,d30a07e1,b2d17b7c,7b838cca,2fe4b5e9,5d305cfc,2d7a1540,a109dc7c,2841b61b,31e50078,329273c3,585c8674,674ee06e,ff04eeb6) +,S(52ae2946,c0ab36c4,a8aff175,73b6604b,e33dae5d,73228d54,98c77a51,8aa82f63,70e23d9b,66061bfa,4d03f899,b65493f2,7179f5c8,643104d,24dd771c,777f87b4) +,S(149ec3bf,55ff462d,dc1ba490,384081e9,89db9ac2,c29efdce,f4f59f0a,394adf9,59c1d88,b91db942,2ae8fbc7,ce6951c8,49642b5c,df949801,341a8bc1,789dd7af) +,S(aff89294,d66718dd,dff83534,61538da3,dbe14a09,c14d0576,8a163810,42ea7ea7,71866beb,cf5887a5,ece2352a,cbc256dd,7b615491,2a88cbb9,a924e764,4d59266b) +,S(de44f478,2cb30472,ad52d49b,303e2b41,33887eb7,38e2ab78,da7bb406,584e76fc,6798ad84,25bad82c,57c630d,7ac8ef21,b13d08fa,830edda7,eefd23c9,ce482bf5) +,S(e0bc7a73,76169366,c172c88b,e1ba02c6,b3a380eb,2894e134,5a2ec7c7,39682e61,bd147eb9,33b18fe8,dfe7c0ec,87b7e993,5ad1f7c2,ab5424d3,c23609cd,262cb2e0) +,S(5ee34f27,2af69f33,9473cfa7,a536a22,ed26139a,71cfbb11,27c7a476,32f0e6d,c1df8f96,dc0d4d82,f6a57de9,85cdefc5,1316bf10,dc3636cb,80762aea,c4e13b8c) +,S(4dca3bc1,77fa7a63,9b8c274d,fe157d7b,67296846,bed5d13a,68bce5e8,e599a0f2,8fd2b558,36fb9aeb,fdb3fd75,8f59c8e9,2fb48968,52eff2a1,d01c32c5,3d2fb234) +,S(554f6bc1,87560290,ef9ed937,3e993f54,98081034,a03484f5,bc184751,f8b48136,b454c3b7,dfd512a3,517834e0,e8c3f50f,de80863a,1e0fd83d,2064a6bc,a172b26a) +,S(95a81b50,a6c0879a,6a960b2e,162dc22e,955af87c,b539eba4,20b2825b,85592ad4,be55e8c4,dfed22d1,f5872b75,f38aa4c3,7c7d5086,f67011af,2651ab0c,c45c712) +,S(907b6d53,9e496a6e,358d14d3,431f5582,44a4f8a6,ea291d85,3efb8be7,477e5c4d,b3d3d694,3853bb9e,67817fad,1dd7d1d5,ff33e200,2922665c,21f872e4,77150eac) +,S(8527c81b,b342576f,67737cb2,33f17605,c8884c64,6b7a8357,5bcccc09,c7f17aa6,b6d675bc,db8d5249,57b1930c,145777f1,9cd47b9d,33386a64,5044e8f5,877604fc) +,S(8e1e3a7d,5a320d92,4ea13436,f906e9b,bc6bf83a,819b9e9f,913974e2,efab00ec,d94f03ab,d81d5f25,c323dad4,ea792c50,792e07c,79281c4a,ff309e0f,f418b0b9) +,S(fc02cb93,be1f4a8d,9acbd86,bc68cb6a,dd0d8949,5cc7434d,72cfab75,519a8d76,71f7a532,729e45c5,98a6ceb0,885a256e,ffe4cd9d,967e84e9,8b73c772,7e4d4f94) +,S(cf981302,a2858b3b,b1ac44db,4f08751b,ff76357f,9b2ed6af,80a289b1,be6e7b8,237e9c12,bf23666e,70205ded,984f1fa2,f1a8a828,b88847ba,d3a1be88,8d73b528) +,S(3e6e45dc,1408e920,3ca74cbb,ac8d50cf,71718d1e,ba05228,e97dc4be,a8231d82,2e3fdb7a,2ad3a805,f61f287c,a7ef86df,961009e1,f0fde8a3,14774677,3b1ef848) +,S(bb047795,7581471,10809088,8119b0ee,3ce1b2b2,df2668b3,749b9eda,707d4657,95a72efc,5f95f3a6,af5ad697,7dbeeed2,8d6ee55b,fce29bc1,bc439168,75c67587) +,S(4e015d42,b8b02c10,4aba3103,4ce04cb5,fe356d,81291939,3f5d1b9,68dd6748,d35b20e7,dfbf6d71,d94e96ff,c9267422,746419fa,811bcd2d,d3942c00,70a870fb) +,S(609a4c57,90c8b210,9eb7391b,d68d078e,70850af2,410df867,92a37459,24a49daf,f3a6327e,bc965b3a,581cb14e,78a4390b,14431d00,d1f34e8a,e35502f,bad0e98) +,S(ccbe0736,2a955ac0,4e1b7558,a17ecf61,b9ea0761,305b4aa1,780bab03,a27fc730,f96b7c16,6c98a1d7,65ea4e3a,e0643298,d981a012,4b03fabb,71fc47f9,1c92cd3b) +,S(6ed60282,85df2302,e6b10ef9,4e11ce0,9143c569,a84388c3,e2151c69,c3ccab14,675ea3b0,687a3b78,e8fc7564,9665e62f,e91b0d1c,25852608,1d591ea5,1ad196e7) +,S(bdff05cb,a0cca14c,55b3c592,38515532,70806177,443dac7f,4c07ff69,cb49d8e0,5149ad04,86cd8ecc,274a7239,833910f,f09d7993,aaac9798,1dd106da,6e0c9a50) +,S(64ce68c,cc70325b,22be5366,579aed1c,af9f6e55,c2c7386e,ed579911,4e2bff2b,f8c89976,3c8a9a0e,ef61dddf,2213cbba,11bf1be1,eab6506b,d596aede,45cb1cae) +,S(cd42e46f,489150f3,dcaf3c06,e1e5a2f6,b40de7f5,626107ed,af01471a,18ab2bb4,d9c250dd,d2026967,b4c921f4,e253a788,17f11f89,f679e5c2,81dfda0a,1bcfada) +,S(f7c29007,e7145420,e2da7e8e,3ec4daea,5e9b121c,35c4ec43,59d55f01,89619735,66451406,4dbda93e,637735a5,6a06ddb0,5ea2933a,36cfa3dd,c2ba4a33,eba493b7) +,S(6339c1e1,d4944856,26b3d221,4715835c,377609d2,d91150f2,c5c1f679,5e93b7a8,efbe6dea,47b4e8f7,ff55a20d,8facb8c1,d10a6960,98762d95,be532fc7,3ed59b28) +,S(fccf1f13,7d22ed06,5f4bbcf1,e9f4eb86,7b1ec78,d9f40b4d,aaf58014,3489b37b,a5a77c2f,ef9facc3,881559d9,d9756b4d,6646beaf,21b3511c,64a4b550,7dbf3e10) +,S(da97ff10,6f284ec,f123b554,17bc8f5c,a13434d7,58ec3d4e,935c1600,404f62d2,65c2168b,4900330d,f2f1e3d1,cd8ab92a,4f308222,881a493c,f8b301cc,af12e168) +,S(6676a4d5,428a24ce,36957556,c1b44593,343ab6f2,21f0b9bd,dce2d898,333e4fd8,45bddca4,b9332535,f5f4d3d8,3467d793,b7afcf58,45a19593,854b1c5f,3daf7b41) +,S(791e6abe,cf461420,54a22c7c,d3deea41,53396e7a,2a619ccd,30212ade,e57859ca,e4033bfd,8c55c93,ec732990,aff43ecb,e2ec07dd,17e4ec92,68a7b0cc,fadd37a1) +,S(3a7c7bb2,d5181550,a78985aa,84b73246,c66dd947,4bd7c5ae,20717f31,af0018a1,2388eb17,e03cedc5,221f732a,9e505f8a,b6c38d25,184afd14,37b52d45,fe9d7459) +,S(249a2db1,86801c96,9cbca936,101381d7,62b74017,2b454c3b,ef720bc5,413ab999,da185c41,76aa91c1,d783cf9c,85c075e8,2f708e0b,3ec930cf,f71897b5,d1d5e7a3) +,S(b25e0d53,b4e0cc09,985f21e0,c5655e50,32c0857f,b792b136,14da6885,6b4f8590,1bd17aff,6b02e3ac,e1cfac42,fd28d837,ac5b80,42b21055,d6b84e67,5d83eda2) +,S(73605368,5e83388,a869db66,f110243e,bd1073f7,517fecd6,1359eab,b7862fcd,e9c7a02d,842c5a6,fa43407,6e12d41f,e767fae5,5a75e913,d6912536,6d5f9d56) +,S(ec2f0b56,71392e97,2f8a0c9,af259d42,2e5b52da,5e70fff9,7115c961,77f1b1d9,47f7debb,adb24e59,c8571fa,98e56d32,d49e072b,4fdec818,2049498e,908183a8) +,S(7d7a8fa8,250dd43a,91a2ad2f,320e18c1,afc25595,213778e5,cbfa6058,4be2d378,6b48ba16,89627d77,2700f11,9bc20d7,fab2b07a,413f752e,2a0e111,60fea3be) +,S(316a71ce,52b6723b,a67aaa01,e26082c6,6e59490,cff4c366,5c695ff,aa6713d7,d6f1c1a0,7820c612,12b44cf6,e5cb4ba1,84152ffd,cf82e020,e95af73,d6a1cb9e) +,S(21a2a8c3,ade89ff,c32e5fc6,ead97a22,9ace8857,11db9930,ade6e72a,9fbcca51,95fd3d04,38df517b,5712aafb,432f0e35,726fd438,a2b941e4,7c56c1cf,8882e4d0) +,S(3f181867,b3ad8170,dad46c68,f513afae,1ad2cfde,41f9535,5369ec32,728f94d5,a51a94e4,e9f20eaa,d5599189,4222ab0d,91abb8f0,38b00a91,5f09df10,a2317527) +,S(e9673139,11be39bc,f11ecb9b,690ecfb4,79b7aa6d,3158ea69,7d0092f0,89f63c1e,c100cf7,6f8783e3,8de2017c,32022a0,da9be6e8,61307546,1f98142d,4903abc2) +,S(61ea8ab0,1407ac7e,547e94b0,6f3986c6,d3096d43,2bd08cd8,61554fae,9008b122,e5c55bcc,a6f713a9,76490488,e69f1cee,150167f4,283fa792,a105ca8f,f4a4d182) +,S(ad8fae7a,17457fdd,9f481554,239a3f1,49673df7,24a3a402,cab73f93,bedab9fe,53b7dfef,7966c4bb,bb01d037,12563f79,48517220,2ed375d4,d777efef,50f03e6b) +,S(8605cedf,bf7f2e54,d3f62f27,44d9d436,cdf9974c,9190020c,586818bd,b6a829d3,5af8a55f,ca2aa1a,6209fe4d,a7708ff6,e7a33df0,50e85873,d786f54b,7d946b88) +,S(bdde544b,465b9ef4,7dcffa5a,7a794cf9,6e83253c,2f22d4c8,cbcd2d6c,ff921d87,6c536367,7ba867f5,5ede7d23,81be6ab,ec97c8d,f88a1a74,14ebd6ce,8caadcd8) +,S(31882a45,e8b088dc,93eeafca,85c28f49,62a47bd2,bad916bb,fe3e7346,32fe1cdb,b3588f0,c5f86e1e,12ab833c,12e028c9,d03557a9,e02aa1a6,fd11d693,55f176bc) +,S(17be4052,45800f9e,db510b72,603b8e63,e49fadbd,62798883,b0d04f76,a5dc1202,1504ebdc,df8855ae,28f7738,e40d277d,81667e55,a2f59cb9,c9e33a4b,8d32fc54) +,S(c633bd33,bb697d2a,6bfc4e69,707f2b28,a303eaf5,a601b08c,9c56afad,cb629537,86e3f413,2d4764db,f2c06b92,461c64f3,9f3b7f78,33139eac,2b4d59b7,ba18cef8) +,S(f39e208a,f4c710f7,190881f3,a33cd113,633434b6,3b460062,570618f5,8260bb52,90c56805,807b36f6,272e2b66,4d943c33,d0171ee3,ba5cd4e2,bfe52f92,b9e2e62c) +,S(ce984394,14f29607,a54ddfb3,72db8ac5,ee4e5414,f59f73db,89360232,f4a16c54,1a4805a1,d1057b13,c72f7835,4d40ae96,bb80542d,ba5ebd7f,627cfbae,ba24e0d7) +,S(5266e79f,81107a4f,ba571af1,885d755,94504122,a15a673f,6257f633,bb0a76bb,5e7ad1d0,9cc85f12,8773ca39,77b55c20,18d38200,fb739918,d3b0fc96,a559b457) +,S(4fb9de57,63f47aa3,bf370113,c778bc8b,67507009,5126f5c1,1ffc158f,be7056e4,2cd97636,8eec7197,aa2fa34,72fe3db2,29fe0275,8789d75e,52e87553,1486f7ef) +,S(ad168024,a99eddbd,aabec840,6158cb92,4ae7bba8,d233745b,ded57407,23cc0226,ab105015,968e4673,8ede230b,b53c4be6,9ee6386b,91ee03cb,a21f7040,f14095de) +,S(55829ae,f7cc555b,733aea9b,f1b307d,277923ba,148ba8d5,5a7c8001,73719cb8,6a7b2eeb,9c9b9585,5403b47d,6c60a7bc,382969f6,c4bafd3d,3c4f09a7,63267689) +,S(2119f233,8efa4e0e,2204bbe7,84e9de01,4e1e4c43,450d5910,960ebc38,6b78b935,9f219dc3,778544c6,7a337db9,69c513a8,52acb469,34a71957,11c36913,b8e7bb93) +,S(11fc3e1b,9491be9,d7de53ca,a2558d36,c5227498,3f5c1b32,57f0fe5b,b1295bbf,1c69c74d,ecb05933,6aa6b6c0,231105ad,91b8d188,d109ced6,2198c528,844cf6f5) +,S(34b6ce6f,ea6e5143,95091bc8,67e606ad,5e64ac18,99085821,80abea3b,dfd2a908,5b6ed904,f4bdbef3,fb9e41a1,32c7a313,28e9f325,4e180694,40339642,2bccad6d) +,S(6c225dca,b45768ab,3b1c567d,97ef745c,b326fb3d,2db6ae2e,22a40c95,3610a84c,7e85d752,2180fd8c,ebf63cfa,2d843bdb,912fe042,d00ea29c,d72fd768,402a1084) +,S(5f776e5,41dd95c2,32fcc757,14b688b,cbfd2020,e7043e3,2a707144,5a8ed7d7,3b8c5c78,fc6d8354,3a09de0b,9a64d529,c116803f,6d0d62ff,2a20b369,8b273c0e) +,S(3e26d8c5,531543ef,5e37eaa6,3244faa5,d5371e48,16fd94e9,b8bbd932,891b0e23,30a09d1b,43a4a036,ee1a53bc,6c3ebfa,a5b4c70f,6d8af4b0,c70faabe,b79bb65) +,S(c634da91,c17a3568,aaa970ac,26553e45,6be8afb,ee12c85e,8aa0dabf,f18b36af,649681ba,e1390a7b,d05d34bd,98d87ed4,16eb9f99,c606f46d,6d522019,f1a925f0) +,S(ed335d6,4d643598,c6eab4ee,fc242d7e,4e8361b3,ac8d747e,806962df,2e7e9a7e,f0e7c3f8,19c97aa7,2334b690,98f28bee,5a1552e7,f578d5e1,eb56b600,fcaa93e7) +,S(d37f8c09,411359ec,3f63dbf2,2870ffb2,d10be164,7553f28e,d72d9585,1e521581,da7cbfb9,ba3ae036,72df1be7,56d3c9be,831467d4,cbe3b51a,191e47b4,9d1f1922) +,S(ee3121d7,c7475ea5,c3aae061,1c6b420c,5b32d05,ee86f919,43c3352e,7515c360,703b2e37,97bea3b2,9b447411,dad7b12d,b809164a,ba690281,b76f245b,bc4c1686) +,S(7b42c9bc,5c2b114e,a0ef1a59,492a6132,3f5c7290,427572b5,fe98017d,1987a12b,5cf76382,e85b73d7,56fcd92a,99242725,dd57edde,30ddd9c9,dc7dcd95,260d27da) +,S(9af5ff9a,b13a53a2,93f9b6b9,a0f925d4,7c8f9b84,5f6933c3,ad074922,f8a555cd,ca93ec9e,89954734,c8aa13fa,5908c855,13a9ec19,6417042c,a336f1fa,be5d4153) +,S(5ebfa274,1a2df1b,6e1d591,f70983dc,a5b2b850,856bd7b6,59c81877,3848dacc,b0adcb9,6ac23c64,2904c15e,822991e8,46e12411,f472e0fb,5fb69fc7,a0f7ad18) +,S(93b58d08,465e5eac,8518382b,c1f6ebec,daeb486,7da65dd3,ac125e6c,fcc81e6f,54be8918,c3151784,d74646c3,6bca9c8b,8a50b8d8,63b1db8c,f4fb3ef5,1a24a4e7) +,S(a28a579b,4fb46474,ffc943ee,32b40664,5bc86899,edaa111,32c31f1d,cb6fc858,40ee91a3,d5625648,196605f,f650ab7,6e059b14,faef6396,46c9b153,9af14670) +,S(e987909,781d5560,b71f6029,750d20ad,add7cb47,f90c9078,e8de5f2a,d606ac9a,7121ac3,4c80dacf,ffea346f,5c5e1a81,c55318de,ac8cc907,10274f18,ee9819d2) +,S(291ff11d,158780d7,fc0ee62a,e395456e,5c84bca9,75e84a7d,1d2b3bf4,61e1dcef,c5c8cbe8,abb6854b,670298ce,8224a945,71e79e37,9335acee,c230366a,53ec2616) +,S(4adb1390,9e28b53e,42bd9e57,373aa131,efda7d16,b8dffd82,4bd9803e,fde315b4,66d7eb12,b827ae7c,970a796e,5c0c99b1,24eb7002,4fde63ee,fa2ecdf5,d4b1456a) +,S(55e25f4b,95240efd,e3c7e47b,2254601e,1707a8d,e40bf384,6b3a7024,da7591ff,e9f2257b,7e98606d,743000b3,72dcba0b,e4491ae3,22e82266,4b1e2b5b,78c830c2) +,S(d24e7493,e41dfc32,be7a6d8d,5463834d,388ddd01,8c213ad8,aa3005b1,fa747eca,e73a8216,a51b4b16,5e9f5bee,414d49f2,6d7feba0,982b9e93,fc4b7863,48c26cac) +,S(a510b252,6d015da1,cb7e4600,3ed61af7,caa03562,19227d9,ed8eea13,61fd8b2a,3d98c2a0,9015abba,63eb15a2,80c6c479,eaa2b2f2,a0011adc,3565d2f3,8abea726) +,S(c04d04d8,127500d5,15bac63c,ca55d76c,8404cde6,fe681f4f,6b8c2b48,87b314d1,cb3fcd77,9fb80eba,99cdb937,31bc0814,e3cd4458,df7fee1b,98c4067a,db4d9d59) +,S(ec9c7c61,146c3357,ba851e69,18ffa770,6b5dd2ff,a789245a,df70f90,eebd0649,9a09d3fa,10ca6923,c068803c,e9161923,b36b0709,b12627a4,dafd0e3d,3d186170) +,S(95df5d3f,5d504c45,f4b7e840,3805e54b,b2598511,2ca53064,baced58,a0488cc,a43dcd85,89b85305,b07d1ef3,23eb305a,35079cdb,743dcc21,c7a6ad48,4ce8ecc6) +,S(b8eece0c,3a950c52,c46bf50e,b5dff949,2fc8ec4d,6bb19651,c72d447,633a6d16,74e942a3,1b75bf83,ba6c1460,d969a2c2,4a49572c,ce3fb84b,8d0b08e1,d5583744) +,S(599ece16,d1f69c22,53deac51,75121ea0,c82b2d77,c5e2c0ba,520bf1c,72dd09a2,48a10c3,25af3d0e,dd8e2e72,5d7baf48,b2fdb672,66423859,9f73d231,a911bb14) +,S(b8ba5a06,8d9458a9,6e2fdfaa,961acd80,7fff711b,bba4e3bc,35a5fcdf,e82ab32,8035ab22,7554582e,9038845,44d32a53,c2d82417,6e2ac7e3,2d44cecc,50f8ca4d) +,S(b6846be1,cccd7865,e56d3d7a,f1b1fff3,ae806380,a1710c50,8c35ed17,227e65f4,bbdb7025,32945f0a,de989f52,68230763,361ee9d4,9c0e6241,77fe6fb6,cbc7201) +,S(a1ffa65e,69872bbe,ed009e53,f846d9a1,20dd31b3,a11932ff,c3580ff8,da9d0fe,aa32e580,d5763bf9,dd054999,68b6ba6f,31c210cb,26846ada,dc0045b1,ceda215b) +,S(9b38176d,67091c7d,f448c707,80cef08a,2ad73cd6,de65eebe,b62f9a21,730d0fa2,22d26b19,c0fb9b7e,f1ec86ba,b8ff5996,64a45988,190499d2,6fb604ed,4e609207) +,S(bc2ccc9e,209dc64f,bb132553,bdab43fa,accfa4d,7deac898,1fa52841,35fd0cd2,47366adc,176ff88b,674931b,a8791fbd,350d1d13,71891343,74d58305,a55ccfa6) +,S(1ce000a1,65452a62,5d036f51,4fbd2a30,d4518734,e7f93aa6,7a7dcd7,24730f6a,e09103fb,5b90f0ed,54b34baf,3e3d5bf3,fa288acd,b6b0ec19,ee3062af,35c6811d) +,S(846c569a,887d64c0,e8fb26a4,49c62447,4cc63d68,4da0909d,63dcdd0a,dde0031f,547753,132c9f98,d7facf93,d4ff0416,7dcbe44,77987be4,7df408c6,fa12c07e) +,S(6365a8f7,28656e23,c9c58518,5686b18b,701f7b1f,54c84b82,f5c81ea5,74fe59e9,8c7cddfd,a992e53c,ad151d46,c9cc0b3d,be27f2b5,7ffcc23f,c8d9cfa7,eb16c2eb) +,S(ed425f3c,89ae3d8d,97972619,55e8fd17,71dc5bf5,98c5237f,bd267f80,7d2939fc,4226abdc,14f7a03b,cd7285fd,19cf14f6,10c98d0,6e3c1d74,daffd602,99a3590b) +,S(cda5246c,2e1b7ebe,8d667f23,5ae310be,85a0bd7a,2e903d56,62a6dca3,971f00c7,791ef296,f8ea9b34,918534ba,318a4fea,96b2c2f3,21e6d3f6,eae8248b,29247f56) +,S(b42a84e6,ce79c1e1,bedd3f7e,596a11c2,f5017d98,386fbbc6,f906a5a3,f4eaf99e,2e722cc9,60bb3718,36ffad5e,47509fcb,cc3d0601,70b02610,823fa40e,d407e6ac) +,S(358be08c,e1e2e9bc,b43149df,58700875,be23cad0,ba8524c1,6d46a01f,ab0bcf90,f3c4fef0,70baaccc,f64fe0bf,b6f5111b,462318a6,36489b00,34f05c44,1f9d1308) +,S(3ed6435d,e5b36230,a4f74bfe,14571041,427d16f7,9b433ac9,85c9e135,6016a789,1c72e85e,142743d2,b5be677e,352d3dff,ee0dc56d,5aa56d91,4b92762,6041f26f) +,S(249f7e2c,580dda16,5940d7e2,672176f4,afb7e50,b9250610,c253d9e6,2416c910,6fc16311,49e9916e,8f70f842,3dcde36e,1630f508,79e96e48,6dc7147b,3aa9f50c) +,S(97b3b144,e8381ba3,1b0f6f0b,752cbf91,14d2d76f,6f418d4c,69f0de6e,c89cc85f,67c9bd30,33b720b5,a1449257,f1de85a,f7282260,9e411dc2,1820444d,c988724f) +,S(3b38459e,868b2912,51d0fcaf,41245087,80610d0e,395e9b68,cfaeef1a,5f395a85,be5180dd,bfde7454,c78cc9a2,b77245eb,91ec4c25,9b17e3a3,c3e8e49d,5225ce6f) +,S(4e6f1790,9f33e08a,914974f4,48270fd0,74fb35d1,49a017ef,c54fe21c,96163ebf,fb6578f,6f47156,5b6d3491,3a9a5e4c,dcd2880,d774e6a3,e56cd078,e6b9fd15) +,S(9141ac63,e408937d,7425a0a6,70a2565e,72e301b7,75619a92,18db32da,315c75de,d35e290a,56bec3e1,3cc55e72,12aa57db,f10b34df,bd7847a0,5de91c4f,546d6045) +,S(ec9b73ca,72052751,565c006a,4fc9200,337c9162,88eddaa2,e212c611,395ba578,37e11ef5,c1a22e77,38d5f3ab,4c74e2f1,ba192275,4c4e7905,1b15010f,3c224887) +,S(56fc14e1,bb1a928f,ce0430b1,feaac6e5,aef50208,be530d7e,f0f5b81a,ce1caca3,4e5a6084,f8680d07,9f3101d7,a80f452b,b05e597c,c38d9865,f6d7f307,90209001) +,S(aecd741b,2cebd4cc,82b7c362,70f1b22c,cf3997c3,f180e1e4,d803a89a,657df731,5f104b33,6c0df49f,1936356e,8dd09b3a,256bd317,afffd4d,8ccc57e7,f90b8e21) +,S(516267af,54f83d52,24a22b9a,4309e9eb,9b5c1072,31c3ff0d,418f8bd4,15836cb8,4187389b,9e062c17,f4ef6fd5,4b6b8439,cc37e85d,8a3db13d,86592098,7befe4fc) +,S(68bbeabd,8d3f4473,f91a0368,7383b4ff,6e7658dc,6e1287e7,f258f543,2466fed5,cf63c80f,ac99b42,7a67f7cc,d978d5b0,8656fc7a,6a383c27,48635ad,97049c4) +,S(20ce22ab,69467e9b,51d59213,8b52c1e4,49ba908f,909658a2,b90dbeb5,b07b67be,562da07d,9f4173f6,9232d17e,49ba2c17,31649ff1,4a9dcc3e,68f20dd2,de97ce2d) +,S(b5b7d6d3,a4a59f92,3afc1ec6,a5215786,9c86cd90,7ff80b07,d04160ac,6e798f78,d05e32c9,775125ee,dbc55af,4d1597b4,45b5eaba,5bbf6dbc,b8ef3e79,fe9d4de5) +,S(955bd489,7a4280b1,5de3d848,f75f6dba,3967e593,6b077d4a,cdc4c30a,33f45df4,4bbeb7cb,5d79991c,ef3b9fe5,bf25dc01,6448261b,44b156b2,749f9734,3d453a02) +,S(9f60e951,98e7370e,b3c02fe1,8bf53735,50fee849,9c876211,201e47f8,660a5a98,6395aaa9,33ed5866,a02570f5,9321d89b,c865a7ea,62e28a6a,3a62c4fa,4cd613cc) +,S(7081f0b6,f5923d0d,be4041c7,589a7100,9c2b6459,a255468,999f2d4e,50d776ee,9cb60005,e067019e,93aec9c9,1bf28b4a,27f3f0a3,288c4758,403a9ff7,668f9fc9) +,S(e290180,d8d5a7c,1b0e982a,bd63ef9a,b607d605,87e663ff,fb0ab73b,3369561f,462776fe,77289a4a,250ccc7b,80b54e51,993f741a,14299f78,61b88d17,d4d924f7) +,S(8aea7328,b285bd5e,b63d5939,c5c8c6b4,ac254cdf,c42cb521,2f4c5643,58598bfb,b682da77,4fc55ff,eb4a559a,8ca0580a,13819aee,990d9e22,8e0192f8,9568ec2) +,S(e9d108b2,54b24b57,ea4fc287,45865c09,27302d7a,1dfe90fe,b3a17906,2f256e68,fff7274,6d29d9fb,e7b0fc0b,1af14365,8d0ba69a,a45a72c4,8f67b939,aba128d0) +,S(9ea1f93d,1f317e61,786d4909,429e4cc8,b81f2914,17d28913,6d886b86,adba0fee,231dff25,d3b0b351,6e63ba6a,afdee115,975a5c00,b95936e4,5d9c6be4,6980ec0a) +,S(e8a12415,e5fabbee,7cd687c,43e8d530,80701d01,85980c5,7181b68d,481e7a0d,dd69839c,e263e746,99462f18,58745727,ac53bf2,2e0385dd,5d6a21b9,922f62c6) +,S(e287f3ba,ae486145,a1c2e04c,7f6d5c1a,ed796840,27636cef,b4446ff3,6c3def2,9395413d,401db0ea,4ec53bae,ff215580,5bcfbe8e,7e6bd6e0,be5b9fbf,9d968c63) +,S(8f99f79c,ec205ab0,e79756eb,a14c8e7d,fb23e232,6ab77927,641960dd,56ad1194,805953e6,15cc6d6e,2f61b0da,389b24bc,89cbff4f,c9f0ade8,c5dfff99,e819a2ea) +,S(9c87ab6a,8cb723ad,e0cdfb59,e5a1ff6d,3adb63d4,7af33e14,c6b3c343,c766f586,74798122,7a3bd79e,7d5012cb,bc81cff7,6a3699e3,75874200,4edc6e8a,a965bb19) +,S(c52c8608,6f245de4,baa10b7,fb512ff4,6042bd50,7d88bc3e,c75ec75d,d99dc00a,e8c2813a,bae8b8bd,9c8762d8,37d42fe7,85e5406c,5fb5cc2,ca05ae03,4ab3f844) +,S(b6286e1,94d5be25,9a79c6b6,ebd634ac,dd7c3fd,66ab0de,d8d4e160,ba8dafb2,72ec2ea8,ee0bf270,777cdf7b,47991524,27eaaf24,2a0334aa,18b3855a,899b5910) +,S(df7b56f2,45f2f8b,7213792e,370ca89a,45c648a0,5f3ba4ce,8c5d6d34,2f086b6d,386ced48,3850bdcf,4209fc90,d039b96d,39ac18cd,5d97ecb4,3df23ae6,1596ab4a) +,S(2acf4c9f,4cd42357,3e9110ed,a64aab59,459b2b37,675e420f,48ecd068,6d46a3b0,5f1a5829,aea5e981,cddff9bb,d2521ffa,58b37baf,9544c0cf,f622857d,5a2cc579) +,S(bfaf95aa,eb55d378,7210033d,b352372e,6a64f2ac,a420b877,586b684d,9cd33f36,7d22bb13,bb61e76e,2a2fce3e,bbf9ec83,78c6ed2e,5f143b0f,60803cda,b0a3d8ee) +,S(78cdd360,4eaba890,da793c9e,f589cca5,faacb6a9,14a29f6a,6add7d8d,74f31421,ed7e9c15,5b801d1,16b0d60e,fb5e2287,76430c8e,faff4bfd,327a38dc,ea19a634) +,S(f2ebcfa9,50a391f,c7b97713,566a8a49,edb8944c,7cb68276,d9843c22,8d213d2e,b1c7630d,956f9f13,c53a180c,569d534f,9513d16,4f3dd900,bb3f5e78,b0fa4eaa) +,S(43cd60d,83bfcbb3,cc19943,34552eae,857593aa,e8158adf,ca850b9d,1aaf4c2b,ff64bab1,f721e6b,9e23d659,224998cd,996230c,4fccd302,47e9e110,607e8f62) +,S(41925ce0,c01a49dd,7be0c3a3,b27f13b7,2168dfb,a5ec1315,f9209709,f38ea93c,5346b95e,cb6a0ac0,1a2f49c1,9b02d9a9,a725a676,f144ac26,c48f0d8b,94f77110) +,S(fd231210,6c762d82,a851bb47,8d0ee0d8,fa1c232,7e26feee,3e6ece5b,323877e5,39763316,f5a6ece8,baf748d6,234eedc1,4bf33462,1db3e66e,7eb2fab4,f96fa162) +,S(fe3e8a98,cb7abe1f,36a54a0a,a3d1c9f,d5ad684b,d05cb2,6ea683d8,f4556ef7,7d220677,34d80663,a1ff05f9,bad5a648,837b4475,abe0746c,3fa940e0,4f1223bf) +,S(e602a764,ae0d1bdc,4c3f9b1d,271717db,38232e94,84181ab6,9ba8eb73,4f5ec5dd,ad1038aa,26268b10,2c1f951,6b77b482,8bc9bef5,7b483450,d513e6f4,cc916fdb) +,S(871895cf,adb772d9,719cd962,5dd391b,3218142d,364764e,eb0bc6ff,8d81e086,49a09064,f7916421,9d51ef56,53861350,dda2c9ca,4e6269cb,555c8996,3f37722e) +,S(e229d56e,77755805,c814ec27,8fbcc56e,8ed4ec4f,4c14907f,4ab3a0e0,fa7e4b4,cdb07ebd,66d68055,bed7a46b,63ceaea8,6d42659a,ae6ebce5,795ab908,14e48af2) +,S(5535f85,6b0cc868,88ca3118,9d20d68f,471066af,a70addd6,ca4a9537,68bbf8ed,8655c844,245e2a67,8427822f,ac3206a1,f6f52953,4f7a6c29,6ab4825b,770ac5e8) +,S(10657905,4b37ce9a,e240d78e,3d1066c,b8c48d21,fb7130c,dd35ee5,24767ad6,52836b7a,508a6190,28eb013,c0355f70,4393a5af,e133abe2,e8b81dd4,83e125f5) +,S(3366b207,2521d023,99e9e311,e3447778,e796db0c,87428e4b,e6cb0ff3,a0868c1c,ec6022a4,22a8dd2c,a7f2f15d,39998394,ac908c64,74a34ae3,255a28d,4311638c) +,S(4a789396,339be46c,73608a1f,59fdb41e,91bd0164,66417332,f2630316,b5953ca,d45b657f,615aad45,809c0af8,4eb8618d,6e6e0346,ae1ba101,3a123ef9,e5b4c442) +,S(ee4f2484,fa0a9c7f,dc0c64ad,4df60628,d75d70b5,7ab9f0fc,ae9947e3,89f1302e,52b77894,d8ecdfae,df7dbd0d,8dab74a3,4092073f,47a543cb,f81ebf42,9f80170) +,S(4095b5c,163f226f,7937fbb8,3035f6a3,9aa9b760,c5086c0e,af9959fe,25f30a1f,1ce180ac,65554d4e,e9b14595,5c059f64,6a15d032,930465aa,d5547c58,5dff7ab) +,S(6a225d3b,67d9d42,412ecd9f,d018bfbb,7a36a59c,d2f53494,3d6cc62f,b0436a24,29b3d63d,9352e0cc,aa23c91e,e300592f,cc698abc,c73c48da,6a384f99,ea7c2701) +,S(23efaa41,e5f9bbbf,c6953a89,e3f4b9e2,17249254,94f2057c,f46d0c8d,71d36e93,cc89a7b1,7f2671a2,5bd7075,5c269219,88cea3a1,1315b86e,f218e493,7cdb789d) +,S(e30c1e97,f7f99957,58d591bd,6a398ae2,f972176b,f637c66a,258ad081,4f3ae55f,1a70cb6c,3e66e925,fc1edb4d,4d29bd89,3e8e4755,6825adf3,11e64b01,866509e1) +,S(be64d782,acd416d5,2b612f53,4601876b,f05aac91,13c8d265,b57ca32b,df08e278,7a41844a,43e837c9,293b81c8,73cb504f,bff8f15f,5a21e61f,9466acd5,87ad7e4a) +,S(caac02be,e009a61c,672b4c2,82fdf2f0,73ada0b8,d4a45450,76d24c38,f23822ac,7d93e4bb,a040f4e2,23acc304,75c455e5,72a9a64f,c66108ea,500ca62f,9216d06f) +,S(da2539b0,3a9cea94,9209321e,e1719b3,c1ef94c3,86d0e860,fc0ec1e7,684ccb3,e85e1387,bef1cea2,f67f601f,8067e9a4,b1b1306f,6a33df15,7795cbf0,ce3cf9f5) +,S(bf2ee552,5c965248,64bc1bd8,ad9cfba6,4ce4fe7b,be9b4198,700e936,799cc0ed,889dea1d,b1298a24,a11529bc,30339023,5df42398,e760304f,6343030f,6058f18e) +,S(b3e4b141,cb0c3662,9fe4c9ff,7a42c635,1130602a,720a6264,30b967c1,47abde36,f66f7118,c38a828d,8c4ff83e,5d6affeb,eff979bb,2e419f56,a7d7c8aa,52865657) +,S(451eb24f,fad7211a,11181826,5a223649,24a25593,63c33e01,4967ba58,889475a0,889ff940,49f6c3b7,9a5bd321,1c1f33e3,4cb2f8c5,bfb141a2,1fe5419e,44565bb6) +,S(29ab658a,6a754778,2127a0b0,c4b8af33,ea4c77bf,4bc0fc53,b5d65d07,38f5984c,aab1bda9,c77d6c3b,a619f9a,d72da6be,947b8baa,b80b16d2,15ee01a2,2bf0f2c1) +,S(9b59c407,d815c224,5bbb9c0,d1da59fa,9d9e79a,c654f8ac,2879b341,297b24db,a4ef058e,e6300114,c2827811,abacc0a9,17bb35b6,9b1b76c,c761ab8d,a676d190) +,S(87d27b65,82aeb975,8b9b970e,76c3ac77,78e69a7a,52ac620f,c0564e74,a66c9fd0,3ff3b3cc,dec29337,41c83e08,7f07f41c,4d03d5c,93268b1a,cd9098e1,37511e03) +,S(fbb3684d,38958163,bd85a0ab,36bcb93b,7fe7d383,b70d8bf4,d9bba6f6,989701dc,7b07cdc6,c9c5b3bd,10dc2af7,b2606d09,759e7342,68a5d4c0,301be264,87b94504) +,S(82022ae4,ccc42b9d,223cc1ad,c66e58a5,a3ef1494,f95274ea,cc7cf79f,4314a453,c2424250,9ddf2da1,6f0481a,9b4db450,3a81805e,9a8eaa3b,b5cd0e49,15d2b695) +,S(ba5cd45b,3b51cb37,bbe475fa,e91f8975,ab4e657c,57d0801a,1dbec958,be20f901,2e0d4fc0,f8b4f58e,3407eddd,298e5324,7f9eb718,b58e4164,78e3a01e,cf41b0a5) +,S(1293c841,b316d1be,76ab4444,53e72e22,cfadaf3a,df5b6d27,7cd065d8,8a6703fc,98f58f37,40fb4988,b844ab52,3420709c,2488f144,88049749,28670aad,5133c2fa) +,S(ec9fb3c8,54bf1bda,dbb972de,a8ae36c7,987d77e4,8d8437c2,c69aa988,df5015c6,d5f35bfd,ea59e974,961d6b36,4832560c,fe425d54,bfceccb2,a00411cc,a5486d3f) +,S(2ecce03f,4cd55b69,6cbd4466,2e7d58f6,9950eaec,6adaed62,7694dcb7,2544d244,e14f30a9,7f1cf747,ead403ca,e07cc4cc,d1bc793f,de79082f,f6615e6,43f68879) +,S(ed8faf7f,a63ee520,7825e7fa,56f6ef8a,4c6ad5af,ac507c3d,77c025cf,566fb3b2,df120b8,ab21273c,a5af1040,7fa3e54d,cb0636c4,8ebf88f2,c9b046d8,83684a9d) +,S(47cb8f7b,8780dabe,c1eb456a,f30fd917,bf3fd9f,3c28e3a5,bc078c5f,14c32e4f,f8607a02,1f16aa6c,68afc948,f21ee2de,c5889d19,8978e9af,66931bd2,b4aa3203) +,S(76365ac1,fdebab2f,3b9a3ee3,8afe70ea,d4962047,1e38e5ca,cf215a24,3d762009,2cacaf72,8b4bb600,ff37d3a6,97d45fa6,5d778334,dcddc32,11fc51b5,4e53aa28) +,S(c9dd5de0,99b8e552,e1375055,63edc83,9f09311e,11868ea8,a233309e,cc27b424,4bd4d238,4e615eb7,c68f134a,eafe7d2b,38163a8b,b117f9e4,b382236b,b8f8c1a5) +,S(22b6a7ad,cc406ebc,7c1c2f96,bdbcb6f8,9a1e08b7,822e2a31,83e5932d,ad0a8961,52b86095,bab24f4f,d2ebe9a9,534af2d6,87b553e2,77536d5e,22c1eddf,ae0ac794) +,S(3ee808a7,49fa7df0,c37017fe,cab7f6be,96f06c04,b2de4d24,a331a9b6,9f81a158,3e954cef,5f1f9ecd,887dc174,64cffe5,6c4b1356,d841ed0c,1e23c1c,2439cb4a) +,S(2938bc58,8a7a4896,de69ae4,4d5b6240,aa97d302,7043048f,3e49c222,b8fa4803,f26bbe61,9fad1d90,de74826c,ba6ea02a,9ea59a1c,59cb4818,65b054d0,39ada03e) +,S(682558ec,da97c9de,4cbea34f,5df43274,94962e5c,df72b0b1,2c3977d7,e1a15451,c4c2e765,22c7013f,19253c4c,c8ec6cc6,8b543f33,5aeb620f,112824af,b9fedc6c) +,S(720d8c68,fc520da5,79f6811d,e1f3d045,cbfad09,f7f7d8c,8ba68b4,6493620,b867e8a8,4f7a6d06,4d6fd4b,8bbb31a9,7ac26c3,b485fa29,50d545e2,644c9cb5) +,S(967fb3e7,1bdf658d,356153ec,6c0463a9,994d5d2f,b3aca9e0,2a17f5eb,f4b84831,b84a65f8,861724b3,2f5d0926,ec9a84d7,e3cddfc9,c7887a09,4cf602eb,547cc83f) +,S(1d9fd25c,77ecc3de,8e5fc113,1ef13b9a,73f6ebd4,f8673d88,db2a418e,8bcedc85,54a06301,d9720fb4,bfbff58e,23fa4233,33012c9,d62bf0e4,aa6adc4e,ae8035d7) +,S(80138158,a1137af3,114dff5f,f346e339,7d04029f,9050d44a,b4cea89,f1311c0a,16f49876,e6d6ac18,c25cc712,da3afe70,bc5e9489,7c55dc36,bdd234aa,6a5a6b31) +,S(aab4021,77fa5844,e3a0906b,3107df22,33aa3418,222a8c55,c6c37933,c3ef632f,9b83208f,3ad0dced,382d5876,7a089711,9a062039,9a7fbd2f,7034e5e0,3201b092) +,S(8f3fd14c,7670f464,d9ef1e3b,3014be60,3c523237,14bbcfe1,d3612f13,fa72f10,84cb7094,7901b81f,bbfa593a,5c8606e6,862ef6f5,d71c30a4,b546c08b,4205c68e) +,S(3ba9c91c,aba3c06f,eaf4578a,33979ec8,df69a903,30cb8d88,e49953ed,4a1f4933,7048a74c,3eb66231,e8410799,591bbef,fdcff65b,b492072f,582ee47b,7a6f99cc) +,S(2f8c37d2,89dab0e0,d5152468,29f6cb61,7344c21c,29860645,5f29a9ca,dcf36a7c,37f0b64e,9d02710e,bfaf145e,69c79965,4223d093,7a834201,d2f74d40,eb508396) +,S(45e6eba2,c9209d27,b87f6050,a656fca,73fc6128,cedbd2d3,ec40ca,76dce846,a3e28d44,ba1882bb,d1c91a63,5ee22582,81386757,4e66ad90,8a062c93,bf5f16ec) +,S(a5ecd3d3,80a0cd23,4467143f,fe842d9d,82ea7d9b,98ad23cc,605fb8b1,fd767ee9,22f12823,8ea84269,3fb31fe5,b5015cf2,c9ab6c33,d167b95,9bea6e29,4f11353f) +,S(f7f45a71,c4663b0d,44369821,318374e8,51eb66a9,ff6034a2,c943ff90,174be83,3a1633cd,4ec197f5,40d3d6e3,e6a3281d,7fbdf46c,f52fa149,8acc0a43,5b46fce5) +,S(92582286,6b314e17,5af03b7d,e5717d42,52bf6c82,a55ec832,a94b274b,487cb59c,fc8e9584,736809dc,65234670,495bbc7,d6c2f52c,ddfac4a0,369f0527,4a811f68) +,S(c15fe8d3,2303d00a,2f57fa96,6ae6fa75,1d7849f1,4dd527b5,a7f76cc1,e556da4,36242bd0,4685dff1,a67c445c,50cd348b,e017c06a,e2e9cd06,7b5fb109,81c10951) +,S(49ef826,152aa60e,310372df,270bf0d4,4dd7136,7d72be5c,a464f60c,c62b5355,7cad4ba2,dc4480b,9a1c572c,77a93e16,4e369d2e,b565e165,d9c7d2cb,20c4c645) +,S(c8de09e7,538ff94f,e12c876e,163133e3,629b2f1d,ed6686a3,be4ae122,9c91a18f,b5a7f31f,e58088a1,5f1e872,d6096562,9cecb10f,1a76fe88,5eab6247,697c2635) +,S(d86b9fa4,616f43af,1d7a6cd3,d9af24a9,6b3d5119,ef764576,9461ffeb,96abb344,2388ce8e,8f931b49,9481b660,669cb8e8,56df6f72,e392e539,fb570e19,f003bcab) +,S(a2cd7618,f351e2b1,3fa7b719,30fe3041,87c4969e,4f3ec55a,7433ae6f,cbbf88,3e0b5c62,436a363b,1455711a,b310c362,29870cd3,a096324a,a8dd36b8,5d19d685) +,S(b7283cd4,e33e4a3d,7836e4f6,b39b5576,ad6c213b,ed2fab87,ab442ccf,2100b2ca,918006fb,111c2307,1821e7e3,25eab3f,9083367,4248fc,2733173e,8eabc9ea) +,S(b1fd2d2e,9707ba8d,355b123b,9ca31365,d12e1854,6efccd9a,cda40f6,48b9a769,8c37cc16,8e8f55de,f604d222,62818bfe,1a40cf3d,62dae94b,58c9ef4b,475e674e) +,S(1b0997e7,4242e85e,cb4be32,885b5a6e,cf6077c7,395d262e,7c0d2b82,cb39f90f,55b4d8d4,27cd1d8a,ed8c2d2e,f3bcf8ce,f30fae12,4c14b183,fa36923b,6b7760b3) +,S(56ffbbbc,94ac925,dea36258,8ee1bbb3,4f1dc9b8,1bfd7e69,8e055065,d98d78d6,aa73208f,46d72bdb,20af3d23,5bf1c5ba,a517fcb7,b8036208,9f8a7198,d8edc65f) +,S(c125fab0,7ddb7f9c,3426cd36,812611e8,e3908191,67228685,3533e0d9,3ad7045e,2806703f,622f654a,f6c3f118,92c1dd8f,1f235ef4,4df464b6,8ccd30f1,9b77e5ae) +,S(e7ede9db,e4e0c742,8b1fa6fe,e81e80ae,dbab85fb,f259d301,48a51423,fe7f4a17,93ab277a,9fbc5cfa,c80d32e6,5e7f50d2,e236925b,c2dba1d9,e635a56c,d33fc066) +,S(74701763,f1bd6bcc,470c3da9,d853f967,a47c1628,c48b1cc8,aa395159,a3df93f3,ab2c011c,7c5510f3,37393dd5,f05547ba,bd22237b,28ed69d8,a4b6ed55,5d8ac8ee) +,S(8d27f97,55baf71f,e6dffb8d,83784e32,a65541c,5c656576,89c900d5,e79081b8,a7176e68,f3c89601,4ae1f837,bd52227f,f308f90c,b7f31386,e5586125,1ac250ad) +,S(63e06afe,9040b531,eac0a0ff,1ac25db8,71b0db01,8e9828c1,f5798ce,accc7ea9,aaa11884,a9dbe08b,6b28fcf9,9049aed5,c911244,b2a6a13e,9300c007,f4910aa5) +,S(dc7ea1ae,27d60ab3,42d617d0,23e4b1ab,6bf8bac2,882084b5,dde95894,744ed50f,93c7d76e,2b95c5ff,bbfe97fc,754a5a3,b63efba6,e111540e,48a0291c,142f3dfa) +,S(f3aeef6d,f69cef4a,3d7dfb69,1b5aea99,36e40239,bb976253,2213bd1b,f6e842d7,57d37dda,339c7002,f87bde03,1cb1e8ae,72e5628e,f493c115,1fbd0f46,2208de5d) +,S(825bd84c,316e64ea,dc5d081,23d7272e,ae87dafb,28f69b67,816a1aca,76bec3ce,61e3a7fd,ba8370a8,6a3e3f69,d62f87f0,849a2564,97658f1d,c28ca11b,40a52251) +,S(310a2cd7,4dec5370,9d2988cd,8e9426a1,edb63b9,50ec3ba7,f5aeeb93,3856a75d,5d6d86ae,dfa5e57f,7f2b4ab3,aaec250f,e3ff1eee,3e18c228,ffa3b81f,17122c97) +,S(3471d475,62a512d0,f82355ae,f9bb6c3f,69f04db8,977ee4d8,5af582c0,1b425217,272dde70,2fe0b69e,bf86d68c,5037b425,ccd444a9,45040358,aed399eb,db9cba31) +,S(bf6d2563,bfafaf24,20a2b3df,6829aec8,aaeee4eb,ea3538d,8086807e,4c257a2f,e8077a00,7e7b496b,64f847ef,755746b8,3a2738c4,4c1e7ff1,a920ee2b,40b496d) +,S(eb33cfc4,a883f718,52fce42a,3cd876e6,d6f4d465,327223fb,bdbed425,2b9cddc4,9bd400f2,ef608bd9,904f03ad,27de86fb,eaab9137,e25de8d2,a7dada4a,1ee5453f) +,S(1317e0d0,3e5df319,fb383edf,7de95645,6b123d3d,a0d8d08f,82091d6,ecc2279f,3bf6424d,5c6f9d56,b0d22b60,706a5471,dcae4297,eacbbb25,2a9d2292,33675afd) +,S(81b09f2e,99dc43eb,eb22cf5d,c5406f30,7e00f8e4,267bb456,c99bce34,309aeb56,9d4856a4,b300eeac,42f5b1df,92e331c9,1dbc5f6f,ebf17d7c,49580180,a3361932) +,S(deea567,a32ff19,722626ba,ef4ea337,ed436d32,d23df7e,98b86644,855a62f2,5c912697,c61a17fe,8557ab3,40c1792d,4a8310ef,69e785a6,dfe66d43,9d032414) +,S(ce4ad083,5746d173,e68e02ff,a7a91b9e,96ae44b1,cee86755,ef3dc4e8,e43444e5,be86cb89,5238d4c,b553e289,1545fe84,df7cc81a,ff1c2a20,d3406f62,7f03aa7d) +,S(9a993e3d,407f1af6,e4d19a32,48a0715f,2e36384c,7d8184f6,fbbce7ff,530b077e,e4a1a52d,80a267ee,99a7bd6f,e6d96ffa,3f87001d,c543f4e2,481eebc1,301a7a7e) +,S(1f10df2d,7c7f05c8,1717ae6a,1267aa63,9247c7ef,45aafccc,6b36112,fb9bd0d8,670b265b,71e2db79,32683b0e,c967e9af,e45ad643,27cc29af,fdc783b0,58760410) +,S(70ceb257,29c9208e,7db17633,dca775de,d57d1dff,9d914a5a,bad5711,86621b53,6e016e91,b3f3455f,cde11c0e,c6d1d75a,ee9825,7e9d64a,ce7c1ec3,49df0c62) +,S(ba46e5e6,4dc882fb,dfb7921,a106060,43fb6c4,ace9f2fd,46693f7e,74694e3e,eaeb4eb9,79381ff,8a208e06,9d8c436,5868d0b3,dea049cb,f342c88,7d789acc) +,S(bba3badf,d233ad20,e4179bea,f3d7579e,a631d154,e048f7a9,e320d388,3c30d81,f2a7c70d,69dd44c7,317a0af4,e765693e,2bdfce6,8c8a51e8,ed3f9003,5e1b961d) +,S(6df6a769,d300ba68,17e58f1b,f41e0af2,57d491f,38e59283,d93750a6,36d3f8a5,63a083b3,aa51c772,eced1f31,ccdfb4d9,ebf0f492,99f12819,dad9a36d,a73a4a6f) +,S(affd131a,4b8c9a98,294c7ea8,793a5173,4fab1953,1d2fe236,1ada5c14,a7174f2c,4c3de4d9,ec4a3698,3feed322,58a9788f,3426891c,b3205708,73429671,3411be6d) +,S(2da31049,9e54b18a,19dba546,4c7c708d,d42ccac6,bc2196ee,2f0a2453,3b0abc7e,f354ac91,20ad9f8b,56d09d44,51c4d052,426981a3,f7b47e7c,bb0549f,232db974) +,S(3882ec53,cbe3f82a,e8d381ac,edb4c31f,23cdd201,eec93f2b,2dc7d0cf,92e57b61,1d34315d,e5a7bfcc,492b0046,b2740646,71a43d53,2fb0bc78,6cd80ca2,ef7e6e3a) +,S(fcab8635,6a08ab26,39bc8e4e,8e9eb5e3,46825975,2a65cb28,d559bb48,7387f9f1,af4080c0,d08f07ce,57566753,ad3570ae,bef2b38d,4ef7f54,d7b2054,c8fceb94) +,S(fd34b8bb,8a897e12,a29dcd5a,57540caa,847bf011,a1548ebe,5dd89d75,9d36bb58,51a66aac,6a56f973,57927eaa,723106e4,d19b603b,d0d5a55b,76235197,7910b2f3) +,S(1e89bd20,c0d85bf0,76c7a167,87c7d817,1d3b4660,99dd82fa,808d98e5,87d4b469,4f53a9d0,e5768760,3dedae47,574f3123,dcf11590,fbc4d353,eafc8629,3cfe882a) +,S(8a1ea7ba,66909ace,c8d7d93e,aefbaba9,ddca459e,548c448f,5fb3a957,7baa05ed,d58059e9,64f37a4,39f7655b,25018031,ea1f1fcf,8ae94f99,e09c04cf,8b7be091) +,S(e0c3780d,80d59926,96886549,af2961b0,e4451f0c,b5572cb,d7ff76d6,1d1331a1,99d9d2e6,a13c3b1f,c2fe6f1e,5230e7b3,d827ddae,bbeda551,1144f68e,4945491d) +,S(964354e6,ed23ac12,16fed36c,5daade18,8e7e1bdc,ff20e60e,f7cc8c0e,83996035,f748a09a,8563c6e8,72253198,4e6f0622,7e6a408d,3c633529,aa8bd326,3428998a) +,S(9809e729,5125c862,fc6eab86,969861c7,8bd09415,585414a1,ab1dbc3c,1afe3f9b,d8536228,bbf55568,833909f8,6fc84a58,ab0fc089,432fc05e,fd46bf63,987b9fd7) +,S(195f4d02,305e4c42,28d83bf9,4025fc7d,1d8d7173,da14bb34,abbecc4c,f01ed17,957db8b4,97aeb9cd,68152e0,23cb4467,ce13845d,3a88e21a,726b8766,7c9d637f) +,S(562eaaba,3eb17e34,efa3f726,d02490ea,b0203fe6,81b836c0,f2c44a1a,854e0b37,b4e658ed,9e664804,2d3a35a7,70ef4253,97093ba4,d7b32da5,9db56a6f,8552b1e8) +,S(84a2c5eb,1efa9014,80c57969,3302f34f,de3a602c,a4b1a28,8d79f28e,dec8282,700d51c7,88cfeed8,587261db,adcac440,c703313f,5f0da023,bdf62b36,46207cf1) +,S(83d12fcf,dbd9168,b14e7340,6c6d4b84,b93e2bad,77d4c7fb,8ba00973,3672f913,e4856e26,bf2532cf,bafc78b3,682ce9cd,3c0dd6fd,861218ee,523b5131,e7279a7b) +,S(9988a6f2,bbd9320e,fbe73bf,9f4643f8,ce64d522,9ed4b701,dfb0068e,dd5451cf,bbb352fc,bd3b2650,d0a44e4d,892f89a4,d2f431c,2abe9910,ed5a1dd1,8a882d5b) +,S(3e92183d,cfa615c7,33721d1e,2a2116b1,83017d4c,2aa70b51,60f80a10,afff0724,c7888251,f4bcbe62,f0dfe545,3a73f3d2,76a2f30a,74e57d7f,22680b39,142dc945) +,S(d9175300,fa1efe3a,4cb130fa,fb36275d,e5f85b98,5ea5844d,e7763d6c,8239492f,59138c65,e9592a0c,d9a36220,d165abfc,fbad38d8,85eeb521,c5566702,9b678b4b) +,S(6ff5825f,7c12bee6,5d17f7b4,7766e677,ed74c5b8,7a95d068,b4741129,36d933dc,661ae9de,cb7974b,2304be0a,4d2b8d80,2ea9aca8,40cd0381,31f80248,378c0edf) +,S(ed6cbeb1,a8761064,3067d580,ac024f7b,9560366b,bae875ab,15ceb116,50b1c31d,9140687e,d1e889c1,6564d60f,702e8101,1269c476,f19d7f45,19a7d66a,8617dede) +,S(5f8ccceb,32d75aa3,1096b56e,eb132230,853bf6e,38643ca4,43abe04a,8bd69164,35f72a3d,d0c81dcd,4b6ac0fa,c4f5834a,4f6576f0,21cd2d45,6bde5b7e,7995da3a) +,S(81e02085,9bb23977,522896c6,7ed66751,86580d62,f015af7c,479a6e23,982d0b7b,8791fa9e,4159f26f,b42ddc08,85d562b2,fce84a38,e2af9960,1ebdbc64,cffbb669) +,S(de226b16,dd1e5c26,9b7aba7a,d63badc8,3eb435e8,7aca85f1,41d42712,95d8f721,62e1e399,fa2ce72c,3f87dc03,de33d913,3428416a,434dd20d,84156470,1ac8423a) +,S(60a46f42,3fcd3295,fd058be5,9f7ff164,fa762995,27cbd2b1,d13a0bdd,97d140f3,9571d2de,7b789e17,e46bc31e,1a03cab5,912cb854,ccbfec8e,f4d370e,df7f1219) +,S(6fef445c,e1b4bd91,fbd3a77a,ba0c6364,80d7e759,3f42a7f5,ce089fcb,c32249c0,115fbcfb,af46db83,9ae0cae2,e581796f,f82e73d8,7d4c9a91,9a92c5e9,f4fa347d) +,S(6d37f51c,a8d2f953,a3e5f7c2,6edebe57,a9892b5c,14482a30,9145c4fe,4293522f,78e511f3,6718ad4b,de6897c,d3b90e08,cbefae5b,a884bdda,a967eee,9d5309af) +,S(c0ac827,5bd0701f,5c9cb035,eddbe996,738aa155,fe74acea,a76b0351,3d46098,e7f32a2a,188fa708,6a968490,60ce26a4,31d76231,6a65a6b7,c3e83201,f8e3cd97) +,S(9000dba8,6f895023,1fc507df,85faf4a5,822a648d,4b256b93,5d012060,50cde108,9b7ae836,94b2e9e8,bbd8383c,2f4cb03c,32331902,2f58cff1,779d83cb,654ef3fd) +,S(f1109bf4,b490bc8f,36609253,26c2a2e1,ad58dea7,463e1d9a,28aae8d6,969098a1,87431a27,9fd72c10,80230514,1c8c17ec,6e3382c2,c325b022,4a800509,5d2f24c5) +,S(4de871e5,4e9cc6f0,8c4aac8b,36d61f83,929adc8d,4f6e18b0,d1dc855,6e8c0003,25d1fcf,ca98e8a6,c75d7fce,19de16bc,805f4b70,e9a3e9c7,f0187f07,70d3bba6) +,S(a23cb675,92972bbf,3a6e89ff,94e10010,8f47b467,fd8cdc80,b66013d8,62766ece,8dc70b84,ed05c23d,a1681126,77d23aaf,cbca18cd,fd7e9dc7,cae5aeb9,47cf548c) +,S(295d0cc,e96d8f8b,91ba9dd3,be703cc5,79d3c938,a5b7c32b,bb40e149,584244e5,a6d45a06,a16bd4bf,6af0fe37,6538ae5e,745e078c,12b3ac95,2653f7ee,2b03c926) +,S(7c683b91,9d5376a6,d40b13d5,1fbd1769,6cb40bcd,efd248af,9e102545,eebabbce,3da0c9d0,3608856f,5b7ed30b,8d9f1562,197d4e5a,7c23ae39,332b1ada,adfd3f73) +,S(30f7512e,d27e249a,95e0e21f,fe22ec23,8505f39e,ca9f41ec,df5e7ef8,1c0c3189,2f5fd85e,25ea3a3a,15928651,4b473197,9e4e7f7f,56e88164,fad41e42,e4875169) +,S(9377bf8c,96584f27,324a41c7,78d6314b,1c7f842f,b4910835,431f5a76,2f514961,d599cc55,e2eddb2a,e7d7fe92,aed830d0,3cfa892d,3a89cad4,335fd6d3,69f3df42) +,S(3589ffe8,67f20495,ba3530b8,5f83c54f,28a66e78,6bff4ca2,40ac1d55,6d31e9be,98822eaa,983089e1,209c22a8,9f133dc4,d75b3a67,8fdd385b,581a9274,6d224c89) +,S(39c1b1f4,b2dadc4c,e58e0f84,1fcc6415,2c79e77a,11d53f85,999db8b8,ea3f8935,e785271a,d9df3389,6436991d,eff9da83,50bb8a42,616cd31e,6289aa84,d4256721) +,S(dcf11459,d3d62c2d,99879918,8b6118e4,b103f9da,2453b72c,ad5eeded,8b25be33,dc038c1a,af3270e6,345a92fe,7c7dddc6,a190f6c8,fae7d7b3,30a3cc72,f3a1c074) +,S(614929dd,1de9b0c1,3f4d82e5,5bd8050c,a32ff05e,6eb238f0,eed635b3,6623d1d,afe8517,c9e7f17b,a1918e3b,e8180ff6,afafdc43,1acbea6a,e0eaa75e,c4d8a24b) +,S(f4a72228,cff6da94,a45da35,5ec8adbf,ef81609f,b59a8296,a7c1b0ba,9cce743c,545200fb,de095aae,9de90f1,569c6bf,2fbcd025,3cca1e50,a25a81a6,e19cdacb) +,S(63cc4273,6caa5597,46e62fbf,5371b943,57aa164c,fc8fda65,b5fe524,e2c93f7,1fa4ef5b,c5a6413a,d6ad2bd3,4b08289,e7d8224e,450f04fe,9b47c45,ace5665) +,S(ac175228,118438a6,d2cf761,f345cb04,aa7f9d89,9678c201,6b84be2b,8eab8889,dd7df8ae,29643dac,27ab01b6,8f7765f0,832f2989,99a13396,3435a982,aa4af2b1) +,S(9dbb5eb9,637c41b6,c4a5a2f,72efab5b,823e8622,f3786c03,dd678816,9e4a0e48,772d6ba,13f4d61f,42dcde34,b8519aa2,5aa0107,89c625cd,1ba38d4e,b7d924d7) +,S(717095dd,d2fcc135,1015b586,65a0d888,4e88f599,b8c32fb1,73d5731c,3ef7dddc,1de0f109,52b470bc,fb23da3f,3c7b640b,4727326d,d18e020e,581fdfb4,7e4fa5af) +,S(5ac230d3,f829b1ea,401e3964,c14d6e9d,a32c4a68,2ccdbb2a,3319a964,265872ca,fac3c3a6,27dbf66b,c5e06a16,e319ca43,423484d8,3217ae81,51bdcfae,c9c026ea) +,S(d27ecaaf,a39f415,e1457537,b2e74e1d,382496a1,51118100,8577cf76,1f8752ef,fc480b67,46cbaf31,e3d8eb6,4121b68,d5938e84,face3ae3,5dcdfa4b,71c6c037) +,S(e08777dd,f92d99b7,c4f87d53,9fada8c5,703af619,3a088d64,77f1e20b,f2ac6cda,25a4f88a,c6cb18b2,4e96ecc5,3ce10d5c,1202c4e7,edbdc070,db05a501,29ccfee9) +,S(45ae7ab7,afe9580f,bdaa6a13,8896ab97,63bbe3e6,88054776,753a1180,699ba6ed,dc1af7ed,127fe06e,4d0d440e,3d96f43e,502f797e,fefcff1,6c46e6a8,a156f322) +,S(fd28cb3b,71c50453,b3cf509a,768b4c2e,6ae26514,5801c045,327e1de4,f4d00590,b0684f95,4867cf44,aa5081f0,8174ce21,3298a22b,257f6159,c2666518,5ce5a7b6) +,S(f226f00d,ac6f49f0,a195e4e2,23b9fba7,95681660,7671dd7a,158b3260,1c1d850d,d05d5c4f,6925a38a,b4630e53,a1986fe9,d823a08a,3691550f,10f71b65,a109ef86) +,S(3cc61613,a80d8480,87ce23a7,2b3038f8,a994e1ec,8c9c740f,f0e44e90,760337a3,8474f96a,24093af6,94221f09,f95ab010,90377f1e,52a173f5,a11dbbda,cd3c3956) +,S(721ecd89,8cd99712,bd3be233,1f57d686,633e7ed5,c95e6223,e5cdace0,ce60e736,31d294d8,6fc07cae,4a09450b,fec633c6,21dc34a1,2f7668ad,532ac192,a0ffd69f) +,S(dcbaca58,1144d9b1,b2586271,5e58fa8c,d5b1062c,ffabaa2,db0fcffa,2b2eff38,9cf7621d,339f6cff,90efbdca,5e2c6174,708b53e6,1af38689,e6d3b257,21ec7d34) +,S(ed314e93,e649ec2b,ce491938,2c7a256e,b9300b99,528e7878,3421f337,15db8b92,70a81aaf,229fef2,e2922355,e1f15465,53ea0348,e3dfb18b,c837ddcb,60744a11) +,S(6bd19bcc,7a59bc8d,19a97768,95f65ae8,5f5c7eb6,429c09,85436b8c,29c036ee,51346de3,f4f65681,bdbea28f,843545c5,31803ce7,78b5732c,bc42735,4999090) +,S(99ed1e15,6ac8dfb3,604228bb,5be088bf,ebe9d640,7ad8be15,5777c6b1,d43d9acf,75b159a4,478b4cca,80ea0ac0,472436ad,69f57e9a,f447c61,e19910c3,9d2c922) +,S(3e166f8c,793addf0,84add90f,b0303970,f00c3c3,8c36171c,c7fe0877,b2452045,91659a63,b0cd2a65,ec330f6f,b9a6cc6d,9f07e382,7b94b8da,1921aa8,1d5bbd59) +,S(fc1baad9,a3a95f38,bf8d1b16,8409d09d,a1b1a432,841f656,cf8559cd,176df936,31f7a7bd,b013b89d,5045f248,982b5b4e,e0b4d791,21b6e638,84a563f1,a08af43d) +,S(80b3ad3d,4b371eca,c903c879,53386884,3bd31843,4e9c925a,5a5a819c,ff7ff340,fb1ca8bd,aac96d84,c67ed7d3,b65fac69,108ae28,7347abfd,f20e4cdb,712af178) +,S(bad065ab,2901f727,d76c6c36,48ef7aac,2a87d49,4d727422,73cc2e4,68616af2,ae9d7902,16b5eead,4d9d69a2,eaba2972,fa925a34,13f15d92,236329c7,470a37ed) +,S(d1f046d9,d700ca6,995beb99,cc8781e5,a2fb758f,7e81bca9,bce435f9,129b8fe7,274ede5d,7eb815af,34716718,84433143,3090fc0a,46575017,fca345a0,6111a4df) +,S(db535f55,e3dca80a,58dea798,d29aa0f6,99df1761,473a7ea1,751a047a,33f0a22f,e7d8015d,931a3bca,1193df83,7e7a8f10,e61b86d6,477a37cc,ed3528ad,5b53ff6b) +,S(da1dba06,a56ef0fa,f98b1a5d,b9a4f184,8635b7e5,164cdd50,82ae691c,ca42a80,86a8383c,a69531bc,ae806621,5cb4160,8807e265,b2179508,d928e312,a210c9ff) +,S(267c26b4,d980066c,7dd4f29f,f7b54277,3b176b77,9b3588ae,ff5ec28a,9aa42e7,3390c03f,f4e5eb25,5d230053,1d93daa9,d584658c,7fa30341,42ff20b5,827161d) +,S(8024af52,4e6ff955,70c7915,208491aa,5561fd29,fee5c27d,4f3483ff,c1cbea0a,c9de78d0,498f726b,8078fc0,609e76ff,df7a8a71,7345ca16,dff1d7cb,b2dd86b0) +,S(11ff6a68,c7beb420,7f0d7dd,371cf000,dc3dc195,406882d2,77953445,6208f661,b53ddc25,254781b5,1e7cac25,c1f7e3bb,916b75ba,97a7fdbd,658c1bc0,a7b4092c) +,S(562a1083,f9a68203,39a32d7a,65a9982a,b70d6596,b00751f6,aa88c27f,36e3c929,a380ec7f,908808b,950e7d25,510ad741,66ec2061,50923364,55744acb,b1e05b51) +,S(4efe70fd,327c0d69,3b6a7598,7ef64573,e097fa5,4cf077af,68d082e2,d341c413,10d47b9b,92e0b62d,d9a8befc,3ed1db10,b110a346,8cec98a,4a1abef2,c8ce3dc7) +,S(4d64bf0c,d7f128b0,bde8576c,91e01c27,354abd98,2cd3034f,f9ac09c0,23a51f20,159e741a,f57fdffa,de7bf38e,14dbc2e7,da3c524f,3d4c8d6e,b9dc32e5,e8a5e28f) +,S(9a41634a,ff3278d6,b3ef0064,ceecefa3,466de2ac,372ae43b,c48f30b3,a187bf,eefee0f,aebb77cf,8447a193,6564498a,f409e530,f4053c3c,ad27eaa0,6aeae2a) +,S(e1804fb,9a6bde08,8efec2d,2e5c6774,2c85cffc,e78254cf,4fc4ded2,9102418b,e9cab1eb,9c1664b9,c2fe81c9,b3a665ae,447e93c3,183cde7b,fa56ab34,7efcdda7) +,S(a603744,c0247b0a,f821705a,dff44d2c,717611f0,25f9fb41,1eb62f1b,64593212,820fd32b,706a7638,4335c0a2,f8713b9a,6dcdb015,a96b9d9c,e5c19bb8,ca603b61) +,S(a6f1d9b6,895b1298,34972a2f,ec96064d,a1108ab3,aae276cb,66a620a0,495f20b0,9a95dcd0,df038394,63ff5ea8,18679c3f,7f55d7ef,83a06880,29c9d543,6dc8273c) +,S(4ac51432,7822b63,e00f920a,b6e22142,f09f30f3,bd74c418,93baf126,cdac5c48,abf5d148,77e94a46,45fda161,f9455bbe,7ff037c7,720f6a6a,d7e4bc31,a0f43885) +,S(5a2cf55b,a16eeae5,8cec588e,1b339422,48af6e37,33604475,2dabbf7a,f7fb7a9b,8f27be2d,32ff72cd,4fc5aeca,5de55a21,a45f8c1f,7163dc4f,e0c00040,e69322e2) +,S(e16f23e8,ef48c1f6,4012b27,f6ffc4ea,a876053e,30cb388f,232b3d8,db011c99,195ffd52,b0afa5c0,da95bb97,7bda614e,47ffe3ea,13429799,e8c390f,b8c56000) +,S(65367cd7,ac109f71,50de4263,cdd86e92,28923a3a,ff96945a,c1bbd163,8524fb84,cf0b9ba,fbe67dd6,4d09b170,beb4fe8c,a7687c95,68086b6,8a7834a5,1747d731) +,S(10a8840b,39443b8d,7a44228b,d6dd6647,89da489c,8e954d54,a5cef366,6bd6eac2,7ff6f76e,e4aa58de,185163ac,ef7fad13,d8cc4055,c4e10a60,7987e034,c661eff2) +,S(3fefe8a6,c01b8202,6bb9d038,c577f16,7b1db5ea,91ae80e1,528b1327,5245d6a0,a96df5a9,37e6144a,454a0b54,39d68eff,a959757a,7c9fe350,ecd58c3a,3b637b5e) +,S(ef93d77c,e4162e9,6bffb908,f5d654d0,58595fd5,d6184c62,6c3ada21,c4052b61,40088b85,c18d97c7,f59a23a8,645d169d,e535261f,6cd7466b,953fbf40,f3cd0bf5) +,S(f1789f5e,b0fa903d,485edbd8,4971b7c4,9224a2cd,519bdd40,d627bd82,b0ca4872,4c845cb6,5456457e,a2f570f4,77b1f4a1,9e36a905,adaaa8d0,5830161f,a71a9da8) +,S(d0bb1788,ebc75ed0,20c0d15b,ad4e41f0,64193890,8a8704bf,ff3cc4d4,cc9b3274,3a120ca8,95a327f4,8e687796,30666649,43ac5524,44df62fd,8f7abbff,222a7641) +,S(164ac10c,f7807ae6,4d6aab31,72110d42,2f05e461,aeb9805a,3facdf7c,dce8963a,8dcf43d4,40f1dd90,bb1d6f85,849f98fc,9b6dca26,301f3209,3f9dc59b,ea549b69) +,S(f122d965,a8e40e3a,b857dcf8,92949f0c,cd3aca29,739a2e40,9876c782,941fbe5f,4d994b9d,d9e68983,78a192d0,bb670bec,71504372,d218e257,f50d0268,da447371) +,S(ac971547,75e5a92a,1aee2cdb,f5781f09,b975fc21,816e7829,662143a4,e48870a8,249fb603,795b1742,96767945,278dc97a,53fff7dc,f8bbfede,f8943c71,43c9aa71) +,S(959ec91e,dfd5fdcc,90d3da81,1e9c870e,fb0add6e,144b3fbd,d48c485d,2d330906,1e5ec128,b707c761,b61b5ebc,653585fe,29f48975,2a4724b9,aed90a22,6257ebdc) +,S(590795d8,ed7d8232,457b2d15,76de09f0,3c6abd8d,23b5e8b7,c59ba93e,1e982859,5edd2a86,1a3c8841,60e16490,a47ab42d,a09cb123,a9d803c0,6835292d,34576708) +,S(c5372b98,7439245b,eda17853,5cad1507,48fdb4b5,bf1ba555,89714dce,a3e0ba9e,f82d0b61,7159db8c,35536a5,46b69c4c,767afc43,8b64b5a0,22e899b1,60bca987) +,S(f3d959fc,ae39cbd3,ec8d2016,630f26c4,10161128,7dcbdee1,6534f96c,e35bd38a,e1e55c1f,87602783,2ffe2f97,fe460147,da586a03,ed0ad6ce,1603cf17,ac9b3562) +,S(922bc76e,be3ce378,2be3d960,489b064d,3a28043,f8a92cf8,dd5cec2e,537fad9e,b3199f57,2508efda,230b9ea7,51a95218,116fbf5b,d1032b54,352c0995,f5122109) +,S(45c7dd40,7a6d2c95,79ab1df0,8070acca,2c461d88,dbafca12,99a38734,d9f0360d,3a17855b,5f2469ed,6c3c4e04,4dd96f4a,d076eba6,a60e8e73,2644d25e,67e85ac4) +,S(6422d998,dfd4b00a,3dd89a5b,74411c14,f1af5c9e,1f090d5b,33ee2d26,b959bacb,e2358f34,491218a1,93d8cea2,276f5b3f,376f597c,703bba09,cdbf7d89,37a3bb7) +,S(8e048214,33196d15,1a4640f1,92bf6c1e,95b1a3cf,5365a6f,535cc82c,c4b0535c,d6d2d73a,1f652c55,9f282ee5,35f55aa0,20012195,8ba94e65,b638ef50,e97c34ce) +,S(5a2b3da8,b5eb2f0f,8a25a9e1,7124613e,b8a7080f,15d42c4,a1c0709f,e64a79bb,607c791d,eb54aafe,6dc95f8e,6ef9d8a5,a6435a82,6b824cd4,4227f188,bf86e6b7) +,S(143587a3,5cf614a6,750f3d91,220abf49,c5296e00,3cdde13e,1a0d2d5c,f6cd7ccf,49bc85fa,de6cc58b,49a1af49,46c340b,15f14c7c,2e83201b,6622f2df,86a653d7) +,S(f0080c42,8737c74c,c3b2c4bc,8c9d8505,ba357b7c,ff25f1a3,ac81be19,dca93193,bdd0119f,57bf674a,7d7cfe32,7027d1c,1c6a5ad9,2ca24f0b,5cf25c39,4a3951f1) +,S(877ae373,e547fef4,36cb26b6,85d7c426,3e162dae,ac0749ce,f7748d50,5d130034,1f0af495,b750341a,ed956b79,8f268ca3,e1275e15,32e5ca8e,6f9f6df0,d4dfcf5f) +,S(a418df6f,635ca18,8c96a071,469a272f,e55f0706,b73aca0,d1df2ab9,e8e619d4,2b06cdbb,5bbb24e0,fe499a6d,aa5b5918,2e755818,694b8856,525ffcd6,2f754e3) +,S(4c213d74,bb6fbad2,25edce4f,44c7b0b4,114dc209,4eb52967,1d907637,a2aedeab,741bef9f,ccc65c15,8752c7d5,48afa9cd,402fb5fb,206c5be0,e480df73,9f970b51) +,S(a37906fd,3f94e51b,1a94073a,4890011b,2cf93bc3,bb4cdbff,ecb7056,20deb13a,60a3b0b1,c14a9b1d,184d5e55,23314b70,8a8a16dd,894aa332,f01a2d67,30e6030a) +,S(2c677eed,639eaf51,64b8ae3d,26bb4652,d6d6528e,5b85225c,5e84ec4d,4de72301,df0e4c06,d3bb7cba,17f89240,cac07c24,5fe63931,3b2d278e,aca1b9ff,7ee832a) +,S(b551f814,eaf86be5,335fc3c,5b01c001,684473b0,cfac8939,5d61df4b,7d7e77b4,a979cb35,469715f8,3033f923,b4ae1e7f,8818b6e6,11a4cbb1,bd399ce3,646664b) +,S(98d5c718,5c8c04ea,f1f61ad7,40df0c71,2cd47ba8,74141984,fba82146,ddf45c39,aca52591,5c737ec2,eaf88f5,f1ecea89,9d4a8e2c,428f5bc5,b36d2ba4,a0050804) +,S(5148e2f7,260fb652,68c10485,4fbccc62,ed1e1386,ef8fbbc9,a0b23e2b,94cefc7c,65b4dd2d,35dea498,5ba4a8cc,b1a08dbb,9e9b2716,7ca96e1,29672452,a7ca2500) +,S(12c699c1,8c9d6410,b8a40ccc,bbeb4514,a08a227c,982df1da,f91e9131,8e0e753c,7d953c42,89b55724,3469a197,50516e88,4889e968,4ed28e1,20b022d8,932fcc99) +,S(4d0d3ff8,a7734011,b36ecac3,7ebb2312,134e4479,5039ac63,9dc69d48,120a8d20,edff17a0,e0984c60,3c4f1026,197f2173,960b3d29,f0b0ea57,3979605b,144ec64) +,S(ce90b70b,3e7b7a71,a91b0985,a668336f,ccb069d9,81a9fbe4,48125061,5536e42d,8cde9d56,12e0ead7,524640ca,2875606c,d3af73e6,457f1e67,2e63a478,5569000) +,S(28c79327,6bb1879d,99fbf985,1d2fa908,d197f5b1,c83be97e,360c4931,563b2d8,c8944e40,e2f3b546,5b6b10f6,ae1cfbe3,bc0f3e3e,33d91085,7c18496c,ec643868) +,S(6e2dad06,2413cf01,804c2b6b,55b707f3,864d4c80,87d30665,9a1fea53,e7442443,9da67c64,e05d6914,30a1fba7,39c0fe36,497bc028,43441f7d,c4c035df,129430e0) +,S(bef94ac8,3763946,c434d03d,fdf437f9,19f26188,923ee54f,8715b724,8c4d20fe,d2324534,e5fc1dc6,6fb83032,e95e1406,38648473,ce7e38aa,ee7ced54,31e25db) +,S(53548c57,f1b45c1d,ca166a24,c0f2653c,9b7d8664,3d45d125,918cedaf,818e433d,cc138946,f0c207f9,c01307e2,130b13a9,c36aec5c,3cad640d,b6a93804,f10c3b44) +,S(7fd4f784,7f25c901,4e8b0e09,b8b723ed,2aee71ab,fd47988f,90f6ff40,4b5867e,ffc3debc,901f12ad,96605805,a6e402db,58eec18d,375fa976,41b5d226,74a1bd9d) +,S(444a8a7e,499789b4,49c62424,cd9046ef,d4251bf6,9cb883cc,d3dc79fa,5397dd9d,4cc5f03b,3356b020,ae8c775,708d56c2,abbe8e41,bf393f82,8f7c45e4,dbb30282) +,S(ff05c877,84d8625d,20694bd0,a4201c7a,4af8c67,8e62abc1,acb0cea8,5726bd8b,7cf0e8ce,6ac26253,cfa5a0b5,cbe984ee,a55f6aa0,90bd12d9,6ec2de7,a996eeb3) +,S(80fdf7ae,6aa31b6b,ce894ea0,83fd9274,e29f4704,88f0a7c6,79b8339a,de7e4ab2,77d7317b,16962745,6344a8b4,bd4575c6,49e066bf,bde58fe,3f46e60a,3952fb75) +,S(ac38a4c8,10a307ca,d5020a74,f0d772d7,ef20227b,7eb49589,6854aead,41879214,f49c4cbb,3c675858,416f77ca,92e229ec,d75ecfab,3415d213,c7cd2cea,1f5016ac) +,S(b3736edd,f1e10262,fd562f40,8f502f19,3a90a435,de9ab6fe,a2691155,a5f75514,818cefaf,f190353c,f01cb068,2a15ae0c,eafa2de,657ee751,4e483057,ad5a78c8) +,S(66d67e12,d100c116,b57f6d5e,ac6a85ab,e698d4f5,cfb6722f,12738b33,310dc295,9cd4fa1f,3a0c9a54,d3608ea7,9bbd7ea,685faec6,32d7318f,d4e25fea,14a05dd3) +,S(b856d75f,756ae484,daaeb651,46ecdf0a,9fa10c6b,a7b9b33e,b8747135,3eb59043,5c8542b1,2f249649,4b3a177d,8df246f2,6566da1c,727284c4,b041a7db,89cb0a38) +,S(683bfd7,3202393,458142cd,661a6543,c736b15f,b8595548,afc52951,f9c47d27,90f52a40,f5dbdf26,51429f84,ac68cd96,420387a2,8d94d746,b4163411,762de166) +,S(2feaa1f0,811e1e65,13895934,533a0941,41ee1ca7,f8975896,3d00f8a9,1b2923c2,9dd80976,b884d401,5d7701c3,5e6ee1ef,690d1820,7d06e02b,7e3a10f,e8499c1a) +,S(ce652937,da9ebaf3,a9765e9b,144d20cd,847070aa,1a968097,80e07b58,2287cda4,c1c46ffb,5f152dbe,5a9db378,29e7ae84,454e1736,eb7a1b68,1b321f3,41ba572) +,S(9a695bd9,170163fb,ab3f9738,a750bdc7,556087b6,b04dc8a8,4fd5fe68,78976211,f40ba1f3,75accd85,9a42b133,294868d9,dce262d,64d6bc27,d0c9cf12,3eaeda70) +,S(e5baaf68,bd3083ec,bfabd6d0,9e4da4c3,5908b0a1,75578ec7,18cd3223,bd34ba44,ab8651f0,365cc3c1,50476d0e,da3e86a4,5feb7f46,a9afbdbc,e4defb99,ba27fb0) +,S(2c26cea2,b507fe77,d8f3530b,b7ee1fdb,dd0c4dc8,bf63d04c,e06376d8,ffe59cc7,b344e3af,54d03eb9,b0b67151,b5845297,c30a1cc2,aefc004a,5000b69c,e630d62e) +,S(7c67539f,52af2e61,88deadaf,a07e2f6,4d53339c,7fca7a3,c2a149f5,c8bbd0e4,3f9872fd,c21c9136,4ecc97e,c6642ec7,df7a2cbe,61b63038,96ee73e9,309067c9) +,S(4b5ddd2d,ec8b0bc9,3b6e1d17,e1da71c8,3345614f,74201aab,8f9adc1c,aa249574,cfada2dc,aa3eefdb,434d18b3,d2a85a6b,6e16e755,6e55fd69,5dfb36a8,aac5460b) +,S(d775c2f2,ccfc0835,86a66edb,873a84f8,f9bb6680,2eb0be59,216bc35b,88d80e4b,c8a5d9b7,988a2231,cf6aa0b5,19640a86,ff56ca57,91135ea7,65bb3a4c,fc53ddbb) +,S(71a3cf09,78810f9d,fb01d984,43dc3da4,b005b07b,36ad4dc,d3c803a9,bcd9bb4a,8aab8e21,7db0301b,9640c5b3,9617ad55,bd4a3c4d,8989df5a,1ad31040,bcaaa55) +,S(bc71a054,92b696e6,200596ae,3d778ef6,a82f7d05,825c0d3f,ddee8bb1,991f53b7,15789125,9785b8d8,b1374460,630a908,d1125536,e400fb52,b07aaf61,729a2a15) +,S(9d220919,ee62bfdc,fb81ec81,a0f60e58,e8d94a0b,c6b79f7e,6f891c64,fc847abc,8149379b,1a073c2b,8dffe886,59f4e94c,75f3a7c8,a7bfaa16,e530bc7e,6ed0c675) +,S(8369766a,d30bbd19,a330c6c9,1e3ad594,d25bff1b,4e3696e5,c6c8c33e,eff33425,a27f7682,b3f4575c,858970d9,c21f7daf,8ed5d28d,8617c8a4,e4b958b9,72e79e4a) +,S(4e277875,e4aeaab,1a8d36b5,487fb427,e91f51ad,1cd68ab4,57db2e8b,20542451,9faeff65,5bbc4b81,f96bf1d2,a152a546,d138fd0d,a8f8523e,7635020e,a26566e0) +,S(27f907b5,1b9dfff3,e68d202,72605a91,825046c1,b21336b1,8b91023,39a0d2fa,115225c3,6cb13600,fb84bf3d,dd5c49d8,105f459,ffc4068a,cbfd7b0c,52d4a15) +,S(6d9feb20,650674c4,437ff42d,41f70f16,ef0900a8,f3cd6818,64b42eed,56b1fab3,82cd97ec,d82b3c1c,2e55f857,653afa3b,5f7f7b00,39aa2444,f60574d2,fa02065) +,S(8981d2b4,3360669d,361c3b36,3284e729,ecb9cdbd,3bd17558,857f2cf7,8187bfac,1b9aeb27,d5a45d1d,8791bf73,614ecd5c,216b263,6c27645a,3e86d781,70d48498) +,S(84a67518,e47ad1fe,25540d55,77e92ce2,81691685,6d3c10ce,9c5985a7,72e1d72e,d3cb93af,85072ea2,e6c11777,dc4b73fc,16ca04e2,699ef356,dc8a5341,c5631658) +,S(d3e66756,72a6cf77,50c111e2,e65a6674,7e666cdd,b9dfb418,d50c28d1,aca8c683,7776ecaa,20e5c6c3,ab5aca5d,8233f83f,4e2e815b,dd1063f0,7359fae3,a6556dd9) +,S(ede97def,71d45688,804e76b5,ee52563e,522a7684,a68efc4a,f7b2db38,65b87bba,92e6d20f,c9c1276,60a279f9,5758a80e,85bafb8f,b77eb513,7587b692,fdae702f) +,S(3359e142,e000484e,cf7db3ae,2312e703,6ff84f84,247ac6ed,25a0b9c,eae8c871,67b039f2,3c845fa1,f38c98bf,739dbf28,d00ada09,36e4377f,87166f9d,d21cdf66) +,S(e0d0a972,c0502fd,2654a3dc,40914a55,96f675ae,cf0d958f,8fd62c7e,122b44a1,cbeb1bc,34575a7e,bbfd916e,dda11903,3ee29e2d,1b11e171,8db7bd47,576b0312) +,S(50b89367,5df77704,64031ac7,a1f5d5ed,4f332019,d8da2605,9397df84,21a4c987,c4765d81,63ec9eb,a089c3f2,56d6ff0c,45c38253,3d9ed204,cb04f335,d292f293) +,S(5dc62d8e,66775ff6,f21e84e9,9f8e8123,7f80cbbe,41ce9113,91ce432d,cd6d446a,4b456b7d,e27045a5,76e1cdab,d163fd5c,b020cabf,125f5de9,9ad6eb14,1773a9c2) +,S(8ba1778f,c7921845,d2632e18,790710c0,4e56ba7e,22efdb03,fdcd4f96,22c10971,1f31fcff,a8359658,b39d7d43,59707268,48ffebe8,8f418c53,f48c7af6,3e3e3854) +,S(a3a14614,7d1ea7bb,e6bad055,fbf9810a,999a102b,ba8b694b,e7ada06c,8db9fc7,c9827731,d4321284,23ccd6eb,3531ffcc,b3bdb87b,1a727d57,a697eac3,886ac294) +,S(9620a847,bd2034aa,c81671c4,436682c5,f6ce1af6,4d8df286,21ad1c2f,e0af78f5,e1cc6d08,a7e3dffe,cb47e32f,4156bcdd,6168a205,e8959f0d,99e1555,4d826e1c) +,S(a40d86a0,aa7d6a79,3f0b6a52,c48d8fff,95b2c57c,584996ee,bc9d98e2,796016b,ec54d4e2,d453466d,ad94c15c,b25617d8,62911b4,45f44873,96ecd950,a351ea2) +,S(71ef35a6,f60f268a,57573b97,9745986f,7e5f40e9,ba64efbd,5ed90779,b3484c80,eabffa1e,9ff3590a,c577df7f,6f5a6ad7,2f3693c,be475669,8751637b,4f8a1ba3) +,S(bbd1a408,c742a3b2,e49ffa52,c5f70958,5308abbe,f103e674,86fc76d7,a4f68de2,4941cbec,9d07e13e,1b0fbe96,c7328459,ee6e1e08,50a079a,2ac0b61b,5d246124) +,S(169ebf38,92116df5,3e09c92f,f2c89b5f,805d60ff,9584d2ab,433f1f9e,84ba9009,914f5516,e7667ee1,581b5ade,bf1de48e,c997d149,1e932a08,34503599,7c6228d) +,S(8f157abc,4c5ec7fb,eac11545,890d8e45,d71c8d9e,4c4e0c3,9777502c,f8666acc,d41576ba,1e78a9fb,9899883e,602bca3e,14dc709,8982e1bc,63518138,3ff25908) +,S(8cd338d5,694b26dc,4ebcd8,39a006da,84f71f93,94fb8100,91ed8cb5,b4ec9a8d,40318c10,dd88d9b9,c080eccf,45464ab3,3fd9d34,c2027d95,2a6ecd21,d0002578) +,S(20e47e2f,7ba5ba2a,d36171a,f4ad760f,a64748c2,94892e28,cbf0ee3e,293272f2,b96ad220,56b89821,5c052089,789e4267,162ddaf8,76c720a7,71b15254,67be00bd) +,S(582ed8a5,a0d38f9c,db6942d1,1f411dee,f9c31ec6,ffbf1579,3f3cb5e6,5f2bb880,14928c0e,4f9d9d3d,ec4a8db5,64baf4be,948ea892,34a6e352,a4cf4796,3ce8486) +,S(f4a6f59a,6e76c11d,3f7daf30,b8c046eb,b0bcab8b,6d1f5e7b,877eb1b4,601896d6,2d39c6e9,e5d84156,559a05d4,a9b148e5,ccde4641,e4bd9abe,edc8a648,b070f0c5) +,S(2a820c60,f71cf5c,76e66bf0,15623f06,fc8564b8,c763a52d,2c329af7,30957b24,b38c0703,d7429599,e6c9a1d7,250078d2,36f77f7d,b9956d37,fd92646,77ff3ca2) +,S(8c2d9c4e,9fccbf64,871d4802,6077a3a9,33634d3b,c1d7f872,6231848a,6e2799e,ad50136c,ae43bb6d,8c49c534,e80985a7,cf032d77,604c2db8,d5954858,a9351a7d) +,S(b18e9053,744b3ed,d0b991e,23927593,db00d25f,adfc4490,6eb0d19b,74061ba9,90f5ca44,c829b2c6,771edd73,998034d3,43a8aab8,442302a7,2ffea92,b33877b6) +,S(cf1d157,b03d435b,905d2f58,cc53bfa1,d124827c,f4ac4109,33078dcd,1ce835be,ee37a9a1,5547c7d6,a0f03cf2,1451cd64,3ea656df,61eeb1ab,1196d959,ca71b459) +,S(8d8b9d8a,d91a840f,b2e1ac36,a6f4bce5,92fc13d1,f22f84c1,562d63f7,e54a6007,9528be43,93ca8f2d,dae0ec3b,439abded,ee9227e1,47ce6ee1,ce61b46b,b842dba) +,S(604b5544,bbc5b0d5,716c936f,b0d9a4cb,7ae04a8e,1d5a506f,2561b463,fc87fc9d,33fe2f9c,4fb9a6e7,41c1e5fe,7d3d9edb,ee3cde6f,106a1d8a,3e319254,a16ac8eb) +,S(3e7ed414,1058ee44,6057aab7,49e14ca2,cbd16d64,7959fe53,9ec0916,fbaed8f6,fc15b241,86dec6e0,c91aa697,10a015d1,f66bd361,82f18648,1ba24568,952e79fc) +,S(d0ae7435,86c17b8a,c9524243,16cf42c1,26e46f69,4c69cf26,736d0527,7943f326,bfa02de8,b983588a,d4398865,abf6b69c,fbaca03e,8bb5f04b,1971ce1b,f74e0757) +,S(ef5c05ce,d4f343e3,7e6ce2f9,45380ade,3627bc65,9de0597f,5f851eb9,88be1441,d9267c1b,379f19e,3bd0e40b,74ae8e21,b681e7c2,ad49f635,d60c619,74103281) +,S(176b8feb,d7998ad9,7c73015c,3b09d9af,d7cf4265,c7bf38ca,8dc64864,5c8f49ae,b4bcbe4c,8267c9a3,69cda190,5676c781,7f989f5e,a014f4c5,fc821bf3,8522f1b4) +,S(88f683db,cffc14e,ebb58d69,fb6da62f,b20771dd,3542fa00,97b3a766,bd16c3dd,bbef3de,812103c5,266797ca,252b74e,cf80096,b2972219,f52ff718,1d1cb601) +,S(a65d438f,1247ec44,fd8c4121,c3d67891,8488b082,31fb8854,dd1fe238,f637abaa,5f65c84e,551e433f,dfdcf3c0,b4c771af,4bb50095,dd0fc986,d4d4a82f,9a3f36a3) +,S(bd6a7e51,c5028bb7,f7e08148,af1597c6,d5cddab9,2883d2f,f6a5a6a0,6398cc27,3f2280c4,247cdd22,e8b97979,b9a98e93,c1ed14d,a76eef66,2ddb70f6,7859d885) +,S(a672436c,2896a0dc,54b1814e,c5101451,58f7a3ac,74d36202,34411a09,909d274b,dee80293,468178d9,5baacea6,badade56,c81f3d9d,95642654,a7afcece,bfc2ec3f) +,S(ca0f55fe,d3a1d0cf,1adb0993,d7d2daa6,57891ba9,321104bc,8d9e0379,f03a24b0,dc01b8e4,63462dcd,91588baa,ebca8d8f,52016683,9671399d,b5843e6f,5a3cfa6f) +,S(610ff08d,9bff021e,544961c,cb2fe206,211843a7,ea0c74cc,b91f0b5c,4b6429a1,4be3b18a,ee965fa7,dabdaee6,8fcd3e12,d889bc36,35f160dd,9b0760be,d1d46b28) +,S(2d6f8215,a70aeccb,78cf006c,ddf8f0a2,6b695dc9,622dd622,38fcc638,a9ff42ae,3fc0964,e2a3c969,e61e4e5b,ed50f337,7a988715,246c50fd,3ff45487,95a3927b) +,S(8c0e99b4,868e39c5,b610b132,de1a09ae,99846826,a42fc4ea,70b0c630,88a1bbbb,32b8ca42,f0a240cb,2876a41d,e61b8c17,6ead992e,8785a95,c384c536,141cfe52) +,S(1528ba8f,9000ae75,e3062af7,74ef6d77,658c6d1d,65af87e4,dbac9eb0,8fc96ed7,a8dd278d,54df6bcd,1d4e6466,5753a8bd,2d39f0d5,c731a53a,5faeca64,513b5651) +,S(c1466ea5,d9256a7a,f13a040e,29515858,104394bf,ac5af7d2,fa09ef7a,6ff1d7a4,cab6fec6,fb36d879,f0684b54,6003df0,d8bab3b6,e1050a7b,c05457b2,75be5128) +,S(ce8bb093,e051089d,2a297a87,cf90c3f2,2ea946ba,87a76b56,c6f11812,d3e98cb4,a8dbba51,b90684fe,6dff556f,bd13baac,679cbcad,90b0e888,4c252e95,e03a0470) +,S(76f3a73,7c9d9e15,8d30ddd9,b092a94e,7c426763,a17a96ea,9186582e,6d6c86d,5b1ca07c,4f345e6c,778ad27e,c6ce3f05,b29c5302,7e40443,b202a022,e5d16c8a) +,S(f757dfc3,23390b21,3bb98872,5dd7d43b,2ed997fe,af7681ad,ee1572d5,a74017f,d0b4e4ea,67879726,700b63d9,88eb3957,74ec4f67,ca1a56be,461d244b,a5b83cf8) +,S(59bf6198,a2deaefd,f080ec6d,3dbe3c67,f27a5769,d91c65c,1492a87b,9ed5f5d0,bf5eb739,9011a282,3110834c,4d467855,6e02f2ed,601529b3,a2f3d70f,8410f8b2) +,S(b1d02f0a,c86d8757,48685790,918c15a,a7b0e85c,f12cc52d,53f8082e,549ba16,7925e03,99926b76,8a80878d,63f3852b,97297725,96d3d06b,85437fc2,571a19d0) +,S(cd27372f,41d8e07d,1bd2ec1,27c41842,7e5267ef,14f3a908,882e4e40,381d1905,cce36e03,661b9f33,ccf810f3,b411693a,c3329617,52098352,2acaf0c9,5dc77297) +,S(112644fc,26ca3599,3b68940f,5cbaab4f,ad2258cf,bbc81695,b01db49b,dd9d3ace,8685f790,7b5ab95f,2f7a49b3,bedf09d3,7ff1362b,3be9db90,4e74d049,15c0bf60) +,S(918df72a,99ce4a16,20e84575,935a24d9,92fb51ea,eb8498bb,3a606e2c,d97d3ce,88b339ec,9ebbff98,f1b8b0d3,c90794cd,bb6b7918,2749b065,602ccfeb,bb8a8461) +,S(9b8f18f2,65c4ffc8,9425b51,d48a770,436e6424,f34a1af2,a7dacfab,fcdcb83b,bfb95e8,6a34c1b9,2c2e8c78,fc628139,476c4af9,3f63d247,5e454a9a,d585ba55) +,S(ad02f2a,c396626a,42abe52a,1ea1d8e4,3821740a,d8b3340c,9b9c78ff,bc24ce30,fcc738e6,cf8a7872,ff827cfe,1b7bb7a7,ad8c97e5,e254db13,255c2d07,1a2885fb) +,S(359afbd,5e60dac9,8ee34f3,f5acf126,9b5c1928,8f54476c,84bfb9ad,da6d85a3,2e2aa1e7,9cd3fed6,71272155,3932ce17,44358636,a18230f6,b501579f,b3088955) +,S(5639aa3e,230f2f1c,e10c34a3,1cd6c78f,c3c15c0,2061f3ca,55e09116,68b279de,e0b6e95c,15de7f0b,3fa3bc26,3a9e83e2,e3a7d51b,462709c,8ed6c2ec,b511bef1) +,S(309cffcc,7b2f959d,85cef3d0,c25efc2b,693d3b6c,ad42ce4a,d8657652,d669ec44,3abb62f,d917b1be,79809520,5521d522,32f949a6,7999274b,cf7965b7,a950077d) +,S(51f3d5d2,dac1d7c0,5d8eab6,375c9130,534a026a,48abf3ca,ce91af6e,533b86b2,50b1e7f,4bdc48ed,9f3fbfe0,ca05bdda,34f9cf2a,ad04235a,ba998a8f,a3e99f74) +,S(8f563d18,33aa4100,4540e0c6,f501d327,4158b0f4,8b3e4e1f,a3fe25ee,29c2a244,4d4c71d8,5ea93371,57f5248d,a012898f,3d031d93,c1803589,2875928,67432193) +,S(36ca2909,d68fdab9,cbc45b39,fb096ac0,3c4853c0,ee19d108,ee7c72c8,a77177a9,64f511df,c8252960,85f3d095,31467a5e,69cbf363,30e12ed6,90516208,d24301b0) +,S(f628b8d5,1f3ffd7c,c201ca9c,2db26f0f,58dd918e,b4d70cf3,80734702,8ea306e0,bd6bce3,ea82e9b,2e8d6eb2,7f557def,b7c2d77d,e6329c1e,a2d360bb,d8adc2e8) +,S(fb7a6bf5,a82c0b,b2a6922c,9d0350d4,b44fa7d7,61002f25,86e41152,c0e67c1b,c12a1c37,f1c9c703,1f1406,efe8f3e9,8419fc33,23a1acfb,345ebc9,4a702da1) +,S(c2091919,5c3e2af2,df14080f,400c8c75,bf8ec01d,a5a5b033,75391fbc,fe78d092,b307b56f,cbebdab3,ef87b1fa,3b66c327,7aec3818,e880de6c,3826b632,f1adeb9) +,S(7627df89,3d1727fa,a06d7c4c,93774a48,73c3bef8,d19bc03e,8d1bfe28,bd3192d1,35d2676c,36f455f7,aa29a865,f0776c52,1326dacf,f6d366f4,bcf726b1,b68451e1) +,S(26666518,7c9f33a9,6d25df65,8dbfe035,a3df6f73,cb059639,ed54b296,2c62b9,bb30bbc7,d34a5e26,a51fe757,8356a876,c4e7fcae,f4a977ba,468025a4,c686630d) +,S(3bda9185,fa9802e7,7dc6a02e,8f2a6f71,ef8b125f,735837bb,c7abf3a4,c62ac683,202edf2b,c11d1784,d7875a76,a0ae3876,22b3475c,bb0ca118,9362e54c,a05b85) +,S(2f90bcde,4486b64d,81313c71,48570d22,3be1978b,7f524097,bc033d6b,983a5c4d,63864e50,2028d475,365b2e30,cca99dd,f4aa759e,cf579705,270fda71,bc384f89) +,S(8893f5d4,e9b00e6f,dc992e65,4c9fcd71,7083edc2,6c71dcb6,562bcfbc,c8becda7,1faf3055,8e631074,fbf566a1,fe0c6996,a80fa29d,6cdb8313,fe313b4,b238ab50) +,S(acfc4ae6,86be5de3,eda4fac5,4da73510,f482fc25,309ce37d,855c3495,8555abba,387f4597,d1878a6a,d37a5b99,8ec291fd,76423f7c,f9bd037c,b9071685,2ac52d87) +,S(2ac4d090,a4c5e988,2f3a892d,d28a5229,d5fe35e7,d74660d9,5422a55e,2017a469,6058f516,2aa3ec45,47a79f2d,7d8e6869,927d172b,f75a1914,a3bc2571,df086c09) +,S(137ed3f,fc13c572,e5bc235c,d13c7e62,c9b1a3ec,250c024e,9c9f584e,7ebadef6,c1e95cc,3a464f51,b43ff02,3c8758f1,319e7c2,f37acbf5,4fb8536a,8ec6fdba) +,S(28a037a,72148a3d,2c89f606,81152b94,6cfb16f7,58f0a002,cfe4d857,ef3ecfe4,b2f4b650,135cde9b,8d3788cf,5c6e7a3a,ec595124,fa903aa8,a1bb3984,fb973d10) +,S(303ecd51,8fd433fb,ce9d426e,8761a76f,78ad6d5b,5f34c0ae,3bbaddcf,1a7a9eeb,6a7fca44,3b73b19e,967a5945,a275cb1a,cbd8dc3e,89d85385,ea956339,99abb602) +,S(cf63042e,5680f71c,2641defd,9d6569ba,c69cf079,f8b3140a,50923381,51533202,39f3376d,fb17fdc5,719a2052,5e1aa428,176643a,f50dc9b6,b8ff3401,eceb4ee8) +,S(cfafbbef,b4a49fb6,96923b6f,2e56c493,34a229a8,e2dd968c,44f485aa,1b1fe4b7,dc0ed34d,4a9c17e1,ddfafbc7,1d76f71,f3950698,18faa16,b5d25c6,c69f9007) +,S(ec0e3de1,fd527ea,6a493ff7,b3c6aa40,4a7ffd76,9a08953d,785d2f31,390d363e,94bddbce,300234c1,82f3c6a,717f53cd,723129c0,ff353528,fc5c285f,8e7a35dd) +,S(f07d3cd1,914422cf,d4b9c0c3,501916bd,13e9cd84,eeb02f7f,84be2a40,4b2bcde0,cf0c96fa,cb393218,37c48de5,16d1f705,dfe91206,8ae2d810,3aa1f77b,39637320) +,S(4a4254b6,6f2e204e,a3264ac0,a00c7a63,8a6fab7d,e67643e2,8217099f,3648db10,b5510e29,be93fc35,efbef989,15f7df95,b187ab08,bacb157a,c26ab2bc,2ee5023a) +,S(56f3bcf,b38eaf1d,35e62582,9f671945,910285b0,3805c1d9,b5d813e8,e87774a8,a9b964e7,9e6b7f9a,9abf3e5c,a147f773,8a1e8270,8677e6ba,c57a7a75,d1ed9dc6) +,S(f89d8f4e,7d32efc,c2d95bf,feaa4c9d,af6b9886,51fe7561,ace561be,6b081295,ca632f11,56a33867,63a65691,17186994,75e48f51,48d770d1,449ec719,8dbacc69) +,S(5c3791a0,d3e716eb,50ae4a07,51f0e92b,2890b933,c6d9aaf9,758e5205,27c5530b,44ef13c6,2de52d11,179e30da,e913493a,c4ed861c,336ae1c3,ca1f8bab,a7b34616) +,S(2748765a,e6baa4ae,62cd7156,16ceeadb,8ab94ef0,d3a3e331,15fa0132,aba38d27,71d4d19d,de63770d,60905bbe,6c7ae92a,f36b333,a93b3359,cd4f1f2,77f69e48) +,S(964f1fa2,f8ecd778,2ce4ee1,87ee3e78,d2c41a0,45a95453,22e363be,bb27e254,c744bbca,de64a883,e9481a5f,a2cce621,5137ae00,3b9822e6,77556610,d4138a2e) +,S(8bf60775,8709c9fa,8503594f,e6c379ff,ee758a07,4f7d2754,58985e25,79b8ca3b,3e638992,b3fbdd72,ff51cfb8,fb118d0e,ccc193ee,718a7715,a5ae6188,87dd51a4) +,S(fa107123,9189239c,2bfc5a95,ddbee798,fbff70d8,ee0d5f5,a10238dd,2e06612,a60cd5e,1a4eb0a5,99133ea9,71d5ec1e,315a6be1,2d773936,c624c468,f968e7f1) +,S(5b48c6d0,9f6f97fe,c03d145e,f797cb8b,3fe2503c,a8944593,83c34e51,44975588,44d86689,352611bc,c1291762,d965f136,173d6c45,28077d83,c6410a3a,906e30a0) +,S(80e153e8,23aa7e3f,2865d1ea,1e5e88c8,5d4e854d,54bca5b1,ae8f1bca,eeb94fd0,edd3fe29,e435c11b,13a92d8,ef4f6413,c888a12c,71823f7,3ed7acba,a06b9728) +,S(16e225d9,77bf7526,c2590dd1,54c6e29b,cd25de9f,7b1fe3d,ae7ed6d0,79ccf2c4,e0702d23,b9b57554,6d2db82a,fcdc22b7,40088c52,e0fa274d,d85188ac,9710768) +,S(a3440a09,15a16c74,8221b65e,7825ebcb,bb064aa2,de3593ce,7a691efc,d9456938,ff7c7aa0,3a582a8f,5641323a,7f437a67,26fa5d3d,e7c3e26b,be970904,d4dbf40c) +,S(8154334c,d1164468,2320401,f2d59385,8d607203,93eb37c8,a030e9e,cdaa2b5f,bba4094e,5f97e4e7,b0f0676f,4a091488,17126ad8,7d573d54,150139c6,5b3d5142) +,S(c91348ca,27b5baca,3a092b25,74e09976,fe7f2361,3e1b5efa,329e6a5b,7d4d93c7,ce241d0d,e9d49a2c,5060e62d,c01bfb59,e7c37295,4095f639,9d61e73c,5976b44a) +,S(9408b5a8,79fead4c,67635e99,59ca9649,cf362940,737e6436,3ba2590d,7e6e8a88,e10b410a,26c710c1,bf2858d5,21f46094,e02155d2,84b80fdf,cbf17645,7f994fc0) +,S(b851d158,eefe48b8,79e0a159,f8582aae,f80ddf90,d9021b92,e7d3e7e5,d6bdd2ce,290ae2e1,792421,c1cc53f0,69c7d580,60facfd8,e537693f,6abdaa2,c6d85469) +,S(9d320b4d,4a7c2007,65805387,5e536093,87e7a5b8,54da05eb,1b971e6a,e53d10fc,4f6acb7b,6a1f190d,6822acd0,ae783b0c,9b44be61,ca68306e,79603f47,25d7c456) +,S(6d779810,7b29ec65,4ff86799,d13a4d89,eaa49114,d00744c2,2f30a9e8,358ac7b5,8f7993cc,105c4f09,ba060a2a,ce265cc5,77b2a334,3ba3880,4b0a3e79,db823950) +,S(bdb2d2ce,77e14fb6,9a17d62d,b8056d28,680c9607,2c82772d,73c91da9,e57f6489,9c1ef71,d43c3b19,dcf8eced,ea6f5648,8a3bc00,3c2b0c1,84c9e42e,5baa590d) +,S(49a8ccff,1ab70a94,a4db4787,f73bb058,1f7897a8,d0a1adea,741ffda3,f055b3fa,f298d277,2049ebd1,ee2414ed,6e053ad5,15b41914,fd6de43d,8bd9282a,6c6ba426) +,S(ca3f7d6e,b466b7b0,56267992,d317a02d,3b3d5652,b51040d7,7f1a173a,769d2236,a26d6225,9dcf384e,f78e6f2b,f96a42c0,90e538ad,f6f1a1b7,126dbb12,8e145c37) +,S(b672ce14,f1c427d1,b478469c,b0d08b99,902e9cad,a66bc65b,c00ea630,737176e4,176c0979,15176,27a0f1af,f3c5a56c,83f4f550,b8c4bedd,b818bf76,68865efa) +,S(bdcbab57,d4ad621b,d6db6866,f43778aa,2c26dd78,8f2e968b,da3c913a,ee9c199b,79868872,9bb213fd,7dc75a33,8d6168da,1cee9f0e,e93c7c11,24055232,88df5603) +,S(f5f25f1e,382f7df5,74c64aa9,6c5f423e,d5beed0,82d80196,1cb384b2,55fbf9f5,ea388f0b,5ad84aae,58393a82,9a50a4d0,f54bc068,e12724c,98a9dffa,f2210221) +,S(d2a10464,f9f8ab9e,1ca6e280,b2747c43,60372049,85a2650a,a730b894,16ae09c3,d19719ed,8dc46533,28d8dca,f2c902eb,2c9ffaeb,ab3c1b45,4fdcf68b,229c5962) +,S(89255afe,e6724c4b,c5522105,8e5e6aa5,19058c3f,f3ff691c,c5f81a00,20410038,8d626dd,9560c934,11b52ffb,4fbab500,c833c3b4,671713e6,9147d8af,da3fd7bd) +,S(5e468c42,c5eceeee,2a67d73f,57819019,5165e3f2,6c93f94,beb12fbd,556e3952,af83e24a,467f97e2,ab8b6a8c,330e400f,ce1fdeb4,3a4ae1ed,c3866505,8cf240de) +,S(70c2bfac,9eca198b,f606850e,8f54ab03,552caf8e,9385036d,7fc85007,e99c4e2c,60322365,f5ffae57,8a8f9939,20cf7596,3b45d940,d2c4591,544feb6c,d6ea37b3) +,S(16143d3a,fe5f6b42,500f86d,7c79630f,bbb0db1a,64e901ee,ab641c0c,b9c2f318,7078e814,bdf81d7,81109561,d4d1cd37,9fd74924,4cad1e68,ecb8b247,d76a8a94) +,S(8ac33ead,a9341644,db25b034,60ff60ab,e1326eb7,73a0bed0,29f6e966,16b62bce,6d07756,6f0d18b4,bd055d0e,d99bda50,ea9e614f,da46005d,c6d9dbfd,18945cc6) +,S(476b98b8,9e7feafd,ef5f0116,6e0c8eb6,70cb3325,a10fbce7,71ea9e06,2566e22a,38dbf041,83252b86,7e138483,c012f220,fd98bd5d,b80fbf47,30c5d0e1,d6a91050) +,S(e4d262ef,f0de9c3b,d3302bcb,321adfa1,2e383a7f,19297058,a19c453e,ed497f11,a1f830fc,2fd6120c,8f2070c4,9ea49001,953d0c0e,7c02050b,fec7cf7b,ce2781d3) +,S(67bc850f,48f0be1b,f18c4f7c,b9f33e67,e2e09279,4196d987,1bec0fcf,f0b5cbf8,e2560470,334aa4b2,4693e927,1d2f20cd,b7e6fabc,92e0f355,526dceb8,5f52d32f) +,S(50dcb2c5,c0dd4942,2564be02,2ab274e,b543a6a5,a2712b8d,58f51e12,72ef2797,2cbc036f,b69c44c9,9c7854b4,9705dccb,8d2ea16a,2f77fca8,90d89f8d,4ab04ea0) +,S(6c9bc577,784948f4,1e8a57f1,bddf5665,f860804e,89912876,44ba7b76,8758bd6e,84a671f3,5998ac84,7329ca3d,1224901b,a0401915,c9280260,cd40ff44,ebb3ff20) +,S(5dac93c6,d27cdbb9,9f3ceb36,18c6ead1,28b44146,467390e7,a337c494,8382a868,86572065,1805082e,7434578a,a97704f8,8a91c2b8,e315ed8b,ac2a4bf8,342df508) +,S(207903c6,5e1c57e1,7a6e9484,d3073c0f,f6b2a40a,b46b996f,2ed2be7c,85780c86,4b568420,29564d4f,6c4fd310,73e17a3a,bbdcb83,115a6c14,854633c1,47f6a442) +,S(da025f63,9be593e9,3ab35113,2282830f,6ffbc94c,829111dd,29546221,2edc2f90,9b4acdeb,a315e576,f0edea9a,21acf5c8,714defa6,5ef4ae68,eb694383,916d2723) +,S(327faacd,1b489c8,2126ffa6,b87cf191,2a0f61f5,ee47eea5,6030a50f,b2823cb1,634ab42,6010009b,144c5ac2,903e5f8b,14c00c67,5fe177e9,6b7f9ecf,b8c33b9b) +,S(44cffbee,1619f462,a853478b,a9d1bfd8,6c9cab17,f5bf50cc,79a24558,7b7e8084,b08983db,62079e28,7eaf8c28,81079a45,76442a1c,fe35f64,563c714d,748e7da4) +,S(c5d945ca,13730ce2,c21ad679,734d1deb,beb19785,480f93a,43a2170e,6a6fe3a,a3aad11b,4d8b7140,f67f7287,8e4a9c1f,74102ffb,ca3ef04,46e7bf1b,ae3cc3fb) +,S(f4d8cf19,84dfe935,11b2694b,8f1db0ed,d4bf22f6,435359e6,77fa42e1,cec0de31,83d02d22,3aae1880,d7ad76bf,c7e3bfde,5b48a55d,4fb0ff02,c0ba5c2,e9a30845) +,S(13d721dc,8e7b0bc8,90c6380a,fd0f0ee7,a2dce0e1,e153ae70,7e50ae7c,1837c4cd,c620c1e3,e1575411,7eb9e823,70af7e4c,9309c412,d5f14d28,e976112e,88841116) +,S(e5f9efa6,66fc6728,207eb55d,94c1daf2,5164824c,e27b1783,92862e11,6265ce1a,500a9fe6,18302bb5,22ff9fbe,163d79b6,1f0f3cf,53e0956c,7712f23d,5c0d9975) +,S(73ee3cbd,a1ba137,65a7abb9,827b1b32,a48ea0e0,a43e9698,8da603c3,c319c9ec,d96832b4,4093689c,beb30bd5,a2e825f3,bbc909d0,20e18744,b0a5ec5a,1ab38f58) +,S(11b92fc5,94046bba,813285e7,122750a4,3e028501,f027a55d,f101d2cf,c5990d91,e08b24aa,e20fcfe0,40dcfcd0,80949b2c,23b324cd,1d957b63,9fe91716,a4315417) +,S(3043669c,22be0dc5,fb14442a,22a625d,b1bf4952,362f06a0,623ca1cf,9160935b,dc4834b0,4bf47d6b,fad52c04,4d26e21b,41eeadb2,5c92ca22,6dd2c86,24d0eb34) +,S(490c39aa,c290d144,2b87622b,407dec4a,3f92aa61,6a9c8495,132b5c7d,3d5f9a0c,5c76c0fd,57844aa6,fe81361f,73cb314f,110f87de,6773e1ea,b3d68dae,2926b986) +,S(fdd5cd58,67d73347,ca1fb212,772b0c42,3a4caf94,a3e0bf2d,2bbb2433,9002d03a,efe5f407,d1d26bc7,6fb5bcc0,6bc94da5,bd69f84c,85d89172,10bce909,77411995) +,S(bc8a108e,b0830fce,443db272,2655ac40,e2d35989,cad192d8,e9c5017,14435ea9,924c0258,cbc3da74,a708a384,b93196c0,76bd3af6,2907cd60,22069b93,e3c979f9) +,S(ed809b6e,41f4b6cb,86ae431a,718989cd,2c706ea4,10152e3b,3395df8e,ae924b44,135d805c,3295589,c8d42ffe,947aa88,bede6699,b119f8a,324c9bfc,64315da8) +,S(26b50ac7,5d871e07,4147d2f1,ee42d6a8,4398212,79e9f276,7978517b,6cda52d8,26599c63,86426e9f,b14b4c8,3494f0e,1fe37ea0,521e4518,e346bad,545dd7a0) +,S(cced88de,27d0ccd4,7f6746ff,98907cf1,679f6b10,67785dd7,25ab94d4,9fe8efd5,5b0ede2b,4dc584ac,b4b6adc2,c52b4268,e2beba67,ce2bc825,fe4df43d,73f5729a) +,S(d8edf7cb,31526332,308429c1,178886ce,bf3fe516,18f472bb,52da883d,d83c6249,a56abc3e,c155eef6,d43427e1,30ba691d,8c71b80,6b487343,7f3daf07,17984be3) +,S(ed82c3c9,f8db3a75,50949aa5,cd6c8fce,52648910,53f66515,c2fb71c4,7564b4ef,5ee59949,6d9d3c7,6fa9a26d,444a8a45,41ddccc8,15fccf39,b06e8fe5,20b2f0b4) +,S(6e277bae,e89aeb54,5e6249d,56d50848,5853b3ad,8588365e,7771ae44,3d8ca937,84871bd8,1e6f94a7,c31a3fe6,63a1170c,8f9623dc,4e24a5b4,3f7d023,39f40b8e) +,S(aeb67ac8,67271210,565b1229,3e1aff94,f2f8b642,76768967,f702afb9,48a03c5c,fcd3c588,94259c03,cde7898d,66ff5ac6,747100bf,3707e89b,6980d21d,78bde197) +,S(9f07ff4b,aa20c756,94c967d1,e38633e8,45753193,a3d13af2,3ba7ce07,5283da79,ae8b7f0d,49d06168,ff3c5f36,3aca3f1c,14308cf7,d95bae36,3975fb7f,dff2136b) +,S(24046d14,a026daba,1644b3ef,7bc5501b,baafc3c9,76acfdf7,243395d5,713e1520,265485e9,6dc40a31,ba93cd0e,915534b4,37fd5380,bad0d6cd,321867cc,aa029ae6) +,S(1376926,bf8fd1c6,80344f48,c574e6b9,1806afab,7d9f90c9,13bbc233,2b3de519,a34100e7,c4b44c26,f86b2198,e7d3696d,8aed9051,a1755ced,56ebe795,d5a61fa5) +,S(943c6d4e,816cc668,87f7c85f,b116ae82,5e4c38a6,581cd5f1,1efc9a3e,ef5a7d6e,d93d4724,f618da6d,29e35165,7883ee36,74112f70,3169eb24,eca31a60,969de8dd) +,S(adf8041f,159260fd,cafc9e61,d5f4f867,a0f46e94,af60bf53,d4d0808e,885432d9,c4eaba1f,99d2516f,3d731bcb,be90b36e,c055ff5d,e6c3ed95,2b95a037,1be57958) +,S(15c17f13,a404ae08,11ddefb6,707a9fa9,dc0d9461,8325dbb8,d96537c0,6e2dcc44,8740d352,21f95e8,36842b48,2512d79d,a799fb62,60d65dc6,79df383a,e9b6898e) +,S(87bbbb35,62365994,9c5bd575,86b813dc,966ec9ed,1ac31435,80e4b7cd,cacb8ca0,159992c,1bfc3c24,95e14ccb,e24a3e9b,6a28f4e9,1cad4a36,f83624a8,d22a48c4) +,S(39bd144a,96454c1,9e082b5f,eae9c433,564da73c,d5d44daf,95b5c176,9f1fa105,ffe8a11c,30b5d4d6,f8abe12e,bc3ca8f9,dadf1527,330319bc,fa277b13,256fb207) +,S(c4e4eb4f,9bcec0c6,6bb99bfe,265b2f4c,a1c69676,ee970a9a,b78bbd64,a83bca7a,1bb9a83d,316cb9c4,bce4be2b,d05e6381,2ecb493b,44fc3cb7,c2248a0e,96bfc286) +,S(c183e783,1c80d334,f0ddd2f4,48ca035e,8b53f034,f53c1801,488e4aec,cf244e69,f998feaa,c7711d48,3db38926,8ddc080c,8ff2f95,494e60b1,59330d8b,d9a8b820) +,S(99d1d7ac,22a2e108,f093b630,f374d9d2,7ac812d9,5753bb6b,e39c2401,fed47d92,a67d334,88dfe341,e8dca3d9,b36a897b,52080a3d,c366c8b0,39cc4de3,52d0e1f0) +,S(e0700a5d,16cd89bb,df3d6f18,76909082,985a3339,e7f5d2bc,5c3ccc92,ad61cea5,26f6abe0,38953fa8,40bec97b,c9d59c20,1fd08b29,4a7ac7e3,bd994e07,70a0b0f0) +,S(b19bf6e8,cf36d839,51b813b5,67aa62ee,5415e95c,d3fa668b,55487a3e,61a7e721,630e78a5,ca2cdb2e,cd59f59e,4c10e712,46c1055b,a7709041,fc03f8b9,1970153d) +,S(25009156,e90dd0ec,88027adf,a9701474,39abaf72,1c333943,c6fe6e19,ff71fd44,324047dc,86477632,214ed74,cb933859,b7825500,2d19ddec,9c466e1f,573afc11) +,S(45ce7fe8,bbe45d1c,9bb0c98d,9d4c500a,aca5011f,96238681,771b8538,61a3e4ae,8cbc22af,d1adb8f0,a5c72570,2b6c7f65,9e41b176,1358832,7ca062e4,2392f8b1) +,S(73255507,d3a27fc6,7df39212,a286ef6,b939e953,43b12683,4e38148b,619ec059,3174d6e6,e941020d,db0f3ded,aed6c8cc,eeba10ed,1344ce28,a354e93f,25c35b63) +,S(96b2cef4,1c6c39e,1ec9a945,8c8bad3f,6025962d,a1207885,97800ac1,c811df58,ed85ed21,41b4ad26,3adab5b7,c0c0035c,2fbf9e2d,983dda99,7d1249c6,8a7fa8cd) +,S(5764181c,d941b28a,a307bebb,912ae87,57f23cc9,37025cdb,b983eef6,42b9c772,e8173b4f,c23908fd,db5f6437,5457a43d,2495764c,f3ce1b8e,f2c8d2be,e0ac7089) +,S(38ec7839,7e965056,2b1e314,5d5b2782,ea16d2a3,82bb6c60,efd29edc,93ec1b61,acf04ea4,c7b6de2c,d8acaa3b,a4bf2656,f522e631,1cd51089,744d4c96,318ec96e) +,S(6ec4ef80,13d01c79,758439fa,108f7389,79c9f7dd,4b285eb8,b7aed579,76c0b572,2328e642,e618ecdf,3a6560e,3eb6af15,7a6d266a,f5f3c4df,13c1ba2f,c898be7e) +,S(d8da1f6b,30c27b1a,5000fc14,9a768683,4c40a581,c4ed67ba,88492449,ef77141b,ccb532d6,876d92cf,2b8c310,839387d7,d92464e1,727287dc,49a3b348,2d519758) +,S(84f25402,734970ec,966aa9f0,eca84a1e,6894d36c,338722b4,e5fed162,8f7ccb90,f2d7fd09,f07e6302,cc97d283,d9f06319,9bee137,d3946944,983c2192,335cd8b1) +,S(ef6752b5,58874372,859190e3,91d86ff7,3adabfd4,cf008038,136b2ddc,ce9503e3,23d9ca50,13cb479,7cbaa675,98dcf98e,73f949e4,614390f9,1e6159f8,3f131c56) +,S(f88d8590,3b3fe67c,f641cb52,c77c776c,fe198f74,fe116a46,602bc2c0,1085ba6d,58af2abd,2178ad68,a3695714,cddf14e4,21da61a2,8e6cfa32,40507fb7,ba08742d) +,S(93b739bd,d366b95c,675daaa8,c5ded7d2,18cde6d5,d15d354,645de017,2db9c01c,24ec535,6c2f8eaa,633af5b9,6ae0fcad,7afea5f1,c7c8bfb4,748b886e,25cf3627) +,S(732cf404,da7ae5a2,dbf82f80,180c1154,6d313b92,58980f95,d413f223,443394,858e8326,1758b90a,902eae58,a777b56,e8820084,153c9e43,1b7d789a,4d596953) +,S(efde0719,2c40002d,3f82e024,a1b838b7,65fc252b,5be4af75,28ea5994,a9d36e32,89c1d35c,3a153576,91a63585,183a9c6f,b8dd69b5,69d45483,f0c2f80d,3dd9107b) +,S(9eedaaf2,80693392,76420c1c,da950bda,f114e65b,9b1a74a6,b42dd90c,1ec90a15,1399dc24,7fa540cd,3249728d,a4d28c52,26f427e1,ac3b533,7de8ba07,d3164de2) +,S(23f0ea8d,342aa214,69deaafe,bfdb487f,775805c7,d4ba17dd,877d3d42,19433195,dc1c6e31,d2a481c5,5d32ca8d,1d4e93c1,63444dc3,9e7c306e,4fcbfd46,b699b03) +,S(d85270,58c29e60,58916e82,76a305d2,edd47c0d,4e33052c,74cb76e,abe060b8,9a0e4904,e4db5bb9,5ec9e510,59ea4993,84d497b6,8a9a1258,3a2fda6e,bd0cfac8) +,S(1b34c95c,ccf91204,5922d2d1,90cf3860,f7d36b37,7ab3763a,d4d9046b,309f28b8,70c2320c,3f5f663a,b6478c3d,2607cb4d,f7080de8,91bb408f,6f14a11e,2951e948) +,S(32558fdc,ae5e596b,b756d4e2,f10707a,89569d36,1498e8c2,8fca1473,4b84b228,7759a8b7,5ed5755b,b23978c4,3d5aacd9,fe63f6e0,74b6fcfb,501906f9,16038d86) +,S(64818b77,37d2bc57,391a3820,2040afbd,6028d7ec,fa3d6bf8,577cb1e8,dd984acd,4202b934,6ae9554d,9227b891,4a6304bd,2cf895ec,a7267e1f,5707489,71ca2300) +,S(c6af6ac6,ec2d7cb5,42aa2373,24288551,bcd33705,72e1b1aa,e572d87d,8d77b333,fffe5559,4ae5a2df,18e393bc,dd0407ed,5d5af18b,85f22352,9fcc7cda,dec78cbf) +,S(91f8fc44,94ea12f8,fa2a031,7f32fd44,2e7a9e34,28eeaf13,a8b0de3e,a4f1cef0,6a0a47a,d81b1dd0,ac6765f4,20cc26af,e76c2225,eaea2a42,481ff6d9,a554dbcf) +,S(e159a9fa,6a26f57c,879b081f,dc015b46,dc610a61,2335d6c8,e353fc42,11c1c017,c209c643,445ae009,a75656f9,b4c1df2c,f1c181c7,ca81d0b6,bd749afa,a93e8851) +,S(e8e9fc5e,135f3a97,1211eda9,c06d283f,1a705169,b89e5813,556beba5,a4f9330b,e8b96899,3b73e8f6,da7b55fa,6f1e44b5,c88423b9,f3fc5553,fe0b10d4,e9af0abb) +,S(f3f5d529,d5ae4c0c,36c27ec6,e13384b4,11aa9818,aeefb5b1,64243536,bc0edead,3f740643,1e40c133,345abbc4,ffc5e0aa,1dd1e306,43e52ae5,33f5be61,db3d34b9) +,S(c5b76430,f5d8bb9a,e1b9acff,e1417602,9eae65c,9ca1606a,2e4f6d7,6cc81159,80689f09,70089098,24087591,6915380a,29b13933,9a000fad,d2e86d8,cf2429c1) +,S(954aa4b4,34f59074,45ed30c9,ffb6db50,ff275564,72894261,e935109c,cfc09b0,8023ca86,1bad2c25,6cd76be8,b3b0fcf3,a808b76e,80a70ec5,83265d3d,c72e4ad) +,S(55da8bb,4803f339,3020c9b9,30a58336,1b96ee54,4bbb4249,d6df1335,6e3d528b,dcc44b88,ca06e9f5,86cbb209,da01785c,2387b14d,355a2575,799ef7ce,32e5b64c) +,S(8084e800,d810b286,b0ad48d3,d262b4e1,db59eabc,a176e368,77a7f8bb,a3a1de03,d8beea9c,59f865fc,9f09c12,9bc5f980,70d60ac,eb348f85,e0888fc4,63dc1480) +,S(1b2bb6c2,36c87f88,748f49a1,5094949b,d15e0217,b00c0bd7,f85efa41,5718b39b,2164b195,6aadf36e,f1bdd018,6bea9a4,c3c3f42c,b0e81dc,8101ad14,51029c74) +,S(fba687e8,125c372,e5dc65ce,3d2febed,de9139d9,9f91ad84,830da38a,54377872,8944eadf,3b89501,ca4a7a82,105a9613,55aabbf2,57f4bf83,923ec12,73e001c9) +,S(b58e4b80,a5f1c16f,f9c699c9,75a2d797,d21e155e,f091ba94,8aae2dfe,fd560cbd,fff9caba,1429bfa6,e571b7f4,12d6aa97,4606f7d,9025efec,937a5128,52cec3ec) +,S(8ebcd526,da5d6c21,55222551,e05c6be4,114fdb7c,9d43a900,fcef17ce,3426edec,73a0fb98,6b3301b6,3eaaafb1,a52f5467,de11f034,aeedc21e,ae97df86,513aa97e) +,S(fba4540b,924b29e8,95dc68f0,e971549b,7354e032,64040d2d,bb956691,1bee325e,529088c3,3b9857ae,342ba0d0,7e52843a,290f3c27,16f5321b,6c9e6f51,9105ebd4) +,S(8b7a2c97,a1a7d324,6d86301a,66f3f36e,ce014c97,651b25b0,ab46f4e8,bf9c44de,b82854ab,699c35b3,6786c1f4,71ea7536,7c88a684,43fc17b9,4cb328fd,a4b247c7) +,S(9df11743,5adb7154,e7003bbb,a1ba909b,93179677,4bd4896f,40c39a58,ead2279c,a7922f4e,a216cc36,c36913d6,e7ab8641,d4566865,dd7a2f83,77ef219b,41b884eb) +,S(5beb7b84,749b444c,82efd9e7,37314892,c54b6215,c1f9be9e,414adae4,56931cd8,99e425f,32cd0a7c,28e753fb,ff308eff,d32b7cfc,eb51df7b,64f60e9b,2fabb95c) +,S(2a830c43,ff204ba,78c5114f,4a3b7b09,c9f8ed5d,17066f43,cd512af6,4c788879,12523a4,e8882652,eba827fe,d207eb00,9ba14809,9ee42865,61e96230,62666c84) +,S(f71a46a1,4c1f2a18,e68ab408,bcd32d94,985a7714,19c1419,1b69221e,1c57486a,adf19b3e,ea79a53,4fcce36a,4cc0da0f,4fac443f,b281cf0a,ef675b6d,20534875) +,S(2b80e5dc,aa9c2b31,678ae2d9,f7d63c0c,bbad2bab,36c412fd,cb6436a7,c69d193b,bc83e04d,71d60062,b681ce04,c506247b,8f3c9019,c2084ffa,27621d62,22119c3) +,S(49cbdf3b,e521c69c,68375b58,d4449341,75424a0c,3c45d5b,b975235c,e63beece,c5615eea,f0f0e7ce,c3756aba,d3a136ae,91d260f1,563997a8,ae46c49a,5c62de7f) +,S(ce4d4714,b643b115,9215e2f3,1dd070f7,f7aa663b,9ca87739,79c5ba31,ce9ee1b2,b1f35e12,a2fc3aa3,4db59ef5,e62101b0,479745b4,200c10aa,d6f8fddb,1efeac38) +,S(6827b6bb,aa905ac3,8d93bb1b,5d5881c5,a8bef479,ed7c5656,2992d4dd,61e10054,8524a87b,af65020d,91848427,95801f54,30fc3727,7ef2064d,1aff8ecf,296bb869) +,S(e71e4d5,48f4d7f1,c7b7879a,a03a49a0,ab947218,b16dd125,19af4ad1,8056535f,495d0461,7098b3d5,6f7e3bed,ab5c9813,83aeed68,3ded1c09,f0d1bb38,e32f574) +,S(ef683979,7429fb30,d436aa32,a3feda68,65652816,873ce542,6320667c,6e00e032,b4b18e4a,de1197e8,fded846,f188a6ac,2f17506,f014d404,fbba3635,534613f) +,S(c729c1,ac8f7eff,e908007d,e2eed85,dd557e36,c1ec645b,a258b03,e52deaf4,2e83edc2,18584f6a,c5ebade6,a335a087,12365b89,ac38f27,bde7ebf4,561305fe) +,S(cf1d3919,9a716d53,b2bc4f2c,3ae2ded1,290d54c2,2124a88c,c1cc7fb1,115735ab,6b44f5a5,7ec3402c,e8980970,dab8538b,c276c8ee,ad542908,9b7b70d6,dd00e6e6) +,S(6cf3d7a0,266dee28,f3f1f772,ee90da75,a9c28a7f,f82d8f55,cf9d609a,5becdeae,3bd18fb3,1e11cce2,895b9cf9,4d9a99bc,ede5c9b4,c44ede14,34dfaeb,49bc58d4) +,S(da4b5832,ae63eeca,cdee4274,f00ae932,56393cae,cf830be7,f28749c0,7d395542,9aabb23b,d2d940f1,815610c9,d1684b92,106374e3,1b694ec4,dfec8818,cdb2210b) +,S(f91ae350,23210e16,f9c63270,cea2c6bf,407d1a10,e95842d4,b8ad5f7a,4330bbfa,1f161ac,d1962573,5969290e,fd3d1af1,53c91543,33651e16,1b51086b,913aa1c2) +,S(7e1bef52,cc3e2a2e,45847c86,27328526,c72e3f73,fa1c8255,56c874b2,f2f1ac02,be4b0f7e,a706e4d3,db7048fe,e0fc4f50,8ff0523,ee8d97f4,4c4c1787,e6f6e6fe) +,S(dd2695d,30dc2ee3,748e256c,cdc92eb7,706567f1,4be720ec,b27fc814,d3d5998f,9af32c44,f1028013,9ee7cf99,845472b5,bba67740,f0f0b96e,d1a02a19,a32dc74f) +,S(78fae650,714763c8,d12602ba,33b76da,125fe395,43fb37c9,4d20b337,649dbb9d,78dc4c0f,726cce6,f65826e5,eaf1fea4,c3b92532,6624ce1,21de2351,bfce3aa6) +,S(1edf521e,510e5dd2,aa1d3e00,d016b45a,1b6fb6b8,591d98df,ee692636,8dc98bd5,9a0d016d,9b2e9b8d,d0f4d817,71ab0f20,aeafd8d3,63beca59,7518da41,55311f86) +,S(8607bb0c,5e53b60b,9153272c,d3cc69e4,7ce28694,37562b4d,4166aa18,d0101d39,15ca31e,c83c6541,c35a294a,a648af8e,38870757,27924e98,8ef566d5,96eb519a) +,S(65fd300d,9a0503f7,80a0dbb7,c42b9bb7,37f9607,912f2df7,166b65f7,96d02eab,fcd15350,84fba852,11f94540,1f6b43f2,904caf3c,d44ecaa5,335b928b,4ea3b5d9) +,S(c918b3a7,6c847ce1,c01845f0,34ccbeb3,36d031a9,33093f99,f47f1458,cc02d148,f256f403,dbbb2e20,32063270,faa6e62,596329d,ca85ceb5,3ed3adfd,7f728568) +,S(6ac2dcfd,2f0b879,becb429,140ade0d,532e54d4,dbe0bbb5,c1352ace,5661817,f2c26310,abf9396c,5af23074,e72251c3,784c3de3,60466dc,ccaaae16,4a9e2af3) +,S(8d71c4ee,54acf389,cee39b94,b5feb2b2,cf8e95a9,45f6a95f,5b0bff2f,cb3f3d19,98442bd9,5a02c1c4,7dba3881,e3306103,f0bc8857,89b44cb6,54875847,f1ce52d) +,S(e8bd24d3,fd557118,f2c0abbb,511e874,2e5d7368,a909b072,b3dee124,44f583c3,e1d2c3a6,e28622db,65b7992a,6716459e,2380285a,cd60f43a,4d4b1bf0,8bce6538) +,S(62dc2975,5cf8cf89,e52c8c51,6311e3b4,483fd024,ab2ad1d0,32d7255a,3c075217,799e132,d80d22d8,e0f01e9c,d0954251,8b3fc8a9,48f3cd1e,9391f8f,5c0e2a97) +,S(37db13aa,cf727e60,cb102709,9c7d3c07,4d43234f,66a95451,a6050496,d44c0e13,c383bbe,8f8ceff4,196e9d07,e013a1f6,d3402a6d,d09eafb0,62924334,89b1066b) +,S(37bfb765,eab7719e,c858e17c,472f1df1,be9dc439,2699ec39,37875b30,fb2aa1ab,72718bfd,865dc4c2,2f935f4a,98af8ca6,5cf44b5d,66f0eea,23b53563,d1721364) +,S(433ede12,87fcbf35,5fdba6e1,f62148a7,b5d5c3fe,1200d456,6dba452,a85d1b94,b27c5613,ad6e513b,28f0c959,13e30781,137a4c7c,7aee6e60,5715d949,4757c20e) +,S(e582d9f,c5ed0de6,92a1917f,6ab7df46,d23295d0,b8b27b32,3af9a57d,3e671861,33ee8785,e2770dbd,7e79faa5,386cb1d1,d1c9e073,1b78dfd6,5571deff,d4073154) +,S(60b07b40,634bf15a,ee2d4e5d,a0f06ade,ad8fae01,4a6a189e,4e428600,4c9442c2,fee087cd,d243ba,62b4a2cd,68d8aac5,1557f29c,a57b0f37,ff2119b1,bc4b283d) +,S(4b167276,1e5f7ca,a245e35,b6e88fba,643e6da7,ce37c9b2,10265ad3,2de03100,28aacf02,476887e0,90d26c1d,cd51f15c,cacda02b,b6314a64,73b90c93,8ed8dde7) +,S(5d56113d,6d797e74,c4803e63,89a88ae2,fab97de1,4ed4e7b2,a17d2f9b,fe2a3170,94ef2a8,534eb2ff,a62462a2,7eb2b34e,c6545992,e2d973ab,ee42b1e7,d9cd524f) +,S(a9d03fae,75111ad8,d1157287,8e8c4473,f4a06cd8,f28dfa7e,e38b3d06,3a34f828,a0733c0c,c7319879,2ca665bf,968f6bab,480c94b4,c7de262e,4d9d1f95,33517881) +,S(74199571,2b1abce9,ed4db3b7,7b3f7e70,58fd3716,1666c522,50855f25,660e1ad5,710caea8,97f7589,cfd3b8a3,22726000,ea3ef2c1,8aac385f,22b67bd9,da44db) +,S(9f16990d,bf81a5b1,eeba1e5f,84673e16,ba0106f2,acc68be7,cabab96f,25918dc8,d60d47b,62321042,34c49d39,c03806ab,135d46f1,ea6587b0,f0b6588c,50ebc4f5) +,S(3b5069bc,4f12b9a7,ad91c888,fabd15a7,c99143f4,c8b24619,b6a70c0b,2301d57d,dbb87cd1,ae59a944,9fb4ddfd,4b311d66,da18544e,a86b75a8,979828c7,fddd1a79) +,S(9dea63a9,67b5a36e,bbbf9af,bbfabb31,f90cdcd7,9b75c68,1159b946,dabaee90,b14bb99b,11bab958,e31a605c,e9180d23,5c7d2eb,94d4de57,b8a66627,c6bc4464) +,S(d0b23392,1da36a84,2565cb53,4411e63b,9fe6b2c,c33c3a18,8e0ddf48,55e31e79,80ed93ea,1a6e5492,dcaf1cfc,c350b3b2,99117276,43fb6a75,15c435e5,f74f8e9) +,S(8adc9655,966ae44b,f98ca7a4,9f441e3f,acfe85c8,f7111da5,52c817b3,90b03d20,ce72054c,6a717312,180c80ea,c9337430,5dd1d566,db1b93b4,eed1a6e5,73c0021e) +,S(f6f76bf8,cf6d3dea,700800b6,d018a4a6,141ac610,e2e13fe3,ec916726,1e0c1670,b2c478af,e1ea9876,98e5e2a1,6b3a4ee,63e4fef7,6644da54,e241c395,3f9a302c) +,S(d58287d,38b7da30,174fcaa1,873b3913,2176388d,6da5f9fe,f873d86f,14b898e5,785fc934,69ed085e,8318f91d,114ad0cf,da2b8ff5,61e545ee,3502e9ec,6afc8402) +,S(7772ca23,50c5ee55,9ffe810c,6d8702c1,538e3d11,f4b8354a,2fbf674,39a3661c,5a2312de,853fda14,5b48aefb,23e98e4f,fe3dd3a8,ae1fcd6c,931d9a43,686edddb) +,S(a2f9f976,c50f3687,7ad0ac95,efc3fb2c,46ce903e,76ade308,69705df,72433ad5,ec565311,24c289f3,35e11b22,bf8d7445,f201dd4b,68afa38a,22af056f,c8c285f3) +,S(e20d9765,85f8c567,24d0ec16,5ad27110,26fce166,b52ce11b,cb221a80,4f8b15f7,63b61933,c7f63862,98b48b6b,c6abb54b,21d08220,166ac31b,fc85d4dd,998f33fb) +,S(8868b59d,ca1de2,cbe98d94,506db1df,659ba688,b2bf093e,42dcec03,acecc18f,f02e9b07,96b98fb0,51dbfe8,4524ebf6,dea56251,afb53076,e2215d83,fcf2fd0e) +,S(1099f82f,e32a1361,a785f86b,9a6bf0e8,99c83226,7826d6a4,3f8581b8,89fb677c,13fb83f2,9aa7f271,2cf20cd3,592eac46,cd2d3e61,9afe9aac,7fcf37d8,9c44445b) +,S(4af9c696,77ece7b3,5f732969,8ca61b27,deae65ca,ee2d5d31,ef2051f4,35cbeea3,73004596,429da976,f96e3f80,a24408a4,ebfe5196,8130c698,5b210826,664e5ef0) +,S(9680cbca,5aceb8b0,322d4bbe,8713cab9,300d1f8b,d16ee045,edb3b543,57dab473,2f293940,e36ba1d2,ecd4697c,209b33e0,6904ee3c,2798aaec,e9131d9,bd0df58a) +,S(7eefcc3a,fd6347f0,5f9c3720,31480c92,3eb7fdfa,d6e9c0ee,4e2db9ae,27fae7c2,b8e9fa75,4f745c14,7c753e42,17bb1e28,7bb93d9d,aceb357e,9738f10b,fb5cac06) +,S(b823156,d63612b9,3461fbf3,6894955d,65e7805,b025c2fe,98fd46fb,2f9fddb4,f23c517a,826fe91e,45f453eb,fe9eadd4,d0b537c6,a2a8f60c,dab9dc58,10bd465a) +,S(e801d35e,2035fd54,92178706,e2e765a9,bfb9de22,e89182b4,4d5144d3,85bdadd9,1e648234,27dee6f0,818868e0,419e37a9,1c216200,3faa7478,48161809,76956a26) +,S(e9d4610e,56b70969,284369e5,7e890fc,29fd7750,8489a1c,2f348f52,cdc67f3a,8e5f6aac,357d82e1,a29bfca2,2ee4516b,1df0e622,257c2c1f,7d9a84fe,b48e4a0e) +,S(71c3ef0f,51d6ddee,340d7aa0,94680084,b94bae8a,e3528ff,4a481af6,d3b7609b,4d1674dc,2f8087a3,138adc4d,aa615a43,db6886d4,4992fca4,544f57e3,315f6b96) +,S(9567ce43,b6f5c41f,bdf8b44d,938abac5,21aadb83,c157b947,ce999c0e,4a7d6f20,c9d86317,31ea318,a647ca8,945cc35d,1fd0fdd9,b2de4fe3,5e2a0021,33a35538) +,S(34523d4f,81166739,10b3de85,11a1921,4f8fc753,fd8963e,b9db22b7,8edcc141,900fb9fe,268b88eb,9b80a066,277d8ba,877bca84,f277dce7,7d6e90c4,8422ac90) +,S(69fd1f7e,5f1c43df,a2f4350b,f20e5cf1,f2993dfc,b61cd278,1590ad79,e3c1bd98,633726cf,8b74940a,edb15665,a9277973,2d1c923,2bcdd615,43c9f3a,6c51d7f3) +,S(e4c2c424,c28cb8f7,3146dd39,bb4fc6ba,411b2a75,e317faa2,a9f878af,e94a3de7,fb8d17e8,468e5ef4,8da60739,820515cd,c861378e,9b3bd158,fcc8a949,eb21ae89) +,S(5710459a,ada916d0,9c1feb59,c494863,98e44513,226119ea,5ded7b1e,34e32773,89deedbd,d2d83a58,4e56b409,30a8355e,905bf12a,f33f49f0,7383eca4,e63871bc) +,S(d56faed4,171806e1,5ac17f91,37101b27,59a3a8a9,90b85bc1,89b217a0,6fd48e64,fa871ec3,3408b2d6,b62f513f,5368f549,ebe43977,a48878c7,6d731447,34a6652c) +,S(e7416eeb,da0b805b,68b47be8,eedf87dc,cb5cf012,804d03f7,604525db,aa599bcb,8610c716,f11c567e,313eb4c7,77e4314b,533d4f37,13b11185,bbcf5442,b9a56c19) +,S(8ca59862,ebdd3541,91c60608,13ce32c6,a4fbfca4,6e60175f,2d5f1607,d5fa997d,aaf3480f,b132feac,6adfa195,2b14d0d,113dd6ee,faad71c6,980d5691,e37698f4) +,S(6496dc45,1fd43b45,1915867a,846c5203,6eb8e4c5,28c2a181,72fba6f1,53243413,44fdc41,f85c99e,e00a281b,9292cf1b,153fe2bc,5c8b3e87,cb14d624,e44da1f2) +,S(3a424463,aa82416a,a38bc248,dcaccd20,67d20721,d4e8f5d6,c9cb2fc1,91925a5d,71a56463,fd242591,434775cb,37c81bf0,d4857abf,aa527ca9,c3178464,8afa9fb2) +,S(6a945b05,51d55194,adbf7985,aa85fe63,8811781e,6b787418,1574d109,d178c2e6,186d343a,1ca3a836,32421fc0,d267ca27,80df9af1,32625d31,924e99ff,9b57ac44) +,S(13f1f692,682d04b7,b7e7381b,8c5c13b1,32baac0e,b7f8c8aa,c9ffd77d,3aadd47f,572a05e4,9622ff88,9eb36852,85d1400f,43372533,38c47ce2,282aa4ae,26e99f0e) +,S(79fa13c1,4f0de8f1,ed98e7b3,3edb77f5,a2700707,e54ce522,a516634b,d2804330,a094bd88,e1969ee7,3f41e40e,60f7198,cf2484ab,5a2efaa0,96e891ee,d5987c65) +,S(df1ff6db,d2c61bf7,c273f735,a6dab3d,fb08377d,bb3dd101,9dda03db,e533130a,2fdc7ad,68c58689,92e5c969,d8d14a94,cd0061b7,5ab0e824,fd19611d,923f886e) +,S(a8223280,5f5939ad,180f8776,810cc7,2bff651b,df7972ec,51d86d2a,1acbdb34,9681590f,982e3632,b2aea9b4,40043751,e7f2ef2a,d4b125b5,2784ffb5,17c2dfba) +,S(406b0cc0,49f3bf58,6990ada1,63c73932,b3780fad,ba3fd8c4,79e6a688,484c7c44,aab0e4ef,f2508e54,79074fe0,218aee7e,8b217932,859192d3,1bb20817,df6503dd) +,S(4e7043fd,5783479c,3dcf103d,bc4d9bc8,523c81ea,dbac9460,4b73300c,f516bcc8,196287b7,3ed01bd1,e8033ead,66c92625,77c859b6,73a4c7fa,98f53d69,e82d1133) +,S(a9a2a671,b945a5f5,90575c0e,ff24c070,a7d55b00,e9d2f44e,43cf400f,f3e9997,6cd45e20,cb972715,167f957c,af7f2f3f,9ae22ce4,3b46d4ca,5b2a58db,6e0c6285) +,S(692a1394,75ffae88,fba47ae4,9315a6ef,12b2dec7,6807608b,22ba3ff2,883d3c01,74dd5b4a,3c14a54,c0a86732,1a77d160,c834773f,8063406,85a65c16,6ee46131) +,S(36f915fd,156638bb,88928e75,d00fcd49,63b44ac,f5d016e7,7ddaa8c8,d62cfad8,3f11eb6,16edd183,5ee17d02,722cf6de,991dc8b0,e37fce3c,cf7f5db,e842e8b9) +,S(3f0f6f5a,7e010c0b,5442fd6c,a3643144,a5202a7e,bb3ac8f,99aa38d6,4aa53b31,2574d7cf,5b33e29a,950099ac,db0ffb3f,ab1f9ed7,f13cdf9a,b869fd07,c35c649) +,S(8c58faff,71f661d,b21d4258,a92aacf3,508a9dfa,bfc00cfd,26b95673,34b7b067,38d1e894,ea1d4ee2,843d08a8,80b11325,e9a8a171,59de273f,694a14d6,73944893) +,S(d806731a,205c1a3c,64b91864,2d940b12,dbc6f580,866b7a9c,f287fb7,c5da78de,870a8430,2ff57abb,735da831,863525fb,70402006,d241eba8,d43c2ebe,cdd0e05e) +,S(7dbda37e,195db041,a4dde151,5a7cdd97,416bde09,12b9a741,3354204e,2b848648,83c89c7a,649d0070,fde84ff1,32f60a9f,e1c0261a,87a8ccf3,885fb003,10715e71) +,S(8afc23c0,c803b0e2,df78ee09,3b776cfb,410a1b52,7d4be45e,58d8cee8,3ec54a1,b041eece,4f4ae4a0,b3a52957,386394be,bf7b11a2,b97eb5b4,1bee89c,352ed76b) +,S(4e4424c2,2c50fab0,4b803b4b,2562114b,1b2531cd,e5786112,36fb9021,3652207b,22bf6181,51187118,fb421e4,fb0cf243,889d5ca5,c14b6ab5,7e7b9d0d,d9796e6f) +,S(60717788,5a230af8,a0816e39,6e39b34a,f394b1ee,c93ba382,8fd92941,e6e97453,a84df29f,2b9da41b,14f24762,df6db87,fc0a18fa,89e356f4,9f8f4017,dc4b26) +,S(c9f73d20,384e56ec,37bbbf8d,facf70e4,a271f169,2dc22ac,6022ca24,8caf3213,7622e7f4,c77f9581,b73c9bfa,8bf5b578,89070e8b,97616cb0,69ea25f8,8dfb5437) +,S(19ea5dfb,dab5a1d8,c3c2bfea,48d90f6d,a8b9959c,630bfc4a,81ea5eda,ee45282a,c21295d,14bd81,7c3a4d62,af307b1c,870a959d,7d6e4c65,3b8e1db8,fdf1d56c) +,S(564bdb1e,30b2c292,cdf0e149,1bfaf852,4780669,717de5cb,290cbe6d,c1617b58,9a8da0e8,6fc0b95f,99e84198,877f5ddf,32508c1c,ebb9984,7004f74e,7e2b1c0d) +,S(5bc93842,4f3ee6cc,926e2123,7bee0739,50b39d1d,e0dda3b5,4bf46953,7d0bf06b,d4e9c3a9,662778be,b7f4bd4,cd753a50,32bb003b,694b5e00,c119dea4,20fd5d16) +,S(19432e94,829e8b57,3eef4fc3,181c7d7f,5b2a5f2d,a2e8c3a5,980db9bc,5cb7f99e,f75c999e,5c5b8567,bb69316e,36e01acf,2e860781,5c5703f7,a4be72bb,9abcbcf6) +,S(d399281e,6196ce19,a2ec28bf,a0b1b559,8d0235d1,beef1672,ea230cda,20080b8d,1ca7e95,20ffce3a,33e94931,95eba433,d5483cf0,d5edbea9,6384d1a3,5168aa19) +,S(6c84e35a,b220fa9f,e55f5556,302f6656,39372e97,74ae26ba,e21ca8ea,10e73c88,98a11b2a,bd442c0a,d49711e7,b0e8b234,1d15465,71efe9b8,9a7b4c02,1101b2b3) +,S(7814cd8a,b1b045ed,a1797f14,c83bd807,ec4205b6,e9df4858,1180a80c,a0f8f64b,ef917e40,edc8b8ff,f53e8b70,4de63adf,6bf17730,41af2284,1b0e38d3,b515f33b) +,S(7a01ee83,1c8e22a8,bfdaccfc,cd280532,444e710d,7138b993,fb6e06c7,996235f,fe512d09,19895c2a,b62f2e08,90dc3bc,dcb06198,18160b41,4527e7c,281a5519) +,S(655ee6bc,df86c9ef,918b5660,5d4a5e79,512e856f,3f3e40ce,72e8217c,1f9bd908,cbeba5a6,91fcb085,f3996ea9,d081e69b,7dfdefba,123df5c3,cae94f63,12f87721) +,S(ebd68009,fb0372e8,eb0be25f,e78117bc,3d4d4814,440f1d9e,1cf87ee1,de5219bb,8efb7e38,6f96df55,bf0aed2d,6bdb75f3,6da8cdb6,ff65868b,d8ce79b4,ba58814b) +,S(87340818,9ac05bbb,4e95cf05,17d5abd6,8b7834cf,1168f914,9f1d63b6,19a3865b,9f1fbd27,72ce0f15,c91d4dee,dfae0a3e,7d24c0fa,de2bf30c,df63f93c,14480838) +,S(61b6b213,b02a7bb6,4de62e92,515690cb,5dda3a4d,aa96f68b,a12f2c63,30513df3,cc71b8f2,4eff8194,36ad2962,8c003a1b,c42c6ce6,53997d56,e0162508,c2b6144e) +,S(4ba7ee4d,77171ae2,e39c9e66,3849841a,ed5e02e2,182d872,98f0a064,3925fe37,5cdbd5b4,fe344f16,cb72158e,b80a726f,5a9da4f7,751bc4f1,f1fdc734,8e96dbd6) +,S(d5827a7f,c4d5dcd4,32e5bd7a,46892e9a,6f9a3971,fe9e1de2,ee247e6f,208badb7,f790fadc,9d0e0c0f,61efb534,9b23c60c,2fb667a6,3b52cf18,ca0f0a1a,6098e1fa) +,S(81ec5159,7f950cf7,c0d44d4a,89efe691,e9086dfd,ca25098d,411cb9b2,93237633,885b27dd,c9eff80c,94653f28,ef92fb60,741d3a2,aa828065,5fa60b73,eb9a1e7f) +,S(28fc41f4,a0d4f680,76a3e06d,af0aff1e,6e723779,d8ac9e68,4cdba2fd,6ab6dec7,b1e4af1e,7affabc7,3eab9415,c15b235d,482c6a8d,b1085f54,d80ca2aa,49657225) +,S(d5e753d6,c5bf75c7,cb0f5b85,77fa2f9f,6341a88c,cf59b5d1,328b18a8,f7ae4f47,d1aa54b9,8eb01a32,2518a10c,8ecd66ea,fc2f380d,d97953cf,faf0c540,c4a1bff9) +,S(1682355d,89094297,e6008fac,44c1a5a9,257d413d,7589286d,8bad4873,1476e836,4f69c762,e29f90c9,e8459b11,d53ed84c,2ec9c2d9,ded4ea02,78d04546,eb09cf4a) +,S(9ef7a85f,b64cae73,2eb511a7,8cc46e22,73425d1a,d02272e7,9030240b,23e781db,c720356f,6f6a5a47,3f35e2f2,f5e92e2,78a50c9f,3a77604b,3eb3987,d09ce73c) +,S(4f6aebb3,6f429a52,4cb1be48,ace0eaaa,2174468,c13cf612,dd7ec70a,2e915ec,406ad94d,a8b6d790,2ad3609,252b6d7d,b28f96e,8780f6c6,39620b11,cf8e761f) +,S(4cac3e0e,5ac02e66,66710dae,5c0d7e8b,7a3cc7f1,a42b1f8e,88561bb,223f8232,9396ec8e,aa96f3c8,4ffcb9c,d8c29d27,dca65556,c2fe5931,8ba05a08,cb263142) +,S(86f3463,3aa2ac57,2c4a9dd1,64c7606,f61fbd78,60619937,38ea0a60,f79367b8,c802fd2b,556179db,5f776c9f,db4c38af,cfb2aa61,b5ae712a,3f23e58,25824f05) +,S(5323f145,7685e123,e7a5ab4c,d1d39fa8,bcd6f23,ba3d74da,318dc7ff,347103a9,3092fb79,ecccb29e,12dec977,cbbf38fb,94cab4f1,fee1e8e3,46100378,88691cb1) +,S(d3d70d46,402711c7,e680c45f,3a0e1c5f,f85cf106,983ff0e7,1a7f1178,33ea74fd,91982773,d9b90f31,16893b9e,eea7fb9,e4f722f3,e1577c90,fdf6f625,a8d07bad) +,S(df63b937,28a87613,2db5d71,43654f1d,f8cb89fa,1ab1efdd,6fd864bb,db6d4359,7c3b79ca,191a3ecb,6c793034,832fa5b2,a2c7bed4,84b792a7,91bacb7b,62ce5510) +,S(f1fe9222,8cc334d9,5f303169,a4e2262b,28a99494,c7decec3,9746be85,71b70c74,5588f3b8,4e65fa72,a2b35f60,f99af1e3,b67a2435,8c28eb64,69de5136,e751a10e) +,S(9030e75d,918ca330,edfec14c,b7cb28d0,fb0adbb5,fa29fc7d,cb3c9085,ba74fd95,7df20128,61698984,c0928821,c38aded7,5a452dc1,3bbdc4cd,71ad99da,38b427f7) +,S(1cd3c139,35bedb87,134f628c,576411eb,dfa0b586,2c3cc7d5,ddd7cf5c,77ad641a,2154edf2,5488bb08,be93a25e,c847b26,88264cf1,30fabcf,5924bde1,4b9a324d) +,S(e56e0737,a19fec7c,78b9f462,1ec0d5bb,bd6e91ff,ac995f42,202f127d,2446ad96,8830d827,368c760e,40a8d9bb,b693e975,1e69b42f,4b2ed776,98f889aa,3ead70d7) +,S(1b0a6ac4,58abe5e3,63e6dfeb,24ad8a65,56fd0886,78086657,587e63f1,5fb6b101,d2df6fda,e64263a2,b133e5aa,bdddee5e,9a35e86b,2e1f5926,5212cc49,335178dc) +,S(10a14146,8fd4618e,4ed390a6,246d62a2,50bb1676,45cfc679,d80cc081,23ea22b2,3383b868,dd7fdd1a,ecd13dba,f4ebb151,f9a09b25,bc30d562,b033800,fd40185f) +,S(9dc4ab51,5378a351,6db8837e,568afa72,e357f7d7,95d546ac,8a73e419,a43f5e35,8ddaa2d,9bcecfbf,e2a422be,1ea591ee,bfe05ce1,90439a06,cc68d66a,6305903f) +,S(aa93175d,e7a4e1fb,c538eb19,e89b20ae,13539e99,362035de,1aaac76e,3ced7196,edcedb04,c1344568,9f3e133a,d8b48004,c18d146b,ece3da05,effb864a,c2afb9ad) +,S(8171f3e4,da02d9a0,8bb6fcbc,6d06cc6a,94f3cefa,35d4ce27,536ef6fb,222edf7b,e91be5fc,aae62aba,1c02b55f,73c1a64f,c32038b7,a658f189,7499ca59,e9e6dd6b) +,S(51f6c983,c89128e6,635888c9,3c79cf79,893fe627,437464b1,11b08058,1aa19ab6,5d2ef149,4bb164f5,20c1dbf4,1a8dc650,b8cee400,d5e37252,a3d0f059,3881a067) +,S(c0a1f184,766b30dc,6a5016b1,9db0dda7,ec34dfac,74dae580,9500ab8f,6fd7d38a,bdcad3e2,c7b6daf1,29d41051,624d26a9,b27f361e,c695d490,52893597,eac6f01e) +,S(b1bb1ecc,95435169,4ab6fe0,7341efba,fde9279b,1eb78a22,2bd39472,33a0eb02,df523f5b,525342e2,c0cdbf0a,671e0c95,4b149084,de4c61d5,5a7bfab4,c81689a8) +,S(b5cc30dc,86d04ed5,88539ea7,e437391e,3b0891e7,6818c470,1803de7d,640b5dce,f1cc0d9e,45c7312d,fb1acc8,62e03f28,9f55561d,fffe4b65,ca41e62f,42d4ec14) +,S(de2b49e7,5f0ff53,28155b3e,a7d5941c,8cacee23,51fe16b0,da8e940f,9263ccb6,34d7a42b,b12dbf67,b0d7c680,178154ae,4690d5b5,703572ab,74b4d93f,6d8de99f) +,S(8b18f4e7,c129e117,e898404,65870cfc,ea5c0db0,ef2ef11a,d515f3ce,57cc8f51,6b1e1086,c8674a59,3c5e9d6c,dc8edcb3,72281c27,e6b2caff,8842e008,99111f37) +,S(727162c0,27cec888,918e46f1,762a830d,822ce424,b6a5f442,f9e582a9,17c86889,de348296,1452a369,e6fde5af,693e5247,24865623,cc516e7e,8416f38a,2f223cca) +,S(4ae4fc1f,4dd17483,f18eb9b8,1c2494be,946a75fc,a3f61605,6d0856b7,3505058c,d87e7812,e901fc17,da034a05,bd878470,59999b36,e2c617a3,9ae46921,f2563e7) +,S(e90bc9ac,e9e873fe,91826f01,66affd02,72007bba,4ef690bf,58b15206,5ff43cd1,4bc820e8,9acdfd68,51c9b0c0,65b9bfd,47f0762c,d2e56d58,905e6360,4564fa87) +,S(ba0ae6a1,db432fb6,f7a1af7d,be9ef746,8340ba5,7f051020,9af4076d,f51450ba,7d3839b7,4099420,1729894c,51a2c30b,51019a18,c32ea908,c58876af,912be720) +,S(70661b81,f77c6531,1d98b403,ed7b97d7,4f9682bf,2981fa5d,ef882022,d3accfeb,9022b973,18959f4d,9ae4bd7c,fb06fe66,7b4eeb92,5f46677e,4e5bc4e4,a6d06387) +,S(fe1b7b47,28153a07,11f81b81,7d9efa38,29451c15,8d1f11d8,e5e0922,fc471a47,95a075cc,68cfb7c6,fb115dc0,5e4c31aa,85725bdf,2344dfae,19c8a034,d2b0f847) +,S(8acf3bd2,bbaea907,28013d04,f27e3a5c,4325bc37,ec5c5e86,7ab70f7e,9acc3fc0,f679e3fb,36da27d4,f29c06a2,5951f80d,b3e2e0ef,dbe2c785,ee148657,3e16174e) +,S(1d855d37,25fc7d5a,b87fc6a4,7f62ba7c,d2db01d1,ca0f14f,1d6ea8d8,4af395e3,ceb263ac,2d41654e,d4655183,f6268c5d,9b0a9ad0,da8912a5,815dc8d3,20b1b90) +,S(1abb4566,30c24ce3,c84ec6f6,d70d19b7,9934498,451f02e,3926d70,592a8cba,4627706f,6be87fd7,2ad886ef,73245452,1778d293,41229863,f4b19548,74525885) +,S(1b4790fa,672c12ff,965d07e2,44a3f30b,620e5c66,4b098a5f,b86f2bea,93eac036,eed050fc,a758e2d1,f2a2a9a0,6b8391fd,7c19fd70,9c9e1283,1b018d24,e7edd60e) +,S(61878b2c,fc9cc88e,30ddcfc1,2561367b,44c106a0,21e3dc98,a433732a,68de3dd3,fa2454a0,37c279d,1b54cb77,498a9efb,afc6f50b,6b13e29d,436000df,1eaed78e) +,S(84048df0,2767feb1,7bcc21ec,f4502238,abc7271a,931730b5,3354010a,8544308a,d4712e4a,39d608e5,d47f9814,f7763c6e,605accaa,438ccb7c,838c88ec,e993c32f) +,S(eb7ac4e5,6c96175e,c3f1e1e0,37e89f95,8ba37d0c,a88055cf,889bac33,ca683a94,4941e267,2ccc274b,6d8bfe07,513dfc6f,cc07de33,2f517011,2bc3814f,5e85da8a) +,S(48a36ac9,877d4bda,b62b452b,a0288dc1,4cbce455,3809feaf,1a4195af,22142e91,e24d6d8a,1256288,6c6d8848,4e950d8,27eec39c,21ff6e25,30b50eba,ab69659c) +,S(9c3125d0,5a62a25d,7869af3b,1b23a00e,e817b664,c82d2a91,2522ce16,bccca1b5,c6ecda10,f6707168,18417277,4e18f5f5,38566361,5506b450,a189b6bd,39e5afe3) +,S(33e81e21,dcc7670d,c7f3843e,4dc8be3,10160bed,49af116b,c2ca91e6,90f80d68,e694c1d3,a0a386d2,e6df1167,8efe38ae,9ce417e8,9ec05bb8,fa592906,55757b6f) +,S(9543769e,6899e0fc,bfeb1071,50959827,5c1d0d4b,8a68f056,d8e1c033,1b6a1ad2,700cffd,afc58410,7635f148,72ed1ceb,1c4be86,7f668b16,3f579534,ec9b0d7e) +,S(4f41ccd1,73e62c39,7d481e6e,5b50807e,6ca9b163,e21dc203,a0d50826,7439efdd,fbf98ed6,aa8c1972,d88b309b,ab74b254,8fea56bf,e158d1ee,d95ce77d,c69f79d) +,S(4cfb6a45,584b00df,be3fd9c3,38eebc28,a667fe6a,4651bbd9,64ecf20,645f12e5,2ddfd6da,fe080e87,470fac21,d1255900,219638a2,5e72b12f,5501921a,f614652b) +,S(9efb8bec,d9bba33c,a5e217fd,8fae533b,8e536bc9,1817f982,1f217757,75eca626,661300ed,529c15e,918bcf9c,1a7dc3e1,8e3573b8,875e2f8e,9440f8ca,b0658fb4) +,S(c2a80952,5be7e4c0,b85ab953,ebe6dc5c,f5d3c0f9,e850e470,da9e61da,e430e441,1d2ded36,bf72697c,7da6fa22,1c09fbc3,6be06363,d50d277b,4839c4ef,809d9d2d) +,S(42b7ff6b,49ae822b,f5a16276,4c620b13,2501a1b4,1bf830c,a242e02,3bbaa707,e41fe058,83f0e400,712de994,dcbb5a38,fb2c7595,c5ea8b0,eb90a236,82b71d6d) +,S(ee0bb129,d420b641,2afe1518,55f78f39,e00cc3b4,7ee3b86d,f781f0e2,abb0c28c,f71d0e7a,5a4fa247,67c6204b,60edbadd,54b17455,54ae9099,258343eb,5c0aec61) +,S(1f1d8a07,9cdb3bf5,2671a716,26c503c,77546ce4,2a252e78,9ca487c0,78ef5b9a,c611130d,ae55512d,ea8e8e6f,9fbc3064,180ee4aa,63d1dcfc,5c39e98d,97571c20) +,S(5bda9c06,ecdc9fb1,5926ebe5,5418f016,7cf3136e,5f9317b8,b2912fec,d2a31310,358ffb70,dce1260c,80fe59d5,b72eadb3,89076168,a17b63fe,b728dc28,45ecad7) +,S(c32f6503,fa50c727,66652dec,8e0efd71,edc78973,48061be9,1f847544,df866ea6,67234a26,7a13ecc4,7b09443,cb13f0b0,6a34af2a,20b80856,6deb9c71,1fca304) +,S(5483d511,b71feb06,70e6c83f,29612640,849bb673,896bb069,941cdea8,9489caed,a09a6a62,d3233437,40adf0f3,8d8e4ddf,494d5350,7944becf,bfed3927,d88c1148) +,S(3d2d8f5f,f0b86ab9,1ecb9342,5a6cc246,d5e3c6fd,9c43d047,2d518958,ea322ef,4188348b,4c23ce05,1879cf4a,b71d7608,fb45d7ec,a184c509,c739f364,d955b830) +,S(3a5c3939,29ed6780,5fdffa9d,f936bc10,735ddf03,aab89e9e,40b47574,21af1dc0,760b1919,76752916,2ac2a7de,22975c83,44dcd52b,a945c81e,dd8224e,90a7011d) +,S(a3d522ac,7c1cc06e,3ef9272e,fe24a0c4,64886948,3373df90,e5dd484,d4590a83,6f53ba2c,b739dd61,219684a9,50001697,28c377c6,93054795,5661f2c4,ee1b6be2) +,S(ef0b0931,13992018,44078583,62e02aa2,c1437d87,ddb95d42,36751445,d8e8180f,73bf4407,8d184772,7d0408cd,f92f8c74,2173520a,41971980,1b9c842b,9486c634) +,S(8140effd,1498ceb9,c2211899,161185a6,a770c15c,d1ca3e07,f26f40c,6d15da20,4c74f3df,6d2db7f1,be68b7eb,2162f03b,51c1102,a02dc3e,45fc49fd,22a474) +,S(3445d720,8e089f1f,93d32f4d,3fd6fd65,7603c7f0,378b74,215a59bc,ebe122f0,6d41035d,fdb54ef3,3a3c8626,f036e1a2,38da0637,e82953d4,b63e23a4,890b6d5b) +,S(e14b2a5a,6235369a,1d1933f9,7124cde1,789a366d,5fe6ab9c,72c23d43,f7a58cd7,216f06c5,2f63c102,6cafe6ce,58a9e589,d67a9f19,625513be,44744d0b,f9fc8f8f) +,S(6d9640bc,8389bc44,fcd0b2b3,3c088170,eec93106,67348dea,f8f3e92e,2d891e0b,4b4c1485,6e42db64,9fe04759,a42887fc,68b5d4b0,8161b31a,1852bc41,7d04227d) +,S(272f1404,5c461f21,3f67cc60,d7c03b1a,fd028a05,b9e06324,62a0afce,fd9b2916,98635ec0,c0b23538,a63f78d,800eb0df,fd6b7583,31544b1e,825cd433,ab348416) +,S(a8c99928,eaae745a,631250be,cde1ce3a,4152334e,de916257,681329ee,1f3a07e3,4ccc2686,abdf3f7e,8e1149aa,5162fed1,24ae51b7,e61e4620,9f5cd611,e7351621) +,S(fb024b33,7f93d565,899be686,9b1e4c81,1c660d50,fd31cef,fac38600,d8975409,339686b7,8bff3c95,7e8730c3,9457966f,ee562ca2,89d95e12,7b072f47,c4c7fdb0) +,S(e0e48547,aa613549,773ecfe3,691b84d8,a6cb14f9,ce4494f2,35187057,28562f9c,60b6dd8b,56407580,52748838,9396004b,778609f8,69f47676,a6d76eef,dca7b307) +,S(bd6c402d,378b8b53,9f74d29,605e1b0b,ed9e383d,dfec2169,8076ef59,125d16e4,cc3aac9c,bb761c7b,3776a8f8,c8c6d2c2,a276924b,79510f10,75521b22,9def2c24) +,S(e6919231,eefa4f44,144e2c55,4f695235,d5886cbd,e150aef5,52c217ac,5e451c0,e74ee1d4,d34d2612,b4d56133,c2a11cfd,73a888fc,6927f46b,c2aba9ac,63b1cfa7) +,S(1a9acc6a,2a487874,4d92ac5a,328bdb3a,37c481e,8c145463,f9cba4a1,a03d03a9,ba6069a,960e3628,fae22422,47fe1f5e,df71fc81,b49b5ca1,26a7c588,fdf0fb10) +,S(5b52bba9,2e5fe301,f2c4e939,52db99b8,abfde642,3d6da8d5,36ccef4c,f6070910,108ddbdd,901e227d,118c68f0,a71aed0a,cc1ab1b0,2fe74341,f546ede5,b747ae29) +,S(92c13760,1ebe82a9,b11a096a,73be2828,652b0a4,d7f9a286,f1338a6,b1e05242,2e3e93fc,2dc6d0fa,5d43dd57,85f6c79a,51a588bd,d14e0275,59fac06c,a449d7c) +,S(3cb6f8da,79964c17,73a1c749,e89542bd,94b4f279,f6061d69,a12ffe5f,1d4318b8,42e4c1a8,b4f45ad8,dc23bd02,faee2956,72a77771,6e6b1d54,d05ba413,6bb11956) +,S(5fed6351,d34518dd,111a5110,50de0e5,3c60a14d,9a80183f,66415145,bdbf5db,6b79a590,de07a4d0,b74140b6,49bd8375,da77e01e,295e76cd,56a6588,7746c3f6) +,S(2b88f0a7,81c384f2,b7c245d3,7c061128,a14132b1,fd0fb56e,7d3193e3,d95d3840,f787e7a2,11446e57,655b6453,c2244974,c1632bb9,4838a981,bd4873f8,89a0e10e) +,S(c7b247b1,5a3f55fb,35b0ac3e,1da36719,18507f94,e988efd2,47bb02d,83293443,4ab40437,34c65f11,236b6ac8,bc27c548,c3c8e5f6,64f3cb67,99e7b8d0,6db85f4f) +,S(ddfda933,8dcb9481,5c08a20,12c137e0,45df69d2,121d4534,4c6aa375,e03647dd,e95f79fd,2a116bd,5972e93a,c58712d0,95f91255,a46fa091,bbcbfe5b,57795c1b) +,S(dc8da645,5084b105,6c7e3233,b247e87e,9d15a6b6,677f8c29,da04fefa,371da7db,c2a345a3,fde3ec03,f6a07fea,8bd7685,8fc66d28,6637cc80,93132048,441449c3) +,S(f53f3b26,c5fcbfa8,f1263bc7,a6439056,a31547cd,3a8c795b,8e355482,d1ff5333,113ed45,e664b9ca,98d88f1d,a17c4fb3,5249e8ec,7998b1d1,bb68be3a,e6716ac1) +,S(648d23fd,c6d4b5e,4ee1d647,7d969df6,7d754686,9313ba39,1d89dc90,b646cae9,d035e045,239375d3,4e6ffbd4,bae0697c,9b336454,3261206,15edbe28,3e18962) +,S(92e6dd0e,5dbe580f,82473f3e,dd70b343,bd51bde2,b1ca91cb,1c483fe1,3c2839b1,cd90dffe,a5447bd2,592d1a46,5a09b391,a61ab01e,a10c9201,5ddf4614,b39577a5) +,S(1315e58a,7616ef8c,fa223ec5,49415a54,eaec0583,6be6fb78,2ef4ee60,f49f687b,729e0100,802d60cb,c54e1fa4,5dac72aa,2fe189a1,737da80f,1ac58426,d7e1431c) +,S(3c8a9799,9857fd85,e26b284,a3554e51,86b001d5,e6d075e6,c9402148,ab3e2a3b,464f0492,acc720a5,59487b3d,60502067,a722e915,a10412f6,d6c69dbd,28b25977) +,S(ea417230,cc94c5f4,436b37ca,e6f9ace1,bf3c7f8,ff03c879,f862ea76,127591c8,961238cb,8d95d50b,baccff1e,b9cd4040,6f4ec475,7026b3ac,e916067d,85a4faa6) +,S(8eccf9c2,f271079e,329a8c81,62c98af7,48496ca0,b0c5840b,ceb19a15,361a6ceb,3e259a19,165bf1aa,630c6a7c,52f37b29,c8ac5239,a132fa5b,b53d687,b17e56af) +,S(32f0fc83,b3503a59,6873c34a,b54eb6aa,7bf3d913,842cd556,77f398b5,4f0f296d,d4736d6d,906f78b7,62eda345,9cb5f7b0,311e50ad,cc9a1e26,655d8ca2,fb81a811) +,S(b7d63110,77c83a8f,a43c171d,a5ff7cbf,e4fa4cc0,b2614a9f,63831836,e0d7accb,6095f640,56441552,a8ac27ef,9c1eba64,8b84a5b4,c19237e3,5e285ebd,796be9de) +,S(ef6c904a,22df4fb0,a54cd74e,6563e56d,588b4f8,d6926cf0,6c32694b,be536954,308910b1,44cd37a4,e5bc3d3c,43715e22,aa7a0492,e0e9cc9f,b1095a22,65dbaa4) +,S(19e13bd1,e62825bc,acceebf0,b48e17fa,b375241e,6eaaae27,672d7ab,22941a6a,6f22c329,7005bc1,155308bb,dbf8ccc2,855ea666,e4af3bba,d3e3c90c,28b613f7) +,S(57d9bcdf,10f2f790,79349ae4,5f2980b0,9a98a7ab,d792a5df,967b7b11,1c8e9420,bf665de1,d9b7854d,e34f8fcb,1cc027b1,42ebfdf5,bfe4e65e,b5068a72,9a65db68) +,S(37bc6685,7c3d5e8b,878874e,3d1ed324,bb530a21,f13d057e,4e3f87ae,3df06b2,15419bdc,764db12e,f12abbea,c1ca7bbf,77764abd,72f5eec8,3a81c452,4c998539) +,S(1b30c5d9,9ca59151,33c012a5,96512c2c,b572e11c,a7412138,7f3658a9,f9c2cec2,dc42320b,2a0dcd0c,5404d842,17af8c9c,2344f751,16a5d691,1db0590,5ef39697) +,S(96831db3,50c55ac,dd329f4f,85ad4a5d,e6e89f21,85b93e65,b8db4e1f,c1efd0bf,86f43820,fd03739a,d0e75ef6,17072f2c,82bd8bd5,a1f8cef4,55e49ed9,cfd47837) +,S(cd2f500f,aa1f04a5,58309f28,f7acd542,bce7999e,a17cb792,66b93cd5,44e3d8ad,1f977080,ddfceaee,97c743c2,4815f795,27dd1b05,63ef009e,92994046,c8dd8c29) +,S(60392a7d,237c9e27,a3318ff9,d3552928,802f519e,60a783e8,ff32be17,4ad01c08,eb7f3147,df91d1f8,d8994afb,df297c44,88ae9e1c,539fe065,663d856f,22893fdc) +,S(f6cf77ad,df6ab73,20d68fb,9f3c1d7f,d8abb679,179b3c90,d22574f9,fa37ee9a,8ffa29c3,3587f716,6b5d513b,7df76311,77e81eba,1cf9b523,280c778e,2442ebd1) +,S(57c8015a,f542c514,595b6f4f,f11be2fc,944a0ea2,d26a4abd,1807142,da7cdf7a,b67c779e,80153cc6,7b6b32d3,3a3754dc,ffb692bf,d16e3e3d,2c9c673e,a8b05da9) +,S(7fe08558,ac184922,ffbd5c51,cae99931,2f58a17f,bb643b4b,fa1e419e,6b4fe462,7600477d,8bbf58b5,36e7e9e4,cd595858,7268cb5d,1599079e,5a88fbe7,79ec7a11) +,S(2e16f56e,73b39bef,d729b87a,d8e7c4e,3d81095f,58be177d,87bd9f3e,dd517b75,4ce271ef,57323a0d,baac950e,668f0981,77aa59f0,7a0211aa,69b4e417,375fcb7a) +,S(a4d4700d,456d7802,be781f66,6ca24a68,49200de6,d2dd97ad,9c2eba62,18ffdedb,c099f86d,e7ba0f0,e8f0e762,8864a4d8,9124aae5,af12f6d5,efed434f,c66e4532) +,S(b4764d50,50119e3e,a316c921,91e57ae5,a2327e74,187f145d,c048c199,db3fc059,e39be8fa,cc272129,3ec831ea,9016a188,4f127070,4fa4f092,c2f3d56a,4798653c) +,S(3e686ba7,d291abf0,ced5b352,e84fc696,c29fe123,aeb82235,5031931b,e7e2d0e,7b35c0ab,7cc3c81,f84caf9a,9321b9b8,5a889b07,98c9eed8,8c7dc4c1,a985d266) +,S(d7886f2d,1d4c70ef,c5961e56,33122317,58400105,288d3346,db49407c,d24a46c5,da645ee6,17c46024,b2e25903,d4d7dbab,c5ef503f,814f23e8,68d94040,54b9efc8) +,S(7cbd23cc,14654d40,5aa57ba7,1e375466,cea867f2,325db475,d3a7990f,ba17a40,eddce5af,96e66db4,b985541e,e638ecea,88d327f,edd37039,54ce5a1d,d2dcbc51) +,S(54626185,c279e1da,eecea0a9,233c2190,18f877bb,58614a5c,5d2b9894,17eb9795,6507ed85,dc8f8454,bf96730,5cfc7919,8cfb07f0,dc64b09d,928d0b86,e0e9b6f8) +,S(edcef155,1cbec2ce,2bedb20a,addabefa,59e68cf9,e2200681,89285c08,563c32e,ade67143,75592853,c296ab45,bcba4db4,bed59efd,9df68b33,b03d7a3d,be753179) +,S(e027a953,ff6ef9d3,f27db47f,bc91db7f,6a30bc5c,c834add9,9cf8d086,23380cd,1e6b244d,e18ad020,8e52d174,ac452a81,62eafc80,975872e4,c7e362da,cba2bbf5) +,S(a5006d68,db980242,54ea251f,3787d527,66dbf92c,aaa20960,e17ac6f6,72e2b2d6,a1938d7e,e854dd5b,94d98766,c0f74723,72d1e6df,5cd6dbab,fa63faa5,6a0b2b9c) +,S(327075f2,1a1fd9e,da69adf7,32995919,dbb02025,ee504e0,3d5e5066,8427be11,41a57eb1,c32e94be,948ee335,6d855fa2,611a4ec2,4519adf3,2deab381,6bc4debb) +,S(97e1a5c6,66694bca,6b10cdcd,7e95f74b,9c87ac04,c623799a,c1c7959f,1a3363bd,3cc9a48d,1ec7561f,7b72bb6c,4d671c25,56689498,42546a9,48c9b927,c8ab5e88) +,S(450fa640,a7374dcf,d11bce28,f4eeb4ab,d0a2d868,9f6fda04,7f790ed3,b0c07a21,eae88298,dc17cfa1,d482a1f1,70d1dd36,aa35a56c,7eba231f,c4c3ca16,efa77f4c) +,S(f5aa7340,fc0a66a1,2da09ce1,f4094240,d81fad91,87e944a8,a7a1ef4b,9e0a6559,1255b3da,9ef992f1,c62e7738,f84dba74,899d9810,9db522e3,49ad9fc7,2aeb5017) +,S(6900965,55197836,a7b23841,97fbd75a,8857ac8a,8b14ec8c,90cc94a7,8a42f1b4,1dc181d2,38c976d,b4627107,2be05f32,952b5bb4,e9ef4710,f1bad8c,171b027b) +,S(2b1aa05a,8ed84136,7e99f377,bc3760c3,bc3bc0f9,33555e87,8ff2d212,c3f290aa,47b25af4,1eb8bc31,915f5896,57f368bc,35e9000a,cbdd0a41,7b267e58,cc13e280) +,S(a4e6b69c,a18caff0,d993540d,3005e5db,454b1e39,d4c81a7a,b5315d25,d052d81d,7cff2103,9c587904,a42d78ed,c2e7a6ec,df4fcb21,17c89822,36fadc01,a15d70c5) +,S(ab44bb96,c74fca4b,3e39cb0f,d9dd7795,f728e1b2,80a7cfa1,7a36916f,b39d2582,59d91ba4,519fd8cc,9e773feb,b1915967,7edc0dd8,1e794ab7,cb76a2c9,9026f5c1) +,S(83b0c85b,3fb9c3e4,8c96a31a,e5442288,93472975,5d42fcc7,715dbc23,9de332a2,e99f5640,fb620582,fd833b34,2f086800,9652d739,2d6494b1,e36d301f,35a6da6e) +,S(ea45313e,624ecf81,676911ee,500bc0f,e5bd10f4,40e04788,41eb215a,ef954537,4ab8b00c,e2359cce,203bde53,b9e8a454,d5afb101,4d0b644e,81ad1313,6c0c7445) +,S(936c10e4,af823d96,9f7f7a26,98c927cb,ae6d609e,37cf7412,ac4cea1f,51a3cd4e,46f72bbb,10dd850b,8e3e5bdc,f0359f6c,bdb9067b,13d2b60,bf68e8df,b17b7213) +,S(436a5d5b,61aac3db,392cf8e1,36a89b31,847bb116,5d1e296b,36c90d60,f2e9bfd6,f81e688d,ae67cacc,1978559c,84a90f9e,5e342bda,e73647e,33655686,2f36d68d) +,S(9eb95427,3fe789a1,3a24b929,e54f6262,d931a442,2e61867a,abd84d80,4b315d7,38bfc192,7dc0e640,820fba,8effa82a,d29f204a,fec11c60,768f95a3,4d2ef59c) +,S(3826b6f5,87ecbc0a,cb6b4328,a00f63e6,ecb77a0d,bda277a,e6e4ba5,fa280d8a,d9435fe,dcefe69b,213e6eb9,eda63f89,db35e293,8ba3d6e6,57232f04,3a4ef271) +,S(a348cd11,ae0ea1be,3f993bcf,84364b9f,4dbdceb8,db3cca21,cd0f8ca2,4a1dde2,1fc851d3,db7cfaf2,6a1c202f,212b68a0,7078ebd,6d6441e9,1d1d4884,1c83ac75) +,S(bfe15639,237fdf3c,4e67646d,724264e,5d70d1e7,3cb70205,3c4e9a06,2bdf7329,902b37e6,1ec5e59d,9c3c09d1,d7767483,345488dc,e492e3ad,f12d04f9,2b5f88e4) +,S(e2fdb14d,81a1b6f4,d40dc346,c8205821,2642ae10,2707e944,14413cc9,c03dfa5e,3011b4ed,846e8551,6c66925a,e7676062,131e37b2,9b00c408,6c60a3e2,3488fceb) +,S(bbc659c6,8f476748,17663659,db4ac222,cf1119ea,ac27c38a,535ddec6,913c7416,1f8b6ee1,9fdb512a,fadd13a4,d3fe13b,48250120,975b8c7a,47798267,7954b954) +,S(65bd2a02,9866789b,dbd6f743,af85a789,ce9141b6,fd9ee056,cef4de8d,a2505521,32dbe030,1cedb7bc,5d5644a4,6c3e6c56,990b184d,710a770c,6b65f39d,3378f5a5) +,S(1ec0e6eb,8382cf7c,24d75a49,fc0f3724,e9318d90,9e05d406,a3a5916b,2278e981,e50e129c,f486bcaf,eac8ade3,c697debe,fa56ac06,337cd9fc,240cfc2b,3415715a) +,S(7390af1c,203da259,9e1aceb1,ea101628,c0399c92,33658d9e,10dcb10f,63a9eb8c,7d215496,60647b09,d7bcad45,1debe7d8,2c3adaa3,39bce418,320e0df0,977c3126) +,S(99a51469,7b913764,783ff7f3,7099cc45,127baf1e,d8931eb2,b4b71e81,6a1a533b,49c0d00f,7503770b,fcbd57d,bae748fc,809d21f0,8ea38d4c,8a288063,a7e2e8e4) +,S(e4d6e0b1,3b4804cc,cfb7dbf,ef1b7026,320ba2e0,c4fc98cb,f12fad65,8a0394d9,aeb0eaac,73a006fe,6a75ad20,3e0ce2fb,af5fc3dd,81865b6c,75075d36,3b761a41) +,S(488a4141,507ce5ea,cb3e1c46,ad23fb3,1a9aa058,2b553459,d885116e,19fe1a04,6bd6a066,43ef8c7,4cdeaf25,ead63b04,e82f8073,a5fd904f,d7235f4,cf12bd12) +,S(c0ffe24d,ed0ca54d,1ad1c2ff,d2dfbac3,2cb65b47,ca42e8c5,5d2c15d9,67babaa1,d15cc63e,29c54df2,19dbbba8,8df7011f,a0a330e1,6756567d,bbd7c6bd,7e7e9289) +,S(336d9b02,6c74e25,9dedd36d,d8fc5ef1,31b05d0f,f20bffb2,8305b923,767780b1,4aedacfc,9886a707,aebe6510,e1bdb89f,2b1b6461,1471fd1,b055e7f5,414e647b) +,S(98353eb9,8973a7be,3bbd3711,dc7b86e5,9a2a175a,ce8464a7,6aece2d,2dcf04f,a877fac2,27894a43,8f610887,305e1c12,8e45b4a4,3d6c596d,9807461f,aaee767e) +,S(cdc35e1c,17fff9df,63639cec,b54fcb0a,71c9fb77,c38eb905,3f37c361,36da1e61,a8ccb6ba,fe917260,df64f0cc,dc14a31c,87ae559d,7d629778,2bb9b668,9494eace) +,S(912cb1c1,5e62a0b2,71458409,39c06f15,5d7407ec,526ccb5b,5159a934,80111941,584c14d5,1723c447,cd0cecc8,6c70dda6,6fa710b9,8348f5ad,bf4bd587,37049bf6) +,S(2145e17c,7c1e8acd,99eec6e2,cff40341,ffd19568,9800d02b,5ddce693,c3bff3bc,3b8a71a2,40c0b373,95b0e9b8,99da7bac,a5c43088,afafeb68,957bff4f,7636356f) +,S(e4a09336,7e877272,2224f7e1,d03cdc85,43e0910a,20bfc4ab,3aa2ea94,8d0b1692,24b1ec31,33146f03,8eeb8315,afa6e34e,898f48dc,af7d0f80,328155f7,c2cf846e) +,S(fdf526dd,464d459b,b7f387ed,46402875,2b1390d8,4006ebb0,f579b36c,d328db40,4396e6c5,679216d1,dd2cf776,61264ec5,9373269a,a745c963,14147c0d,e53a3987) +,S(6c85c16,b3e37273,509933eb,caddf3f6,52ca4c49,4e751da4,fab5bfb4,ec729f86,9b530fc8,520b807e,5e649040,c5de9929,e592ce99,1b9f9cf1,21766f16,eb648d6f) +,S(4fbfae3c,596ee2c0,10c98ce4,bde00cfb,4e7da2,25583203,feb0c791,2ce28e58,fecf0504,ed0e364b,95edcfdc,ff50fd62,396b8a65,83bc1799,3e73557e,da6ff099) +,S(9bcc3b7b,80171179,3b683c2b,90e9c811,97c1d7bb,d3c281fa,1503513e,778bab8,da2eac92,878289d1,a77825ab,9859baa3,a887f009,d7d8be9f,3b70b917,41bc0b43) +,S(4415a040,e70a3b3,f5a95695,672d1314,855b0a26,3b5e3c8a,24e02f9,6b635150,d8a53b8f,cf55a9f8,81e92160,39afd5c5,6843ac56,39f3223e,c58a5869,da3986be) +,S(55e759c9,cdafbcf6,a38988fc,be203839,b617b536,2d537092,4d2084b7,45b2341,4a6933ea,ca8a3405,89952483,4a231585,3c1191b7,42eb95d6,cf7f82af,f931bb95) +,S(21021f25,bee23c2f,a57e072,bdc83e09,8d115358,adbde4b9,5ed63488,5540e9c8,9aef5691,a7700eff,7c42c98f,8dc822a3,4ed8dc1c,7f8648d4,ba5bfe3c,f9a8c9f0) +,S(2b4e311d,dded1aff,edff3c64,10d40b8a,c70771ef,6904e4a7,a28c7982,cdb376d1,145c30f5,6b255b07,fe43d02,b57f5b96,48b25dd3,6c792575,d20ac730,d709b05c) +,S(5190b21c,7e166100,c90dbf5b,e05d25b6,5ed91caf,904b091e,8b98b5f4,5d5378b3,b83cce47,1fbdc5f8,b50e3f26,8be0d540,1826d26c,216c1166,4040b4a,66650073) +,S(2b211ee4,54c65c0b,3647c7b2,87608189,88b1b009,77d016ae,1f2f4030,545b56f7,75743959,17d8fc1d,571a2563,47a61288,fff74669,b863f506,f9b70ddd,76854f5c) +,S(cb30b792,b41e0aee,3478ec37,ff6ba66f,a3caad4f,9418e1b6,d4af94ae,e64134d4,45571ade,cb3a9f4b,922b8b4e,c0d1c728,9142300d,daeb08e7,71b1aab6,228358c5) +,S(f4e437a8,d2fcaa16,e9749d07,89be67b,e4687952,7eea12e0,65c3cd32,4e4bc6c,fb52d28b,7e81ae8a,30de51f8,bdd0ee28,8e7647fc,392249c4,3449e62a,77ba97c4) +,S(a0a676a7,6a2a19b3,bc6a726c,193d9df8,ce85a94b,cb678080,545c53cd,df50d518,647fe8c6,b1b7bd21,b9816e5,aae40700,41198d68,a3c9bfe8,e437fc88,8f190a71) +,S(15dd4fea,d7f39428,b10544ab,1eaeeee6,75a2ba5d,15d8971c,7860a5bb,b7ff7b7e,89955ddd,5fab2154,7d231342,7b7322d2,53924d1f,1b1fa961,8442c471,9c38445c) +,S(a806b800,40294b47,6377a188,ed74dd9f,1bdea3f,f72cd2b8,850f6321,930ca522,4b6d7365,47d8b1af,697f1fa8,8ab3bb86,53e49aac,618910db,9c6bedc8,deb97213) +,S(41e3723d,ca086487,7a36ff9f,6e431ee8,58a983ac,f3c0406d,f31ba3f5,5b9f148b,8ab166ca,f27c58d0,1a80b136,dcda9fd2,2753c52c,dffca007,9139481d,3b8392e4) +,S(63b8a0f2,78558c89,d9ba3e58,70946615,690e0447,f8d4c953,ea00bca8,65bba3c4,321fad41,85eb8b49,53a95da0,f004c80,8c09b297,728b3a0c,2d300b32,43cf787f) +,S(62beb7f,aa8b0d3a,505cae5f,82229a61,c1ca21da,d2ff856c,8942a9a9,b14c5963,e3d9ccbd,7120c27f,5cd88655,3efdc43,a36f4c02,2f5b7045,1ac9d7bf,56bffd4b) +,S(b75a180a,f524b89e,be5d79a9,92f0313,bc133fcf,3cb2d99a,c65f2c48,1bd20427,e7855056,b11cc054,d37094b4,1e62dfb3,6a636964,633eed48,c39b8225,4a1d2747) +,S(4e5bbf6d,5298fc76,97ddf9cb,e4d063a2,6b51f93c,eef032f2,f03eed04,fe4949e9,66702686,40cd9dc6,54514a19,ecd80930,1871fbbe,99254119,476e44e3,16a12188) +,S(a9778c3d,f509f069,3baedb83,6d5fc1aa,b78e86e6,dcb61200,74bf6df,c173237,33a9c991,86a0f913,95fa0e50,d0a85d65,9230a41c,8c0be5d6,90ee013f,29d0cab7) +,S(f1b3aaad,16664be7,c49790bc,1a4936ac,757fb3e7,26ccbc95,cdb7bb63,cf570449,d1dfe1cb,ea3fdc10,3f218398,14626782,643426,24d3aa3a,52b0fb4a,7460cc06) +,S(d66cfd3a,b015d585,6a436ad6,a4cf019d,9563a05c,af4ce2d0,6988a4c5,9349f598,5ea179b6,d097d9e5,663b7305,6db940f8,d8e91bbe,fb951756,d07cf6fa,111efc4d) +,S(a532a4f0,924b5d13,bef0f30a,a982edfd,5d87a16f,2c0d8470,ea8fe3bc,da0ac7aa,c2e62c19,ca4e3481,3cc3de70,df50386f,74fd1efa,ac6217ad,5532a927,1f8d5c1c) +,S(a9ab2512,5df78835,ffbd08c0,9e07b632,81ebb3ef,3fe2fb3e,1a3e5ff6,28439b70,58ff55db,56e015aa,9aa43698,acc35df1,f2eaadb5,4e950c7e,3501a5b5,85877514) +,S(ce058f84,90813dec,c184dc83,915c6d5,53df174a,41ed6521,f2cff46c,460466eb,414d38c4,58817414,5a815a7,84f4f71a,28237741,97b37d47,c7646b2f,8af3e745) +,S(991fab65,30a2b36a,ab385c7f,31644de9,afe9253,9db603d4,737beaa9,6e406299,2a29b576,77c544bd,f156dc9d,44da01f4,5d373cfb,7ada94df,4f82af9f,e48eed57) +,S(ee6cc81f,bd034eef,cc841921,5ab4817,ddfdd2fe,a13f1e14,e91c3f2,af715d8e,b8f79ffe,48c3e965,21c7358d,ea5cbc04,df8fd847,a97bca3f,6893af3b,e386d8be) +,S(66a2d372,d6426657,5544d5cc,5141e003,16ff2dfe,813357a3,c5daccda,159c5ef2,b57d2d6b,91c6f48d,389423b9,af265e04,780000d0,598229a0,5bada3f7,4dbc8929) +,S(20a02dd9,f697de3a,15043e73,fc7f36a3,7a5798e5,acb4cac6,adf5c692,3a421da9,1e6cf100,d162361e,aa6ab61e,711e3dca,ab4ab538,2fcc6b97,33836c30,cdcf34f7) +,S(a0b8ca43,7818e81f,6be98b15,4da25331,9f92b79a,1ceda110,92e3a303,cb7bf552,4541bceb,f447d990,50663ca1,10fce2da,218508e6,48b630ba,a1abfe5a,3d543be6) +,S(51714ead,73dce488,7e15c25f,b5cba9cd,e0d5018d,db5b8ffb,9e4174eb,1cc52c63,47b794a0,82ef561e,bee272c7,d66dd201,a5c24831,99977097,73b9141f,9bdafebf) +,S(18ea2763,1fe4de07,3e7c41f6,a9921e91,7da195a4,13417a2f,ba74ac2c,d6451c59,398a0b37,fff6bba9,b33e0428,e8d7c93c,d31b3b83,2e955e6b,106aed50,d64df316) +,S(e1d58b4f,c39e1834,a61ec341,acfa985f,c3d1f0a5,9d75b0cd,e8b9057,17c5a87e,1b62ee02,15fdfdec,8fe2ab3,bb7f99e5,af82153a,dd9c7f2,cf299225,9c6b3c47) +,S(39793917,30d3c125,7dff5ba8,eb253dc3,2c19c541,11caf9a3,bbdec3e7,716c5a84,d6a1fb50,189f36d9,912cded5,c851da8c,be7b4ebd,41c2a1e3,f78aa4a7,f5f18015) +,S(49b49e4b,601b406d,381dbf88,8b02519e,1d57360b,24f2aef1,5520f17a,5b9ede88,fcf3ccca,2f2d7b3,59be7be1,9e45a3,a0a76e9c,d0e42fad,bff7e772,f969a38d) +,S(2cd8190d,b42f36d,20d88548,f0ff17a1,d64e38a1,2241e4c3,2bfdaa45,28bdc871,f729c369,22141490,5aa84f45,e5abfeae,2fff780d,2b16aa67,77ef59b,68259187) +,S(1fd0fb11,17385466,2da0cb2c,f1f9d19a,b5b642ea,45d1c6f2,30808626,5e41025a,3136a688,fec60820,abc7825d,1c7012da,94e928d6,dbb6c08f,5579181e,469ce0e9) +,S(f08e5f3b,d7f8b5be,18648a0f,5bd844e5,3f93d5bb,120d3871,7de4440,7af3a141,3dd8725,9067eae1,cab61bdf,cc94ea0d,bf7ea1bc,df1d289f,a526e15f,d9902fac) +,S(a0033c06,b997fa96,373a046b,b5c6bdd7,a0584cf0,1feec5a5,d3f5cab1,1c5ee207,eed61931,aacbe48d,708c2cda,2208d40c,39a577b6,3d4ffa17,d140a8db,c3e268b4) +,S(77deec08,68bea671,df01e29b,117791a7,83ff8f70,4426bb1e,1ea91b6e,62c16f70,b908a228,ba8f73f6,3271ae7e,f19f5e9c,fcc1fe27,c0a224b5,dc426b00,5664861d) +,S(2fcded5f,fe2f10ed,1a1bd1fc,63506b3d,994a03c1,c188d960,5fd5aa1b,a9aa72b1,155bebf6,f09a86f1,d20d7c12,e12a0c66,b4df6628,4ff9d45d,3fab7d76,6bbefc6) +,S(1f0c0b2d,fdf5e733,abcadd0c,9ba47c09,8667f8ff,77c2a904,c8310e20,995db3ad,bd711bcb,84cef55f,5139b761,33268489,70f63182,85ccbe44,8efd7566,577bc566) +,S(b4a8544,e7162c44,60dbdf3c,5edf654f,d603fded,4aa885ef,465ea8f9,a37dcf8,53c04391,b3f2e8b2,32e27b,2292cb38,99f8ee6e,dbe1934c,13938a3d,203c62b2) +,S(df0ebe82,dcdeb735,38f31cdf,ad307397,d00a900c,6d94221a,9d85b0b7,2c5bd68c,c3299639,e7fe2e55,447b869e,3a4acf8b,4a1d07e2,d70701c6,8a2f4733,88decfb2) +,S(eb04b9b6,d1c38c33,e1eed101,fd28f89e,f9fd460e,5b379576,ec7c9267,3c101c0,4f26d849,7f47f80b,2b13cab5,782d6e9c,f5ee7548,3974a4eb,8d8f28,f5e0ee9e) +,S(7bc9efe2,197cc6ce,ac94b37a,cab9865,7db4ee0e,ea7b9cfa,ce9f71d0,d3294334,d931bcad,52347906,a941d940,4b5b3a51,ad8fb493,1c15c9a3,7ff782da,5da72013) +,S(8922d1e8,f4bd52c6,4bd0c10c,66a3e8b5,1321dc50,cc964844,e0a41ad3,b73e0b9b,2b643cf1,7d23e21e,890e6abd,3337dc52,61c9eec6,d5edc318,2a02a7a3,4a41c431) +,S(42f2ede3,3a9312ed,22f6a842,ac46801f,139a7da,77ca0e9a,cdc19d1a,f2ddcc72,50d45bcc,715c985c,b9260edf,fdc8e342,ab95360a,6bf4776a,c70e3497,8f26f99b) +,S(7bdc9720,1862feb2,58879255,726b5e4,627549f2,92936ea2,f3b27051,4d6761c6,700eb72b,7f77adf5,76e6f0bf,f8406660,65372ee4,cad6269,f1ca8541,2da4fa8c) +,S(b9b527a6,4bf549bf,5e42e0d8,5228e1a1,f79d1647,d2102306,6b6d98e1,746314cf,8e1b3464,2a721f5b,93a2a2b6,802f30ea,e35b1539,c6d84eb7,499299aa,aa0cd93f) +,S(b65de529,34d47765,1c29192,93ce1177,d187c431,590d2d74,978ac258,75e3dda9,3d6fcbe7,4ab9b5ce,b3dc5535,13036457,f0755509,ecbd94ef,324e36d6,3b9fa529) +,S(18eab632,608751e,af3604f6,a3f05611,a036edea,3405aca5,c2e66366,ce7c6b9b,89eb07bc,94671119,36e11f05,79f91e6e,ccd42605,24bd7dd9,9d12b365,95074c5) +,S(a2611066,4a479643,909a1606,596d39db,c7502ee4,a31b40a1,4eb1c60e,ead360d5,4b45d74d,88025576,3262d9fe,38198218,85721a81,f323cac0,3e87f372,75814901) +,S(789454b1,2c108537,a019dc58,35cf25c9,c77ac0fa,f6001959,5da9435d,3c08a8a7,6bee870f,ed2859fa,cbef4337,8a0bd760,8841da03,252687a2,591ae0bf,a5829041) +,S(1977c206,fb4f65f0,11b683b9,c2e0df95,f81570f9,9f6625ed,7cfe25d4,62791569,de76dda3,c22244aa,95ff435e,5a9ebe05,9dcc79b2,75d91de4,67de435e,bf698479) +,S(891f0df7,d259d536,40fe6086,1ac34d7d,ec3b5ad4,c3f56585,189ac986,65f4222f,cc5e0bf7,f538a2a,1ee7a601,1a8d6b0e,5c3293ab,404257d,ba90ace9,1b2de219) +,S(8534bbf6,9262f81e,5926c282,f412b4d3,50169de0,3c5c5e55,c80a937f,fe99530b,fbeee581,e0bb0737,4cc764c0,be5451e8,f70cfc23,4d415cf9,fb08e7eb,557423b5) +,S(e5b6f564,4e7dfd3,7474eafa,354598d5,58fc897c,f010198,9e44b07e,a86f63fb,4368bbfa,68a83a8b,76de7d98,38880780,8e153cc9,b380ad0,b2c6ce26,6118da79) +,S(f9591a8b,11c3e514,983dc5e5,507247a8,46e184f3,b4e38e29,f7c90d4e,6c2b850,423b6436,2361f587,cca4e288,a366a1fa,957de393,f29ff2a5,1fe97a0a,d90ff6b5) +,S(3d3239d3,252f5e9e,ef9eb617,c9646379,7c995059,57bc7821,2f2920b1,ff72384c,1c3e37b6,fc9bafac,e52798bf,695eb4df,ef860ee1,a9b67df7,8f73ca9f,22a2e57a) +,S(f4089723,4b574d76,86a8e855,408612a2,a0a6ce61,c1f14055,201d5c67,bcc5dfb8,6b8283b7,3e72fc91,54aaac24,2565a79f,c3a62fa7,602ffaf3,c7453209,c0a56a4) +,S(ace076e7,aea9c745,f6be65f8,498b8b47,95058ed2,b0413c64,bc4b462a,2e267ccf,b62c617,377fa9e5,eb72ed6d,caf353e2,dc58f362,a994520a,31f1dac1,168b97aa) +,S(70ccbba7,408c6069,3230b848,eadb1d1d,b4e63f33,b4fdf6af,29d6fc2d,86ec161,fc1cd9a0,46d30e60,e4128677,654a80ca,5a4ff338,71fbeec4,d7782c7b,a14d6959) +,S(e6e7a8b2,7c0c5b0c,5ea58d3a,4af5abc5,9e33fcb3,9970aede,7a8de629,e758d372,d40d11c4,c8c8b5a5,d511fee2,793e2c80,b40df3a5,c98bd704,9a8db3e5,c98d4a66) +,S(cdc495c7,e0a02e68,329495b7,19e2c424,7910e9a5,cff6739,117b1d32,23216346,63664f6e,9306c0ac,f29ddcd8,7f1df6ec,d51fc68c,6ce422f0,559205b1,681583d4) +,S(2784e89c,2fd721e0,22ba33,3b824dc1,d0142f19,6f35ae4f,825975d0,7a2fc5cc,ba58a66,bdfa661d,354232b9,b25628f4,5a391e44,f00841db,4a335ef5,dc3b8cf4) +,S(ab699b62,ebcb7380,2141dd83,184ba3cf,c9118bf,f6af4d0b,9b98ecde,b01a2390,5e548210,b71420f6,c5d42547,da0a7ccd,2be0117b,79847e71,a609044a,34766905) +,S(781ea7a5,67ffe37f,b9fad6d3,96dd1eaa,2209552a,9835ae08,dda3d4f0,b75756ec,3c76d87b,46f63b97,e4d48174,4ba664cc,403a507,dacdf4b2,af9505a0,f2637256) +,S(75ab2d30,dd5c0a82,a5c04fe7,b8fee5a3,a0e1ce3b,e20b33fd,39d0bd3e,e374029c,aaf46147,fdb1393a,cb9f6f8e,694c1cf7,30536efa,b5ef921a,72215fcd,61914b9f) +,S(294b6698,37303da9,6d23caea,684ad56d,8712433,d11c7ced,85a10cf8,8ddaff0,af4d7ef7,feb73e9e,a9407fa8,b38bf1f1,e5861bfc,82f9cb42,22fa64f7,9b46f7c1) +,S(d8676aea,7433639f,c9683b06,bd97011c,f290f6e9,1257ee55,ea3c6e34,b824c8d6,710c8876,35d45545,90f3e5c,d6aac133,9017b2a,de71e30f,d71a5b71,97a7456d) +,S(5e4eca03,d90f5ac,2ac4771c,6d86a458,cee71427,a93b7544,fd8bee74,161270d0,44fe0143,b970f8bf,affa6d60,33628894,a93bb4a4,f48cbb9f,f0caf0b7,40c97351) +,S(90152daa,244fba85,fe708f21,29b55485,265c3a3d,dbc761dc,157f125b,8580097e,1694d2c9,200b8690,b59fa3b2,8fc2f613,8a6d392c,48357939,b9435739,83ef2cf7) +,S(67dd54f0,96f171c4,53fa953f,acbf2b9c,daf3a199,732ee0f1,91fb3c90,8c5637b5,5327db43,2d33676d,b6502236,5a338c62,5fd6c4a4,536645df,b36279bc,4ede74b1) +,S(c6496a83,8f95ff57,65a0f144,774cf543,2e770457,55efc790,142df95f,bb6c51ef,cc0041d6,604d1d73,92d86f01,d8b05b53,1177b51e,3a38b8ca,ca8267fc,bcd752a2) +,S(e799d70a,b163bfd,475e5e72,8810d9d2,425bf4b6,9461e9ad,933fdb6f,68c11c74,fc34745f,e29bee3f,9b0adcf7,618c6d13,e504449d,1a272b21,5ef9fc18,14ba8600) +,S(6d3c97b0,151a9011,5032aa22,1183d82e,820c8774,c3dcd75a,cb6f45ac,5d489d3b,5aa8bd01,3d15d77b,8f695d43,8cedd9ee,64b57df9,ee672323,1c2cd5b1,4ad4749f) +,S(86e53e00,1c1e7de7,419cf2d9,a4c6a39b,b96d8ec3,a82f8165,45658eff,a517539,f8b1b70,f2efecc0,cedda525,40663114,c24491ac,266df520,ce475f01,ab44ad86) +,S(a641c339,ac877cce,a9a3267a,78edb33f,75feb90,1f3c8743,47c50843,52a9880a,d88a6d4f,2b275ac5,3c7dc101,b7d69ca5,407559c6,afdc9009,c34a7256,f982163) +,S(3a0153a9,4d778266,4581de43,6de31754,b925aad5,4090cceb,9e013568,9d82511a,f6ca48,94935c5a,7a252df3,8ff06cf9,11154b0d,9f0ac55e,35a33d7a,58802035) +,S(e78024e8,a131c9ad,40526b31,d26e96f4,2c2e51d7,c63f458c,5bec2a61,472b170f,c540a14b,1ad7b18f,23493d9c,edab65dd,3a309204,976408ea,f197f658,9f4e0c53) +,S(7858c85e,8351f0ec,740380fa,b1924668,7f05a161,e2dd87cc,7df13338,a86a5162,cad94344,5313a06f,c382897e,7c444d53,7e658e06,5a76fa60,928d7e5b,36a6de1c) +,S(6643e28,1c5bddd4,35a68c17,965f334,ddb9da8a,d599a4b8,2f37147a,cb0263e6,9f9f9e36,8ee1aa0b,9bc8f928,284968d5,6f2dc8fa,6944ff36,d728b588,a72cf79b) +,S(5f36d937,a286f14c,96fe8f9e,3ea05d56,b3132523,e9a135e7,106592d6,b9b2254b,9d6377c,c8265ff2,dcebf753,ef2fd39e,9adb0e1c,3c86acfc,2e54648b,9056310a) +,S(212eb1ae,93d3a0aa,5f626f26,628503c2,310f9172,461ea12f,b17677eb,c63e2224,51e57e33,347f2016,c738d9fd,cf528269,bbc5afe,f5fd6fa5,1dfcfd47,4b6d1b67) +,S(526952c8,940b9f93,32848145,203ce261,dedb3b93,8e6f277e,9a085d77,35e9eab4,8657cfa3,56df2aaf,9a5fe2fd,81804ff8,1d9aa58f,143fa109,52e4f4cd,85a42918) +,S(20f1750d,ef762812,e4ba8778,c953a2d1,419e03c,b97ab6ef,8f98be07,4c1c099f,d2fee9f5,3e7ad2a7,fb20bf88,16a1ec2d,d9d97b4e,5abc060e,bd8e8b31,bacd485e) +,S(e231a3b7,ea011665,c223cfb2,7f13c691,dbc7f5e5,efb66496,da2936dc,d67ee910,aa645c2e,18e80131,f3e7316c,7cdf13c3,45e4f602,fb17011e,96eb5fc0,bf65d53f) +,S(7a4e4d52,3fd026dd,3daeac35,552e7299,d01aa962,687a02cb,ed7174b6,25c702ad,351c12b6,a7398e5a,ae461204,4cd7c9a4,7d2bdfc1,1f941b84,71eb3304,fdb965d2) +,S(fd2f707e,76965670,67ca5a5c,a0010c6f,9a858967,19a23eaa,5574d1c6,cbf137b3,c45a430c,1d5ae473,31f9b161,3ce55f41,df00e287,9e3bf8aa,1ae75306,f8315408) +,S(c506cc1e,8cf2f4fc,e1011d67,6d304877,6c2ac2a4,f8265373,f3f918d3,f02bb89d,8de6dfb3,74029b33,2fa47f6d,1f7ba609,bea33d6e,2f58ef0c,58641e2,a5d3118a) +,S(2ea7ad02,d9ccf999,86ab901c,3c9cde3c,ad1bb4d7,d8f86eeb,b8204b75,ab5c0369,11222bd8,6d750302,763648dd,daf76947,2b213562,494ebd9c,e4003195,eb0ed43) +,S(ab8cc192,3555e4e5,2f84b421,ba2ac134,f8a6023a,ddfd279c,4c338cd1,9e159c5c,2c48e3bd,cc268dbc,23e9fbda,6c449079,5a5b54eb,54ca8ff5,14d1f23f,8751ee1a) +,S(88fec2e1,cc7c41fa,91b48e1c,2a71089a,c3778427,f2cfce04,c54af407,f5dad430,ccb45e88,4f696653,5fac7a04,9b035c26,dce30666,fb1fecf3,c4b89deb,8b3ed80b) +,S(404587ae,1accf5d1,b42c3127,2ea0cdce,940522a1,c64c757c,11d3768,774b0d41,e8dcf25b,25ae61f4,f7368c36,9b351b35,63401deb,5ce55325,f96a393f,ef0e787b) +,S(8a701eb9,cadea8c0,8d0cf20a,b2750915,28a377cf,bc4d9097,51424d1a,7eb9ab8a,4f045982,82a9ac70,c3c76154,ca98b5a1,265e8b26,6f02d43a,4549cdea,caba5a45) +,S(c2812978,194009c2,9da141fd,b108a4c3,66e15e06,c6d64389,29b2aa78,89ad3d56,85409efb,6670e969,a2834255,dcb1e546,9c9db5e7,6e549afa,974936c8,b75db5c1) +,S(9ffd36b1,c810c843,92bb04d1,90b82be0,f8ea4b4,2baa6129,8adfb810,71d72fe,11e27a4b,a11f0df8,1a42955e,bfa9fe1a,6f25fda4,6a65fd87,1caa3d6a,1b38404) +,S(ac4a0044,bc92b017,cad07210,750eec62,39e43147,5e3feb25,f1c6f879,a5a48b96,41c7c3ba,731002ff,1e749853,344c1f53,f526bbbf,457b4de2,d5f88ce4,1eb8dfe1) +,S(c78b101c,157ca920,b3fc83bf,9d19fc5f,57d8086c,d764e142,24ae4e86,7b06eb5a,1a8d2c6e,b9d660ff,faf5f533,b4f3b8f6,b7a9d7cd,5c29c1d2,deb37f19,d38126c8) +,S(d08f3b05,572348b9,5f3c1c2d,baedd921,c24b0db8,e6d17d13,578e5ae8,77147cd2,27b5fcde,a067cbb,69ae3e5c,90a38523,4987dfaf,5dfe0696,91461e26,762713cb) +,S(40ea043d,5060f61e,b81db0f1,c7c5c1fc,1091cf51,c5808489,3d08c4b2,a5e312f5,2ef11ec4,2836302f,e02719be,259f1536,43de03e,fb659f30,84816a00,1d66b27c) +,S(f9d104bd,fb53b4b2,de8827b2,8242eba5,17db73f9,dbb1eec3,9f184ad0,358362e7,d7644a0b,6c371948,2ba707b6,d7d43f0a,68f4e3c1,4af6f167,296ccfcf,4d771877) +,S(dd276aee,14c34829,4e6132b4,9a05dac,fea5f8a2,41712b6e,5703778d,eff9ddc9,9be617d,5d92eec9,7fede655,39690d0f,4803f760,2b74066b,7bc98353,a5ceb7ef) +,S(8522f839,d5f17bd0,c67d11f6,7f0db8db,2104c7d7,785252f4,c8be84f0,61155d49,b7791951,80311f8f,6cb9b59c,ddca495a,e01f3edd,599f8777,3163a959,5a3ea117) +,S(732802bd,b4f3be8e,fc02a62,4614672a,51049166,4bfce64e,eb2030d8,b6b5b225,7bd4cdec,590eee1d,6a505f92,cc0b25ce,d9022d62,d1155f8e,35a6ab72,46a3c6f3) +,S(1b3641a1,2c4f8352,21e73276,b8bdea15,f5ffcbaf,c4496fc6,8fbdb573,5967af62,3d50ef5,e5d12b7b,2ede2e15,3b4cd01c,b824c32,7a8e1ce,f0fd866d,99664048) +,S(d3034e18,4e9284ff,ed6cbe60,cb66d391,c897255,dbbe8c85,2c79525d,3f01a7ce,b3666304,16ce50e7,2a094b05,85f1ba1e,11172ac4,eeb353b4,8c4f8f99,f9d09e25) +,S(8e7a8200,bd22f5ef,18fa4461,8f4f85a,61c6db2a,a3ad176d,65c3270a,69e9db17,841fe3b5,1cce979b,f87536ed,c71f4cd4,4a482475,19b35cea,dee4b3b1,f3530568) +,S(fcccb4de,29ab8671,d1aaee27,61421ae1,c4af5f3d,839009e8,5dab0b65,60a4027e,a0229f96,203b89af,d5b6ac06,9e977e71,a6e269d4,bea29c47,fa6bd22e,f7f993b) +,S(e68cfd7f,44358180,84c681f0,aead705b,9e74a476,1f99e576,9252c007,e44c8a26,add9c0a7,b027e2ae,42378d50,cf0d0eb5,71229161,8e9f13c1,672121d2,c428f82e) +,S(8b6f0fad,4b81ac16,4866de7a,c8bb3252,63bfe008,b726e9a8,72e0461,2c6891d8,9bad6508,a8d604b7,8088d328,ca27fe13,91493e8f,a6291288,92ecaed,ba4bc9ca) +,S(108a0caa,37ac1949,263178cf,20674616,470f8943,57a921ba,8cfd499b,d64b78b1,68150d22,be05956f,5ffe302e,1ff517c7,9b7c0452,6112b2a7,5a819f64,a265bf55) +,S(fed18333,844c579,1d32daa8,3370a5c6,ab8e13a5,2654a08b,42940284,c757edb6,67bddf37,8395ab84,eba29a97,6952ea34,b1b52c2e,d3f89e56,f839c1ff,36457fe5) +,S(bebfb39d,ecd56cf3,50bed6f1,a4cde24,848b2d84,23518da5,1fb2ee0,90170a2f,1302b4b3,bb86f887,22925fbd,e146d948,5acb2db,a61e751,97dd40ca,2ba11573) +,S(67135aed,2a58d3b6,c4470d3c,b4da7b56,af8d5057,9d28a86c,9c67bf28,181e716c,97c40aab,2786e3ef,dc8f3e77,8f374446,30fa2f3f,53eb040,194809c,8efd6664) +,S(b00eb5bb,9566e5a,cdb09dd4,14d6df03,c3dea75e,90db8b9,c37928e5,4354f90e,6d120e41,1cb6e674,e9973aa6,3999af3a,ccc3a670,112c964d,8aef93ee,e69b1258) +,S(721b1a6c,be8d2022,f09db6d3,ba39b2d9,23337592,de9efbb8,ecdf3384,f3bb73a2,cdb41b62,631a0f47,75ae1f2,e94f8075,4acbb2e7,950be088,5b458c8e,4a05310f) +,S(cb8d78ac,15b12ca,8dd47cde,190c420e,42f60b83,9489bf71,d10a3e44,df8a0837,80be31a6,a3073675,e8cd3846,cfb2e127,abdc448b,1081a2d5,d177ccff,ea96dbc2) +,S(491cfbcc,4919d884,d23f3ae6,6d143e55,37e5c52b,e2ee017a,afec785,6c781920,76321b50,26283088,d344d29c,c4d9f2ec,3ba714d4,edc1bee6,2b17ecc4,56874189) +,S(6ca33ee,48992263,23aed33f,f822303b,8145d146,c5ebc27c,fb3700b3,6ab507b4,96b73ab3,f189d064,1e0a20cf,d09522bf,8c376a0a,9c9dbec6,44e3e8d2,c0b11f4e) +,S(6d1fdfcb,3c48971b,6cbb33d3,822cfa68,1bf602ef,98160f89,97ccaba8,19d842c7,82bc7c4,66088262,5e57c062,96f04600,fa555ac4,5596b769,9c6d29c,cfb1713f) +,S(a3e81699,1cf92f41,a69ac3ca,36b23796,daeb533c,3e1e9b55,c88e3fa9,fea43554,87a6fa9b,e802467a,fa206b0b,45405309,65887df5,786d20fa,25e94832,312855f1) +,S(fc84abd7,cbfbc329,4eac7438,d50b2ac4,7f570e4f,3f2ffab5,71f8c3e8,7dd49c70,7447b269,71356b0,e59b3f1c,d99b6416,589f6c3b,a566c75b,6915377d,a7f73dd9) +,S(beb23240,8fc515ba,180d3125,2eca15a1,af4e02a8,73a69769,53982408,355d1b1,12fa480d,6fa8a9aa,e5edeba9,31b765b0,e2bbe6a1,5eb9e95,b3bc343f,519c1459) +,S(68891679,cffad7f3,19a373d7,1bc02529,a50e63b,60434f13,df760364,1a99eb8e,40b78db7,6db28aa2,d2ea7c1e,86d01503,7736ce96,2e6ec524,da07b5b7,68772fb8) +,S(ec435ad,1ae7b040,fde2f736,e8fb5d53,b42e2fcd,428e9d96,ed401ee2,bb068817,13bf6eaa,1283436f,4a828a85,66c4f795,26860c45,d650fac2,44bbec8e,fc96f9f2) +,S(679f5afa,661f688b,7dfb7ce7,f77e4904,60a75576,6216a49f,374594d0,6bde3033,ff3fffd9,6c254fda,558f14bf,c8f05cb6,c8fddd32,a487d709,4e0fb35c,6f617ca1) +,S(9febd8ea,5dc26e5,fbf48aeb,64307b21,1aa2fc02,eceb6d68,ba89a652,f633be60,c0867bc8,ea6238a4,ad36e785,cbbc5e0f,3fc5dc96,2c778992,72be4364,8e630bee) +,S(d886b154,c534b48e,db6bed69,6dd8f9f1,347b381,1b593acf,e2137c93,600b1601,a4cbc118,aa07daa9,c4e246c8,efeaa3f7,d74028c1,93b77964,f10ab5d6,f75d077) +,S(af8ccbef,c187a3a6,83f6ab6,8ff217a1,96a8e27,dcec349a,b7ee4a74,446e9d47,3ee327c,99880392,7da5b625,be554e6f,1662a733,25a8fdc4,990716cf,6be941f0) +,S(1e9800e7,891c261c,a3451d22,44a54a84,42d33458,a997b365,4a6198bc,7dd3d26a,322f8986,bd6ffc0d,d5f1a321,e82e6b37,978120c9,66f753bd,5669a773,65a215d4) +,S(115c62f2,9f008009,5840dc97,f3a90f30,aae4ffa6,a2d255e4,15d64c56,77150044,4d944c12,7e37ce5e,fd7660e0,1e4fdf0a,cceef95e,8bc2da14,a8fd7e32,ead8af95) +,S(1cb9f9d,acbf79dd,b34d78e8,e51225bf,3f53135f,f4282ba2,59855968,2ae0178c,8fd3a4e3,7a189bc9,421595e2,bcf234e,d7b602d0,855de84a,50c68cb4,bd1a4bf5) +,S(62a15bc4,63e4c167,4bab2a5b,dc991e39,af86d258,f9de770b,66a79ee5,2fbfe357,b78fca9f,d9467e4d,256da69f,e6f45522,d376fe41,e8ebde9f,9f7bde4b,8ef52749) +,S(574a6ce0,5bf31948,31570914,a73bed4e,6bd2c82a,5a19dec4,54b11e93,5edf505e,e7b2e2cc,cbd6f338,f0ea60b8,c1a9a50e,d02dbaba,8bb5cb78,9b281a97,5c001318) +,S(64c6e37c,a3a361a4,baf9ceda,d9ed24fd,c5ae50ab,560e6319,4adad1d5,264084e6,e6e42f56,56b6b404,9c54a07,f35ae004,4b7a480e,8271c8d3,f7996ed6,68116067) +,S(49065a97,fe4a8de5,55646af8,475607a7,71b27746,ade7fb11,55308107,4900fd84,985d689f,67a03090,9ab8eb43,c7b2767c,94e7217b,fbb43342,83485f1a,d70ae7f9) +,S(6fd32ff9,185790bd,876a683b,7e889f32,8500c91e,7e5889aa,44394caa,330999cb,12fe8084,1be1f25d,7a93784e,9c6bf01f,efbd6493,8f1a678c,64497a8c,85d2de3b) +,S(4a67d4da,48189c8e,6ff34812,f7094851,2d6d12c4,26fdc98b,4ebb92b6,62d3b185,58ea83f2,f6e5b777,737c668e,efa71b8f,3e50095d,389a5540,684cea51,7f8150f5) +,S(ea1ac931,d3a92770,5d20752d,b9adb464,edecf4c5,95c20c85,987e1beb,a79f4db2,cf689b0e,25aa9601,58316597,b06fd91b,426b5753,68a48830,9c3f6f34,6722b83e) +,S(8cb35a6e,248a0527,d572663f,7abc99c9,61414af3,f196c6c1,2de4dbf4,dd545c5a,4b32e4e0,47dacdb6,66edfc3f,a08d500d,c43292ab,f36bea7c,4a3952e6,680cfcfa) +,S(247c800c,f150c2ea,cfef8dfb,f4581560,84318684,430788e3,c8d99ccd,d27f21c8,cc82d8dc,914fd1a0,e626462f,5829eb7e,a708395d,db3e70a7,57942e85,1f1d0db6) +,S(6543d7c4,7fb927c,fb0f3566,6103708e,5e0c4a4c,ed202482,c9f48647,33426673,e252b29a,69b4ad75,814ae0d1,631ea750,20bbc730,3fdc819c,88d8f3d4,7907ebab) +,S(c4f11255,d81c33a3,a09da4ac,af5c9c16,d5e759db,2e1026c2,9b3556b4,c388e6d0,e2e636a8,1af48ab5,814e5530,e48f518d,95379eab,186e94f2,4fcd551d,1ca8fd49) +,S(cf186a9d,85da39b7,7383d92a,14af5a05,b082848f,c9e60598,1bad8ef9,5e019eec,cabde21b,c860fe08,53f672a1,64010968,6b49f37e,61cc642,48f455bc,b079e3fc) +,S(e6c3e353,ad69dc13,e595c2c7,a88b8fd8,fe9d1d47,3d45f7f6,be9ae903,86ea8f32,7d3becc9,4f455c1d,21610800,a4985f33,96b5a920,d5ed2b57,2107c28,ac690be1) +,S(3827b3a3,9bcb554d,54695dc6,bcf22911,d1ba01f7,730d1c11,8d6a7b2e,c1060988,32413047,b7c9ee83,1b818c5e,cb8f4c10,c800a362,419227bf,d9f50aff,ca25a211) +,S(ff37cd38,a4b149a2,a8dae898,c40b0ef4,4b55ed85,11b5413e,48f5608d,cc6d24fa,5e615919,8f4c6665,7c3a489b,86853a95,f3ffded5,20433cec,a6832cac,b9c49048) +,S(bdff4fc8,5b492fae,1ef34322,9e83b751,d9e53c7c,455141de,f68d3e8a,320ce509,e8fd9864,9dcc5d66,6155088a,29959e12,531f8a4e,44d70b8a,43b4fde0,8bde3d20) +,S(fd6ba29c,313ff2d5,7fb2719d,9018f11e,e59d1007,24146aef,625a9b3c,3bbcd0af,187daf5e,913310c3,39f584b,3196b877,5018dbe8,1e38abf6,de73e97d,f5c1079d) +,S(ea3c422d,48606929,ef72ae1c,3ac30178,4f4b5f78,1405fb62,1d0b710b,1b29ff28,e458b41e,c6c3e06f,c37637ee,fa316e25,d10b377c,ef99aaf2,564fef92,33bf208c) +,S(46537133,4982d600,8d228924,f0b459b8,2ba8aed,af1b3c39,f87053f,487b3978,fd96654c,13189def,f243bb29,e2143dca,3b2444da,3b895700,6bbff65a,4dadf3f0) +,S(fda493f1,1226069a,ac76227f,9f9e1051,b5b29b4a,a2d0f9dd,99637176,8578d8f5,5a33593d,f63d136d,f43a69d7,f9803a62,e04e55b5,25633a06,d8eb86c7,e1d46fa3) +,S(74fc42e9,5f09018a,5468e283,5ea36fee,7ab5e757,c57200cd,966174f,39f3e4c1,ccaa0b40,3802c914,da86204d,45f8f5d7,3760e075,4bfd10b3,2a8b2521,218751f0) +,S(98cec4a,997b79a0,cb818da,58e41477,d98f8c2,8140fbaf,e118bb1a,ec483d53,2fce6058,14945cd5,367b82fa,182c19d5,ac422d9e,840eae4,d81689ac,7eaaec08) +,S(c742ddb7,89a5cbdc,2055119f,697fd575,e4fa1540,96cc5fc1,3c2374b1,13cba60f,9b0af128,34a990e1,d402474b,e6dbaa1,b32248f4,f2b1d680,13fa0dea,46f3532d) +,S(dba2e04f,9a78066a,b5897913,6c4c7224,5b5973d8,3b13819b,77409fd1,e791eb89,34747922,3adb5f74,168240e7,a178f077,aa0e90e0,870456a8,89dfca5e,633baf43) +,S(6d4cae43,6e598586,7b984dcb,6c2472b3,6cc47f86,eb69fbf,1069c69c,42f6538d,c7fb58c9,f0c4f7ce,dd7c53c9,23efef52,125c2b67,d67f1ced,b98bb1f3,d5e0a84f) +,S(4c457f6e,d5b67b05,5b664ed4,3bae291a,9ec5b539,6fd9410f,9cc16a03,b8523982,492e5bcf,20aae19f,5462ed68,2a72827a,a435f47f,ec218e98,8e91fed5,20f344eb) +,S(4d7e6922,34778a41,f58033bf,d74ae295,51fd8ac3,64cd817,9cdd441f,cb46eb3f,756ec0b2,ff5c9d3c,3a453879,17ada4bb,6d7bbd07,bd10d2ad,c092f46,c62750c4) +,S(ac5be50,69bad479,bdbc565e,ab74ef94,4a48399c,a4af915c,fefc47e3,7d464b2,3246e3fe,bc5810b6,37722c54,69ce45d8,8bad5daa,529b4381,928b7cfa,de874345) +,S(7da88d41,21350139,bfe6a481,2534b25a,24f91e0b,60d882d1,5d69e840,da3995b2,9888ad8d,62a7a4f8,700bb03c,f9772432,6a2d092c,98adbeb5,cbc20348,f0b9c587) +,S(389ff31a,63239cd2,c9aa3eb,4d3ceb49,5d3b922b,5d137d4,e8b52be3,b1abf149,b0ec2a2f,bc840bf2,8a22ab22,b76c1485,42f54ed,5515ad49,dc3c0037,38fe7c93) +,S(c1cc1acf,5fb128b2,ea65afaa,d3d5736e,a94b2e49,8dfcf6f8,f3c27a5d,596c4370,8903584d,1986ad31,6cc6bf2d,aa2a88cc,ecfec6a9,c1bb153b,27c409e6,934fd38e) +,S(399ace52,b92768a2,a4740be8,31c96c04,2a34957,e91b3cf9,8b3518b4,87c9aa3a,908314b3,abdb3a47,a117ae09,5d609fa3,fd9af1c3,ca04a869,786eb134,48800005) +,S(69543fd,8c9d01a5,702d9859,305a52b9,470cc606,cadbc76,d8283ba9,ba06d0a2,e998e7d9,a0c372ed,2e348f17,b3298088,404eb1c3,8a901d1b,6f4e8a19,731057df) +,S(2172d54f,df9b46ef,5a1289a5,872b1c28,911e553c,f703ad6d,400b6af7,e8200100,2121b47d,3b790e5e,c820df5,772b226f,34a8fbeb,f642b5d9,edc18971,1b687a8c) +,S(f606f7e9,37a324e5,d0e6847d,24923965,cc27133a,10e43f28,6d45f7ce,9d5e8b56,70013fb8,622a21e2,d1337944,89324a13,f5b80580,91ca08d1,a30e7571,3e86e007) +,S(9f1520c2,dfceb64f,1f432013,b342af35,2f95bb2d,d49aa14e,dfcd8e71,7c40fc99,fe8fca26,feb1f004,8fa4fe3b,764a907e,d53dc0a4,10308199,6cad54d3,898e863d) +,S(6670af6e,7587676e,eb0674eb,75c93d38,53afe418,cb286605,18a9370a,231eaa08,2993ff5e,dfc071ee,97fcee9,bb12fd8,fb59fccc,524d8537,34ba4cee,4beb09f3) +,S(15c6d58b,345cc4bc,e4ca4e2f,ee954c2d,40650a4e,ad6c9524,65f59a94,b3898350,894c53b,47276196,65a0f3ad,f528d2c0,221b12aa,73df2cf3,a6b0e778,a363cf7f) +,S(bc4ab6bf,60dbde42,c9293ef1,75f85a48,adfffd20,960ea454,8a919977,75389621,fe28a0ba,24a4e2a7,45d6bb68,ecd71931,791a74,61549a44,37a34761,19040e42) +,S(5dab1c63,23fbf2f6,e495e87f,1c703ba8,64f20e50,4007dc80,54ef2e11,d3e6ee1,1fd0c200,cf4460bd,ae6db415,3e68bffb,e7f01ac1,6b30e305,9c134a86,52695d93) +,S(2df1cd57,d7357c44,7be28dbb,c339ceb,5cea0bd8,e702fbb2,dd67c189,6a8acaf2,33192011,20cbc8dd,c3b9c031,94db76f5,86eefa67,995dd741,492f425a,e2f1b9e8) +,S(2d81ac17,5a02daf0,83100585,ed2bac76,3d9f9764,15356fea,584ddef,60d9ab8d,f9908cd1,3b1785f5,78297fd4,9e6c26e4,21052e2c,ce9f51c9,cd58183c,2df9a0b7) +,S(1fac1762,fb732e73,2440d40a,5356eb17,67b1e7f4,f11e8db5,9ef90702,437dc097,edd5784c,a58d5113,2b5a08ac,e75cb30d,5ae7ce27,129f158,4df5d95a,7b9b8729) +,S(d06a0b5b,4694b90b,80c93e88,4aa9086e,45cabaf0,99b15a9c,c2b19678,38c8c98e,4cad46ba,2777b24f,cd1b391b,222ff3b1,14fcc814,5f78ada4,98620cfb,747def3) +,S(4928df27,590240f9,9907928a,cb6f0695,870059b8,cf9b1d69,29b152b1,7de53445,b773e60b,655b3b0e,7b0c400f,37dc336b,240b83cc,286a8ac5,3dba751a,3300d505) +,S(a61bcdf9,cd541811,4ba99261,7322827f,f945d450,c331ddda,1b8639ff,87a28390,3e771d6e,d6fdbb28,54601b2b,301fe24d,8e61b370,ebe644ee,b40fe807,b8d93a68) +,S(535a35b9,3e2fb7ab,b3b1228c,a7977,fb8e34c,107f093f,9f641b15,11db93c3,2471ff35,5657cc8c,38283fba,27c2e3c2,92475fb5,e8d52e96,f0c9fec9,b2ff786f) +,S(e68a652c,e0140f29,376888bb,c6be70b0,f23ad42a,d10b8acf,a5f790b4,c465d4d0,49d7390c,c368060b,3134ecb6,dad52120,ea6e0c7e,b80c94c,6cf9c1d,3c1a7385) +,S(e8939e7a,74dfccd3,ef17855c,3ea20e99,f5f05f6f,8bc4757,6b4f0e99,37e25fde,6b48a73e,ff0a55b7,c90c0fdf,449e4c2b,3773f454,da2c388b,3e0829fe,d661b173) +,S(496013ea,31451874,800fa293,a6e70ac,7fe16483,67c31daf,bfd00faf,48751543,b5715111,8790556f,8a4001cb,282b3312,581e1508,b8537f65,6142e2f1,ab8c4332) +,S(444735b0,b1efc3a9,56957a07,22604d09,bb0f6c29,e7cc5201,89ddc3c1,804b1e1f,b1ad60a3,461abab3,a9732a85,7050e55a,3e9a439f,32a5b21f,9aebe400,7e59d6e4) +,S(5805ac8,4acd7d5c,f85a40e7,4b9c98c3,e8882189,e77aa475,da3b4114,3ed9511c,c952923b,fbba533f,7bd70dcf,d8d69b7,1ad0022,aeae363,bb48134d,6a3c07c0) +,S(8ac11518,30fdc785,5e1c53a1,2b690202,c12619bd,c46c8898,dcab77ef,279a9501,29fb7cc7,7867fa0e,1d015493,abfb2000,d5deb3b8,ddb3053a,d59d6bd4,a9ca4fa4) +,S(aa47add3,e42998cb,68fc8a7c,cc7beff5,4d70226f,22f41ec6,7bd7b444,aab542d,cfa5ac81,ebefd98c,3af4f9e3,9f67459a,4f8e8c4f,c1959816,f771e75c,c43683e9) +,S(f3504127,a27a14ee,92133f75,364922b7,d3984898,e433d3e4,19e88db9,e599889a,f1af9f7e,9f9868a8,84ecdae5,47bcb886,56c6d423,a066b313,c09cdf08,601b45df) +,S(33730f44,edcbe688,35887076,69a989a6,272d3ce5,9261b98c,7c6eeeed,7e4bf08d,3f833928,d87716d0,4b2a32d8,1bd2d789,b6fd057e,cc70a794,8605cbe6,e1775a6b) +,S(3169d6dc,8c06f584,880bdf07,29249cc0,a33d417f,be137478,6e5b4a14,3edfb0d6,2a91422d,ec563839,ba782f59,68f428c8,a311600c,2fde77fc,ea163e86,aa74ce5f) +,S(d8c64582,13aae81,cf07a64d,5a8dc3eb,c8c43a45,d57f8e9,80cfccc6,f02a4429,c4873051,968863ae,8c92f195,c9fee3b2,c4773d47,849e2a7b,e7f48c4a,93822aea) +,S(ae67101f,307e246f,7a7cb039,5631b884,7e59c8d8,14da3fe1,7891f69f,402b6f11,f5f2dbb4,a90b09e8,b96767af,a9f9a357,1d3900f9,7d8222ae,e411e1c7,11ed44cb) +,S(a9e87231,83ba8338,1c0a7dc9,c81a2c5e,b4e2ff43,82574f0c,1a9d7f14,81dbd8ee,96810599,90d90e33,d69fb59b,ee68344f,333153ac,3d73a335,4b7ddd6f,96468901) +,S(616bf21c,ae7d40b,2694f43a,a33e6848,694ef879,fb5bc48d,ad141e34,e43376f2,bec18f83,2aa8a0ba,83245115,3b5a4faa,4a27725a,a3d9e799,bf05dc94,9880fc77) +,S(121e8335,601f33d4,78a882b1,1e9be5bb,39be47cf,701a695f,8d351098,af3f5c2d,2e992933,18faa04b,7d85fdfd,cbff81df,10dd070,4485b659,f682a298,4d03b3e8) +,S(bf884797,3025ca9c,9413948,fef1bc48,3a83cc28,4a909933,25c8c97b,b89f1141,1953a326,3d26d1d7,86d5ae3a,7838d125,6de24760,6abbb63f,e2713f6,6ead5386) +,S(7c28e9a6,5a3800f9,85c94d4b,ddc75cd0,dd1b06e0,faeda124,e86600a5,6af811f0,a3756db7,e339f03,8914cedb,707427b4,2d396fd6,f2e43863,13414863,8ab5c277) +,S(e5ec6dad,45e62cf4,1ccb5bf6,bb92387b,46be0791,31bc2b9c,b8b93172,90a66077,d0045ecc,775703ca,f854bea4,be3c4d21,2bacd092,7a210eda,67c33aba,e44f0e19) +,S(6fc96e1f,92039545,fb31c352,544a5974,7036263e,34d8e043,58336169,118c2fed,d032de87,1571de8d,96b0457f,84397e36,6ca7c20d,d90d089d,9aababad,8b8a9a51) +,S(89e3d351,1c219c47,42e79091,47c13146,1db684dc,e1a1149a,cf49115a,746e4133,aabd970b,672e8468,d84b53d2,303d57eb,52fde5bb,bb224b03,6892f918,630c5c90) +,S(2b7a60f0,b2136453,878eb44e,aadb8da8,c043e947,fea1de8,4ff8e18a,390d5890,c829b16,1ba032a0,59340709,1b38b365,b806686d,19026f41,ae8bbab7,d04a5244) +,S(464b9f1a,c2c2aeb7,e6f7c3df,a8782f25,bfeb9879,9263a9d4,2f872050,6c9627e7,7c260bf4,59e1bcc2,df7761db,e503875e,9a23a107,6cb4e8aa,dac5b5b5,b6f7502c) +,S(79253e30,43572295,e331519,e774b670,b25141a,986eb5ab,268b63a2,759b616f,da609d7a,55b62353,b20f5bae,969665ca,ed6467d8,f2577f69,10003586,e27f88e1) +,S(634287c,e900c0cb,5c2b1967,f55190f9,19acb09,43596773,87642d16,dd399556,a2350909,8cf01601,30c042db,253334ac,223c473e,312bf758,1fcb461a,c3debead) +,S(761121c3,8bd8fd5b,a3418557,f6a75b42,d7ef2f4b,91620223,3587f183,421bee98,4014715f,f9c17435,10e6eeb0,1bb29226,76070e34,afaed040,5c897bdb,52dd530f) +,S(2618c8c1,bfbbdf1a,59da3078,4e50a2b0,77990fe1,c2f074b3,e63dd606,6d453413,ae539a37,20f5b6ab,18ce584b,4ea3cb46,4bdaf35b,326fdab0,58169ddd,32a48da0) +,S(d429fccc,10c6f025,fc7a57e1,949308b4,d91699b5,c099820d,ab31f1db,90f685be,da2b15c1,ee155918,de414ae9,1be51688,a8df043d,6fb6c964,689bd4e,5a648edf) +,S(6a18e3c7,c04b8cab,36e07625,ba2daef5,bf1e0cf6,36650b6d,56dda8d8,e4e8b705,66291330,f56c96db,ebf9c9da,bc52541d,20e75440,25fcc49e,d6215d8b,c0e94eec) +,S(985b6846,d1c9f3fe,5482fa4a,d6a21c65,d7ca3eff,a41b3220,1a37a122,f8f97756,3e2b23dd,98e18f6b,76a2f2c3,2c543f8b,bb9dc6c0,8d391592,d56f5440,aaa3a92e) +,S(948a0ddb,4ba838a4,63eee339,5c7bcca2,96fba8e3,9654ff33,55c9296c,9e6e8c64,c5b34c25,da19d83e,b67b69b5,2e527d61,c7b705ed,2f794d2e,12c4325c,3cf5c1d8) +,S(4332d02c,1332b03f,b7a46b47,e82617b2,a437fcc,694868c4,256aa40f,a8a3de2e,e6e5196f,5f9c555d,a94327c0,39411780,393985ab,73765de1,e1bbe0dd,8aaa5289) +,S(5dc977b9,2ac1c895,f3150b68,a8d69f5a,f7e12dc5,6b211d96,a67cc3fb,722a5aa3,45888ca7,4bf1ec9e,1cbd2912,3cc696d2,83260c34,3410217d,10fd0b95,9d07844d) +,S(5b9cf534,ca94f124,a9b0cb6d,f0003924,605e3bd7,d063a2b0,c6e1a81e,3fd15764,44e98dc3,b0516ffe,bda48790,fa0b2d67,f9ba4b48,ce88bd1d,d81bcbc,897458) +,S(84353007,3a63714c,7d26baf9,c895e2de,e2feb4b0,9746ca66,97fd7ff6,d5372f59,d7373a9e,37689d44,4cb7361c,f2f3452,3f9fea7c,826c62d2,3ca3f368,b0c7a175) +,S(9cf0000e,3eef9b5c,89c8485f,c3826e78,8f1a28df,f8746619,804030fa,c21e6a61,2b3dab3a,d8684b2d,94e1fcb9,d2005c20,2764cd76,aa91e0a1,ac2612f7,fe91543c) +,S(bb292fdc,5897188e,20888b25,b491a757,8ee02853,83aff5e9,99671a24,4ce1235c,d3b6d9c3,50ba7863,bcb83990,95893348,d5e9b8f7,27e1a3a0,9e02f59a,412507e5) +,S(95d6d1d8,9835ed57,6a88a21a,9239b623,efd2bc6b,f27c5ced,2d770c90,fb7d680,c91535ad,39db65ce,fab4ac72,f3ce692,b39e7d38,c72ce468,e40bfe06,6cbaf048) +,S(cbe3f20f,a164ec20,9c2c3fb9,ca0c95,15ea3787,df2c8fd8,9ee50a3a,85d09a46,cd589754,faea165b,48e22280,4186e6ed,734a2251,a6588e8b,8252eff9,afb9a28) +,S(3e01dab9,9bab9e20,59b1c215,ba67835d,2942f4,487d6094,9f39e293,b39f604a,b41ddc32,33365044,ee350979,8679f3e8,d0a556f9,e8b6a267,bd5cb5e,8523d481) +,S(298974c0,5543dc96,15f1cfd2,e4b6331d,c798918e,15e3f350,97213a64,76afef7a,68018355,55f2d8be,a74e02e8,747f60b2,22354ea3,62cb657d,e5cd8060,7a99da2f) +,S(1d70674d,54763c96,ea3764b4,641d14f6,2aabdec8,a093c3df,d936793f,511fdc61,9674adac,697e44bc,6324378e,59753f42,80774101,623dc10e,8a4eb4be,38dfe632) +,S(75220107,b43ab970,6261875e,c8f8b634,73c47aaf,91ab8fba,cc0b1c4f,40fece1,29094e7c,c3bf07d0,12aebf2b,fb56efb8,41bc9ad5,9c350b7b,885602e,a3aeaffb) +,S(cfadb9ff,b3474ec3,27db31aa,b0bac83b,fc7f4c8c,9d0efdf9,2e7e7922,f779720,ffb7657f,6f7b8cc5,78f22ee0,2a99fa82,97d41806,cd2b8b06,ab00b993,d9a09b2) +,S(24ee919d,be3c5603,adee46e1,39d84aa7,34a7b4f4,d7b826f4,64ce8b6b,c1cb828f,44039756,794b547b,9360b63c,539b8f11,ca651476,ed57fe29,364a5ea6,17ff1506) +,S(5995e246,2f755256,f4d6b8f1,a5cbeec,c50ddb53,fe4391dd,1b530eff,7cb100f4,77ddda7c,7da05165,c46d7ba2,40127ff,fe78ac6b,13dd018c,e08161d6,d81dc64a) +,S(a7233471,97dd478c,e129fa20,59193c08,364f8c37,1cf19c2,9dbd51c3,234d54dd,2c4e695e,ec2b2ccb,384a5fa0,1a96664,9cfdd711,1a1d19ad,92f2eef1,31796e68) +,S(6466ab69,d5bc21cb,d7e75fcc,5de9fcc9,a57cfed6,3ad41c23,4ed56cd0,132251a5,76e7ef89,6dbb16e2,76622f5e,5f6894da,2e0c1ecf,c4af05d2,990dfa4,25294dc9) +,S(a5eccf90,a29388ab,de6fca2a,bf216145,7fab8bb5,1e33d4f1,1e0acda0,f5c28e60,afd75916,468a11f3,73e88643,56690adf,110e74e2,c81123f7,94805b26,620e3ac3) +,S(4251bac7,493678d9,f26e52a1,e3ed9e58,6a15d060,4d1c9cdf,89ed5871,ee9c2779,fa1df27d,92e6716d,76990c60,e6603bcc,4bb023c9,dff938d,3a15ad8b,72987aa5) +,S(77a9e6a2,4c3cc21,d8cf6b97,3181e283,f40c9d0,26a81903,f042c2a4,fa7db30e,a1ef4fef,23f25ccd,bddb757f,aaa10ccf,e78d9310,72b2f180,b6e3de5d,18155aa0) +,S(33fe7961,c40d4e1b,d6ade73c,4577fa2a,e9c0d20e,999f639d,e751ff7e,6fdbea6b,91b7d5cd,4eeb306c,e316e7c1,464c30cf,9a591994,7232b037,5840b8c,d5f54849) +,S(43f66b2e,5ee52211,a48a9d8c,b485be2f,39535701,5249c311,5b682170,f9179564,5370b55f,fec0ebbf,c30cf7f,e63f5f88,3555e699,728e6892,1dbf7874,2da46a45) +,S(4ad36614,97ef1074,d74c7f6b,446ea87b,ad2f0b43,73f5970e,1a745b6c,38b19bfc,8f5dc1aa,769a5bfd,5eada00d,436f850f,6f9eea82,329ebcfc,cd4cd60,ef5cfd39) +,S(9799aaef,95204d54,f3734dc9,75b797aa,59336866,9b2f12f9,155d5953,c012754d,4b6b34a3,d31fe173,43a5b476,bc492d54,44c256ec,ea236f3a,9845a875,e83e6353) +,S(c86249f0,c6e4635c,2d03f252,50e35d67,c1c22f51,6f9a8dca,fbc9d41,15d828a1,e21770b,37dc4d0d,f4d260b3,94bc76b2,46523893,469f1025,86d99467,ee95ec73) +,S(b48dfcc5,de5687ef,c7282c84,cfd4060,61a08fe6,92fb08e,3accdc2e,6656038d,87e3e1f,ec737074,71f69c7b,c7147665,c0b52a95,37ad1566,277b6d19,fce8927c) +,S(77dceb6c,62d65535,c625c828,fd3836a3,146fa4d,36732da8,58503fcd,4e357fca,d90b2600,5a139713,525b8521,3d370ed2,4304d08c,87fbb67e,9091d1ea,18228bd4) +,S(5b588cbf,4cda0184,4df1cd63,3cc70ac8,69cfb43e,332f5c17,47364750,3175e49a,1424ef1d,f9e69e4a,84eb823b,2f95fce5,a52e1978,474697c0,d47890ca,fad55cda) +,S(c087bbba,83934208,8c70251,8c9ddd93,2c50cea5,11c443b7,da107685,9320b20c,77f26a69,717555f3,b030e345,5cbe4b30,f637c23c,7ebc2b5f,6ec2207b,9209d996) +,S(8d16057b,68f8082f,208b3e7c,fc2c558c,247d7d60,f117ea38,35e474c1,3031ed94,3d305db6,62ffd13d,100f6e0d,19c439e1,6ffb8ca7,eec6b14f,ed551091,d6ba3eca) +,S(75fee0a6,3d32bc8,6dbb8cd2,af7371ff,d17daa96,5e1e19d9,242fdcc1,edc184b7,c2b1e4ff,abc30975,fe7c992f,f8091795,61ee89e,9a040409,10bfdc64,93efa2f8) +,S(65da3959,b147093d,7d092599,a87710a,dda7fb75,460e47a1,10d5c1e2,6f368abb,3599e1f5,2f92c1e1,c3f2b463,d9a30230,a6f53028,cbae3ce9,5e345c5c,21862844) +,S(6561fc10,94632125,d76b787c,a7539870,5dda1a5b,f4407f4d,f8140b6f,967933d3,4c06c7ce,a88e2828,3eae8aec,ab6e8802,cd083f37,6d3a1ad6,29fa9b55,920e6337) +,S(c9a53f80,70493701,523041a6,a9d23343,c8a3fc30,6664d6a3,5ca5e7a4,80c4410e,9af470a9,b2e30d45,ebef0dd0,6e3b2736,369d4dad,f2366d42,18344a22,b6e4bf9) +,S(5c1525f3,443e56dd,b009f45a,1b9a1540,c203f814,5f577bf0,3c734597,33b89158,967892f7,cb3ed91a,d74f4c80,3625707b,58574afa,cb99fc02,f5b3493b,eb4f4f18) +,S(3565ccda,d87c171d,714add6d,472fee0e,69bb6ea9,75f61454,d69939cb,541648ed,9f7d87bf,ec2b6358,5dbd09bb,d008b197,4f02d3a7,6a8d54ed,d486a2d9,3462aef8) +,S(4003ef34,c0f5e1a8,afcf29df,42a14a5c,4527d3dd,138b5eda,bd8de661,1d0e3614,67203152,44894cef,cc3d0a76,35839c2f,3d3ead0f,36174e2c,d3c4c682,4c3048c4) +,S(f5c4df5b,37965079,3ebb7de3,9b495a26,13886422,929393,1cf55d1d,912ea57f,b0b93c3e,12a98cc4,5a3672c7,4a3610d3,aca34da5,7d31a968,f30047e0,31eb3482) +,S(bc9f680,e21186cd,ba63533e,56580289,cbe8698e,69ced0b3,97a96793,569e213a,6adffb78,8105518d,50fb94ff,87d204dd,7bf54ef5,b91e1d72,713fa9,b32e06a3) +,S(4dce8797,f1fe8811,453e15d3,7a3e2621,549e8347,4e7046b0,55f99d2a,c9a16516,ea5e6b77,cca7825a,95cfd9f3,7d70d7b2,fc8a8aa8,749a9d43,37ce0754,abe668ea) +,S(f49b5aba,1ef29570,bd72a0c0,40009382,af2a4f85,26511eee,81869d3e,9759b16b,2e496c20,b996e8d2,696125d0,f60abc66,1d2fb343,b4181202,8658e459,d57c7f7d) +,S(26917d4a,7573e1d2,7b4ff765,72bf2948,a2d02f07,7d7d7fa0,54a1bee4,92125ec,b8e47f7e,ae9b66a0,2a6fd2d5,cf8c88c9,7eb12530,a618678,ad5ce83,7cd8f97) +,S(1b4948d6,285a2fe4,98cb71da,f213e6d8,7ead776e,cf8bbcb1,cd7faad4,fb29d290,1ab4081f,ef87d925,9b736c7a,92d28618,d5698499,b2f5e27b,dd30c1b4,24d3bfd8) +,S(14d712ec,8179baf7,9dd9676f,ea99653c,f8b20ff4,a69636c7,7258bd57,99ae64ca,2e1db8a6,424650ec,32b0df37,d72ce3f0,6f38538,53bafad6,d366e04e,380c6ef0) +,S(7675220,41747684,9e1967e1,54445913,a1111988,8b5bf813,4d9694f7,1d952453,3f1fb063,6457b603,3a155a90,6a722de4,de1a5c3d,6094dc27,37776843,ed82fd31) +,S(5ac8e534,a8828b67,40016d02,80bb1e26,a53b16f,96b24937,fc84ba34,dd49fc63,193d020f,68f5fb7b,2c5a429,6909ce70,18568f87,115e987a,8e5e206e,b8a1fc73) +,S(87cddeb2,8d16562a,531135b6,193449e,d618d0dd,6acf6c43,3372202d,ab4a14b8,5c1de4e6,7c958ad9,9411cecb,de2e9129,cd709425,135c84b,e5b68cba,9f846e2e) +,S(c431ca25,a39ed09f,48e1dfe7,afa86630,4d4f8b7e,eb0d6d52,f8c778a0,424c84cb,450607d6,5b2dbe6d,35cf2d11,d3129330,489eded6,e35ff429,2aeae0a6,7100d825) +,S(8c5021e8,985c1a11,4bfaf3d4,40edc4a3,aaa93002,5c2f2c1d,9bff3683,88a3dd5a,4cb960aa,8077d81c,71d74ba,6096fd4a,b6d31fae,d4315db1,3c2b60aa,a12fb108) +,S(338e54bb,38a47485,8c17c07a,177dbbf,6e7a14b,26781bb7,70b9d717,6e513d4f,7876ae4e,84cacfa4,c22951de,f67763ba,c44a6ad5,52ee66fb,92f80cf8,c4420548) +,S(87f3bca9,efbb3a21,917683ab,ccd268ad,3c7b0fe1,7eff461b,cb06ee8d,2f1f3c5a,a7a1d2a1,ecccfc54,4881f258,bf5fbbc8,e5cc11f1,a117c7f8,361a33ed,55229b61) +,S(f4023df,8ed85856,8e56a037,5a6a78d8,de27d6dc,467c9aad,52407bbb,413a3e40,b2499142,fc4e3a11,6aa30e56,6d59f373,d5e2c545,3e274161,5cff9f6a,1fe178cc) +,S(cfb51fc6,d55a8a22,89d3d282,fe63b2fb,453b512f,374e01a8,92708564,9c6f2d3a,8d4a3223,283811ed,28ec120e,761e61d3,e4ea5312,1cb2525e,b567fe9c,9070635d) +,S(59a44a0b,97050147,bf219db,22249635,c45f77b1,1721c486,8937ce96,ae43c539,31e1ca6,6a910f3f,1de1d0cd,55eb8a76,400ff959,13774efd,158d931e,7039afa) +,S(b99cee56,ec277a37,6ab44628,14bb3a8e,d8e26d73,19fd786f,8ab570e8,28a8ee7e,46e0f398,dda05d4d,7253b16a,b4d80c14,b6be5d31,d1dce230,62ab1135,c23494ad) +,S(a39e136a,d96b1a22,6d039872,5da75b38,1c6b922b,52947cb0,25207ad0,d172bd2,7a5c0758,74de08e,3d10fa71,79639fa8,7dbfc977,8af1a3a2,d910a1b9,b6abb532) +,S(6e8b4125,3b2eb74e,626dd59a,eb7512b7,2c23c855,35f479c4,5b48d974,57001976,cc0b88e1,e4e8c045,5e804068,acb85aa2,715bc82,ec21ab47,873999e8,cd2bc88e) +,S(9942b6f5,681e4189,f7fb6ec9,8efd1343,cd1fb66f,1c98e418,9c44478a,51abb019,200d0ebb,b0cc2d52,90a11e6f,f7c989e2,d2fe986b,ed266430,56951679,8d0e7a9a) +,S(7fdce1ec,3c57b949,44166918,b48af352,759636f7,2eafd744,642e0f7e,5078506d,d7785aef,c19a76e3,73b786ed,1e2d2ce7,53cfb979,65d3d46b,2e313a2a,d7baabd2) +,S(6f13205c,958c83f0,f170906b,d77c79ab,5f51654d,88195b04,a70d4e06,93989c57,8ac9a15b,b386e483,b268d4f1,c950da35,33deb99,55116c99,e848f13f,73b55ee0) +,S(f955a35d,833c69be,40a0665,f4dffbfb,cd405f4f,5b4247e6,e50cd4b6,3697654e,89f4fbce,22468389,a4af2407,f40eb37c,f56e80b2,7da1983e,4e2fa4f5,8bc9ee44) +,S(dbcd152d,619646a3,42a25743,1df9798d,b58b8d1,89238132,e65fb6a8,26248007,66fa717e,c1948fd3,e4425e9e,2e6830f7,e57d23e3,d0219dce,c02b4d36,32d8ba13) +,S(f1aebce8,e57b909f,ac7cfb1d,a2e7953f,99f713b2,8b35b5cc,71eea153,5e6e8ebe,8755fa14,3e77e5aa,60dc24d0,92e4f596,88b0bfd9,585fd57e,1b7f610b,e5d9d516) +,S(a202164d,941f84bf,f89ceab6,50430905,c002bc5a,91d505f5,fef6e48a,4b55187,e0cd42b,2bc268b5,1e572e97,8b9bce4d,b6d4b095,ade884c1,bee3b3ef,c2f057ff) +,S(572e1657,46fde7de,9480eccb,287f8b9a,b1344da5,8026861,e784047d,ca8ad68a,c174ade7,c066abb4,8d2461eb,405dad76,39eda86b,a0fd170,47569617,31eb5d9f) +,S(f4e2c907,fee4d753,c08b1052,b76e49e8,b67047ca,59e64dac,58acce9a,5beba31d,b243aa2d,3a92d2d8,e48b8317,ca8fe897,2b76d134,248070f8,f41bf871,2c11c42c) +,S(a6fc6aec,84455716,f5e9e436,d68809b2,26698781,f24d0463,e06963a5,fdf06dd5,dc16a615,548efd18,6ae135fd,f748d9f0,a96b7f4e,918513d5,73900aa,1818ca8d) +,S(bd806817,5fde9652,9ccd8eec,937f2cbc,c4ffb3ce,b04cc9bc,c00cde2d,5a05f026,b2791ae7,8e014328,e0fe6a0d,8b6bddc6,db048274,5152bf76,bce228b3,64a26216) +,S(f888a667,6f8c3d20,b9d5e810,ecae6b8f,2d8614b2,3a5da51e,16386dd3,5c0165ef,fb4ee20f,e429f3ef,f6f4bfe3,9c7b1ebb,57978853,de242239,42a3dadc,909a0dea) +,S(7c8d1e05,5adbaa71,ec9023a4,8d160fcd,c3182ee6,bda76fd2,3ba8877c,409ae200,8a3b820b,ec595523,d96936f4,fce83779,c489b9a4,f2c8c524,f16e1764,2f907ceb) +,S(18886ea4,ee257120,610ccd71,593baf72,6dfd9bb7,5229959e,75c14e76,26fabf43,266c6695,f57068b0,d33ad3f,7d02b7a,898a3184,39889d31,ffa98d86,e091531d) +,S(fea70f1e,38c8adbd,3339a44e,cac036b9,1242a099,506789a3,184fdcfa,6be52cba,9dff6df5,ba8c1b9,ddc58093,a36670b6,76c0e2f,d745c468,83e26ece,3b9e7915) +,S(4de30389,45aa3c90,76d99142,e79451b8,96dcbf7b,fe420c8f,b1dc4b4a,37d1365a,cee74e9e,9093de64,2401eb2e,201b3377,992ac0a2,13b0b16d,35664ed8,d287cba4) +,S(67d09dd1,eafebe79,c63b8c40,1c102982,8c2d8e6b,6b5bfda3,73988830,1a104fb2,10eb5508,92660d96,8e99049e,818f89bc,d4f03558,d9f2c984,61ffaa5b,bd360a5f) +,S(2b5d70fe,186834f8,d3b96d4d,87031cd5,325e55f4,ffa31b5a,f5ffdd77,40e6010f,646e7e53,24d2a373,78b1f54a,fb2081b4,38439890,c9f53b1f,7bda4d47,a895ed02) +,S(cb426299,8700a76c,193f7b44,6aed0ad0,5d600b23,ca24c752,527f62df,e17be248,92843e13,f3eb60c9,e5f74eb,8cce7723,bcfd0250,4c2186e6,5ace939e,5819a8b6) +,S(3ee6ab7e,75b3bc57,135ce4d0,1e6de88b,22d0b853,fd8e0d25,f9b04ded,418e4e41,69c83f98,4e52519b,931b6afc,933f5200,6ee1ab4f,680ee768,9ad55368,1b4bcc87) +,S(583774b0,a95a5143,17232df6,f17d7829,6918acc7,2a385724,e904085f,c887e7be,33bb1e66,ee8cf17,30c16073,665c353,f8f047fe,150b4424,18c736aa,807c3e7b) +,S(af32e1ef,39822787,79082b77,2a643ea3,eb334100,9a7a3fcb,a8838e0,7079dc1a,6985e28d,c660123e,73aee7e8,b1a36697,16938331,e4b4b7f8,b3a9ecb7,4e95fd4c) +,S(6edf7fdd,32667551,9b60c740,efbfc3f5,50f7249c,deabbf9c,948adc16,e034d0c4,f08c5f18,5def7da7,5fb0de81,9b092691,64534f14,bb7d96d4,bb4513d,ef46026) +,S(3b9a6645,5d268f94,6c504120,a81821e0,86257a60,b3fd9f00,72a0a4f0,1f16b42,ed583a15,aedf6c08,95f60109,6190106,3dfa4848,645b0117,e2e1bddd,2cfe7c7b) +,S(bd035b08,2b5cfdb0,d17cbdf0,7a012b0f,27b52943,82e8bae2,d683ad0a,747a1039,6494cbad,ed4ad7e8,aa135ccd,572be8ac,e94a23c3,8b62bf61,ac90f9a3,9bb2ef54) +,S(e25fbf19,fe9b180b,ae3316ef,89e0382,4dda59b1,41022ff7,a8c45b44,f15338c3,45ec47f6,58a3dd52,34241258,1852e694,7c2c8f11,9f4fbbe6,f6388363,174c7cf2) +,S(2e231dcd,8ffd7356,52ebea7,50165405,f30f595c,3871ee6c,7c072e64,ecffc9b8,c664452,db15961a,8458f3d3,ea24ade2,7610d4cb,ee51927d,29cf3164,6f59317a) +,S(7c0f29c9,3932626f,1b1ae126,316e065,fd2a4174,a66a6048,3b458660,f5338fc8,27ef533d,df6f1272,c0255d7a,587f56a9,b76e2c4f,98c98162,350233ba,75cd037f) +,S(e702d61c,ea6f9fef,fb43e014,4794fb32,7bd857e1,70b299ba,31bb6a20,7cd5bb48,c4779881,c924ee3e,7f228a71,2de07794,ee5e28af,ca63af21,12ec0eb3,1a3f79c9) +,S(f1780044,eadec1b5,bee75c11,7c1647ed,c362c5a4,35a66d8,cc2ae45f,66c852a8,5f8de9f0,f31b3977,f08f63ac,1380310d,e8b7a304,85c9f0f8,9a677572,329e1c18) +,S(7a41b37f,22ec5b18,d4952c53,326665a5,1582ccb7,1660b69f,8d00701f,1f12dd9e,8440be13,2c57259c,80cd74d,2a2f1e01,3448865e,2429c2b9,db750951,607fc443) +,S(94fff7d,8111d69e,198f4e16,57c3551a,a5ce6316,d520a779,ca4ccd0b,282db6d3,482c9270,26c0c05,578a75d3,8b1d8ed7,42541d30,3a933b90,9c3249bc,505c6fc0) +,S(d6a6d44e,8a3ffaa9,56cac76b,1b05a4a9,d3775989,2f70e560,a54c9440,17f4e9d1,48c3bb22,cd839de9,9163bbe7,83a8a057,c7b93e87,de388b6c,dc57ba57,90863e1a) +,S(cc0e25c0,8e24edab,1e5dbc47,71543b92,c47c0993,95b93d53,699204f9,50cdf80c,20c52cb3,7170cf3b,43b76ab2,cb4a6d3b,1a977c55,2431b8c8,220282bd,51fb70b) +,S(cf953f68,4cb7d1af,a125d0ea,cfb83cb5,efddb6a4,41079be3,db72573b,62f8d827,70cfe366,a45d11b1,a847a7b,8e3e50a3,b302fa50,1afc89ac,b89eddb,30909c0c) +,S(1ac22694,2b34ab06,ff16b711,2fd5fe1e,f8ce6975,143ab19f,bff99d6b,6815d5dc,a43d457e,2bd0975,4e9b7fdd,d9e16681,1bd823d2,24476615,4d9e3fa5,ab6539fc) +,S(d02bbbff,1153804a,f0f800bc,f959406c,496349fd,a412e9e9,bb9f7232,7a4d65c2,5de80de,3c7832f7,1d744f9b,9ef08b56,d41e682,1c20f2f2,876fffc1,b802a384) +,S(3ccad347,8d464ee3,42e1cc2b,2c4b299e,d8a60326,4837a040,25a8525b,4f1831a7,35ea2a4c,a59b55b6,ac79fdd,6ceb3401,47492f3e,49b5035a,f3036b26,d02691c0) +,S(eac4d554,3e69c3ce,d762e90,fff84b3d,b3a758b3,419d06b,80f7ba43,36033688,aa64fada,c54374bb,fe8449aa,ddaa1846,ee00fb6d,c9435dbf,17f6a12f,d1deacbe) +,S(3d2879b1,73d93713,3326d0c6,133be281,5df62465,d3dbb7a9,a028e0cc,63fca753,576ce64d,9b95b5e8,a9e3eecb,34cdb8d1,fd38a08c,2a6a8c9d,8f0a7296,68d6e0f0) +,S(3f58ab8d,56a9682e,25137087,ca8c766a,72358a56,99ebbce4,cf74e304,6976ca14,3c9053d1,1a2a8a8,1f30f45f,1b480dad,f6bce20a,15e6315,447405a7,b321f29d) +,S(4f5f1289,b48dcd19,41a9df0f,a8aeae42,2a4ed913,58845b97,3145ddb1,13fd12d7,b5c3e32c,c40c6577,3e286ed,a233ddf,42ac0d6a,5a3c3e86,77f8256,e0dc1428) +,S(a64a29e2,a52dc6fa,e74e70dd,da2bacd7,e4a9dcdf,f9a0bbc5,ad0392dc,93376a76,ade2f8a6,faa9b1b7,7baefe87,33ddc365,c776f2cc,b0e5730b,4ebb0166,418a9590) +,S(dee0aa12,c4d6f88a,d1d86f94,e1c6d3e0,b8694b5d,e234af04,994cc7db,c8480e70,cbd9acd4,cbda37cf,a9d368df,332d30d6,413ae1c8,d34219,3d4651f8,62f93389) +,S(8677a99d,c8af6ae1,b653e294,80eb66fd,772b958c,882fdf74,f9c0f188,d5796936,31c668c8,348c048e,4b7a24f3,a0861f44,6621151d,4dc3e9ed,783eaf81,ff97232e) +,S(51117d3a,cb73a7cc,2b229bc7,9bd6d676,f44aedc1,98cedd80,ed6178c1,f6997fee,5c638c04,123f85c1,170651d3,96343e,78f20770,321c1a4d,174e568c,39110cd6) +,S(48d8af64,69670828,e87585d4,52ea1242,a83c9f8,3423e468,9c3ca383,9f141b12,558a8f42,f07f49a7,c6a9843b,9055ed05,1998dd35,9406c40f,dc4d64e3,5265e9de) +,S(62ba9ac1,b0fdeee5,a143d457,41c164e9,d4060c7d,f5bbb17a,ecbe80f5,f6966d2c,65a0653f,2290416c,5fc96494,b70b3b99,9329fe67,3b034aed,b586c118,a5d9450e) +,S(be4df7cb,679da56b,50ef2058,3c79310,508d8d05,43f3004a,486297d2,49febf0d,c1b56550,dd5f3e7f,a898cb8b,aca88694,ca697306,fa3fa09,95f6c43c,d5f3ba9b) +,S(e49c036c,cca2e068,5acdf34,8473316,424eac2c,ce1550c3,a0c435b0,28c9979d,456bc25f,457fde5,5bd0d273,d27afd7d,21186b1e,3b42bbca,b168992e,61609a1b) +,S(ae6845ed,a81d5d90,b3fddfc9,cb774c2a,976e701a,ad5c1302,7057a6f8,97fd58e3,529bdc55,322ae360,9926194e,7539a534,4501126c,e69b3e11,e5b4a675,7ed755bc) +,S(52a1d8f8,bcc2b772,cc8717e0,2d713864,4c274499,4a19ed18,3fbeae31,bea25e1b,da2a0b2c,e7f17894,848e77f9,53b7528b,dbb80673,c70341dc,9f869e60,4189011b) +,S(ffbbaf01,d89a7804,d5d19f50,dd5a4abd,cc5529c,90d26918,425f3805,96a2250a,88b5f7b7,eba662bd,5aa47a6,c2fe1322,2d514410,f6b1a145,38c37ed9,9a9880e2) +,S(6ffa438,aab51ab7,afb840ee,d4f85725,4473fbc8,ff6051f9,fe5a59e0,ff8c942e,5b0226dd,3b88a040,33860dc6,69613bcb,50a0e95a,2ac7df8e,66884c7e,e602d775) +,S(9c895658,f92ac47e,318f5ee5,91d26a10,c2c1b77a,c8bc8cb5,a45ec943,8a2fc79,708071e2,665ebd58,f1655e28,6de258ec,ef4b0115,ff74f38e,516acfa9,c01045f9) +,S(532e6e0d,efba35b1,3fdbffd1,8ebece3c,a59bb3ce,54fbbb5,df1df6f0,c1861ba9,1af465da,d326bbc3,eb732ed2,464b4593,36f04b0f,a50ba7ff,f61b4754,aebc5b8a) +,S(99043321,e3f27092,cdadd8e,b50cb4a3,8a8a9f80,83da6ea1,38d48e00,e5fff425,11be8597,325c250f,d9e5b1be,8e52c336,404ecb24,df29b786,ef9d1f04,8f77ea6f) +,S(96799080,3a0934a9,9a0a6e94,120c22bd,7d79085c,c331e172,87daf46e,7c4084f9,ea90012d,18450bfe,6a520b5c,9b2812ee,574903aa,d75cad04,7dc46c23,98005e03) +,S(74f5d157,915ffe10,cf6d9981,9eff7616,1f36f71b,4fc386ab,729dac37,3aa0afb9,54a0011e,4922bc74,12ae225c,dcc8c447,4e4ce4a4,941a409a,2c49d421,19b29eb5) +,S(12692753,81c63955,5700ddeb,e8d7a751,76e5f3d7,2aa0631e,3e7cd6a8,c1927855,b92e5076,811002d5,44c554fa,1e1d10b5,3eefeffd,513357b7,2c5e0cc1,c39ae553) +,S(84ef81b,1d143d73,5b6ae35,af18d810,d7cdcfbc,dd1c68e1,1aae007b,80230d9f,cae39a2b,a5b4ce8c,21ebcf2c,638a2e5a,b0dda645,aa6e01bb,33ca2edc,b575d42a) +,S(1c22ada3,326e6ac7,6647af5e,ed62a85,c8d89dd2,a733ea62,dd71512d,ec9037ad,f5a598c6,1562a6af,99e46283,cb9e6fd4,bc4142dc,99600b64,49304981,16aab458) +,S(6b91ca4f,f08eabd5,aa8dd35f,e9e04153,c00f1f48,50bbff4e,73671cc1,fa4aff1b,c6cdaada,85adf99d,4fb68c8b,6104f585,b3c9551a,7dd87977,8cb250fe,11b31852) +,S(57bb4999,6d2e2157,613f0321,983736e4,b99063b5,e8f7188e,23f7895c,edf85bc2,93b46dc6,72eea90e,9274b9b2,73a82da,d0a1ad14,55b550e,94fdb765,ab47cc3a) +,S(75790b27,ebf7566e,1056d9f2,463df8f0,67c38a2,78af81cc,b40f5260,4a33ba6e,ca0c8ca3,d99b0a5d,b065decf,346eadd4,3af8dc71,9ae06dac,6be99c5c,b89d2045) +,S(ca7a75ad,a90b590b,f7f2b6fd,e3004a1e,8dd7b4f4,db8c4a08,f32bcbb5,474ebe9,b3278d9c,5c9351e7,bf4e8a08,e0f1dc00,51273259,acdcba1e,fd3ded69,83fc69e3) +,S(a6dc68b9,3bf46294,392a8d6c,e52bb365,47b65a5a,f318765c,7a4f5d5,2f90b2d1,41ba6d67,fc575561,a0f3c76a,931dc62,37f53348,819224de,8f925c33,c90ad45b) +,S(da2139f3,f8afc90a,c7f5a025,20c36110,2fafed4c,3f525b56,fe0dae1f,6bb6bba5,95adcb88,fa9ed816,dc097522,de5a394e,71e92c1d,f5bac36,9ad06067,1b6349db) +,S(a32b2475,2f0e0063,acb4194b,faba9ccb,2159357b,23f102cd,f5a8e24f,413da4de,57df4143,bd8b27fc,c7716ffd,8c35036f,e09f8ab8,34f053db,ddfd3161,ebe576cc) +,S(aaea491d,33824ff3,c7319d8b,a233c73a,741718f2,2c921392,b893894c,ade9bedc,c8fb291,84d8dc65,93a6a3a1,a5aed86d,a7ad0d32,d5f8ef4e,b24b6154,4c1a63a7) +,S(2935e0e2,7a8409bd,224f3eb3,d68fb639,ccf75d5c,2b0315e7,ed388acd,887f2c75,c4ff024,62c9ae40,983d0068,180d4c3,977e900d,fdfc164,c89a938,c568aad4) +,S(7fca8076,9e2e7253,5834259a,abeafecb,fdebbd96,5066181,63d244ce,770fe577,a3ddc3ab,f04ded22,cac3b8f6,ffd14ffb,69cfecba,7dbaeed9,9a5e13cd,55bc3542) +,S(c5b5f1c6,1caa4a7,fa5e665f,57b45134,bc129ec7,131642a9,6a7b4191,5e8b483e,26cb3816,da5098cd,a3f58fd0,c26011e9,73dabb66,d8cc9257,6d37bfbb,9cb538e4) +,S(410da274,df436772,64decf4b,f790035b,d7d5b174,cffdb4f4,56bfb6a0,79a50d88,71c81968,188eb349,6dc2ef1e,841979fa,254a1939,5bbf00f8,8e1d2bbe,ef9a6abf) +,S(3d9928ca,334dc800,abb6c5a2,43a2681b,6f7976ac,50abf387,54058d05,cf67769a,cfcc01dc,766127b5,3e183cdd,80a0a1e4,62bf01ab,c4df115b,2e4f4e9f,95d2beb7) +,S(65a8f57b,c523e4a6,4777ce31,2000a322,d858eae1,f39fc919,2e4f436c,c8040cec,820698b9,9e953745,b1ff7b0e,a22bff63,c9df69fc,c2055b32,3f07fdc0,61192432) +,S(84e553cc,baa606c2,ffd3ef5c,a62725a4,55f4e539,24a72153,1ac3e66a,5d92fb79,34d6af32,4aaa9465,fd9f7731,1c01221d,4c0b5f75,1902dd67,4dcfd0f3,9cc5f8d2) +,S(3b4a7558,28851226,f391578d,5d146da8,dda3d4b4,f79a36ac,5f8c166a,773783,e37c96fc,4de83cc2,eb4b3cc1,44d4d35a,1a4249bc,4cd7c787,7d0084c1,b1a59e53) +,S(6dbbd12c,6164e8d,ea489819,37fcd12e,74339578,6482ddb8,9226d9ef,50cee6b0,89e48f49,b3f5d154,52e47c17,e1a68ace,eed3bc6,8002a70,33316116,ade02b90) +,S(b64180db,3b926481,74a0b743,1f84af72,f1118e9d,6cc1fe02,f0bfb72a,97c441f6,b394f997,83d00816,267a4f0f,8c95a05c,33cc19db,eac704d9,9e1f0c2c,4fb25fd2) +,S(2173f38c,f47377c6,d977fc08,ebb67f29,37e96fbe,e46b2115,b260f03a,216b5c56,bda02a78,3c4a684,fd88c6df,6becf56,3bd1c61a,4e79d36f,27e22fb3,212e2abf) +,S(9dd9ecd3,f3732f0d,864df0b4,8cf35e06,ea2b89a6,a8a2756a,222e266d,fc5c5214,e42ea720,2ba68242,ed9256a,57db94ad,dcf00b1a,50ded06f,a70d712e,17e921fe) +,S(705f9fed,5cebb62e,dd549526,af729092,9d398232,604d136b,2a121cf,e7af71a9,bb2cb17d,aa4472eb,12e69a4a,57a7863c,2b32c100,a1601d2c,44d2cc29,750d30a8) +,S(f1a908d1,807169bd,7fb7fcd8,cfc125e3,3fbcdaa2,8d8df1a2,17b84c2b,2cef4410,e86cc08,804c6c56,f81cfa75,9851e67a,d792bbe4,87812cc1,4e7aa468,b8911512) +,S(db0c5d79,35693c81,c752a475,6852260c,5625e434,5247cd5f,d40cdc24,e1355f57,120c5ea9,fb00d295,37721f1e,2539ebe5,d0de9bd5,354ce629,fe8c2e8d,c683daea) +,S(5e4d5935,56007e92,1b158f68,3411da86,e979d470,7b53caf5,9a2ed94b,ca423ec6,71588b00,1a0e9ed3,27862fb3,7ce6aefd,c309b5a0,928766dc,b947773e,6272d935) +,S(1a79ee08,3c46e5f8,8e97fd11,22410164,a264d106,7ecfabcd,4872af40,4fec7f28,f928dbfc,49bf7553,356289f,18a5c8fe,54f94bd4,d9406aac,c4df7a32,32349111) +,S(e693f88b,e3be0c46,cb40a2d7,f3a0a435,1c3a1812,4abdf46e,86ca3af3,6cac5468,55f0b7bd,24ab2a2b,aef2db89,d8aec5af,fb4f354d,66538efb,78f094a6,dd649cc4) +,S(6d15e8b1,f3c73c76,f73b12d4,f5e96e28,43bb6157,5d0d7e58,1bcc551a,329ca25e,f21f3ee1,84386427,32a0d05e,419f8a59,173f8cbe,6e3b765d,b74c3588,2d7f069d) +,S(48b8f127,b2614af4,95303f2c,f6593d16,20dd98e4,ff536dc4,8a5aaade,3bddb682,8ed1b9ba,ec137c62,5127e23b,55d786d6,a50d191d,6803ae99,c7ce57ec,2f546e3f) +,S(2ec32631,ee1e4510,94719f29,1a32e0a0,8c29fca4,8ff7e3d4,170a7c0f,5aeb3028,eb861d9f,e21b536e,58d0ee35,9d07d09a,491572f8,13eaac91,6105785c,697aa945) +,S(f7960ecb,3b35d4d4,5ed2c13f,b55cc944,7ab72f66,ea1857b6,776b8ca0,afafce3a,90245cf8,d40f6b40,a7140334,da02eea7,d8f7cf7f,8f87c510,cd6d9ae7,8410f08a) +,S(a94ccc3e,4b22f7e6,ef385780,d58f3aa1,139b29b8,c7dcb5af,7a247125,ba613ef2,ef7050fa,dd6afa0d,a89ba357,cbc6a66e,782471cb,8cfa4c45,e94d445d,a2845409) +,S(e48a7ff8,6d80f430,d3d6f57,6c56f026,8c42b3ed,17086399,56d62f54,f5485c38,b1695229,b4997b0b,229e3c65,c7ffb42b,e429b702,47b98231,a7bd9c5a,5e9a6255) +,S(df99488c,7d46c83a,cda5b422,b2a633d6,cccb09bb,f6488d9e,ac79e9bb,7f22d2ae,89490280,a958f45c,4501a878,5bd3c72b,aaf83a45,d91a38c3,e0477562,f345fd4b) +,S(a150c6c0,4db9f9f4,6f64368e,bba348ef,2bb4e43e,29b27770,553ef41a,ef22fd84,61dfaa74,e1525a0e,c3922ab0,20e3ed1c,e7b5397e,b4485cca,e1f64f29,19c5c201) +,S(9b7dedfa,452ec6f9,1d7aa167,bc984a28,937392ff,d856a4e1,204aa541,f3aa0edd,a37f4912,2f5168de,bca0ef6e,7c9b31ab,b4262c09,ccadbe79,10a4a844,ffd2c74a) +,S(c7d77a51,6d0cea71,b20f75c5,579a5906,ad1aa83c,f9209a23,d38ed358,28e51904,399a7c7d,9e1a3660,37b0a7a1,49b0dae9,8e5a288,cb5ece7f,56de4d8d,74a44bd6) +,S(d313a829,8e4de5b9,a166c2b0,f73d9812,fc1d1dec,b3b86e8d,8062794b,42fe73fd,6524463a,7eb26e2f,34f062c5,dbbdb4db,b8514c9c,60af6a16,fc9a8830,1f708fe4) +,S(4bbf363b,4d66c693,6469b8e,83c4f18e,2e6c2a3c,498f38b9,787607fe,97211e5f,9e42ca4b,243872c5,8c7b6406,11817743,82bb0d59,c0de2562,9f26e8c0,7d1c60c3) +,S(3be10ed,23a0ce86,d4a7ef1d,a667cf19,d471bd37,7467403e,3f84535f,861e9cf2,bb959378,cb317c0,6534748a,49bb9fa8,edfd2090,cb95cead,a7b0433,4066d885) +,S(fcd1f880,d723963c,829074ec,8d29eec4,946da198,cba5d96,b169cdb3,5dca2076,9489bce3,a31362e1,c4cec275,5fa5fc86,d3b105ae,25bed346,7c0919d3,b2a87b01) +,S(b5fb358,993d3662,b2e7114c,d8ea0681,f39f42a8,52cd217c,f0ec0271,fab317c4,89d88eb8,ee622cbc,f0dbfa82,8b04ac27,80a653c5,14df734a,791b3bbb,f3a71b43) +,S(a86bbad1,7fca460a,4740f39b,d2ccab3f,30fc137f,604e77c9,55624815,8fe274e7,c26dc259,ba969ac7,8d294742,e4962c07,1394ede1,263f5a0b,d03b7a29,30753fb) +,S(ed321f6,348cbc96,7e34bc7b,a935d129,9dd3fc94,c27d1467,88792180,1330d29a,b4078360,832b5de1,c77b44d6,cf07bdc8,fc5ac402,15002135,1be0d251,a3f7c3b5) +,S(c8179275,e4ddb936,f55e827e,de094c4a,2c425b8f,701fc979,96ed7194,1ad17dea,d99f1c5b,e241d165,eb49b0b9,266486af,8ce5e963,c52b2622,e16fe99d,d82553a7) +,S(6f08f13f,23b9b383,49274328,3f8dfcfd,eeaf82e,1d91e512,df1d0d7d,de84985b,96b6a829,f99f433a,6ee58ed0,50370ac5,665d61e,22cc7a76,a4a3fe08,d8bd602e) +,S(9443a7e3,410f9d4f,ef9f8b60,9eac3e5f,e6ab5d6c,a11855e4,b35c7e67,9f8f9d5a,d8c507b5,78188c3f,31bc93e6,d07abc22,ac9b2add,5a11db53,8fa0f936,3beded57) +,S(432ea8ca,3ed53681,ad3afcfa,570056ed,d38c8848,de293d2,e37703f5,133c502b,9e19228b,70b52bb0,8e66a49,826c6a61,965dddc,64270118,faa3389b,6bedff71) +,S(1d17589a,42f82fd8,c5a584a3,d3c7fed8,5e22ffea,e2b732c1,30f903fe,1982403b,9f7bcfb4,8f18d208,26564ed0,245f0c6b,511e965f,be5e0e94,54e0f552,78c39ceb) +,S(743399b5,cd84846f,65e778ea,790412ce,1ab8c6ff,ff7c098b,55436a1f,e18e6b2d,dc6cc81a,82801be4,e6566d3f,c01b6fd1,e84ff49c,e5ccf145,fb1f49b2,d8b784bc) +,S(e4378558,3b2848c1,62e3e80e,3b5f9242,5330d232,e05f871f,a279a0da,7910b2a7,c39b4171,aa4978e4,7d3f99f,8179a189,d5e2421b,d076d1f0,80cdacf0,55624b68) +,S(eef768a3,1b1639a8,f1755ac7,d00a6463,8f8a99ce,f5f42a10,664026b3,6718d63e,2a9005f4,cbf4e686,1af0043a,fe97b065,878efcb8,8be29ef5,ee648473,1e24a991) +,S(15db4687,2504612c,f40dce1b,d601d848,fc2afa9f,b2de929a,1800caa1,bfc91fe9,a8b6e64e,7d508d9a,504678a9,d90b82ca,1e72360b,95a2f515,f17710cc,4e7eded8) +,S(ad45facf,2529a84b,9d28d2a0,456a1fd9,d2b3303e,fc78e2a0,c7757bad,d4a4191,1a78e571,473f3035,16ef5867,8f77d5ad,bf8d8109,60f9925a,a6b4a88d,3654f069) +,S(41a03744,6e027b4c,eb775050,a892bac2,1c19b66d,5fa4bd89,58c949b5,b9151824,ed7c44dd,fa96d38f,a721cb2e,60e07a84,27c53acd,6435ce74,bb45437d,95140317) +,S(2020b869,58f4c7ff,2cf64589,f1043d,5a70d5d6,dac0740,56011f1d,27217ae0,111959e2,2757f431,a1994617,124eb1c6,b37f5961,29d52aa0,490b94f7,e1c4e9e0) +,S(2f99a946,859f74a9,50f3bf27,d85a169e,99c5f755,71000180,283383a9,eabd4ba1,3e622182,d3caeaa2,47a4ed24,6e608592,36ecba9d,4e8d79fa,12854f74,df89fc53) +,S(ddcf3989,57f65390,167688c,2e227f29,e7c5675,d4a83a3c,177ebdd1,9e369baa,a700c63f,3fa6833a,239a3cee,a90dd021,c3c3428c,f2b11b87,3da1dc01,2f4b2431) +,S(9863a7b8,4252360,19e2fa9e,9319c5b,92df1eaa,c0b7917b,73bd1042,191ace4f,49a499a9,281dab21,4bf09f8c,724a30ea,3a1fa7ae,4f1b2b6a,3bf63562,e03b69e6) +,S(6c5465f9,ea2c5917,34f3734a,64b8e92e,19cb4def,3c6d5d2e,467a8f58,dd733886,57e22bb,179df35d,15aa2616,a319ab3f,768f655f,a1c07c8d,3dafc443,1e0e733c) +,S(ab375513,360b3beb,d0ca387,fb0a0690,25acb654,fe703a53,d979f14,50f3fcdd,3e9c1149,309a2de5,9b7842f4,3c37a6ed,57f0f776,503ee7c5,46445c2f,6c41be4a) +,S(6acbe3ea,4a72eeb0,b23aee37,905b22d0,ff0878a9,e9143111,4821207a,4c2603d2,1ecefcbe,9f934d96,a163dad7,6c9e6806,ac2ca23c,e495a533,aecb19d,df0d32b9) +,S(7955d144,58fd0c42,5e4ac9f9,c766e253,b4ddd105,7f1c8c3,653f95cf,3a955d89,8fa9c5f7,304387f0,94a89225,53a20287,40c6723b,d25245,84735024,9650aaca) +,S(b5972d0c,90433f,702b25a2,27bd3da2,d488ebbf,e5782132,28c20cd8,35ace377,235470bf,7fbc3de5,279ef70e,d174b2fc,e3e78f84,5c0bf212,cf3d64cb,42b008fa) +,S(a266a810,33a5fa68,a204f3bc,53cc79f2,cc500d7e,4495f8e4,d9cb48bd,4bcf886,31a8b1a1,958d15b7,664390e6,a46f3e37,d52b7824,5b0b91ec,b568b7bd,f55949f8) +,S(1c6412ec,21191b63,5bbbf47e,1e9f7c21,ae7f4f3f,7de0f123,451e421d,44b9cc15,833f8a2c,1111c4f3,f5973851,d0256309,6e7fec1b,22ff969d,82a62284,c42c685a) +,S(ee3532ab,17575b57,9c19ccbe,fee04ff3,8172677c,5e625f68,a7462107,3e0b7fda,f12e10c8,b2fd987b,83dff04d,cc48ee6b,4b704b4,92b2cf53,a9af4510,6e7e8718) +,S(5ed10fbe,4867937,2ed2765a,f7f5b4bd,52ef9a4b,96515e,37944d9f,ee1a3838,8c4eb9b4,9fbe3924,ed8ac641,25dce66,a4bffd7b,5fbc68af,2a8c8633,b4080573) +,S(fe348a21,f04c85ed,69fe7345,f73420e1,b8f6b859,7082152a,15a1d535,d01378d2,d595d446,c9f5abf4,5ceabd10,3e38e423,5069473d,7d9f9911,7fa9cfd2,81f2b7b) +,S(7140369,b7b64ba0,861e1c0,b5ba3973,b573679c,c091623d,bda88745,fb2436e9,f0770350,f9799607,28c3bc21,30c6672e,40dfa362,72c50ad,1f376a54,83a12b2d) +,S(6d14c4e4,8e981e3a,e7ec6b88,b1230096,a7465db,a8381bd4,aa82157,99dad15d,25e4d2aa,a5f2d12a,a4e635f6,db58b2d5,f9c6de8f,b5bea99a,50e5b050,e7e0f841) +,S(7931b9c6,a6837d7e,3620558e,55504e88,4dffe071,5bb628d,aeadb0af,1a4383da,586caa73,320925c6,ddd12128,bf3bd38d,96b7a904,8422c2ff,9d5cfede,fbe80c0b) +,S(149e9d6a,35b83d43,5d0e1f32,a1518b88,88dca145,27aabd95,b0ecd0bd,e5cec834,45807aa0,fd84cc65,e91d49b3,8d012fb4,f87b11cc,1906e1f,cbc74c5a,ce5606f5) +,S(656b276e,b4b351a8,222f2b59,d7949010,1bf6e696,c284bff7,b809bd27,d297394,8746f309,5f8643a2,928ebfa9,a0e35893,905eb6d3,faa8e5d9,b6473281,7b763291) +,S(60f399e3,68086989,ee62370f,f7852e1f,3656a720,539880a6,9884b60a,f1eb02e,55dca05a,8347be14,85251676,d20b779f,9e5976fe,4def267d,4f1b2b6f,d444ad59) +,S(4dbda303,a67a41c,a46f417,54f9bdc1,34a305a,9018ce0d,4cadbe41,886eaa13,e062cc86,fec33458,d65f9fe6,4433b745,909a3b95,d23d7970,c22585b8,3fa48fc4) +,S(816ae1ca,4d64cd9,5a7c10c8,fd819c6b,f8c8b1c4,f495b111,d07f2a00,dd0363d1,c09f6bff,c331d6fd,56ea5520,8e9d13bb,b12187f2,d49366b,2dfd1c18,66526009) +,S(45839f9c,983fe0a7,c3b2b8fa,e5e288ad,87202944,c16d60a0,f18daf,8081b52b,f9368e07,4de74eb4,81f7beb,30835af9,aff40c6b,cda104db,2a785a6a,65dd8649) +,S(50ae4a48,3a49203b,1e04c482,ec2454f2,44b7157d,b23bcd50,63c5b6e8,d4223465,e1b8cfd7,e7bd2e1f,65f2031e,c583bda5,a619028,5c364658,36dba37e,7d5f3008) +,S(df77b231,60395089,19edde15,b21ace77,c5d8bb4b,ed26f9db,a694195f,616b72d6,8a4b75b8,9ecebfbc,b88cff82,2673665c,c99e270c,b33f3037,17dc9500,8b4344a4) +,S(ec6c0e19,978e2f18,b74419d6,70274075,6d2d238d,63b2d345,437b0b8e,f233277d,f90dab9a,2dfc4cc,62571dc1,35bfe4c6,96bd3968,173ced8a,4a363f0b,2636e553) +,S(2874416f,90e7fce6,a6d4eacb,1a722218,5af2a885,4852be4b,a4619011,617b3329,1f323675,f6ced648,8ba4c9af,7912ad7f,b8628e49,5b4da82d,448dd265,eaeb4466) +,S(872367ec,586d3a80,f8c87f3e,83b6dd3e,529de5cb,897c9d2b,e7dacf3f,70ff4247,e5bb60e0,fae0843b,788768b5,e427e009,7dc571c9,e4b62eec,eef68512,a6a3ac05) +,S(c10f2004,baffd30,ae430ce9,40c4af34,4339a0b2,13bf1f48,91b8da3e,424713cc,37be9055,f0c39b36,c546d456,b3f82edf,bf6dbf79,6343ee59,c3537fbd,8631c7ee) +,S(14e12ee1,91c83005,6bdf0f15,3353e80,733b8bb3,b93bc59d,a356dd94,70d847c5,e9707b8e,e00c1781,12b32ba7,c66d7245,d487f032,18d20da,b1550e3a,9befcfb2) +,S(dac3ba1e,2583379d,d2cdd89f,6ad053e4,3687eab4,ae804305,7b57823c,489fdf36,45e3da4d,88211519,55c20ab1,c2d1ec4e,d13a6942,fd37bfa4,7614745c,6fe2c041) +,S(d9bfc67a,5c086ae,e879fad0,b03a5a2c,a2507dbb,fdd2cb09,2644dcfe,bf800bf4,e015dd4b,5a39f5bd,1536c8b1,e93490f6,e5bb4e8e,b23e6ca4,2fc14634,2be6730) +,S(de6f3452,2f04ca0f,170d7e58,1d965982,8a9a981c,12f6cb34,761873,7996c61e,1ec16f3b,28d74fa9,43b9c251,f34e15f1,2fc6d814,ff024e3b,826054ee,f72a0cc7) +,S(432ab355,338e17ae,884a15ef,2365283e,b35c873a,4fa8cd93,f54bf828,a0e30eaf,f56066a1,a130dbf,8a3e076,720c10a5,caa9af0a,7d86ab9e,8703dcff,95447807) +,S(3d2e3507,cfa127c3,a350f546,d95431d4,8d96990d,b5beaafa,35a408d6,7f7c4d99,da60885f,4711c373,145655ca,b0f8a235,7f4a0508,2bbd2ac5,1b255593,a35f74f2) +,S(7f3f431c,b96dd4be,37c29d0a,55f3b71b,f781c7c6,191983f,4576e518,24ba87ef,f4df4345,7649d24c,2b8259f6,f7177b96,cfdb08c2,4e9161c1,695c8027,60b8bfec) +,S(4270bf59,f2c87000,44b6cdd8,b558e6ae,6f7b67d5,f128d716,3d604a7f,2f687143,358cef,2e8ff919,6865da0a,15a25524,6c4a180d,ed25174e,d08eabd,4da99315) +,S(c663722b,9930fc9c,4113af50,d51c6539,b7931cab,ebe2ebd,46f95b8c,7f603852,3443e7b3,2cdf23d8,eb532a31,3ca4b32,b94768c,78f8f13f,719708de,925ecfab) +,S(b0014864,e396ff02,cebd7b65,c66e57f9,168e8f3,95ae614f,21f8f162,c86c4e14,3f6c99d7,e2ec94de,ee65007d,ab501230,4a80b69e,a0e0672c,b7dbe4ba,182eb876) +,S(64c9cd93,98fe9da3,5d3329f0,ccb82e43,c2d735f4,d2467b2e,1250c410,da84f41a,d24b50ab,71bf6033,d1206fc6,dcedf049,c223ef78,ff50905e,c8d95115,564372e9) +,S(ffe0841d,51e05862,4f759706,b27db960,ecccfad4,cf326736,ab4fd9db,cd29b766,6bd1f1c9,f6956c10,4fec1595,24d8064f,eb5d8391,30b34a01,77c07491,79cf2562) +,S(d1dd0c0,c053c597,bad38d63,c40d1e7,4b451861,cf0f20fa,47fd3f9b,77ca7432,34aa97fd,b59495f0,3e7b5628,daaaf66b,5c9dc5ad,de929032,80ba23bd,6c55976f) +,S(87a436e8,c76bd7f7,a3e49cd3,af996f1d,9153f704,1b185d8d,f99eca45,ae8e5779,8d2cf3f9,12553844,ff905d5b,2a1fc36c,369ea4ff,6a89a027,b6dbe797,f11006f3) +,S(a54500a7,4899c440,384f707d,a8fd62ec,1801070d,cd5396e4,b59e9ecb,df27c379,e216444a,6d26bb06,5f5b5e5,72c927f8,5315df3f,11da2cae,2f334572,33cb2668) +,S(937ea4f7,99a319f4,fa5aea85,b48d6323,28417b72,8690a9c,88fbd51a,57d8187b,2931a7fc,9eb4aec8,b7dce4af,d14438ac,fce77bda,a7d3e7bb,b24c8554,cfdc9d9d) +,S(50793c76,bb914aa3,204dbc96,cb04ff26,c7060863,8d497f07,a1eb05d9,b7fa6f36,afaafc78,b5e30762,b68940df,41de9ef3,d963b603,6bb1ffbd,eb13fd67,4bdab21) +,S(8b600630,fadae564,dcd1c570,9bfe1ad5,f8da5282,61d55bf1,3a29766f,6d8bb5a,fbf1b64a,3bd0439a,ec45a7c3,859374c1,7885389b,9c201f4d,c1142120,6b2916c0) +,S(14e88bdd,e32a15ed,a37c9650,ffc18ba,1fc61643,22b167bd,635f3d02,e78c8458,82c1ec3,dc240faa,5fa355be,475afe0b,5cc2cd13,760249d7,35b1efe9,976f02c9) +,S(c201e4a3,24b68472,d453dc02,8c78b1c9,975a3d92,efc70a30,a912fcf4,991c6c06,263a954,41d6e6d0,8ebf3e50,3c786a12,a82f5f8c,d38dccee,62469e9c,f0e2dc08) +,S(4097665d,319a8b3f,71861b1e,11828cdd,4094182e,611b35a7,c5d10ee,99db4fb,ca0d7ceb,b1aa2b1f,576cd1ef,56ffee03,322a6b95,505727a8,5dcb70d5,27a506a) +,S(173d287a,eff9293e,dd2021a0,4be052d9,3713341f,37a537a4,45deab49,b427fa92,9626e204,f03a1886,c27c37b5,85725465,72e5302c,d3f9ce54,1fb9a46c,16432548) +,S(c923c74d,1b114f,30d4b03c,92629bed,227fb8c6,8f1f39e7,8f121a44,694d4256,58edbe6b,dd5e1382,108d1e08,ef022788,c9f91803,d8ad4273,1f413440,5b5b3d29) +,S(92fa7906,b1f25c2d,3df104c5,196cf31f,93e5a8be,6cb91a57,c88c4ab7,cb92d46,a12162bd,79341fc1,e8f74db6,2bcd0d9c,ae99a75e,ce588240,79a61751,c887f307) +,S(37477df6,f51f78c2,a9c8e17e,ed30d5dc,976a9c91,4aea94c,691aa3c4,8639140,6a6a26ed,1955656c,64c6e15d,e50b0453,25c3da66,f5067730,5c2d5fc2,a8089872) +,S(b5b2ee59,1195f38d,f834e78c,abf00fb0,be9bc724,36c5f596,67ada098,dd0521bf,10f36f85,95233008,46dd276d,951abe90,cc8baeb0,fd8fe44,314706e2,15ddd5e4) +,S(b05d1b8,443f1bfe,36a415e9,d307ef2,56039335,76ecb630,94845b03,d2a137bb,99fece4b,ddc90b2c,3102a415,6f0d63f8,54098f48,3e1ef64,65f7f062,7d066cbc) +,S(e5d711bd,4778b3bd,cefd703a,e9525b5b,d69dcd86,6cd0b179,de76ae8a,5d918fd,8af014ae,5aa05b29,a0c88e21,8fef5690,9685d524,af389327,5421c35c,6db64248) +,S(7703cab8,377a482f,bff1c6fc,4d137998,1e217d11,c424beb9,f4f1f786,86fa4f30,3323edd1,3c80b8db,c7e247fd,5568c92c,8dd329ed,420aff0a,8e903571,e884e8b3) +,S(f834af29,c18bb488,366cf722,52a44357,2c87da2c,c14b3085,5405f626,154f3cc8,2e8a0ac0,ca5441a2,9e27dc09,4fd5bcc6,6bd8f7c4,717615c2,82001fed,bd5ab248) +,S(783b093d,13f33c60,1db8ee84,51d852ae,13bbcd7d,1d03a79,4c774336,4bbbaee0,3aa90b01,cfde6abf,fa0dbfb2,ec2cefb,6b5fb1c7,41701ab,66ec9b82,74ae5b4b) +,S(be3cc435,a7770b99,14a243b,48ef2c77,3ae42e82,1c18a266,6f92da59,e01c3391,f0d3bd36,9118c58,159fc64d,e61ebc58,a560f705,25dd5c51,e6aa9276,5ce4a701) +,S(3e980bd7,adac00ee,fe362454,5fee1ae1,97f89e06,84576a08,fc909285,783b606d,c64f0e41,204c946c,74473434,7e091147,67455e30,53fd488a,34d333fe,e9c5c228) +,S(a6b04140,aa621e6a,34959bf1,29790d72,91d7b154,5dd5e7c3,35bbcfb2,d582b442,9cb2c9e2,9cc05d97,5e61d151,542af6e7,a997f8d8,ee42d37f,8041c169,abcce830) +,S(7ea7a83f,c133cb8f,a109a6a1,b29b2c3a,29ba432d,222382e5,1f280e2a,47fa721b,cbe384e8,8a1f7731,831c5562,ad1430a6,6aabab75,e38571b4,5bb7dd8e,a699d7e8) +,S(8525e87e,f0fc9ebe,2f82b5fc,a14ba6d4,8189f9ee,146aa6c8,d842aca6,90fa042,dcf06a78,f311a3cf,182a393f,2a34a570,192873e4,7dfe22a6,86c70e75,6b32c86f) +,S(7555a77d,fa050d0c,9ed29c33,765fe967,16dafff3,6cd04fc0,952a7b41,bbd56dce,9854c0a7,bdc3dc1f,d8bd0a3c,d0af3111,18dc0392,830699cf,d0bd6f1f,17152177) +,S(9ed142a0,7a0adac1,14e6f026,133e00c4,972bb3bb,bee62f71,beee17d,9aac296b,c1eaea41,6c80e3b8,d24d4006,f699af50,9f4dca85,11c27f6a,39150a20,2b7a9d08) +,S(a3fd2cb3,784d8ccd,92aa67c,8118fd80,c9d761c4,2e0169d5,fb13b1a8,dfc56b79,75cd9b41,55db55f2,d50fcdd4,8c90d58a,b0d13df2,7a09df6d,659bfd5b,f87ea755) +,S(2ab4be05,217e7ee8,799ad598,b9c0e211,554338e2,8bb6d42f,c9952203,605ad251,2c2a1a58,da066d4a,7fc8c8eb,83e1e47b,b788afc8,3c8c5dc7,bd8f5e31,5476d853) +,S(4afc2888,af8c1aae,af6268af,566ecceb,8c95d09,d9f8f359,2cea567b,8648c383,b1e26b82,5e69e92e,98902579,7e99c7eb,cf3f284b,e1de0054,58b59336,a84f5eed) +,S(dd800faa,92319d2e,48038600,aac1c2b2,f63f5fc8,dafd988b,548021b5,2d8e3d4a,59fe8092,6e0468d7,60e522ac,91881bc6,8fdbc192,14fee60c,e8e1a977,1039ed7d) +,S(84aaf3d1,daa3a5f8,89b9bc88,6afb07f8,7bb5182,6df9d7e2,af5a74f3,c6378c91,f4164ab8,45eadd6f,a6331218,ecce096b,a04fd586,b744f0e8,11c2a48,3835afbb) +,S(b770f2c3,9e2e9db8,a92823a3,adffb690,d2ffc180,b88cefcc,8adad3a8,27c40b2b,f7c6e37,9894982,5d1b90a9,16ea564f,7e319c97,ca6cd22e,79f599e8,dc0d53e6) +,S(a60608a8,a0d7e556,70145c5f,bb107cc9,7cb1db87,2493f362,36a21e7e,babb2b29,3423527c,4e414548,96406f90,6d4a3819,a289c91f,b580ce19,6f25c57,7b54de5f) +,S(80f470f9,7b7f393a,5e6b4e5f,cc911a73,20f6b0f7,fcabf2d9,21eb649b,53414597,57d8f2f9,6e1bbe0c,1328faea,13c3f3b,770fa14e,4b5b7e4a,fa1ce9f1,2bd9adc3) +,S(4e111bf2,1f5248cc,3fff0096,c64a7b58,72e4a3db,1f0397fe,261cb33a,995abb6f,249cf172,102733bf,5fd829c1,d60bd930,c03af614,31faab0f,6d5acbb6,96eb2b9f) +,S(7d8c0cb5,47fa1d8c,10254660,a20e85ec,960cb70d,f38174f0,18416c68,c62844c9,2d79ba3c,17ec4d79,a157335b,f358cfd3,72b0f1ae,1f6bc743,40400571,5f35a271) +,S(bc0d4cbd,95896fa5,7f23d48f,a5a9f2f0,14b132b8,9b5953aa,f612aaf9,670a0034,f5d06670,7b316581,7a641091,55773bcb,83d7563f,28ea5412,480a0f48,2fa0639d) +,S(b154a2ae,ad08d115,95eddbe1,c9321e15,5cceb0a6,a7e646a4,2dfe70fa,b6d37a40,9abade21,674dd12b,d01e586f,695c896e,17120d8d,9e3c756,c8b5e53f,3216592a) +,S(ef603c34,a6ce06f2,7053bc31,841fe2e6,314be756,7e477325,5315ca58,5772e1e4,f9ebbe28,96f3b0b9,923a7e57,d819a231,15fced8f,3bd08f51,64aae597,c49ad65d) +,S(a601176c,2d901ebb,ad5a05d9,1adc0041,14f7bda,1ac496e2,c04e23fe,82aa9376,f781ddb7,ce0c3649,3772fb84,9e914377,d59abcf9,d3eade68,f8c8a303,1ae88ab8) +,S(abc41547,b6b3104e,fab968b9,bc9a9027,b1c7f0ef,3a9007eb,27331539,5c31e6a7,cd2858a2,28f21d6f,bd8a1821,dd78399b,594c5bd3,52628dce,879b8a37,d97e0ec9) +,S(92890105,c9c721,b2e4c430,26e413a,941d1da6,d31b48a9,2f2e3a17,d87f5a81,c1cad87b,1bdcc617,1e432e17,c13b47c4,15c22399,a7cbfe2b,b3097f28,da60a5da) +,S(e520dea6,9f4b35ca,46a46831,9947690c,500a7a80,6bd64228,ad144a7d,c37ca563,6c00d766,ac3f8fbe,90355dda,6ad4e2d9,e2330b0a,db673356,638b0d3c,8a2a82de) +,S(c0337a23,e2b3f1c1,a57d18a7,9d6ef25e,ac2e9315,18f0ffb3,7502d701,c57fadc4,fcea5873,be22df35,4729c3d5,b07a570d,7ac7e938,f6e061ec,cdd2146f,50808b65) +,S(276c62bb,6a8e2c07,6b5fb6a7,62d1d624,1b796a96,f53593c,fa51279b,2981ac04,5c53a65a,bb6b01d2,3f9284d7,d696236c,773c4578,88f692b,73e2ea17,6e1afc1a) +,S(604e1e87,e5051dc2,b837ccdd,43c8ede4,c4a2de6f,67a9ded4,fad1ddbe,8d663a5f,f70fe23c,e3511973,93d4d675,9444d862,ace4c473,99c34349,2d06b27,8b429bee) +,S(f2fc151f,470d9106,d58b05be,5e9039ba,4aba16ae,f7e4ceec,3b6e3887,5c41f6fa,f49bd2c7,f1aa5c63,d8e7f2d6,e0769060,d4188773,9c16b7b8,5d2a9216,e1e98de0) +,S(8e031346,e9f34ef,3b81d9cd,7e46eaf8,7ee0b294,d66b0315,eb0902e1,340ac560,ff00c8bd,a5e21e1e,5127441c,ee0504e,6b028c,ec0dca,450145f9,2c394296) +,S(a8680f1a,d75b7a8f,27a1cbe1,6b2954eb,d4e26eb3,a85d1a0a,96b9f40f,e5a9970b,60c6bf41,a55bdac6,397281f2,a3f52896,757401be,c42964c6,9501973b,e6070c01) +,S(4d68a1e7,f4d82ea1,e03407c0,5085c794,9ca8c00,d4dcb066,128e6c6f,504f4658,85c5de11,e5dd3691,2aa95d2d,2c36dd6d,26a9550a,3a672af4,d36265e7,a3d1ce76) +,S(3708f41c,2a6d8649,6983cdc1,bd02eb39,758c0bc1,ae78a483,5c6a20ae,e6c2a7a9,310b799e,79b7f5dd,5c9ae0f8,7aab193e,3c2b7145,c70af9e7,f4553faf,abec4152) +,S(8c883967,45028c5f,f1b96181,43f5b732,2d1a18cd,3abb1a92,f6ce3780,a115f059,24563ad4,e4ae484a,c344180,66dd87c,40128e42,5c8dce10,b008a7e7,620725d8) +,S(c445e76a,7b377ad3,bdd0fd1a,94a7263b,652e83c2,6342305d,a0e1ff4,d58f8fb0,4bf5a41a,dc8ddb61,3afbd3c1,3aae7dc6,f60ae2e7,23065b8c,c94cea61,cbacc89d) +,S(4ad9613a,c8a635fe,60d9f1d4,da4b9fd6,36949d5e,edaaee8d,eb2f65da,8e419f16,5a9b5b06,8f67a0fb,3ad31c83,ef1a81b9,38745877,b4b07316,42ab4951,68b0d7c4) +,S(beb3eae1,958bfe6c,9ab49d77,648aa662,2e397fbc,58e90b0c,20d1d29f,d760c943,d5a46be,f43a67ab,225dc6fb,5aa68daf,ec76f27b,6a822678,dbaeff88,382c9b8) +,S(aaa9aab0,bc0e21b3,be3f1dae,ad4a076b,4623fc14,3e4018ab,9df9a19f,d134f397,9c7d7fe,19642c65,a6c0347e,8fa2dad2,d3f094f8,bab6790e,d3c703ba,2742e40b) +,S(553c1e89,99d6f446,2fd7ae86,f1cf9d24,d4011661,9fd5d356,604d6a55,ad99dc52,26b40d3b,8410ac5a,6d2ba776,f7c5f0dd,3f6fe494,379344ed,6460bd6f,f550cebc) +,S(859885ea,36378fc4,398dae9c,4725d604,c3d56509,559ed28a,b47ebf82,5aa1abc8,fae5aef9,fc74b963,bb2fd930,5b2d1636,e6e84aa,3c40b066,9e531fcf,f00687f5) +,S(5fb0a118,679c5d48,554bf7c1,63b82345,89e51032,a70c654b,bb7bdee,f0368f93,e8d55f0,4a6816d3,bfb02111,eb95d868,5b9966ad,39d94c70,a4cf1826,6bc2a2d0) +,S(a424347,86f3e153,c9bd737c,1e70ddae,bbed445d,77ce4302,194be82f,94f91dfa,27d1cad6,abd9fda9,c1012f4d,f25b69fd,a54239a5,8ec12496,97116548,e7beed46) +,S(5d007508,63fc1f3,a0a8213c,c729310c,39465945,72b083ee,f571b921,a0c821e7,e538fbc4,5d055a07,b2cc2605,61238486,d99bfa81,6b0407f9,39f1d12b,feb2df3a) +,S(a3eb25b8,97b10286,934605a0,e4aab7f9,e80393aa,71cdea52,5f82f5e8,282e3db9,e2b354c2,1430c45e,4236baaf,128967c7,6beec58b,e6890c6f,303d83f,71e7f77d) +,S(73f63220,8a133202,96f3f51c,d10fc816,1e309e51,4ea35f0f,ff72e09c,e897981b,43412959,cc78f32e,d6df7ded,349a92e,3095257a,8a1b5dc4,15ed073,a420179) +,S(5f0825d1,c21bb5f3,8f0d9628,f6046648,7760512d,f1bb9bb4,ccfec4e7,48da41af,debac60e,1d95de12,84f1abd5,b6592824,5becd4b8,c2496323,b374239f,fe5c0cab) +,S(cc42a6f2,b4a8e9f2,fae3f624,cd12294e,efc26dff,c66a676d,a10259fe,f7d84294,91b26600,f92cbd05,f13f2adb,2b5fb17f,118a7ae1,6a011690,1bae0e14,3b230519) +,S(7d56e0e7,6eebe13f,a81aad7a,8efbcd1f,4de0c5d6,bd136261,8f0002ec,6f635a17,95462707,fe55e3ee,46dca813,eea5de7c,51122ec,55a91754,f7d13ac2,43fa1ad8) +,S(7972b61b,4fe85ec4,acb605b3,aadb56b6,fba8cafc,3c764dc6,add54c06,f7a5be61,ba186670,2642fa6e,a7cf5141,c46a8e92,4764c4ce,5d45b7dd,9f4926c9,32b8c7d8) +,S(edc8a440,347b1500,899f6360,9674f90f,4344c87f,361fae0b,bbe08235,d5025626,2f812740,9a14bf59,9bcc7cef,ad140b2e,7bf84122,9a51e486,4d01ecc4,1b2cd77b) +,S(bd9b65c9,7a8cf4d5,2f727b57,19f99986,d4ea1bbf,25560d18,d54877cd,3db16899,59cf7127,4e878e5c,bf0d9e02,dbe4f861,ee9c8e3f,5dfe99af,7db98e2b,c2fe432d) +,S(27635e38,1191e8cc,d3756571,44c5d8d8,72d91802,5950a106,f3be2acc,4cf35782,c359fe47,a019870d,7fa3ab,8f51bad4,eb5251f3,7e6b8ce9,db1992f7,cd1ab7d) +,S(4492dcc3,16c05300,a96abad1,47a00e98,359950f4,95dfb261,839ddf21,3b21d85c,edf1371,a4e81e42,dbfb8c6d,2229dc5a,fafed4bf,a58c2433,18934ed7,dc9ad35b) +,S(f8124c40,409e01e5,8de8a386,9bd88f8f,25887fc6,cee37c01,279aa606,edf9c67b,e0071d1,d31fee0a,8a26269c,3d7f3662,2b0f008c,61e749d3,65560c21,a26fa6bc) +,S(cc597b67,66eccdf,a2c0716a,dd5e51c2,ce3aed33,8f55f0b1,b5784bc3,9a05a2b5,12e031fc,394a43d9,d1e12ec4,28e8d5b,df52dae7,f3ef22da,74e3a418,74682865) +,S(142cb2c6,bc1283fb,d2164270,7d525dd3,d4a45f71,a63222ee,6fdd31e2,805aeda2,bde93d12,c72c422a,e4d5b718,bec6458,ed082bfb,7c686f2e,1815edc6,5ed66ec0) +,S(fbf4d602,dd765941,e696704a,1a8977a9,c3327375,e3f0d479,68fd9148,c01d2d3c,65b46df7,99e895cb,a6d4cae8,e68f6160,c7b96fb2,9af7d18d,8ef1396,c06afa8d) +,S(efdb5d57,bb5fe8cc,e3300ea5,ec14c50d,f09436db,cc58ebc7,c6d123e1,8dbfffb8,39083803,d9a90c62,6219ce93,167bd89d,d444e47e,ddd60deb,8137b8a4,203fe01) +,S(5bca4334,faa30557,b4b36c7,b6bf2d4e,921f59f1,eadebd74,97690742,2c3f35ad,3c97baf5,e2a663f7,22bf2fe1,cd646db5,79d27f2a,353fb45b,520d227b,c21206e3) +,S(9aa1dbbc,e90cf065,5ad8a0f0,54aa6641,ff921e97,1a73cd4c,49ff1f3f,51156632,cbf6e81d,8bf1e85d,b802f0f0,b9cc1125,6e0b337a,b90112dc,6513bf40,2b1a4200) +,S(2fc7fc55,86ed7676,4d5d4d23,ddec2827,5386e56f,eff09b86,abaa9562,73c2d408,5bff69e4,773c34ae,e477b0c3,e0310b5d,6019a558,5d4c7f3f,54f9c810,69d6285f) +,S(8e5fb941,c3ac6f2c,43195487,80df9116,6ef3b210,f2fff34,764cccbb,d34190b2,dbe2c1b1,5f6668e2,c63ae154,ce7b32fb,8d29b59e,dcf1ac4b,1df9baeb,fd10d2ce) +,S(7a5bbb59,4748d6dd,5d3389e,aa95b8da,dcfbaa07,26693690,4801bd61,b3d49c6,c2d28043,a42d33fe,8d8b755c,61235c68,ca13861c,effe3fa7,fd4edeac,634187c0) +,S(95beb8bd,f0d33531,ae73ee1b,1b631ce0,917c2fe2,22534745,f87faf21,bfb76753,c6cf8600,d9c55975,527e269f,b4a0e4cb,b9bd7783,7e230ada,a43c2f0b,c64f45b) +,S(f44ecb0c,6d896dc0,304fa480,90ab9793,576dbbd9,76b8fa32,540d223,e2968d25,545064f6,29644329,76a03c62,9ea46a09,e20e470f,5e76f810,6d19f353,c321086a) +,S(8dd32cd3,3dbd936e,6173ef50,1f7ae265,d56d68c2,77061e07,4fb49d26,538109de,6b110e5c,80daac20,5392bca8,a47d6d90,ad158c25,a10c0851,ae985f70,7c3f1e76) +,S(3d4afd30,b0f0f578,d4fbc77e,b71d044d,fea5e3f,891cda8c,77075dda,6237997b,2816e0e8,664df57e,c793d442,49c23ada,ae286ab,e748493e,d83b1efc,58bb9ce) +,S(a9b739fb,beaa3b22,b295ccac,86a07ba2,b8391381,2d2be020,a5ffd17,85d95ff1,a1d08230,21d6a6ae,f696d732,3c43fdec,d3c5d42b,8ed7ad40,1a55b2ae,bfb84f1b) +,S(e9009747,e51251eb,fc2cc754,c8b55966,a37e5d67,acf9b632,bb77f46b,9203715a,34258967,9ea8f997,71b476f2,5571a588,756f277a,17ce3907,d9cdab4f,cef9df72) +,S(7e348ced,55aad74c,c24d09b9,6b332084,2108fe41,3ac4c6c1,a8376439,f21a3f2e,39874f8e,3b722795,d8465706,e439e4f5,c884c22f,365920f9,1edcf83e,b4389e5f) +,S(a7dd6676,5ec2d701,56f2cdab,f0fcc0d3,8e340fb6,8a0d1220,aaaa74a6,fbb1f55a,b7091bf2,ab00a63d,292ded9b,b00bbe9,63710dad,445e8e73,760a50e7,2f41d447) +,S(b8579e9,a8cccbf6,dc033a48,16d8934c,51c0852a,4693fa96,a308d51e,3f57025,e696ecdf,4d79151b,2f164a3e,bc11bda,42c88833,6f694fec,a8bcdcc5,7158268b) +,S(7b29c45,9de0080c,bf8c8c72,e7b59a7f,184f1c1d,46787cda,bb42c2c2,bff57af8,40de8367,a6d8d13d,41901ca5,60376ede,817578b7,25f4e614,5dc46de9,5f801799) +,S(1ceffa6f,89b65be7,ac20e34e,f0b7e503,d1c4e9d,b31fe14e,179afdd,96f00f9f,6fdee8b1,f05930bd,ed98feb7,81790e10,8e293bf5,bcaa6da9,79a744b5,1a76f179) +,S(556e2d6d,11d301c5,6d5d01e9,a01e2ec6,80ba4efe,a004de47,ca2d97d9,15e58d74,9588349b,b633d7b6,b55ba7ee,feecbc99,3d66e6c7,2f4d8961,8a2c5d7,5249d711) +,S(b3506e88,73b93dc8,ed04518a,42b62ea2,b97f7bf4,e9ee66ba,6a7ab917,a1e51586,474f8100,1230fb7b,fe693eaa,7acba9fe,5917a39f,1f8fe3fd,5823ae4c,1b0b3b38) +,S(d186af3,89cb4908,db01a886,f90ee67c,1ba7ff3a,19994504,e9774b96,bd2628f3,3b39782b,c6567cdc,b4778c75,a862ef36,d01d746f,f411821d,5d08f7ee,f2a2db7d) +,S(f951d921,e1065ac2,3fa45900,62c639d,19e8c980,2a810d55,d6788572,ef987bb7,dcf7ddc1,87f8e975,27db239,7f553b5d,51abc66,bb76a070,55d098c7,f9d7d950) +,S(8dce8e16,7bac6fc6,1161b75e,8f340e0b,8bcbf874,fc82a42e,bb53e0fa,c4d915ec,11ce53a1,4a9eb9eb,9b4b410b,34d26ed7,9c0287f4,9032f674,e3212617,e0ae940c) +,S(ce2d3cdd,a0a7a43c,d7d2ed15,ec12a7aa,755dfc5a,ed5a85dc,4f439eea,99e26e2b,6a96aebb,e7ca2740,ea75c285,3c582207,6a8eed64,7e21809a,36b97c60,7a5a145) +,S(239466fc,dcc2d4c5,cef367b5,c8339248,f712c40a,558c80f0,5ea390a8,dcd92092,f2ce223c,9b49f08b,ca63ee8e,98e01736,65d176ab,3b7d718e,d0e855e1,27ac28cd) +,S(220ab764,341d3c08,d9c5bcd8,331e0973,4a2f3c64,4766395e,f6a5fee,3563e033,ec1e4460,d03013ef,467dc7a4,2b520c03,aa51a9a3,57817f4c,f9dcd837,56df5011) +,S(d5455dfe,16406a6c,70fffd81,f3c4d10e,845f0b12,64fa3db4,ee2ffe80,904b469f,a0f93b8d,257e1e62,265d99e4,9158497c,28a20af0,2af959b8,8810a10,60aaf9a) +,S(52367377,a1f6f05d,df054665,f1eec0d2,f5039cf9,cfc1d37e,1a9d89f2,88e60c72,78d89f55,430fc352,cd58d047,7e2497a0,d05e7016,d98f9ce6,a039fc5d,9ec7bb41) +,S(5b996113,3ecc9422,26a3dc88,67364125,a8e569f1,912e6c9f,4c1ddea5,5fa56395,bb9d7764,12076caf,5d8ac902,c5e2fd5f,f7a0bcaa,10898f19,10142af6,4e436d0a) +,S(f36cdb5c,bfbed1e6,58c7fa4a,5b0a6773,eecd1a43,db96cf0c,7c24f32,b84c13fb,cfc6d2f0,5ee9eda2,9156aee1,81b62659,993744e7,479379b9,3156c919,18c394c) +,S(3208c58e,25107af2,b38bf754,5531266f,842ce33,10ec7e44,595fb91,7079a6f9,831c6dcb,5346b6c9,605d9ab5,895ec2cb,653599a2,c88801c6,45a4758a,32c785d7) +,S(a6073a07,1f8510e2,aa021b80,b44d7356,47253583,6501a5a8,c5253918,8c9927a7,e93a9fc5,4c8a7612,16718baa,dcfc9bba,6fefa30d,85803246,2a9f191a,6364fec9) +,S(3350b462,f79eaf7f,260f2147,6aa7ffe8,f7ec1a7e,35624713,9e335758,b9f0d913,1f0c9db3,fce1222,fbd2341,ba8d2e93,20f33bc,482a4d4e,80571711,21152959) +,S(a54d5b17,bc82a74,9207c89b,5a1650cc,1773913e,66f6744c,11de24ce,3073caa,3c243b5f,5309dd11,83c7fe5d,49222c9e,fe62dc26,f92b73af,cdb7b7b1,32cd3ab8) +,S(6590a2bf,676a7a34,a1424f7b,1c7863e,8a7d346d,563905ca,e5b25729,4a04cf8,11cd5803,490419a,1382d972,eea2f734,4f8d0cec,42466f09,39650645,a3e781e7) +,S(b3c09c02,9fc7f48b,d2f461a2,a367011,8840393d,fb5b9592,89e96ec9,c7cba9a5,e7b5aa6c,bce54ad0,197bb1bd,ac030e2b,c6a3e6d6,af2db60a,b97cc92b,8f5cfa9) +,S(d7968ea8,44a137a,7db36143,98b29972,cdc693ef,8fdd4644,26a92939,18fa8bc0,82402589,2901434e,cbd5dd29,410ce2e5,56dd3174,d74da2e5,28326ec8,ad57a75c) +,S(8a57bc6c,2f98f9cc,d1eca172,b2501adb,3bf6edc8,4b50365c,6d959f00,838e8304,2ebf5462,a0f85985,438b5d67,cbfa68c1,bf643410,11a478b9,92cbfe0d,87e7d14e) +,S(51886841,684750a8,c3cb8d18,f8c863cd,1a555dd3,7f0efb4e,551d0d50,6073fd22,eb05f09b,9e983ad0,a6ce0f15,c2f5983c,6a28ce50,6c52f691,f30517da,36f3f192) +,S(fea8c35f,27e4794f,a9eab856,615d55d2,d3a02616,9b9eb7b0,ab7493e2,f67c85f3,c325de97,cf0a6e3a,98512337,8e2ba2e7,b24158f5,4aa97c88,9b54a502,8c148864) +,S(6612cccc,d7bc25e4,f8dab955,d5c1c9cd,d79d5f69,7ef4c510,77b5027e,d1f94b63,615512c1,7a378d0a,e7aabab5,253df9b,e9bd6a80,15c3b200,73d0499a,3457860b) +,S(c998b07a,499859db,4c9d698,33199956,f8a7ae67,9f6d3533,cbdbd7e4,a86f8746,d9e01371,919e775e,a259d81b,ea206e9,37d6b5e9,113838a6,6af11bf0,8dd17138) +,S(5c0e4669,c5cf965f,854fcd0d,23ddc908,c32e3915,460d44bb,520fb0c,3a4cc1e1,cfebbbaf,7e0f9a4d,d2f35ffa,cd0f7cb9,89f5eded,c8b3c554,64fb909c,675adea1) +,S(d0fdda48,30385167,f06f6433,c6a9d3fb,7ab3195b,64f9750b,cb2dbfb8,7158c0fd,4cde5577,6a34f61f,c82e1359,8618336b,f5c6e315,d10abc35,8f0020e3,ef1283db) +,S(d925570f,d78bf65a,5d48265,6222ce74,7cab153,19b7cfd3,7bc70185,fa4a3e81,3c399a,c448ba90,1a21a5c7,b9c6575c,ff52bee0,cdd00ed1,673d8370,87c1924c) +,S(45d2b56d,81f84bac,2077d607,484b0802,a023cc4f,d7818f9a,1d0c2187,98374c8,14ca18d1,92a9cb37,ad50506e,a25663cc,9829411f,848bbf05,3064041,9c19d7f4) +,S(6ad3ac11,8588c5bb,f793404d,df9a10f8,ea8c1978,65a93fba,5b7170b7,9e157400,fa25741f,1e242c3f,edf20e80,fd76292e,382eb5ad,1731ec97,a8762fe9,811686d7) +,S(5da24445,b6dc960b,793ea9e3,912b21d8,26d54028,2ddcbf5,28e1ebf,4a595f52,bc18ff8c,ad1dca69,8995063b,ff8a2fd2,fabfa0d9,8c8885fd,1b401f3,65f16026) +,S(ddff6468,11ce86d2,93b9b89f,865d7133,d7b5f189,d527cf44,5ed15efc,ad32b346,7260e994,cb22016b,e121ae08,12b01c3,4d236b67,13ea510d,b1aeda36,567f5737) +,S(a8b9ff3b,9120fa93,d0f2f50b,c8509846,c1030d98,dc9d5243,6ad9e69b,f897f029,5cbfa29a,4e516872,ea9a4c2c,a3b07efc,c866aaf6,a2b1d7b2,3597e332,8466c591) +,S(943077fb,177b9d6a,723c18ed,ac8deeb2,62875264,868eceb7,a2fc1a01,51dbcafd,219a9fc,41ad01c9,d3f8248d,ac7df93f,ccb6e312,fa5fd442,e48f4a95,18e7eb4e) +,S(75cb61ac,9c9817a,fdf60f52,4245ebbf,82b33f9f,a564d74e,9e810f36,6458b8e3,aa8135bd,f66f0843,460986f5,f9df6b9e,66441477,cd58cfb8,5b3adfde,ec03c367) +,S(1bb7e177,27cb8e85,4bc922b2,28e7f0ae,c34fdcf3,b9bad0c5,750e7c8,e31fccc8,bbf72886,1e855e70,bd9e322c,2425cdea,855ea00c,3e6263d5,2380da38,c0221ca3) +,S(9443384b,39e9dbf3,45b4b41c,f05d0f30,87f02471,c98e2a2e,afda94da,8bee8dbb,e3661173,ccb211f6,38cac6e2,27e3939f,e7b5da57,f6f7a504,abae01c8,fa4544ee) +,S(49bd15d5,a68caab2,8d51638a,ec1a9668,b4c27d54,d6691839,61ccea76,ef740d25,648fc868,8760e47d,fbfb9f0b,d995cc0f,77563b60,eacf3e57,9db7439f,3f18c6e4) +,S(d0c7b78e,92809e85,84d3684f,d078907e,c151aa78,a5832f90,73f945fd,7acfed85,a80d95ab,be494a40,b5529046,bc305203,be91e475,22ad9d57,7ab95b3,8e970c89) +,S(debddd46,3ab22232,5e98f9c7,5cdc875a,7c4c28d8,79748bf0,cd96bd7d,92eb9275,d103c8d,c3fffcb0,5ffb3dd7,a73af259,50d02064,b12bc754,ab594c71,ab9799c) +,S(1d79b17c,192a6a15,8ea2d6bf,9da07312,9f9ebcc8,54b02dc3,3f64012f,1bf33998,6ec818b3,dbc1c8a8,50d986f,bcf64702,c787682,bc408a12,b78e6bbd,4cf60a5e) +,S(2feb76eb,ff5d47e9,7289c38d,7d1535ff,74bd3b57,264c5844,9edfd36e,6e81ca1b,45bd4e4a,7ba3a823,dfae18cd,1f9cabc7,bb462e74,7899c899,378c33bb,89f93b74) +,S(14d0d90,faef5a77,f5372ab6,2e4f5efd,3eef1b39,498653c0,6372fe0b,b0682573,517f169a,80c2b930,4f530f51,d7196831,601a4f97,72ba1312,36ba92f6,36081453) +,S(7306a7a5,728f91c3,384bd9ad,b10b39b2,ad094137,46d2e476,fd522abf,ff313321,215e22ab,a5b9e87b,35bbd4e4,f492f1b1,574c85ed,25b86a85,a8e17b81,b7a915a2) +,S(85d8454f,870cdb8c,b32873a0,698fad20,fd24067a,737e9719,76d4d362,6a55aaba,36d63c0a,36eb9e8e,522a0715,cb9c833d,539fe7ee,111af3bb,951434b1,3117e4a2) +,S(c68f6782,993067aa,259b21cb,9e19122a,2f7da28,96d8cdff,c1f0a0e4,b34384c3,74e6e96a,331c3387,7ea484fb,995d6a3,8dcd493,6b2994ff,b7dc3681,3079e94a) +,S(81448111,5dbe5550,846d5c9c,3351c89c,e29cd850,6870a17f,e18e3184,4214dd3,75dd78b3,d4cdc29c,697740e9,2478689d,540ea33e,5edd6785,210abcb1,670d19a8) +,S(310b5b19,de24d478,f5f25993,a706f21f,24214e1b,cf614ebe,3e204815,60c945f5,8b42c6ca,f01d205,e09d017e,2e840d69,bf04cc53,f02a21a1,47e33327,104318c3) +,S(cf8a47c7,4bafe2b9,dfde4bca,b2e6d451,b0a90f11,c684f420,a025974c,bc4bc3e,f0b7b264,a9a78699,786331e6,2c8762be,614d8a69,c0a65c3d,1cc201bb,e34c97d1) +,S(a0fc6226,7352a904,e70100ec,63d3b60b,ab553388,69b982d3,3d747af9,8b8650fc,ba3ae54c,16b24eb4,64b88c39,521c399f,cd162eb3,f9966497,e2b96f2b,3b85865f) +,S(aae5dbe2,535edd47,584d0339,10045333,2e1eaf70,a4e1bfb0,7dce3c23,6cff8bdb,7cfaa5f6,e55806b7,bb278439,2473732e,a51d85c5,a3558321,91195533,b7a7449b) +,S(8a4e9311,5b897550,cbc0792f,b2705a18,5c317226,86da5bd5,b0a17bb,503ae39,1623adc8,d85f08c7,1751b976,daa17572,2442aed8,a9dc1692,2dde923f,d17cef2c) +,S(cbcef535,eca90b09,5295cd61,29010259,8627e1a0,ccbaff26,a51cdac6,87066463,651c2ffa,c2a2c99c,3fcafb9d,8c50e156,498fee17,3462fc25,9d87fb8d,6b212653) +,S(25971559,4d6a2bd0,baa90e33,62b9c841,bf12c4d,2ead6609,9902eac1,ed0f8c99,49e01b6c,c97404cb,8144002b,c33e8bb1,d974dd22,d0a26a82,94bad2bf,2875245e) +,S(b754d68b,2b049f6b,ac389044,c80f0364,a707da5e,3e9b2a89,1672cd29,b6f1445f,1b29b7c1,625e23d1,67092e3e,ddfc2f4e,bea55542,5f4ddda1,af2aec5e,4de37740) +,S(20aea5a8,50e68f39,cc7ca2fe,2f38b5a2,ab0bde8b,d294c40a,afa898ff,4f084037,6ed576b3,f17666ec,6aafd6a5,6fe7e1b2,ab1e883c,31230fc2,b4e1df0,3f59444) +,S(26844e02,919de923,3288cba9,a97eb85a,c6939fd0,7cd01e7b,f0d5e1db,e31979a6,3df9a8e,6a5fad1,266f11e,518fb60c,cc08a6c2,832c45a1,6c7c5520,5c9ebfb7) +,S(11afca61,33a69aaf,27cfd413,becdf9b4,efbe0a6b,1a38b3fd,485dca95,dc28414c,8d4b8790,c0677fe6,22847bbf,8e47b400,9e4678fb,b9c9377b,2121f5ac,db737b1c) +,S(c46e14d5,2fe25d65,37bbe09f,ce7e95e0,4986337b,23e7160d,f3d78dee,e8d2a63d,a200fdab,4211e9ff,2d008dd7,7ddf67a5,1f04b9ef,43fa1758,9b175d58,f5d2b723) +,S(570aa12,578afe09,245f598a,210a7605,2412283c,8f58e142,d31d9cd8,d455e4d7,c28fdb61,f8e90de1,d43439e0,8512a071,9a2beda9,5d0a5601,b932c0f1,2cc50ac8) +,S(d312db5e,88a1cea0,28570b84,e3854e16,224236ac,cfb14d1f,3a33108d,fbc3fa64,ca5e5089,1843383c,845fa0aa,e031c930,64b8aa4a,ea72e6cf,36b617f6,cf97e1de) +,S(1ee22876,9981670e,14da9ad9,9279f001,c9be5eb8,76224a6d,1fe4ec08,aa398087,62101114,e303e37a,dfe42c65,54460d4,b68603a2,580c7452,6ff31c9f,2176dcc) +,S(1fb9cacd,e2b84ff4,ae85511d,1c964c01,1700b9d7,2d4c04a9,4afa9aa5,57bb81a0,430b73c1,295c5f2a,d6d9f59f,74201435,15b1306b,2cfa038e,e0456752,5f737fcb) +,S(d04cc82d,d3cf0b47,69f2934a,9807e743,4a998bb9,fa44d145,f191a176,611c085b,7a4a19af,b551d151,c42cf1ca,ce123dd5,8f4c13ac,c865b92d,15520169,1be5fa9) +,S(1e4cb208,8bd4d17e,ba8b97f1,f27df5df,8a544f8a,548dde15,712e8704,cfe7e9aa,d805c61e,b72933ec,e799930a,53fda3f3,db066396,5c71be51,5e8466cd,a59b828d) +,S(520aa398,707a85a0,d672bbad,cbcfdab8,8f769f69,df3de8c7,17d6dc48,de51590d,98d344e4,a9047a22,c09095e2,f1176aad,3b54724d,998e052a,39a52554,4ee9ada8) +,S(3a9fe3de,165bef7c,2e0d45a0,60693fc8,e7080ac9,783245d7,a79cac6e,7b614ef2,5189446,fd3fdeef,c7a895f5,2934c888,7607ff49,aa6d798e,151061ef,73038d4a) +,S(9c929dcc,c26c0805,e4289a3a,2b6d68c9,8e3c6806,43730056,65fd8e73,da149938,6dfbf940,b4c29209,3f39f6ba,b102762a,c81edf2d,aabe6dd9,56aa140d,396ba2fa) +,S(355b60ce,f4e00651,8baf1e42,e5e7a08b,ee22abab,c69aca66,d117748,89be419e,7f478a3b,b277fb10,5fe0eaaa,cb53fb73,4fc01dae,bb44f1b1,ed146f43,fc2604e2) +,S(76bff14f,21ad4442,e1389bb1,c11e1019,ea966091,97439705,dfce7bf3,d7f7f37f,3855a291,376aab12,b5f4da79,bc22e02e,a29a34f8,9223f07b,93f6a549,8289d763) +,S(91bb9cdf,10577a3b,7e23aadd,35883396,becbb4bf,fa22e1db,fa08f8b6,6156b454,ec6cbb9e,4f149b02,edc53e93,d1611b5c,a3edea42,c2ca9a1e,f2cccf25,94edbb91) +,S(9e56b10f,1ba86c61,36481204,f0c45b09,a7dde7d,4eb32537,f8c310a5,a8865562,cdf3453d,8552c16c,48bca1a3,79ee8c6a,8b523eaf,d1862d5,16f4361d,5a8aa67c) +,S(4e73594d,af286bde,4e6e28a4,23930571,a11dcb75,4e9a4af5,f4972d,988e09f9,a59f23d0,70c042ce,e03d812c,ea274035,af0d8e53,828a418,cd1b51f1,458a36e7) +,S(156fdff7,e92d89fa,691d3c55,7cb2c614,393d5973,4b11bb1,d9fac953,3923d860,4e929637,c448760c,ef6d68f6,4665023c,bff653cd,23132ee,620eb013,a13b360b) +,S(f2c8b650,eb372336,5d57a905,23d34db9,70d23d52,1f893569,98b0a7e7,ae8ea03b,bd9ac314,84a99bf6,973422a5,60bde9ec,204488c7,6739583d,72f42a87,181a7881) +,S(27dd3657,a4a37430,5f5bb92b,a7b816ba,88d526a2,1ae316c,d4a4e67a,c751e3e3,880cfdd3,c0faa401,6afaf3d5,1fe975e4,8a756b01,f7d84e8c,226424b,83be3304) +,S(f6c25e0c,19f7357c,3cc5d98,1cc4b7f3,7a390182,c2673708,1c64f163,ebb3d1bc,8c80b3ea,7c05a0fa,39944d66,643b3589,29534152,adf37c2f,183e7c22,8e89e43d) +,S(c678800c,71305ea1,ea2847d3,d9d37612,ae280305,716fdf45,87ac7f4,a7fad4f2,be5ffbf4,d2fb2b8c,ddb49a42,ebeaf5d8,55d41d39,f106e2d9,2d549e88,6c0b63c6) +,S(f35db221,e66b7786,fc9e2d3a,68f0d1ee,f98177df,a05bfd30,931912e8,13f6d560,4899a808,e6b2040,89974ca5,afe5b1ee,9eccb15,36a7c7c7,bb67cc00,e43f29fa) +,S(2b93e37d,a915633e,db9843d6,c33888c3,5d944f04,c4074deb,d021c639,93e69de9,eb3d1095,c6ffa1cc,93f72a58,f1320efc,366a4a5f,c7250167,6f2d3c88,4b0522f0) +,S(818023b3,90454716,f51913ab,fdb406f,e4875b94,8b14a331,60901d1,66091b69,b3f5718a,6224e447,c5af3e1,f38e4f2e,6fe57389,fa7d8990,f98e44c2,a227e7b1) +,S(1676e6a,244ca69d,b2ae565b,65b14184,6645ce7b,213dc1fb,db33f060,3c662bb6,88e1cba5,deef5dc1,26b20830,d2c7c0d,aeb9689b,16ecc1fd,cf4a31fb,822e0298) +,S(2f931a1,a92537de,38629d73,323e2f21,d9657454,30e32e4c,3912cb21,dc298d54,93292d08,6fbc0fae,eef6fe43,f5626711,95a5b2d1,bdbbccc,52e1dfae,a30ef904) +,S(7ba4d612,f0dd8c91,8bff20d9,b4f45486,be8a32c1,122601af,2d1730c8,a1fd0279,8aad7aa1,f5b06431,b2e20af1,4cd049a9,3018e3c5,bc4c4310,d0234e78,d2401179) +,S(e8dfab0,85fe7a91,6a79b2be,723799eb,d6974d08,ccc8e3d8,5286aa61,c81d5e78,2121686e,519db556,e6595d47,a5487bb8,fbaec53b,b18dd81c,37dbab40,6e3f926c) +,S(7d5623bc,b1597ef4,6f907106,17eb2e6a,ea751da1,5535a64c,94c90c9a,d84ab5e,dc639f31,8004c4de,31514b70,ebe2e8b8,701b3cd4,5d66b7e4,204dcbc2,a0ce7575) +,S(8e81e2d,8074bec7,48986194,b3b82200,1e4ac916,81de2ad5,7b9c84fb,88a7ffa3,4085ec1d,f4a34480,ca56f6cf,762d03f7,fa94e99a,8df93e6c,dc781499,59fa890) +,S(a9d5a3e7,8290ee62,5e18affd,169c6829,73e68ac9,2b5cc52b,53ed3a85,a68da71e,1cdaad6b,f9eb5889,5189ed29,8793388a,8d6e8b20,ce47a536,ee89be4a,b4805fd6) +,S(4f7c17ca,bcda7c0e,3b7b313,4312f848,984985f0,e46ac497,d64b123c,57dba2cd,860bedd9,5f470c3b,f3cbe7c1,d5070cd0,c877010a,9baa8f5e,888b5ca8,a34a25d7) +,S(478f3d7a,9234a7b9,a91bd016,f55734e9,34b8c3c,535725b5,b4fbb0ab,9fa64921,db97a394,f0253f18,ebabca05,c21e9a7c,3f253054,d83f2101,8ffb4d93,b8051a1f) +,S(ace7e57b,73d96e7d,69f7cc01,b1da179f,3ea09aab,61fba329,f2552eb1,fe7963d5,fa0251f2,2b8dbd04,ec90f824,be025965,7e213e4c,1030611b,796efb89,26908918) +,S(cd56e867,f5170771,8253757c,dcdf69ef,4401f2f8,a1d09f24,374040e7,a908d1fd,878f7216,52cf0ba4,8a2b29a2,2f620c7d,83e4bd84,277b7b90,a454bba2,7f338fe1) +,S(3042ea5c,d9d2f89a,64b1dd24,97b25da5,67a2c672,ba067e33,e923e513,ee4d5329,b84c144,d5516a14,a0a8568c,d6d227a2,d3fa1d86,8e05e612,81ce41b3,5a68b1fb) +,S(55e088d,a094ed26,82b042,bafa0345,30a2e291,57af3f1b,ce351ec9,9e712ec0,c6f8297f,64398324,96091933,514c5449,cacadf,82d51db2,82c9d2e,c66b33e9) +,S(bd2db13a,69dd93bc,a37f9181,7a57a0e9,e0e0da83,eed71875,e63b4691,3b408966,46e12660,f9489b2f,123c25d5,f65b3f8,187ee6e4,405b8cf8,78a742a,9b0da2d) +,S(7d7a5110,cdbb8455,5fe678e6,24ed1a14,ef7c5219,986a7ecb,6095624e,7fd3d210,c9578dc3,c0a54524,f819d640,abaa4a04,626a46da,15c0867,72774a59,6ac6c37c) +,S(1ef12317,513b1354,2a966981,34edabc6,fd4e6d29,1bd7782,5bdb30f4,937a3fa7,e0e4b688,a391bcef,3451cee3,36a8c9f9,12319899,4684c039,909489db,590e1ade) +,S(effa0403,766fb976,dbec6b2e,332d2f12,9f463b86,8b9a1d19,49d30cea,1606baaf,8c5b1c83,bf3efa64,f38de1b7,da03de17,b0cbfdc4,5b4a03c2,38221def,bc1cb082) +,S(dc9271e9,76a9a042,5565f022,273af5bf,20bf780d,9d0ea069,df5da661,a087d65c,dc8679e7,b27bd30c,986f11bb,1c73b76c,55ce7c7c,621490c1,944cd8a6,b63d6063) +,S(ae1ddc2,1e1ca02c,218f6946,275501d6,a1336b93,ddb1b2,384ab414,b8264619,21c6b39d,300b6125,ec8e5c8e,19aa76d7,32466bc9,a887c76a,1ff4220,7db26b48) +,S(aea2c00f,fe5835c9,2b892480,83164635,33dd989,bf2bca12,85cce3ab,4e82cf5b,615598cf,935a6112,42a20e84,e670b193,9aad65d4,53ba967,3e8193b2,93dfa97f) +,S(913d0e16,34b43a86,f55b30b6,5914767d,b45e723e,636c866b,6348c8be,8aebf696,e14c6607,51affda4,d02574af,43172024,39c0c10e,148d4305,1487a5c4,39971a9f) +,S(4f0b3354,775cac80,5e0d6191,6bb0f9c8,40fc163d,8878c05a,301252d2,3bc26fc0,b0b75486,3aedfdf8,3a6eb2eb,5f3e25f1,6c0e1077,6e855ac3,fa8fc3f3,bd8da1e3) +,S(5da21940,73cc978f,7673b2f7,5c65ead2,f469df96,f80883b,181a3da4,f316129d,8516d080,743d2670,570d5e63,e19eb543,237b1db,6285b1ea,f3bc1459,8ef311d1) +,S(76e1b330,ca7af91a,ccb92fb4,63404d36,a8fbc132,269d163d,d4beeed1,6be74a23,10b39253,c5908ef3,ec96f2e5,2ffa0dec,2ce2800,31a791,bcaae0de,1e7f5326) +,S(c4be488b,2f210ee1,82f91263,78b23359,8fe8ef57,671ddbe1,d76975d0,ee393e64,bec1392f,a1a09a54,480beadc,b98ca024,b910cd70,f807eaee,10d4e270,bb79f449) +,S(546918d,a141fd77,b1f13848,d3d608c0,25f5be00,4d36a542,56d0ca5c,9333ff37,3d1d4c7,9684be1a,5cf00d71,6cf9a1bf,b0b82ba4,833704dc,c2d23e8f,39914ac7) +,S(cdfc6fc4,2c51ebd1,2df368b0,98ff0f40,2e6df8b1,9c67e10a,320c1960,266078de,5985e930,23e5264,547bef45,6b3774f3,c2689411,b6f7463c,febe068,fd89cb0d) +,S(7730fccc,593b14a0,6f21eec6,2408e146,36f0e4b,4718ce99,c99bbcd4,7cf03034,f17d0fe2,736e412,9c30151b,492aa7dd,52beacb7,6f97001c,cc28f991,3e016b72) +,S(8aa4c3de,474308f4,674c7b55,9f895bc5,d855a7a9,5fadf090,5726b354,7941b3ea,f275c44a,eac2623,1bf4ae9a,df403ed2,78d9da42,150c98be,7dbd5f71,5cb8594d) +,S(15926da4,97a4e925,8976f87f,f8940491,f32d33dd,7855b13c,5cb54d10,d325bb79,15ac60b6,5b1ebfa8,e871bf67,ec9f71b8,1aa03c78,82880d40,d35f16d8,67ce8e51) +,S(55f4f4fe,aa741574,79462b48,f001688e,fc99f545,d4566dbb,35faeebd,f5b1710d,80ecea05,63f24c84,e767b894,57dfec3f,d015a4ad,b6e3fe0f,662521b4,bb02d15f) +,S(95a56acf,402f7f33,fa357c4a,e4db337e,f04a60d7,4cd73e0d,b137f68,e0e93cee,e72405bf,b7c9ba84,16f4e72c,a30c9ae5,d21c89e3,ce5b61a4,bd521b4e,ef6501fd) +,S(28a9fd90,b50d7bb5,13034b7b,c36a9783,c2a697ff,499bcd6,4b0881ab,8e7a2aac,76b151b0,5c7e7ea4,9a263596,81508781,a37cfaf5,14fa1720,b583faa3,9794a788) +,S(6406dd13,6d6462c4,a4116b93,eac38eb0,b571e2d3,99cdb93c,b36fa5ef,e734b672,3974c77b,92b8e614,52d9c9d0,62a911f9,b4c5eb1a,977da74f,defea358,5dd7fd1e) +,S(8fd8f23f,cb62e1c0,94fef903,9933747e,9d40c37e,376703c2,e3c8b666,f1066529,8b0b2f9b,de10175b,24a9099d,75926296,5ba19013,20912baf,3100e057,d4ab5c8) +,S(51780a2b,d4457368,9c0679bd,c8c94e43,cc525bab,2d2723cc,3e0eec15,63a1a24b,5026cd9b,e178d1e,c746e5db,29391c4d,4b6b08a3,3530fdfc,64603fa2,f0e01109) +,S(aa01493a,e7c7f9bf,3d2fe0e5,cd939dca,5b8c8534,6848d065,beeb42a9,8c283561,a08f0b45,4a42b5e3,6463af14,5199e3d2,1783e908,b3e130f0,e9e88110,2cda82d9) +,S(cd8ab749,d4bbe6d4,ac81c4fa,d6a27e81,e4456d4,196cdafb,97fa6053,18ceab70,fc6c7739,bd68a20d,e01c9249,3cd7ad3d,ca862183,b0529231,da32f1b8,5df59beb) +,S(e69cdef2,e824501e,7a17bc54,e0bb4886,379f56e1,c59a27ea,e00bec5c,55fe3e32,e80ed10,40375398,10125338,f6291791,3fe735e6,6c4bbc80,f41d858d,8ac41cd4) +,S(5a4e72d9,182b1f7e,efb08af1,9e3181cc,f6b6ec69,790184a2,f30188e0,dbff8a8d,2d1cf7f2,d5a857d8,3b31c588,5ac33a5d,7b62ea62,7b5b0bee,2d912502,2df9da19) +,S(9e000859,48bd6211,410416b0,3920a79e,d78f154,5dd0330a,8f23d1b5,f8984a2b,36ae0492,412fd3c,c230680c,edb0dfc8,151ab85a,d8d3338,db611674,c88e3f62) +,S(7e0b97ae,b12f8734,ecad35d4,aea425c7,99f88485,f0bc8d18,ac82f213,258bc6ff,e76f4e24,a4be1b6a,3fc3b0b8,ab0b6e5c,ab95fb40,4692f7bc,cc7640b5,69f3946e) +,S(62285cfb,1bdfc495,dca81ff2,867878fa,b3064be5,81be0c86,b9336c6,61038ee2,f2c91be4,5f60e9f3,40e85ea0,8f159dd4,a65ca8d8,21a6e4f7,71f4dc17,849b5161) +,S(70234e81,2de1b5cd,699870ef,36d5c19c,cd3765ba,eef3cac8,6f126a,a6c82623,e2dbf98a,f92a777,263f3c92,4738ba,3140f769,fd5b6ec,7139bb8,41330736) +,S(ae770461,8f31d5cd,ede40ef5,7434b0a7,7dc1b4e6,7f4be5e6,136978a7,cd5db07d,a4e25164,65584487,3f520e42,74037c,5cc43e12,95167b01,d46d3e93,d93d16e6) +,S(cec7ac8f,e4db698b,48ab78fb,768e6094,5b7f4ce7,d643e604,9e349b6f,246f2b53,491bb545,99330685,433bfd2a,7a4fc831,7f5d3cf4,80d6bc32,5ca6d001,b65fadfb) +,S(80276e96,b051e49f,276f62e8,35622979,852e4cf,c2ff8665,8db4d5c7,7c5eee36,f510d696,882589f0,870d526e,5f7513a4,2c4d4ce5,3733f30c,f06d7dc4,f42f6d9d) +,S(b19027d4,9d85faae,e6163934,ef8f8508,e9e351c9,82bda741,b8944317,da85b27d,c12461cb,dec0e69c,b378443a,f2eb042e,8439f812,205742d6,dbabb372,ea47a824) +,S(57599d4a,cf07c001,d3d3fc78,aae147f1,989c656f,fbc43081,29e05b2e,570c792c,5cf8ea0f,d215ba16,e18e181b,1b4b4f02,38b57af3,9010ba23,f13bbdc4,18514b0) +,S(5ab76283,fa110b82,c53cda2b,653e763c,306e6f8c,2b07d490,bad6e418,eae6e4b7,ff365643,cc2a78e3,17a7de95,b37b3f83,aebe8272,4162a884,f7437aba,b55e8ea0) +,S(7b93d9e4,8602d7b7,ea52dd45,fa0031de,66ea88e4,4250c898,64903e7f,959d4a85,99ccb201,5ab91fe9,a0f50a0,fefad6c3,f6dd060,1f2ad099,a4851d33,162b52f0) +,S(2d5878b6,af642776,41101be7,2b37b4b9,1de26a21,b9610a93,7ee2ce2,fb96ebb6,138ee05d,df4b004e,820815d9,46716f2c,a887066b,b7d218f5,47d4bd7c,2cfc585a) +,S(1d637068,eebc32da,24a0fce,2e41cb57,cf1ccff5,38cfbee7,ac13269c,e560af3b,6a932df1,a2896445,6685ce54,2ddca0ae,d589a494,b7ee89ed,1b4ccfd2,c276eadb) +,S(82babb6b,460e1235,f3187a68,912b057,26a478ef,fe929a3,9479cf04,467de64c,3a9f4e33,603d0396,1f3c11c,94d58369,5de43a1a,327d0faf,f51089e1,1345647f) +,S(ae86e71d,4e715bfd,b63d899a,9daae610,a01c5134,c1b9262,c276dcaa,b48090a,3564b48b,fcae8f7b,feac4df9,3b458678,6f2f9e83,9c9c6126,a301de29,4cfd7b5e) +,S(35a5c2fb,fc661cc3,f4ad6ad7,f1eb32b6,664c50bc,91f4000e,f5774364,2aa413e8,4a5029a2,887f6648,3e072782,68a81c85,b901d692,4ccae752,7111bcce,cad6cde5) +,S(386bf07f,4dd508a7,61e7c29a,dd251d9a,76324496,6c6d760e,cbc6b069,5858e2dc,d4f14804,9c1fa038,1d903e19,68fb14b2,f07c621,15a81f41,e811ad87,de407696) +,S(dfec381c,9bd6f4cc,50ac445e,c9104d87,f9c46c7c,cbd70909,fabde6aa,12346f96,5e7344f8,25b6649b,df97ef3c,ad96945b,d1ce0f76,a48b7f2e,56ccff02,797553f1) +,S(3606dcc6,4db04cc,5493e0b7,ea0bfc2,f8a24302,d2358aaa,7c1ea8,842abbb2,a5c8743b,bc4d9b74,b8b569a1,feca3667,87eea8b1,be2025ed,bb547e78,5687301d) +,S(3441e737,e19096e2,9a3025a4,71d192a0,db086038,8e76d2b6,66052825,e52b0016,6d10f7e,d5cac98e,73c3ad47,bb233a39,5eb9bd4a,37861b9e,7dbb60f7,81eef0da) +,S(b2c97c2e,460d8c34,b5ea7a5c,456a9cf5,b1d902bf,5cdff030,25410a,26636e99,67133081,a8c8ef30,753417b3,cf6973e2,1f151e1f,27216bfa,23289ea3,e2057b7c) +,S(2740bd8b,59a43ddc,f8ffdabe,d59027b5,9b7932b7,3db45a97,3b6c1501,57e045fd,8106f2b1,f69f1ad4,2c0787a6,3c137753,987aabe4,b0ebd82e,1ea7807e,93b02a85) +,S(a1acffd9,bdbd94c0,cd8b4f40,3f9400c,aaa8e269,d8cc49a6,9ee565e1,89b6c21b,62ec7d7e,733f518,974acfbd,4f4e4f44,bcc4fdc0,cc194a66,df7c16bf,ef0235b) +,S(50bb2ad6,8d524acc,3278c0f1,538d3aad,9a5357bd,332d8cff,6301f417,57349847,d8fc33d5,d03526bd,b97d4c6e,1ef018ba,ba4b33e5,9677f139,b8535287,fbacfb32) +,S(ebdfb262,6031b4fa,d675e860,12288101,948e2ca0,8fd0d32e,c9fd0838,5f4fdbd9,b078066c,c470113d,db3964e4,466e319b,4f853a42,8951aa0a,9c4629a7,a40dbf2e) +,S(5daf4c23,65482a2f,bdef73e8,208fd5ad,d57b35f8,171541f6,3a48b742,e98bd48f,9015bfcb,5a248607,f5ffc83c,4fa3dfec,9cbd11f2,c230327d,b2cc75ca,2e87f967) +,S(22db9c20,5d840814,67a19517,f353f825,238c905f,2b12a77d,8551cc9,ee8533c7,680a1bc8,23432a28,a3219264,2b9acf0e,7ad19e29,b604631c,85f7038b,386dcdf8) +,S(404435d1,2e8be51,92625213,f86e6e55,9fb44658,44694d4f,4db72861,d4c100ae,9ebce682,b321eefa,e8e04776,8f82491a,dd734e5a,941e0f4c,b6284f78,6d1586d1) +,S(dcc36eff,6831a6de,f8600d1a,3d52da1c,fe59df9c,cc69c9f2,60c26532,e837530f,8609b5e6,7360b7e8,5ea98c13,578566cb,b6b385ff,6990d4d6,5b795acc,1f77a893) +,S(ef0dfb94,1a1c383e,4a44cd04,c633cb48,e991d140,45e2d9a8,b4353e79,9c1a1514,2685d60,f2a75f9a,b733afab,f693ed05,9c3599bc,3e3346d4,61e5c86a,f76f6f42) +,S(24884cfd,c6c3efd6,b4d2e18f,2ca66b06,410b0fba,d9d61b30,86abc537,1d766b8a,7c1cdc85,66f3daa7,d395c6bf,8a23c130,86a78619,aa68519e,4657b17d,ace2267d) +,S(541b6691,c7004a81,2c607756,f81b6f05,485b0708,678d9a45,de74632,4acd8b20,ddccf301,8a3c429a,c749f0d5,2383784,cefff3df,ae98517f,c7f5e764,c5c609d7) +,S(5462969,67262e3f,a905eea4,ff1f8296,f792cfc8,bb9dbb9a,138242c1,a1fa822d,63012289,8e429527,4fad8e7f,9865659f,da2d7370,10f6e185,70dadbfe,21e6880e) +,S(94070912,ad2c129d,cd122bb9,704616fc,3ddfd949,6ce9f6d,6e18020c,ec848e83,9c3b38e5,6bfac9f1,4c901080,b5a732a4,b5d261f8,2b571536,d1fba6d9,b714017b) +,S(2a6330e4,8ddc661e,afa8071c,c1417b92,ea73b060,3653a017,3edb92a5,6e3ca6c9,b38c51cd,4754c350,ba2d56a3,fbf4fbab,5802bc38,6b5516f3,d8b761e3,c3fc7d79) +,S(9142e493,5f95da17,5ae4078c,5ff5a7d4,8c418c1c,7efc4c39,dacb047a,d3f7424d,15165a74,c47133a9,e8684ea5,5a4f9b05,37d0ab7f,58a7eac0,e698adcc,b885cd05) +,S(2e198b29,5cac4dee,dba63ef3,888d47e8,bb8d372,7fcbd69a,d1eea656,ca85804d,31dd5db3,e700ffbe,152b0c2b,1b1c830c,eb382468,1c522e63,676b9ec,6780fd52) +,S(b44e35e9,b2efcafa,f123e52a,7bd9bc58,32a671e2,fbf0264e,5a3f536c,b272f72d,8d489fe3,beb39fd4,2632b80a,1243e64b,f80c81c1,3934ab08,71c16a5a,5aa43423) +,S(dc99ad01,e1324b6d,b5ecf365,c22463dc,f609f0b5,90e6d3be,efddf641,b83a3cd7,b4b422ca,2feabeaf,32c0ad6a,4393c087,a4c1e794,47a043de,cf0fe486,ed11b682) +,S(e174838e,eb991c2d,cfaaf89b,b868f4d1,3029ebfc,ea286376,48fc51ba,f962a359,f80dcc87,27cbddc9,4bb1b60a,4da5cc74,238dc62,821a9ec7,c05ad2a,a0e7570b) +,S(6240358b,15bd16d4,42cd79a4,8b739eb5,4ca21d18,b568b497,65d10dfa,a2583d33,6acb054d,724e7550,ed6d8caa,8a436d51,fc546116,df33413f,a613c0dd,6cec2d00) +,S(a757fceb,560aac0f,543a29b4,bfd3af7a,aa61c077,2c1c07b2,e6268342,e63f8d70,5864ceef,f80855d0,fb4713e2,7bc6a202,b4c07450,6749457b,39d0c40c,f40352da) +,S(f36e1073,57c3149d,902e9416,2e509d19,d4b1f498,bc74814,3a1bd411,2f777bba,d4d7da2d,139a2693,e40d9396,76c3fe48,45f74b43,78f0c25a,14aa9698,3bd1993e) +,S(84ef2d4b,55a40ff7,13934949,b6277ef0,4a8e0e4f,cc49420b,17269d59,224af99a,57affcb7,1d3508f,65ff2b7a,b1d6752,60465e76,754efe3e,80a83085,85ea73a6) +,S(138ef64b,274ff66d,7defdca3,4ff28bae,96b046df,408b3f47,84f78784,3fce7576,ebdd04e5,1d517c43,412010cb,d03252ed,dfe97912,ee4a7d4c,ed98551b,fee1ecf1) +,S(e82f03fe,2ba05692,212a1145,550d3057,2d454728,e2d9989b,435cb608,3d1f318c,191a6fb9,cf295881,92aaaf1f,ea34e123,613b2937,602650f2,eb25f63f,5812dcda) +,S(56a68400,676b6fac,7eb5fb3e,7f345ec0,11117098,c0d1a96b,e44bd2c8,5aafb317,3a41827a,5ae1b7cc,5b9dcb5f,4c41819e,f49ff2fc,ce1d1949,3f5b0ce,9f1dfb4e) +,S(82f5747f,1b353db4,f3afe255,e1f2660a,8f735b1a,e40a5008,4efa3c32,dc1309f5,42e8b903,f4ccc01f,7e87e4c6,71572bbf,d05f9ea2,a4cf7bd7,dd5a9906,264a0144) +,S(89136941,c47b1964,a4b89e0c,376b3136,80ef76c1,19e02bb,bfad594,76e0cf13,b3a2a785,fb6a564f,f4871bc5,177c635,d722e659,77f621a,f6f7537a,2c2d3f3b) +,S(c6250969,c98f580,f0cb51,eef5d8a1,b9954bb,97671df1,c7360a5f,42238909,83d0324c,915eab22,4dd3f935,e197e0e9,552d5bd9,6b1ed240,219731a3,58ec724) +,S(e2399ad9,63913200,4664a481,dea99d85,ad12938d,dd0e4184,27411fd4,8fc7e3b4,60fffd62,beae28e2,2ea836ed,389c3780,5d8b1fa1,fb10f298,f9b54df8,93c69d47) +,S(4d00b1c,186d2992,9a6383d6,cc8d1796,a59c5d7,c27cc7b8,5a1f821c,3003d959,8752ead1,27eb19fd,49dc8ce7,a0b7c7e6,dd4aa3dd,6f8d5cb4,687327e8,ce487640) +,S(344663ef,8b8b52c9,1aa548e9,8b7e1c48,933cbfa3,59644318,5ea973ae,9264121e,73d099c8,9dfe8eec,b957e624,bea5673,6fe3885c,e2f72b06,dfeae760,514d9efd) +,S(37ff484d,dbd22a98,333038d4,7949b4f3,f411d3d5,7ca319e3,5c788bbd,a0de6648,55a5394b,51618d81,d2fb1455,4ec1f5c3,a45cf086,83980bfb,a9aae6a9,20547c67) +,S(cf3bcddb,ad5066b,909339d1,4cc6d3d8,d2881f70,d6f12e1,4d795b06,17556ca5,e12686bc,99e20f20,6220e402,32760224,b61b90f7,8b7c0b1,3c197a47,11678a6f) +,S(961d02e7,db8fd1ac,a38f9110,13d74a5b,d35e47a1,49818d41,49f02edf,5da73402,9462eaac,d698677c,16515ca3,bff217e9,765dc8ad,fe2fa82a,1db05158,71fed240) +,S(43e62f90,574a8e65,25d22ca6,74814ac,3648b724,45a535c,5e1af97e,b46ec3ba,6def0a56,17c1cf17,9369e20e,d18d0503,e141dc85,9edc73a3,18f6a35b,3d939734) +,S(9e682b79,9d79018c,352113cf,98de93b2,457e4b4,a962d160,33b80052,57dfdbb7,9db9cb16,bfe96343,89c468a0,6405d2c9,b2983354,ee9a81e9,3f23ec5d,5049041b) +,S(790187a7,8079b59d,b2a22d13,8520192,5f9682e4,2002c8f9,436876e4,d5a1a8b4,25c8b46,f6b43180,3654381e,56a8e6aa,ade0ad1d,6a6044de,17e9592c,affa456e) +,S(928a4b8a,6c744b33,99e22d65,35a21ffd,662a0dc3,d5bab1d,683ce555,f0169583,251fee84,c064954b,e1daf7e4,5fec87a9,323d55f6,687fdeaa,75d4dcc9,9a6fcf84) +,S(684e88da,81182f2c,ac5872de,8c98b86f,a6ffb73e,9bbfbfde,6c16c3f4,be084c88,c451b59d,fc9d62d5,921ae45f,f7557ab3,ad179eb0,6afb8bb6,bff0645,cf6383fe) +,S(8bdd2e83,a403b0cd,7a8ebfa8,6949bceb,8e8166ce,a8596f6c,ad7b7bfa,4d174343,7220c147,97f682f8,7d707b2f,eec937c3,643bb359,e9effbad,8ccbc8f,a8177172) +,S(c3fa3b21,6e3c4952,85258ef5,f921f6b,b7195869,e46948b4,b69e80b0,be399543,eb2044ed,21f6661b,77088050,3026c2c5,5a519ca1,748bb10f,c8eed953,aec1796) +,S(1c063c13,eb2d2959,379fb0df,50d355e0,195a8bd2,e642ab48,3d6a38a7,af7e63a2,20538f92,d14c9ff6,75c5005c,8c40e26a,b0042874,7f446ed7,cfcf5737,870f2abb) +,S(60c06797,7b54c18f,4b82dc6c,227cb539,6c6086de,107e3999,81f1b5e0,f31d452,3f4546c4,e3eb11b2,e6fd2617,b57afafe,ce0e8bf7,aacc13b,73755f18,dc98429a) +,S(fc15cf99,92256abb,cf263e90,a231ed8b,421cdc2b,af185722,c0af008b,fea36856,abe346a4,d9c40853,70dd46e4,69a3bf24,c01dbd97,f5c9997e,27634dd7,c635d798) +,S(f6143985,18173bb7,428da262,bc8b07b8,1a92b06a,65926ee5,c6f8fe44,27249454,b1d832ef,3a2558c2,d41f06d,4be8e5e8,11fcede9,9cc784aa,b9f3ce18,d701cf84) +,S(579458a9,62218442,41e68542,76a116ab,1f1fd43,109d4bc7,ad5216dc,ee61b5f5,33e56474,68c157c6,15cc8d46,135bed70,21274a4d,97aebe23,7bdd4b61,2c53e2d8) +,S(637553dc,b0804132,b5562678,fe355e8f,abab2001,fe17e3bd,8c051e7a,41fe62e7,28bd6dc2,ad586e1f,f1a6a951,167ba14f,6989b296,874e0d3c,31917920,9b572dce) +,S(eebbd70f,6f64855b,e21ddb92,3e54f583,89e99ddb,577fa8ea,66c3722e,b580e2a3,3d1b6979,15b50345,4a55606e,ad3ac4ec,7c986698,3df60e1d,edc86827,32fd4d68) +,S(4ec8931f,2bf4b1da,6891135f,37791236,3a6e888b,6e5c5ddb,2e350e42,686c56fb,d5f6c679,4c2b306a,bd719770,48dc3e28,3cbab910,556919f5,35d9df23,56a09bc7) +,S(6b5a7f76,fc5b7e7a,7d84deab,ffd5c771,8f49375c,cc4dc1a7,35bc253a,bee9730e,1e935dc4,8fbf5f6a,b12562df,11855757,9eafb8ab,f6ad8b7a,f8f9df64,43b58af8) +,S(2a3129eb,f620958a,4264c759,17e29807,5f5b73f3,21d4cf27,683e4788,9e013af7,e940f5e4,c1fc28b3,fa346ede,fdb8ac7d,4066732f,a6c276c6,89a1921f,d1020da4) +,S(8bfe81c,e99443f3,78307f34,5bf2c826,94a8723b,c4836d12,4c6f5163,bb28b5ab,58b16e27,857e5faf,9768edc2,68d177a4,87de9848,52e65348,36464ac3,f0433c71) +,S(47820cd9,449c566d,2d39daf3,ee4d356d,5423692,a050cf83,1c1337bd,8ad61be3,48dfae03,2988a810,6d069d,22f27445,1200d38c,a9aea665,5e5f28cc,9952c2e4) +,S(2d7f03ce,8e453605,89d221d8,84c3ef28,f9e8dc52,41d7d131,cd6e9921,55a934e2,8414b3c0,5a39f38e,1f14d55f,e28604f9,16a7b272,6d6c843a,57a2b8e8,b7ee9c72) +,S(83887cec,919d8c86,c2150d4e,e842505b,f5a5b06c,b3b1e67f,1dc2005e,99d8e37b,fee0e7cd,f5c9eae2,78d34fe1,2e58845f,fcea9de7,f9883e32,7a2ee941,92b4c009) +,S(519f9e1,138bbab2,da8c03f,565c3fe0,a9d0b709,1a7b50f3,f37df191,d1ca1e24,64d6bafe,2bffce42,3f631ec0,781e96f5,ef6cd6a9,ade6b9eb,367c036a,1a61ba9e) +,S(8091f78f,84bc74ea,69ade208,72936152,3946ffe6,63edee6c,3cd13ad9,4a8fba61,1aaaa58b,af84688c,1cba5d90,d700aaac,6765faec,39e7a212,fe13a9cc,b0bda1a) +,S(50abc00d,d3fe5748,7c2a5343,4a36f10d,8388cf20,56cd5bb4,9ed8e97e,7adb3afc,ab8bad95,14b6040f,b1c64f01,d9b9db01,670fe0d9,3add5d6,8a80e41d,8ded25ea) +,S(a9a428bb,4da01f44,a9e4f253,3436ae75,20e5722e,6d12931f,aa20772b,36a2f110,ba05121a,1830a26c,440f0582,2fa53e20,f8c226b6,85b437a0,557c8450,774c0c5f) +,S(d7afdbd4,6314d677,727fa11b,211e99a1,d6948be5,b7753ecf,64e9b1d0,ac7a83ce,b5f8b97d,748a4abb,a390ed9d,79cb42ab,ee9b2afa,517288f4,80aba1cd,34e21d04) +,S(2b6b834c,d2b54466,a3d41694,b672ac55,13f19b1a,d518ba99,d622abfd,9b6de265,c1922593,ddc0b3d2,ad1d52dd,3cbeb2e5,74ec849b,892d9df1,87ccec50,7ab9b0d6) +,S(f393cf4a,d7f93fa3,1596ef7e,a9c11c6b,f29c344b,1a3ee5a2,51360c9b,a96ac8ea,4e811ca9,de67ceeb,90e48016,30d06125,fbfa56b3,35e3a7ec,41bedbaa,7a8133e1) +,S(bc3b9250,4e14b254,81305012,a248a94,bbc546bd,52fbc0e,848d75e,9c8f418a,9a52afc6,f8b487c1,7653a911,f11d78c5,8f5eca38,c761a2d9,af0ef2ad,a6a58223) +,S(2f5a0e73,c601fb8a,7321e170,4abdb1f7,e71edc3b,bf6f9cec,1467eef,5f6055c0,d8bb1d0d,142d2cb1,3b9d97f8,f807212,b79a5ecf,13d942eb,c5a3f442,6553e393) +,S(b83e51e3,b4fc69ac,84d099b9,6916c11d,8d8d8d7b,f5cbe15b,fa13ed34,73a54ae8,232e0f88,69c53923,22018084,a7cfc251,daeb7a84,6e1daa78,f3f365c2,ca3dda5b) +,S(10971993,50b07a32,1532b372,2ee89058,e90e9b30,5908cc0e,a249a40b,e7516377,69a0b67c,7bd55a04,9be3a3a5,e308799d,dc735f9,ce56ff67,2c796b6e,5a0a1055) +,S(dbeef75c,c95d5018,f3d71711,a0299dd2,62250814,c1469647,dcb27a23,e85c4477,dd4712cd,16334f8e,2baa6855,6c5237f8,676311e3,1cbf9753,35e76a90,88d66413) +,S(28cb1199,2bdee938,f3405f18,537b410f,2723888,e4ca0d29,d96806d5,6baf114f,e6c63fe,bbe5dd81,e3a9fc1e,83a5ce89,c3e2ef6c,c2a57fea,695ebf4b,e81e5aa3) +,S(f0a2df0b,64efe99e,65f9f176,89cec5d4,caef385a,e4676da3,790ba2e2,4e9f60ba,a7ca7e08,b900f664,14498c12,aaa77da6,6a2520,7bcf1a85,713b6d14,807a4519) +,S(d1bb46eb,38e54396,dc7ad4f,f553106,54fe9b06,9abb1410,799dffe5,482b0f00,14b0619f,e08830b6,d0a5463,96826b6c,d03bbd2c,af930b14,a031f922,eace4214) +,S(27bd2e56,7705126a,5f5adb31,ac1d09a1,85d74002,c548a84,15c0cce0,1f69517a,12203dd7,cba21cd2,9f9ce428,a8e302d7,202690ad,8734c08f,65578192,a5468d32) +,S(6b2cc790,1c72e201,693835ef,ab2b676f,55441add,b8dbc3bd,61d43201,bfd21d9c,59973406,deea0493,daff90d4,b62ff38c,6690bb05,18e75560,1bd5b3a3,4add7456) +,S(75e85c3f,32f953c5,632a8bcc,6bfcd6bd,c63c3b93,e607d267,5df09fb5,94840f27,22f5a376,8714c73d,96b24f89,d426e668,bc59aca0,cbf6dc47,723f01ed,6cb6bb30) +,S(d37a3071,969e152f,41c0eed5,7e28f1e6,f26e1752,68c52683,15e200b9,f86d56a7,53d52726,98751d1d,dc4b1fb,d9621723,70e296c3,b47436d3,abe20356,76ff6181) +,S(715bb304,7f5e6973,36546640,8e183bb2,67693198,94e341d2,37d5101e,a7414976,28440f5f,9e82d5e8,7a5ea672,2e95c3d6,a89dd1fb,3d81aca,db7609ee,a1a968d4) +,S(f72d142a,4f5b1595,a7b4a52c,c6812ec2,8e4924a4,b087c139,68d8adf7,dac642e8,501b644b,b5d8042c,f16ab9bb,bc594c14,585486cc,fbaf47a6,5378f97a,761087dd) +,S(7b3eff8f,b4ca8a3a,5fc3cf02,a469f34,3840846c,d8fbff28,243b962,c1284c26,be2588fd,15396124,a50bc555,5e161022,3bbf636e,fd510522,811902b5,b1748579) +,S(2441a8d7,71fbeca4,cd365225,7974e4cf,ec2a7035,ff2b58a5,9cc5fc37,8a113dd8,54b0776,5316713,4bbf4c6a,7ac23360,fe035d2d,9316cfcc,ae129893,82447981) +,S(c20fca4e,d05467ca,45b916b1,2f4ab386,512d097c,b64b824d,e78e9a2a,14cf7591,8851acc7,96ee4072,ca87e69c,9dad10e7,931fc48b,238cf46d,2b2355a,e4eecc02) +,S(2f6b0e8d,1375263,b74e415a,ad758130,a34c6c6d,690ddd67,63492eb2,49ec8e7,d0c791f8,438cf6a7,976cb614,eb4c9f67,adc72275,f6236868,e384d538,daf25dbe) +,S(bfafc1be,426f056d,6f8b3ed1,1374db21,fc00373c,3dd8c762,c5ab91ea,b2b665dd,9c41f297,a4cf003a,7fa7b071,a106da4,6dc40050,a7592781,68436115,150e2a2e) +,S(cf711dca,90560273,6d776f86,759d74f,895980f7,1728dbe9,1df93076,cdcb4e8c,52a379bf,cf25216f,e3556def,e889b23e,2f91f6a6,47ece012,4e140aa7,734f1cd5) +,S(b9be95de,27aaf198,c3001ec3,63690f2f,f516fd75,1864794e,1c3516c9,abd1384b,68875f97,dca1dc43,3e9b614,488cb8f8,1ff85d58,2ba853cd,27fc1227,1ecb6df9) +,S(f5f257e6,c4d06a8c,53442b37,7519ae03,7bec31b3,c257f331,fff53773,28e9638e,b6a1e60a,48d03213,bb52e3ed,d20d0ca,c80beaec,bb40169e,35ff2165,43e986dd) +,S(fc35c74c,17e38aa1,15803603,30af7d92,a5281b3f,cb6cebf9,df09155e,64099ce7,6e2f984d,41e8693b,5a4c1c58,9814d131,8421fbbb,2ec8e45a,c6239227,db79dae9) +,S(ac135e01,49d97363,7405e5a9,89ffaca6,c1bc18a1,cce34aa7,4732fcce,d54384dd,3e38bacd,ff954a6b,6bccbf63,9f8d709,d8e54553,6113dcb1,c471a162,af021d0) +,S(60a013fb,efb3c5d7,802400c4,e791a019,bfd8f657,cf4c1055,f3674f92,9f5f345d,7e763c48,3582fe3e,2a0a5138,ca320013,9907e364,5468b5b2,711205f3,38a1bd97) +,S(a099a106,5d907a8a,43a3d027,3a789992,ceb3a659,bef93a9,6ed04ea,19a7acb7,137f9ffb,fe3c22ff,c034bb57,9f0c9b46,d5cca4a0,db1407db,6fe3d7b,5bc5a50d) +,S(9ba1da86,d02763d6,187ea5a8,c11c9da4,c6ed7017,49f107b,9ef4fc3,94a792ab,f19e22d8,ab5459c5,5bf87908,90175184,8716aea6,5c2d9650,c472199d,6663f741) +,S(3642701a,d30d1430,17be9363,3f28d90d,b5e02238,9350934f,63a514c9,a677ada0,2fdf9ab9,c76bbbc6,c4e79f48,7a8bbd86,6432fa98,4f52ac22,3440de3b,f1aba970) +,S(29f79c58,100b7098,d8d53012,e2c98719,6188c0d,54712c31,c2ea3a52,d6941a5b,be9edd99,eaa6c1bb,d0ec42f,586a2806,919d5bb7,2d59bf3,7216890b,9a2d524b) +,S(e011aadf,bc35284f,816d5030,c3feb350,4b470d0,ac5ff061,e5ed2c47,89ba1bbc,e0a98f93,4f2b591a,36e6ee97,f293be77,21ec1a9,3f4b2700,55a0c01a,3cc979e3) +,S(a5c8816b,fe5356,37eb54b6,88b9221e,ee06a51,77ffedfb,3ed96ee0,4fd78585,3f86637b,9d63b11a,44897792,9a6aed53,7d65951d,aed6476f,e03be5a8,c9ff8e5f) +,S(3b952c23,7e44350b,95207798,e708fce6,2e6d49e0,912a2509,abef16c9,c7194707,f784972a,419e6c8a,c9d41a38,57912e66,e6ebb631,6bcdeeda,ff49b59d,bdd68936) +,S(8d9796bc,d9d8152f,80c7982a,187a4aaa,b75dd611,99f86632,72502f24,dd57af04,fb9b1479,94a31e3a,28d5695f,2d689951,317c2d2,98e9892c,89c98202,b7e611bd) +,S(96b2bc5b,2f4e6445,1536f689,d7889669,4fde4d7b,6ef67f51,84517704,6a02de40,e0b76d26,f91982db,5039bbf5,afbfce51,914eee9b,352c178b,2145c4a1,88e89cc) +,S(9bf7cf10,9f129500,e2a8f54d,8658ef97,4e3ab2b9,a1d0d036,25bef5d2,432e2d79,2113d7ad,f77e1c68,51b8bb52,188ebd25,dd6373a7,19bcc20b,e32d0f19,496e8582) +,S(10d3ffa7,20375b5e,afc8c741,4d9aa184,c91f853d,61d58dab,11a04f2a,f3d4f1b7,c1f84b2a,8a96f43c,b215c704,6f8c3f02,c98d750a,d416f21b,eeb10ea3,f298c90) +,S(56d64e2b,6adf1cd0,b8d63692,1b68733,e92577e,88430e92,c0e679e8,c3a5eb6,1370e,fbe98423,488427c2,57d5e696,5d4b687e,25e4b824,51b1a6eb,7ef71cc0) +,S(fec4a03e,1c83cf20,75deddbd,20c24792,6dbfa352,a56821c1,420adc34,731528bf,a152b2af,8670e42d,3bba0d98,f387e9bf,1bab788e,fd7bcb2a,a787e6a8,bda95509) +,S(580a7517,7ccea9ac,63ae6d53,e8959e5a,a45d11db,29a87001,779c260f,2fee92eb,793be69c,3263c64c,2048c411,115375a4,86733a90,d8c12a06,862f4f9c,669e8edd) +,S(9286bfe5,78931ceb,cf97431b,1137a19a,991b46d2,d0dec2f5,35edb976,6af636f6,7e774d30,e962db42,83cb38fb,2053b780,c55fce80,51edd5f2,8cb1b5a5,d329f516) +,S(606d55a9,9b702652,5382cf2e,efeec65a,803e3851,da60a041,e5422c1c,28f4890d,dc895a6e,3c2a6411,4a04a1e0,31b8aa17,79ae2c05,1f4eee54,7f8a54c,50eda1a7) +,S(a16a0d40,833ec1cd,dcfef2f1,bcfc8ed8,11387dc6,4e4df6,6e807f69,75f917f5,548d7d37,13de4a53,151f32a8,2880d087,7fd281d9,63011388,ba991bd8,822d6527) +,S(5949d2,be574e23,9a3e3e7a,ae20726c,4a687a15,edf5a62d,9b79d0c3,4f9f0329,71dcb25a,167ab25c,311d9427,5480f78e,f7f4e777,9723e55f,337a9121,445288a9) +,S(841f4e4a,e67b0d8a,49d7b295,e9c1ff4f,cd1e2333,82101536,cef7c4e5,7968b240,1f561c9c,265fa4ed,eb979f4,a8dbe679,ccae8037,8cd73d5c,b56671d0,571f4161) +,S(22623df8,c748e9f2,88bd4b83,142788ff,faf680ae,a2640d,dd43ec1e,46cb7442,380ef00a,dfcdb592,f964381d,ce9f787,17d5827b,494c3aaa,d5e0e013,87a55da3) +,S(816067c3,6438301e,ea07a21e,5a60a17e,670083de,b3b66e2d,c88c6548,f45185e4,5afa391b,9a95e9f1,f04f4e8e,236fc39e,2eeedcec,45026647,f5982aee,4dc4cbf7) +,S(f8f23561,4745c531,24cf6431,ba8e0425,7d28af9c,2c196485,3546924d,ce085c1f,a165067,e3b41b55,a548c1b9,3fe76b5e,bd101275,acd29e75,7f66753,6734750f) +,S(21325584,e25b8a15,c25537d4,c70853b2,28bb933d,de04be23,7753b933,57f2f57a,3708c8f2,78ef57a,f0b00d5,17f21a6f,f627b5f1,59ba1f53,d20b727e,86e873e2) +,S(b2f4f7fc,f48519b2,c00c24b3,7ffac141,88b0baac,bc915c77,845cd6a6,3fdfbda3,b206b59e,6f52ee43,3e7196bb,5f4cf3c7,de49723a,cd5b3e17,1c94e28c,7d57702c) +,S(b4e65d4f,5f420006,b7c70fd3,9564f9c3,fd9c5c53,dacae064,62212fec,ee7f7265,307b6ef2,e3993bf4,f321723e,a83ec2c4,3c75b8d,684665bf,fc073506,816bee0e) +,S(4f104593,9ac609ad,25f3968e,9798ee93,aa58b61d,43f4bab,8f2352b1,de3a7240,ed8d87bb,988395fa,581698f5,c55a5093,ed9d0a89,3f4aa4bd,186221ee,7f8179ae) +,S(9b5e74ff,e515c125,9fa6b215,7ad7529f,90018e85,23888738,d097c016,494672fa,1d55866d,4c4e30f1,7bdbf70c,43fb3b9d,fe2df3d8,41e18bc4,3db3e3af,21fece15) +,S(77bf442,ac8cf718,102968f9,49387b1b,30f8a2c2,c76a2cf5,10d817c8,7e17e302,bb0f9e61,1d90046b,1d3b1103,e6c5beed,e4daaa85,f6eee1f2,6a6e756f,d32af0e9) +,S(27de125c,d49f2049,6b028f34,b16a9988,d2f5d469,30834fe6,4bcd388b,78c266a9,f43d86a8,483dd92a,2ad9dac2,4039ad2b,84cdfc2d,323979b8,1a43de25,5cb54bfe) +,S(21bf7178,ae1d75e1,94bb60ae,4efb5a8d,7f026cf0,7f845b13,2250989c,4be9c116,6caa82ad,bc21df15,d1744466,4d3b58f8,76b52291,5696481d,434f689a,edb8d967) +,S(249254,93ee016a,41b65b7f,8289da2,dc9100f9,9c0b956a,66d245b0,5632e234,bca30194,1cb51f98,1504c536,74f6f904,d883ff46,7aec96f8,2ed5ce31,7c45b3d) +,S(d3f644c1,e3472b4c,d46d89b9,6b937108,ea8e9425,9b9316fe,230e7538,7d867f76,91822603,fd629732,a3b37ed9,d5227942,2e536ae,316bfb7c,597b2da5,d8cade5) +,S(c8461f4b,e2bd14c,a88e52c8,147f656d,915c2675,46252e89,d0337f7a,e325b261,18971181,97ac799b,3f632868,e46efdf5,fa3b615a,a8a92b07,e38ceeda,9cdcae06) +,S(b6e5f590,be20a938,c1b57e1d,a7bd6ca1,a8c2406a,aaa5860d,9133342a,c395a380,a6728cf1,a2f2eade,72d86569,ab5a6305,cf01eec9,6a6de026,ff146d5e,7d8a04b6) +,S(3d25179d,465701d0,56d4eee4,b5efc10d,8b70138d,f14908c0,3124ec95,59eb5d6c,158b7bfe,1d61d7ec,633e88e2,b3c5897a,3b56f7a2,ac557c8c,3e032a71,8b95980f) +,S(abb5d54,c7171499,95893425,bda27f10,d8515511,91af6927,9849a597,46f94d99,4cdfebcc,3be28dea,36d06e89,ff4209c3,7012ff0a,d93d7ad0,4e454422,c4b9a161) +,S(989d0125,115ef9c2,900dedaa,4e31cbb2,f1243386,73ec624c,52352907,b325c73e,d3699ee9,945de070,fc1f28ee,14279750,d553df63,2951c0c8,d1668206,94c6c8df) +,S(c4c5c5d4,29c3d1ff,628bbe4,e0edf70d,5e05db13,c82a2af8,2d0e4232,5e013884,c2c76cb8,825188a9,fc29da67,70ade97f,ccee860d,d13323ee,f2ba7e7,efa97eea) +,S(8662d850,c623b65c,8db5080a,900a0e83,be947111,ec0b9edc,3601549e,26c0807b,a71d677,b0c9e7a4,f66a72b3,2918083b,f91e724c,cf8c9526,b3df0f6e,35da840b) +,S(d26fef49,7e7359bf,33309b38,93abbd44,543b73c7,c0eaa626,cbdedb17,1d083898,ad8bb209,bb090b39,6b501ea9,a5070f90,4d60c20,d48dbad9,56d381f8,79851395) +,S(569be8e8,c584b682,7d742ff8,5b402112,5b4560f5,f173c983,8f8785d2,229d8d0f,b09381a4,a8267d89,a8d5581b,f9a49d52,47c74a33,5e26e354,22edafc7,d41b8559) +,S(de34acc3,4d1787b3,ad967bc6,c5960d8f,842f82bb,c95aa255,d4a9e794,d30116d4,2fddb41c,b2b6b52a,57cf4d3e,883d3f0,e322c40b,ef098505,b6cb3d77,a21816d3) +,S(47430b48,76dbb762,6d549b86,1742a5b3,ece85240,70dd83d5,5446fa99,c5c50b1a,d75592ba,7004573,58c6a0ea,dc8ec772,b53dd048,8ddc73e8,5af357a4,af200df1) +,S(f1d1e0b5,e6687266,ba17339b,76bbab6d,8c2d8ffe,f6c68fd7,9140b097,d6e9fe13,a56226,fc233385,349c5483,72300f97,a1d8494d,a67db50b,b96543d5,bf24e580) +,S(22a6f735,76140de1,3dbd0426,e968c374,6e8132ff,383f44c3,c0515b85,f8cdbcd0,9dcd89a8,90270e3e,358dc004,40f95a43,430a399d,a8405e48,e69e3455,fbd18d1b) +,S(2ddc5328,afd8ca0,9bb0c6ea,57442e8e,fc307b30,c29e2867,b46654e3,e1a9ada2,7b9ab90e,db84e6e8,7bedaa6e,31ff90e1,7d07793,19977393,b5fedb73,c087dee4) +,S(60b6f839,a60af52f,d30a116c,58b9c65,1fb1c854,546dfa9e,1a01e2c1,95da0fca,5e77f69f,28cfb414,be39b07b,2469d8eb,b0e74306,1d856bcd,ca54d83e,20d26c40) +,S(2790c19b,9b9092e5,cb06bfd,f95ea43a,2a1f1f28,57c96776,dcd26a7d,ddee53c,fdeea120,d04e6e78,b2387afa,a0217098,de067759,8b2bc5b6,2715d9f3,714e7f64) +,S(e544320f,9ee8bc8b,127576b1,6fad9782,db181ea3,4514f7c0,d7f9046,f5113803,b93762fb,2397444,e69b63dd,9dce7c32,3c73680a,e26b5e0f,95211972,c0510741) +,S(6c7f25ae,73e428d5,860a236c,bbd4d74f,8e2706cd,69bb4cee,39f9aafa,db55313d,d8cb8fc9,e33f9b18,e9a0864b,e58ea921,8db30c4b,d5dff091,6a44b581,c8dc9121) +,S(289d1b28,ff710d47,4d1e9c3e,f3952f27,dd9eaa3a,30ef499,121ea53b,9b93d4e8,f36af80a,aebc2dd5,84cd5cb7,245b3cba,64285932,77f4be38,cf2b394a,ee880667) +,S(f02ab597,ac01d673,25e87b5d,29130c18,2a6f4a8a,d4ef7476,b9fa1da7,5910b5aa,ae88c02a,ecf28b13,ecec5379,5c34633d,d3262d1f,65ecaaaf,fe89640a,cce38adb) +,S(a9a974f,71a73106,57732c82,d6d4c6d3,c625bb70,4ec29a8d,2d8f8418,dca0413a,c20df433,eed4e96f,d5ef222d,860ed1e5,af1497ac,cfd1dc21,26e8925b,91b372cd) +,S(7866190d,728e0899,19a0e9c7,8634b55e,4cc392fc,1650471f,4a21cf40,8d77496a,1bb5fcd9,540422ef,caa8e265,c35a1e64,29d79de3,a9369b23,3512913,ac0cfd22) +,S(c8a7ffe3,44b3b8eb,f00e4e2d,e63d9540,25cc115a,9110c773,ce0130a4,8333b9ac,ca1ffbe5,10c63b5,674141aa,5ca87246,ca91280f,da97e806,dbb523fe,5ee67b6e) +,S(6cbba6a,13ff6ad3,83419e84,e4da6871,9cc1e633,d4cf3347,2f9966e6,4f9208ba,35122582,c7893f4,4fb92c34,e9c4661b,5859889,62a7d1fc,fac8a2a6,1e214a88) +,S(e07f8dbd,691a8611,eb5450c8,2c765dac,ffe9aa81,49ba3e12,87b23fda,fd9de719,932e35f0,8e39cfee,a2593799,4e118c7f,acb0c6e,5b526bc6,894b061d,8cfbc509) +,S(62136898,32fd9416,cde720d7,1d3f32a5,51f3e238,fccc69b8,4b633a2c,86d2c5d4,137e9a4d,62247e41,8596d968,4f1e5997,791f3b6d,69cbcf68,206f715d,be784e9c) +,S(8b010588,62de6706,253eb2fa,f710c086,40a318ba,1ea684f2,3254e8c0,dba7b9eb,54a48862,dcc56c60,cccbf43c,f7a33f9f,dbd7e419,56f0f48e,2ce2371a,19bfd264) +,S(12d3908c,14af8346,fefbbbac,e56bcbae,3fb2ed87,dc30b1cf,eaf480ea,84f213d8,fc4615fb,df7ddac9,84676421,2c4d99,fef41e5d,98e5824e,cb181a98,9a67fdfc) +,S(219d05e2,a7b8cc69,bbce368f,62922992,b474286e,df7c13dc,8da62d16,1784cd2,8aee4f73,9a7eb1e7,8ee9407d,e8fbabef,dd28203b,2161ede2,761e178,a34c7f5c) +,S(d7d0cd59,9a76fa91,f691fa23,ad265f38,49bbe213,c38cb074,852005b6,d85de204,f349572c,60750dae,5ea1330e,a725a0ef,ed1a2d60,c0b1d9d1,e938f37c,911ce2fa) +,S(a3fa69f5,a04c9023,83d8b73f,6fa8fc3c,9f65cfbb,2c77042d,635f4978,eabb6c6d,c798a1a8,9994aab1,4af95b18,f389a2f1,accb2d7,59997e83,72c1ca5a,c3cbdea2) +,S(902e881a,825c457d,79872e71,e5d94170,8540734c,1d050e92,cc5c8afb,13b2d1cd,ff075132,63bf6fb9,11163ccc,f62f8246,de099f07,ccfc9e33,8ac82c30,bda62d43) +,S(325f19f2,4c470556,d361aa2b,3f1932bb,6923ea5a,4f8cb505,d34cc60e,729c144,f4a9aeb8,29a6a0cd,f981bf35,81bf8f9d,73e3e9c1,61996178,2a57c46b,9e94bec4) +,S(6994f3b4,41a6cf61,53e5f860,2cfffacc,bcdf7245,eb078247,63bb07c6,fa1edd4b,ec2fc5ea,892da897,29c479d8,d3f05152,198ee4ab,87f73bd9,27db1160,1874c174) +,S(21855832,4e8f796f,fd51bd2f,8c1f6a8,5663c5a2,b5bad37f,3b7a1052,6acb2d8c,e77ceecb,33cec03c,99690d44,b0343bf7,3b93c495,5d67ccf4,b15d1d76,a1897c2d) +,S(905daa3b,32f2a801,a567c312,ae4772b5,3196933f,487aa1b0,a5674cef,9d91b099,bf6285c3,6d271719,13691d5d,767fdc17,82b64843,5b2ca1d6,b695871c,41cf369f) +,S(df7cfb84,34b60524,75fe5161,3dbe0e7f,1b685376,315397f5,b39951ee,b65339f1,e725cd7e,1419e455,2d953393,dd9651d5,d1beb3c,6fa44d2e,e580ccf4,df558243) +,S(e7fb9efc,88842b9e,a3c96b82,1ca5eb80,385cb276,28cf64a5,d8c5bcb4,e5732491,c8e676bc,a6f9e037,263b8390,675a97d,1353c128,eddabd5f,5e928153,78f22331) +,S(d1a35f0c,272ba216,1e6ac0a3,fa440f59,bad79715,d71e12fe,cc12369d,cd24285b,1f5b70f7,d475716d,b9ef2f21,bb156400,49dc41a8,96102ec1,806b949a,c99edb3c) +,S(66ba6e8,5f2ddd4c,e17da74a,c7ae629e,4f420429,45932e5,55110da5,2a7b079f,d8ebac5b,eb8eefbc,f4da4f35,79bdffbe,21967904,36487733,263089e7,7a80402) +,S(6f7f69a,26881052,b4bcf806,575f9c50,c36e7c22,1d7b9e48,7b1f39a0,b4f3a749,11d06b84,d89b88b,ab4352b9,cc160e50,bc183558,25bb602b,89235aa6,7331a4c4) +,S(4be16d6f,571d503b,26169906,75c01ac5,41c23afe,84cadb90,eda0c21c,926c0abd,1041ede,ffa1f2dd,61a116c5,dd33fed5,d9ede78f,cb2311bd,9a04fe32,9ec1d06d) +,S(8af88c5d,b55eacb6,760abbc7,91698c57,19160335,ee569bd,33bf050b,1e75886,4f5b850b,6bf2b4b1,29aeeb24,596007c0,ca203eb5,d2be6bea,f61bf596,bdd9a12c) +,S(ad33e77a,3316eb8e,1a764849,13915e81,edb69518,8ce7507,2e2b6088,4cef8672,fa0161e2,4bc88bd9,da5157fd,7950c75d,6c4f4f89,f158f13f,16ca5e4c,af7ccd90) +,S(444a81ef,7620afe7,91d96ee9,b1c34485,cdb51e1f,6022dba0,69ededb3,d9d8c2bc,a88017d9,a49d4ebc,2ee811c7,fbfcd9ba,bd268329,1efafb52,e641af11,9751e2fd) +,S(5b1e07a3,9530f8b6,60787e9d,26503a2f,77af3ad1,24ac8aa5,1d10b663,ceaa5c51,fcf4c0d3,8d55e0fb,2731e59b,686a806a,e87cb510,7bbd013b,4500c470,f77810b9) +,S(3e8c17,e986a86,57b4c403,3317e67d,b1d42e7d,9625e844,ba533ed1,73174309,deebe49f,f4f5a35d,ea0f396,63c7ee0e,9db702f5,c296fe5e,696f5521,94cd6caa) +,S(a1096eee,5e9bcb19,9d24c078,b46b528b,6432af90,7f1d57e5,746e83d8,4d112c1,bd13e4fe,699436cd,656b3019,acd54f3c,97eace0f,e1e92fc1,3f08a76d,d2e7c6d4) +,S(54758579,4218de75,db40a6d8,99a75ee8,36861093,4ded0938,98c071b7,6665f2f0,3bd55642,13e1c689,70cdcd94,fddaa656,6bcde4bf,29c761b5,c6f613f6,19174548) +,S(4eb32992,fcb4bc44,bff56604,f4f74586,a4400290,5ee9adf7,f7bbc694,45456057,8576a8f2,68349f01,ada77c67,30510030,e0cc9d8c,66db7609,21661540,ba45c3d4) +,S(350b2def,d2eb4933,c6d428e7,5990a7c0,f291723,f92e5ea2,69c5b4c8,b661a22d,61acdb00,add9f34b,f36126d8,380ef5bf,70f807a8,1320d59e,3540fb25,90de6943) +,S(914ea8be,ce7f8819,5337341e,eaca129b,2da3c96b,306b017,d7afd984,75f360ff,f2aa5548,ebef80a7,483b563c,e8b242db,582948a4,9fc89213,d3272a63,85ac7b53) +,S(f656e17,38da25f4,baabaa6b,d70e3f5f,ad6d44f9,c53e1a33,4596246b,83dc0fef,40a8b4fc,34639287,a65f53c,f373c2c4,c742ce4b,2040fef5,4c31dac9,59fd83e5) +,S(a47c8af0,334e3ce5,464310bb,c0daa66e,d77e1023,a2124182,ce3e6771,933b618f,6dbccb54,56d7c75,5e71694f,fa1713eb,41ec5b2e,8715ec4b,52295294,c0c7f08) +,S(a8a2862,5e1d04a6,5e87947f,82178d5c,3b5fde31,1eace688,6766ee9d,30753ca9,f82ad6f7,483aa04d,a79e672,efa109be,1feb3f75,d73923ba,94df2f1e,2efc2169) +,S(a01ff54e,5f8eb855,e26903cb,3fd407ef,4fe06208,a0f44837,1e83f7a2,31c017d0,2247c6f9,c52f1a68,84c18ec0,77d92514,9fd59b00,27663ee2,f0e5b2ee,f2edf92) +,S(e7b09c3a,626ac89b,6caadbd6,99a320c,61ef4fe3,11f6072f,f2d7c875,8d42aed1,8ed996d3,6a7b50e9,8e5c64ac,e03cf5a3,37c3c5a1,6d99c5e2,c0faefcd,38609fdc) +,S(3bba9e53,336c2a06,ca89fb52,26059041,96307c97,373cb717,3f35a45b,863ff2fd,f2fe9109,3faffc16,f58ccaea,e54e9b8c,419d5123,6e8c960d,52ae8341,27d24799) +,S(f61d22b6,dc660174,22122400,432f533,11950c21,b6240acd,af905f9c,2c0630a3,6068f5a,1a662cf3,93eb7e86,5cdfab18,692bb250,15de2796,1421a457,49ffb05) +,S(a5b60855,6b1aa22d,8bc38dcb,8f3e4721,891c45dc,2702d13,7189be70,e8a80962,f77f97d2,d5e305ca,1fe20b99,e6c182ae,3a9b3a69,7cd5e34a,7199032,fcb1ddb6) +,S(70c3aaf9,eb2562,e1cae950,be6f592e,f030301b,28022ac1,be3aa5cc,85e1a259,3f2cb7cd,31a8d319,ce4626f7,213aaef7,3f91f2be,a17addeb,61f217b9,4c587583) +,S(1dd70dd1,a8755e37,28dfcc4d,443e7911,a67952af,c33e7d93,b975d136,8d06e530,4684f974,1f5894ef,47040074,2ecc73dd,240e677d,b6bee0c4,141dfcd,7190d084) +,S(d44d698d,7aacfd4b,d8d6bb7f,2d0dca82,f5d37c3d,46573546,2b180cc6,9083fcf9,a18d803d,4232965,90c67b0f,4c415bd7,c0c94041,3740be47,2819bebf,87dc407) +,S(84589ae1,30455742,85522ae7,4b1bc3bb,62730a10,6154d9f9,4109c010,51b34ca5,b979fa08,f2a9af49,bf6ffce9,b2fa707f,de14fcba,3de3b903,49bf6235,37b3606c) +,S(3dec8fdf,89118996,bed31c1e,fff15c1d,bc84e73f,fd04c6f5,469d2f04,8b724627,b143f3c1,e20b5bcf,dbd1a555,f4ff88df,dacccaa2,bfd4310c,16ae2710,1beb2c8c) +,S(367a5fc5,519dd9c6,39bfcc4,70ce465e,23a8dde,417b412a,2f0f4374,8cac160,5b8fbddf,2c6bfc90,e291b136,a3e0f8f3,faa64820,97a87cc2,dbafac5c,a7f021a6) +,S(8aa5587e,7777606f,60bab6b3,20d88e93,1e7c2efd,487bacce,5fa3256c,9463efc1,ac5ba76c,98bfa132,c16921ec,aad52289,50beeb34,449e0c18,88a39fd1,d3f091dc) +,S(79c00191,ea632ea,30fd9e6,b0d11c6,af3aa441,eca678c6,a5d6bf3c,c84cae0,3f954070,3b19a941,3ac0b659,bf401c2d,ae9c8bdf,2bd19e85,472d2d82,39dfb899) +,S(c84de722,21a59e95,cdd951a0,66483255,e858aaa4,ada498b3,d4ef8bf8,3a04fc8,73cde958,915abf28,df811109,a6220449,548fcd2,f639102,158bc451,4af0a0b9) +,S(8b1b8c50,c6327d61,e063822b,2a3c5935,fedf74dc,fe694c21,8cb6b892,b5a9d6d5,57bd8952,9f156435,f47dfc47,9ff4314c,c036766b,5b6437f8,41f60cb0,fe168b) +,S(b45eec8a,3ae82f98,52117c4a,341f8184,33a31ce7,719d7650,e783fd52,48702c52,cd556b5c,c7086b4f,905d0fc,ea01497b,25411785,9ee9046d,c988c6e1,9e0a1c90) +,S(a2d5dcdd,d93096c7,67b4871e,ac58cbdc,31ab7013,865a9cd2,c5707780,80757319,7aa406b4,b130b23e,9e6b5978,b1e0b537,227ae8a8,af62c1a6,a6d46ae,4b064547) +,S(712036b4,e5d35950,a7564ea8,3509bec1,e97f6e19,121ae5db,3d314c19,b9ed2b2d,25862ff3,8d0560ea,4698d2f,425342c8,e3a32232,f9c9572a,21d7414e,68a93616) +,S(5bcef0f7,d70fc8ba,942e58c8,79afc973,dca402e3,795adf0,7562b552,f0bfb392,7cc85a4c,ecb45bfd,3efb0e12,c3fc56f9,1a444ce4,73256474,54ccb089,baf1919) +,S(dcd5702f,9d508a1b,afab9f0,af5c4e9b,b9e5f214,6767ab0e,b5c1d859,39741ada,f7eaead7,ea13e3a7,dccd40a4,a2526501,3369d558,6f0c735f,9eb2518e,ddcc1fa1) +,S(2cea30d0,4f629d,91c3ade,1b8b7176,363bfcb9,25d3eec9,784b91bb,e6cb3d9f,a83f4bad,a42ab171,cfc9a76a,a3dde34b,c48ba454,b39b36e3,44446096,a1c42624) +,S(858b41f2,767b191e,df15fcb1,3a41934d,150e54d6,e95035d0,9c6dfc7,a1c32f8d,8180b97d,76dc95f5,478a2172,4802a28,b34d6e9d,f65d5358,e5cecf82,9fde8dd7) +,S(d5c98002,bee359b8,6d1234e5,ff418013,3eb9a668,d2f1294,245fd020,c30e81e6,4e522da4,cd2bc795,65a2e4e,e2fc87b7,a0b6bce9,1d90376d,921aeb49,5b3781de) +,S(ebf9162,2f9cea9f,71a4ddf5,82de4b7d,34002d76,da8acfb7,d4d6c3a1,9520c1ed,eee75322,3e1881cd,8e3fb483,318c75aa,7e43d049,8e53536e,cd481d18,5ad4e251) +,S(387f6a9,d08756f3,8c2e111,af74be68,acc4504,f3669ff6,b406f6c8,a61db4d,288595e3,ea1d5f91,26df96d5,dcf5cf4d,ed0bbba2,37224c4a,59db552e,87cdd28a) +,S(897ff1c0,989bd52e,383a2d70,e5920144,9aa409ee,9fef20df,25574956,dfe46714,3cfbc0c9,308c6529,f4e95a00,644a873a,de094069,36dfd6c6,bcaecfa5,9adc9d1) +,S(3255a8a6,8e0484c7,8b6bbf21,e2d8b24f,bbcbb337,6f84feef,b577ef1a,b5a395af,17b3c002,f9204b84,e6d4a426,d2d74893,79ef3fd5,441e881f,d8122599,2912aeb3) +,S(2ca4a952,d4d9e3b0,3943eeaf,b1eda225,1fbca101,e7071b7e,2778ef9f,ddc55599,bfacbacc,df02c18d,f81a2c04,4748c7eb,e98631cb,63ca16a0,9892e163,23891e00) +,S(c3e8289c,478c334a,d47b0410,e1b6ecb6,46ee5f8,8a4dbd73,10505f6a,de4383b2,5792c2ce,b0431238,647f4309,cb4ed220,229bee,2727b91f,de4004b3,d6f0f55f) +,S(2bbdef60,a86292f9,867ad63c,67f98420,86fb968d,db92d9d5,f87bd27c,15119049,f4a4b762,3536c479,29099d19,3d40d4d0,e75dac62,54f03538,80286756,60a85362) +,S(77a6e090,9e7dacb3,18014ef0,714a4be1,fe3ee47b,e22afd2c,e0333cb9,ff2496a9,54f0e475,b1a9906c,d1d915d1,81961492,34461e27,e163c384,3815d188,5251065f) +,S(d195b96b,78719254,deb4f413,979f64d6,ea94d5e4,79350b11,45c39e45,4f40ff0,238a4440,613c846e,9472d4b2,b0a4db88,b8245cad,a5af469b,d997f729,c0e0636c) +,S(c39aa336,208aa65d,75bb0f3c,6084f414,ad024d15,48da5bd8,113a619b,4815b1f,7aab1ed6,32741dd4,14883b22,6e573ee6,455a0053,6d849200,4b233153,1126fe5a) +,S(e80ca23d,baf82db,cbe0bd27,24cbb31,d6661c70,44d8a8d2,2967764c,fde31f30,a153d1d4,73187878,bcbc583a,5eb83e5d,f67e8142,46861713,8c484744,a597451b) +,S(395b7a65,a5a9c23a,f96723a,4d595a7d,f3e8505f,e0aec120,711cb7b0,2e72ef80,59020dd5,47476e39,36ad37b1,9a256543,4f88cf03,2992f4b6,2229a5e7,e49bf990) +,S(67a7e8db,b83e23d2,7b57e2cd,9512a5da,e8b49545,ffef2577,644fda22,910b495c,7c01499d,3791b9f4,100a89f7,8e80b410,41fd34ee,68ce1f15,a8753032,e8965735) +,S(c4038e7d,76d2e7b0,86986395,2cbe2ce3,ecfb4b08,61423892,ac9b3b3f,6dc0c7e7,61bb3b0d,9efc9b7d,326a27ba,bc34fc8c,129460b,6642629e,72f20351,65e92f3b) +,S(7705a5e2,26a4d3ae,ee69c52f,5fc3f575,b9bdda08,70a19a8,8a525698,c3a25e5a,458e096c,f01906f8,c2426973,d1c6a982,44be9e02,22406207,3a883e4b,53c7a1b7) +,S(f3ce8bc3,5958b5e6,16a994fa,1fe0396,68a5f1f1,b464a875,9e4a3475,34ff48d0,9c1a1d97,be3ad78b,67c8c441,f7aec63f,8dc92aa0,87500d6b,222a2473,e10058fe) +,S(905ec120,de69cebd,b9a9d764,e01d6f88,3ebb94ad,af5685d7,6649e7f3,3ca4e0d0,92617e99,3974aa3a,774a75d0,e51c00ca,4d42ce12,d79ab0e9,3a8e449e,9ca9d554) +,S(b1b74a4d,a3578592,8bad0edc,3664c1e1,27d48447,fdb246b4,f15ada68,9b21eeed,c43539c7,b84e9e8f,bcce3823,1322c4d0,c14e4d90,33c4e132,8f5b26ea,9d3206d9) +,S(d440165,c72f2d46,b2fa2a47,1c42dab7,8dcf814d,12d3e025,bd5fb963,3d8bcf1,e0864950,261f5fac,e97ad9cf,fc7683df,fabab749,1d80422a,ca30721f,5343ae3e) +,S(ff524c4f,722c19a7,f7b910be,6d573a57,fe08d5af,6580aed1,de03f939,5053b303,fd4ad4e,5b25aa8b,b3a62dea,b320335b,5b9f1368,62f5f913,98fbaa61,b753bf0d) +,S(effde0bd,331c1083,e4b76a53,c9c1ba43,8fafa2b0,4a3ada44,63a5fef1,8d8d091e,fd7a869c,a75c2105,e6ae5420,86ccef0e,c563bddf,2b41ab9a,ee0e14c3,1d947dde) +,S(a5e746c0,99c8d99e,88b4a304,b583adb2,1115ba64,e409d278,f40c4571,2f3875e8,7f832112,c2af3830,2c4baba4,f073f7fe,84170939,dd9e8c07,fd2c1eef,2e934a68) +,S(6accb9e3,af5ee943,9d8daa72,2fe45513,7df5e274,486fa46a,1ba19093,32ccb431,f0de1658,842d6580,507c26a9,b68f92e5,a3faf108,1fcf5dc4,43ec9dc9,9f28dcae) +,S(c813d055,e40d32bf,6e8e782b,3ef85698,b86f3d31,ed0123ba,1ec8978a,f72b6d4e,baf6d757,2f924631,c4da4191,684c6280,47d37ef4,2bb9528d,28879011,8d068ca6) +,S(8b882012,2cadfc62,44fbaeb5,8be4d587,599dfae6,2fdf1177,38a844d,97c7aaf9,f5e6c293,ac900da4,f716e131,fa5a42a8,7867c8a4,76808b2d,4093c782,6f7a6a3) +,S(8f075050,f49ee582,b54a5acc,4ffaa443,bc02ff34,4d0717ee,9619d83,2d7310ce,13b901bb,7ab3d325,7cc555c4,a4799a3d,f1f9f9a8,6b7021c9,b99a1315,b5f7fd3f) +,S(bbc852f8,cf643e54,3c65fb1d,f2f72c97,89a456db,21c81f66,921d411f,b0374c58,ad08eabb,e7971e24,b2bf604c,fb248b3f,a27e1c2f,84f032cd,4c14bba2,b30a590b) +,S(2d77dc4b,662b55bb,878edddc,9dcc2dcb,9278cc,b1e549fc,ffa02503,1a80bc1f,288bb0d8,4fa7f2a1,ad1a62f4,e76ef6ee,c07707a0,89caffff,a8e60870,ecd058eb) +,S(bc83f71f,f3b4a86e,b9bdf7d9,94bba6c8,c90945ab,9c858b4f,fea7914a,d7ccbdf9,18e91fa3,e5067d23,809ed455,3d119541,fa3c2563,a3a88b30,20d3e49,4b232292) +,S(7d5b9657,8d9b88e6,b0e11b7e,847d0524,45f83dc0,e2bbb7b3,205db435,2c200919,1e689f7b,8830c10d,c28e7230,c569af4c,b1c9e672,aafd4d35,2faf5570,90515ba9) +,S(85e9f364,8d758688,31dbab4c,7460c4a1,51614887,cacc3cdc,1baf928a,200cdc80,7f4ce518,d5045c0,5865224c,c07f7fc3,5ba5e4f4,c03ffa9d,d5f8e5a1,31369e27) +,S(425390df,c1c094bd,34855816,dbbdb71a,9c1d1077,45b1c65d,a101d974,4acd0810,81f14cdd,20ef4d70,69026d94,f09de176,707547c3,8c0f27d,1e277d4f,1f49bc00) +,S(3cc7cf0b,66dc93ac,250d00bb,60a0f75a,dbb59409,bf8e4419,4cedaff6,413549d7,331a632f,c3dbd899,f688bcf9,9df70e66,ae17b719,a2beb23a,664c1d6,1c204a58) +,S(fd72088d,b8a1bce8,8fc923b,cff789d8,9d6a0b2a,2be3b5f0,17e2b3eb,ce70853d,d3912b23,a38819ba,eb329638,3a0bedd9,93db4aa8,df647494,b710dec9,9eaf599) +,S(3e558f8d,5e0096da,4d8940af,9a0baa25,c7318541,c7dd37a6,b72b35ac,efe65060,2a403d7f,69d805c,3ebbdb3e,fba95b87,f78f6431,7fec0dde,7695053d,e660e90a) +,S(70708223,f525f222,16c00149,fe1b745f,721ec32a,90fd0b01,e82f2049,d8694a7e,ef4ad787,f0b4d53f,19d86ac9,7d943b5,fce17d88,6366354b,410dabeb,efd12569) +,S(eca29625,eabffaf6,4b9eddb7,11e4cf76,440b4a94,def9d2fc,6e5e9114,aa414f72,f1f83875,75afa3fc,b23bb227,4c5890cf,f798b628,283989dc,d3538b8e,237618cf) +,S(5b7c4750,542df0c4,c4606db4,6861925a,da7423a5,66d6c108,77838f65,5f297695,42811366,1ae1889f,d6ccb1a2,4cd9a6a5,de04db2d,5e805079,5f922b9e,791f784d) +,S(af1a5fe6,40cb2ee,d36982dd,1e7882fe,bd5da168,8005838c,b379b986,bc012042,71570549,305fa634,a63d12ed,1fcfc8a2,5768778e,863d4778,b7e41215,ad3e6224) +,S(727443a2,46787e70,f83cd1be,1189c4cb,e1e8b18b,1d57746a,9a319676,9366b1d2,86357826,9bba3e89,a12565cc,1770e5b4,4df56ac0,d202fdea,d68928d0,6d16d540) +,S(967979,db34e62a,149e6835,213991f7,ae2c9a2b,abf3d255,6c5e198a,12640b8d,99dc1d4f,52445651,3cee44ac,3bf3d1ed,8547b827,251b3b01,4d4c07c1,fd9edcc4) +,S(794009db,8f3491e,27ef9d73,905b06b2,be56937d,be57b8b1,59dfb883,af203601,5a6ad64d,7ee5e1cd,15a6a087,289d86b4,5db60d24,243917e7,50eca61e,2ada40b6) +,S(87cbda39,6f90b090,dba9470b,1fb0dd1f,d2f4212f,50791511,cf6297e,a9851d10,9ca095f3,a2a4f997,501fb4c9,c5585dc7,fb8f7952,e11cd3e7,73a92005,a41b63f0) +,S(9ed57b03,475d1752,58c20772,1be7e12,cd1f3ada,5b95fa8,4b245b01,b910acb0,d58c9054,43bd81af,85c58a7b,d0cb3e8b,25310644,8e1ef50d,324eea36,a3bbd5eb) +,S(ef8d0a22,92ca4498,2dac77e3,86113363,35fd9521,fd266be7,d5d354e6,28b0402,e55c4b4a,556881da,a4a23e5b,677c1a9a,f2f547d2,e2b4037f,f9758a74,3cb58b6b) +,S(6dba21f5,a274f29d,502d369f,4fa4ed08,2299f6e1,b12f5c75,abd01597,d127e3d9,7685f72f,a0ce41e,8c4302de,3e6e9c81,c951f69d,d2df0f3c,930da77a,51a39d94) +,S(8cdc3ebf,857ac235,7dc1b0f4,26ed2a52,7841969b,7fb332aa,6ba44693,c8399a3d,234dd3c1,915ac714,6cd8724,9b68a19b,df250dab,2748abec,a5876fa4,b7f910ca) +,S(a00829c8,caa665b4,7e3391b6,f4706898,a9c790fa,29344de1,e88fd882,b5eca2da,b7c8fcc7,1e834cce,5884b129,98318254,23486297,6068eaa8,184b5316,fd424110) +,S(5872f762,446cbeb1,4a12e54a,1d4f22d6,a4ed5b2e,eff7c5f5,640801dd,2149ce6a,8aacd3e8,862757fa,1a70c29e,24364ef4,4c37d5d8,bbacde2a,c75a0c1c,28ee198f) +,S(b70ed5c0,5dba7150,f22677d2,e5b532cf,53e7ceac,919d3b2f,ec4cc6b9,2fd34f2,7e43f528,cc74171c,a2fcee0b,18d8fcb,76c3d69b,8560831,26bd4482,a4d28cf8) +,S(4beaa213,3c6161d0,c7da6d7c,8eb09cba,2e8ca505,a790a7d3,9d0c16b,8053bb52,da4c083c,9cbdda2e,c6626d8f,e4b2ee13,703496c,c298bffa,db1acdca,99d4f6d5) +,S(a8d31ec6,53ce1834,a78de363,c5f9abd1,8594b34,4d34f5fc,8a10e81f,5804831,b4d6a9cd,7cbbe370,9edb5601,cb7c8ba4,8c462c18,594a4bce,64f4c286,dac5cff9) +#endif +#if WINDOW_G > 14 +,S(a8f11586,f3df4945,a753c485,ee0fd4d,e410771d,bddc1b26,c9ff10e0,77b915b7,a4ad6f16,dbd741bc,71b2dfd2,dd2d340,3816bf73,4e73cc10,abcfa6bb,d0f161a4) +,S(13e697c3,812d4772,254082da,372892d4,e1a66e1a,eb16bbd4,f7a0d531,c979cb2,87fa7baa,f6def12d,31e42c14,f672c0d6,a9d0e2e1,ceee2546,d65bd01,c18df57f) +,S(3cae4590,821a9697,a5963269,b44f0222,98f60021,b6048b3f,49c6fd4d,8650c7a,e03f8745,60418449,ad97f28,41664745,349329d,268c1c43,86e25147,6e44b234) +,S(6f42f6b1,cb6bbe13,cf081480,766cbb36,9d2e63e,e691722e,ac81621c,66e0fccd,e5d8f8eb,67702ed9,e33c7b71,e3cd7b25,cc9cd315,314815b0,b67e8622,fd35f022) +,S(43d24bc8,469cfdb7,51ca7d82,98727059,6fac14e2,11d37041,370f3bec,90e411eb,2129d618,fb1f7030,9715b2ee,d8e70aad,8b172b74,425cd747,3a3fe40,d7c50dea) +,S(259170e1,d48b6f36,6a281592,3474f0de,434f4ccc,e45126e4,a15c503e,c1f8b97c,9ec06188,dc194bc2,be131217,bb862943,aa9cf36b,7703c45f,b1ffd282,c3c12549) +,S(18d547f0,426139b8,7837d1c1,ca0f5f06,883581b2,c001e8e7,2565c9fa,80fa2719,26d9dc3,e1145ccd,23ae36e0,5c133f6a,5ebaa9fd,bb954792,3e762a8a,9fb60260) +,S(23b5936b,f2dc961f,2fc93814,4c96232d,dceb477a,753253cf,1bf05713,1b9e58be,9b678070,1bd976e8,8d66e740,2c00bec8,e4fbdaf4,976289a4,4391b28d,45519b07) +,S(46de46fc,209df62,6185387,938724fb,702c3239,fcf29113,2807894d,148774f6,cdc2ab0b,5d37a348,1b44de55,d9c50ce5,4322f8be,6f284ed1,ee49f04b,65f4f2d8) +,S(d3b78208,f5876faa,c4d3c970,3a87a586,e897c11f,dca9a7cb,6573c814,9b5d5da9,112ecaec,9f4451ae,23485579,9cfee804,ee053df7,8e65713a,cd43d953,471863e1) +,S(52d51f46,ac86afc,391e6a1d,8ab1d862,2492ae18,b3e86f13,5e42fed9,4cf3735a,cea47627,e7eefa90,7b8bfd12,f3212ea0,bfaf9e00,f407bb4,8a86039,d4815215) +,S(46451d04,48f3f959,e133723e,b9138a73,b3877adf,f294ff15,6303a845,65a4c39a,fd1c4a00,bbd9aa06,afb14790,5c0530e1,d6c3b5da,c9001b9f,8ec76df3,c7bf3c76) +,S(a12f5e51,16c58aae,90d8532a,9182d54,f539014e,e2d8357e,5ac7854,26fc78db,3db94e9b,f37ced91,7c9f466d,2a6db2bb,21725e9f,f4dc1482,3e6e384a,265e0cad) +,S(98999fcc,38fe6b71,97ebfd61,fe8942dd,be944f98,6f139c4b,7bd6bd3,28ac250c,48adfd3e,c348281d,c23335bb,8702cf8,acbdfc84,9ee34a3a,14bf36ca,b7dd0ae8) +,S(8ac22420,f9b9aa05,705b31f,bdb57d05,218ad72,ce09b489,4d0b515b,4e5940a8,37a7e2ca,442b2446,686f91da,db6975b,6f63454,e3a96df3,de8c62a4,364d30b6) +,S(cd0804d7,b1aea00c,13a94a33,f75f3736,f5759080,96a2d418,c5b54c72,de31d619,c7f68576,10df1c38,6e677bb,dd6dc121,b3d9e9ca,e54d22bc,a5ce1184,a3dc755e) +,S(b6c4bde6,2f8fe3d7,3c32e641,573098c1,c559e847,e40f60c3,49d40050,49b0411e,62c691f1,68510458,3e5191b3,758d7e3a,b2cfa31e,7a00d7b,97e39f88,786f9a9) +,S(c20990dc,70134917,42cec766,8b725c26,d918cb46,6cbf7ebe,7b1f37bd,63d5df0a,6f1e71ce,e28b22e1,9c6f180a,4d7a48be,9fc696f4,cfd418d,134c1196,6e285d1f) +,S(ebf16672,45ac7f7,385b5356,dbf977a9,3602a11,40ada114,7face805,dd93f9fb,24b15faf,3b3ac9f9,833882db,b81a976,9a37e6ad,1a4228c9,a4f7d0aa,fcca3400) +,S(1c620657,63199ded,804deefc,c33822f9,cf3d4c1d,72f2022f,37714eb3,83367621,600221e1,48f74ad4,dae118d1,b6dca782,e00117d4,92881c23,b5a7cb79,86cad767) +,S(40b300d0,7520348,38bec63e,f155b527,286db841,754702d1,d512c183,345d492d,29305ffb,31b1feba,abe027b5,f432679c,e265a57a,3960b8b5,a66e6de9,5a10fee6) +,S(5768ffa5,c8b56772,1e10c2ea,421afef5,dfd84120,a8d40e13,751a895a,fccc6c2d,52ee5ce2,e60ec485,7ee62e81,fb2eb118,4d2a6ecf,d8ab7e09,dd728d16,5e508d30) +,S(d906e71a,b6bc6697,858c66d6,82aa85af,e8d80ced,5f470ac0,8158b5aa,4cabf2b7,c75ace8c,74552756,8cad89e2,201dd954,bc6f4ae6,3a671d2c,9bed78f6,40b7e70c) +,S(f71937e,f4553a81,a3f155d2,2f81a5b6,e080c0ac,bd8f5c5a,fd437960,6a63460d,d6e4e57d,422df901,e6292a28,c83c3bf4,136b5700,f6da0351,33099feb,f1228b19) +,S(3c498699,da858f1b,364c464f,b4317b76,5d085393,1c187888,83072cfb,39ee337c,cf3033a8,9749a0f4,fd4ad867,67b919a1,c946dc67,cc46524b,af5c0015,833daa0c) +,S(c416570e,cbc5576f,97090660,438dc3ec,be269c42,6e36fc44,45d53b0e,b2c5d54d,cf6380d8,76e20ce9,5cc181ac,4fdd42c4,b91d7132,d1b1c19c,4cc0db01,4ed782e) +,S(8f97b2bd,344fcf8,62846992,e826f5b6,7fe7d103,28f34231,8a9f7de9,20d71110,e296632,fe41f8cd,b3da3ca,e1c356a4,2424c649,11dcdd58,c21aa1f8,cee07ec0) +,S(6283f371,8e67e917,5b8c1bf,28e66bd8,470dc4a0,1a720a8f,cf1df325,fcb0e10f,5e80225c,87c0d6fe,3432db79,e8cf4365,8640ad4f,21efd2a4,333eb6ae,a46bd342) +,S(9e29c616,ba66db06,bb71e56a,2a049727,e07b83ff,cdbff6ab,898a73a2,f2f9d58d,b5997133,bdfa29e4,431494f2,8444f186,7c4fcc1a,516ca195,c8eb6fe3,f5693dfe) +,S(7a0db51d,56a2b33b,8ab33329,a1d41454,a30e34fc,3db33a31,45c1cb07,923ca061,334164ab,64cdd8fe,9a106f2d,156a16c1,5da4f07,fbd7f1ad,e9d1fd7a,c8630fc9) +,S(5994233c,13ba74ea,19c1c65a,c3653a6c,cef79c4b,bbb827af,e736545e,33ac05bc,2175bea7,3090437c,9af6f994,b33023b0,5fdb278d,c0c59063,eb3b805e,a6b6bf6e) +,S(11e13de,2371f715,4d15373d,d52c504e,50811146,10ebeaa3,f47a3335,ee4e17de,fa961827,b81e71fd,60696d97,17820d67,ec86e8b8,74d3d4bb,f50df644,61f738b2) +,S(787099cb,c8896328,dad08bca,4e682e4,90461574,29aaf740,23795a1a,47f25ccc,1ea5755,bd653ed,ee7ee8d0,b3e6214,df2e31d7,731a1c9e,47a95f46,8c3c8ac5) +,S(c644c88a,fa42bae1,27bec7d9,528cd695,7bf7d906,942baa4e,14ac960f,46469cd,9d7b39cd,22007b04,f61c5905,3a3b7614,81dd45a1,532d395c,baf8ffff,377f2644) +,S(79d1abe5,cdc8b0c4,9508a87d,46163d1f,ada43640,ca1a5e89,d2f1c07,8c58820a,465cdc,983f1be8,948b850e,a9a4d9bd,f3898781,65d5a186,1c94d3d0,3fb9289) +,S(e8d4fa8e,db2a1612,d7b6fd8c,d6aa2f1e,a8f1ba1,32572d6e,dd0826ce,bede0e55,92aa3d43,e944d032,afa03d23,dcdb4604,56cb0363,1fe2f8fc,404dd9f3,f832f065) +,S(6f99e75e,b09110e7,3d5e304f,bf569037,577554e,51861356,40c2c69f,4a92e88e,63b5bf05,c554aa30,261a09e3,b292b9ce,8f1bcbf0,ad91c35,aed04f31,567757bd) +,S(cb089170,d912f8ae,e59f21f8,8860c0d5,182b5252,3b2cdf35,b9795d1f,20c37815,4e8c5b3b,6d79cab9,9f2570de,8c58c34e,6b6f5e19,b285bc4,6988ac86,20e645b5) +,S(5c248793,51e487d3,af1b6d16,b25367fd,9d2b7185,9923c565,5d7567d8,ffd621f0,5806bb36,ac3cca86,2624401c,27c54e90,c76fc747,7e83e6f6,ac89f22,35c84211) +,S(f1d10f0a,2ce54b90,ee71ccdd,eb6dc4d4,c2cab0c9,5cd35bea,5f20d3b3,51d15896,7bdb4d3e,cc613f8a,8fb84d25,541970e0,6c7385e3,c04022d5,82e2efb8,4998eead) +,S(536a5966,b594b460,bd27b4f3,aea6b555,95940f06,311970a0,36dc0fa2,3a274519,c44b0b54,cdb4eb87,b5d70d9f,bfd4a601,5c34182a,31a882c9,880878,7910b3d4) +,S(7f8165ce,ed27a393,41d542e,ba9ae875,554265f6,1c1c56c6,cc0bbd66,2ff88686,6993724,26c18b1b,dd1207e2,f3bcc0b8,673f481a,e7638d5d,45134835,9b4e39d6) +,S(12214607,c610d012,83b9265b,c59d7458,4e0a79f6,8a4e8535,a72809fe,11a6830a,5d26e498,9e3edaf6,27cc4bb7,105ba8de,3344e506,d9bc9a33,8f1e3219,e473e609) +,S(9ad7f097,1d1c326b,8ac468ef,706f53a1,9e8fff25,8e599f0e,72acaa15,b21d58b7,2e7c0921,2199c7cb,da8d3645,a5bd7831,4234849c,41a238c2,a3dd7fad,fdb8a880) +,S(355f75a4,9df69d8e,4ccad41b,1fb0445f,619ba9aa,34697a5e,24ec8e92,f5b41068,9ca83421,4622ad8a,90a09469,d155bbec,717295ec,c071894c,6c91a7b6,e1345f24) +,S(bcde8058,8336a996,fa6af5bb,5ebf7441,ed3bda73,4802ab5d,5c0eac31,8017c706,49e40844,78cf1912,ddc91907,26411814,a782a3c1,452117c9,993d9e8b,4f247563) +,S(372cbbc3,3417320e,21ac4ba5,f286a9ed,273b6425,e8ed22b,d0c352e4,f0a97270,6e05363c,bbbd6b11,8f2842d1,243dd629,247e90d8,4e7c9d02,c3677f93,d1d01bca) +,S(a1122e8d,82e97ff6,ce9fd024,cd4ff32c,76aa0aac,c1c2849d,887240a7,a368e064,ef97035e,1df99943,1139cb88,e03bdcf0,8b3a5c86,d4b42d13,9b3acb12,e4e7df3d) +,S(e0101d71,1d0c7b60,8093997c,229bbbed,63b05224,53c0079a,518826f9,2bfc9d5c,a0acb9e9,c3d3d384,7f2d38bf,29da71c9,af0b5a41,5bf738fc,be24e367,c8db2fcc) +,S(6df3e575,4b62c92,41f8aba4,12804ddb,74ec864a,12076a34,d9cdf9ce,be336e8b,bc66fbf9,276fc85d,767c2155,ef481295,963cf371,c0ae6b48,50140d1f,c32f80d6) +,S(e5794801,97d3eb68,fd859d0a,a616912f,a2a52a7e,f3881969,626f43ae,4ac20586,3ba69743,176c43f7,7afdabef,a06eabf5,94b9d0ec,1114f352,7cb1b127,697a5275) +,S(7b290c31,de7dcb10,177313f1,9a15d751,c128bb2,16823c5d,69298baf,575657cc,9d3b3707,d8f2b17f,e14b6b1d,80c55d14,b747c3e0,8c79d55a,bb54809f,d96f99e2) +,S(4ce2adcc,18632b7a,560bfc3,beb7138d,8ab210de,6cc7f6cb,47171b45,13e991f7,5aa8204b,689d8f69,a42e08d,5ecd2936,97ba76b2,1bae122c,e9252659,25a874c6) +,S(dd798cc9,97530af7,d7ce96d1,a6a93aba,c29056db,c69eebca,f4649648,4942bcb3,e9ed537e,7b679852,88bab4bf,36ed677c,14db982c,9ce8714,b4f3a32b,56609e49) +,S(356f4414,9da655e7,c9ea5a3a,5c4847a9,f908c608,aa492efb,15e7cb00,8b065b79,2adb4e6a,ce059ee,44ee8962,b4aa8c71,a4d55f31,28f56877,6c70c4c7,19fa6332) +,S(b607a62b,c16ffea9,b30f61d9,c711adb1,d110c6b4,357b1e0b,dc71c8e9,4d06668b,6b933ae0,9ba42b06,96419a90,e6579a33,8f4f3fc7,5134abf,70cef838,efc5270e) +,S(77fec5c9,24fbca2f,f564bdc2,96ebbfdf,d52f0dfb,15011792,57085c0a,8fec498e,6c7729a7,c92a6626,44f33fd3,1ad5142a,b521720,24e31308,dc11f73c,ee29d69) +,S(804dd2d9,8014a95b,7fea2651,195585ac,acab7a46,1f3134ad,f2c4403b,3de98461,66fae33c,458de63b,dd04fce8,1c425938,dc13194c,ac03205a,c278c071,918a4e84) +,S(65866c36,90a6cf74,95ef54a4,f222bf9e,3ea803a8,98eebc19,2214133e,9ad35234,8cecbc5f,4a152864,6350711f,c4df57dd,8a2c44d,4133ec17,c95e00d8,b49c62ee) +,S(eaccdd6f,2a9616ed,d6f8c3dd,bcb04c1d,49f0c4c3,8d8c34fa,d47174f9,2323e15d,15a435eb,e23d23fb,2313b59e,2fe0367b,17b6d9d,e900332a,20430362,19c4591b) +,S(860d382,8ccde42e,b27652d1,c159d9db,57a0b9de,f290b071,e93e36aa,f730c53e,b4688879,ef616c7b,87bd37,641e0381,115dd487,d5fa3e87,99257afd,26906aeb) +,S(fe446d0e,8d174570,49394416,9c332f9c,eb47e70,3f214d83,2777398a,dc8189bd,d4cb299e,760ef11e,a3846dd3,9a49f34,4d5c10bd,ba66dccb,a43e3647,718e598d) +,S(e4e6bb03,528f913b,bc34d910,2a96385e,bd0b8aa9,a07a863f,9d5d41c7,b982a578,46ed6885,471b4806,aca3c265,d0c40535,4bd63da0,af35a89c,e8a86896,63d38690) +,S(12d69042,a5515732,8b729ba4,4fc3bac1,95c419f8,ec71f438,e676d722,4509bc56,80d7fe55,52e88a74,a87d24ea,de1f9e35,de5c45ea,b8a9b48,9e7a0b8,4bcf5d31) +,S(d3ab5380,1f1b1f7,36d94c4f,2af00a81,ee1815ed,83dafdb6,ef5189e4,13a32552,691c4594,657c0809,f7b6335f,fa4fddcf,8af5b729,9262f790,2ef12e34,f546a401) +,S(50bd549c,2da95051,7b4c72c3,67074539,412f3b4c,45ec69cf,aed0fe61,25b50d7b,147f8768,515cb545,2f291d4f,5a627f36,5c88b2b,d19457b0,1fa711fd,9bc71abc) +,S(a36bfbc2,330165f0,728578b9,ec81d14,c0417090,e6ed73ac,e8aff550,2ad9c62a,acb88155,5251f37e,f31aca05,bf33f9af,9ccc57df,58692067,4f11b787,8c7c9337) +,S(2be3d416,ca9627d5,9f259f0,1d52d915,9972f50,c391531d,70a6b79f,735e7413,fc0eaf6c,97d11c6b,cbc2722a,b3e821d5,363b04b8,edf2b700,15ce37f2,f70e51de) +,S(7ca7ca3,393a9884,c94430ad,20731f2b,7629203e,9c892d22,ae6df1a9,fa66aecb,c05c74b4,e2580f6b,9be6efd4,379b7631,26d3e0d6,d4e9925d,1a7f874c,fd620f43) +,S(6805c83e,19aad851,6fd7a4b7,e9bbb82e,28d9d0e7,1f1608f9,dcf37a71,3b434893,2313791b,8fc68b18,444cb309,9cadde98,f4c95ff9,88ddf601,ea3eacb5,bf1c1512) +,S(7540f073,3a358a90,80d2b07b,64e179e6,5de8010,6eed4eec,dc8c879a,87d007ab,998820f3,bac2fc51,48b0823a,d20b5f77,eb7acf5c,fb2e968d,2b98711,a1ef778c) +,S(6eb9b5ac,960407e4,465a0c22,8d98621e,47f169f7,61189aa8,f7de2fe8,79daa64a,6a32f21d,379c38e9,229ed85b,33b4a35b,9999281d,f96ecdc0,18d2482,67d85d54) +,S(e32d3fe0,80d92f46,58331d25,f0f2bbdd,43671885,98cda416,7b4920ff,afd5cae,61a8a2bc,aa82c5d1,1e958a0,fbfae374,138efec6,84ea8e18,af1d13b3,5388d1b4) +,S(22a0ca56,c95c5221,3ca126b,65e5382a,5f14d17c,976da5df,54942495,43415d70,4cfbb8e7,7e3f04c8,69e62ffc,edf23907,e8b17a48,13fc95d3,cf307e2,978e0bc6) +,S(ce3aeaf2,dceb0f4c,50120b90,fc027d7b,b5a4cddd,fc337e05,14298873,e3ff340d,49f2b65c,4a64b462,69e93c2f,ca6cdf14,b0c81982,b095ed3,644805c,cf333021) +,S(75251b27,b360b236,9c0cb297,c5f6ec1b,70f6afbd,5af1acfc,38bd765,9c9dd5bf,cd0559b3,9b18ceef,85c15189,fbd7a93,1ceb3f7f,6cc93d3d,7681f564,17f3f891) +,S(9d69e5b3,32a9ba92,17884f7,e7a1ab91,53a65c43,917c566a,c2969f50,accb9047,9ef330b9,d347c93d,a9441706,a502491d,55d27723,ac1138dc,751308ee,fc6b3a37) +,S(783ccac1,f7d6409f,758849b6,f7c4d5bc,401fe5f5,b08c2f84,1e0e3fc4,fd7a2d47,e5c62a27,65ea5ab8,6aa1aa00,9297d1fe,57248127,a5d3c36b,9665cd93,b6255f83) +,S(dffbb444,8362773f,e45e0272,eeb1a8b8,fefee1b5,59a6bb12,b9613fe,55ef33d4,fd539cf6,aacc930d,2ff104dd,405ae6e,e4a6b3ad,1a9a0038,f4ffb4ba,1a6115c5) +,S(cfc948b3,c14d06fd,c528d299,22305663,d7a427f2,fe08cc2d,942528d,dac8ebe3,81ab799e,5be02ce0,d3aece6f,c6ce84ae,988872fc,ab640d96,c3ea6bbf,3e2e709f) +,S(d9fb08fe,6a7cb6ce,721cca32,74e20732,5933595a,e59aa0d8,811008f5,cee83490,2c7f1287,8b6ad3b5,88cf9483,f08a92ca,ccc18ece,93c68297,4d80ae31,54965938) +,S(4272b558,49ef0ac2,d7830183,bfe3cc45,65ab9d9f,32b9366a,b0477d1,ae93956a,caa07aa5,d117616d,9f442b94,40549bd0,f64e7a2e,3cf96053,bd14faab,196c698b) +,S(69536c0d,6404b026,61598e11,1e6eaa4f,e50a2cfe,879b0f74,4df57727,933367fa,aeed065,2c5325a9,53913334,7e4fc4b0,d2583608,c2086bf6,b2e5ad25,261c6bfd) +,S(199589ed,5c4b6e24,65d58257,2fcfc194,60f7643b,7019c02f,8038d04,70368268,c48567e7,ef7a3507,14d1b479,1a70e7b0,5c1d4351,eabacd9a,1d8d5e80,a5da23c2) +,S(ef3c4f9e,53ed652b,f48feb4d,1c7b711f,5526dfaf,6588007d,1c2ce942,86db1f4,128e416d,570c3eff,d45da6a6,31246fc4,f45b7d2b,8cf85a93,22b5f65b,361fc49) +,S(6bc3a126,11ca8f8,3d0790c9,f5b5b137,4ce51c66,6c553ff6,9d103370,3b3d7cc4,b20988c9,4b882f50,a0ba8194,2f168bc8,f29eb6fc,4c3d0149,571968e4,81b76ab4) +,S(a0100574,5ea131b1,4c180c17,f26bd3c8,1bd48ca6,c2310c4d,34bad277,6bf51aab,177551d,299c9ca9,92de3e9e,f82b115e,6d3cea9c,fb276955,5509795e,4870a546) +,S(15553b6b,defdbee,532599ab,9e0de23,b4954dcc,912f49e8,f084ebb5,af6088e5,8dbaf203,351a1119,16e8aeb2,e5eeaade,b0ee5d9c,2f5020,62b9f5cc,ca40cbf5) +,S(ae84a42d,49dad25f,f0a5320b,d6a33f8d,79c9f2c7,2871f41e,f8b02cc2,c469452a,9b23f07a,234782b1,cfa524b1,ad539ea7,b8fac3cd,e9bfb867,799a2587,95a48ca8) +,S(eecfc7a7,a41f75dd,43e2b85b,5af33ad5,f017e0d4,8f9b9bee,f0cf4499,a3c762d0,65526d26,73b9e5b2,8ec256bc,a524e376,f0e40f62,2db6e492,e1c53820,a3180d11) +,S(35e427f6,d0be7dc1,2d306ecf,be9fd8ff,107a044f,81c38c8c,5b9a181d,f4565440,de09eefd,27a8bb89,d8fc38e8,d32aecb,5c6bdc57,5cdf91ca,2f18e926,dfcca94e) +,S(d27cec9d,11130024,7f71fadd,4ace1139,cbe3168d,174c93d,4c756c42,89cef3da,5747fbf8,c4040895,fded5c00,e1f60403,40e07827,8924ca96,2f83b3f,e50ed701) +,S(df30926a,ca9062bd,7bbef9d9,e312a1cc,49442ebd,9994b93f,dc652e68,25efe5b9,8d1ffe08,de113447,5c3adb77,ee5aa58c,593486f9,c3f27c32,a20df570,6ff5c572) +,S(c2602b7b,56d0eb73,ab494934,5eb77e88,787e54c,79558ea3,dafe3f50,84f96682,45885bf4,65996b12,993efe44,39861b39,84d5fa89,5242ea8,f498695,57391182) +,S(d6d606e6,28c55e08,61a37803,72c17b1,6a2fe04b,e68a0cc7,60fdf7ac,85c8816c,76b299fb,9e716eed,7f09c879,ea8256bc,a953454e,490edabe,c90a2e5,dd277da8) +,S(d1bb671a,10ec5393,9d67f6aa,3b09e1b,57bb6414,e1f707dc,b832ff67,56289c4,47559cac,311f20cd,55760ed6,2e1e87ac,cd8603e4,c1d0cba9,79f6802,6b294a94) +,S(739ab4bd,6b6132f8,2659fcda,5fb46836,7adf2133,37f897fd,70a9552e,786dcb91,b562e798,2bf508ba,1b932deb,3e6b5962,70bba4ca,402db3b4,d806da6e,fbf6670d) +,S(a710cd7b,2aef0005,6d8db954,2abe6cba,2a6c6132,a48a6670,c501fa82,4de21388,4a6037d1,87db5b52,2996bb0e,47fc7509,1ad9eda8,e15faa56,92d56006,e72fb220) +,S(cdbf59c9,b38e40cc,d63b36b8,b6e894a,c6baa22a,93a1382c,9d7fd070,58e69b7a,3e836c78,6954d509,348314df,8ce08f0b,59967aef,4e5f0136,9c6d0f91,2682d77) +,S(1d32e93f,6e5e138e,7d226636,d5e0946b,8117f91b,bd59efb1,560a15bc,657e4dd3,82c43daa,bc1e23d6,3632e167,6bbca422,9797551f,f729cb5d,c8ac1460,46ed20f7) +,S(2730066,cbe72e84,304e3563,a18689a1,c6c8e0b3,e92d8c0,d63a96c7,e3573337,8804d5cc,6aa91f7a,1ae23506,17332f7d,811b8f1f,752fea43,5208b770,94e67c58) +,S(44624ea,a1607e8b,8bcbd736,9c67f86e,6b0f5226,4cc76a3d,b40042cd,bc621cc4,95867a99,d110d9d9,e382d3d8,a5dff78c,d8db012a,972a87ae,ac24bb42,b2747e53) +,S(8ba805d8,864774eb,4494ca5b,f8257bf6,980466f8,30028340,8aafd665,7f1ef49e,1a1164e3,c1b243cc,57507b07,7348495,95cf67c7,b40d4d7f,f10ad096,3f3866b4) +,S(297d0130,25bdd2d3,f4a008d0,d8c51a3c,7b16b605,95958d9e,93e427a8,7ac01267,56361e70,22138026,683b7bf3,1a6bedaa,988d3938,cf8399aa,e0f3175e,61d7e2bc) +,S(d866bb84,23527208,e66f34bc,e26a8ac0,daea9d03,27c9dccd,cdf0e2a,a0588f52,5e16262d,3564736f,30f26e68,1c5ea26a,b6f63429,f0b25dd2,5635a3b3,1fc45584) +,S(ab1e9d8e,b18e016c,d8ec49e4,388636d,5dd2ab55,8b3dbaa2,433a976a,ad8f16a2,a14cbcec,6327451b,15d47fac,d3f3cbbe,fef828c4,6ea07a0a,9c7155cf,2a2f291c) +,S(cf2f035a,ce393efd,3032cb05,4f4e92ae,5311dd04,bf8f3653,5197748d,2094cd30,75b38e90,9f02bb50,7a778243,35a1c97d,75bc653f,c6dcffcf,615bf8c2,ec6b32f5) +,S(a801d552,e63ba120,2c3ff08b,8fb025df,e545ed35,1adf00f,1a08d982,9e8bf9bd,bdb9274d,f5298fab,4cb08f42,252639e4,a24b553e,892cd1ea,93499c47,41c23165) +,S(f7ad7a63,eb2b90aa,3de2a80e,844e5336,287984f0,6075d9f1,26f24108,f4a5869b,d151e7d,9766a81,1db45134,7cc22654,c5ac40f4,a1d82d96,2de02c58,d46cda31) +,S(732541be,26fcc3e8,c824d539,28282611,96717b00,2af01bc8,57f4c0ac,cded0a80,d44adf28,f26370a8,3c9eee24,4e870dab,3fa7a508,bd14a56f,17c9a845,5055f8ca) +,S(892ee5f2,a5266a86,5bf2094,14c31225,b92dffda,7a3ec00c,ee53dc0b,8c3a3367,21bef833,3b983665,7d243b85,c0b4e2cb,6a5b339d,831cfef5,d676c7d8,87a0df00) +,S(1a4597e3,77569fed,70875f9b,f8f5531e,6bd3b363,b96a345f,9275365c,e1e64424,bd142738,fff7b9db,cbff1c,93a968b1,f0ef3e63,8279b745,21aa53a7,6e611f7a) +,S(c7306404,4b4a3a00,6a584193,e915a174,631c8a2e,ac45973,c815a2f4,aee82f35,280adb29,4f9642cc,cbcc4345,28bacdc5,74beb7df,84c06216,68cc2fec,d78731e6) +,S(c06d9d55,264e4ea9,e160fa78,78a7e4fb,1757f6db,fe610966,503ae03,b4723f2e,c0d82600,ae072564,b29373a1,ff1a036a,45f68f22,9d1594ad,1c9584cc,ab732743) +,S(e878c0b2,bf38b500,6c309a51,5121a3c4,5b13440d,74ff6e27,5bfe71d7,51e6926a,4b8be149,11432ff6,c5169731,1c1db30b,c921cc95,b4c98a39,5228c08,b99b6229) +,S(d1f6621f,89ac4421,7ef39a54,a0922c77,dc7addf4,78b15796,2558ae72,9b24f65e,657556fe,e02492c1,97c9c97a,67bf1d6c,eb689415,80a1ce6a,1e4d98d9,64902f3a) +,S(f9199ae3,ae51f441,d88d72d6,9c1ff64a,d5cc4979,b5fd6a23,c514e9b4,66ea0a5a,3c484bb8,8ec31009,eb95b971,69c7ae03,c20dd833,eef53cdf,fdab8cd5,7a82d4eb) +,S(4e059bc7,516d5fe2,510ae63,d3ca9543,f840bff5,710a744d,62de3965,af6a657f,222309ca,242c5858,5a792045,bbfb3e55,b61daa3c,afedd1ee,19a0038b,f929a47) +,S(c1673413,d8b4298f,6ca04741,a3c32d79,83a7d5b3,dd39ada2,53013d3c,9750ac65,333b1660,7b998e8e,fa7e3d32,2d51c052,1de24d3e,9e389f0e,9a00015d,6cc32d54) +,S(c078723d,8abfbc03,63f12766,cf9c6261,9c31173,5f3a9654,b653a8f9,e08f551c,880fa5d0,be09cb8e,4f145749,1c7f54e1,ceef1477,ba7ed718,5f27013e,32deb89) +,S(c77f3351,4b44b047,3835e3ff,abe8d7ac,ae5f912d,aea4e6e0,4ed03feb,78c41ce5,cade531d,26ee668b,5e2fc7ce,421de2f,d9a14dfb,87286c22,c840144e,1290e910) +,S(90e14c45,4ba40739,10f800b2,bcc7b017,ec58660,bdb1e72,16cc6afb,8320277e,61dfb75d,f5f74d47,287f828d,c4ff46d7,fa351a1f,66da99da,40e74758,2c6bd4b2) +,S(34c65f34,23f2474b,7e2f294c,ed4da6b5,c05d19ef,a2b5a792,103b681a,be1a3f68,d0fba1a3,b12d3e4e,f18acdbc,68fc285b,8ef1365,6aa900c8,c86ae191,37f028ee) +,S(fdcc63b0,aa5017ce,215735cc,2802eee6,aa5ef53a,6a258dd7,a128ed7b,9a5df38d,217ea863,5c9b88c7,19c7f9e6,1286844b,d4f4b758,81535954,7b24df0,1fd5bf03) +,S(10624260,58bb9f6,a5e83740,59595ffd,e7013492,4392c753,15853f4d,9c7070f8,84a92509,e809874f,86e60bdf,85c75d7f,2cab596e,185f56d9,262b06e4,e79cf785) +,S(e21f29c6,70cfc7e8,b104921,bb524414,53acdc5f,fd80066,39417966,ca235c9d,41be8bdb,969ddd53,9093dc1,b85dbd4c,a78f7e68,67fa916c,36136d24,b6c4af38) +,S(154a85d8,60b532cc,16bfdcb2,2769fdf3,6dac818e,cd2daeb0,864eee0c,f78a5c5b,15f2dfc9,3e5e08e4,9d340ce4,bb805afd,79f940dc,f97456eb,c73b47ea,5098e429) +,S(ae6f8b12,d52907e8,4ae5063a,114f8e2a,da7be317,454ea505,571f2132,5e4acf42,49376af9,1aea68bd,cdcd637a,909b639c,b7ff8800,ee003fe6,540d6797,f0f296d1) +,S(de42ac26,47fece4e,69341582,7e3c5b7d,a19dbbd6,22da9fa8,58a3be29,8a47bb65,e57cc346,b83b33cb,79a34805,42811d1d,4178805b,a2b88de6,d90b4fe0,ba8e2740) +,S(14c2030a,c65ec50d,2f7c176c,45256587,59cae0d6,55cd57c2,c1ea970a,11d7bd0e,f3d9f0f0,5881801c,ad4df439,3a3bd2df,1a045181,af7ccbe6,7500b02f,61edece) +,S(32fd40e4,7a94e51b,e4c927c1,42b5f470,b2abd2b6,2773934c,a29a5ff3,924b2e8,b3d74958,f17147e5,1da38ded,7cb09c27,96b7e36c,3149d85c,9b7db85,acd89bbd) +,S(fe468154,cef5383,4820fa33,ad85c158,33635cb4,a55870fb,f588fa6,b8d2918c,96650453,25235606,7bcbc214,b0a04021,bc71c9c5,4617b1be,dd34e6cb,dbb42873) +,S(57826e08,8fa3841d,a33ad3da,e5b5a688,1ee770f5,bfe45f5d,507b4801,ccb511d9,6cb01dc4,4da6d83e,77a6e8a6,d374275e,7d8484fb,4863b5f0,34bace60,30e6b3be) +,S(61bf08fb,1d537624,1dca6119,19f0dfcc,7787090a,6747cdff,8757b037,a1ea59ae,6bcc632a,f4f43c6b,547e6ac5,5854268f,1801614e,5bc9d4e6,ea0dcd99,79f7adb1) +,S(f54dac2c,b5521855,9dc274ce,25b77645,6525e91b,c011e657,5ff812e8,d846ea4a,bb9734dd,af492c18,82bd36fb,f365009,bd41b8bf,1378d9c6,a18477b9,ed627f11) +,S(640ebea4,b85cafa0,d5a38ef7,7373bfb1,36b9571e,f9694724,680e92fb,13efe03e,eaf8d756,c70ee813,60dadfd9,702f660b,516fe3a8,4c50043,92bc7c1b,892a43ac) +,S(6c4814d1,e3c6c16c,366c8776,93b6df4e,266b45a4,26fb0d5b,a2d8fef3,a3803975,d9330c82,8fb02d63,33d57990,b6bedffa,ccd143d5,1b5eac78,5c7f058f,af77a37c) +,S(8dca10b5,95293452,7bd2f264,6170b6fd,59d636a1,f2578b6f,cbde0c96,8bb2db30,50da6972,64516689,57d2273e,55dd046f,1c398d1b,9e5e864d,ae6746fb,825ec83b) +,S(1409a8cc,34389c3d,3fd1b482,fefdb25,3ba32070,dc23b7ae,6b8a1ac0,2f00b776,f8f1c0c6,3bef8011,27ffaf53,d5c07c,430566e2,6c4a9591,f92d694f,82d7a9f8) +,S(1c752b3a,2cdb6257,fe8bb102,e7560b8c,6f86e7ca,e809892f,58df3b16,728c0999,9f1341ca,61dd07f8,882596fd,12531577,d09fcb45,5a086b0d,17dd5390,8326c741) +,S(ae8bb1ae,a4341bf4,c18e7d99,7bc3ebb3,d9f13c9f,b01b93f,885cb32f,d0586999,92eaf2f5,c4e231a6,851a2324,a146400e,6b9eaf63,8eca473b,9d4e034a,3d5c8e6b) +,S(e3d2429b,ba45b4c,2d9c9bed,45f384a1,7d74cd28,56c87772,6d9a98fe,67bcef97,729da85f,927c04e2,c1db1458,c133bdef,c454d0d8,88262b1f,418f3420,5df2380c) +,S(858ee23b,e5166c66,b99d48dd,24cb5078,fcad23e4,a8df9f91,53ffcab2,fb8624b,c5088132,3af436fd,c4f63b91,b06061d4,b26fadd4,6bccaf05,bbe1a8b7,338cdbf2) +,S(7c6a82f0,e2d6c5a3,ba37be0e,1bd8d4e1,99f9aa3e,c9c58054,a66099b9,a4938a1e,881916a7,87e1f9eb,b38906c,c101b0e6,5d245fb7,733c0093,9a7f6f0a,9b4d113b) +,S(4c980c4c,144e4060,c00e7476,c782cb83,42ae8b02,6a155904,c29837b9,fc25caf2,fbc05490,a62e49f5,6daac9dd,5c730f90,183ee565,d62ca949,5bc7ce56,61c2e8c1) +,S(c9b66a8f,6c163037,f5bbc7b9,889e9cfc,357ed5f7,a5e5cd17,6a7e4bd9,6da2fa3e,4eb8b3e5,365a6a44,4b277b4e,89b89e04,2b44cbf8,b73f183d,42c9d8b6,547885d3) +,S(f2f8fb3e,2bd3cd82,99e2faaf,bd5809f0,12190658,b1efa389,f58ffe28,c1056fbe,db6c4cac,35f78015,8fed40c4,341a93b5,64af02c0,12d4817c,478726fe,4faf8273) +,S(8556c286,895b9402,283b5d2,f90ec950,f91c4dbd,6c1c8a0d,6b27cb8c,3bc7da8f,f2979daa,81ea79b5,d3ee2718,4aff3805,9bce1bb7,fa36cc53,4d139b83,c176badf) +,S(4d4c2752,5f24a7d3,ec3673b6,a3c8f110,f5bb5c5f,e9675776,3d81620,90579267,43ee95e6,5834075a,83675a88,15babeb9,824d4703,763b5b09,8c3aff78,837b353c) +,S(cc6689e1,d08b243c,a49a7020,b08ce4ad,817193c7,456fbf4a,97fca02d,f1ccf2e6,32f00dd1,1080c238,cc7e8c9c,60a1b7dd,7503417,2ad0464e,1cdb4221,35ea580d) +,S(966525b9,26bb6596,584cbb3,5da78cec,e6709134,700974f2,6cff34a1,23fba535,b5c18347,52894cc5,26336590,d961af5d,2453d9a3,40bd151d,259d8be7,6c5a9e7b) +,S(df7f51dd,b0e6c595,c8f3de9e,eed5da8b,b05e2cf9,a4555001,760888e6,38b11c4d,19759148,2d4f49cc,b69ef50c,a1cbf3a2,49e3958a,aa9af2c7,becbb72b,8d53f8e2) +,S(4ac2754f,93745ef5,61d6d213,7fd2339a,81cfb619,b6699d9d,21897ed,975f6fea,854a0153,17ce38ef,e070da13,c07829f2,1bf50d40,6458109b,5700a3ec,ed6a3c0) +,S(7c062917,2c59c7ef,2d488806,b1131193,b6b6f0e0,221d1ebb,eca1b358,43959694,77f73272,291c1c73,5d79857d,60cc9db6,b6128e86,4613b3dc,92dd970b,d5dba9ff) +,S(c80152f1,e4b7728a,36acf22,158b8215,d8ce0ea7,401274a2,1139dd71,59d81557,dc0c54e9,88d2ee7d,e8a56eab,d358aaaa,4542a45b,a170db58,89d634f1,dae95df5) +,S(9c2352fa,464cd430,31f43578,53feaddf,7d5ee143,c6403ea1,230961b6,377423c6,841277d5,71934bc0,20f71b36,dcba2293,65819fa2,b20c57b3,5774a524,d6fb20d8) +,S(8d7554f5,fcaae19,cbc20c7b,73f22f30,aaeba42c,a22bef77,3d780205,8c8e1d7a,c6bfa4c0,9db5101,d33abd0c,47c4e125,bffab86b,8ed50864,6b6a2b0f,322bf5d2) +,S(1e75acec,28a2ce98,5929479d,e0842826,bd556b56,6961d5db,66c9055f,b1b63635,89cbe475,d2036dbc,9227db67,d62b51e9,ac669a22,76e4e1e9,d0be9b1d,58efca6d) +,S(9fe62187,5e71bed4,7d9f2d79,91e76b41,88b2c8c6,10f20d33,5b38bed2,eee85236,9a3fe290,fbe192f4,8a44177d,4f0d037a,fc6fa8b1,c57032b1,3d5894c8,c426e8cd) +,S(8dc1710f,8869b645,73c361d1,ada3f43f,6f2c175e,b24ec358,6409e978,1687a220,37a4187e,bce1845,9520b60,9317a4b8,f33b371f,1a768ba1,96316f41,373ec87) +,S(71ad2a17,5cf75568,214fbbd1,f177c1a9,9eb75486,c161f1b7,ad47063b,567e8d6a,29d80786,e42d9cd,4c801f96,a7d44eda,5e325acf,3b82e143,2576ff1a,3b334850) +,S(be0eeb11,aaab9c1c,ef7a2004,731e3ca4,435c8a02,548b36b2,db68ea4a,56ad8b7a,cd7ad5,c9b7e867,1a1c7889,95e45cff,bcdfe42a,6222e0c4,1054a0f5,f7bb00f2) +,S(364154a1,3a7d9fa0,b349c6fb,ec36ea43,51cdabfd,8fa79318,88e4ea5d,ee8bf6d4,40b40474,7e8b30a6,a3cdf3ba,f0956fa5,f7f61a2f,89a8cf7e,c2ed7445,504a71ee) +,S(19daf7ab,c9f69a31,8b2cf1c6,69d50532,5bbd7254,c4bc4126,d7b31dcd,e7b558f1,6b740772,606874b6,5b1f819c,c7339ffa,30669d9b,2770506c,e9fb243c,6ee4a925) +,S(5ab3dc00,eb9efd03,ae491844,50fe176b,765c5da7,d95ffe6f,61aa0073,7366c918,2603f1ce,935e3af8,af5e3d1d,d76a3410,200037c,87c17a93,96e11018,260dfa01) +,S(47bc2c3,d7dd83f7,2b2160a2,64640e58,16316d0e,3272abf4,b859dd0f,6c7b27d7,1ceefb1f,23dc61a7,2f663d9c,3cdd6625,441a63f9,f9cae8d5,c4ba88d1,22c0f258) +,S(b220435e,e903f1bf,3b443549,5a01e739,250be2c1,43f08a73,bd7dbfcd,75602ab5,3659abe7,953b817f,fd1c02b6,56da4e54,9df250c0,7c28e9c0,89ba315a,bf25e1dd) +,S(be25604b,d52413fe,2c743031,98aeff78,c27086f8,97fe4b20,be5b6251,52fa2fb4,ebdb5191,aa195ee,a0a39bf7,399bbe03,76073830,fe54cccb,a3194eef,d8d34fe5) +,S(5cedfbfd,633f16f7,8ec8a8f,3dad7cc6,edc1a6bf,3e37cf3,65069731,64aad0e3,70e687a9,d8632ed6,ab188f14,229f2e31,34a3adc8,727c7b0a,d7a16d78,1244c9a9) +,S(8109ca32,a86fa712,690315e2,1bc09265,bb6bae74,588f507,1bedebac,47e54a3a,e7f3342c,6e8a3dd1,f6d02bf7,5610511f,d0cffb40,1c14633d,308c2939,e662cbf2) +,S(54264a0f,dfb894a6,b29b6922,b859d715,77f0359,ef825442,e0d43b79,a0fbfe3e,4884ea59,cb88fb60,4ca4de66,110b7d98,ec529112,d4574cbe,9a2e7a5e,5a4a644d) +,S(f2756955,a6a7db9f,eabaae3c,844cfd37,5d86ad8b,a84dcfba,582bf4a,273f90f3,b24c14a7,d2f60103,a7d3652b,c5e68988,390c0e67,1f0fca22,ed927f6c,96302239) +,S(351da3e,6ab7c98e,840d0dfa,e7231d21,ca21a81b,3638371a,673892d2,e40498b9,e1c5ffeb,43b443ab,d31332bf,aa314fda,5a4c2634,afccfb97,67bceb3f,13ed5f3b) +,S(b5107be0,90f84c7a,e3d89782,c6751b22,f9a7ad2b,3a1810c8,f14bdd8d,52344357,3d5571d2,36a7c9a1,aada0835,9e8ce162,c46a878,5e09265d,bb52b419,144c5b6c) +,S(b6172135,85b2557b,7c253189,9422c428,79825eaf,64d8e8e2,2f7bae12,31c9ceb7,dbfe3609,df9b8e1a,33629219,eb241daf,42d8be2d,b9a20a0d,942f24ce,1a117e3b) +,S(5eeaaf7f,577b445d,13481c9d,a567825c,f0a5a3f2,9ccfbbbf,d8f1f8a5,36e712cf,84a4352d,c40556ff,ab75acd3,b5a63366,39119d8b,f814feb,e55fb3ee,dea5821c) +,S(c1bec874,44b0210a,9a86ca9b,94891d00,e1fee6c7,490aa26a,1af61f97,5dad1c13,14a61af6,d280ea47,433d795,1786351d,f90a9879,7678781a,8d9d8884,e88a06a6) +,S(34787098,f0df9eb5,e4825449,6fd7eb6b,3118dd45,aa0ccea9,f606a794,126b9ad3,85c30ff1,c8dbde4b,88fe9ff8,20c9908a,a35a0c53,c2175524,a5929eea,5566a564) +,S(6599b07b,5d31c19e,ee02e287,ccaa1bce,70890b14,cd739140,6f1d862b,39d794a6,d18396df,27e6fc21,a9c36a1,8d8f73ef,c79e6c56,ecbab9cb,83750220,a816d5ff) +,S(27b50b15,c92c010c,60feb473,5ac6ae0f,9ec0af75,81e41a90,a3a940da,a1a44ee8,31c2c3c8,61e64b7c,df8ca011,bd4002ba,5373ec63,8c3608fd,619bbb92,3552c1b5) +,S(40aed5af,953f3a17,f5d17622,127f16bd,4cc5bbee,33e23443,5f49c4f7,a48e7a32,e47011ee,96c702a1,1eff428d,2940ddab,d17b76cc,6765d5ed,126876ea,2496f6e6) +,S(cb56977d,f69956da,cf40909b,69fe44c1,4a5ad547,a025d684,c9815ff1,b5331ef8,9904de7a,9ce0f656,2f025ffc,79e8b3a4,2e410ad5,8f0caa16,62a13e29,f0b00bd2) +,S(11dc40ff,58c6d2a5,9768a776,41c611a8,2aa651c1,15e9d36c,bd3ebd18,ac7a0df9,4717af95,274f820,28592bc7,4a84e467,9d168dfd,826a292,5789edf4,a06e0e50) +,S(3baee366,3d2033a7,f3170bd0,723eded9,2fad6501,702fa530,b26d0623,8d6992d0,47497025,41900ac2,fb236a26,81ca09db,c34fc84e,98ca289b,63e07d17,2e4671f4) +,S(6b19e8e6,b2010e2b,d461d716,66f691ea,88417df6,773208f5,18ee5fb1,e0fb580,a7c74380,9f744b05,99b6c4e4,709a8b86,241ef931,effd9323,9a6d15f7,22916578) +,S(412a2c52,b31158ab,9d3bf4ac,d4355eab,b7e94e98,6a839681,94a7322c,72bff9f8,c649c493,b19b713c,8b3c4e30,567547ab,472a599e,cc95ea73,d36d373d,c92f7dc1) +,S(b5e0c57b,f79e7364,9826a818,bed1d521,3cb88645,5dc91a4,eb157a8a,dd869c24,752feebe,9614e233,3b876297,175078fe,f9adc63a,4639242,6c88ca94,aa06163c) +,S(f656ab08,9e75bac0,6eaaf373,1cc71347,6a636347,35ab57c0,222589b1,e914160f,d05493f3,52b660e0,4cb00b45,5cede6b1,74337488,dd1650c8,4ddeaeee,b73a6ae9) +,S(bd2465b7,b5af290d,2d1157fa,76e4550c,ddb23922,7d30c255,8f0cc3ad,ae5fa32a,63a28c79,cbb50c21,bcfc85ab,269090ea,d56f6396,1fcc6dfe,b3a000e7,3284880a) +,S(d53c8d24,3dc3600d,fa32dd69,11a87ab,722108e4,192d7cec,4d84eefb,9b32a351,af681092,6afda47a,ef5bc91d,97f273ab,78a21c01,64f59c0c,ed66f7a8,5b67ca24) +,S(4a83ae18,ab379d5e,f6cd2be,77f64abf,8fc23b52,edc88ea4,9efc1bfe,402432c9,e9eef9c2,f595ad74,abf10b85,6ea24ac5,603d46de,c320f9d9,a1453be3,92eef8a6) +,S(d1df4416,dc7cce22,832f9ab0,b74d927b,f9b3b7a5,c52acee5,3d95812f,f26caa82,9e5242f1,163a863a,a5702af3,cdc21f7d,b0143f76,ddba2a2d,d592676c,57c310f) +,S(e6add3b2,583addd7,8299fd2b,14b87155,93dcb13a,3231458d,ab6864ce,87b9c890,384bb2a0,930ecde4,1e9945f6,247a6530,58e26bf6,88226c8f,ee9a1ec7,a1f07740) +,S(7d3f5447,295479f2,96c11443,eb9b1fbd,fe81a258,78ce4195,d2f01290,7e01fe4,d12e4fd7,9f66a45b,2596b066,651d8686,83e62627,95f681a4,12022046,86304ac5) +,S(60636a7,45442fa9,57f21668,7fbdde4e,a6f7f80a,ea2832e,ca3ea43b,d1f12709,395ef963,bec2979c,fb211f8b,da3f4b4f,2c129ce8,26a35367,d955243d,3b40022b) +,S(6bce0837,39c04ba6,b9dbba8c,f668bea9,4d8a8b38,2ac17b87,765bdd52,86e47963,a2d85e2a,7ff5c433,c2c77363,666ddd3f,3fb28f8b,2b7aea1,16a8f42e,384a0a37) +,S(59e4e7e4,438ceba0,cad5f146,bc127c1c,df7f4735,f581a0b2,6a53a366,947d4581,32207f5,95fa4cee,3c8ea269,9578b28b,6290a3c,33eb0ba7,e3bf7267,b2bfa445) +,S(ae2cb18,d4f053ea,3a497162,8c822f6d,72806f79,bd39dcc8,364ea256,f30af032,583d363,b9ac6fd2,709985c5,79603d9,4902da04,1563879d,245433d0,abc54a1) +,S(bc4eb578,630ebde0,f58fb192,377de006,c630e96a,51219379,43e9a240,c30951f7,5224d403,4635eea8,e63b9e87,2875f27a,129de5ff,fae3d516,5f6d0cfb,5bb7e584) +,S(848ca19,6fc34e2c,e484f74d,79565ba6,9685128e,7b2d21fe,8cf0e4b1,edbd3b13,2a41e449,532de110,e0d3fbb2,bb794fb9,32d0d4a6,33aa65f8,ec40e5bd,5c4314ef) +,S(b90e1d09,4257ae30,bd12debe,648d4cea,3f063740,e3f9d3fb,c67eaa4b,8ca0bcfd,5604b475,31b28a6a,e0a13a47,31f6cc70,de91d429,d2204d45,e1423652,5a5a4b43) +,S(430752bc,3e1191f3,6e084f2,5f3e30b,da104f40,1de93267,62dde1cc,39d94c71,e707daaf,841f62f5,6d9c45fd,3304e616,30b6af9c,d6871476,6132e127,40f5ebe0) +,S(ab919243,c8bd75b9,d67f331a,b3b487e0,ee9c97ff,c35de7b7,e29827c1,ab643be2,d4d853b0,3971f1fc,ce365db9,cf4a54f1,5e6059c3,c5138b2e,dd765c51,7bdc0c7d) +,S(adce8be3,2277c2cf,6ee46781,f1da8f30,1cafea51,18322adf,8d6b8a29,fc3f7551,e819a7fe,73311592,bcfda0a7,3609748e,6c039066,feba9e5d,41e125e8,4dd67fb4) +,S(d6ed759d,15f5d47a,146e7fac,423b952a,5eabc238,a0382762,c2a226ed,8c24b601,456caee9,1c212f19,acdc2d82,9eb90cb0,2ac35a72,8d280042,658af65a,b6840e9e) +,S(3583bc8f,c3ca09c6,6f2f4fe2,83da5c47,f0ebcccb,fe8e94ab,fd315173,fd3fb2be,ed60aa95,504e9b31,81225d0c,a4f513c6,6da2a2ce,9fa9afaa,c12e04c4,f1d50b59) +,S(223879b3,b9e50b46,7bceda29,905d09be,1acb206,5b23a61c,686d6f39,bf0744d4,a8326789,ddb38afb,e993ae33,6cb1c3f7,92addfad,e47663fa,52a296a3,b6f2873f) +,S(29329ca6,c6ce20b5,81a90873,7206d44a,95ff382f,1ca0cafb,755a3450,83883d69,5d2aa87f,59e13a0a,8ca4460a,4db7f496,1c118ab9,b4f783e1,305bf43,ed44fe71) +,S(e1c6a08c,593454a4,aa116edf,13345cdf,6dc00b1d,b63b7a64,fdea70bf,e4301ea,e0f9f3ff,5e7e395c,42b3e093,87b8363d,37092335,31c317d8,1b61f20d,f06fa662) +,S(da098bf4,133f656d,f2a09d95,c437eaed,fadb4c9,8102d164,b355c7c9,38e65216,74ffa0cb,1fe7f0af,8a1a6ed0,531f8e98,28be1110,90b580dc,5ff55fe7,b75d9b66) +,S(f3f7c27d,54b40dec,5b3da04,b2cd222e,1507aa70,bd236bd4,2d6e5c95,c71bbe7c,80e17f04,7cb2203c,cc58c364,d77e9a1c,8abb092c,18a9f8d5,6edcdaf6,1ae4062e) +,S(466b6e28,8981fbcc,92c4ec3a,a54eae4e,2e266041,5b242aa5,523579b5,b1fe93cd,9ae0e0c7,d056b2a6,831f540c,67a97732,33bedbd5,bdcd2904,2a8987cf,1fe2a86f) +,S(e15af336,8c59576c,a36b5f80,d9ec0458,d9534bf2,6650cc26,a2079946,ac43fcce,7fe0423,e6ea121b,308d167b,ada98cc2,fb8cd772,f95c3d84,c1907f09,66e5b46c) +,S(c20ab235,6dfe247,d8fd1a9c,d8c4f16d,a5322bff,692efe70,f256521d,1b990492,3c0aae11,e4cf9a17,57feb324,e1a2f0e,48d5978c,6007429d,ab32b2f4,d1a19bd6) +,S(d8b6c190,4a848755,f126651c,d96fe374,7c5a3744,1fb7048f,e15c4693,dbe35e17,fefb5310,e7e38891,70fca6ec,61ffd2d3,72605ed3,4bd22d73,c852a92c,c22fd30f) +,S(a8256823,5416b18,a01d2df0,f47757d0,f42c26e3,780ae6ca,2421aef3,83361f8f,c9192412,77948b80,87d1c45c,a95224ae,5f9c294d,fa74c1ec,42ad6004,f8646540) +,S(28f2a237,c4dcad5b,a6bb5274,1e743020,e90bc598,8ee66b39,cd672ed2,ccac6c33,416c59f6,c1b1b036,f38a5523,722954eb,52848872,8ecfac4b,5bfea63d,cfc181db) +,S(e65d92b7,571bbea5,4e541862,a4dc7890,bd546782,bca886e8,3c1ea17f,33d77e9f,6116ed43,13def2ae,6b0f2b92,ff07c91f,4139982c,12511152,fd7ed5fd,851bd04e) +,S(68adb9ee,c7ae0198,726b0457,91fe52b4,b5c2ec78,4199da86,bceac230,d55914b5,41ff0808,e42aae9f,e93ff704,6f08fb38,4b72d7ec,7b1dc6cc,e0071306,7ee5cfd5) +,S(3f0f7d6e,6bf73a97,40eb842a,35cd4800,85db4766,f7fc374e,1ac915c0,e4d6d6e2,392aecf6,8b446346,2d37a106,8299a09d,9ceeeaa4,f0ee3397,dc54b2f3,5e3332d6) +,S(929aa2ad,48a1f3a0,24fbf7ea,70e9d57b,9ef65afc,b3cb2d8c,5041a933,321359e4,b1cfddf3,4693ff40,ef16d8f1,8fd1fec,a71252cf,ee13ba4a,16094c20,3b4fbf66) +,S(9a9ff691,f16ad46a,d0b753a6,fb09025b,e196b443,839114a9,580eb2e7,fc494e2a,3776f83b,92c135f2,5e5e600,27f65e2d,582fa2cb,f5842c3f,644fb726,1e305c67) +,S(6752b226,65900d81,47ea6b73,25b212a2,9bcf899,799eb1e6,213857dc,6959d32e,fafdac9c,2f791be2,d1cfa78b,7530859d,c1b2ff43,e546de14,1f42baef,3d6d1371) +,S(9fc32749,e636e845,aebfede1,1d0928a1,8cc6e3b4,5a2536a9,fae0a2b,ddca6434,9021fa85,56c5fe05,cc87bdd3,6cebb00b,3d1b77e1,80ce2f8a,a4d155ee,84fc6441) +,S(60ca338f,ff905b58,b1d70d5f,89c4cebe,15600495,698b262b,e1550da,a0054a99,6d57de6b,f7c637ac,4d728090,9960ce01,4b541abe,754b82c,bfc87ad1,5fbe6ede) +,S(91537a09,697d3658,b06b853,d07153da,6d0228f0,786f334,db6151c,64becb87,231a2595,e04dadb4,b3900188,9f34b43d,5cd3c81c,f13fc6df,d432a377,4f53015) +,S(93a85356,195e109d,ddf054d1,2a901d83,b10db692,fc17e878,849eecfa,5d387fff,58f2112c,3df38b46,51e347fa,5aa8569a,48d95b2,670c76ba,d0de339a,72ee87e4) +,S(d5d1f0ac,bc2ed1f,50490030,43fd020d,7a1afb27,cdf78318,6a043bef,b0708eec,c473908d,4d754fe2,a5fdea86,62a6ad21,b711560d,77ad85d4,e3b47175,b5133e52) +,S(afe283d3,8cbb257c,5f2c0dde,2fd1bd56,2ad33e5e,605c24be,51a255ec,5725b1bf,a050f64e,978a9ee6,36885656,5cf22d7c,2fb45e64,6df60abf,6d3f9e1,132311a7) +,S(179667a1,72e0c37f,33e835d9,b5b6f326,3d963f37,1dd07d40,e790e0a1,21765180,da24290e,e38be6aa,ea2e86e6,bf683d4d,90f5fb79,20257b78,aee8be4d,fa65eea1) +,S(9add8ed2,6feeca4c,d3e583f0,88398ecc,f245d30,a888e135,b86ac1a7,e4e42d05,41bcd07c,c2e6acef,bc488d74,8a338c9a,7e6d3e43,85029f75,63dcde83,54d82232) +,S(25ba1237,6bb6e146,5195db78,29f51889,869dc972,fc9805d3,f6dfabb8,bce6b,a39dfc2d,223f924,47ae617d,537a4877,e6a47e0a,7e5fdbca,e1bfc956,a9c42571) +,S(dbd78620,c9a75ddf,55d0a41f,7312ec44,d3108f34,e7d75195,d3d49f99,88e2f986,c184bf06,ef304b72,1637bd3a,d511dc92,297dd5f5,9bd8d053,a048702a,fdbc400f) +,S(f8d67c64,b71d14af,b07d734f,675913cb,7a1bebc1,6e4a4916,44f8f4f4,6eb69448,eda6023e,5df40a5c,89a7bd26,94767a5,f17042ad,f95fb4f2,88bf9fdd,b91b280f) +,S(fd5f3228,56c096d3,4683a672,64ca5d76,58a8b7bd,41c3c1f2,5de2e6b3,164c8fd7,8372223f,3fab4f89,f6604b16,dd66db85,b8a27eaf,30741bd3,7a90d34f,f19c154a) +,S(ea49d0e1,b07948b8,b122d52f,8e8be6c6,e470262e,1c239b40,483a6076,c005136,b81ee77d,3d8489ab,42a9978,48a2ba17,273517fa,604a2abd,f2e1e726,d71b7e19) +,S(bab8ce82,c1210a99,ce17a5cf,3636baa5,52cc793f,89fd25bc,b6f078c3,92149bc8,afe2bb15,d00cf460,953a7c1c,8e466556,136ebd4e,ebf61a76,e49726f1,e3aa8e73) +,S(98802d2e,225bcdc7,9e02e746,891cdf12,ac434154,c08c2e78,589dd9f4,27277e1e,1eeb6b5c,4fc6459f,28e3fc49,6d9a6baa,fc66ede0,85d4b0d7,4af45840,78987514) +,S(5dc54290,2b33fd65,7d37a22c,c669ff21,75825cad,b34e1ee4,7aecf7f5,2dfd750a,41fb96de,60564df7,6c8ec857,d7f0ceda,2b330fda,2195a70f,5f64f973,ec0144d6) +,S(c4894f07,f6679f4e,13369495,dd501aca,73666303,2f7bab6c,fb81d7a9,1495834e,31b7e5c0,35e81c22,89de373f,85d648dd,892021e7,1d120742,e4ac6af2,44a25a8d) +,S(f7c9950c,d5c5afda,ede613bb,8f21ca15,b0e92487,81e16378,c7f2cba,5efd7beb,1746037c,b9211262,f0867180,16f0fed1,75debbb9,5eca39df,ed757c02,aa282d24) +,S(96703c67,4e7e2859,f274e7f8,d458f7a2,89ac0bc4,961ef3bb,b120a1e1,b82b5a55,1f92a15e,5e8b476a,a165823e,59da387f,2f9ab551,4703010c,c35b787d,c7d8ddf) +,S(4e8fa83b,bf9307a7,8b997e49,68227e86,a0402f0,643f98bc,5d13837b,63d08156,81f1f92,bb2a9ca8,14cd212a,6de7ebe9,7a04ed97,4de89e5f,cd8749ba,6e49e4ea) +,S(bc239122,b0cb1f43,2ed0c2ec,bb3c5391,b7eebafc,c4190fc5,8f62d313,7f58c1bd,5b3cd401,d9cf971a,6b9f70a4,b6f8fab2,d0026a24,cceaea2,a86aef0e,a76a3cfa) +,S(90b7138d,5d2e11b2,86d29b78,521aa9d7,205351f0,1451e134,8a593b78,fe5f1778,77cdd3f5,829af7d9,937ac98f,58a78b99,b54fe9d7,593415f2,18dde880,b5039a37) +,S(631d0fd3,27bca9a6,aec8eff9,54fdde7b,df43edb7,b1f602fd,a32c387,825841e7,d6e8af71,273702a3,a2a767af,3c438f0,b07ab614,2fd0f67d,74a9d358,74e29100) +,S(ac2a0153,d810371c,6a7bc097,ed09be67,14ae9935,4a9910ad,7ee77ab9,6d54cdee,39707795,a4f01640,87b5e149,2ec8fc1e,be11d8f7,c43555ac,6f4674fb,8ac5b0b0) +,S(89751ec3,c1aeb288,1953d3d3,f2f634ee,29b1aa18,c55b8b62,59d5cadc,852ac99e,8b4d51e7,e2f94c0e,ef80e16d,9b62c935,2ac91394,902537f1,e93744c9,72f22a3) +,S(849a6cfe,5e3ab81,2e21f491,4c6ec76b,5233d405,7ffd487d,bb0b5091,2ac499d2,a490b967,b5fcea21,d0135ec3,c9ed5efe,ecf7ac6c,81e06648,66cdca60,a1be7037) +,S(4ffa897e,17d760e,41859b6f,3bfc421c,55fa1e31,eb999f72,5028be41,cc8a9ed,87b4b5ab,d9875b94,aebe632c,64ea441c,71ec7353,5ae2c83b,d9b904e3,7f7fd326) +,S(4fda56c3,8bae34b6,55b2ed2b,621e5074,7ed1dc13,a1a815f3,be12a223,d54c43c6,6cfaa7b3,c53a1dfd,a03dc7eb,6086b84f,ac280c55,7c357d16,fa5938cb,c149bb10) +,S(b572c9c7,9ecd2ee3,154c56a5,9c81444c,b16df1f7,82198eb7,40a78c7a,e5c7e99,a1fb603e,42d3ac6a,5ef5dd74,ced31624,fed9086,5b02b3c9,2bbad21a,ffb1b79a) +,S(a77038c8,e79abb7e,a94b4e17,35f0f5fd,a07b1ad3,367047f4,895a5104,dfeaa623,e9bef9db,e8e2078b,346aee0e,efd64657,2210e451,ed2e8d63,b92be059,c577e1ea) +,S(3158f3e1,14de5071,c6e2bff9,32f1c269,7e374dbb,786e960b,7e59df03,26e2e1c9,1d0e950a,9124a626,4553d29,3e5cb8cd,9dd05d45,f48de2ba,f60fcee0,ca42a9cd) +,S(b0825b69,373aad7b,53c256c3,1258169f,2736d47b,1c4aa22d,a052b864,375a807c,23ec01bf,a857fa0,1f3d46f8,7857b211,f7533c9d,611dfdf7,951d190a,d7ef07db) +,S(9578e6e2,1a738f66,ca04647c,ec610da1,afc5602b,1e72e096,bd192ed,f19c205c,fb5da982,7208b4e6,11e6dc5d,dd8b8ba3,569a578f,275e6d21,3417fd37,7e4e6cae) +,S(a0aa979a,5448d27b,e42c39e2,2fcdf40e,d3b64c74,42b2c40e,2f6d38ff,fabb196d,7a9bf938,937be244,38aa212,d9342f98,ab9a35dc,1361fe56,5d04a25f,176eaff9) +,S(f535145c,d57aca97,f4cef68b,ce57d5fb,62ccd1ea,b48dfeb1,3b87b188,4614be82,1323e73b,dcd6b16f,bc481294,198d8235,b98a1885,a336f07d,593e5df3,a21ccc11) +,S(587d9e30,2f9d60ed,eeae03ca,252cd2fb,117bd07,fc91163d,a7cc569d,1b023f9f,7bcd5b42,3c01038c,9d3f7f71,ef52b4ef,a99e4be1,6de4314a,5e517e8a,950f45d5) +,S(b1e3b70,aa8a0cab,ec119ca0,5430396,ed98d9f9,e3e1a650,94cbd985,4cbd0932,3c9496c8,eec7dd92,9718f7a2,8c7a67b5,c4e55d88,5a943cc0,deefbd11,fa4f8de2) +,S(8f7001e2,928200d3,a478ba12,424be4c8,de8f16f2,a932e000,1468d9a0,48d57816,bedb10ab,72eacf26,1ab17a34,e5138686,34995952,545129b5,5bd6c7cd,84b50bc3) +,S(c95bae04,e1c397e1,498822f7,b7910019,922e43de,83119ae4,8517aa9b,aad6f35,8fff7d3c,d8bd7af6,c8523375,84f73aa,2f1b03c6,585c7987,98fe29aa,36620486) +,S(228fba21,ffe5ff9c,e04017e2,7cf04c71,1cc454d4,534d3404,49bbd1c9,60d2230d,825fb4a9,169ab67f,50963731,10f27fc3,f6f7acbc,9f2918f,c6f0bfa8,a92ed32e) +,S(89610875,bb7c5f53,87929e38,22249817,ade80ed2,a69dec5a,eee31a48,6c40e316,f7d5f522,92a53c2a,447f9b6a,5c06b3f,22fcf19e,4a200ef0,9167c255,a373ef47) +,S(9f0542f8,8e7e2b4b,c20b7b5b,87f051af,6650f605,67dca77b,7b6e1ccb,2a63f6e8,2b80c840,5e343203,d0a7d1cc,ccc99736,4bfa10d0,6e71880d,a0955cc0,b1ff98a2) +,S(859b6ce5,b7075222,549b59bd,3de967b2,1655d163,c57e94e5,6c9fae12,e5222061,25b8cf47,baba2000,19036027,fc86f03a,1c4c406c,4a8b2c34,398b7191,bf125aa6) +,S(e6febd1c,91e66c5d,afc7caaf,4150a023,b70c57fe,2a14f84b,c9fabce7,34982ddd,b606e3cc,f997b627,a0a02c4c,e147e0ef,58e3e275,a43940a3,4ac74760,457ae5e5) +,S(956912,ea1f5ce3,52d39e67,a41e4ec5,8c7106e0,4552e1a0,48e4b195,6cff8c01,b1eb2fe7,7419c11f,f7e34dfd,a752064,39fa2e6f,b9f9d34f,70740950,cee3cf40) +,S(1bca39eb,9b6a5d5,3575e510,6955143d,a6fe9d67,999500,ea78cb89,d832ddba,47afc8c9,358e5f7f,e92370d1,44ecac99,4e69afbf,6ef1af7a,32adefb7,9331173f) +,S(2c6db85b,c4d84c2e,61f0b5c6,2f330e7e,dd672c63,a14fa534,9e4d1488,ad462c5c,bb488565,cb2da5c9,be8a6f6,c71555bd,d85b4a53,20ca0753,f524f91e,ca1e331d) +,S(f66c0d73,36bc153c,5f85e297,52845255,8957a08b,603e4d3c,746e0c19,572c9f82,74e32022,faa58df3,1e4a02b6,f00ce5e7,bf34ec93,d8095144,a1af69f9,c637f01a) +,S(774959ef,cf8c126a,67012f8,10217d39,298040ad,da97e973,9fe13f9,927f6757,c33b9f7d,b2901f8f,171151c5,dd8b890b,62c0a1c1,9b7d4691,9c23ed00,cdafdc24) +,S(f59361a5,74b69786,f7ea4abe,44eef2f4,5000328d,dd72c2d5,a6dce9b8,63037ca6,34deb360,ece45bb0,a2417618,e7c67adb,24b33620,80d464af,a1ef20ae,35da05b) +,S(add233d,31c179da,bb62567d,2a5bc5d7,9afc5c50,93dc8196,9767ccf3,8790a5a0,b9ecd675,13d81a64,8ca5ab2f,4d580d3f,7f7d4def,909f2759,af61e497,b6d8f82e) +,S(3d204b0d,1d705714,7e947150,52a531bd,b6749743,5c94c7f4,8f821579,170fa257,ae20862b,cd86c6d8,e8344911,cfa8914d,f40e3a80,b762fd54,e2b7f704,4de86017) +,S(22be58e5,1c5ce0e2,f1ee6f5e,523a2f55,e110c4b7,bd3135d2,39d7a25a,94bc13f4,56894dfd,6c2cb7c8,5689cf04,3c1d4221,a7dfdfd0,d05b1e68,cc41afb6,6a472a04) +,S(6e015fb9,af8ec2d3,9f101509,f8f1fc9c,d95dcf57,82621ead,4651a062,c8487687,c7dc43db,d1d068da,9cb751fe,51251bf8,7f6edbc0,bb19925a,bc02cf6d,d7cf8554) +,S(3baa1e60,42844786,fb720758,67ec526c,2e0f7fab,ac8e0eca,24eff876,47720c2b,909d202a,b40037e,9afe2ef4,d8638491,d27a1d24,98e497a0,908a52c1,52b1f8da) +,S(689cad9b,2cde514,b9c25275,d6a3e68a,ce0b2216,4418a403,a83d88a2,4dc4d25f,53e7be29,165632b1,d1887aab,94c525f7,86166f32,56b44e70,295dd0d8,bb9f22f0) +,S(c1cc4802,101d0251,76875033,ed9fcc07,a66a57a7,71ca1374,63d7c7b,655fdb6b,ffa73601,5dc4ccf6,8afc41e8,e254501,93eb75a1,60a98c,6c800d0c,f10edc5a) +,S(888e34,86eef22e,2a25aaec,9bc9b84d,fec14fa4,c98e9d57,4fb9e08f,5b0f76a2,d2e3ec7c,db9286b4,b0223762,234d771f,a5b6f378,b6a4bbb3,c94c3303,af49b4f3) +,S(ab355f17,a43d24dc,330a9195,c2be2ed5,6894a9d,e38d3dd1,1a31f9d9,9ca88a93,7f8f8748,c07cfbd9,fce0ac7c,b624f2d0,f83bc49a,53276b00,7ca2b821,51988e6e) +,S(12a65c28,aa2020c6,5f56d916,c1cd111,10f68f0c,2408863e,635e05f0,1dbe4141,48bbab23,1be95484,7a0b61d3,89913ff4,5a8b97bc,384a0780,294d97d3,9c9b9be2) +,S(9d96107c,591d95b,42854234,1371290b,370640d4,2dca9fb,5f5397db,84a5577e,183fa1b1,cda4719e,869c8b44,e97cf214,3ab14e5d,e5d0d781,78e5d68a,923b3dc4) +,S(7ad05c26,aa642731,9eded7a,43f72faa,d344ef4,d413d884,67bea154,4459ad55,cbd8ea0,7fcbda54,813f990b,a6eb8450,6faa12d1,cd478a9b,cc278a32,511ba8f9) +,S(d1ddaa71,27959090,65ea358f,b887e4b0,894028bd,457d217,f1ef6b9d,143a2292,e040cd3,d5f19cc0,456a55a3,88ccb81f,787eae9e,51a289cd,d8ae8d25,881e6ed2) +,S(ec3bc5da,a9be90e5,1af0c1a2,bf41adfa,8023bb4f,b40e65d1,c65a0e82,6bdc30a6,d4962737,f9df1f4,48df1d9c,d8f7a140,233c2175,5d8ef5c6,f292b230,9ce263cf) +,S(f3135904,dc55f515,806dbecf,d51b8106,f13dd1d3,43f78e05,91de1f94,86fd193f,c5bd3002,24934faa,2f9ec634,53fcb3a8,20af608e,efbeb963,23871faf,a7dc2246) +,S(fb5f135f,b2f7638f,36bc332e,1bbd2050,335c141a,49db5452,619f266f,df85e8f9,6e71e045,827c3ef1,b75bffd2,ce54361,1e627cca,c94c8d3c,9b8fff62,e10b7b6) +,S(d1dc12ca,62a1285,e3c16125,f71a1b7,7b0dfa9d,c1068ba,2bb56bf3,98864620,6a6bda82,232af467,afaecb2d,f4a7ca53,3c41d63,d8f7093b,f04a2964,6e4f19e0) +,S(52354730,2d24cb39,f9117e35,d9374ea8,f3b6d027,cfcc23b7,58f0bc1d,b4f2d94,83719f2a,ccc79c43,1d8ea584,c78dd5f8,daded80a,fc3341f2,5789181b,7671d586) +,S(fd8247d,d208839f,93eebd97,f6068ae8,a6640a46,48c16b65,6bc992b8,4ccfc5e6,dd560b93,9b530bf9,a8bfd5f9,614f498a,49e54061,61107517,e9ab0104,54e42f3f) +,S(da5d83a1,9254990a,c14af844,df04bcb9,accab655,5468d08f,3b5d93b8,425f1600,9e5a8786,6be51fe3,54bc2412,6315f8de,1f0113cb,ae78b72f,cc70572c,d978fba6) +,S(1205f8ce,b9c89dce,13cd44f4,9ef0b2e8,14b78639,372d9f61,f0543f54,bdef2944,6c820a46,afd1dd98,499636d6,afc34ae8,218a8c90,2f210dbe,530a9211,a058768a) +,S(7d94e0f3,3969c5c8,164739ff,11aa05e0,45b32702,333d947f,8a0cbb80,57dd3c71,7b92b367,33f92723,17948d9c,a1875303,865fd47c,ecab145d,9ac9d4c9,864d62bb) +,S(d7f22ab5,6840dd87,d939c4ae,3bbe5a67,75e7a2c6,dc969a96,40c7f65a,9c18b2d8,bfc60718,2509244,b0ab951b,f4032852,54b73d5,a23a19a0,b4ccff25,1e5dbd6a) +,S(cee33146,2accf4fa,5f06b598,cc36aa06,342c83d7,eb4b6aff,90b9555b,fee0fe61,97583a48,5c323459,ef4b3f02,bf63f9bc,315cdf91,6163b389,c6a48cf7,4127da34) +,S(1e1d2d64,1ec550e1,1a29bc03,cf7c8442,ca13f10a,182783c0,d4ee9bf0,8c3c8a18,1ca8ff62,fadef98a,4d1faa0d,28e75e5f,117cd890,2934e457,e042b870,d8cff1bb) +,S(f10b2e75,8246bf49,1b70ff95,a385e701,dbbf333a,95a94652,6df7cb7a,4b4cb68f,ad15b5a4,d39d6458,55e57a65,3872d9d7,5f4b3168,182bdee0,a6289f68,aa7f99af) +,S(4674dd8f,16ba5557,c9ef32a0,2b6be805,e864e7af,c4fecb8f,666cf396,f7e6b0a7,c9d95120,73388bfd,45f702ac,8851b5b7,531edbe2,df04d855,7bd58b3a,c889f48a) +,S(95bb741,da472f82,8ff1f98,970c2bc9,1dcaa4ff,2cd4c0eb,195978b3,242c66f5,1e097cf6,d47dbdfa,8c3f2ce,90e0ccde,5adbd581,9a6e135,957ce258,805a4130) +,S(9a892056,42e03fae,b24d8fe0,f94e4f6f,d0c72581,604a65a0,99e3d28b,b103d2dd,c6bee4e0,d94c30de,b99c1a21,5d28d7cf,930e89a0,7865ea1c,87d39f5e,1522b33a) +,S(ade39c3b,e9540095,2176bb09,20541076,dac8e68a,a20903b1,5048e5db,4b0539a4,6bec56bd,60596cb5,7ea8a355,a6a6a4bc,90871c81,de902b0,6abd45d2,5802b204) +,S(45f808f8,bab4b4e1,a790240a,f036516f,bf0a8eaa,dd4dede1,eb88bbb0,7d248b8b,3f3bc72f,bced768d,bb90ddef,5b1baa9d,aba634f,1fe19842,c3b4b456,8957794a) +,S(ac9aa903,845a3081,2ddb195d,d79ffb6b,6e8ef0e,d34d0a5,49b577ca,35a116be,368ddbfd,1c5a2fa,c2c183af,19097414,82b272d0,52cec4b1,745fba6b,4a9fba89) +,S(ba26fbbc,ffa6b9f3,584f18ca,255da089,f561c30f,29a378e2,9f76de9e,b756f6b6,55f67b11,81ff78c4,c4c86e7c,931e314f,dffb392,306a7145,5efe875b,fbe39ba3) +,S(d4b1a902,1ebed925,9d53f2e,d76b03d,25b4241e,d5f932d3,a54c4dd5,db3f0423,6f1dda69,9e60053f,d9d2f5c2,c2ed2ae8,ba3337a9,b669ba05,3e48d974,f73c2d93) +,S(bc91d139,b2de4778,458ca891,fa97e413,d4cf32b1,753cfe0e,540726c4,648b451e,b56454c3,4f568840,6d198248,19ba350e,aa291f16,5676d7c9,fbd2d592,169c76e7) +,S(cd7a85ca,a0f408b,26b29306,3e01dee4,acaa8f9b,36f7273f,378290f,a4435450,1d9508b,1e7f5bc7,ba8fe5d4,f44e8c57,2bff9a98,887c3ef5,2fba3057,f132c5c5) +,S(497f8e85,57880856,32edbfec,b0065ac8,3267fc31,da9100ce,c2b99cba,1e7c26f6,e6729428,fabdec3,2db731bb,f33cf45e,5001b890,8f82c0fe,f7cac291,f89c6a46) +,S(68a607,4065c372,a95e7a6d,fc742e32,e59cc4b,86f9127f,f9465474,a466e30d,58e59131,1cfff974,e9e9162e,e974de92,904ffaf6,ffb97f49,d9dbb1ca,bfd927e) +,S(79d2dba1,67b93ef8,82ca60ef,b803e1a6,eadb4406,7f9dbf6b,d45c1a72,23da19b2,a59f1b7d,9ca146bf,93b89f2e,244dbf00,31511075,4dc03050,aabf0d20,41230ad0) +,S(5a2802ac,f4b92bf8,1c98c431,28ebe1f9,c921c211,910b6648,6391ca0e,4c6ad50c,5a0d7b4d,49b5835,dc3b395c,83031571,f7c361dd,840b41d0,405db351,14d86eaf) +,S(87b8a84b,1fd98b53,e9eede06,74555c7d,806d5b7f,4cfced4,16203280,18c398d5,a38c4d7d,549bd5d,28fa39e9,805e81bb,975cd137,64aa8c7c,a7055d63,bdec52f2) +,S(f7ca4d9e,7ac11395,70db6a06,c7f00833,5982181a,6642846,5d0899bd,907a9223,2c3dcce1,2ee6a995,52a72eee,e0968552,919502,5d4962c5,a33035d4,501badda) +,S(15bf39e1,5a11ff6d,216c0f7f,f1597f7e,ceeeda34,91b450f5,3b3407cc,bf7ced7d,325462a,6591d018,e495c6f3,fedb3abd,75d5a4f,15e9ab99,e43418cc,4aef1ecc) +,S(2755adc5,e69db19d,7caf52ee,117c6907,5b342e73,4af64a4c,77b369d4,269897b0,199bbefa,7e0b1c10,bd78ead,d5e65a6c,e6b3ee49,1400b9ad,a7874bcc,be580d5) +,S(96ef0e89,80602225,1d8bb9e8,693f3a67,5152cc9c,43c4e953,5310b9f2,c4338d8c,2414e799,14b2d6e2,a9be60ed,52508d6c,15765c0a,7fc1746,8820fb99,a9feed56) +,S(c1642d67,339fa6dc,c553233f,116f8086,2edbfc24,5512c2bd,4ca6e348,712bfb19,65e9a14,c7356a36,625022cf,873161b8,ef43ce38,a99586cb,9b5c8189,f3c6b8dc) +,S(54c536b3,cb6da9b7,e4483ce5,d5c9e660,bf973ef2,f4c8b095,f52dfbed,ffdfb96e,777f16c3,b026b75a,c9863f38,d015f04d,e1067f2a,a9cbd15f,9ee27475,ad46a4b7) +,S(706041aa,63dee9bd,4a441238,bd343bef,14e69929,f6e007e,181ae87a,68362926,36e15a44,57b86f4d,9b233dd3,37fab91f,67e4c811,3340463f,8f443b50,5a0ba014) +,S(49acc336,116c91af,6f90a6a2,d69b9d3d,c0be0a16,afb9830c,c1af0b5e,749b2765,bc4f0f6c,725e037e,3a9d9be6,c5d4f80d,67b3e28b,92e5d3a8,fbc8f66d,9ba97d52) +,S(96bee384,ff79ed86,a9d816cf,32f3d569,d1ae03d2,d154c65e,a117707d,74c818b1,848e45ec,27eaad75,5328d84c,a76a7235,ef4f492f,5be115a,a622171b,51dbac8e) +,S(3b2b0810,c4052498,189affe0,4c7ebce7,b9050aa4,6a702d0f,72c5c770,4ca4d1ec,f782ad72,1bec3b8d,b1df97d4,7765434f,e4145c81,27acece3,9dbba604,4df2543f) +,S(54c3547d,e4873721,df6215fb,ef7bcb4b,b9acce42,7b0381cf,2de151f7,c69549f0,5e7ce1b,728a3b21,e94b4138,bcb89af,f4778dba,fd21aa42,16d83a7c,9ae81edf) +,S(9f1c53de,e7b895d5,6081585a,c6eb3821,d89bfa61,55cc96d2,e8b6c472,edf57f27,38369e41,ecbdb4ac,619aa7da,4d708eaf,4c572ed7,f1f2c079,d0bd17d5,3ba8288f) +,S(e79f75e,a1a224c2,a0533936,65a5f705,15eb0aed,b924dfbb,5aa30055,d1d82b44,30c65139,f6a6f5ee,5304334b,1ce9dd15,27ba6031,2ff2697b,8eebbdab,67105171) +,S(7f95a1da,79cf25cd,a904b7f3,11674d02,fc6dbf34,ae8ba7e0,b179b48a,d942821a,3d3dd8bb,31cbafd3,247ddceb,be1faeb3,b00e057f,7e90bd1a,78f89cdf,648f7c8e) +,S(41e83f7b,9067a7c3,bb6ec755,ab7c83a4,dff74c93,65d0259c,cb635bea,718a416a,a54a4b56,5286b26b,d0bec338,2053c349,2de80062,2189e2ef,ed10e3c3,9457a34e) +,S(81599046,453d0a96,2c5f3b47,fee7f827,537c7c58,c5ad068e,e5e6ae6f,7a9c6848,4a83b015,3abd0df4,177ef3f7,e8a7ac7a,e8e5afb9,a2fd359a,c30c13ee,321f943e) +,S(11c9aa76,2cc334f0,a3274f15,17a1e60f,2f0eedfa,d603f83a,120162bb,e87830d0,7c73d374,26f648fe,4a9978c6,a64ac787,f4c8d79f,b58b0f58,70e373e4,d317136a) +,S(2b41f344,b285a31a,ebf4f4fd,f0c4f463,49fcc794,e5762e04,dc39efc7,936735c9,7eb708ba,3f683d48,db8e0c25,ac8a6f8e,5c340749,c3d6ed5,7936d515,7f3d6e73) +,S(dc063e66,38098e8c,6ff55a73,faa20099,c10d0258,87c19850,43d1011b,ab211b93,4abdfdf1,285ca3ad,65bb9a85,7ad647f7,fff01782,79fc6df1,6179e1d,495d212e) +,S(7cb514e8,b6361aee,f9a7abe1,f84ef401,97de721b,609c3151,a056eb03,71ccdf8a,4d359c89,7d03a633,369bddcd,52a67387,fd4d1e00,2406502d,9ba6e967,a5efd0be) +,S(103a6644,ee731721,bf29f036,97641fde,9775a642,9ce8d97a,26b06ceb,f9066693,127b6948,6db0d230,6ae90a1,4b8c8ecc,1e9293eb,cf154371,5ecbd579,e886a726) +,S(adfaf771,662d719e,532ba045,72a50f12,144fafd0,afe93f7e,1d8edd13,99226e5b,b4d0335e,8b600a4f,84d919ba,514bc249,e3048cc4,281db3b9,a7c62013,4f00bbca) +,S(609d9352,30f3c6ed,bf64275a,23a9a258,33fb8c3,9c25dde,4b55ce22,e64b50fc,cbbae84,c57f9c52,67278c4d,3b0cc5de,9327ba71,ca1a1bb1,8aec9a97,bce17552) +,S(5ea5aa20,1b958a8c,49b70510,b7c6a29f,86d9ded9,afd4e833,77c433d0,f62d9ba3,27c5cee9,fe3c0bc2,af8d0e30,57eb0f57,b1fa4237,996bf8ef,5ccd25ef,e1b87ecc) +,S(3f801115,3603a689,800c04d2,7d3b3fe5,c415ea29,c6e11951,7a56712f,20a10862,4280ab61,65b122e1,85abf4d4,14a31961,ac6595cb,421db183,34e57cb3,fe9bd059) +,S(54981ffb,5b692a3d,6d9ec7ce,f027fff3,c5dafb7,aaab4c5,572522b9,e1157e5,893183bb,554c81de,21c84134,e395b9fe,80a5a9ee,b06e3b67,2ef93127,24c307ae) +,S(97c18e92,d499ef62,77585c6b,28f36fec,e9a2e118,f793260e,32750861,a1aeb813,38a87702,7f1df077,d6e734fe,18a023ff,36c6d4bf,4a7bc7ce,d3a3d38f,c3069f33) +,S(d5507aae,97bb6e17,410bc87,26d9eb2d,11558b96,6c54e7db,6428b44a,3589820c,e78d0140,7468dda6,d9c4af92,1984460c,e523c101,79f7aa15,d8004dbc,4fc63cb9) +,S(220d6c2e,6c500d01,9ded2aa6,5de205f7,cdbb15e5,69038ba5,7bb1700f,1182ca70,64b68506,c387ec2d,9e030448,797bc28c,5e09e8a9,95f5f80e,70c26a1f,db7b16b3) +,S(c1a45038,da6aaf1e,396595c,3ab404eb,9584ec90,d894985c,18e779de,793d20ba,1a443da1,72e281aa,4393e1de,6f1e4f89,4fe5d1ec,b3a5bcd9,607cf79e,6f20b533) +,S(9a66f9b7,f3162c80,d22d0b5d,2a659bc6,ac01c74f,46804ca6,c908b6cb,90fb419e,3465357b,209c2b,a7c766b6,9c17abdc,69205c54,787fd0ef,e744692,16b95d3) +,S(8b305bcb,1b6156e3,22f0f0df,28265cc8,79e5909b,b76b546e,eb223d62,89883387,929a341d,dfa05574,90cf5293,244d924e,852b00d0,d328ffe4,7ccc5356,623a31a) +,S(4e36ee67,b5398169,8ed9460a,cb450023,7198f249,4dded391,4c2ae003,63c8f664,a784c95a,9a443b7,5859a1b1,373eb750,150e1ac9,d5120ca6,f273578b,73df77a6) +,S(167275aa,38d02988,c53e0a36,d8312e32,369bc677,6d7143df,cc6fb83f,66747caf,f26b9851,31abcf45,369a6415,84b2956a,7122a51f,b909bc30,5427eff3,916e6e14) +,S(c93d0b74,c99358d6,d24a962a,15adafcc,8a4e57ca,df0afeb4,9d46ef53,cf619797,f93b324a,b144c6df,336e34e1,beef5c13,b931668e,54ab34a5,eee1a8f5,5acc683) +,S(8bcaa2d4,671bb4b6,8a924109,32128551,fbf6d924,d4854027,7c1dff57,3bc4a8f2,88be3e1,6482477e,62255fb3,24512abe,27cbb4df,f63c6d8c,93c3c923,47e519d2) +,S(69d186de,f9a7ea8,be833f2,590db08c,fc0acfbc,64a648b6,8ca412d6,88c03808,d776b644,43a81bf7,527f658e,45d92324,a08ce171,6db6c259,898fab8c,f3d6d41d) +,S(4a53595e,e2cfbc6,7bdc9f07,308f57c,7ff5afc8,a35e27ec,e22cdbdf,6efde161,e55913de,d481077a,ea36c502,494b3b72,b1691786,335b0278,3e40fa1c,1a1b0876) +,S(90856f9a,5f7bbc14,557dd419,516ce5c9,aa451bce,13c17ce5,5c9fb1b5,f2924995,ca083d2e,b5a3a067,4a2534fe,e03bd99d,976b96bd,2b7f16ea,6e2552ee,648e934) +,S(2eed315e,d863298c,aa374ca6,2bf8313a,a0ca07e1,9a94bc4d,58eb235b,52d36dfc,afa36c8f,90d7adeb,ec33ec69,40c08d1f,2a4044a7,477da88a,6653d90b,880856a7) +,S(345a7f2,ab7ef064,eccdbe6a,ebd11dc5,3c7ede0,b62ab3de,f8e409e6,258e84c4,c0c0dce5,93cf9647,c0228d8,42b78407,c3b634ac,799fae19,f0e685d2,6ccfd73f) +,S(5a669d7c,209b222b,47843a5a,633e0b53,48442258,663a58cf,f6ee3cc4,1b893d3d,7067be1d,8636698,2b808b16,3c05e57f,2be77d1a,2bf78038,e242f5c7,4ce10523) +,S(3f0b0f3c,30a991bf,927f5119,6fb4af39,e1399d01,1766b1ff,1f0ff2d8,a3199062,be8f8781,4c06a75,97d062c2,196a49ef,93a73923,f43d16ac,82c015e5,4789d472) +,S(9d7f2c64,98e78982,8492b8c9,2e0e49c7,b5c9d4b2,e86c409d,828447fe,4a2f5a13,95ccc540,8202dbc,78323d6c,7ef66d51,4af34699,5be50b56,98a5864d,34e502cb) +,S(9f741436,55b3cfb5,39917a7c,79fec4ba,164503a8,3958aee1,f6e8f34b,3d861b78,345738c,ff8f3c64,f5cda5a7,a1aee7ef,f3a33141,a5139c3f,b891c6aa,feaaa7ad) +,S(cf1d3136,11d4b6ec,5f1a9728,c9a7b037,d9c16d65,bad95fdb,17376200,b1a9a97a,51c72169,bf7b1ad8,6159fead,dcf3b0a7,a7fc13cf,7bf12d98,409dc3b4,fcb7a9a2) +,S(7e04c6ef,c7433f3f,fa2bb827,3fdcb3a,e0470abb,cc7c8dc5,414ff77a,915868a0,781125c,2184eeb8,87019f7,c5c0b4a5,5922d11c,53c3db9e,d5795bc6,e7539cc4) +,S(fa6d73b2,a97801b6,16697ac6,102b002a,53d29d33,289708f,d8f73964,77f3d57d,543db558,25c67a4,cd010413,9f8a093,7ea7ac2a,380799f1,c2249569,3cf557dd) +,S(d0fd7208,8deac18b,1bd63fbd,6d5be0ef,5dcd34c5,538a9b64,ef43daea,ef321d1a,7a5e1e2a,1b290241,7879f223,8cc8928a,65988130,81366846,69841b93,3ddc3a1f) +,S(e856e67,e28330ed,77d8687f,bfdce5d9,ab8ec155,4c94ae0f,491d1e43,9361cb99,c51585a1,9da7c26a,4fc07c6a,f17999e7,a6718542,d7500fc9,1bd21fc3,8acf1eea) +,S(389cff20,9f240748,b9beba0,34d36e0,5e758a3c,95c678e,28cb0226,37db1bcc,ae5a0d3,db1e17fe,30daa2af,1e1f759e,905811c8,95706b7c,e5741051,2b7ac4c) +,S(28ce0f42,ff79cdb8,16b666c9,c3014051,d46e8df2,e2377c3b,619b78d5,17f21a1a,4e835188,f742237c,fe581edd,937b7294,e06fb295,d401b35f,5b7b293c,6d57f875) +,S(3d955bfe,5b27beb9,68400d11,3b8666e2,63af6ef0,ac6ee49e,8628e2ac,4d1e69c4,1fbd2aa9,b6913655,e00f1384,a15a7215,d3d7340e,4891893a,a67faf39,88801e9e) +,S(53dcaec1,2dd48ad9,ee65c9bb,ef21a023,58cac930,316263d4,9d607074,8aceb771,5b976f2,411d7624,d4659e5f,db624b05,9dd5e06e,f0b65740,ba394020,b9d279dd) +,S(ab822568,f7e9da8d,3f1220e3,24752c80,b02a8124,f8d9f65b,3b4532ec,3740881f,6c2152dd,34451ab5,b47b7c08,f7edada8,f9f230c3,5fdc2de3,35cd93d9,e25703c8) +,S(36719c40,1518b976,684bbdd9,2a923485,ce92b321,dc26534f,e5a0473e,4c873c30,d5d58a83,d493cccd,d16a1282,68aa93e4,94ce8638,41ec947,930c72e0,887564fd) +,S(360c82e6,18a53dc2,e44677b,a0bb8c2e,2a08f6d7,afbe8498,15d605c3,2e5fa969,ade18222,e1d0fbe0,a31c55b8,d2cb947f,1fcdea11,1e08ea3a,4f3dff02,e3e38b70) +,S(ecf50737,25a3b81e,dc621bb8,6c98fd59,f805d6b8,2f08380c,64270df1,95f020f,f5431b8a,cba5d27,1da26cb4,fc3412fb,14ccf088,6e0e08ff,ce0db47c,6b4172aa) +,S(3b751389,e6dadda0,85298860,76076249,46df960c,e030caf6,91f91d46,4d05be4c,244b0028,48829fc3,824dbe61,168fa1c0,3e4d3835,d3da3a53,7c729f0a,191e92cf) +,S(ee6e33ee,7fd9d7e7,aab10b8d,2c58f2a7,26ed307b,6fa69b3b,f1f08a74,f1b04ffc,4233398d,6ee49505,c5f21525,6cc9112f,5dfdd7e3,4bfb9a8a,476b3cd8,2645b8f) +,S(e7141075,e20f0903,f39fa384,f91a5708,7f24deb3,68571939,572caf0d,2fb543f9,5265e24a,bd84336c,26b4607,dfa25c44,49c4693f,adddca01,599d814c,21787cee) +,S(d401b043,ee9944dd,7429a8c9,4291dc55,7e5827d5,88375dbf,1513d394,a778826a,9ac9b417,5ac3666d,7c6327be,5172b8b8,1dbdc96,eaf8578b,76f01128,4434b937) +,S(d48c45cb,b90394d8,23574c16,60898091,75d503b5,99d936f1,f60246d1,79c9cac5,4e6b2bad,a67ebb7,a0743cf8,52298052,2737f0fc,6cbef646,fb270d44,2a285612) +,S(19f6446,fabe1899,ec4476ee,1d61f6af,961da42,ada1f77d,2ab41cc4,28791c64,7a0aa5b1,4f2ae030,d9711963,bbe160ca,424f6a7f,17b6a709,b5f0dce5,af1d0498) +,S(2db1d56e,f19a848f,6d6747c6,82cffa47,78444b3a,d57ea076,b0560b1c,4e57c83e,701a5894,d1d6b6cc,b421b168,fd34aeaa,e85262ab,44f70c65,b8ff61ac,ee541cf6) +,S(443597f7,9da3df8b,5fddf8da,3bc3a060,83f2cb6f,affbb1ab,8a12db92,59661adf,31b2c4ea,362a0cbe,2b9b1488,719b7ac4,3a85f7c9,63e9f2bb,b46ee055,71e2ac2) +,S(e49ad52a,7bd2db07,d972def2,d1ce6684,69aaf6b3,3c7e3427,52d79fa0,9d2ee9ad,b2063f37,1ca78c2c,429cd401,c5e46d6b,dcbf373f,5cb77163,5760b8ed,b4f91ba4) +,S(35b3fc0a,4a625cb5,808e1c2e,73c962e1,6ab7dfb3,28109ef,fdf81e15,841afd0a,cb558481,145a5f75,b639133e,8ce42c98,d36d8fa8,5348c815,d92a2c8e,cc993bf1) +,S(1cc238ef,3f64a075,c3c264b,ed42a0ac,aa6de195,7db40d52,86c482cf,f62f609a,d3382317,2b8a1450,bd918aa3,c57de76d,3012887c,98452f7b,c1f58610,f528af49) +,S(f5a2794f,48885192,dec727c7,79fb0b6f,c2cdf399,4ef7cacb,94e35791,4d138e84,d3ed4f1b,912f5dce,5a0842ff,d2e671b7,f3ae8448,b1a73f43,249a1acf,915b9c34) +,S(21b41016,a8eb7c6f,5519d94b,adb0fa7a,5c553822,6d080e3d,6d2956e8,8a9579e9,802570ed,b9b01b1b,ed79b6f1,76ebc4b3,55dfdd16,f43e82e8,7803be0,fc44e274) +,S(9b5611b7,938ac10a,9818bda7,3615a47c,1ee0f072,75aa3dcc,b8919dcb,e7beaa88,89787c01,d088e3b3,603047e5,2f49981f,7f007c8c,a88502c1,3bd9c327,e3c83b1f) +,S(28163c9a,b08a7ad9,38c7b35d,b19e700b,3865800a,55a3103d,2213c9ef,2c03858e,661e089b,df356bd4,afcd0604,fa5ade9e,74c5663e,77ab57f4,a069bcf9,b8b227bb) +,S(bae9ac08,aecc06f0,ffb8540e,2589a32f,11d34a7f,6d899e5,7a8f5ec5,bcf1601d,f5b63d9f,8a5d23b0,80d0bb6c,b8df736,aa660a3b,6f987683,cc0a54e5,f7d1b4d4) +,S(19f48542,3ed01783,cb83d2d,2efd7264,a10c6c23,1f5a242b,112eccb6,31d91f7c,79ce383f,f011ce13,87537ebc,3e70dcfe,2cc2764a,3d180fdc,74a21062,a5b75f50) +,S(cf459ca,cc8c4ff2,c827efae,6593a52,838658ec,bf1a78f4,75965856,a8ad007e,786781e3,3279964e,da5e6374,bf088fa7,5d18901,df01a0d3,6c87b62e,b419dca0) +,S(c19f2008,e6945d10,471a13e4,8b16f3a6,381de3e2,b24f2d92,77ded25e,930d1f47,7179aaf5,322b51d8,7758219f,cc30e9d6,bad5ab77,b35dced9,6a513b4b,fa7fe147) +,S(3fc1b649,3b6cbecb,1767d0e5,6202c84f,39a6b41,87f05ac0,d659c45f,5bc565c,db9edee1,1768e29b,4eefddae,c6234622,55d06e0f,1979c8c3,5c366f4b,5cac3f5b) +,S(502f74d2,cf589c65,e63b2a8d,b2b1e4ba,5f851715,bbb27e8f,165fd34f,29cff7c5,755e6c73,765bc45a,c2f9d4da,499198a7,36743571,40846ce3,6afd8063,981a96b1) +,S(b9eb62bd,7cc6d1d8,b0eca2b6,1920be5,9227534e,7fb581c6,4dcec4f8,f1ec44ca,ac567b37,891e3eb5,c40fecf2,d4c5b106,bd222c8b,64ab491,f7a028a6,a02178e8) +,S(2e5280c7,25a109f4,c5de565b,9fe5357c,718f9fea,db53aa9c,b07a0f3b,f5030ad4,4783be94,1b162e,79f58d4c,448756bb,8ea18c4b,692e236b,4b2b3ffa,24a456b4) +,S(bd59ac74,92d24606,9b233efc,1b68c371,bbc9713a,284f7f0c,699a1d5e,ccca64ab,1abc71f2,fce8372a,a4a16abf,1d75bd87,a19c08ed,c8843f44,fb71bb7c,a74ec4e3) +,S(6acd12ba,4623582d,d769c8bd,3d6adabc,2c13ba3f,bb67e4ed,ee0fe70f,3f832f5b,982fce11,ff1e6c05,2f21be20,ce1710d8,5cc043dd,eca9bc43,5d100d9f,f68150b0) +,S(601f4285,8b0cbce9,90500c64,e7eb77e1,c433dca5,55e6ddff,5264a98,d688decc,56110eb5,d5b3ed79,5906ed4,c0275827,79cff7fc,ddecbe7c,74d2bf10,ab2beac1) +,S(4d393daf,c47391d8,8208263d,b8132156,e9fdd6b7,da48eae,90489d12,832dc938,a14180a7,898a5a00,6ae5b8c8,d034c233,93ed2ef4,faf6a4fc,42c4df1d,62d0ea7a) +,S(4ea24f6c,3c164285,166bf2b,1918b3ee,3cac8631,5a1175d5,4104506f,68b7171c,87da621a,a18d1a18,b1dc222f,af37b5a0,b149714a,e755ef03,ee3af91d,f2a7f5ea) +,S(eb1f6f2c,a5749f80,b88a7359,f0b67230,b2b844a2,4fb72dba,f5604e73,cf6e432a,6f58093a,55e3cb37,8830e58b,10612b24,56a35fa4,b8e60409,1b9b8304,e35cca51) +,S(2361315a,3d41b82,98a9d768,be7f453c,eeb977af,bf1db132,c831bc00,aaccc9ab,90df3be,336d4b58,7965778d,9300cc1b,3d954d4a,89abf173,a9bfd99c,29492dbd) +,S(44f432f0,46c7defb,630d5535,aca1bd47,10505012,6b2454b3,4591b079,7f8e9b28,1fdfbcb7,25eee981,c19f98b4,6bd19dff,9b6cbdab,730ca2e3,1643d415,e3aa0489) +,S(d563a475,4c130e71,81b60a66,a3f2ee52,7040f9f0,eac9e26,866fb226,f93db593,49fab7c9,6e320961,6f4610dd,532d547b,b24f7f07,f916f10e,630ae5cd,b40d3b11) +,S(2fac4651,f0ac9876,4a74c066,16e7f1b8,aa6d2bb2,99ef9f0f,43bca81e,7a4089b,fff2b7b8,c330e1f9,86a69324,a63bf10f,fad8e78f,dfbb6062,c96a67b9,eb460d5f) +,S(b6f60ef3,d8b793d6,5794aa89,12e8e1a0,9ef7604a,5c9eaede,b803fb31,e8195dde,b9b17946,4057de11,9d0bf993,fe92e4a8,bb633d6c,d03ce8b5,10200166,467e6bbb) +,S(d08c6813,65789ba2,4e580637,2eaa1ad1,d1254462,3cb64d83,5ea2e1d8,6e34620a,e94875ca,f5beb1cc,f88fa3c5,e2776203,a6f3cb5e,b4803618,52215d0a,9076b185) +,S(dfda222c,a4ddbb56,661f56d,b9b74be9,a5a7c34c,4761483d,928aa48,9bfabf52,bfac4ed0,ab4ccfa7,caf64d8e,ffdf1aab,6aad50db,595b1b49,7fab28d7,656b6475) +,S(3f72e4cc,ef5c0bbf,995bf8b4,67759969,d93ee40,8e738a4d,41f55896,17f241ed,c42ad857,3f49218,c7daca7c,8ebc5c7d,f9ac301a,2aea209c,ab6648f9,8ea16f5c) +,S(6e85f587,91431b6e,dd848aa4,70101103,f63881d3,2fa9f1c1,e3324161,e9ebf0ee,f7f00d38,31e09d69,f0684107,59dcf837,eed3d833,90efa352,40a9ac5b,2daa2a57) +,S(d991fc76,2f75235a,5268a32d,64dbeac1,b2333a34,5ad552a4,cedfab54,9b191f14,90d58a07,794983c8,3f6edcfb,55ed0b68,8f43d9f5,eb7678d,29610299,63c748b) +,S(24cd7922,7ef207bb,6b9b678,5156bf76,77101e6d,f5fb5576,a9d33175,8d7c00,44608974,5f1157bf,9c9f45a1,b212a978,8e348a0f,55129935,b038940f,84e91468) +,S(5c053ed8,367806a2,8545692a,47314850,66910d02,3373b89d,e85bc7a1,c25bf6bd,9a3e45f8,dde03e64,6d6c546c,cf4c8fc5,a253054a,2d6df43b,d8c4afb6,385311f2) +,S(4f3a4d88,20948d82,b598f118,1d350719,ffaa5ce9,9a7f614f,a9e3cbf2,e021a6cc,149c6722,980a41ce,5d4c0b94,9cbe3c99,4d94f2d7,c36ef45c,d7b9084a,79f451a2) +,S(badbce64,8d55b579,cf8d6dc6,74580211,a6bff856,10804077,adad7c2d,238aa542,567d75d7,1570d7e5,184f4f4c,a53fb92d,654b67d1,f6bff96d,fddcc3fb,932f0343) +,S(d2eda540,5f828eb2,cd3bc5c1,9f9a838f,8a1186eb,3cbe9575,5cf6642d,13601942,ecb3dc3,655ea992,4773cb57,f4f4c8d,6380c665,69f08184,f521dada,c108629c) +,S(191ad0df,31c7f3b8,258e5bfc,ec9d1ff1,2143b240,24d93a17,893da095,97304f1e,4ad4991,6bd2296f,b6f6b697,dbf5a3cc,4c3ba136,6f6dfade,c859b190,48fb523f) +,S(f108bdc4,a1874aff,35bd1fac,b8e81b5a,7a7ed597,e78dfb7a,c716bf7e,7a15dcac,b88e4fa0,d630d92d,bbdeda05,4a6c6624,e7bb1d5b,a6dded85,347e5275,e08c9414) +,S(30fb7605,7e2a6cdd,59fa279b,3574cf1f,db9d5159,19d0e523,990be02b,da1ebffc,5743e72a,752b558,1b959a48,3b6229c2,33fa1b3b,2719ad3c,a6f8f9ba,1702ae8d) +,S(6facb1e2,6d1ef1cf,ff413145,63f3b2e4,e762ee7,3e43378,c4c15f85,1cd948bb,92000e2e,a3a5bdbf,f6eaeae8,8619f2a,48b649c9,19972b7b,83cbac22,62d484d7) +,S(741c1253,8cd4da52,c596840f,e6233558,fb480a0d,43232756,2a9e2d59,a574b981,79040b6d,580efd7d,84356117,a93941f6,b47e6c0,a53627e1,bb80fcbc,e6881234) +,S(2b86fe60,2b2e87f,59498185,4af1f986,7debc5a,84ae8bf,94d2d6ab,4ec8be09,cf4c27b6,b33b5020,2ff7fdd3,ff0743e8,f28ca75d,3cb74d21,ecf21dab,ad7ae079) +,S(e6e7b676,9f0ed86,4163e9d3,66a7e2a7,a37f1ee8,e827b105,3119b8b,d36e7b84,c2e5b9b1,d82b4504,454062de,6c24430f,53e03bd1,819eb1e3,2f24606,73d09be2) +,S(86600d22,e7bec946,5b0afe05,5e733b03,f8f81548,ea44e008,740ac807,ddaabbe1,abb367d0,5e6d2fd0,a2c1d0af,5ded2926,1439c985,ef287860,80614bf9,8e8e33fd) +,S(67171261,5cbe2da0,b252a773,58f81c91,fbe561f4,87df09e6,cedc8a55,cb3414b2,bf02d81d,10a47287,2b7e65e4,93d97cfa,e3bd6ba4,39977371,8cde674,8829b0a3) +,S(97db468e,7f3a25c4,c34e202c,e9b2480a,4344aa9e,1b76a147,4bd375ed,6d10c0da,c58ceb67,a28f99de,2eca70ef,e8af24fb,c381f962,d5db6e3c,481cca6c,469c4c27) +,S(f3ac0267,ef19ae9d,762c4023,4ba97e33,a88b015a,e6a83f4b,cf730d84,405aed26,cfb8a3ef,d1104873,8c1c927,b31ebd05,105bcce1,d57c7fad,1972a5fd,cbe84f06) +,S(fa44128c,3c258fd,5a99c85e,775fca63,4e8a46d8,4fbff953,b373bd50,6ca3da85,f3196e74,d17cae3e,3c9958cd,ca591374,ddffcba,7e362139,17e5e119,a5538b1b) +,S(95244462,1eda0b2d,acdc1a57,41725c1f,a7c5660c,feafe18d,ff8789ba,164e7dbd,214bb6b1,7af1584b,76a9e5a6,2c32eefb,497324d5,7b00f71d,24b162e7,1383bff9) +,S(11de80de,c03a732d,6769e52c,64be4d2f,fb1d696b,2a658721,94aa384,392dff9,e1eb8932,42386216,f543eea,a2d1099e,531d8e27,7cb2e5fd,ec76b3af,e9e9c7b7) +,S(7318b452,a2b9d23a,eeb30bb1,3883dff5,b373be94,94451c72,36a2c02d,a4c37e75,26713361,aaedfdbc,2966fd1a,ecfa705,772012b2,564b077c,7f5db7b2,c810861c) +,S(82d189ad,e5610825,1b03cae0,4b138ff7,dd2d77b5,422535c5,cef9be7c,1899cf75,3634267b,1b3c3de0,d2dba36b,924949b6,7e05d790,29c9452c,18c6ff70,252d570) +,S(e5dfe995,82152513,80859865,f16fd0fd,e4d60c7,be0e2aa2,d9b2af4f,3714f8f7,e1d87d8f,fdef889,52918e62,5bcc90e6,83f337a6,103cd000,1cfd01d1,eef4b9bf) +,S(54cdeddc,9fda5fe4,63240f72,8ca66c34,ec05394,899f2472,d82d2378,28a06a3f,27bab620,cc373ed,10a71c18,345ff27f,e20e1bef,98052afc,bb45fdc1,80b94a2c) +,S(7f96757b,8b473785,e1359cd5,bffbce2d,5b26e8fb,579d7833,607d58,a791c47a,d4b43e2e,20a43fa3,5a96d1ff,93109aa0,b7831fdc,2d2c016e,181beac9,c1cfcc4c) +,S(eaed18ba,83238fa5,ce4e6c82,edaef108,b1f9929,3148f3e6,2d3a6d4b,535455be,1017291b,805f7b1f,eba367f5,9a1a10b5,f7501355,7e6eb921,20838c50,aab0d29b) +,S(91ca8ba1,da9c2625,66a135ad,81f57b10,65ea4632,5bec5d42,ca1ad62b,826f04fe,2d5d619e,84fac3c1,e30343ba,a61d3bfd,e1c4a9a9,8d968e92,d560956e,138e34ee) +,S(8a31ad57,12e32254,7d0d2907,cb73adfb,a9a1ed5f,fe98d645,22082e6f,1cdb1364,8ecc3fea,886737f4,f94a2984,e6edba9,8128b2d3,bc79a209,2b2c1a7b,b00bff9e) +,S(123acd6b,ca673170,400bfc4,1071cca5,4e03daf3,e1ed1458,88470c04,568b972e,e97dc60e,cfec2d5,c6a6e173,9d60f7e9,838ad723,ad0fc7e1,52b5e70d,b48b853b) +,S(d7c26043,ad647f0f,d056c10b,4ac932c6,6a545bbd,509de346,d4391942,52e69df7,6bbf2f04,2c9459cb,c72e6aa3,1b6d8e4d,e606eeb7,d5d4e0f5,7f729a79,ab1f5e9e) +,S(67c4eb00,548e2cdf,50626c8b,1aec1173,8370da41,9280c9b0,1c8783ee,91e018d0,ffff201d,91a4538a,97ceb50b,c9aac646,bedda1d1,3f22a121,c709bfc6,23b95a67) +,S(7e1264ea,486b08c5,19c7d8e6,5c80e1d4,d2994bb0,95185c72,63172b1f,ead93428,1797609c,816f10a2,e82afe39,65112a35,798b0874,b24503a8,f57c983b,6ce7ef6) +,S(912cb164,5f7d7bfe,5ea443af,1c458500,a95ff22b,212109e3,12fa01c2,41319cf8,bab658b0,111c48f8,a2f620a5,fd130d53,e1c70e7,62e33dec,55b22d87,38c1eb99) +,S(1d60694f,15577a40,f6b9f299,be5eb62d,251f62ad,b9b5651b,df804e27,df919fb7,3799eb92,e18335b0,bdbc29b1,f8ce07ff,3f7cd409,5840d5,dd324bca,2f902a14) +,S(8166b50b,811bf53,4a94af10,7672ab4a,4e154b2f,c5cebee8,c8ef6ebc,18cc3906,6dea31f3,343e5b45,f5b08c19,903491f9,349f4ca,29818fa9,16f5e02d,85e09ef) +,S(4852393,e42d0821,6664d5d,f85eee60,9660eaf9,54ccc6d,fb1c31f9,da17923,e4cadcab,17f64d8a,f5dd74da,eaeab7f7,13be1de9,600d4db1,a781a058,5ed2006d) +,S(f40031b5,ba171b26,e02be47a,c34173aa,18ec3850,1b1d529e,a922a418,1c3491c9,c2db89ec,2e50105c,4074b729,a53ef0a7,9371d2a3,354d2d23,8fb39bf4,bcb5028c) +,S(8926d233,3c842f9a,213547a2,fc5ef5de,b0bbd603,e69d347c,41e7d49e,aad76cb2,8459bc10,b7b2617,b0d434f4,b62a4452,80bb951e,b4ada14c,fa800389,b3ff892a) +,S(7f362b16,9d9bd514,c6289cdc,70ea4b77,e7518db6,a2e33acb,8acefcd3,d8c5726d,dd1e69e2,71d77dc,2629cded,72869345,7c63ea2c,8636c712,e45e6af0,4c15fe35) +,S(261b8037,98ca780b,50dfd56b,81093f32,d7c348e,4f093b91,70470ccc,4516ee1c,5723ca6a,5959d589,4a24c12b,5f87a5af,84c7a6a6,89304000,344bf5d4,81c7752a) +,S(d137c0e8,edb32642,12f6b958,8b527a9e,9e57f3fc,c358a2b,68f11d61,89fbd900,d1043b3,5f809513,ae370588,4adf90c1,9d164c3a,8166027,92ca55df,74c71466) +,S(96274665,253f4479,753de9ff,ac94af8c,943b8231,b1302040,bee72240,2ccc445e,8ef6f9fc,f1e21c2b,d913f877,98c6ac9,f53445f3,6c2b1678,a301a4f5,17867296) +,S(bc6ea584,b1f9b006,5f39226b,e31a866f,7f90229e,12aade70,136dc747,b37f70c3,23f1c4eb,99dfbcbf,66539762,4d20c4dd,4414bf15,172cde8a,b7652ad6,f87ad5e0) +,S(3e968741,5adc1afa,696e3222,fe351939,1d3f19b6,feb1de83,f4f1aec4,d25e2387,e3f4de27,67ea84c7,8baf1382,4b7917dd,477bdc87,cf1cf38f,8f5da1,e096b528) +,S(b5973535,c9c9d4bc,2b2a9b38,57cdfdf6,4995d64b,81c9e68b,abe4d4eb,4eee489,907cff05,5eded925,770280de,9ee0e025,1629796e,8ca05a47,48ddaf98,72bfdc3e) +,S(d616bde5,acd5f345,d23e8b2c,3d95038a,a1d7a354,a7613cac,57ec3e8,d07e11e,6c88c62d,d795d065,c6c86478,cacc56d3,2282b4f8,f3059aaa,55388555,449879df) +,S(540345c6,5869d3cb,cf4099c3,ba7422e0,feb87ab6,ad67429c,2dc99840,e6bc82b5,9f424998,bceafc7a,a58e5f16,c58e53d0,c0d51f64,285b0afe,e84ec9f6,b22f8f37) +,S(6b7893d0,ace6ab5f,c93f2e80,65a3de57,4d552e5d,4a89d660,714113c5,a256fb84,81a016a3,7be94a2a,f45b1bfb,968006a3,58398fab,424811f7,6765fe75,d4438d5d) +,S(357ea5e1,7a0795ca,cac47e4b,9e59bb24,45d1b6cb,2c713f04,7029f6de,2be57734,571de7e0,27dd05af,90bebc29,bd7345f5,77babdd2,75498bb6,d43a668a,8a4d6206) +,S(7baa2739,1db2a0c8,679d0e18,8c5e7c8f,ef1814ad,b7bb3955,519b4189,1a63ec40,73b56168,20fddbb5,749e8dfe,ef834f74,e266df86,e34510cc,f5eebb52,a868075d) +,S(4d5251b2,dd778e04,5143169f,8cab93b,9a9b7428,1a0ea1ff,964225a8,10b1e578,9376395f,2091036,16a95686,4e55382b,39b6934,2b2964d8,34face11,a44f491b) +,S(3c0fb553,b0c6330a,3cc06bb3,b0cb4c2b,31be7582,55264b29,98bbc166,ff57f7ca,f1f409bb,cc227824,4dc08c3,147e0b83,3522da9,6859400f,8d19272,e33ef1d9) +,S(6dcc7ba0,4b3b0827,e3bcb462,7b7db8d0,e0997c7f,900d27de,2d6c87d9,aab2c373,f2dcb11e,87b69faf,4400e9b3,186eeb6a,4fb48cad,6d6da276,3943772a,4e18b450) +,S(a5271e35,ca54c1b3,16d6113a,40414ed9,26bade46,c3258c6e,82a63e9d,927ce06a,e2d6051f,bf42dd9b,e0b2e00,1fa4e308,66232871,313f9c82,fd6ee37,6e8e376b) +,S(574d1ffd,976c616f,60371e4a,76b2712e,84b0a231,8d3c1c0d,3b56b10c,e978efe0,13733a17,a956efa5,733dc130,cc4c848c,19ecd6f8,7fae5ac,82c73de5,6d1bfa0) +,S(ccccd911,ea84c247,262a6e61,8028b2c1,a147f55f,b637b570,97400472,fe3e27ce,cc4b4f5e,491f32aa,eb6d0404,5965a97a,e4119e73,33bd1b39,f2ea9873,7d8f33ef) +,S(df1e4fa5,410f1438,9a41ca26,31eef376,4f10868a,f2f05a1,50e2c7f,8c3a2643,8185a88e,2b4a343d,bbc10da,723d4cb8,29014cd6,3211a82a,63627b01,1b01e87e) +,S(2ca6b7e,b53516c7,2e216263,213c0d60,fbb02f,dd227f6e,4ad29069,f6da9213,81d5fd1f,5264af85,53a8227b,7500d82b,84ca1fb5,87ea30bd,ab30fae3,67e3d7b3) +,S(df4bd790,ac3a0db,1663a8fd,aec1cdb5,b30c7a67,99ac2ed0,16f1c474,5bea92a1,db80f378,f33f920a,d0f4fad9,595b0655,44ffc36c,ebc3f294,3db13b83,cf609bbe) +,S(792648ad,8c053cb2,102dde19,789d3782,79e0e0ca,c500f40,d46bce68,97af2839,3c2d9b55,afa4ba1e,1ce3d142,5e17ca6f,191b4013,7b7d8162,8de35e8,801f72f4) +,S(dc6fe845,50fc1136,1f648fab,deb9b3f8,e7fee837,ea545228,b2fbd432,e53a8aab,2a4bf746,19fc5408,b4bc6421,f4a570aa,172ef263,c890c853,d7b06aa0,65960dff) +,S(10d4786e,9151f2de,89f368f8,9502b7fa,74b7b9e5,7a1485ab,f82fccb4,9c2deca8,15da7f51,bc84f421,2ce948cc,28663e57,8b4b851a,f6533f2a,b548adc8,147d2243) +,S(67c7c0ae,e82dfd5a,194dc416,41388947,29ddce96,5b7d50f3,ca922512,6e730bf7,a8bf40e5,666ba93f,1f723414,24d8a7a1,6a2aed83,7f022fdf,557e6082,e3e515fe) +,S(602c3df0,8a2efee8,329f391c,a9f7b2f8,31ab6d32,bc4623c8,92272934,1f78a4f0,ac17903b,3808ee52,c0208342,696f5250,5789206d,515421ee,8b1ab28f,5b788eb6) +,S(c3441893,e78910c8,3cf917fa,44b608b6,671ea508,37a7d2e0,4e658c6e,2a91d9ef,b5388381,17c264a4,a0876c3b,7c261bea,229c2d0,a7399c05,114f520b,a7185dcd) +,S(49dc68b4,412dc3c6,c4b265c1,6cde755d,bcd49f0f,394d552b,76f67ff5,33c7fddf,f1490a38,cdbb6c88,d270eead,7de6358,132cff29,ddb6aea0,1baf6353,4c0cdae9) +,S(89080197,4a95beff,da864c28,36997c7d,3a4c0fc0,4ad59eb1,5ba4b124,702d0f04,86e165a3,b2e7eb55,9a7996ad,63265609,aa6e3385,30b51d22,4ae4f16c,d30be3c0) +,S(c9671a3d,f749d635,5684de03,1764cf19,1087bd06,965d23bc,4ea0555d,29ee0804,33cc0d4b,b02a1910,c158db0,ad2bcd66,c9585f9b,456321d7,61752148,e6224d85) +,S(f3c1a76e,1d4ce622,dc667a4f,dc0f4ede,7eb7111a,1539ce5a,bca71d2,fd48a26c,269ebdcc,e1d42428,4e0dd49a,73968676,58857998,7a062320,6251ccd0,ac9f9e2) +,S(12002fa6,68924900,8a540429,50ba2901,5870a70f,7fe95ae3,dba4b07f,aa6fa460,51543d34,34568008,74e8b1f6,6ec72fd8,e2936b6a,6022401c,d13d50bf,931996ca) +,S(a59df11d,d3fcf1d3,264028b3,6e26dcf5,62083e44,f91f3d27,f23acdcd,f1392a9a,4dbda718,48afff3f,faffaab0,5c5376e5,5fd15ced,68b03ac4,4785ab2,201cbe70) +,S(89f738a9,802d7deb,5cf2895f,60916fa3,d6d74bf9,e740d2f3,13ba393a,b40cacaf,293aa5b5,b03557a,e7288066,5ade09cd,ae6abc71,8e7d445b,cbf85a44,a035b73e) +,S(d0414978,6252c5fb,b4bfdae7,56092769,dfcdc2f2,ae38a5fd,92ba9df7,f91a9ee,53ffb526,a24df2b3,d6e8faf5,ee6d79dd,7f427d8c,14d2d5b5,880f1863,e7e95099) +,S(4a638f24,ef3528c7,a4e42cdf,3f5bb946,81e6435,ba2c99d3,625dc282,b941d341,39d97ef2,949f1338,bc016ec7,89585780,832043ff,33777357,9ecefac0,ae40620b) +,S(70a25f6,34d32af1,47c4dd06,5d52f78c,eb5e53fd,64bb151e,18e8629d,f4f8088,1b6bf3d8,15a0f919,68dfd6a7,7ab7417,d4aed9c0,a52b93b9,9b4e4e41,d1e558ce) +,S(59ea9490,24765add,f99fd908,11c65ac1,d0f9ee8f,27e459b9,b5851765,8e96ab82,b38bc716,896e0337,e4a1b361,59e2b5b4,e1680ef5,beb4b47e,c5934b4c,8d6675b3) +,S(874a6ecc,6260617f,c6d4f334,40c8e080,3d993594,ccc2d47f,be2869af,9881f2aa,f509e39,6663327f,7d768a67,aa0d2ef8,353b613c,bb60fc38,bd2715cf,349c02e) +,S(dbf3567a,1e634ab1,63a860ce,244f3046,c7f486f1,b12928d3,1c44624a,48bb5df0,bcdfcc85,38e4702f,99f9d55,eaa55216,730405a5,66fbdf07,4c62b310,6baf7ce3) +,S(a534bcb1,96450965,5593155d,2da069a8,4800e4e,eca0b504,62d844eb,d179ac50,f86b38e2,d558be4a,b0a216a2,906099dd,f3cc16b7,30e784e8,745f39cd,829ff3de) +,S(e11bb840,b79063c,4e090771,29d2bce7,8f291f10,120b57ad,63594780,fd1f1905,7fcac0ad,e0cdc573,67c9d74,1c6c9928,15b7c3fd,3a19b266,e0e5a94a,9a9ef9cd) +,S(d79bf0b6,552c5b6e,6e9192b9,765e687f,ea226d86,c6f83f44,b427ea9f,14b404f8,54e7a54d,583e2cac,129f17d6,835597aa,934b4732,6ffecbfe,deb503a9,eb9660ad) +,S(103396a6,57856b61,5507969d,958de14c,251bbbd4,9851a5e9,ea64e0ae,2f87817a,9d66ba9f,cf3e0c2a,655cabd3,91774015,e209d771,334c461e,d27b683f,f83b477b) +,S(9b49e25d,ae607f4f,fd876837,5ffc0fb7,142f9cb1,f0fde836,537f320a,9636723a,3472462f,f9fa5ab3,1fd1279e,7953dbc9,85623021,e714c951,bf00f632,e9f72ab9) +,S(a017d4f8,8e757556,b7ee81b9,d4c9b260,ba2f7f8e,5e1b69a5,fff94abf,723cc438,5f2819cf,53fcc35f,c9c15d2f,13dd51e5,2c8dd134,f012aed3,4b4383f4,8b00cd95) +,S(aff1db2d,3fa6dc00,51a8723a,7127d57f,69ed0b49,ccbca35e,25f72bd,19076211,7cccb7c9,4adc2075,9c7f8870,fbeb1a1e,9f95d644,af0411be,a6b12d3,aa6f00d7) +,S(21ccbdab,f6902a86,d368d445,dfba0f31,4f80de6c,c7f05f7e,9fd1818d,45a174de,eda0b8b8,7f40e9f1,bdd5ded,e65bd72b,6cbe049c,bb1575c9,6b779818,a67251d4) +,S(c3e58ebe,36b0e5b7,2e15c47e,cca6848f,5312369d,d270dd18,93b589b0,56ff7082,212df92d,d724e3aa,c42e293e,b1a2de5,3c340712,7ebba791,b901ff87,9fce94b0) +,S(f19961ea,da1d77df,2fb9d976,7d7c664e,c0400066,2ecd7244,12b72dc3,c5de133,74f321a9,1287943a,8ed14d02,96b05ada,1a24fb52,a09d467e,8e8175ef,8f04a2c9) +,S(3aecbe48,2aaf6af,35e63dda,fc919adc,f974e89e,765c4437,69ef535e,cdc05e01,92b854b9,30e5e4a8,85397592,fde89d3a,601c733f,d88d230a,a1168e36,ee367273) +,S(55fdd639,b87de7c3,9acb95ed,33222935,bd4217c0,fee1c924,f1060f54,fd22055d,81f4ef46,16e51585,cb443bce,f16ad8e2,36d6ed18,87ddfa60,ddba2089,f4b83c4d) +,S(b86a6272,ceed47d2,4ef4cc67,bef0b117,c0761b4c,29548c8a,367d8ae7,bf90744,1c0de18c,d5f3331c,5439020c,5964404,be582f88,3feec4c3,112396ce,b657c4fb) +,S(d141a7ae,9d92913a,26deec5d,d2acb7a2,115da997,63be5a76,c5a0a415,8b5b8170,de784bc0,9308c82b,ce3be9c8,9abe41a,4ed9b9dd,cf817aab,3785e344,dfdc2ecb) +,S(af340559,6902ad5b,e3fe3464,3cbcea5e,7a478a32,b1bde828,ec966837,192344e4,3f65050d,13e7b969,35b013c4,9df385d9,833d419f,aac0f754,5c395ca3,75ae8965) +,S(b70dce7f,870d3d12,472d3c5,481a1288,cccfdb2d,12637a9d,973f4e12,b026cefd,4b4f733d,e5322132,80a36e4,ba57894d,a563f4ac,b1a55a9c,83c8dbc8,96a7fdf5) +,S(14fa3dee,44dafb00,d2e71c91,5d217cd7,a9c2b50a,edcd0025,f7aad2d5,b6c62ce4,67c3a65a,65bd4292,d271fe13,9a8c9d84,343bdf68,cc16e50,11676580,6bc30d8f) +,S(baaa6a53,26a7fc36,e519d9a2,48dd3aca,f6f0628d,a6406021,caf0d0c,56d9bb3d,4fe9c638,c1078c39,a0fc39cb,e9a81bc3,4b15840b,631ecbd3,8ca4a2bc,10d1f3a) +,S(ffe2afcb,5e53bc7c,9ee07740,c8094a3a,32c8e627,4dec7eb8,cf2673a2,dba11725,68d7092e,2b8b56da,1653dfd6,42de49c1,799d3ad5,864e052c,8829815d,b2ad952a) +,S(a25d7c5e,83a0659c,5ead610e,b581d325,adfdd3b8,af03736e,4039ee1f,40612431,679ecfcb,b1da355f,d73d02e8,b79fc949,bdc9fb5b,5a4e28c,5e68c244,7599c806) +,S(1c5d082b,3121c4b0,2e0e2244,88e53b8d,ac5500b,bd396f0,7fc218dc,7311b299,a2a435af,4838d028,4d459216,f3955427,59f1f51e,9a15f28e,d83987dd,9c09e5b1) +,S(d8d21200,2cf2ceae,6c9a90db,89f7d0e0,42a2e97c,458b9024,437e28ed,a775ca26,b31b6a02,4b01de6b,6159ee51,3c118921,f61a536d,c1442525,cc613290,364b9df2) +,S(b5265664,54579771,947bee20,f8e7bc48,1e15d07,2adcecbc,3aae7b91,a4d0f3b3,170ad05a,da7f67ee,f7c611ba,3c55c835,f054bcf2,445e5c1a,399c7cd7,640ba8be) +,S(1d0d2a24,8982635,18a28203,b78cb089,acd5c296,98b86b7b,48fd4db6,3c80812b,71e2e1a2,7bff3bf,9e85e145,7f446048,7643f154,1cbe829e,f600d861,dbb752e0) +,S(cbbd4ee6,33aec586,ec7ba712,c3bbffaf,a0e6497b,8618a476,b64c660b,340046da,d792753f,c73090ac,177ec5e3,40aada73,3b31dcf3,a1f46952,625dab85,7e9b9795) +,S(73cfd295,99b6b80f,8757a873,ce9166ea,b1960f77,fa8f1d55,ddcdc90,9420a751,17832aab,c1083af5,683f8cf7,23c6376c,c22d190,241e1e37,6b1ef2dd,7333c873) +,S(20572bf8,abe50ea,37a064f,738dd18f,531b9404,e7e4d693,2c9fc34f,ef6dede3,41c79375,11c8911f,3146bb2f,63750887,c663d2d6,f3fbbd53,30af73c6,9d332191) +,S(ac208805,2f1518d0,3724ef5d,cb149f36,1ed713a2,94392f92,96173857,94794f70,1820bb1a,e843255,9025f3ac,977d9f59,4e812cd7,e27c390b,b2fe905,ae2b7017) +,S(33467f95,60aae872,b5c9afba,7f29cd32,a213f197,47745d8d,945d06e8,295afacc,44040bd8,138d9bb2,76181e21,79f4bf98,4b0c3965,a1a47d34,be8f47ff,52e15af2) +,S(1a77910,75bd3497,cbaff6a5,d5e8bd6f,439f5bb7,ca3eeb98,68033ef1,cff83f03,d8af802b,daeebe88,f823c43d,447f1906,63ede3d4,c4b9dbd5,caf82a3d,b4f1cecd) +,S(dfacafe8,cc15f85c,f829d913,9a9aedc8,6a98e010,5308572f,94c183b5,533f5bb2,c076b6d,c708d2c9,895e22f3,2fe42f4,33ad38c2,a0c55aaa,5c551fac,fe601916) +,S(3cd975ea,9eb5fc56,14955bb2,db0ca413,b83116e3,a09454dc,7fe973c5,7ee33ca9,261e5544,2fd503f7,7c1c7a49,de96fb50,aeac56d,30cf3ae4,8b2e1cb,1b9fcb6a) +,S(168ac250,d23cbce6,23eeda,1389e261,c56bc718,4234bebe,6b108bf9,bf6df45d,add3ffb7,b0a9a860,21ca51e2,f3d2e2d,19206bad,78d9e661,2895068a,c880fcb2) +,S(47bae439,31966a6,984241b2,2afc8b86,94db88c2,abdb1737,728e1af0,e3803968,a7cb7d64,a07cd13d,2c8dc7a7,8a7a144f,8edf915,5cec20af,102260b2,d8d355a4) +,S(76e73a26,730b1444,8ecf60e1,3489de8b,93355af6,8943669f,20da17f1,4f04d517,41f75520,3d5d528b,2e81bab1,9ce8031b,bf9c73ce,7927645d,178ad762,669b99fb) +,S(f6f08712,d85f9219,bb475122,1ada6a75,1a8d4758,f5dd72f,f5231d56,e634c19f,d72cfc42,379ee25,eb0fb134,338109a3,7752fdd8,1ad102b5,f365a276,1d133f10) +,S(1acac95c,9b0ed53b,e6c37d03,7d47a796,2a371caf,cede380e,799d0110,b0634f7f,658c6b74,44846952,93a5215c,63695a5b,fc80f818,633e0278,f6a1193c,6d441bc1) +,S(5759a8bd,ab76d449,13258631,68773369,5b76d2da,7b1e4004,1bf99198,bb25f218,15c1dc97,8ecff6f7,cfd6cbb5,44ab8666,83127b41,951c247a,f44855,4afde3cd) +,S(cae1e14e,c28ddbfa,379a97d0,5f3ae379,3771750f,5a9ec743,2039f440,8fa7e2f5,eef09268,6b9f60da,8e64ae64,8f13d01,8f7b9ef6,aa849f9f,72df2f9d,f80fbf60) +,S(9aaa132b,947da7e4,9c1de2ea,ce06e3f9,ccdc37d7,6d2081a,be5f3a37,9b0756a0,e9bee628,d6a64476,af601737,68829c11,e8646e8c,beba7174,806d800f,56f6676) +,S(f38b62b2,4d609d01,70cbe85a,cedde44b,7a766a30,d8b7db6,8d935735,c4d0d204,8b61a5f7,e3caa2f9,17ef9ce2,c5eb2499,667558f,7c4e4e84,2644dfdf,a57666c6) +,S(25c121fc,74c57f34,29a143,8ff3c47a,f06b5de,74c4dcef,4a093b87,3a2ab659,69254121,eadbd76f,289cbf3c,21cc96fc,436ea33,9ccbc8e6,fed92b2d,331246da) +,S(95666156,c40929aa,8a7ca656,c42c64d0,e24c3789,ad3781f7,9e2a0ea,c7ab9c1f,116f5750,7e07b846,92106d6b,6976741a,59bf7cf7,909733e8,e1fb54f3,fd77e783) +,S(cdf1c010,7c48b65b,c001df94,c6e84d12,d8885af5,820d65a5,4e7ffea1,ef4c0081,8f3d1be4,206bd313,e1c498e1,5e7a9995,64312ea5,aa823196,9c566349,9c3a04b8) +,S(955269f2,be0d5e20,5382b2c1,959103fd,fa2c2386,9bbdd33e,a09487fc,294dd1ee,6306a092,4ce63798,41b2d773,8cf97ca5,e259f81a,a67b1e0d,42903f1,beaa869e) +,S(78013976,449ddc23,4d32a793,5ea525d5,9afa3617,47e0a8f9,c8141d9c,2b231e14,8d28142c,bb88abfa,1a72d583,4e509d69,3cdee0d3,bdff4788,83618ce7,a1ace69a) +,S(e6d67a8d,fe513147,2c0fe227,bb08a8f2,25e2606e,23672969,ad3acd65,155f972e,46c8695a,5b9d931b,adb568c9,d3f9a8a9,dd501508,fed00c99,5159f518,bed035ae) +,S(1779ea78,eed6d974,563cac2b,b3e72693,409b7029,789e0188,d061a182,3f18e962,82590ffa,6b9e0e13,d2e72bef,96d555df,9f7d2b81,2423a947,e0dae41f,91cc0722) +,S(28ec208a,6e929f8e,a815fc17,7b927086,7d482547,53ba5c3d,3b56fa91,acbb67d8,b4453dd2,eb964348,94cc1cfa,25616a2e,2f0803e2,8796206c,dd31ccd2,dc69aff6) +,S(c218c6d8,3124c9d1,c988981f,d4614af7,ff85a572,dd89e4ef,6209e80f,e7656de6,7259c421,45ef6e9b,d4f451e6,e2dd226c,2e750650,8ff7834a,965cca4b,cdbfede8) +,S(4c9891e7,5559d993,536fec73,a433006f,4f0e4e42,f427300f,7a3825df,85b1cd9a,7463ce1b,9f9af66d,7a5d2d43,ab0f09ed,186eb132,92c75431,ccee645,4280aa2a) +,S(a89fcff0,694ed82d,537399eb,b59a054f,f43eb74,f8e1fc95,be0c03c5,9889c931,3ef3c627,e3011b2f,38d596d0,8ded759f,fe30ffc,9db95356,4e01c8a0,2949ea1e) +,S(a8b3ef89,561da88d,ca9890d,5e4be652,8a4b8fe1,691d1522,54bcca43,1e7ed801,c86fc397,52254f61,88ee5128,4bd54347,8abe7390,c784b51b,6d41c947,5d58bada) +,S(6a2fd5db,da9093c,2f7c7ed8,9eeeec7e,efd7e759,eacc2946,5d1f3a15,baef5b42,8b71ac63,3886ef25,74e212a0,499c34e2,d2c7c1ee,b70fe7f4,38e08914,48395e4a) +,S(d33dada5,30626dc9,1d23d16a,620dbeb4,7551ca44,dd6c8b18,fbf136b3,1ae4e097,4161f6a7,8273ead4,443c93f8,2562a29,1dea1adc,d84ba0d3,75a997d0,f07d4ed0) +,S(53ef9ef5,731d9473,93e70829,bcac3396,3b7a597a,1f3c861d,401af7f7,fb1559d0,8654f8c3,63e53905,a4d1e2c4,378fc3b5,fd5ffe3d,e7fd3adb,399d883b,3d1b9e18) +,S(5f13c5af,6979832,da1bd43c,4b7df970,1ad837cd,e59d8f15,381858d6,6263b0a1,3b0ec16a,1024c902,666dca02,4649c110,2a17205b,e4ac20df,26ce5b92,8baf90c1) +,S(674b7de7,f65337a8,c66dbf23,2f86d6a4,feedabbb,b71e83dc,fd854926,86f14f86,e3961790,a662c6b3,70460e16,18ce3b6f,42bb6142,78fe9e2e,6bb1179,181c2aae) +,S(291eed8b,47c3e2f6,b3c2967f,76743708,5c460c5d,d5d6a75c,489dcf0b,4d98b8eb,e19a9d2a,72fa37e1,e10ec853,9c772565,c53e36e9,160651d,c2a8e364,db408ef8) +,S(e737a407,1bf4fbe4,ee5d3d74,7df3cb54,cca38f48,f977919,907deccc,7090ee3a,ac66d422,79441d73,2809d695,68f700a0,3fc5be05,8241da39,9be3a63f,8da16069) +,S(67fb1676,7c3231f3,428b39e7,bdd082d7,1194a51,ae99a7a3,6c113e87,d338712f,38c2ae1f,afb521f2,279aae5b,6ba5c636,1dd34c04,a7726555,acb9265d,31c996f8) +,S(9b3b4788,71bc413c,5e9d2b9c,61e0cda7,f2fb908b,805f3370,45639,5e616230,7028b68e,af818a13,d32f116a,aeb0bf45,215d3d62,6e6ccb1e,a901544,ef1d696e) +,S(63193415,59bb1e39,2f92dad6,e5f8576f,7f49d4d1,439f4f61,a6f2be0a,75bd99e6,259d5f21,6c780a8a,5bba3e66,2242f26f,1adef829,a535dd97,11f8e786,f0a57932) +,S(4163082b,7720a8eb,e881b398,dae059ff,3a65fba7,f8b93afb,6e3dae6,6a969c79,3939395,d8e90807,e77e87a7,4c89f861,c689de81,a37caf6c,32788310,7b938ffc) +,S(b3a6baad,15c01677,ad6bed54,ea5ee415,4d0bcb7e,3ce59f17,7ff26,ef23b82b,711681f2,1e56c0c5,f2c2b011,dcf75716,300e305c,110f4071,51d11890,25bc4760) +,S(9011d111,fcebd882,b9a228da,fdee1297,824c4007,7d5ad9bd,59e603b,43be8f52,d530102e,aac87930,eff135f2,e55b5310,7c03ea00,d24f1201,6653e3e5,5d778246) +,S(d50adaf1,d68a746,e1e7b148,7660e90c,f268450b,df460d52,e1f761ab,bf7018df,4ed454c4,5eb30cd6,e6f1c4d8,7df2bea,e15ebc07,e4b4e50a,e4dea733,93abcf8c) +,S(cf886295,d1eca9f3,4c95acfa,b86a5061,82e30324,ba5b495c,70318cf7,9e910d70,59bb7068,3147c26e,45c76e7b,e018e467,1f47f488,2c044484,62a5053,8023fd40) +,S(38723d58,ffc69ea0,9a8f2655,dc225da3,78b9224a,f8d81e7a,bf8f29ee,292ddd24,c41d67bb,e699e504,3198adb8,ff11a5e0,4033b66,98d3ec18,256bab11,93db5535) +,S(5b41d5f8,1e2443db,d13521e6,e7b7fdf2,4a226cce,f369279,22b353ef,107f759d,8ad730a5,bfb9f01f,853434b,24866a49,912fc756,e086e781,a07ff2e7,98ef38d3) +,S(4f3c24c7,7dc7e41,843e9018,400d3bc7,5d1dc958,2895c11d,3855b80f,4709373d,a485adae,c547a5a4,e0695913,c4c2fb5d,ea16a3c,5211c162,4819d704,5b0d8d6b) +,S(f603e0c2,8b40c8b0,a6a0378b,c4289059,5a4cf4c9,2b74199a,4e4e231f,a6b458a6,a73aa12d,76572041,f01c33ea,ca599a30,9ba0b838,f1d67fd,67a9a5d5,c3ffe258) +,S(84ef0a98,229c7af,9404cc25,60f4fe1b,4c8e66d9,1aa96118,53fc4f25,eac78a61,653df937,3640b28b,2c2c4061,1d79c4c4,a2d577af,b572f5f9,e50cf3fd,2b2dbcd5) +,S(e675d998,6b3bcd4a,d098ec95,c386be9b,4e96e448,ce6c9371,15c5dedf,d97941b6,4319799e,c4103d65,18590091,e333cd58,9901b020,a62565b7,f84219bf,e31003fb) +,S(10837b33,3603f33b,e528f391,b5b672c8,93fbd813,99c5dfea,f6126e6c,2a2633bd,cdee9534,2456a261,8a293b49,d91ed2ae,f620addb,ed83fc66,d169da3a,a6d0e2f6) +,S(4cb1ddb6,6ad3c1b,68c6b0ea,408ba1d7,dafdbe54,89c22d47,7a62dcc7,77a8e013,6c005484,29e789f7,5c34d8cd,a473270d,75eb8f1c,3db13856,87cda96e,5cd4b370) +,S(db72d671,ff3e0102,b1c52481,b66ea142,8f7fcd43,15e2792,eae234a9,291926e6,71c55f71,68a088f9,980bdb6b,79b052d7,4edd0b19,7ab7359d,9a2f9ce9,f1c5a5d9) +,S(99f92125,162e18ce,7493e6e3,91cd06fd,681371b3,2e147ab0,24ae3799,15f586d3,9286b3de,12ee578a,12ded341,75bdb712,d939b7e5,555e86c1,82f1f283,3c1b1d40) +,S(a2b8b63c,8984a666,2b09c18d,b2d7f263,796660f4,3bd78eaf,af7c63b,986c92d9,2003787b,2af02879,642b0a2c,f716f4d5,85dac86f,e58c7d41,d1959763,310a67e1) +,S(9292ef40,21bbe6dd,8c26a862,c9b7da54,4292e479,a9e89264,618e3a47,9773b446,d1a51e4,65bdfdd0,dbf74fd3,d449f6bb,ea862eed,ad369c52,34a695f1,d229ead2) +,S(8d5a920,547d838f,90159068,ceeab220,cc6aa126,d423edd0,2e136cc0,1cea5d4,c3334a69,f7694e9,43ccb182,2caf2abf,f4caa83b,a006af52,bc010bab,8710b596) +,S(7b62f4a7,7b79c09,76dd2f74,4ec08d9d,21511fa0,7891ff5c,52b8dfa4,ae3430bc,70ab2073,cb3a7cea,350e6aed,dd0c9a6c,ff8e02eb,69bd14a8,a09e9b8e,ccb19a0a) +,S(e18a9c02,5829b47,cdd34c11,f97f2edb,a7fb9b9d,fa4777a6,dbdc3cd6,85245b12,7386fa51,881fe49a,adbd5327,8d6cd0c5,1063dab0,aa830b7d,88c7a4d7,9998e743) +,S(ab9b68ad,61335dea,767c763e,3294d414,74a6d4ce,e4ab9a78,7fbb6749,7307d0f,aab48fbf,53f365ad,bf94f823,ea973a25,f6ddd341,397bd81f,8e825f60,c916852b) +,S(3412531e,8423364d,8d8bac05,bb78973d,7b8d375a,9e52d81e,bed48027,2abdedeb,1b9f5eae,59ea3385,9de752f5,db973a86,4c735e69,fa8882ec,e1ca8350,77d77335) +,S(6a6425bb,af9f65d0,1a401330,46053b50,7ac8d45a,77b30de3,69eed52b,956799b0,7cbdae81,93368c60,5671ae9,faead4ca,2887bd8,9a06062b,dd6707fe,f849f484) +,S(87860648,af9ffbad,50871c2f,29bce0b3,e9693835,8a067201,5c1156a6,7107a4cf,8660c0d8,f1aea58a,c613f6f3,5b27baf5,53835493,fbc0e203,f024ee36,27bbfa53) +,S(35733610,71c55057,5392c685,3cadd8a3,6618443,d80b3625,53a2f197,d3c52539,42935628,adab5bd4,e0aad0dd,a7d76627,58524b2f,34ded1cc,d3e44249,6d213630) +,S(82d21949,2fd48d51,65bea027,6ac15cf5,d27bd736,45e03271,24f0f689,8a2f4a25,f13d9063,fed02a94,1b4e5c67,f42d82b5,33f18ff9,ca4622f6,79c6aabc,ea454c21) +,S(ba1a1c83,6dabf825,e517ff65,549e1d5e,729944a1,d7b17cea,aa4466ac,39ec6eba,f01dd751,3557249,d2fb224b,40ea19e0,57b4052e,adc46787,af587ad1,458bb4f0) +,S(5cfeac36,6bbe58d8,45a36cd7,de6601c8,56943a07,522364b2,23a1718e,6df8de8a,6651d3d5,a344af69,25fe039,c9e29e77,95544b96,66752f4f,c9a3bb57,c5586c32) +,S(e5e314fa,2b2bb630,6fc235ba,cfd356ae,bbf88bf7,eb039629,165d8651,c0c7d5ff,c727787b,a63cddb8,feef96b0,2f6c8d0c,9722fb4c,6274e034,32d9016a,eb4d8cb6) +,S(f84d8db4,b745cfc0,bad4844c,b5a28d7c,80ed5fe,6baefda4,1d9cff9c,158c7ec1,cbd7bc36,a8313a27,feb8121f,a8847bd7,937fa53a,d56ea066,fa600411,d87dcad8) +,S(8806a2b9,d72156ee,4948e86d,43f4b3ac,cb24529,e1b2b2f3,5ff94812,e9534513,aff42464,773f6535,b4dc5eb7,76a3f7b0,7bc2fdce,1413587f,c4055cc5,afca3129) +,S(e2ddb5ef,a1105437,b6107305,bc715e55,ec0266aa,a0ba1bcb,e12ab801,45af7eb2,43e4d056,804f229d,da5a1efa,8f429189,6c9edf94,fba505f3,1f22b511,8b698ba9) +,S(636f32ff,ea843368,c0cb708f,43841ef3,20151e39,35683ebd,bb1f476e,af2f8c5d,7fd53321,517616c,c7d24b51,851bede6,b03c50d9,82269773,dd51e36e,4898365d) +,S(bbcdd1f,f5b47391,d728a06d,b4783d5,b0e279cc,107488de,44446e36,9d11d143,6ac7dfc6,47d25b37,7281abf9,ead782a,b5f815d7,b2c9f6a8,46a8a6eb,9253014e) +,S(af0ed949,22336a4,337e9c01,53357e02,3d7a2728,3c649712,3e117944,39ed3577,d8b9c03,958dfa89,ec2105b1,d9542d68,568797e3,7df16cc3,861627f,298f3359) +,S(11ba75ae,db365552,b0d3f938,f03a115a,544a0818,b2f54f50,e4873249,6f80ce13,a6bce69c,f9838317,70f70370,7073e87c,61b65c0d,bfd34dea,f0c549f9,c58e674f) +,S(e7560fb5,79e5ca35,f45881db,b05383f4,c5536ea8,a5438fc4,ec198ba8,7543d3ad,ff48d1a0,bcf5e510,9ed50a0d,ed8e5b83,44da25e1,a1a3d421,606d19f7,e28fe79d) +,S(ce7e289c,61f4927b,bf933eb5,193fd2a3,a0686435,80c8f235,1e24c33c,e418cf10,17246f2e,e87f4ce,f1c8596a,ecdb1f95,1407ee7f,dd839c9,98102344,2f4dcbcf) +,S(b765b875,32ba4db1,211c612f,b833ba18,156fa0dd,875aa61,df1ba9b4,7d1c405d,862d28f6,d85a8ad3,bebfbc82,437404f5,2e0abafc,64369b51,b75364cd,c827171) +,S(400560bf,d2863ea,2bd9e246,4eafab2c,2798cb95,b976c022,bb9d2153,e5978a0,92ca9a1d,938e53d5,d10f1f83,54abe43c,e8f8c2c9,d4e851cc,a363ed59,71e2681) +,S(7859190b,8e619c98,76af21e9,64f323e5,221cd4c8,83dd9fdd,e56f691e,e3db91a2,e1874376,755165c3,72abd73e,415f2663,bd94cf28,2009492a,e5034da8,6f6bf949) +,S(87d90b40,bb472b84,f9d24caf,ba7a6437,b50febd9,5c643aaf,e235750b,12527ef6,e6a0f719,25697425,23517ea6,183faa64,dee1ef63,183ab1e8,3a603b98,20452c4e) +,S(dbae1ee5,a1b6affd,f9b41ff6,a1f2790b,2c492ce7,53865690,ce5281e,a7f08177,f6a2be90,a2c3cf,8e14bf87,4cc52648,b60f9a26,2930f6e8,9fadad4f,d919db6a) +,S(943a79cd,88260475,10d90c99,4d8d784b,32c03d1f,f2478102,96125f7b,28576216,48d4477b,f97c4cbb,4a96ff99,e427d4ac,cda9a367,2ae66930,88d8cc57,3bb3e2d7) +,S(699911a3,81ff3c7e,71b3a458,14133f3c,ec644378,e3244d66,6d083c55,7b6c040d,3eec684,3190d6f3,85b07116,b3b1ba15,4ecacec0,63e02933,9b83afad,5598b22a) +,S(f002302d,9ca256e5,cc38ad82,e529b461,efb69f28,52513917,fb8d63df,45e602ba,78455ea9,708b750a,97dc74ec,8939c880,d76010d6,78e0c112,3616483b,fb4e788f) +,S(5f701ce9,65a20314,a65e2c0e,1cedded9,ddfc9d01,41a1e095,e91b9915,cd2aacb1,57e770f2,d04e33ff,c9d7807a,4c3d1edb,3f9ed2,c19771d6,7e85e618,463e5663) +,S(454c122a,ff85c42e,49d6f033,87744462,8acfed31,90c41255,e8e34928,83563fcb,9d9d6435,a2c4d146,d92f34cc,40b32a7e,55584885,82143a,52039fd7,129fa6f6) +,S(d9abd19e,81f392d8,8382918d,6ab3f89d,de793abe,2eba3aa7,b58b0ca3,1e614e51,8c1a0f80,8b8d9e56,aed21554,95f8902e,a390505e,15cafbc4,2b71cf05,575abeec) +,S(20779414,b5ed6524,b3613a8c,d0b6e9c7,ff3b14b7,7264cb8d,7b266ef6,cbb224b7,c1437dd7,71f46cc4,3cfa52a1,28c70367,d6682553,28942150,c4068da4,8c218d66) +,S(141739f8,503f2225,feb40431,21f0a5ee,844a7707,62e37d1b,3e43fad0,81c631b5,a0a13de0,10566ee3,1af8c6e6,38411c1c,a3df6c63,c8ed67da,8ef7bd19,5fd6e73f) +,S(de8d06ae,dd58b148,91184145,fcd9bc64,634725fa,e4a77d35,70b21c8b,77890b60,a046f351,eccab99,1d3d1c1c,642387fb,fb9c3f92,75bbb93,46688555,f7aa9460) +,S(312c7ad1,53f7280a,9bb86cab,ac573944,d271bcfe,bd59291,c6f05fe4,ec003a81,3c6428db,5eea01c6,9fa2556b,1f20c1e7,4e65629b,e73e6429,81b971ad,b6563866) +,S(2eafa04b,d276e33,75b8d063,b206785c,ed69f763,7a5a8b99,ef7d3de,bbcaf35,f06464db,56ccf55a,1f41efe4,d1cedf81,a642da24,3cbe68eb,6ddf7ace,f67dac6d) +,S(5873091e,dcc8a95c,a0a47570,3d88e54e,1381c2d7,a418f615,eea97470,2c2c6fbb,5a91598,b8e47d2b,2fee6cdd,c33aa309,9bec74dd,21688542,9b76543a,c233ccdd) +,S(e713bd84,ca505ad3,aa022577,c0cac85b,466874a5,b02f4ab9,e8d14bba,c131fcb,706dab4a,fe49e6cf,d290913d,358d1dcf,62e8b4d5,b9bd46a,322ee4a6,5a660849) +,S(aacaa633,6fe86d41,b05feec1,cf4866d,340fd268,f869f912,c2373e10,bcd95340,d933cc5e,c01024e4,77d1e80e,c533f293,e4fd0dcf,7d1156b8,7ebd9d81,b9489c57) +,S(cbe0ce9c,77649031,25590e03,cd9643b5,dc45ecc,604d51fa,d5bcb8a,196b65ee,d2287fed,c331d56f,e585bf1b,793fd957,ce425492,df41d8b3,4faf84de,c3bf4d22) +,S(f9990413,deca9f9a,4ea6bb8,fd9b8732,57d15ec3,70e98187,f4170103,dd416dfd,b0593cb5,dbce573c,f0a75f2b,c4756781,963e1a2,e988e0cb,23efbe26,c215ace7) +,S(2ee21d79,bf3e82a6,2bcaef34,85276c5,3b51bfd8,becbc9f9,6ad316f3,a74bab97,fe3cfa79,b208de80,f659cb81,bed12184,ea2c2524,dc0bea05,64acefab,1acd8fb1) +,S(af5c91d3,44fccd3e,70345a2b,ccefc0d2,19287be5,aca40ebe,e61de522,56f25faf,bb58da83,bebb5346,9b345695,fc23853c,bc0221b8,5d75ced1,da107fc5,c106875c) +,S(2cf50e13,477d628d,117e0bb6,1d3ff9e6,1108fe94,bf82a6f2,4138a743,6077e0af,339c0a53,77a6465b,29377e1b,dc344464,875687e2,7d1f392d,96a275a,e259793) +,S(c51a6610,1522f63b,84b98ec9,31984865,eb3b29ce,fe115b28,a87f89c,67bc441a,240b9717,6af4beb4,b0502d7b,2caf8c7f,47a9362a,9f9610c5,826762ea,a2a2be5a) +,S(27478eb7,b14d84b0,80426792,b0e2e510,8a4804e3,a15e80b9,c430d7df,c09d05ce,eaa0a072,86fac65f,3da47bfb,4010fed0,fe8a9e17,ae42ece9,233c2078,2b36422d) +,S(531ca72,e21caa6a,43f0c9bd,d0bbca5a,b12dfb9f,70f045b2,f0865077,cdde192b,c4ed88b1,a0397589,3cb14ed0,897d6bd,783dc647,ba59772,16c308eb,630367e8) +,S(295775cd,950d0702,602278a1,56c1d05e,4343474,a4b3ae87,63f4a686,7688e42a,907fa8f,1269cb64,41591004,f6e62b14,4d6c54b5,f6ed424d,6b0a8a75,26935b49) +,S(e88425d8,bf6e89a0,f9c9f525,97eedd4,3c331058,10936c23,4da69d21,9a86f82,56d53ae5,e7a354d0,d65cf742,d603da2b,199e147,3d42bf3d,639f83a1,cf91cb65) +,S(4d20a032,c44453f7,b374a82f,f088d816,c1fa9338,57dae8c7,b87295,98869a4e,a7ad5993,af43cd42,1620e87f,fa0b3305,e7da39ef,704319f,ae5faf55,5e3fb43c) +,S(b98e9728,e9288607,a7ed6df9,c68749e3,9d7efa1c,4f964428,5e9bf81e,246e936c,1620c470,19b9cef8,7c1f0612,cf56adfb,5526573c,f7746a98,48a0d40a,3a92d38b) +,S(562eb109,e9988778,bed85413,2fa7d086,6b37a8b,fa2d2d3,470da3c6,97996a48,29f4f0da,e554e380,613156e3,34207e6,fe8fa678,4c08f2be,c3d6a59d,1e0941b1) +,S(b189e864,8dc0ee06,b09ea73a,9a01cc06,b6fa74dc,f626e41c,ffad926b,901ae851,4e42c870,3d04838a,9f0682fb,bc13c849,a515d5f2,f248f393,e2caf0c9,b6d61d0c) +,S(3894cdb3,425c618e,1da2c6bd,1177109c,49362a4f,24030692,244bb0dc,27af6913,20c0021,5c72939a,497f08f0,bdb03493,8d04ddd4,8fe8f3f2,97dfef19,ec9397c5) +,S(394f74a9,9146fd43,9035266b,ccee72e9,36ff59cb,eab7bf4e,925c6363,fce7d4f0,c7da15cb,c1cdcea3,21efb1fd,c56bb3d1,2bda06b9,993b6f5b,2293e493,5aa3e5a) +,S(44fc66ca,d6e67f97,be95c667,fd5dfdfe,dc82edba,35df2bf4,737b3ba4,14d15c27,9c485757,351825c5,245c6eab,2ec4a51b,ac60c9db,fff7988d,8f28728e,60f418d) +,S(fa355672,d9f7a1c5,30b2d76,f183720f,e50840cc,ba413b64,e449d2a,8b0518dc,63fe1c7f,d97c7744,35613167,660926e3,b7377fd5,97dad03c,9debba5c,a5a76e3) +,S(7325c269,50f1bf21,2f9cff6a,170e446e,62dafc2c,f05dc50,4eb951d2,6322eefa,5f8fa04f,ac5232b6,cb553630,5a48b647,263a57d1,2c485363,6c930497,40965f00) +,S(7004b364,c89ac7ba,ad03a03c,c8e2972,e5fc52c,bc656165,e08df216,afa216c2,971a4284,80556797,ebea8b1c,b37de6a4,1aa11abb,df9b28b7,7f50d362,b6554974) +,S(ffd45087,eb9308fe,e7644817,9406d9b9,77364732,f3570ebe,80a4710d,a0ef292f,f4ae4df0,5af2ee0e,456cca0a,2c9d93a0,83eb9751,a09c2f8c,5bcefce7,83764ffc) +,S(ad899e8b,a7aedce9,e53d86ac,5ca15408,140c8f1d,be3ba4a4,275f332f,b0320572,a914795,bfd9850a,24251eda,98bced8f,2e2627a7,8a1bf6e2,8b66ffec,f11ea105) +,S(7078718d,e94255ff,ae25f1df,4ec2ad90,e59ada11,5ad4a6dc,8b305fcb,93a1114f,ee736453,927cd7ed,bbb55010,32eaa95c,c0f6bb42,be77db4d,62b77650,1094ed7e) +,S(30858d4c,d39abb36,51b8d35,58800c18,5495bf31,bf23dc8b,176c1f04,171e304b,3aad8415,4abdfbb9,1eb95aa8,4e7ace9b,fd8b5f6f,cc8ea08b,e094c874,8161f85a) +,S(c06d6d2e,5637fd7f,df08b41e,5573478b,eb19dded,ead1f0c2,9309fd59,9551c787,78cb2514,37d4ca62,91bab9c5,57e88244,edb9dc30,fb1a6441,78217039,628e1db2) +,S(2f93455c,279d2a26,1cc7b724,4c32c853,459e5d99,32692fd8,ffe7ff0e,493de2c2,455f0902,74d698dd,a1a97586,fe797421,899f7c22,60ef0bbd,db0664e8,fa323156) +,S(c00c345b,b4b53f5a,5dbc5f10,597dbad0,75e28162,32e0ac71,fd778c50,20b663d5,c30f78de,3495063e,ab98f001,83fb4bb5,5cbf58a9,1bd52ea5,36a4a38b,cfe89288) +,S(7d78faed,f86a22b0,14e86e1d,f98d425c,fe2e65a2,39b37994,ab25a4d8,5c863382,cffee7d6,5181e361,679c9d51,feff7a36,e8d84282,32e752b9,62689eef,a1ff4441) +,S(ab492cb1,da2e8463,a2536c0c,7cf143a5,9626497b,23d4c179,d2af4cc7,f2b55866,11d4205f,55a74f81,e9512496,becb61c4,6363c42d,baede671,9bd7f2f9,3e00b14d) +,S(d1a3790b,478bf657,360b3459,555e1dc4,ece339d6,93b5b51c,8a3af121,79578688,c6028991,3ea89956,802f8b8e,cfc8dbc3,5894846d,1aba2074,9a55153b,83f73891) +,S(6fbb6fcd,36fe0388,a4bb648c,95a004f9,b3c64e4f,9aad672b,42d8c649,4c0cef3e,51be473c,74ca2609,c3b79c60,2fe90d98,62eb9d14,b9e52aa9,ddde106f,7253da44) +,S(db150ec5,680299af,681ce826,794e4818,c0d6d3d,e3c392e2,79ecb408,aa55b243,15e47cbc,1c4689bf,fbf7ef42,1db5c57b,e3ab8c16,b69bb518,2ed8a1cf,20067de8) +,S(51ffc919,afe67f04,a889323f,4438da99,72d2161a,54f9e81f,aa1e644e,9cb88835,e4b579b7,e985b38b,486d0600,3f825538,52a9d0ca,b8fc98d4,371a7e33,4898742b) +,S(fc86c54a,48052ae8,d8480235,e4dbb7a7,6d05d830,d2c0cbbd,297db0cf,3d2d6cea,6cd61522,e2a22531,da973c1f,9cca1c77,98ff66a3,8f568935,e378f73f,9f1d7dc3) +,S(d440de01,20d619b0,6add3d7f,66184864,5754a424,f4b1054,479a83bc,7df0db9f,3f09b245,91124175,89071c56,84215cde,a6999b17,b5b2f664,6074e7ec,6c38f68e) +,S(f3310bc7,7556f234,e7c83d69,48afebf0,5bd91a25,b516cf84,60d0d6ec,8483fefa,1d10f23c,e0e35816,6b817553,cbae0792,9e34a4a6,ebb47186,1d401341,1ef2b3e3) +,S(ea770a59,e88b598d,493fc75c,62eaa9e7,485271dc,edeb1d2f,76df983e,54cbb51c,e2a4baac,96c9538,3de82a29,5bf3cf30,53bfe2e4,6fb0861d,65c60c09,978601f) +,S(2cd56ef8,6fd04d2a,ed4f8520,951798c2,a1c69a38,8e635a2c,edfeb08e,3af0e331,3b9de80c,42e0c683,85aecbd9,c8775b56,86a8a376,39efd24,98664343,e712707f) +,S(37bb0206,c96d8fd4,5315e96c,860f5cb4,a44d2b6d,af17844,bc305b4b,59c9c649,c77b4a05,373c42e4,e071090a,7da9b4a,4ccbbeaf,d399496d,f6fea1d1,a83808b1) +,S(55fa08fb,f83dab6e,ea7034db,15bbddc0,ab2b472a,b29861af,543a970e,d16033ff,73c8a90a,86542970,4e25f370,a5caa4b,a68eb72f,5ede1edc,5549105,491858cd) +,S(4eafb675,281fe8,98593817,efe128ca,c59fb775,82f6006f,339631e0,6e7d2e7f,41347946,6630f6d3,9fa97404,6808067f,fca9e173,3e1c4149,6567eacf,47a0bc6) +,S(857587d8,375f24f9,e6924793,9ddf3a60,e0469f38,6ea0d55,d990f1e8,4ba5c7dc,1913a118,9d867c57,2f947fb4,3e062cec,3df37c3,e8edc6b1,927b315d,10c37be3) +,S(89e334d8,f71eacef,6cdd0a87,b1e03352,1078a1fd,20dff144,10108202,93143815,8b49aebe,71b60eca,c9256794,3cf74d9,80bb3e47,161b2730,9ed15872,7accd84c) +,S(69902d6,8a4ecb1,d2e496e8,cdaebf94,58f71f94,8f4341a4,11fbc2dc,524f694a,19a54c4a,5de17930,6c50cc03,b0b8d54,b613cd31,6f0bdfb7,851db63a,9c605896) +,S(52f8a3bc,832de46,1bade518,50121b5d,2ff475ab,5eb0e71b,a91ede46,41f0d576,2a946bc4,42f24ef9,469b8121,31021186,5b22f3a,adf93648,5b7907e4,791236e2) +,S(146fc341,4ca1c497,73734f6b,b78ee9e,56fedee4,9487ea01,a31d3e4c,152d2bf,82e21722,e415f5a4,1a076f3a,8324db4,2436da5,a3776f60,b5c6f53d,e5419db9) +,S(9e22043,8458e463,b1bd7399,28200a4f,ef7c3760,a7b6357e,afc29a5e,36b37b94,b1f5fd78,c1c40d98,1473fd4e,72af64d7,7387c28b,7f005191,5ed2587,674877a1) +,S(53190555,8d044a1b,94caad4,526cbed1,82807c65,2bb053d7,61301ab9,68323f1d,ce591f2d,61b47a8f,8707d8f6,a8717139,68ad569a,667ba4ac,f2d18356,ab6d326f) +,S(b93b3c6b,1297cadc,392b0cab,da322a1f,69791a68,b48b0ce7,4352ba3b,b8a3cc8a,136ec007,24fd378a,53d5c573,3aa7a06,15b2fb20,4fed82ea,934bc131,7e7ef22) +,S(62e6af72,a9fcc956,4367d44,c0699897,3674e3f7,b79c67bb,8c8a82f1,6d3f744,4c1e4e33,2e9316ff,24a7b38d,13ed1b30,a659a8d1,8423db6a,af6324f9,4e7d5475) +,S(c91facca,aad0790,886c4421,d28f3ce2,9d64dc87,514f06d,cfe95063,dbbd0e3b,e7a0c83a,18d655d9,7a555c51,4bf8f117,59ce866c,61a7e691,8ecb1cfc,21e50710) +,S(72b3b928,bea91ce8,767b2f22,958458ab,9a23f455,78f836,65c89717,7e7ea502,773235f2,c9ec74e1,c06e4e7f,89247d12,27f303ff,2fa354a0,663791a6,ffa40e49) +,S(1b014ac2,7213cc08,67877fa3,c0c07b1d,91529259,23f6164c,f1d204d9,addd6f4e,e0dec57a,c1ec264e,380909bc,c62394c7,413cfd48,180b1de1,c5440d08,99c67f2a) +,S(985e8845,97e2831c,4ba48888,ac219b3,bd891dc,63176953,4e0d8a96,bf583a83,5afa0b31,1e909594,4b228958,657b95dc,a198b008,6f5cda96,c3e4da6d,e444a418) +,S(ec3cded4,cce88ac6,22315a51,ec99ed3,1ba2cb32,74a43e6,98e033d4,e490bae,1c2a2236,2704a765,252b2a57,aa1ecaa5,4f1c21a5,2d67c050,a3dba077,ad4b4480) +,S(f882c4f7,7911f6e8,64da7cb0,5f09da54,b9cf7125,21504815,e6fdb9e5,73f24be6,9ba4a4c1,e0978ee6,1f83aedc,b1db2193,518a71d0,c112b9fa,59c629cd,d42ebde2) +,S(f06c3a4a,9f1e80cb,e2ee6b06,ff50e447,13d8eddd,5857243c,cd02c5d2,7996eac6,6b38bddf,fccb4888,da20ce7e,495bac5e,7b9ec8b2,2feaff5,8d4329c3,c546e839) +,S(dd1c366d,5be82883,eb86da5a,f9b5d5b2,89de6b9,1165b91c,20ad7b73,ab4de421,19bb181,70b31a81,45232ba7,ed0fa93c,273751f4,838633f3,c94647e2,93c06bc0) +,S(e965c1f6,89b3f7a5,97d23d9f,378b9a03,fb1c6e29,5354de36,a5bfed53,3338372e,d98295bd,890e98a5,9d6dd93d,bd9eca2e,e79b028c,7459779c,2d3fb665,46692242) +,S(4f9148b6,cf21f5fd,911d7fb0,e92132d4,686d3e10,12da444b,f5a89040,69c2fcaf,60e9b3ef,924260db,ad68793a,d684c316,6889b0d0,38474c70,6ca25978,4a5fa7ad) +,S(d9341e6,6a505a91,dcefd533,90abbd54,52b39594,42deef9f,6a67dac0,8faa5e00,eafdc1b5,2b7c97f2,21ba8635,d49b58fd,17cc7983,92e09d13,8c41d679,6fda331) +,S(b948bed3,4f426bbc,e6c24ca1,fd1d2092,1de6f9d9,f561c32f,877a4104,afe81ae6,5cacf40d,f6fba19d,763c5b0b,83aaa284,f9485705,ad882b6,d51bd46c,b12f532e) +,S(73011c97,dbeaca8,8bf04371,311e9558,1e494b73,1778a2f3,cf906cdf,64dd781f,2b5abb31,c2e56a38,e8236f7f,b28a93ec,1bef3fc8,9be46d92,c2fc476c,42ff4ed9) +,S(44835043,1373a095,13f756e7,36ac8342,24004348,70d6cc5d,ba31f74d,565056ce,748f041b,a9c990b7,70c36f68,5667109a,acdad74d,4569b107,c968e517,143499ae) +,S(3463b029,e9dd1907,bba2b582,c9ff1f26,4a5ef4b,40f5af28,2a00c136,97145ffd,9e30bb18,fbb70c1c,edff9065,968523af,33665b53,3f14457f,59d7edbb,d5f07c5c) +,S(5d95aa9a,9fc67758,56e6655c,21a62670,c567e236,a41b523,436beb2c,18e69c97,d6478496,4220cd62,b4651e8f,965bbde3,22aeacc0,6557f656,764a20e4,649a1ea5) +,S(48c65239,d03715f5,71ddc36f,313a1723,b014c047,30cbbd8b,ca9617b,e8fb3874,c0bd39e6,3cc00fde,74c991cf,f6d711a5,356b029,5b6eb9c0,28c445af,21de8325) +,S(67c610ba,fda8dfe6,c7977b70,7a57ebd3,9654c7d4,c9a0aef2,80c896e0,e8134078,c3d4ffc9,891a4267,612aefe9,6c1093f7,8e1b9a58,746c986,c5265381,3ba46aef) +,S(4605213f,4a21b15a,4a471e10,f157d0c3,faebaf0a,f7cd05c5,a27c56c1,88b6d430,9853c145,5f4b3d38,200aebf9,d08f87ae,3eb4a99a,3d94ace2,94331e03,876fb751) +,S(6277ce5d,fb56c2fe,3d32e28d,6754255a,ecece179,70615443,b0d33e5e,b54e475e,dc7a742f,92160074,69d53e73,da526102,a6f68e7f,e8f07a91,98614f0c,17daf06c) +,S(7fbc032a,fdb50898,3270249c,f1a7d27d,198432c1,6815b7d2,c929ab67,bf12f01a,dd696a37,fbc4f852,6db85ca0,6bb498e8,6dc33480,a4f84564,2b49775a,6bf20ae) +,S(dc849e28,6b934ef,30cab6c0,1cffaed6,9ea74ab6,96578027,4c88845b,8ac264f1,6d7f94ae,347b9b18,bfa2bc0,d6b9a8c1,13ef1a70,78e317a2,53f21590,667f4b5d) +,S(e29e0833,7da9e0b6,b6886c7d,fe010cd8,9a4b10c6,f5e4ce38,c1202f59,94a69016,de082f4a,9c21db41,573dde9,d2ca8256,57c67173,207d43ef,e42ea81a,ee812dbe) +,S(407f0e21,ddccb63b,5672eb15,742d72f7,1a522f9,20d04247,3e1438e3,7bdecd35,28d6f39c,cfb36986,351d7619,daba6271,3c9869f9,357504d3,25c112bb,74ad336e) +,S(653286df,15bf657f,1685bb92,98462383,7c819def,84a8c332,77f6d777,4c8dd3b3,c5ea3d4e,f7a97324,96a98abe,f999c25,9a8c622c,944a099e,146c0708,d108eb34) +,S(47613ca6,ca7fe67f,4286f12d,3b4bcd86,455a1863,94f2bfca,e162f991,3bf6ed7f,4409a6d6,2ae63ffa,a3f2be74,e7d0e5e,3ad4704,76282b0,c2919750,72be1386) +,S(8f9bf4cb,4aee791,12162fff,75f35393,509fcd4d,aada298,655bd58f,567e6adb,893c8b52,c2c25f8,e2ea051e,d1a35a3c,8ddbbf9f,508ac792,37e53143,7818102f) +,S(4b25cee4,2f955db9,79c85682,4dae806a,3925a33c,42e6b6b6,ab4997bd,884f68b1,ebe38f45,bfa13922,d3112af9,1324f526,1c5f864f,4d722576,24e3afe9,9eb7ebd8) +,S(a8a40ca0,56b5e168,6fb9a348,ae26b15b,cf812cc5,b9c5abc3,44f86021,69958e81,a55421a9,4f1fda1a,f6d64e48,cee3e4a3,434293d6,b49a5cde,b521c0de,49cd31cd) +,S(1f7e97c6,198e27a6,48ffebcb,55c001f0,d591ca64,77c7c1f9,43928e2d,dbe88dfe,2dcf0a3f,f296f744,dd402fd2,48d29c96,49abc871,28624da,28134cf7,6242e6d2) +,S(7ee29348,7d6520a5,586b3ba7,4a0a660a,a4392e5b,77529e8b,890a5927,aad1ab71,a51d3123,b4faabc3,77bcc565,d66d4c40,92decf92,f63f81d2,ba3a4f06,2a8ea485) +,S(30880ed,b4f5f2d0,95c34730,d10a8c02,11efdf6,784b4886,4afff98c,407734fe,4ca4b106,41c55905,9a19cbaa,bc6837b5,300aa1c9,8b0d8a72,8caf5cd2,914ea693) +,S(bb7ffe45,b725038b,597a20e2,6f67d0fa,c77730e2,4ebadc9a,23afb4ef,a01b4d50,dcfbe717,46bc35b9,81357857,c0b4564e,1ea11852,c5ed8372,bd15eb69,e674e14c) +,S(ddb59e25,20a5842c,62607d4c,6d31f2ed,b79e387,527dc12,5d96fd04,84385e51,2a167f97,85ee4285,7471c45,2c38639e,69940f77,b3fcd54c,a697100,37d9e5ef) +,S(3c405df1,36b1c6f9,99fe0b3,2bf5a305,bfa4a6e9,994a1506,9c5fcfc,318dacf5,ba5ab8fe,43a2de82,ce289cf1,2255f554,d7881d08,a54017f1,e0c84180,d963f3b8) +,S(ed4e6e9c,9d4eb277,73f2249c,13d6fc1c,5c07be47,9ca48e35,913f6fe8,384851a0,8242617e,36b3c298,b13aab58,b7383dd7,93ccd4d1,7787062e,195456ec,43fc4198) +,S(60fb7766,9f312be7,11d0a269,a72a85c,e06b70c8,1d34416f,f7ce1a28,41d50895,ba2097a9,772a616c,82cd5dc7,84585c80,65206913,474f49ef,71579a3f,8cc0d825) +,S(1336a678,bd5d495d,c688c039,a60b256,a09fc946,830fa80b,1622890d,9c8f0881,6d57f261,b1073b42,f6eeb514,58e994f4,7406b3f2,7245a0e7,528748fc,65a4937a) +,S(adb7e6dc,72c02a9,fb99645e,a3695824,db60df0b,f9b6a420,75cf02bc,4e3713ee,96325866,2a062180,20f8b86e,e5ef1e04,57d01fd6,d5541d6e,50798883,9f03b3c) +,S(674d6e5a,6501f824,87efd592,c37bc14a,ab596cec,4d5e6e8f,1be44a53,a9d2f416,e6ca1153,76af0429,1bc2dd6b,2c47a816,c17e0ad7,c252c1d,cdede8fd,c9a18630) +,S(ed73f5a7,93dd0359,68e253ba,8ac4f2ae,83d7f290,24eea4b6,fdc418e2,4b63dcdb,bf687b81,4691d48,5296e192,d5371ec,daa831ea,ce2d502,4e321add,b62f0faa) +,S(601cc630,47ce63d2,c1fbbc49,f3b2dbe5,6edbca09,17ac41e9,b39f7ac4,5cb3ff8,a773b9b6,d98c7b35,458e956f,f9cc71e0,8539b118,bc2529f0,fd496e54,efc2b25f) +,S(a31ffa07,e16fd36d,2edd7d1d,944ecdb8,2da2641e,cc6ccfe1,88219a67,5677a740,c2253d87,59ab43d7,c919710,9e9ecdae,df1f2d82,d34c5d82,d113958f,cbf1e3f) +,S(131060f1,ba302b06,b26360ad,de531db3,422a6bc9,6ca1e9e2,98b5da8a,c8266249,4dae16bd,40159bfc,96665d6a,d64c6c5,3ce90fe0,95a316a6,8cb84844,ec183cf9) +,S(f4a29fd7,90f35f1f,4b3240d6,c0cbb983,3e701a9b,ca241d3d,bb7630a6,da2de25a,b2ecd794,5afa51e0,1caf3c21,5334dd9e,9f9a1f6b,8f35767f,c63a3f00,69c01382) +,S(b30546b7,c5e45266,854b90ba,53afdab8,be115251,5ae22f1b,5e0c472b,a3b44042,f14a6b95,178fbb85,5aeb9cc3,a4e65560,3e8b18c1,4cc54cb4,1e059597,faad7f4) +,S(b6cbbb5,10ff83fb,c8bdd55f,cfafeae8,947f5e83,4cc78eef,dce45dee,2014e175,d0e29276,a14cfda6,f518a3fc,ac6a4163,13666f91,ce5ae7b9,7abfdff4,925cd415) +,S(fcaed74f,19199482,564ce4b0,7e1033ca,c17bd418,769981bb,6547caa3,b61bafd1,c52c08e,f5331ccc,271b108d,5e7794ee,4a493ce4,f6665773,f97902d6,ffcf40e0) +,S(c6d1ed83,29ade032,c9924945,189ff23a,c6b1befa,e4a33794,8b1b4126,6d14344d,6e1c0e9f,da231092,86d23cb3,2c588799,507368b8,8c0628de,b8a79c97,e4ba817f) +,S(ac7d0edb,a7b86cdb,60963277,cac43674,19dc5d85,ccd9a649,bd335dd5,eea2a9e2,61790bc0,ddf5307a,56fce870,4bc9eed6,9d61d857,f4d2fd34,d53a97f2,4c4c5206) +,S(fd9d0c61,d3dc3ff9,bc3735e2,b2c7d5d6,4a740b1a,bcd46a7a,860816f9,84a64645,701e082a,5e59460e,c3e3ca21,40137ed1,5bf9ef49,fb4673c7,4fa5e4ff,2ad8b762) +,S(82ce7d44,87101716,6ee31310,11bdf02b,336fe44c,88572c37,930a33ff,5bdcea1c,d7fdb097,3961ba18,b53b421b,21c0424b,7b4807ae,256d883e,2e3a6f22,9bc44c0b) +,S(5e507c80,bbd32e0b,efc31714,b464580e,f7ccd3a5,2004f2f1,9fb9b0f6,dad1a767,95facec8,a3b5c996,e0bc9d5f,77c11407,d0ee071b,9cf5af3d,ed625025,3aecc75b) +,S(640d6b4e,bde998b4,1bc86fbe,2e981683,a83789d,b71bca76,76715a29,143c9b55,61334a92,358ae235,104aca00,a632006b,769475a,da8789f4,f7047f75,c8b1123d) +,S(e951dbb6,96ceb16b,6059c3ec,9d84ae8b,8adb146f,fd79a323,59c04677,aff990e,d3443900,ea47be0e,10ea9178,3f1524f2,fe5c5720,efb62458,987dea0f,1612a94e) +,S(2b601b8a,550333aa,2a0e98c9,a4b28043,aa38f20b,13a72cb8,7a8cf212,cd0a2a92,2f3f309d,ff296fbb,a406602b,be72d9bb,c3ca0578,f5f0aa08,6e65ec0d,8989f670) +,S(d803b242,9814658d,df7cb378,bb9708ed,6ddd7270,ffb7d712,b64da007,158a5add,bffd353d,c4d664f8,6d7f150f,30e44ace,fef4abe3,83f30369,15b4d5d6,5ba3c131) +,S(d5a8348d,fbb9f9d5,798d7d1f,3515e25d,a2707869,26ae598d,500186d8,a284e86d,ce31c62,19960c61,f2a8a7bd,2fa36f0d,6ea7838,5463a4a2,9dc1ee95,2f37905) +,S(250dd67,781128de,65f0529a,11b2405b,eab01ee0,1e9bde06,cabcc9d3,cd038065,524aa9b5,8dc5c6e0,6951aa70,c4bfdffe,a2dae26c,1e8341a,5f63a180,731a0dcb) +,S(f3a2017,127dab2a,917dfaba,5eabb6da,bebe554,431e796f,a3b09771,66cd47ec,69d1de46,2e63beeb,1334fccd,ce147b96,23683942,21c4865c,d50fd687,5c1659c1) +,S(15626140,5aabf9f9,d7dfd218,3d7fe2c,900ee051,784537b8,deab8bcf,20c6e0e,863d8797,f2b20b0d,ca1a5b93,9a43a712,4d5f0725,8ae7caba,4b76d308,65f9a98b) +,S(3261fb49,2c55978b,20d2c5b2,3e6ac5d9,5e3b40a9,462b748c,62a41035,2efd227a,4072fb7e,3fafe456,8f62f4c9,83d0988f,f9096c14,317f7584,9fc1aed1,3e39708) +,S(2a5e6aaa,f5cd7466,b851802b,80305dff,3e655dd9,b0456bfc,fe704eb8,582836ac,2e3894d5,762e70d0,4d3595f8,83dbec7d,5125720,c516fcd,f361ab22,be67062d) +,S(e85a7e08,13294e2a,6eebb00d,2e3fdd76,318b7520,dc682705,8b3e923d,536cbcd7,5a936569,77b89e9f,10c4ba6b,7dcb1611,fb6a85fd,af0b1136,b19cf222,a2e9a477) +,S(8e36e66d,2f080ff2,a24ac836,25e50148,e5017b7d,b898820c,b7d73214,bc198b28,edf99b43,c2b976b1,6eda2a75,f8bf5aa8,6945d700,9965b528,bb78b530,3888c56d) +,S(99ead62e,11cc613f,2290332b,9d5ddb98,8c121ed5,21a0147,589bbfe7,db0f0c58,6e73b10d,bac646ab,44f3a062,4150da41,d666523f,ed55fdc1,c1146fd8,c4a262a7) +,S(15e233c4,783fced,39c74cb4,34e77491,83004e2,6e16c372,f6f7f23a,e30efb13,c9954660,eedf09c3,af8e1642,3b57af59,227ee5fc,e1885837,5ac5a853,34fc5034) +,S(3b33e0a1,254d310d,efbf526a,8a2314bf,18bb490f,e592e36f,6763b174,96f57a67,e4e6a395,a6e6c730,67fb2e0e,2c5dba63,9745daf8,bb9d6aab,e96f59d0,8eb24c83) +,S(8be3fe6,f3e45fda,270d54e6,49bdfa8c,1dbbecf6,35922aca,2d605c66,6933e859,10269847,15eddf7f,b7b23972,ed1f6fd6,882481f9,1a12eed7,f8fabad9,da0917c5) +,S(ae6863ae,e6d519be,773edc77,8e7bb5a7,5e0d30ca,91dd0920,aee35870,5bf6effc,d104a8c4,1939444a,1a5843e3,92fc5fa8,d2dd864c,1f442938,9dbdb543,415988b3) +,S(58a06c8c,658430fe,e03b3218,6ec051c1,18174f8b,ade2cfb4,a98cd9b8,13e12dc,17f4ba3,da575c84,81cdfc04,25567dd5,1d2b5e94,a8ed37cb,346f88fa,e6f3553c) +,S(cf0b0d64,3843e10f,142ff912,720373e7,2fd18576,1f3d6c71,52647afc,1ebae367,8ed9b909,f4b622d8,cf5d5b19,fa2e1cc4,bdb42133,c4dd9261,22f1aef4,6dac4c64) +,S(8be41872,15902e71,8f75558e,4b1a5ba7,9d3522d2,e8a2d723,f863c4d7,3c4713a9,f7be5a77,6b8ea8ee,1e59765,ecc6a33d,210eadbf,df4c5586,aba43710,49c715f3) +,S(1e6bfed2,36a10a7d,9efd88cf,af1dc1f1,9649197f,785b4a30,c68391ce,808f713b,90200be1,29c5235f,41a79bc7,2d4d10a9,b00911cf,b9f27b5c,6d47eba9,8530b8c8) +,S(97176463,8cee344b,1ebd8c67,17782c6a,86108b76,e1eb74a0,791527dd,b18e14b5,ccb128c5,2295ca09,626ccd39,b5827ffc,3168a628,6633843e,96184aed,d7bf898a) +,S(2fd20134,8e0b7259,415cc828,c3e4f79b,2184735c,86e534dd,77f1c5b9,9d8cbacb,41fc80ab,25ca1a82,67582a89,f901ac61,2237b942,9d724a2b,8cd0dcb6,c96564b2) +,S(5ba918f6,6bdb4013,481bee06,6aaafa88,f741c362,b5c3a4b,28dd4555,3c1aadd2,230f6c20,f39849af,9de4ff99,8e39ebcd,818d5d6d,8056ca67,8f04f33a,c4fafac5) +,S(69b5676d,b8e2a30a,8870c86c,4a859ba0,dee25a28,493909f0,9ac88af6,83b70797,4831db1,98c1b4dc,69942571,e4908ac7,41ec4568,e27089a4,682ee7c9,8ee905d2) +,S(faab5a9a,c530f7a3,343c71a4,273935bc,fb280258,24a63ce,8f8da6e2,a60135ab,1443a23e,793eb339,f4353371,34937bbe,9bda0eb8,c2fa2d50,bcd85757,68c79797) +,S(c70ef20,284cf135,7c437093,10451a9e,5ef10cbf,e3a0ebfd,b90f487b,8ca62d9,8970b394,35c29dc2,b8254d1c,9c4cdf54,6df52979,ca70ff8a,7dc171b0,5a176ce5) +,S(acb67abb,fa6dfd52,e9829767,182f5ea5,66dfaeab,42a2f2d9,aaa545e1,2e9cc68e,4a097150,2367b1eb,4f51f6c,a394d351,b734b30f,fb36dba0,9e53b4ea,3f6ebfce) +,S(2da4ea09,315e0f1b,f5b6e0c5,b8af330c,c27e26ef,54affcdb,fda834bc,cd578a3,a4097d6,ad006cca,53ea3391,10c80150,f63694be,c5ea7728,f77ebb83,2362a407) +,S(70cb8427,c2d5ee86,59b26055,3499374,63e7a482,6731ab85,6b3fd10b,be3dfdf,f44efbf9,a914063,3e8378c2,6e9676b8,351b6ddb,33f7e7db,5ced5208,e4cb7361) +,S(b14283ed,9a9db980,b135557d,97190066,60e4e1cd,3ab288b8,dccba9b1,67b24934,95fccfb3,827332be,a813457f,28a63a89,87dc8c5,340a8f88,76788a60,f03b2606) +,S(ca24774c,727efbb1,15bbbf12,20e59841,891dfd50,9f99744d,de815f5f,3e959555,2519e414,a9703de5,60f7412d,8949f509,bacecf3a,e672e7ac,58c5f98e,33162bb2) +,S(5a5c1b07,ddc79f18,26bb95e1,13e03894,bb63b593,c808f0a4,2bd44b36,dcd3765,a11bc328,2f672c9e,60846826,521add7,57b891b5,d4fde6c9,738c6329,dabf67b4) +,S(2caf2545,1daf272a,b169a4e9,b0eb9c0d,26888c18,ae7d8357,b8dd2b73,ee4cf7dc,bf8d8ea3,afc9d56d,9799083,c79f1289,7d20d7ed,48ba38a1,acb039b1,2292a3c5) +,S(af6650e3,4022d1a1,b66e8c3a,b0a8e9f3,baf44318,f6946a0d,d1c65aa1,e3f9c9ce,1b0222c1,a5f3691a,248154bc,bc9e5e9c,6b2c96c1,ca468feb,97a7c01f,2551bd5) +,S(3653e476,4215cd7f,83ff59e2,f63f2a7f,dafb8795,95006bd0,182e0e,78ca5b39,c91824ee,6ba3c685,2eeb2695,9a3b136b,371c9bac,4141344c,a1eb3051,8a6d8ab9) +,S(7826902b,cdd4e7b5,463452e1,baf88534,64723588,86643d49,cc89b482,298f6394,dd5bf1b6,91647ce2,86c745eb,6246d087,35cba4f,22c26a37,e326ed1c,4e3d968b) +,S(da19c301,4e77f987,abb00fda,8a5dc50f,d2777850,1fafec84,2ce7e5f6,37edd1da,757fb28b,366104a8,cbd26981,3697d8c7,821c6e0e,5acbb33f,9cbd5fed,25cce98a) +,S(efa31697,2a61cf86,df713186,c1bc61f7,63a618a0,8034c26c,462a2457,907436a,74f17527,e6c7aebb,ed6b28c6,26e612bf,82d61ad,cd1ca156,b971abfe,2efb15b0) +,S(379d460d,12fc351,4c46567a,ce05cc9e,ded3cc35,fb416bfb,76d14f3b,c5164f7e,f548ad44,a5c87313,aeb52885,5ac3a955,178c8992,2415837d,d3e7863d,685004fe) +,S(e3b66f05,ed217cb1,6e3f8ce3,56704f70,36b97104,e39c5649,83bc204c,5b112de4,8a2ee4f3,ab9c8cd4,40afe707,d8dc0fed,473db9c1,be2b6e7,b14de905,ba38ae2c) +,S(b14ebf0c,ccda021d,8db1fd20,a4108c48,750d10a7,e0659cca,64f3e6e,ee8c7a4d,c94ca9d4,d2ba47e4,576aaaad,c15f9019,f335ebc5,763cf232,f56f215d,ce42322c) +,S(1ffb2e29,df24e7a7,6a71f607,f4f03608,43d3715f,c3e468b9,92b684bf,1352cee1,27c39636,54ab505,4b008e5b,4598d025,ade823c3,df6aa7c8,18d4d4fd,32442990) +,S(63e13d75,38f1eb8b,7276ee28,acd56bf0,448f026c,f98c77fd,5f743c24,4872b70,845d65c0,a6cd8b30,7c7ea0c9,8024773,86a50daa,3f361539,57cf995a,43705cc4) +,S(169b95d5,417e6173,b4393c6f,1ace153c,21c83c7c,971418f1,27e1abf3,aaa04673,bcd1ca4e,5618a183,420b34d2,52d25dfa,e7cf699,3e936450,ffaae3d4,61a50c50) +,S(3dde4fce,54d27794,29b6f6a5,8c5315ff,ed682bc4,5601c623,948faa88,2309ed27,2b22dfb2,dc46f625,4f29f8a1,4cb4496a,dcef6806,26d4f499,a17c4751,4a1802a7) +,S(6b37e3b0,2422eccb,299e2b89,1a150be9,ef56a628,62c78c11,f3411614,9fd37802,a9c347b1,fa5105c5,a27ed367,261a1cb5,5d54a071,7a2927ed,29d45eca,6e958295) +,S(7bd6703,ef78de4d,f32f0d7a,274f6371,2d0b0a9b,fafc3f6f,5c03b654,599b443a,33d9b1b6,8254d47d,6aabb7b0,b66298d,8447d674,4612a2b1,f722a597,857fda25) +,S(2e9a4aa0,a2062c8a,63b18e5f,91a609de,b60ae126,93d7f1fa,757057e9,ce169b61,65a55523,e34dd131,3597b250,acd11763,62df6b07,1d3f0f1b,907fe0bf,46ff87ca) +,S(f90c1316,9524f407,8c7328a7,126c48f4,eadd6d65,8baccd1f,403a0b68,ff95e7e1,1d6a1b16,6f5b4f7,9f51b046,42306f53,bd84b7df,2a58457a,a8869,4111cb38) +,S(a7bf0bfa,8e84b448,9ee29801,a5d06f66,a17d2374,a6d91eea,2482354d,66c60074,e60ec871,7ea63cc0,e4785455,478848c0,363f6717,748ee9f0,1c928370,df0905cf) +,S(dc4ac1a8,372c06fb,ea7a44cd,11a352e6,fd204df6,f6868cb,5230e420,9ab36e6b,f3a1b986,c86134c7,40c0ac9f,8f2780,82a103aa,e9e4269,84516e09,659f668f) +,S(538086b2,aba47aa4,dae137a4,4bc747ce,9bb225c0,6aa015db,e9478da5,e2c9cdb3,42ed59f0,fb831257,84b15d27,b9086eff,9aec4d8b,9ac36f87,10f93bbb,2ce7d971) +,S(92eaffc8,955f3f06,fca49a8b,881734e8,6750b34a,d253f160,183388af,f18b8106,fdb45519,36f9e291,9e2e2e6f,7e5d2dfe,16e14da8,b5704a27,60e92d9b,13758767) +,S(63fda46a,4350fdea,fba277c6,190c5f37,c4cf7c88,ab1b2ba5,7b0ce9ec,60249c46,b64fd169,403a2687,f5f41038,91e811f,6dbb344f,2c3a1492,fc408f74,433c65e) +,S(f9f7568f,d2e444a8,14b03934,72564798,5c16424c,1ea6fa80,79f96df2,ff3c73d2,8ae3a292,fbef875d,ca18fd89,8e1e882c,ef7bc222,64140183,1cc2d268,ae795a14) +,S(43a5ef22,93462849,ecbf95d,3c92eb63,ea89a39d,2e0a5da1,eb261c1f,2e8e4bdd,896699cd,e580ef97,64ef1860,19317dd,f7c17ccc,34d340dd,b23621fd,5e5ea5aa) +,S(1fc26dd2,9a3ad966,4206f233,82e54363,6ec9d95e,a58e7af8,a4bc8aa4,736c155d,5f6c4cd9,c6f954f3,f0f3bc54,8bfc4a58,faec99d5,9f3466c0,bcc09053,346bab63) +,S(9a63cdf2,84ee5189,34b73c8f,d8b3932a,50ff88f4,8ecf9b40,c0056c7e,168956b3,e52e7902,6a8d4e95,c7f473e3,84b9966e,16347c60,8b6fb6c8,484335c1,2872f4ad) +,S(aabebcd6,8050337b,1e6caa45,13d279cc,ddc4c218,f849afff,8c1302f7,6b728bb5,808fc6b3,90c2f001,bff1993,346a55b3,663378d6,e457c639,b9a73f87,78ee8d09) +,S(9fd45b70,59cd26ff,2188167,ecdb5ad7,62efbcf2,b668830b,475df22a,bf526239,6fa79fa0,e76536af,92eeace7,77c1b735,19092fd4,870ead71,35634768,700a1241) +,S(ebb3ab2d,e71844f5,b6ff8baf,637cc0f1,1004611a,e8a3b570,1afeebb,a7a4edd4,30eed3cb,55a23613,3bec9aec,b620f1fb,1f39a067,8a44622e,84b9e271,62294133) +,S(a0e7ea2e,33c6a3eb,423138d,8faa7ae1,d7802a73,507d48c1,bb38bcf9,29838ca,31158fe7,ad132036,62449ed9,76c4aa17,67382a8a,cd42c842,ed22badc,882d7d26) +,S(a19abdde,db579ade,1dba9264,9d58b15f,1bf3b87c,eae44520,2ae758ad,f2164fa0,508d24fe,f53d8f4c,77e43ef8,eabecf3a,ddd04eeb,acfbecc9,637b6c07,fbe88084) +,S(e86ea1ab,95e23d10,f086c91f,289e2f80,d10ea0bc,aa9d8f3,1873158d,19166976,4b6bc016,6d95e08a,72c4dac7,9eeb405f,938346d2,ae45ea0f,ab76ba98,8c4e910a) +,S(aad23857,d8d835f8,e3785020,6b1cf1f1,efd9c9b6,ea15d42c,70444ed8,81710ca1,a550855c,381bca50,44be47c1,42d52259,af2f486f,622699a6,aec28138,554cf06f) +,S(b5c04c3b,436fe2ac,97bf2043,3ba57e9b,897816bc,eb8383be,ab11d488,e231a138,b1ee4b56,1965ab9a,9fa87112,57a250a2,d7f06de,7759918d,85c69d66,5546a6c0) +,S(eccf5dee,9b6e3fe3,1e3c02da,a2d5c408,72766edc,29da88b0,cdb01f4f,524b0ad9,7770c7e5,d97ca3f8,cdda858f,ed5976f7,cf2bdcc6,60459a64,daa495e9,28f4cc37) +,S(4c34b06f,6d02467c,9e667ceb,630d9865,4540b18b,8832292a,17e74d9a,d0cabc6f,57671dd,326be6d0,2ada8789,b5f27c7,b052c8c7,d300b2b3,ef881a24,53bcb6eb) +,S(9493f9c3,98a50b50,4db602ed,ef50cfce,5bcc9f0a,bcf80ffd,d5f65d1b,d030ca31,fb45d7d3,fc1216ac,6b948369,42d33e82,932af020,fd7c29f0,f2959eef,a41dcb30) +,S(b0ca3c54,153d435,b9d6427a,20ac3456,ab980b67,ee92c6f7,605aa934,faee0bbc,2e2a47e6,8b959402,1ed83edb,d4968c6a,2eb4be8e,2cf128e3,a3778751,20f27b16) +,S(d5632117,2e9b97eb,4b282d8e,1e303cbc,d50656df,2a99c9fa,bad35909,1888ee8b,30157215,efad51b8,20c03f8,2e4c9c93,11d15bc8,3dc75bea,e44e1e52,7f1ced7) +,S(3a0f593b,69396a6f,62655efd,97c103db,5e209554,8d45de93,8963cbc0,dbb9b4b4,66ba5298,590d027b,30dcd9cc,e4605e4a,73adf43c,6e377bcc,cd19eb92,e20e267c) +,S(10eb3c4c,cccd5ca,e15bcc7b,92d108a6,de762cec,b71bd78e,1917752f,b3f6cf86,6d65809c,79395f45,153d7650,74597eb7,edff81bb,598ed20b,f9780e45,bd91d077) +,S(40ae7e81,e33791bd,154945a5,105be36f,57477fdd,d36f83f9,d31fb73c,862e70f9,71511daf,e9cde10a,7e4ff05b,948a0454,e5fcd355,d98b2bf5,8ed3ca54,1a568498) +,S(994dac9f,3c047519,823c007c,57851a8d,41be0480,7c6ba5bb,88e19869,261fd12f,913e96eb,bcef4fe7,60469aed,51e9dbd8,4910d606,9646255c,9cb3bb7d,55b1e342) +,S(f0d9a17d,112e91df,63c106a0,5df3cf41,6471b817,a3ede631,d845b604,3c04d0a5,3ab43cb6,cefaa228,5c84a42a,8f1f41b5,631bab61,1d006946,f06be576,bc817f18) +,S(20919d38,ef12de1a,64992396,f7b265e6,2ab8267c,bb988d1a,6771d8e,724d16e5,81f79a2d,b629ce97,47f146d6,b16cdfd7,90fccd71,c46cf9f7,fe526e58,8ed1eafd) +,S(b92087f7,43494d53,71978b1d,63e11ae8,a1595239,33b87a44,704ca3d5,30f1b02e,6eef6ac2,49a8550a,135072c2,9bb42afe,5d27c8f7,fec88aee,6274d27,36dc0eb) +,S(f69dedef,a8894583,c05b1fd1,ae205fba,3ba11a37,ca628150,d287f01b,b6920b34,a9f88097,66d18287,9d97e01,5544c7ab,ca0cf8fc,c5b9f305,ed0bd9e5,58fa5b3d) +,S(8bd8b3c9,a301a76,9f5607a3,e116edab,9d87bf79,e4099d62,a328c1c5,f8b8b6a2,167117ec,ce6e15da,47a076c7,afd851a0,cb5dd1c3,d8187f4a,9aa5abca,cc0af771) +,S(d7e2bc76,e2a87357,82611,2619513c,10a2eff8,857fe6fe,a2e2c00,c6f8ef4f,85e1891f,531481a5,e935e80c,448d8da7,32f1d061,dd234e39,d55c58ee,df8cb93b) +,S(2701bed3,778a857e,c7a9095e,6487e92c,555ecc9,32ad8e0f,b1b59d70,4131768c,9e38370a,8d30d5d6,6aac5302,efc7496b,cd5734a2,20d2e76e,fae3c72c,a793d991) +,S(3662a916,a05a80a9,13bfc287,c81cf28b,7295dd1f,aa52badf,5ea1c83f,e1b90521,b14bfdf0,a33c9286,eac83a4c,b982f5ae,82e2e134,99bcb3de,3ac930e,2ed0c931) +,S(d778d74e,317063ff,6556388e,2d2ac429,410337a,d62917,a94b7654,6a04787e,f7d92bac,c92600b4,e8184960,11f135fd,adef70da,b72c1bb,9da26bcf,7a81f0b7) +,S(7b05001e,388f9197,ff3504fd,402a5291,d1257621,c8eb202b,dba87b56,154b6f8c,8c9c1c9b,5c151be,39f2875d,b31797ba,2899047b,6e5c491a,56f7fd28,1b897f2f) +,S(603546d0,1fe46be0,eaa9f00f,c99b2a6f,c38fc225,6553bef4,9ff47442,ffa7626c,1f86de50,aa457ed,ea306251,91cc3cd5,61cbd8f3,2b41145f,139110f0,64b73b74) +,S(80f9318a,ca3b7aca,65cb1965,a36981d0,86ba3b32,8a95cfd2,9c6bb718,1f662c25,c195025d,794abeff,49c9b1f6,724f72ca,70b0bada,d06ae11f,2101b49d,d592ae18) +,S(61182e02,a877565b,1209dce1,bc84c62,f3b1007c,48332c56,6dd6e697,664cf64f,d21f9259,517656d1,3efe7166,750c341b,6c064b0,542bac29,28424a30,ce4b51cd) +,S(21cd4f22,ec3a190c,77073680,58562d82,36d463c,f7706f10,fbebd283,c19378ff,2e04af2b,155beea,daace708,c510555b,467727fd,145426bd,680d1964,fc1b03b) +,S(2d3f6c78,94479443,6004ac92,554a507c,5a20ffd6,f275f715,b176b3b5,3d2000b0,72e0e16f,9d9ceaa,2ffc5a1a,71a2cee0,eea64e44,7f716eec,1fc417be,ba16d92f) +,S(a9f45433,c040d1ac,6bd36d33,5b655fd8,eec0d3a0,bf1a622b,df422039,239de17b,264ed6a,8da4a169,a66869a0,a846229e,81d52517,22fa4c2a,4c775322,f33b1184) +,S(16e052be,bb65657c,309d67e5,b68ea441,4179ace2,38315c8f,df88626e,84281ce,91c007f,fcd4633e,597ee06e,b28296bf,2837f30,8cb21be5,9bdbd52c,4ae0422a) +,S(ff6d96b6,f633beea,1de80512,73c06bbe,181a1098,db737c8,41a48d44,cfab935a,cd9a8011,c22b643a,90f1d9c7,54b7330f,1c1970fe,5ac04225,c2720054,fa6a8444) +,S(dc2e3b1b,a2619ea0,6e4ddc09,99630c4a,7b94c78e,ed13517,25b8b8da,137fa467,f97e82ad,49bb4389,84cd752e,820aac43,bc6cccc3,f9b0d9eb,c2337bdd,89cb83c9) +,S(d53b97c5,8e23d50a,3b855c43,80a992c9,2d667afa,bba4b028,20031f58,dd6947c9,24a54f43,bb9a04c0,8b93aa96,9dc61f92,e705ab75,e644a3c4,40391af0,ad375ec7) +,S(b598a510,beb9cbc1,c4e03f8c,1ff610e0,7123ddc6,ad69dd6e,f9fa7810,f79c8ab3,b895b8f7,68a80a37,77d8b5bd,46754473,c9590768,a56fd586,58ce97a,366dcdbd) +,S(cc2296b9,ee9726c,17b0cc6c,745a038e,38b5535,5e19fc49,e89f4ec3,372b2a05,6a466fd2,f9a5c412,9f5b2faf,aaef4cf2,be71406,590ae031,d68c482c,86e3f89f) +,S(3e84c76e,254c858d,51cd4e74,72c22ec8,364ce28c,de81ddbf,b7b3093f,44acf9b3,ce8ae6f5,f56814dd,21186370,f70196d1,339c264b,c78a502e,bd57e771,b438c81c) +,S(976f67c8,c626f8de,9de43f8b,39585d7f,d4cb35c6,e4211b00,68669ca9,a973a3db,ae4f1f6d,25af4ccc,3eca4b2f,6cda0cad,dcc28f78,c8e881c4,eaca9131,2f0b057) +,S(b28bc958,aed50ba7,6d5293f9,7c419828,53bec43c,21ef0f96,9000fa47,49ee95e3,e7d4cc8f,f68182a2,15dee707,4df2c351,906d5527,c47e6414,54e97c1c,b57525b2) +,S(e54dd5d2,16bc5903,9a630bba,7cccf5e6,81a3113e,be8fb57f,83c51209,965cddb2,86352dbf,5f2b2327,ca50458,b3b2cdd1,8d403629,a2e2a776,5562240,7e8407db) +,S(58379e1a,10115a0,8f2b93a2,3f2f4e2,2787aaec,cf129910,b1911b43,c209f379,a526d32c,abd99175,e63b4493,7a0dc96e,e0feb99c,bbe00c91,1e606537,c871c6c2) +,S(7858a68a,cb34cfd3,e1cb7d06,4d233322,ceefa6a7,a2de391f,991b94b4,da9ebd63,f54490f5,ede73b49,946ffe19,d5ae6f7f,ca026c07,b1dc0138,b1409383,5d792db0) +,S(3c8c636e,d20d58c2,f03c26ac,bbbfed70,3fd13304,74bdf2ea,7526f16b,4fe6f7f7,550069d1,cec630e8,6d22af01,5981f20c,ffdfabdd,6416bb00,f2dd8c6a,44401759) +,S(d03fc7ec,eb716cbd,f033d76e,8db97314,858674db,48ede8dc,1a1c7dd0,82ae7f93,16f7a717,a197fede,dadc25b5,a20b0486,1cfaa63e,3157e5ce,ff0c81d5,bba296d) +,S(6d6c983e,d60601d4,ae5ef4ab,c73914c9,b9546964,a6a3d2a5,681b09cd,afee2c22,13f5af59,61877fb9,2a2ac09a,eb691a88,20ca8361,81359fa3,96558ad7,b2276b1b) +,S(92a9f5d2,149065eb,1241d82,fd06ac2e,f1f48003,3bffb06b,ae3a9d88,a1d05f8d,f0be5964,75545835,f64b0985,1baad682,b84d7a39,91ea0f49,1d19b7ad,77ad75d) +,S(222aac7d,c2fe0066,b766e1fd,179c1912,5f289e98,33cce93c,749afe38,ce0aa74a,bd6c4d8,43e5923,b5944e40,8d309733,dc0cd9c8,b266dd8c,2df162de,fde5bf5b) +,S(28b14628,3a7e1785,1c9d1831,6c9ca17e,56a13c25,7877ca3f,49ab2369,ba2898f1,292856f9,572ecc,5f000e0b,1e7ebdc2,3ec72619,3c97542e,8ccb10cf,d608eac7) +,S(5031a6da,df8d12ff,9eb19209,b844b008,dcc26de,c4a6f9f1,bbaa45c9,daf909a6,ef31dc6e,3cb5c39c,64011c0c,89cddb04,7ef9a881,a0d718b,5057bdfa,3f5e1ffa) +,S(925835ee,ce55e98f,130008fd,a6f01768,aee2de4a,f96f239a,430d408d,95a627c3,cac1b7d7,60362e24,f3b5f277,e370ba70,f0f8c6dc,a338c15c,46c5fb4d,f9f1bba7) +,S(6b7253e6,9dd65781,8214fa04,67f59e92,a4671648,c465ea4,9c993bf3,de8d9e77,50a9cbd6,b429c3d7,32bc3b68,ec581327,1c2b0a4d,2d8587bc,7b26ee15,ee7e92bd) +,S(f82d660d,cd5df408,714213aa,a7406a3c,868a8d05,1fe37689,baa6fbc3,effb3e33,affe0a1a,b7bf498c,83b331fa,f3e7b723,2a2dbc66,3b93da28,e12f0d56,260677a1) +,S(990954a5,5342c5a8,db3fef46,da2b31ba,32b6d597,c67c8290,9329a90,c39845fc,d764f091,40891e20,a2130696,216049d0,b3eb1af5,7dcb9797,4c42abc,5298977b) +,S(d6b8e341,f8bad7e6,ff434dce,fcae81a4,1946f237,e0467120,fd420,f3dafc0b,a8ba941e,81677d32,140666f3,55fc28fa,7233ec8f,8fd13703,214bdf8f,340c389d) +,S(fabf5120,8632ee4c,81ad6d34,cc84de68,728197b0,fcf07971,326d4c04,7017b905,79c781e4,aa7dedda,4663b8db,7fff3cad,f9752cf7,ef2382e4,b0254489,7c6c04b2) +,S(e62db266,d9b208b1,83016754,c871a8d7,4b6848de,e496ee7,e2c1447c,2029b0d5,ef7410f4,f44d7414,53b9c1c6,8e5689bf,37cfecf2,1602e95f,3fe053dd,aea24f77) +,S(4bd90928,14753ea0,1025ea2b,86ae2310,5b581b48,98359481,d1b7d36e,d9c6e478,2f12e4b7,b825c858,5362afc0,d0029880,45fd638d,65f1865c,6ffb31ce,424baa50) +,S(3e397cfb,cc5c9fa1,15519366,c6e814ec,4b0ed9a5,dd093321,219e4028,28126ed,31c352e4,d4bef7cd,8929d3f0,aeecf9b,1d577ef0,e8086a28,40d46966,c1165dd) +,S(24bee951,54baf31c,f5322941,ffc01fda,9e89f80f,2662f5b4,edb751b6,5b372ee8,9568a4f3,a34ce5c9,8f591550,b75f2a84,be5cf67f,1fd7713c,c126f46e,1c3b6883) +,S(d242bb09,e4c6cc42,a2bdcdc6,bad2a02,8e4bfa21,430acb16,3f0e8a70,2ad2f0d7,2eede9ec,799b9e5a,13c40c4e,4cf6dc0f,9640d472,2a78cc6c,d920b610,d070b913) +,S(a57b5fd8,f50de3c5,98073cef,bc6fa56d,20dbacc0,72dbbf81,347bf0e8,7a36ebef,a99f123f,a45b1369,32394f8c,1f7ea2b3,563ca2ba,9c0da00d,b2c9c119,e6f20287) +,S(82a43e2c,a533abf0,6aab1199,fdd20f9e,1616a79b,859c6467,ffca4b27,989da9e,19cd40f5,8c997e78,311e5ba0,c0b3328a,b845da97,91dc8ef,a6cf7e5d,efd51c6a) +,S(95bf3b4d,b8ef8bab,16e00f5e,7dbe9907,b54c98f9,2331c4fe,688129a5,5cd021c9,2b4c46e5,b9d9f915,d5d020a3,3c63fe49,eeb32931,9373bf9b,e359c40a,19328c47) +,S(791ea768,4d333125,893356ed,dd8ebe4b,3f98ae58,e25a2d1,67006a4b,5c05799,5f72cf68,7827ce2,6bebd598,539f6519,a50788c,9d093766,9c3b9c29,f52d5422) +,S(85138ec5,a5d3f0a7,881ce23f,e34fbb80,fc3038e,bb7c2a24,ccfeb2ae,5ef07b74,8eb9e80d,8664b11b,d24753f2,bba612bf,c06bf9f2,a4bd061e,82ce9037,895b084d) +,S(3b4c1149,1d98483,9ff33b31,39da0341,f430175a,d5800c80,37e35dfc,a68ec256,574d6475,e225aeea,dace647a,1489b2ea,873175ea,83cff3f2,fec684b3,fd2ad143) +,S(2ea17f9c,6a028f58,396474bc,8c51b1e3,cb9ac0c6,7f73f533,a428281d,4101b04a,19d1f021,8b8cc0c1,bbfb8925,77087caf,ebed3409,69dc2281,3a1dd6eb,9d6c44a8) +,S(67839592,2fcc7ffb,627486db,e1d98a45,25ee1338,5a98c01d,6b3b9f8d,f64c507a,e13ed82a,a1adf761,7cce3760,d049a72c,7572508a,5ecd0615,1bbb589f,17e10a7a) +,S(54a0d2ed,39778fc1,237ab423,1e4384e6,4156c1a7,d5e999fb,2c92ba42,ef40ee68,3d879ff8,c25ed54d,df848e5c,49e3eeda,e8eccf33,afcb1c1f,67440810,8b3e979f) +,S(263ff1ed,726d0ff3,8b47b398,c713455a,3030d499,3a77ffac,b9cde4a2,cd12f7f3,a5f3fb33,c739bc93,c442508b,ac70884f,d90c3699,34fd698d,bc27f7b0,ca48a0ac) +,S(43b2fae4,a431beba,598b3ccf,caa1e034,91e7099f,c19508fb,8e693de6,dac9e3ac,3e43aac3,379c321a,5313b412,7cd00a1,bd8cd177,49c4240e,7cef1e97,22daf69c) +,S(a73e77a8,5733a296,2da7fe71,f4c16166,cf0acdc8,2d5288e1,8cb9479a,2a31f362,12b393ee,e323fd52,e44a9ab4,3e19256a,f7a8c892,76e9e6c,9052f0c5,3ecbc031) +,S(f007a9f2,bd3d0d4a,8cb9524e,a5aae499,6b2d0c1a,19aaa56d,4038a21c,6dabdd86,517a6a7b,3b75b68,bb04bdbd,d6f93414,c97b4b75,47b8fe22,c5828d6,7e979702) +,S(bc64853f,111371d0,8381c082,c72d2528,823e18b9,99de4303,c85a5fb8,87250833,51e7dc7,23256176,62a9f6f2,70bde4c7,94020e61,9e8dd87f,3f266d99,71596146) +,S(144dc699,a063c473,4b9bfd22,845317da,c4b55e92,a232b92f,965967b9,9c8e21df,a20a7982,7d57de38,85e573d1,6d22025b,648b9ed4,c656c48,bd6f4902,2b67c681) +,S(834ed659,98d49650,c3f525a1,b34ec725,89d167f7,a3cc6e86,8e4cdce3,b2ba3179,6bc2b06,c97a108b,2abf4033,152065f5,24c1bf1a,e79adbd,b7eeec17,9e598cbd) +,S(efce9278,6052c989,adc9595d,cd1500c9,8e93eaa,dafe2b87,2011bf55,3488b1a6,48ca33d4,cc89b486,c0930829,91f23147,d910f29c,c9d13787,7bebf55e,a3dc92ab) +,S(5b150240,c3563354,39adc9fd,23e9f94c,369a6cf9,27f45bc0,f0110cc1,b7321f4c,629b62e3,1a85fb44,b448c7e8,e76ec423,b059c9a,c8144c64,9d77a4da,eb044aa0) +,S(cec8cb02,3f166bd6,9fe04f66,8ef6e949,f4e3d26b,d748c30f,53a9b9f0,9ef3f9dd,997f9fdf,dee5cd89,352e6c38,760c4cd0,a7bb2696,94916567,ae60fc5f,39b908ca) +,S(58427cc8,edc5e616,3726519c,7522980c,30443eef,7e72cdbf,b135ede1,f15c0890,d2fe9c00,7eeb0be0,8295e972,e69db2e6,a54193d3,ec9a3ea9,f2515e59,6e34e88) +,S(a7d0a30c,1787b9f5,8ebff502,e4e38000,6bf896a,2feaefa4,4670dee,6030bee1,774eabaa,863fd4f1,63b3a16e,4c17078a,fd0a1761,b39ab05c,3c6b1d36,5e487592) +,S(9d70eeed,55ed86a1,ba17e817,4c400cb8,ab0e5da7,b568ca81,60b585df,d1a84e74,f4c1fde7,f11b329e,f3c3e196,bd78a3ce,5387662b,859f99c7,d61f7962,2d01b5f2) +,S(e0715fee,9639817b,8501de6d,6561e623,628de7ff,d0dbab5f,bf58ee4b,a365f684,e34ba5d,acb60318,c6ccc001,871800cd,98ba2c5d,529a42a2,fd145336,7b10c22c) +,S(594612b2,4cb1912f,fb945465,1036bfb2,79be0bbd,e718ca26,973552b6,93d20143,d68338a0,d03fd0c5,e6c6e3dc,7070c78,72eef1c8,cc2154db,cbdad699,b594b142) +,S(f4f41087,1dbd5394,5fde2583,b08ba65c,6729dc05,b32ec3ac,c8aadb72,a6c0d8,8e948ba3,853102b2,99f2f558,ffc66181,310bc676,4b82dd7e,85fd075d,70d92fbb) +,S(efca7b38,69f2981c,406cfa40,2bbdd00f,15ba56cf,c6e9f66,9bdfa14e,aa9b1d21,458fd928,a07fa32f,d6a0ffd6,64a16b21,2bdad00f,a4534093,209b0c92,f507f9b9) +,S(25b2384e,d9e09e70,8098971f,153ada48,f3f4a9ae,fb946225,77d213c1,e7b326cd,ef50fa0b,4cd30cdf,2667bb4f,7dff0287,df666dfe,7d5bdb9c,ab567af4,b77c7535) +,S(ed12b20f,aa2ac5de,db62c17,2bc67cdc,f0534a33,6a32e26d,b325321b,81901268,9245a6b1,35df02d9,3db1224b,1a0a296b,a39f07ac,ce7ccee8,eda552b9,748eca9a) +,S(5dfa472b,b84ada50,da3ede14,8bca4f0d,aa885d2c,61633336,b2a8a37c,76b200b0,f314a5d8,2d20fd30,ee237487,7a922a54,f4c10468,656a5432,974cc3db,c2c7fbb7) +,S(a9e5c0d6,5b6d4b4d,b242d87f,57c805a0,5b7f243a,515c5d34,a037ddc6,afcc4470,d90fa599,de5fc8d9,87a42c57,f3bf9dac,d5b766a,fdfa07db,4c56c0d,3d71324f) +,S(4e9ccc2,c0e3169e,e25a6701,a82e7f02,2663d3cf,585100c8,2c6b5da4,d8c42e8c,854aa160,d48d241d,f5bdd1da,2c74d1f9,a00fad7,effa29fa,5ecedc42,3ba43484) +,S(2122c569,da05f145,48d42f9c,5ce3a96b,bbcb49fd,fc5b2dbe,1a7ab0ea,84aec76d,40796418,39879018,93bac618,8a7286a8,f8745709,58a40cd6,1202ac,dba5867b) +,S(aa8cceb3,415df249,b5069899,75a853fd,eb409729,331b1807,ca2242e2,a75c6968,5362b581,fb676eb9,9f125fd,5f674be4,800d89f0,133a1363,f1cb30ec,1fa5b468) +,S(beaea0f0,1fd8e442,50648032,530e41cd,7e3c8271,f4b83b4f,7493039b,b21013aa,e21f7d1,53e5d411,794fb472,47897cc6,a86396f6,3f6291bb,fe2f0f12,a263873f) +,S(8eaa225e,63bb92b9,666bb318,22c166e0,3843ff47,482cec9a,69ff584e,d1a750a6,aa26b32,e69c5d94,19663e05,6c9f7a60,1274aec8,a839ff1b,b5a43c2e,136ffd64) +,S(bcba926,40d8b4cf,8d73c0e3,7867f5dd,81eef91,70e904e0,15f05f3e,1bf6591c,8913cf87,e33aae4c,a16b1391,75d60106,ac7d05f4,a8f10db2,b0569a6d,ec121260) +,S(2d03aaf,6828d0c5,9ffadaa7,5d1b7e95,b3c4a547,46faa5c7,c428fe45,1a9f3332,68468e2d,597e7534,37b3865b,3c968e4f,e3f6b1fa,996e6b4d,296a12c3,20e61cf2) +,S(b39b4de5,be757b36,b1e88773,47cdaebf,11f8d6b8,ab59d780,fbaf2263,a823b5b9,1b609d2,de73faa,d613c4dc,6ac3c2e0,33d62b22,7ca3fcfe,4aca992f,eef90b0e) +,S(eabf705f,b6996148,170b23,9fb8998e,df6214a2,cac27fe2,9c66a899,63d2f0f0,e1867fd2,98603f79,d17876f4,7aea4437,cb39ee7c,bdafbf0c,5452b024,86182d17) +,S(a4ce885a,ebe9335c,6ef43c6f,395e1644,201f578a,4caa7f74,65c12542,27f1bc80,bde32eef,f7fdc498,1c50942c,efb38cf3,c3f1a8a7,5addfe7c,f11723e,f57d0c41) +,S(db8ee69,b0e00ff7,6a094251,a53c61f2,e00dc65e,a11e00e5,553ae121,ea958361,24e7ba71,22742e09,728108ac,59c5f46,aba40d1d,c308edd2,9d494f39,d156b2d) +,S(88a5b43a,d6cdc2b5,aa3d58db,9a9a2e1a,6d70afa,808efa87,1d7f3cbc,509cf064,88483c55,e5bc8717,8114605c,1febc726,e14345d4,4211b670,6b6185d8,ea6b7103) +,S(e3cb24cd,2130716f,10a4d432,d4e59229,2e11a2f5,3190bffd,4f478da2,216b0051,df432db5,caabb417,f8252d37,dd23e117,38066c87,101cd934,73a2883a,1b7e8de0) +,S(d9c88471,97f04254,731794ec,e29ba74,f1d72f19,8f424beb,8309e1ad,e09e1301,12037266,331f04b6,db4264df,ae6d934e,5f753828,35a646f5,cfa4ae8b,e6defdc1) +,S(80bb740c,3510574d,10afa586,a6e541fe,b5368797,231d2a63,67d2890,8877dc58,24ff9389,bb268f42,b04f1702,f7b7c6c1,7194c7bc,c5f4f63,bbcd4ca8,ef476fca) +,S(4b8b08fc,400d6fae,da05cb19,65c9c785,8f93452e,d1be8f29,28c83e6b,4d2b06a1,70a6612,2549ec2f,6cde4a4a,9ae8a528,1b05081f,8eefa8cc,1111271a,1beea7ae) +,S(d2708078,4d19552b,13ec8473,1eafd2fb,bc0ae927,dd746a8c,be1dfced,d072ddc8,9362bac1,806dfc84,e736758f,22f1039d,57a5e44c,40586195,885abb78,f75d3355) +,S(7345d1a2,7b9dc922,f51a0466,57721451,cea5b54f,6673a484,7a210b4c,339d1f18,293053e8,c180ee0e,d81bc4fd,658fcd5b,99bad329,9e62aedb,74867df2,3ac12d98) +,S(3b3a6baf,b9003f37,ca27889b,a2be2a02,748ba52f,6c6dc719,afcacf2d,578b1e24,a9749973,c49ebecc,501f9b18,83056505,6c88c286,2747496b,951892c6,8a61ffcb) +,S(b2d1a3e9,15b02709,1abb5ba7,206ad2c,5d07079f,8d4c7fae,3e6837be,34159226,90007202,78d4188e,b8efc45e,8306ab47,be1c6a16,d88284dd,fb627b1d,92959898) +,S(298019e5,5de972ae,fd0b4c94,9a9d4eb,46689fa0,9b849947,bbe27805,4a3f4a5d,5b7a4298,be50ee99,363b5f9a,1ef103fe,4fec0034,fd8a2364,5cc76f8,ff804f0) +,S(604f1e62,7f503661,5b55fe74,4540df91,67fe575,e0aafe13,8af68214,f1080eb0,2ade0355,b373ddce,2353669e,6af5575,cc6b01ae,58b2a581,2b63f36b,58effd5d) +,S(ddcbadcf,63ffbfce,326db7e9,2df0d483,9a35df32,fc576070,9f2422f2,6e07b8be,7a3bf369,dc3a5ae0,c91cea62,1429ad45,76f7110,b654a1f0,edda9b57,3076306e) +,S(160a19ff,10c8b334,7683b21a,880226da,81d536de,d9dcd357,d4f2283,18853837,91dd522c,f6d1d276,e88287a5,a37afefc,ba010111,82b93eee,1483cf56,e6cf5218) +,S(bc1210ff,d75737ab,51300e3e,ea48a264,5f363793,1f4c6f95,e8507034,84834819,8acc70b,363e52ee,779e6342,ea7dcb7c,d7d09946,5b0eec60,e35ea360,e8baa7f4) +,S(c2da24ff,f2c5419c,3d2ab241,e55cbfff,5f41b9ae,4efaa105,abcc173,a81fa1ec,3fed4d9a,4eabf3bf,6b913bd9,279761f1,4aa630c,e278d0d8,4bc82ac7,af77481) +,S(73a495ab,b26d4be1,bd99935f,f5583f6c,f5c86d79,fc86a4ed,48f87f40,2f12259b,f4126c3b,3e9b8dc7,ead63ddb,5749fe5e,6cb0bb3e,3c85426b,950326ef,9092301a) +,S(599baa65,fdf949f0,f54c44bd,ff605ef6,2f53d68a,f0e44bf8,274f0b73,ce251227,297ec5da,e3893363,617f5448,b13237a1,91fb5a20,e52ee897,a124daff,9f1eaa9c) +,S(9a032a50,6786e1fb,bd9ecd25,243ea67d,57f9e4bf,d1083879,e309690c,fb07f253,a073c6cd,15445d6d,80c51af2,4e7f540d,f1b75fa0,89a4849a,ea14ea09,ededdb0a) +,S(792160b3,eda1d493,48ea96d6,857d8631,ed1e198c,c7f185d6,b9d2c75,2b1cae63,d12d76d8,bd73a681,9bc581e,cdb84efa,dd143704,5554984f,8f1132c5,fe1bc32f) +,S(8fc4cc45,9639aec0,2c337f16,589c09a7,e787dffb,69ba2907,37b6c465,db9f12d8,b2ce3c2,57ccb79a,b677a9d8,49ce1833,2a97fca7,28bf3e83,6dbefd23,5343571a) +,S(fc06a9a,5857b2e6,df0c3be8,b5840946,ca77f690,4ba114be,44e760e,267eeda5,6662078e,f0de0e94,5a770654,b8281a74,f82168c4,49455250,136dadf6,87c5bd2a) +,S(345da4f,e1e89eb,eb27b353,4352c5a8,32d3c9ee,456c01e4,657c2885,733b5f69,3db274c6,b89e7400,cec4e2a9,9995ece7,be8b98da,39a2fa48,bbec96a4,5c758be0) +,S(309850db,36d8c2b4,610cf8f3,e1c12431,3931aebe,1a9d2099,cb3bc7b6,fbd8b0d8,edb3a9bc,f6417672,af9b1379,9bd8aab2,f953391b,27cdf167,320005d2,3fb3e4d1) +,S(8a35d7fd,8c7c75f4,e22ba36d,d84533cb,f314a54a,2e17a43f,d250c941,5025b0aa,97ae015f,fe364a2b,6c12cc42,fe526eea,7250092f,79c40b94,ab7102c6,fde1fa5a) +,S(982d9d66,dbe6b738,2cf2820f,c72ed491,d6a61add,f1eff091,de30fcb4,96ca4161,b4a7b42,2e9cd74b,10cde7a8,12b4d88,f3621324,acdcc911,b39d0952,3cb3b501) +,S(1396bea9,57d47670,735ed20d,e2ecaf6b,afe7e067,5f2a0f65,6b3e719f,573cd1a2,cd77e7d5,a49d6cac,5e7871c4,58df45d8,821d77e,f3ad3db3,56989c1c,700cf484) +,S(6857993,76774ed8,a08da47a,9323241,71d09fdc,964893d2,aa5e783c,b8030057,640c986e,befd426,8fbfb131,8133ca77,879ced3b,56ec251d,12d0a650,28bc9d3e) +,S(801865ee,fecd50cf,4970e6ba,efeed453,769b3e14,c103db6b,2632e241,2405fb6c,b3d3f23c,8f75e475,8784016e,6ce1b91,8db76599,8c7c1aaf,af047282,ebd7a636) +,S(f09220f7,27e57fd3,209eac13,1ed93f96,142c400d,b9bd708c,9e716686,20f1793f,8280375b,1b2f4915,cb82a72c,43c9fc6c,f3a7de5c,32762b69,43187a8f,13510eb) +,S(1c814b69,6104f8e6,5a51b98c,e6b0c4f9,f26b5633,8ce24ee2,24a5aef2,967ab705,1cc2bbfc,61828277,90502c11,bcaa1f1c,b5e34891,a7c669f4,dbbb604b,df2e3135) +,S(22fff436,de961dd2,a7ef38c2,f588aade,320d0721,55e6a42a,3201bc6b,c7d24a54,6f13476a,f48f9197,3845af18,ce68ba91,77a0d4f,a835acce,76814c81,f6aaef5a) +,S(39da98ed,a85b2de3,c9bba6d4,1af633d5,5a392dac,b1d4fb9b,654fde5,a3343a65,29b89534,35045e6f,2ca41bfc,9e5c9ad2,55eee426,95f41744,b239659d,460fbdaf) +,S(6fb84bb6,3be24203,6e067346,1a5c1fbf,7d89a0b0,c98ad2e2,25cc3ba2,191fbdc8,21a37f8f,e4f821bb,3886333,c554d6ea,cb8924f2,bfdd7ebb,339a8a92,ec9bf8a4) +,S(29080a3b,7c1d33e1,13b70c4c,8388fd4f,59118a86,c4bf697d,25346368,8f60766b,745ea31c,e9731f68,89aaf5d8,1e7f686f,b345c9d7,3af728c6,7ac2b8d7,60ffecc9) +,S(a54f7e6b,aaf05de6,77e7d98c,5385d9e9,57f68d2a,8e3c24bc,11b6435f,50cfd955,f7d61099,22ff9c98,ee79998a,597dac10,be885d5a,e7b53158,fb671e38,470b5c69) +,S(7472bc8d,c109d56d,a5f150c0,bc41edce,7e378335,15e17267,62f50cce,e8845b2e,3c59290,820b997d,3c9109ac,7319048d,e37c5280,88e671fe,9cd85487,f03917fe) +,S(6f4cbc32,ff1805da,6cf83c64,b0d0eefc,6bae76d0,586de80f,df2317b0,a4e68267,29e492e5,89bf6c68,17731a29,76577124,c9bc9e32,1856bba8,8a060bf1,6a6c9d9a) +,S(1a93eff,b60cb865,8538cb27,d8c12490,483e6886,16320327,e2689591,c5413a12,d96609d9,251ea2b8,f150664f,efe6bf6f,a0634cda,b8846cc6,5f6c8a8e,97697c9a) +,S(79b82e7b,bb23efda,cd79c0f0,87f2d0d0,e2d3db59,97696c73,e6e94ea,8cb72027,bf16f23,47e594ec,fd087189,48d531e9,8306b173,88546493,d620218,b25e3758) +,S(a806c902,28fbc405,ef56057a,aee9993,ef177261,74d456fd,818126f2,5d93f986,fc49c640,7d9d26f2,f043a1b8,8a41bbc1,3ced6a93,bd669ddf,3186dab2,9eb7c5b7) +,S(227d9094,69eab478,9da2fe7b,3cb618d8,d781e0a6,54892f86,92eccce2,f41e9a1,81cbb45e,adfe3fc1,de5975cc,f87f0a44,e9f106d7,19cfe796,f33b5c60,85de7691) +,S(14f8dba6,4bb5aba,f7f58e8,1c9b0425,2c357f3f,fa8aeee9,fa4ac700,8c49e060,26b19dbc,52b913f3,b6aafb31,3de99445,b49d64ef,2503d28b,bf2f9e2f,4614609c) +,S(f22646cd,553c5008,aa3c4cf9,f01a05e9,20cee021,4e9b0553,38a75c1f,23e5fe4e,52cdb77b,7502794,ac16003e,2f4e859d,ec3e68d8,c84a3365,a307ac80,53d3089e) +,S(515de841,814df2fc,7cd43689,8780686e,f3bdbfff,83eed568,af19c75b,5ee93a2a,7395bd22,705a81a3,d62f3130,ad416db9,268961c7,facf81a4,44d2ed8f,e4df1282) +,S(59f4aed0,38f07bd7,b2aa6600,ca6f15f2,d396310f,e4ffe212,4e6a89e7,3c7c4ed3,47a048be,5d6e45c2,4fa69329,86b86edb,b990eae2,f5dc6524,3eadc69f,43b2ed3a) +,S(7492492a,d7f94293,4287c7e2,5f05203c,4c70b8f5,80d23b4d,4822d1ce,fa3450a1,19523158,2fa06da5,eb5368b0,f0b19971,1a1bdba7,50d1c6ab,80ca1b4a,d649eed6) +,S(2e12d13d,464de937,372a69be,b90dac92,78977cd0,e7b954d9,30360d6e,a51cc3af,35a900c5,6c7cf352,8c4a5af1,56dbebaf,32d2a128,8a58e3a2,ddbcb539,bc3e3505) +,S(ce4c4b4f,a52f06d1,11dce52c,402395e2,a6ffd186,dd8275b7,bd43e941,9f4699d7,957b994d,c5bcd5e0,179a67e7,94a40ac5,cfc074da,6d23d178,969fd8b9,2d9dc455) +,S(c51f1cac,5814de82,f4bd5d2f,a8e4950c,38fe78bb,8d09bc5b,628ec13c,e3084592,721122a2,f63289c1,f8925ce,34d810a4,be52f7bc,9bfea232,47617f95,8db1cc95) +,S(9fbaba14,8293f578,46c717c8,718a3a9b,9dc5df98,63ae10e8,9c3649a3,e26128b1,4917061f,ad964c4c,5d79780,7914b2f4,b6c3e730,3bd440b7,bc00f15d,bed2b497) +,S(a4a9ed86,ed3a1dce,5423c1e,1bb5fb9d,fbc1ed41,66a4219e,bd343922,8542ea9d,fcf6821e,46386764,c61eec0,19b1a84f,6a8851d,89be0da7,9d2768af,6eba9d89) +,S(a6fa3567,9a732aa7,b58582b1,5f3e95d1,f702ab16,5249e9e7,89a5a395,3858d1eb,3bd67e4e,c0dae02c,43d32cfb,d25a4b2a,75898bad,eb2986b5,6cf61825,ed2830ab) +,S(3b3992be,8f7e1b1b,4d8f5710,6feb825d,568b176d,af0e41f5,9c2fd59f,f67d9b7b,ddf2751,ac17a413,2ffc5c08,3e8c7728,a74b0063,377228bb,a60cdb87,1b5db297) +,S(e9ccb20a,8a279cef,2a15de57,e34f510a,f60ce397,3fa2ec2c,4558f166,7ad20201,b70a11bd,1b5414de,1b30035b,3dcd1dbf,17558bad,368c78c9,d5d9136,6592fa53) +,S(98083dcb,1356be80,b324aa95,e38217f7,c437f421,5a7f3e98,ba803fd8,5cc04445,bc0d9ebf,ade6c640,d16b82b6,5328a2,d5ef2f8b,52aeadca,e406ae25,e9b756a1) +,S(6a0f3b01,9e3b2a9d,453cc36d,275fae6a,b94aa14e,e0b4103d,137b1741,8b446ba3,ef30c9f8,46c54902,c10a4ee6,c5013b25,709e7109,fc004b6,e291b1bb,a021facb) +,S(83a62b60,6a1c4d03,1a18473c,f2230088,1d767332,9513b7a9,4f402f18,3dd45640,b23888d9,98bb9c00,ea57c9b9,517080de,95e6491d,cba0d7a5,729ab99b,12a1246) +,S(d2781bf,4b059449,75da8b83,cf82b43d,b5ee89fc,168186bf,74f22321,30678492,76fe1955,18e00974,6af44fb3,6e623f4b,fd0ae8b6,474e91c3,3ec364a3,91049d49) +,S(e4445252,dc6acf3c,f7b3663d,7176d46b,efe95e40,3063d1a1,68fd5742,2795a986,cf7613dd,eb200aef,e665bcf5,a6dd7fe3,cab6ede3,877f6a28,22b6620d,1eecda68) +,S(51f59cbe,68f523b5,b435633c,ce11c0fc,ed2129f3,5d392b2a,ef789044,722052f5,10403f8b,e7024887,3c4f0aa8,e4d0fe46,11f34268,178368e9,1eba8e4,d9b318fa) +,S(7d1806b8,410ec629,77fc41c8,8c86ebcc,74da9a0f,c6b35c43,68d069a2,c8c974f4,efe8890f,5aab9bd,c2da2956,bc089b58,b67ffd79,957ce0dd,9a53da,b26d68b5) +,S(add67544,8cb87ade,f8cfc3c1,85fbce12,e0d1525b,812fb5d0,2420481d,b22dde96,bb80527c,b22a3bf6,728ba305,bbff36ce,c6b44d68,9cf79ffb,93030460,8f461174) +,S(ceb2968f,fcc7b751,f9b560bf,b08f40ec,ba1395fc,9a3f63f1,65a1be1,862c3dae,67727357,b2dc8d2a,47606c1e,ae61ce54,1d79ba49,4a5e310,e0435b,383cf088) +,S(3a03b03a,1348cf01,afc60665,26b6fcbf,b3977ecd,7c17725c,a9f0c494,f31223d0,3e71c6e0,7da0635a,a2fadf5b,78c892c4,c95f794a,88594b72,183a9b2,4dcbe7a6) +,S(42ac22a8,c708f2fa,559f9b9c,fc7ca705,4356d18a,95a69137,bb8b8b17,2b771aa,ef669b2,85ed6abb,477dc2f2,bf0517f3,794c371,9ba5b267,8f622eb4,aa4ce374) +,S(b2ded9ee,ab06f1c4,19c5aad,5163e731,722c4923,818185c0,d99d6a8b,dc603a06,23bb4786,f84e6c75,e565a708,2600585c,e1fd60a2,b935bb4d,390d07ee,5e8646dc) +,S(ea1faab0,bb0b6cd5,454e63a3,d1546747,cf9707c6,48e4837f,3fc6b6f,a2ccc5a8,8fddc23e,651ebf4d,89e54148,2043fc34,7c26b66c,b2ad2d80,1fd2fb7e,77d4058a) +,S(487920c5,14ce0cf0,9d939ce5,81e13409,9fcad06d,3e6974f0,a3b5925,12cb3a86,db447217,8a92e9f8,65a1b022,3baf54fd,618a87a1,15887f02,11cddbe,986dc927) +,S(6828652,aa506655,60349cdf,132ca8c8,9a6f9a1b,8baf6adf,64e10c12,9ef9217b,9615f563,20db2860,9062aca4,7a136e85,40ebab0,3f8b5f7f,93bf0369,aeee0cc4) +,S(b66a66f1,9c94868b,3e45139c,ef9d7586,1a6d06db,72027814,83dbefbb,41157a94,5c0763d8,8aa90b2f,ee04eab9,fb96b280,5ed5f7e0,58c9805b,64fb17ae,9a0f224a) +,S(5318b13d,a824dbec,eced642d,d742ca30,479874e,31c1013d,d770a0b3,c9ddcd9f,13093540,9b5d56cc,d5004948,3bb22009,4b7d5a5b,6d357bd,76b79117,458e60ef) +,S(6bef6b9,555f29fe,b5277c48,863c990,8f1fe2c9,5b4b45fd,8c5eb482,3ef4964c,36c00eed,4281871,fc5e15d7,7acfe3c2,6793455b,9b3607dd,71f3e163,9790e3a2) +,S(7972f783,4c010837,89b92a08,d21b8b8a,b6ff6ef7,92eabe32,fa1c92da,4c8dba6,2c3352f3,f458a538,f8228321,c1adf9d4,a2df9f8b,bd22675b,afbdf041,9538f1e3) +,S(7f03f087,168dfd24,7a93e840,e68cd221,f02735d3,93d777ec,c9d2c9ff,7cb0228b,663dc741,fc8e98d0,7dece960,5b506b5d,a5f2af72,1b64480b,1dd3e7b5,a0ee7743) +,S(d06ffe61,973be011,2f17bec,6f4dedda,9b9d310,4ed22ed7,d4c2f009,843d2c04,175f409c,edd739dc,5adea16a,187a951b,d42df4de,d1aabfae,d56f1ac5,26cda8f5) +,S(9094c510,3a34209b,45f7062e,ec65c14b,72fa75f4,13999117,38cd7f6b,792119d9,da541e51,7211db66,272f8f8d,413e1717,13cf499f,6c9cd694,b98e53df,45e9d501) +,S(22bb9cee,8a5b99fc,d7ac7d67,5e232183,3f71a72d,55248a3b,451699f4,9f151eba,841e7292,93a98297,ebf2e9a6,6d106325,265d91cf,f7e4c245,845e5a40,522b94a0) +,S(b548dacc,944b013e,d50dfadd,fb84173f,d5829b2f,69a2242b,c152684e,7b8a3ecc,6c7b70fb,9ae39eaf,583939b1,1a1b8aad,673b18f2,7568d2e0,b2680b19,8c662a88) +,S(34f46e0a,2281a617,f8ab78c3,86ed27d,f837f23e,e986dd20,bf705daa,1b0188d,4ce4df08,bbf1e735,6760e05c,6e5d3f3e,664fea9d,6e1a72d6,bad17bbf,a3c089d5) +,S(3063ee2e,3834842b,84cce6d9,50ba5afa,1d645c5d,e0acdb00,a9cc4ce3,c266f649,b08247a,f79c2be1,a0e4e021,7c9ccfde,f76d1e46,65f3185e,8623aaf8,63bff9b6) +,S(d7232b55,3740b2fd,464a919c,46168ef1,e09638e3,65117eea,979130aa,d40fc525,f842c256,38e84dbf,47d13fcb,1763a296,47b72908,1b522623,4e307dc0,1a402ded) +,S(6025e82,e2ec643c,32b10e6f,62ef310a,11576957,96c10f8d,b099dd4e,1dd8cffa,1e5aeacc,cc5c5455,d542dc51,b12fa3d1,75061cc9,45931548,7467d09d,945e2596) +,S(141d07cc,256c4d2d,44ddb7f2,ef720aa8,4bef767b,3597ba32,3b39915c,1d84f175,a842c439,9366b2a1,91e850df,333c9cd4,6c983158,cc57989c,588c305a,1144ead8) +,S(ba4ad105,6ffde493,54d13149,31846519,86fee8b2,728917ec,bd1a0112,b986a90c,97ac53,f84e995d,92d14f0b,b156f47c,be5b6506,2a7f8b07,7e235da2,808029c2) +,S(5a6ed894,bae212f3,eb44304d,98ffba1,4a944cde,ccd12517,5e52d767,5e0f801d,d8160707,d43053e1,e5806d7a,bc17563c,ffaf92da,ac51deee,55fcb9ef,715b08d5) +,S(d82a95b6,56bd1abe,50933a3f,e291526,7b257807,c8cde42e,5f1648c7,f35c4f3b,748904dd,3157bb07,65f94c18,7528c74f,ac639a36,be18963b,676b9b37,83f54591) +,S(df7c9de9,8e748188,74967340,34a76645,c1e55bed,3a90fc65,dfd9726d,a2bd3826,3bd77fe3,e4a4018f,3e256ca0,2bb5c8b1,b783b729,21ce329a,fff9caf6,b530b1fe) +,S(d3ae1d68,4614c95b,51cc4af5,a9e8a05c,4ad7eb4a,ba4a65a8,9a151b96,d91bdb68,a24cad0c,ad0ba98a,860d6d74,aea57c3c,23780812,5fb2356b,b55f0bf2,95e25e67) +,S(ca85c924,48a27be2,2b68c9f4,c9ab431a,b380ccec,2439c8b1,944c234c,bd865758,c53177d7,6b16e0a4,389e1e32,7072d460,90e92f48,22043bea,924fab46,4023038c) +,S(34309aa3,4e9fda0d,f2c20da2,3e8f8f31,eebea096,1e769c92,6c4251bd,5440bb04,f655cca9,d5811164,577d0525,2f5605d1,b4e2b6d4,dd5540be,aefed4ae,84caf3e6) +,S(40212a4a,b2bfcac9,62442617,8a807655,185d2929,7e26c437,4879903b,41307b3e,26624605,6ceb4509,b481df00,79e25f1c,4dfea60e,a3768e8a,462ac273,8166dfea) +,S(2e441425,d121e140,5d2118b9,7a3b305a,fcf62e91,4f24bb72,46e92aeb,1ebdd152,c3c7a567,51dfd709,9535d07,23778131,692dfdb1,7584d9c0,c8fed42e,5eb662f5) +,S(31539912,9e59668b,49d9b8bd,5ee66b2f,aa727ff4,96f457f4,33400a20,b5242b5d,5e90a20f,a700c59c,fb0ca2cc,ae3f2837,6dde44c0,3cf6af64,365e4cd3,b4e6b3b4) +,S(3b586e2c,30eb1959,bd5171ad,54b81c36,cda6b0ec,b5e77b41,a7b5b0d3,e1ed4ba,6782aac,d675436c,d969f413,c471edf8,ff7d89a,d0a07575,16bb695b,19ef40fc) +,S(f4299c9e,b3453201,375b972f,fa39f01d,90c68625,a63c9d06,513fc9c,8c623fc3,cbd0e2a5,f9b9ebd3,f482a5bb,c5c17894,d5c320e0,28744292,31c94fe5,55ecf68e) +,S(96d35f35,eee50b32,32371acd,99d6db8e,d2b7c4df,1f62b867,5559543b,785503d2,c0e8bce8,8bee1e02,29a5d2ac,113c9f2a,feff0260,869ecde0,7cdb1cd6,3ba5f73f) +,S(ad3036ec,e2bcae0d,1fc34680,be2d293f,b40d9133,905af375,1ff89c49,2c183e1f,2c0773d4,bd30833d,24222f89,3a4f5e8,cd6abe06,63d66d63,2d5fb832,4c260f9a) +,S(a0f340da,909f04df,70a33195,1c48901f,6353f4d0,4d22f99b,3763f567,be9d207f,caa1d9de,46a37b8d,623a39a8,6792475c,bf3bd694,597351ac,515ecc8b,1a4fe78b) +,S(2adc4874,af0b3cfc,675421b9,5369ff0f,950b55d1,331aeee3,dcd0adf3,859be4d,6ad9fd3f,a840d02e,ddc01fa0,ffa61bf9,4dc1db4c,ec733976,bf1c6e41,bdd92b79) +,S(b9222a37,c14456a1,cf931410,d96cd84f,a304b9f8,5a96edd7,6e67f928,43536175,4002a875,dfc4cda7,4ff7145e,ca46aab8,8cfc5ed4,53b34eeb,1e5dd859,4793e3d3) +,S(530bae23,c3796fbf,76f86f6a,d8b59b80,801328b7,6c46e8f1,cba6398b,270919f8,d4d3b34c,6701f07,bc47d1d9,fb868fc2,b46ff397,2086cbc0,517e29d7,38a7964c) +,S(a7f2ce51,5b932506,c740e84,40f254d0,e0da57bf,4d9199f6,acfa3664,ec36b823,4946fc41,3ef1b3f1,86a2c781,6c05ce7f,803fc7de,a00fbc2e,7e6c4688,fcddadae) +,S(8ff613d1,1c81c4c9,fda3860,cbaa71f8,eab9ac3,d9263f31,55317949,d6ac1d53,54f683d1,fd382305,b2193554,bd3a6d2f,bfbb99b7,5d9c3e1b,876c3b52,e2bdef49) +,S(6fb3bc81,5ef3d8a0,d7aa1a69,dccbdfb6,3f7a58c4,7a12f98d,b09cc105,4306422d,798fe7ac,f9fc71ad,7023a8e2,c9376161,8fa632cb,ec607109,d28a63a3,9a4228f9) +,S(c32aa38e,bf0ec0ac,61bbea0d,d2c633c0,bd49ddae,d77179c7,e0098c8f,4488da8,e01f5fa5,1107cf4c,f4c1c5,78c3b5f3,a1baa059,90bb8913,9e2abb30,2e9e5042) +,S(ef5e1efb,d1ede40a,810434ae,833a4681,5f9021f9,41ef1d82,fb8c1399,16c4933a,94a9cd1,5f160c1f,4f85ec8,16fd1834,9cf19f8e,96ac9247,695ca37a,dbad6ef9) +,S(8e3aacf5,33de35e,4f923b36,c378ea57,7a5aa477,70ea6390,f92c73d,50fbfed2,49cd7650,ff69ed12,b96ac3b1,420784,7677497,b731e0ce,316eed65,7e40e014) +,S(84521790,204c64cb,e026152f,474b0da2,25703d93,25943821,7d66f20e,3ae0d06b,c1da2f7e,438fbc82,57f7fe4c,7e49b73a,446a19ae,775e7f1d,20c8fa31,edc3bd20) +,S(604cd900,97fe538d,b27cc2cf,a2d6c79,692f2e2b,c1b1b23d,1f0eb949,df560697,914d5288,29765538,d77f8e04,182c50f,d2d9aecb,2412ce47,4888d666,46b2258d) +,S(c13a44bc,9a27e241,5531b8a0,5570e66e,6763b3bf,a80e00bf,59d6124f,b3d67858,71557bf0,4c261c2b,19196d0e,9e459f3a,f629cc19,84f411,31835400,3a60563) +,S(14f3399d,5204b654,23d9318e,4adf3af9,dc43099,eb43b719,eb4644a4,897ffbff,13808cff,4c096655,72329034,d489433d,976cc011,d1a30ced,702ba4e9,5892422f) +,S(bd84d712,43dea7fe,f151b207,5d03d2ee,170488ab,4175965b,128411f3,f592a36d,57a1c602,408fee75,ea9e683f,43d7a984,bf03d66a,37513c50,5cbec6c6,6d286fc0) +,S(f319d4a9,b5f2c1ed,6619ae06,e5aaabe4,13a2a6c,265283fe,4a51c7ca,6c49b572,bd9d90c2,2a369a03,1856ca9c,86426171,db952537,edbb1ba8,93fd16ea,35aa43b2) +,S(9649689a,424ec9f5,aa4cf4c8,45588046,c50eaf9f,700d0412,83e02640,9a80c61b,5cba8567,95b0440a,53e0d1c6,ad560364,c398dda9,d2e97a1f,e594355e,1402fa33) +,S(45fe12f5,a340034f,381764b0,adf503b3,8026374,70eb26e9,6f4181e2,68cb1c38,ab7715c4,52e5581b,ed940fde,355892f2,b8a16a3d,d322123c,14a57a23,72f244c1) +,S(98bcd24c,3222401a,a4683213,5a378790,6c9812ee,989b8f52,fa522c6,d39adcc7,14c7cd38,7bb5191c,f49bbe41,52af8b03,7135a6a,bc7e4697,35a72a38,e44433a4) +,S(6dc56512,7be34196,a7653057,f79b854,83c275ab,65c05c2e,83663da5,31d7d652,a6839fcc,ba7db053,affaf5a9,4c95676f,9d65eba3,c2474472,cadbde17,2ad3692b) +,S(7a7f66de,b04492d1,fd2fb9aa,dbc4ea7b,ae5a3801,47b86e68,60513a57,eb6b10f,fffe4f2,b722f36f,1e555671,90d84d9a,39b819e,fb7a3436,29b83adf,f6045f05) +,S(aaf9f188,3865e2f7,eb500794,3888b4ec,9013371,f7162947,2cf52adb,bb5288b,df634c19,e7496b4b,478bc10c,7c00ac8a,5fc24dc6,4f193355,f0fa9c62,d6048243) +,S(6304b1d7,56988ca,25afb747,476acbad,2e5afa5c,86136090,c86a82a0,e52b373,91a2d829,2357463b,ea1a7cb,33d79be5,8bd71732,f1d2cc13,ba4b2724,6fd39f05) +,S(6eb17147,2aad3d80,bf4e06af,a36e37ee,5fed9c18,bbaa1c4f,5cd871dd,c526515b,6afd615a,e2512fa,70c9670f,b56682d0,f304a0c,6a23d1ab,fe958a7c,2a4173fe) +,S(9113b613,ba815ca6,43e7bf66,27dd71d9,8c2d40ea,5c00f596,6216ca9d,d32b1ce,8790dac5,bce4100b,8e4e5135,66a104ac,b55d3ca4,3d6ea083,d23716d3,3894de2d) +,S(5c7af38b,8821169e,2f7e2edf,18b3b73a,c387e6f6,a8ef1cdb,441f5a13,284f365,e12619ea,e2a07b8b,c55dda85,6cd37927,d448cf2a,f4028459,2e371e10,8e91358b) +,S(becf19e9,23fa7b4,1cca0efd,937a5b11,e227fd18,22743fff,80c42692,6631ff0,3213c209,9f255eee,93323d1f,b440cbb7,64e86f1a,4021b82c,485517b0,3440ed4a) +,S(f22954be,430be6ab,34dfbf92,264c2406,df3a0a7,19ed45a4,d09cb161,4abb0c91,a60397e3,ef3308a8,12527744,311673b,c18bc43f,352dba00,4dcd4124,7b84846b) +,S(c50ae8c7,61776e62,5156f9fe,7d863c36,79d43126,c5f3fee7,5b837a38,1803e770,be966bf5,99b67e6c,ffc421a5,e6d12e4b,cbde12,4d84eadd,781ea562,aac7dab8) +,S(c6c3a65f,e849c113,748e9b6b,c9a9419c,1a919503,36201a6d,f989bc5f,fa07d359,fc205b83,b4764ded,ef58082,11eef120,4d9fa959,4d5b7086,c2fa2c9c,3e56f37c) +,S(73466c27,8d5f13ad,dc7da10c,b8855c23,9069f57b,6ec5e80c,e27191aa,196d9b1a,7e7e2cfb,533cfe9b,24243cd6,7680ade2,35abddc3,d8d00faa,c8adae39,15ddf6a1) +,S(6315ac10,35eaf884,8919bb56,759f7013,92fe442c,771a42dd,dab88ab0,2fb0df2d,a49d2c97,6e0e66b4,50e8511f,d91f0f71,a7516fcb,70ca61a0,98f135ed,8e19396e) +,S(fa195146,fdb7ddbc,41daa8c5,98e1f811,36c33eb3,bf23dfc2,3f20b36,1c8e7bca,324fc70b,38677dd4,c8e7bd82,4b836d0e,738dd757,ca408ff1,95bdd5d2,bcb5cef2) +,S(ac40bc48,87734bd,51247e91,43e5e188,e5e2bfa4,2e3c0392,f39755f7,3952bcad,75904ebf,603c2f07,4eef9435,eb22c663,1279afad,94d3bbca,d5349881,7dc4a472) +,S(15b7e1ef,d2c41c6d,416b6dd2,5f6612f0,a0acb0c4,1b161b4b,c40c5ad2,a92604f6,a13da672,17501833,4c4057d8,85be8fb1,ceb6d369,6979b805,83fc0a37,bc27a0a3) +,S(adf4aea6,6fff705d,5bff3c84,93e8870,4ba4019f,ed550cc5,c203439,ff8512b3,53ad2122,30528e1f,4fee43c9,2369dca4,3d071177,3ccfff26,aa16a502,6206a3d1) +,S(da0d5286,fc261d92,1095e1cf,f67e729b,501f21b9,45e8d84f,ba2c80ff,335d105c,5632ce7a,e8d9ce7d,aac7cf26,2ef7bd27,418613c,b288e793,35a0a638,6abd83f9) +,S(463fd081,daf02794,18b95a48,bcb8dfef,3a9dc67c,2237d2e5,dded1522,f714d6d6,3de4cc76,7126750e,4038fb43,bf6af17,63ebc0b2,ef56ba8c,a376b815,6b4f28b0) +,S(15e37b9f,58ce033c,2f0ad85,d49f8207,2e2547c7,91c7ec52,a8606974,2badb586,38816873,5e37c957,c18ad56a,e7ab81ca,8fd89a2d,1710f032,54393ae,a046490d) +,S(2e121b79,765d4f4e,8e7aa8df,5c70e4b3,716b976e,9e4536c0,dbb3b5ae,4044a345,d7ba59fa,97a7d6b3,8b70ecea,312cb01,f9016b33,c160d1e8,d33fdf50,ffcbc928) +,S(8d4c7aa3,c59dede0,bc146b10,38f8f823,8182c4a7,1cde0d8,e17005e8,64ad29db,78aa343a,28a48f90,edd7fb31,849d6d3e,fdb4c677,73cb523f,82c0b187,2c17f44e) +,S(1ae12a1a,19a5d1,3b2f42c,35a385,f8302721,86a67801,c22818f6,94438c58,5cb421bd,990ddad8,16de9439,87bd96e7,e1ddfc5a,8d0f86f7,b30e3483,897815d3) +,S(7a6f584c,d48be9eb,a7b73377,8a173d5e,3833aed3,a603a226,741ae1f3,a1c21bbc,5995b840,bcb6cc28,b83d048,9faa5dbb,c6a93190,46b11b13,59827266,d177d27c) +,S(2dc5ccb4,8f78db2,3f0933f0,ef67bea0,53c7f2a6,80788bad,b71526a4,f55fe758,9e4743f9,ddb46206,a5449942,71743b44,713522f5,f358ab47,34c9afcd,f528736a) +,S(f7a5219c,75dc4426,4322bda0,3b603127,26a6b3aa,c471f42,a33072b4,a44fc9bb,9e1feda5,5da277d5,cb18381a,4471939b,a12c692a,a40ab965,fd03949c,d8124ab3) +,S(a1bc311a,e29e3926,5b3be1ba,23d7ffee,df0de8af,fba089c,fad797dd,8ba67c68,9abf66cf,109821c7,68c98164,b0598068,c4590d7e,b9ff4c53,594af6e8,e0ceee8d) +,S(2c2ffba2,e3fee930,fe8d061,3bbb8290,22429fc6,654d5ed3,61eb8720,1d6b92c5,ed89f28a,bad9510b,acf44d05,5934cc64,ac7e94e,2dbc72c9,986e6cb0,acbe434c) +,S(1d157e13,97f6b22c,3dbfe448,d1168b8a,bc963f86,bb3bda29,a8011f07,d2cb5ffc,bc7cfad1,e1633419,cef1c82c,d0249ee8,4c38b3f9,d628337b,aacf0449,4ca3c0b4) +,S(1b9e9723,56f8a4c9,5e8d5fbc,8e2f2cc5,99c77d62,90b2fd44,2e63b3e6,dc33c772,59db6eef,988386fd,21e8a772,a1fe048f,95ba77a5,122253c0,1a52830a,bc12742d) +,S(80460a3b,16fd9ba2,250b07fb,c77f2526,bec5488d,7d6c45ae,6f480308,39af48fb,bc7648a7,744347ad,e17da2e0,5cd1ce10,db704acd,26c81fbc,db251ff1,c6fdef10) +,S(c6903a0d,d8c26c8c,cdb675b5,972aa050,6912813c,a6f0c8b0,2edfb792,491222e7,f4759b4e,9db7f1db,7c8a1c38,dfe76d86,c3778423,29280aec,12b1be06,d8e49ff5) +,S(95ab78f3,a4268c8b,39aa645d,8c9fbfd5,b92469b0,809d6369,3d57d076,d305a241,8df4c8d0,ed85ac01,a965d580,78f36a5f,690aaa03,d9479d1,b2297a52,53e3c6) +,S(bafa3ae4,40a4b8d0,40862a18,cca806fe,8cd0e780,483b396e,41543486,db91d9b0,d7bd60f0,c0ee0b8e,38aad85a,85a42ede,56c66d54,ee73d371,a3bb7cdc,e93df670) +,S(7cbf5d9e,3bea6864,b87ae157,fee6e352,dc3a4f32,6e7cfc68,377fd199,a6dbb71b,42d082e7,5d55eb62,9771942e,3801c27a,fd80b502,a997ccc5,9f5a95f7,d7276999) +,S(9108db63,751b8a9e,f4870524,f1198f9c,c4d3ec20,af54119d,6011f263,de13ca29,8c1d6c47,aa016e83,d2c8f76c,df0935b1,b6f909b5,bf5c90b,f4203493,22c711d2) +,S(a705e7eb,c20ac4d7,43be660b,d61340c,9629d069,1b08ef01,a59e78e8,2d8b347,1ed8ec9,13ba19e0,851e1912,5854433a,f71b21d8,df64958c,afc5d7aa,cd29ccfd) +,S(b75483e1,60144d46,78af9a3d,701c4ffc,fe154c49,fad45ece,3945289d,c3781c3,a4c0455,13cfa7fb,ba2931cf,722fc569,87b2c79b,c4b94313,5a458d34,5ee16d57) +,S(c59aff26,bd4fdb9,37468989,763376f5,64abce,c00d54e3,45b6dc2d,9b7b76cc,c396c194,db446fb1,a22e86e1,8a37981e,d114e675,474bd24c,784daa96,91eb15b3) +,S(2f6701c7,815ba7c6,37c4649d,d05a31d3,e909d8ba,931e7136,1e0662e,3ea19985,937eb67b,9262bbd5,12a21e90,393f9e65,66e03203,55c77afe,cb98d1f4,bd25e8c3) +,S(170d1e33,f0862542,dc72b1b2,950ba98a,812cc308,74ecd0c9,23ce7c09,ed7cf9b3,5148ef39,68ff35f7,a633ba7,dab6cdaa,54dc6f87,510f1a7d,4d3019f0,c00bc868) +,S(743b02d,b02301db,453f8694,cd517c6b,433f609c,e205cac,6f6a49b8,55890708,7af6350d,56130339,1a9ddce5,f566b9b2,9c10d535,d5183850,6c743124,8dcd707c) +,S(ba6df8bc,f9d83988,4991c6fb,e0aa0ecb,d0b6cdc4,d0e372f,3ec83b51,da6a6570,7d27b176,3a01a8bd,fb7dbe0b,226dee6a,73ed3644,807ca33a,1f5fee61,cc161fcd) +,S(d3b63a2c,364f01db,6a6f384b,4bba6c2f,2fa46a02,86090826,1c8b5045,4b92ca5f,df6b9cfe,fe7aa14,a38bc44b,8b627b6,e0ceeca7,1720d630,cc4fabf7,b020e2d2) +,S(638c2b1e,374ff6b3,4b634f4c,bf363bbb,55d66c8c,af4d3fed,43cf436f,a1daa7f3,9854873,37b48f32,4feda3a1,f267dbe8,8831aedf,d7bd36c8,6cc8d862,857507d7) +,S(1749ab4a,607d7864,5c4cbd30,4bc34c06,94a7a636,9c8c8f8c,be4602bd,16c4b4b8,465bff86,b459b842,dfae4df6,99be1758,8b1aca97,f9802827,d892792c,748ac92) +,S(9071a5ff,ff23ae4e,2d81b2fe,d341bfa9,cb86ae6e,ed32870d,d549af20,a1db9feb,c0e3d4e8,277d099a,9801ddf3,3e513aa9,1761218a,967d530f,21d70894,ea7d38ab) +,S(91bc0055,28e2d857,ac644954,242fe0c7,bbaadcf2,9119837e,898244e3,a305ba6b,6fb63758,3aefe600,46997b88,315d5a24,683ff955,94398694,be304dcd,8b588f67) +,S(9663913d,48c865f6,312fe51b,6e8e7c6c,51ae397b,d141aaf2,df3d6ff5,edebbe68,c6251751,7e24d81d,b1da26a6,6627fbb3,28b5f818,6477b34,43f7c36a,918753bb) +,S(e88e8702,7843b941,61c71887,9a0a9a90,cc0d6dd3,8329c73c,a18acca4,3f44ffc9,7e31ae63,1f9c927f,bd055f58,e682935a,3225e778,9221a062,f2826d86,97143a61) +,S(5ad27e79,dee03a52,be771a9c,ded6a02a,58337f26,be810d1a,f8cc5ddc,f1eeb917,91c18e01,dbee34e9,a5302a7a,11bfa7fd,ac852e1b,e53aec2d,3138259b,bb53e6f6) +,S(bb7f4694,f2935a5e,8711ae47,bccca550,cee2632,4347b468,58e40c74,49111ead,d9f94c14,332ad75a,59dc784b,d674e8c6,146a2b74,566ac1ef,b0ca17dd,9eec8d74) +,S(ff77ae06,e0624cf5,f6d905ee,b0de7281,5377c026,3e01b6c4,a139e4ac,3304e82c,1f27acf9,933d08b6,f0892199,11805d14,1611a318,661e6e7c,75014b84,cc35c395) +,S(84c15fb3,1b12d39e,ae59ce0d,f8646e9a,67c85492,8d6c498b,4b836be2,eb19a060,6aea0d78,d54090e3,2216c3ae,be0dd433,a666e67b,44cce0ec,1609804f,fde33f74) +,S(9a48086a,8bb9b150,a6ccb966,3978f555,41db6d48,1b3d5266,e958cbd1,df9ee7ab,d8eb2109,13ee09e7,b5767661,13157905,b3cafed4,641903b6,da0ebc08,a0ce2f58) +,S(db32ad19,45f4d9f7,eff1b8c6,b87c5545,1b0c74d9,8f1c4ffc,6ff1e79a,21ab3033,2d56e65,a70bd23,617f85f1,4a5d0e4d,52aa6a70,a8594158,36d02d87,309c7eef) +,S(4de7f1aa,b9089f5c,b6d95b67,a04952b0,d4696cc7,6640e1da,f4bbf7d1,da985851,96f2cd33,5fd4b816,4499ddc5,5e81f5ea,c4db4399,17f2151a,f86d2ad1,e2b3612e) +,S(74bcfa73,5aa43e8d,1fb540fc,9922362b,21878c09,666bf541,a0e739b9,dcbfd1c6,84b26fc2,8b2a05cf,a67947d4,99c1ffe8,f94ed4d4,6ba583b7,cf26ee81,ba60bca8) +,S(9c596bcf,3d2e1df7,cd8d9807,8a1ab17b,f16e27d8,66cfb582,ef58498c,48ee0fc4,14dfc093,48f72d7d,af9e3599,8b5f18bd,5287f3f8,381308e0,63666028,dda9ac56) +,S(8e2a0d3b,2786d67c,a15cd72,4f2cc6dc,16cddfc5,cf080ef8,d9576b2e,e5b0ff9b,2ec4853c,c83c72d2,68555129,ce30c836,50fb59b5,17a3d61d,56ac4273,1b33ad06) +,S(25ec4838,5fee8fab,773498dd,85a23ec9,46c59839,14fb8a9f,d1239ea8,ade3f829,123bded6,5312030e,d4760047,1867aa4d,b7537239,b363b6cb,58ecff98,44986924) +,S(a1cd9872,7551e2c5,db7985b5,1698b97a,31b90d3d,32fbe60d,34f8ec2e,398df76e,40858565,aef814bb,8bd91fe1,410f9556,3f1bd170,345c1283,b64fb268,4980c398) +,S(bf7d3973,aae2cc31,e831390e,f2458e85,9ed6847,e9eefd6e,cf91e3d,4a4924ef,c2829fc4,2127b303,c801605f,35602b84,32357564,d9333ba8,d962d639,ef21a6aa) +,S(5a5299ef,e0d394ef,f4b510ba,96dc73bf,6332d358,e276bddd,527ec290,b73e3313,9ccd4618,17e18104,d324e1e8,1597eba0,cb6b475f,4e5f2e02,9cfd2d63,b613de79) +,S(90efd8cf,9e4b9d74,5cb36c13,20a8bb0d,b5cb8578,de49ea4b,c289043,e2ea810e,87a73339,aaceed7b,af47b5eb,97aca554,d80a4f78,d439ee14,4b2d0fb,f8df5e3a) +,S(3a174294,4db7f2d7,2498e2fc,e2026d5c,f8600ed6,958db97c,24ac0de8,417f6def,e60c566f,f3fd14e2,2ff0cdee,45c4c2,31797951,7aa0ca68,af91a5,e41f5f60) +,S(2213e0a1,3679040f,73e4d68c,bb941665,6ea83640,33abac76,2e64d509,48a97656,2b87ce0f,bec2728a,aae6586c,bc6d9a89,a4bb9b9a,211de522,cc909279,5860791c) +,S(382412a1,ab396523,8b06c47b,e941051a,bef3b215,16efb280,3ff3a1c4,824954c6,7cae8b14,1938312f,ba482980,ab9073da,c66c1ca0,d746231e,8ba8f331,4cfd9cea) +,S(3d76bfac,89c1269d,53b6ded6,bf13c785,361b1fa3,84be2ea0,d582ee43,f06de56a,18b1cdbf,96d12859,bf887b89,6d8f2e6c,a08b892c,688c7687,8294974d,af6d6284) +,S(715b18a0,68d86cfd,41a20541,847b36a3,ed7814c1,b5528751,927042f9,85e7ab70,2b8e0228,b0a4d39b,85a3d3d4,f5a10db,c6825659,f4b967c,361da449,24890911) +,S(a31a10ea,e38e6a00,ab4f004,8b45c8a3,e57856b0,d0b64e47,fa90e234,e17943f9,5d4b5150,7d3f3a82,87e5d51,6bb30b89,2cb9f540,96aa5962,1f77e028,480e594c) +,S(b397f965,1dbbb6db,34708066,a1743511,d4a16332,95f53772,72c43a6d,6e21c1b0,673fd327,45bea2fa,748a759,30679b2,471e4004,423dc8b3,f34f95ea,f88d2b8d) +,S(2e4b865b,c1245325,1ad8b3f6,e8776bd1,a5878b93,ec34f847,65af84fc,146d9919,b3e7d479,661ce034,50094432,c538f55f,c8be8693,73a91fd0,350c8089,ec0d76f) +,S(9a38c790,7c0751e5,ba750bc3,485b4a4,72b661c3,63a3980e,feeaf59a,98533a43,dad7ac3b,65493036,d30068ca,72808000,d54b42d6,d263de93,a1ced3d8,fa82ca71) +,S(5599d251,3b3c8337,f8af18ea,70d1d2e1,83f3e363,63735357,2b3f6cba,b4371d9b,7ccddd9e,ec8dd507,69f6f633,cc70488a,6a4e322a,2716218c,5de50fae,45398dfe) +,S(610c472,4699e983,530e8a32,b60a8077,c7f60226,cc3b2010,e49b2e30,f2a98afd,42157de0,fe6d8e53,17a3f565,fa450f53,8755679,6d98c7a7,ba0b3e96,844d25d1) +,S(89c082e1,1438e2b5,6a4bff8b,cadaf804,c9d11fa0,8f47bff5,39cd0741,76f24a59,f4dad4e6,19ccf814,e899d48a,904a88e0,6db6ab19,a2e06a7,b359db9d,cd0ad0ec) +,S(bf810fed,48d1ec4f,77cf3732,ed10a44,df9e4540,2e1a1e1,6b29c82e,32537565,6657fd30,337e294,fa31d30b,409b426d,546a47cf,38cd23bd,75aafaa0,b527d66e) +,S(3b1317b8,bb3c9c91,964ce369,19ea811b,90a8bd5d,ebadabc2,d4d1af3b,50fb3524,cfd5988a,78aa555b,595531f6,5fb0e3f1,e756c1db,626cf60b,4c1b17e6,caca603f) +,S(88520439,61558d79,7b084143,783d9e03,791e6183,c932d1a4,17eed30e,bcec0bd1,271097c4,4c723ab1,c1d13e9,93b7b232,235957ef,f21a13b1,2b3d302a,ed46ba1) +,S(6c420c30,343cf500,da0cc05a,c315d3c3,45ed8aa8,e0551bb0,32fbc512,732f34d7,fb3c0808,698d38f8,3310fe1c,15587cf7,137bef2f,666229b5,bc789dff,1b2f1111) +,S(b12e21e0,e060fcf5,580d75ef,22e8a800,33e2c19,487d0660,615f7d51,ba00e430,3931d63c,a6e0da2b,295bd22a,4bbb27f5,fb52d89a,3c4ac36,795747e6,e74ce944) +,S(4fb9da54,4da95655,c0de5654,f68c2820,a7884734,4bad6934,e671d56,e7bfe11d,16586701,9bc89b28,f5fdec40,78a2a51d,6e087ee4,29456cf3,d258b97c,209d44fb) +,S(18f8f6ef,23bf75f7,a7811025,5babbeff,792109ca,5a550472,245552e4,35588e7a,e712abe6,3a374f25,fd4b18c8,4b1451fd,ea77692a,43c0e3b1,cf3469fc,7a9acd55) +,S(d730d167,1bd36654,7188c07f,78d82ed5,6775d7ef,bd0967e6,1abddea7,7ed6073f,49c4bf3c,ad4e31df,d840045c,aa8be15e,43f90196,818e30f7,b379c74c,1d866553) +,S(a915fb72,7d4c40ab,547c983c,24a4f019,1f5e89ce,7ab0636,e903aef7,592208a6,fdf28a3f,6557f27,5813ccf3,8d927f40,b910c5a9,ddc3c83,14a48eb1,6a5956be) +,S(7abe8d85,bd95c580,cd9d532c,c1295f5a,ad5168d7,e3dcaf28,b19f5e76,95107157,694abe9b,9a6ed0d4,c3ac1db8,79b49038,6fe9d2f9,443647d1,91533fbf,aae3cc02) +,S(93a83e8d,c80c7cd7,64dafff1,edd148b2,9c336de7,cf978b14,fbd35625,c965942c,91ea5775,db50bf9,a7e3f79b,77c7d5b2,deddfa08,a1d455e6,fa21e547,356c634f) +,S(a334ed87,dfd2e1fd,699ce1f0,a09fe921,487f8321,6cdcf75d,fc8d7e5d,cbbd1af1,42a0874e,d148bd32,ba4324ae,eb0260cc,7f0d20f3,f43388,38904640,8f7ae7e0) +,S(811597c1,f4129ac6,e150c231,bfd8e4b8,4ad441ff,2c698486,affd4ac4,c22bf8b5,5f7fb47e,11b476cd,acce1552,95ac000f,3acb3838,6ad3c6ac,191dc12b,d1e299dd) +,S(cf754ed2,47c9eb9d,24f3129c,4b4cefd8,94b5e58b,832f158e,2e82911f,8177a59f,262cb605,2991777e,bd1ed5de,d2e7ce29,76dd73d1,ad4c9bf4,9fb5d8fc,fbe4a3d1) +,S(290ec604,a6b4d816,ffe75715,419b0f33,452530dc,94f48883,b3982161,4592b229,4235db3d,df2e3f1,b61ac412,a90f543a,ddcd519,4f4a315e,d889b32c,ec8f76e9) +,S(1f90b869,4bf9ffb5,7697ee72,29b7f20b,52b47997,35efd7f4,1e4b9102,51886858,dc3d7a68,abaf70b3,c84d533c,48ef38f6,9be7d26a,13c4e834,5a7bee29,c6d3c87a) +,S(ea20b4c0,931087a3,44d5642f,6c018aea,2da5f189,a4d25968,96110281,88545ba4,f9adfa96,f945e745,88d2ab41,e32ef5a,76b370f3,f0362e57,129c3998,e32cedeb) +,S(b8bb88c1,21948c01,3a61fbf9,bae86eda,28e9bb4c,6870b0f1,7109e5b7,c00cf4e1,90685129,8607d7ac,25bea5c6,1cc4feb4,4148e07d,2fc3fe7e,449773d4,8245019b) +,S(2345a244,f2f411f6,ef091904,81eb9083,9128f7d8,67e8b910,124d1e44,d116c529,a8eaf530,c69b792,d6595967,4f23b9,b0e239bf,b69d05ea,466f9f5c,9bd5affb) +,S(75aee824,38bb03a9,b9208cc9,b725f13a,1fee1aca,20ed129e,e5ecdd59,b92c89cc,fb6bc8a0,fe0f684,ce4cf153,2053312f,b97aa1e3,739fab8d,407db39a,737ee51b) +,S(ca46d3eb,c981eb1,764867,c99cd7fc,c414bdf0,31b2c9a8,96829ebd,f31e2e36,46363355,862a64b,97541f7a,7fc5cf51,ecae168c,c6530db5,3a7f2394,2e87bb96) +,S(4fc1d258,575c4830,bc7a03d7,6a259406,7d633e9a,da2c734f,45ce4d9f,99dbbe7d,cbdc616d,fed2bae2,9312c5bd,9e195bb,bfdeb2c8,d1aee5e8,cae8fa0a,4bd6baac) +,S(4edae08,54365c27,f6ad83b3,8f68c7d3,f0a09c6c,153791d4,df98b5f2,3f0b9be,cdc8a485,8ac66847,c732a2c5,4be86af8,d6d637f3,e62c7802,dd71c7b9,2eb18223) +,S(624dca60,16beeb28,c35bef5f,e97d320d,d725619c,3faa7ca5,ed79d491,72b12469,cc33b49a,6fd125cc,98d65a81,c0713cb6,2a7e687,276e7fb,641e2f76,52646c12) +,S(6738d38e,760e50b0,6a18a9eb,b5e3676e,c38f3487,e34461bf,2e5d52c,5bbd6b4a,c3ce0343,9b9f624e,a92eecc9,860ff680,63a907d5,b57c43e,465ead5b,bef5e709) +,S(bcb74527,10f178a9,eb48655e,3d373b56,8f02036c,e9ab826,4ab7cee8,52f7f9c0,4e928392,52ee05de,587c91d4,6eaf5e5,92ef41e1,5a2b5c2a,da9e4512,c25bb416) +,S(3375c7ca,1b5fb4d1,1838ffa0,c21d7e03,de34ca5c,92bb4592,bb4598c4,2b490382,8c284e32,f016d186,875b87d3,3bf4271,4b9013c8,ea159634,b39b7365,7ea837de) +,S(c347409b,336c0677,ee95de61,f93fad4,738268d5,6f31059d,380af075,60e496bf,37dfcc4c,c13bbfa,5df43c69,eda0c68c,42de70d6,ab64a9db,a4ed22f,1cec3fdb) +,S(305ea4ad,ce72ff73,976544d7,a3deb346,452ce997,f280c3a6,106b7c9e,3b9bf5d6,bfc33cd4,ca178310,c4caba86,5b87477,77e9e572,4278f0f0,56b86a86,1f2e13ea) +,S(8333f714,70e57841,312a33bb,4f1463df,d237651d,fec4e1a6,40c0ebe7,478c5a9f,d39b03d1,11657c2e,19ad78d,3e1208ef,f8505695,1bc67098,b891c42e,b427bcb7) +,S(500af03f,eba3b646,a0690f0,74cac255,804c8f8a,c2aaa1f5,f5cee4e4,41913e7,5e67542e,8a8f0411,e9985a76,97ba626d,f0607f66,9f9c11da,826b47b1,a52cfa2a) +,S(e440385,c16bc15,5023cab3,3e7a48e0,5e7e0c57,e0fe848f,26b146ab,237a3abc,dd8ac982,b627fc9d,7fd83c26,51805de3,d7369ef9,2e970664,8744badb,3db060aa) +,S(83eef59b,b0a26fa6,60c94e45,c097bcfc,8622c37,cec46eb3,f9e93aab,d0fa6438,8b51311c,ff685570,d9aa7a66,5b47a3ee,b6bc05c0,a2709421,c73ef814,bc703723) +,S(930cdc95,f723a7eb,d698c1f2,46692f39,e1add95e,f8cf84ca,171d4700,2a7d759c,ff161a2,31fc8964,5bb6dbb9,f595daf4,86cf01c1,944021ff,6ff793fc,2613bfbc) +,S(4f7cb0a2,c83f3520,86085b19,a6e5ccc1,b0beb700,35637e6e,8a79fd78,337c2616,aa32192b,82831ed,a9412f4d,6ac6d148,f68ef492,5b438cca,12a73b37,b4a8fb74) +,S(c7238fe3,17590be1,d8403ca1,3eacc6b1,71cccad7,e2e8f659,f11357ad,70590424,59079180,90bdc74d,aa06abf0,940519fd,d09f24b8,88c15cb,a632b814,fe8910fd) +,S(c6afda17,e6582427,95cd34e3,edefb600,70c73737,2d99f6c,b2b8dd3c,99874880,d805463d,15d185e8,b4461293,b6e6f6fc,a0b58a49,eefd4d0,11ef48cd,da5a16a4) +,S(4a14de26,ab18ebc3,414c6856,1a77d62a,221821f,8c216496,700bfbb8,21d95b2d,8037ef39,d1f190b1,a24078e3,e554ad1,cf86d5cd,f731478d,b34b6b5c,c9174314) +,S(cbcd6696,547fc496,8c6e7ba5,4caa4a74,43764852,43f479e5,558e2be5,77bbad00,8e0099e8,559db5d,dba0bc72,21505ef,d42c1c95,876539ab,19dedb2e,8e561482) +,S(37f168b6,4b41be85,46abd1a4,7a5ab3dd,5d690661,e41b16c3,87025106,caa4e2ae,8c617348,bce3bbf7,54a121b2,37342794,5d734e38,da08066,c4de59da,e60b5c89) +,S(3aba7081,55dbb35e,dc4a3fd1,1db54446,a7501ea0,d67b0286,8d2e6d77,99162697,829502c4,2dd1105c,cb046e0d,41cd68b4,38437394,b93f17de,5534f014,270c4602) +,S(84842bf5,fb46c697,44eca720,7b1be6b4,e5f5809e,eaeb3e9b,1058eca5,4498cafe,f4210fd5,b49f6484,2efe3089,327673d7,95642ad1,73b6840c,7323b7c4,16d61fb5) +,S(88383dee,ee0db44b,959edd96,feec2bdc,73d6ab56,9333fb3c,d4b18b01,ed8af5e3,8f0cf362,7aba3ceb,104009f0,baf84ed1,f57402e,fc330f10,6e0b45d5,4e0626ed) +,S(ad0a97ec,2197c5d7,4e8eb9bf,9798a24b,aa7c3e5f,ad6ac263,1acd5109,5178d8f9,72b352a7,445db832,2e33c93,5619e7d3,266f254,64a4c4f0,96051ebb,1e37065d) +,S(9b727e4,d107418e,1f62b499,99c1f8ec,55ef6e91,a9a10ec6,8905be97,33903d85,27d6456f,5ea52aee,a190dc81,647ce31d,15ac8c36,de65685b,4784eaad,4a32e41c) +,S(e86bbef3,8d740a44,7a2cb0d0,a89c2106,d85299f8,c38fa540,a7075efd,3a02fe03,8a9f75db,ecc532b6,ade5be9,b855a27e,185895ca,d6a6549c,f6c4c1c8,7e151b04) +,S(b72ac468,9209207,2cb735e7,d424a18c,5ef097c9,3a9b96ef,1ab7e29,d0f379de,89111544,27b03712,e2236fcb,12cbad35,98ef794f,b8141913,aeb1ad8d,ed9e6467) +,S(f8f5819b,203b2bfd,ab2dc532,53277103,2f9caf34,c53c7ec7,7253b314,2e731ff3,433fa831,3dab76fc,aad5bafb,12362126,6d8d7c09,9d513ee1,1b633c6e,e3f1e96e) +,S(8e4a8890,a15da3a6,c14d2df7,d09f6157,d5dc95f7,4f9518de,8aecbc4d,c0ac62f2,c06063ce,1d3c2a24,2494a1cd,db381513,6200827b,78ed080e,3cd14f4,5e545acc) +,S(b1f6dbe2,ad730748,f906d1d9,160996cb,f3f2450c,fa656856,e34f2481,40767081,ee6b2a03,3f3245da,76d01bc6,e61afcc6,94a9e64a,4f0256bc,62acb5a1,82e45ae2) +,S(2139dedc,a8365bce,b9c49cfe,3834e4d4,27a46750,d6b0f0a3,4e7672d3,d12509b4,b20a9101,b63be2a5,28340f58,893e10d9,d3c63fc7,77b5c6e6,a9a67193,13725870) +,S(da3aa585,85c00e41,87db0240,547ff665,376aebea,a24e5aa6,67d477f3,c4d3b914,92405390,d255ccfe,a6bc7dad,4fb1676b,c741e530,cebdaa3e,669bfabb,d1c4780a) +,S(89c47de6,84e1eb9f,a5828e65,dd17a852,7226a75c,3d113102,97f5b8f6,5b67b210,970bc229,d60b00a7,c2354a70,37ec8569,ad615faf,ac77ddab,f5847a09,c1fa57ea) +,S(48ea67ce,db716a95,6b6066f1,e5e9fc71,5994a4f6,f4e2cedc,bf0c09f,4f8c8fd1,513e45eb,159f9865,5ac821d0,e18f4e06,fa3cb8e0,9d45c3f1,8d3c3bfc,48ff3da) +,S(c5ae6651,ded2c479,a3b6c9b2,44fa35f1,2eb1eaf3,fc78b529,42ffab7c,4e33a1cf,ae6ad807,435d4a9e,e8bedcb6,3bc804e7,e67e9418,6494bc8e,384b29e2,31af8cb2) +,S(24e485b6,7c27af76,e18ed116,90c9dc90,73a0b80b,e93f5381,6669e2d,3c0175c9,fcb183d8,696805be,789d83fb,a197fd24,996d3542,b2f3eb5a,c207950d,f9c079b9) +,S(3bb47a19,b1bdc527,a8fe262a,ecee2d7f,1e772627,e5cd5c70,eb2a8c39,f1977628,2d10cdb9,91fb5042,905f822b,68846390,a922da1a,7b7b313c,47edaa6,85217fa3) +,S(7d4233a,cd50bad8,71e0587d,e10204f,6013a784,b65b6540,73307364,5f3078da,be85d3d,dca838a,1f35ca11,1333e943,fb498cdc,63258ac8,74bd6acf,2b934b77) +,S(b5d0d791,b6685aee,2f599505,d01bd3,d41d5a1c,531ac7fc,e6c33b97,cb0ed264,47fbad30,413084aa,619d7bd6,62502cfb,9648e64b,e757d6eb,24fd5e2d,6b1629) +,S(bd6178e5,b1c558ba,432a89a0,482585ca,40ea9922,7c94ce,23f5b081,d606c7f0,9cdc6bf9,d32b98cc,73bad7b8,c08914dd,b9a8c937,913eecca,fff72dae,fa1cddfd) +,S(13ca834c,a5f41671,ce7f0978,a310420d,6a82fc38,fcbd997b,88a1e79a,66fb9375,ae32a0df,7f269c8a,744e409e,16ec3d8a,eaac151a,99bdd7e5,50287005,6f48f6a) +,S(96322802,87add117,4040f802,ed5c71c8,5f924398,1ee78480,4f16e5f3,f0fecb6,2d07de71,cfda4b43,44baf838,7933a372,3d536411,7e4c0f84,2b402156,3f9b56b4) +,S(961efbd2,ae687808,bbe275a2,cba1769d,4ca537a4,1046c5ab,ff269c1f,b9477ad1,9d22a10a,294666eb,5c816bf3,c4dc2c44,d7836202,e15bed89,e3d28822,8193251d) +,S(4e7162a3,8926282,84ac4df5,88301fc8,5d91c869,2fb854a3,ffd34c47,7b216ee4,6e6dc88c,d91b9702,cb38cff,2d6a38e1,d512fb46,9d85f878,8510ed97,2704ba27) +,S(6c1f707d,51b1d3f4,ab261d52,6d0106e4,3e0a5b1c,76a59868,62e9d97c,bc6e3e38,d2563843,5dc8b102,c8f4ee13,dc345f85,289cd499,9bcfbe20,1bf3dc7e,7dae1f74) +,S(3ae98e6f,49d363fc,8416f965,4e57beeb,d37635fa,4e78d8eb,77caae69,f2201798,ffd95480,fcef0686,9ee781ef,cd2693f0,e6be2e27,f207411c,39a18465,4d2c3cae) +,S(eaf94fc3,fae4eed6,35382e91,2cf963da,2bbbda8c,3197e522,e0054cf1,4cdcd5b8,a838a439,3d4bc0ee,a57e6235,5dacfd97,7d70afc9,16e61209,10d13fad,7c1c22ec) +,S(7eb52e7f,bbf5b802,2fa6d66d,801c3632,2c195b6a,4eae4050,5295612a,a184e2c8,b4591e5c,c66521e1,b991f63f,456306ce,cb2e7568,5227788f,a2e9a75a,bd58b384) +,S(d22b8dd1,6ff24603,5fda0ebc,77129644,a8469373,99b2c7a2,60d8e985,d4f2a215,7a9a092,e8473776,6718e2b3,9068e163,e06618b1,6d6bc046,b33e2d76,8649611f) +,S(8f6eff05,f746f0e0,9b328ec6,2089e575,ca64175e,d950ae4b,c67a7ce0,83afa1b2,3681243f,ca51a6c5,7ac92100,f38df1fa,d1093fd6,ecd53231,bfc01fcd,89e38305) +,S(ac9ba060,ff520335,9a4111f5,c8c536e8,e27a79d7,33528ef7,9da7b21,36243a07,2ba3cf76,3dfc0860,ff3333bc,e660ebb9,c4e5a988,909880d4,1ceb4219,89f23f77) +,S(d6896830,62bec27c,815191b3,4addf36a,cee1cfe7,475d34d4,d83a83cc,6dce3992,9f038f46,529fb86,30b19b08,db11c630,70593570,70bc51b4,fc1ced24,f43fbd00) +,S(e815019a,f6923eb7,cf963f2d,476db569,bb04cc7d,78a0bbf5,3b422ee1,caf43b70,984c16e6,593d8642,de871694,800ca14a,a103a61,20b91c17,4e06567e,2d731c95) +,S(3670e86e,e9aaf036,40136ef7,3344152d,c792c8d5,a064c0eb,a511e14c,41d6f7b9,eac7dcca,e491cbb7,cd27a522,a7db96cc,7d300c35,7413433b,9bcd430e,152fcd33) +,S(3d03f819,4802149c,c6428aad,851bd879,189c557d,cc9ab1ff,8e2e4cdf,f0723308,1f56ada,27f2c923,27ed2fe5,88d8736a,fb68259a,1d5b1c14,7f85669a,eaf47615) +,S(bf2ac011,9e417837,d4815c9f,74351869,4395ae40,77429013,7aab32,980748c2,17a47bb9,6f7a3e7a,31b5a8ab,2adc9fe8,98fd94d2,9ea7c3b4,a5b6c5bc,9c367ac9) +,S(c72eea14,ef09c0e6,85c22840,95e73e0b,6aafa64f,9410eb0c,97f6ad4f,64dea571,9a46c93d,256f67e4,1ccb609f,4ce94390,df9c91,38a9d2db,9b993456,13346031) +,S(25463446,6da168cb,2d816bdc,3c9e3a43,7ca3463f,8c8a83f3,62704996,c1bb5b96,3d69cc73,6aca2a,cb97e1a3,cd57be14,243e458b,305df59b,3e3a67f9,fdc17b6e) +,S(b40dbb03,7062dfd7,7151013e,7cb0a921,15096a04,c39f7e2e,66188aaa,368c49d2,34923fac,7b1a4570,e824c3c5,2edd775f,ecf93573,2198f801,8f617db6,474fb519) +,S(23fba417,ff084b42,afddc4a5,c070305b,553ed7ce,1311e5d,4c1f7b2,772c9aeb,af4a342d,f9346ead,89b3caa6,6a3f187f,96f2b470,c0a26752,76e895cf,c5ca4adf) +,S(2e7ecc9e,d4f21af3,a3118799,d1ab7e3,a30d011,edc53e33,93dfdc5,6e80927b,b3959fdc,f6c4876,36813bfd,e7e83b4d,7ee0f1c3,54e0491,f3195b4b,aee2df72) +,S(1c68c34c,8aaa0f2c,7daa215a,961180af,3938599b,1324aec8,7a1b3841,710db2c3,d8d68179,71acb598,5cceec45,fc5a754e,e002d09d,4be45e8,ab6d2bdc,ad094b24) +,S(fc0ff082,ca6708eb,9b9294b6,fabef142,2cddb5a3,611dffc6,f06c05e7,f1eeddea,6f67fbb2,df22611,e2f1e796,c67d6c3d,14b17f98,2b6e39a2,7bef257a,d6955b70) +,S(fa683ae5,8dc85748,1a7ddedc,708865b9,267e9fe2,e485a243,1d005e47,64130548,4d9759ed,76326207,891a9649,3b4d2307,b9694fe2,c15e2327,a79dced,db8277e2) +,S(3cfead76,5ef36c3,fa9903bf,6d43cdd2,46ee8fb3,3fa1d13e,42fe9818,6d299009,85a18ee1,da24ebc7,3dd87aa3,ca1e7565,8f868fec,50225e2c,d5b5480e,cc0ccd49) +,S(487fdda7,364dacf6,2fcec7a3,fc2dfd27,c38079ef,d48f0220,85c62746,2c8ac658,1479200c,b06440a7,186a946f,83a137d5,7e5368b6,7ef8a66a,9540a131,e4bc9b8f) +,S(f3e413ff,81c2ee72,74c079f3,451f41c4,bbe1e51,f7c3a1ca,513392bc,9edd487e,46544553,79a33a0b,13fe5904,504cce47,55d0e2e5,6c4163a5,14d5b902,906caf54) +,S(d93692b0,53ad5194,b70b9be0,1dd80926,e2c93754,328b3eb7,bc85c45c,63e6258d,7221837b,3276bd2f,9ba0981d,883cd68d,97d2ce77,9dfa1073,d59b01e5,df311ec6) +,S(e85af4c7,42fd5424,2964eb26,b531fd77,550d3b2,eb64bf39,e97de203,ffe2d28,8368322c,e40ffca8,49ff1a53,76cacb17,98fbf4c4,38f58690,54dcb642,f805b9f1) +,S(9e4e35a2,d913a2e3,bc931c59,298ef6bb,3893b086,ee40c978,430d8436,49fce4ab,ccca94d7,d4bad95e,c15b19e7,9555579,d47cec60,9f42112d,3d992035,6d31f7be) +,S(7d72793c,dcd78afe,23e8b000,41d67983,6528b1f2,6978e262,4d022416,7ac5e741,1189804a,2558ff1f,63a7ee1f,ad5f8ab7,50a412ff,a83a9783,996e5f26,637100fa) +,S(3b8dd2bd,ca65d7de,6a7c55bb,47dd5ef1,5ce6f533,96ab335c,84c0c9a8,4e06a7da,2ac78cf3,e1baa981,b27dfc9f,e1b7cd2b,1ed4c37,f96af6e4,99bca1f7,de62aac) +,S(128aa84b,3d920356,db64bc95,b52d4c8f,3054cf5b,22c6039d,1d21ea60,b2274c44,5a748932,6a98019,824a9d7e,cbea2de0,5ccbd9f5,a2cc5dd3,ee0b3dcd,a92e8758) +,S(de8b04b2,c761b876,4c41c344,a3b57c41,fb62e6b4,ba25ab19,8fc2ded,2849e151,134ae148,d89de734,a222b656,b878fedc,886d5928,fc6bfab7,bdd0a74c,3753f1fb) +,S(f643025f,9fc3824a,6ce70677,23475aa8,8df24d59,682f5a6c,b18b1c0d,5e297017,24eb7c8b,e3de50a7,cb473bd8,81db3515,8f9484f8,8574af66,a15f920d,3986a049) +,S(ce2e5454,54324680,7035594b,1aabcf6d,5d8cad20,729a787a,7e01b61b,106fdf19,f3a2e5d6,745a16cb,3403a768,c1de8f73,cd26388c,c10f296f,f00cf9f5,209b1555) +,S(bafd293,dd071a21,25a857c2,6acc5afb,ea79093d,3c9771c3,cd3b875e,b74b3280,2d56802f,b8f26950,4adb2a51,a91ad2f0,d1ee6501,f8c9279c,6a27b524,8dddbb70) +,S(10e0909,5dc7ae30,9f1afbfe,1bcad71f,c66489ad,56256c3c,a648f554,c000f414,47a5a7cd,968dd158,e8436399,40c30179,3807713b,c09fb0d,83c6c851,c6b7029e) +,S(73b8149b,4e7bf050,b6cd9f4,93c85bf7,61062329,2dec76a3,2d7054b0,c794da63,44cb915f,b6813c71,dff3830b,ebb6888b,76312778,897903f1,d9988c37,3c362bbb) +,S(59a5dcce,9773617e,73c529da,6015ca40,bf923956,339a366b,84a69e23,d0a60fd4,4c62abdb,c4453ffa,2b806a6b,b823fbc1,59f57f23,2234c8da,a471192d,3081ee09) +,S(1ad2aae4,f571c6ff,1abfd45,35b3d085,1aeabdbd,b3a340f6,7bef0f78,f7afa954,1c394b1c,94539758,85d72498,b36a3be5,56b4f80,8ef52977,b0157885,649549b5) +,S(2403f66c,a6a7d60a,254b51e9,32cfb700,f37ad73d,193f25df,6024bd51,d0f337dc,9ad75d44,24517aff,7df86c,9bf4f315,cb40199d,4a2a5d5c,74044c4a,9c79d69f) +,S(f3139f4b,50dba596,87080a7e,b19bcc34,2b58df9,26576bc7,dfdc8e7,4914c524,fbaad228,ab34e8d4,451cf6b3,a1dbe225,bd46bfc4,8a4bcd94,10c150fc,5636c687) +,S(ec415f8a,81b1f559,714dd790,2441eb9b,c5c7bcbd,e87190c,c109ca04,a3e75149,9b90bd46,d27e0200,369fe995,3b50752f,d00b9472,fd31383a,f01bb88f,b223bc5b) +,S(5e336f17,264a53e7,d0899bf8,6f676440,f83ea0c1,5d53fae4,f19a71f6,998a3ca2,2a86fd9a,8358daac,828d42e7,9c6c0fa5,bf977cfe,56899db3,27ea32fc,cdf09f3d) +,S(98828ad8,a6ee9ca1,37f9ec2f,f0cac84f,5e664e09,68455773,3f8fbab3,ec38570d,ae7ba3cb,e617e9e1,6e67f34,f69af863,3e69c9ca,1f46b182,88126f16,9ec0e548) +,S(d6a7c2b7,169348d5,1d98f0c,27464732,6f67ad5a,4809acb1,6b783fae,36808436,698cc098,ebe430c5,4dc74fe5,dc300f64,7ac0a002,4109e002,d2f43ffe,89fb3d9e) +,S(9bf4a4ea,9fc4b731,5391b653,1d3ad3a0,f0fbaf59,b99f76aa,7807c442,f8e63bef,e69fbade,598fccf4,6f1f0931,f37f3c55,900dcc50,64e54ae4,191796fd,a4791068) +,S(38a09628,aa450076,3826f384,7e63121c,d6e9e645,f6ee0f,8cffb106,508021d0,5460c8df,56fb7d67,992928c7,fd969f95,d29de37c,14c2c9a2,2d60d661,6cb7c383) +,S(dcf8afd8,ee73bc87,c17c97c6,807fd3e6,a9c57a1b,cca058a1,ad24f2c2,6e9728b6,efee9612,3e78cfcf,1dc3132a,fa4ef492,12369710,fa2e8e99,3cc70b48,6ba78709) +,S(9c26ca1b,f52eb7b3,a0d40dc,cf546591,38945c43,41e0c611,40d0662d,1033420f,4bfbeeaa,ece9f2e,e11cc672,24749c3d,e12be6d2,d3d21d90,ed742d,31541ec) +,S(2209194a,6a3b76,1ddb2b1,3bca12f,3697248,4bec29e3,102d7734,9832ae6d,7dde1b85,cd00a08d,38035f68,fdef0576,c458476a,93eddfc7,4bd4927a,cbd64543) +,S(6ffff27c,ce5efa3,a8f8af72,edcfc736,9874abf8,5d15e1f4,cc71a186,9a7a29f0,27a0e163,bcdea297,1abe52a8,a92fe191,38b839f4,67772c83,81504328,fad94a2e) +,S(34e91b7e,e2c5f407,8a9d1ec4,7e2b2c02,1b8480b4,8c3b6e47,19cacc36,b4250382,8d60947a,42d88728,e0d67d2e,e9a0559b,55cf3887,92c733a7,3ed50b25,3706cb82) +,S(3b2de979,9106333a,98504128,e2135e5d,7deae86c,1c921c58,529aff14,12fd62ff,4ba40985,8c5b594d,f4bf5e81,bd7eccc6,3a7bbbaf,fb32926e,9a47503e,f031d86a) +,S(fbd44acd,9e593ac2,12fd1f64,c4e18d31,c3b3fffc,ae1c88c4,6aebaddd,ac608b2e,9f4feb5f,2ab68e29,ca64f458,d162dabc,7a05c552,2e38c4cb,74529e3e,41d805d6) +,S(d21c3321,bb6ba2aa,dc0cd52b,be68716,864ce1f8,44107374,c0481c0d,91729b39,2b51f18,7b95725e,f74deb00,8e9d96f4,f1a9bbb5,c9aa28fb,275f700,bd964566) +,S(ea2d29,f85855db,78808749,9ed79c2c,614406c3,adf64663,8756b60f,16166578,33971e79,39faeedf,15b14607,37fa7112,7d6f49aa,fc423f63,783e808d,1fd10369) +,S(2a1a6709,301ba6ef,c5ad4958,e29fa73a,caea18e9,e01214a9,65291977,8bec874a,56c971a8,d29d6641,9c05fcc9,9b0c0156,a1ebd007,bcab2cec,b9e920fc,85f796b9) +,S(aa870dd5,6434af8a,36d89551,a7109cac,c1d0c5d9,f5e43630,17bba88c,579cfb6e,d1fab1ea,cb5652f3,cd4d5836,82aa3cb,3b1b6854,c0ec1157,41486028,73625dd5) +,S(e979a3bc,5165f53a,60042a1b,11e8062a,e74f35f2,d70aab2d,b250a4a6,f4507507,4de86928,b9dfb2d,8509a1c4,8efdfbd7,a5432933,e3f12789,cd51ed9b,b967ff1e) +,S(620979cd,f37b1cc5,b1fe3e01,f761b8a2,ffc29bfe,8afb7cae,7ded5cd,37f97829,cc971616,6ad43824,4c6be489,7cac0b95,afe5ed6b,11be673f,d67f0d89,6d58f7d8) +,S(90a5df7d,986198fa,70152c7f,e2abc14e,2c80d5e,6b75b42b,aa042e03,f3aa00b3,77e0ad,2f3e1eed,472a543c,3852925b,327e3eb7,aae59030,2d7e12a7,862201d5) +,S(17802140,e10d8be8,ef210b69,b7fa1afc,16a85d9f,ea1150a6,c6e5e234,cf638446,af4982e7,fdcb7a8d,b6478b54,a5bd7cd7,c48d1dbd,2a3d003,7e87b6e,13c9f5f0) +,S(1f2b8d3c,fe515cd2,53f66b0d,59fc51b1,4cf75ac5,d9c7b4e8,4c75d92b,f0380b8,6902b31,19f38b04,5b979f94,cc140481,d4e6f7ad,b3efe12c,4de1bfcb,c71be72a) +,S(aee51eec,9e5dedb2,1619d114,5594ea7b,27e21a4b,37accccc,d5fe522d,2e46d29e,d40ef18,86725504,fca42c2c,b8b80dc2,c1028b71,1bf3fb18,9fdd579d,f7f0ff8a) +,S(40fe6d08,b714ee12,a4d643b4,21b331c4,fbac165b,d7cd88fc,ce35a873,875bed7f,c32f1cd6,3083a976,6b7dd8ee,7133831e,6796709a,c67953d3,4ec5d8df,922d2743) +,S(5425c555,8a6f9068,946f7075,db347e6f,cb6c723f,c5ff829f,1634fb2,13b3c820,c218eba,db4e3ad6,e41a28ba,129a0c1f,8626ae2a,16839b77,ba12257a,a6aa2318) +,S(83663c0e,f024207e,16ba74c5,ca534d37,733a7dfb,b2d531bb,21a28243,d0572a00,2699a48b,dc9af87e,bf18c9a0,929359cc,d7f2f137,b84fc070,2bc3497f,69c83d45) +,S(bf931d61,e72f217c,3b820b63,282f5d4a,c929134,efa06fff,88480f86,f6247535,82553f48,bc40dc42,cb8bb098,ecb84af6,5cb3956a,aae7bd0d,cfa9e181,de93c21a) +,S(1c6e0876,3c2242ab,17e2885a,537bef4,e8920782,9c573d00,64fb83e4,910312c1,b7c14efb,bea753a7,5d8a597c,7f1a716f,8ae4298f,379aa64e,d070ab2c,28e66185) +,S(9a2cf62f,9eb5810c,31b27614,1592f201,1eb158a,3d123610,99af0b77,7d42c0be,159ac59d,728d1c49,843a0207,e47d1cec,7b9b773a,9ddaad52,3ff27d78,d2767d7f) +,S(3596950b,393a56e3,443c3b93,b4f8288a,7faa8d74,d26cab37,dd7a5b4f,6a9e183f,f99bbbdf,c566b3e4,e65dd63a,15c727a4,403cbe85,202e45f4,ea5d3462,173babb7) +,S(6f556cb8,f5da812,24bbe628,6dc4e379,ec12b124,21cd95d8,6bb1d580,a13b5c37,eeee3133,1dc89e57,48fdf10a,1fc0693f,1c09aece,aa27dcbe,919d60f7,4748d656) +,S(b952070f,fe60bf94,cb14bf68,b37e3e54,bd9b8063,ec8cd4d5,20408756,bd318bff,57996eae,d38f066e,cb3f8113,aab5e4f7,f322859e,1fc075cd,69ad1ce4,3fc48ff9) +,S(dbecc166,8d94b2b4,8d37c133,26fffedc,3e690b76,87563677,23352ac,1eddc2a5,f124cd3c,e42f56d8,a7588145,e53931e0,ce8b79ca,ba5195f7,3dd861c9,9027823f) +,S(12dde570,aae95b1c,7cbc2da1,ed2d936,bbfa5155,f61979b3,e67057d1,5fe5e1db,328711a9,c30e4455,e2716e60,3bedf4d9,8fa25d1b,e892ac72,b5be17c2,b25ca311) +,S(64bb18aa,fbfb7def,3493c920,d2faf9c5,57856710,766b0bea,275db46f,f8271282,717c28ed,e9284844,49cd0db7,180cc5fa,20ba79d9,41c979bc,c0a8f274,3e2e2901) +,S(a798f4c9,bb3ef48f,d2ba3df5,2b040611,d0d5532b,9134aa28,e21b5585,d2379ee7,91f903cc,a4628477,b208bdba,59ecd246,bc50be70,34620a44,b55e0e9c,214e563e) +,S(7bfc5902,58f80000,82946c5f,a1a352aa,808fcc59,4bf2ed7f,bc6dad3d,8bab00ed,17b5dde0,3bf6a814,efbed180,3e5f1950,59499cc7,13e727d2,405e0748,2f912cd6) +,S(23bda819,978c9a09,864a1c53,e0fed0d6,ddc18777,b614780a,1c6fe08e,c35a820f,aab57ee2,7d226f88,6e55b8a7,c4d7a245,7badf96c,9312906a,3efe2cfd,3292af5a) +,S(8f649152,54696b2c,1804467b,e1619ba9,d37cd874,88db9418,1259d69e,135e1455,b05b39ff,241ac0c7,7e2fad78,da585b09,c98815e1,b368040,d493bbf1,3ab54ac1) +,S(177ea3c9,e592ca96,e9e0ef4c,87cb00a1,cd51ccb5,1e1d5252,963cfd08,77f30331,57185496,db5e5971,24e55b14,1042ef30,99f206c4,67415318,ccbefdb3,b18cacff) +,S(16042996,9ab25db9,e4ee4231,7497a607,360bb1fc,96e74d66,cd87cab4,44af2f36,1dfa3d9c,c3acaa95,1f7ad037,bea4c20f,c311a8d4,c2ce9cb0,bd30078e,b0ff64ce) +,S(10210453,fae1b545,de76c4a1,4b6ea5b6,172ea157,1fa60696,25753231,2630e29b,ec8aa759,5708f292,72e2ebab,eed6bdaf,955b27a1,469758b8,44c2668c,42acf576) +,S(659574c0,39345165,e35deee5,ab4c3b09,5b873ba1,fa14283d,6bced3f1,d562abc1,1a8b17c1,bbd83037,b20fc2ed,495b890e,526461c7,8f0b8d61,e94a35f1,bac9520a) +,S(a8a00f02,174b4d3b,9ca825ba,88cb1ec4,4c188343,5478a00f,38025a5d,1e2cfe58,fdac00d9,55b6872a,62a36dd1,cf666423,b4dd6b4f,4558cca6,d931a1b1,1e42561f) +,S(3ac8f67e,b4c2c3a8,2cd90fce,f612ec7e,7daa1072,6e4f8da3,57d9ab96,56e30414,15f71b5d,17dece22,a696fbf0,2e360226,bfaf685b,6575fb99,68fd52fe,7a21f9d1) +,S(87c56593,9fc7bce5,650e57d9,37e77642,a1ef510b,dadd117d,2732d316,a4f2ce19,59908fd3,e2b646ea,210606ed,c790851b,4077142c,ec7733f8,613dce61,3431570b) +,S(6531e4a7,f9cbc2f3,f0448bb7,f8250542,6cf5c7b9,d4a1ec6b,80098799,d5e43101,622a2201,f3c0f766,6e81be2f,22f1ea60,f4b45807,6800fae8,c353c283,b6ec3d7) +,S(e2a5b419,cf421b15,859aac6c,9beaefe6,29293f39,3beada53,e1ae567d,9bb7cb34,3c20b681,578aef9b,138f852e,90f49526,6d30f3b1,6ea2d3,23dee943,1af4a5af) +,S(d4e9df61,35cf81d2,21003bc6,e167b6c7,9e912c1c,2dcac775,f7d9d07d,6ffc7334,c8f54f41,513d7bde,3055c7f4,8436c812,898770da,754ed9ac,d6eaddfc,a80f6c21) +,S(b83ec734,10a1989b,988e2bfb,a46a421e,dc3ce47,d549d838,8970102f,98a6943e,4e0274ef,ea2966c5,200dbca,d8090f78,98bc66ea,44164fdb,31507ad1,e7e5db5b) +,S(ec57668e,12f0590b,e99a75c7,82c02ef9,88354f47,522c114d,bbdb9591,238d3eb,2b3c508e,81a3f696,389a5ec5,974a1bac,a572c042,69ad2709,25001215,c58ad7e) +,S(5acca76e,7578cb86,8d5ba7f0,aadfcf40,5ca4cc52,d778712b,785764a1,2afa01bc,7b0df4a4,5e048fae,65a0683b,ea0185ff,f867a578,179c153,5fa93561,54138359) +,S(bd563b91,6419f92c,43a7c2d,7042fa71,fd88e5e8,41115b5e,36a673cc,93de4e07,4ec5b773,b35a5579,b7c729fe,1cde3b32,ca34f97e,83b989b6,fe756597,3cbc840a) +,S(a070b055,839d93be,2b4ca25c,a4a6b133,5ef7d09a,268bce7a,fb1406c6,42e71025,d3fe8577,1241be24,ed209e8e,b5b28ec6,e3a0bf52,27f36036,3a7325c7,5eeb6acb) +,S(9c50323f,c758663,346c5863,84d5aef1,123b4338,eae00ec6,86aef2ed,e19b2f06,1dd9442c,cf588e6,6a3cebd7,bc68f2f,6f270d7b,bf01f088,a49a5ce6,da430229) +,S(90fe8f78,166e3f6c,2d19bd0,685fa2d0,1f6bf06c,2ea220ba,cedb0f22,ac9c558f,826d63c1,60fe3875,9c5887c9,cabe8f93,905fa1a5,e87a8272,670cfaa,ffeeba13) +,S(d2f44fa9,b704491e,69488c44,cc8ccd29,6addc630,2fc66900,1703afd9,a2a5d3b9,2de1d619,247636dd,ce1de2d9,75f14515,ec5807a8,c7c0cc4,5c7d03dc,fc19352b) +,S(17f1ce71,9e3dfefa,106e95e6,62786729,e8ec2bf6,25421ede,ca71ca14,5782b23a,62b51d27,74f514cb,5452cd29,e3907a7b,b39a9b9e,400d78bb,f6cca78f,cfc1aec5) +,S(5b1dcad4,5974f0ee,e99d7c23,83e48585,24428c94,daa956af,cd692c4d,5a63213f,6958ca48,f13e31aa,c52e531f,886da246,5ba713d4,748cf6e0,de16e0a0,366c33b4) +,S(ad284e67,a0682585,f18be40f,e966b605,8cc787be,c265606d,12f202e9,31f3067,c86ce860,ac3c3955,28321cb2,508e4da5,abb4dcfd,2844b95b,ede54ce5,b17e45b9) +,S(9ba71712,dee6f0a2,7352cfad,59f6c0ff,f133b1b1,37ecf884,a537b672,a4275c8c,b910f036,f906a419,21fd37d5,5e0273a5,332edf68,43dd8afa,43070542,b0849b40) +,S(cfc757d5,171c9d6a,ed8b9123,a2b4a405,d8e869fe,e80aebd,75255454,ee6319a9,43dc370a,c2eb8fb4,4f78940e,b41d614c,ccf2cd7c,c4f324a7,92ba37bc,7e48144e) +,S(b8288ec3,2e4a569,27df3e13,6e81498a,bc9a52af,80d74bd6,c85eead8,85e0c49d,a0d53c40,d2234ac2,df69605b,1422bd1e,4a1d77db,fb0d7269,13de63bc,a2f96078) +,S(3808cddc,497c9065,cec574e1,3b82a10,fe2323f6,65a99df,1e724221,3eeb9a79,eb046225,eb6aeac9,5659f1fe,75dd910d,2932cab6,9b4b810a,d83e7681,e0c32907) +,S(a1620bae,cc99c311,7b3889b4,7bca5d99,4ecfd67a,ad5a7461,646e55a5,19e46398,5cc4b5d2,edc5f7a8,54cc3054,1c7ec571,e06c59a,52bb5cf5,5882ec18,1b07c0fb) +,S(f1d942b2,bff74aa7,1f9cb411,91ee85d,e6955802,4a4d46eb,53ac02d1,32fefa93,19a564a2,8352bc48,a8dcd932,50274bd6,496cf488,6e2ba390,3cf91631,453f57ad) +,S(1a4e3836,a34db30,c47ed6d5,9ba6fb83,fcb7a5a,a0002ad7,1b93b154,a5fd566a,745e195f,d94900b0,aee3c5f8,7c6fc62e,fdddc18b,984900c4,20c77ba5,4141cff5) +,S(af37075f,866d7aa5,9371a08c,1e7aaa5c,d23ee51f,54428fb6,84c09b27,93b432,b32e8869,fbe53ef5,4250e803,facc93ff,a100a84,becaec5f,872d0548,da4ae9ad) +,S(88e39f4e,83a0d6ad,a1e01ac8,9021a7ea,fdd1f9de,740bc10a,4d572c46,fcee9330,a14f6881,bfaf691a,96249322,37522174,e8a17920,52da7bec,a6c77d4,5fb8a357) +,S(8e406574,a46e56a4,dd4cf780,9a7ecfad,5a1f9225,cfc2fbdc,6b7bfc84,a5ce14fd,bdc6108e,d5616bc2,3ed52c5a,1314642e,a9272707,20f00be9,62e48945,3550f167) +,S(aa31e1fc,118e00c9,8b8f561c,479c6427,8676356c,640304a8,3b687a34,8ad4a091,31c95ccc,2520c0db,7c7440ac,7e640be0,7a8ba4d9,c0020b1b,f31418fc,98d9eb17) +,S(ef278702,becf4f15,ad43fb6d,d0114077,d9f8bdc3,ff4c78d4,d0a2a15,8fe160b,377dcf3a,774d6416,58bf108a,87201b9f,f28c70fd,449a77f3,966ff441,d89246e1) +,S(d1903199,b9762761,fd02c4da,99fcc503,ac15332f,4be01b7f,a044c5c3,f848ebc7,662ca3d5,9ff2c5fe,a75ad64a,f7044a94,60abbc25,defd0a3,aa6b0e6f,2c7f4f3d) +,S(682ffe36,6838fa12,827ae055,7e38c12a,bb571227,47643f26,9cb9f1bc,922b07ab,4531b021,2e8fad86,6f6f67fb,d8eac752,1a360968,f0f9792c,a4568a55,855924e5) +,S(418fa3e0,b32be1f3,f06b96d9,728aeac3,3294ea8f,16f35139,76b30801,81d8e833,dc1608cb,68bb0480,859c9983,6baf9558,9451022e,b9966e0f,498245e0,2183ef80) +,S(e3f7dd7c,f5898b7b,174cd809,5c7c0890,4188bce4,bd6487ab,e974d979,f7faec2d,5ed5ca26,77d3bce0,15a6cb51,9922a55e,9ac1adc0,61bb0774,503e79e8,204441ea) +,S(810ecbe4,f43814f4,e658ce9,234d71b3,946556d7,2ba9c3f3,6fa04b,4dc25cf9,5fc57520,81397434,e395a752,560a8a76,252e6eea,b9ec067a,16befea4,1f1bf1ca) +,S(6dc50f0d,7e9518ab,fa16bcdb,f43ecb2f,745d5ee4,7269225e,36811819,6542b7ff,dfd5e416,2d596f5,b44602c2,20a87cfb,77473aca,6dde260f,856b3295,527bb87c) +,S(d39c9858,5ba2a859,a6fac25d,602c8e1,fb205a88,7aaf628f,5d1a210c,bc648fb5,6e92fc09,9df932e5,1bd0c6bd,5b6567f,61a1e8c3,93d69add,111e9320,661ad724) +,S(d7fd8580,59c1a86f,1b81c05b,ee63bda6,8ca93c4e,5ec99e91,88d9c7f4,40dae0d6,ceb56f19,cb3e5b39,64a4c58b,5cbeddcb,c736f0a1,8a2f8f3f,f0758f24,525a8fda) +,S(2e269d93,319a79d7,513e6f73,918638df,c4b1b7c,4c19ec83,b254d780,dc45fa87,650b6846,4e8537af,583cfc48,caaff61d,f31dc67d,5a48e0f8,5857d7c0,9bea1d70) +,S(19f396b7,7147937e,bef30096,44b292,2a6e3c6,5b5c929,22b73118,7120224,4751cc23,4d49e926,651a9a29,c2a8a55a,f7e4b25d,9cb4bd2e,83530bdf,494b131d) +,S(88f843b4,e3689ba0,264d6d4b,4d310afd,85de2ea1,6fbe7275,d33112c7,538a7c02,5dba8024,30d31ef1,412f2310,3ccc5951,66e903a,55bb2a35,8be1e715,27fe45eb) +,S(b1301f5e,1474083b,3828ba5a,837efc44,21990da5,275f6b1e,bf773b52,5ef14a1b,f9fa0af5,b508ca7f,2345d06c,5bf1e5e4,907f2b19,3681837a,802259e7,7208864) +,S(63bb3295,b57ac21c,4b96ae49,92b8f3c5,7c23743d,44ba348,195c5f58,d5360bb,f5e6a98,96683293,af6b9ded,f9f163ba,15b44017,120c61bc,c9e51758,f3ac793) +,S(dac9f722,7d0c012e,e3e1ce88,a99cddeb,9a23979,14c1cf1b,915dd41b,8ce27687,85bd90b7,7f2917c,cf1ebd47,3bfe04df,386d37de,69893cc6,9e79ae89,2255a12b) +,S(ef05aacc,a8082759,33719aa0,e0958f6e,4be6a6c2,3458f243,f84fb2df,9aa422f0,d6006b80,bf611afd,3f1ed523,988b3e8f,d44be73d,565ef30d,911e4226,ae546f23) +,S(dedf3d9c,807065ad,8c1e3714,f682ff86,4f6ae08d,6bc15773,53f27677,ff86783e,7bf6f3f,1f3e5ca6,6902639c,a0b071d9,50dc2331,52f1b47b,5c68923,9a1cccc6) +,S(3db2b461,d18b367f,cbb4aae0,7a73ce9,6c1b4cbe,140099f4,d3839764,7414b5da,515ead0b,a8ba7b25,9f04484a,4c55b532,5686b882,77562b99,21827706,a036a142) +,S(5516a03,3da8cc3e,28170010,5e8d57f3,daf5bb84,596c040a,3d2ae05b,41cecd4f,6bf44084,f0ad14a1,f129a267,e13b0717,6d2fd274,2d4be75a,2192e54,7ceeebf1) +,S(7bd86d5e,6fa18e26,cb0b6e2d,faf2a4d6,a784e831,2e7168bb,8e660e3d,92514c3c,9b634094,dcf4ade0,eb49eabb,a26334f1,7770bb94,b776de46,64d847fb,f1574afc) +,S(a24a8b40,d63c242c,3dcd2513,fbee3c04,cc15117e,aae40daf,b39c3373,e6a83bfe,49163714,afef59b3,b503eb73,ee091349,e599c563,bac4aa37,13d7a6d,6f5271a3) +,S(acbbcaec,8b01374b,454208a5,19051ebd,e5128307,785f7b25,706642f7,775a932b,102283d8,1bd1e9e7,e5641b8d,a701f51c,86047d76,51becfba,89478d8a,a6226572) +,S(efd5654,8f37a094,19f9fc11,6d818523,c4d76725,860d49e4,a1cd8434,a0cfda99,d521204b,da2b9db5,dfa47c9c,6ae4616a,52b3caad,5440e4f7,f1fc41ba,766bc180) +,S(15600bf3,ffca622,a163244f,47789725,b4c112b6,e3d7652f,fe829a6e,386041c3,b1a1ddb3,e2b0e170,8cc9e6db,13c7b111,93673cc8,397d9b59,5b4e8dea,a39cc5f7) +,S(8d14cebc,62f7cd8d,fc60c2de,d144c76f,55d9d6c1,be5380ca,1e1ecefc,5a85cc53,244bdd67,5030a8ec,af876f5,99a34f98,ef7388cf,e6705734,540f57f4,15641220) +,S(e3cb7328,29c6d09f,6ee940f6,5f30c79,7dbbc26b,b8b8c860,f6e07088,a485ebaa,e50a5c44,6768827d,ddd57e18,68064e61,51c8951e,e4cd920b,b664ca06,67096db0) +,S(9a18212d,45364ebd,3ecf4d76,3efcc66a,ebd17b7a,f8bb7f65,8679664e,16888e47,85297209,abebf492,ebeca275,bdf3bd2f,987d1e29,6bcee299,9d6e59e9,2b890143) +,S(43366191,859bb3bd,5b44f1a,d9076ec9,5439c082,c99f70d7,4363117,8020521b,9dd6d890,16666a3e,6bd8c0dc,76cc9792,fe5d76b8,c49cf9e3,75e031c8,bfae2556) +,S(1b77e51c,b11e514,29955ae2,37659c5b,a8050ddb,685e5b74,fbe38506,33bf9358,f198ea65,1ed4a743,a14fb905,fd0bfefd,843bb00d,675781de,5fb1552f,c7f382cd) +,S(7cc6fcc5,558cc6b7,156a62d2,e823631,e0b95e8c,57fb79d4,b4aa3ff4,9cb718cb,526becaa,c0c84e61,b3fc85f,60d028d2,eb90567e,319bd6f4,12b1a36b,9c3d30ac) +,S(18c1e51e,10a7dc5f,7783d511,6f2c0457,664ca2eb,6541ff29,591ee59b,f9f958cf,7f72840e,ccf4d03f,29ce01a6,725f6b97,d701a935,bce8a2b3,c1e44904,cf98a300) +,S(3b9335fb,b191bc9d,17efec98,77960307,2648edb7,2c427521,34df37b6,f1620c44,ca526125,8239c80a,1ae893b,268d28c2,b02d56f2,d03a8a7b,aca25def,34d6d694) +,S(f39660c7,ba9bf800,381b8ddb,d783dc6,acf8c183,95f9144f,688db8c9,9d7874f4,c5037625,2abd41f9,7574a607,52be4c31,e5ef2874,5e9d80a8,da2ea676,4bce5cc1) +,S(d1d2872e,ee06a4b5,d3b735b1,9db1d88e,cbbf9ba6,89c1e411,980b2cde,e70c86d6,dc5cd630,859fb9da,70f25023,5b7bf2ec,938743a,a9f04fd0,69d1d746,e3ebbfef) +,S(aa4f71b4,720f6470,8b6261a1,ee97bc7c,ee85b274,caf71a6a,1f7f000a,b06a1948,958fa65f,acdc42f6,c1e98f7d,f67ccc39,14dc5e8,d20bb872,32d7c898,e451c017) +,S(85904824,63e69633,42cd1e89,1502c309,d74e1722,fad8e766,d7e8f566,49bb732e,585601b5,5bfef406,ec5f71bb,6bae29c3,c5e77247,befbb549,5ced52a6,da64a2ff) +,S(dc899ab4,89a12ac4,4152ef63,48553ed8,29855449,c204327b,bcce6418,75df4d99,6791a965,65fb749c,44f133d4,b3c9c8d,77488831,c8a99ba9,7b66c9b,43deddb2) +,S(2fd60f25,3e0b4f1f,2589a096,f9a0ea3a,405906c2,690fce35,ac7df791,f106020d,872d52b0,1cbfc3b0,ff699950,5be33b51,64a7054,bb00e22a,9a87d692,dccbe782) +,S(a74830c1,7f816549,cd617b94,c0360b8c,9206b382,6782d351,650785a7,fb71212c,fa928b97,75b28be7,4e340cac,eabf866c,fe7e7299,7c276680,2d211b1b,389823b6) +,S(fd450d48,c59fc4db,e3366b43,caf00c2,bd10045,842311ab,20f8e24c,6a9a10b7,512d1998,db747e39,34451fb7,9aaed7af,48801051,dc8ef756,4580db9f,bad910d) +,S(c0816923,9f2bbbc7,34d52def,79f9f4bd,cbd8c435,d90561ba,fb23f12,f1fcb93,fa00c81a,8c5cc2d3,5f78f0d2,475851f1,73f70cbd,cf2c950,8ebad1ee,b35a0852) +,S(247c4075,9a0e7098,25a5d82,4fad3419,55103052,bcdc7ab,fe4e559c,84a04a66,8da3cae,878260ba,1b95a5db,900f20c,12597187,4191cf21,939ab6c7,fe378067) +,S(fbe3b30f,16ad6608,32f9ab15,2f44076,2f7a09a0,b07b12b6,4375db15,37fa4e9c,98cf3e68,2a914c3a,ee54971a,793a9309,8c63aab3,e2db5389,3f05450d,61b9080f) +,S(79f71ab6,fce86bad,be02055c,520e6e0d,88e98def,d37f2d2e,488bf455,3ec954c1,b5de6a0b,c1745341,3023a650,45262a31,e9264089,8a655b0a,4b3042d3,a9114330) +,S(d190f258,e2e3bb8e,6812da59,606f2f4a,2e3fd1ec,34e2c80a,9d280f5e,e1e9c4cd,98997b49,afec7d7a,26a26f50,9d4948c9,b5ebf9b4,3eef6183,3a2b7a8,6183c267) +,S(24f355ca,c0e00545,f47e199c,3818e76f,534eca88,776ff6e2,54244686,24f0b636,37710da6,5c3afbb4,308d5906,7ad044c1,4df30f03,427ac83c,23b829f5,37d25b46) +,S(bd221461,ae73e639,6b23d269,ed6907ba,330544d0,80342de3,a769d3cc,668cf536,a5f25513,3967fa67,b22dbe31,917d9d1b,ae11a1d9,dc7ab731,26e8f0e2,fbc8deda) +,S(cf0371e7,22194be7,ac5d19c1,1b447978,b38f8a1b,dc1dc3e2,471d4a8f,75d0f6cc,4bb04426,94fe9d55,cc49dd4e,e168b604,564b95f5,99566f3b,9fe2fbdf,16084f1e) +,S(ce21a5e0,287752fd,ae9e04ef,363540ed,f6736c34,266a2d77,b5d0bb5a,868fc32a,fc30fc93,bb5a2731,8b81b942,4fe330d1,878e710e,b9a44fa7,bf4cbfa7,10c7d0dd) +,S(7c95d800,da4720a4,102de774,d585f230,2b849e57,1f42982f,a785bd15,334b4b12,244deb56,fa5b4367,2c39693a,f09083f9,2b153a9d,4829ab3f,ff604fed,a266b30b) +,S(40bce9b4,f90489f4,d392fb93,3f98f71,e9281976,164b25b1,982cfcfe,338d93e2,5a9ebed7,25bf11e8,7bbec766,c52309d5,e2036454,447b8ee6,6dc79dac,7a2a9b4) +,S(f15a2ed8,2c00ed9b,9e7a9338,2d08c46b,33ba7bb5,dc15f5df,4cc29fdb,86f11c4,d02ce92c,e556287a,3acd4115,a190767d,2979dd7c,7a32dfde,cb6d806f,6e7d0205) +,S(4230d263,d5a4a915,cfd863c0,e38514b0,4929d352,d8a90c00,c0ab9ee0,56215932,4b134eb0,51699656,dedc7704,3d5586c1,62134b00,e21ab1b4,517bdc54,5f05fd69) +,S(6cd6bfa9,63327c26,fd2c7aa4,fc159956,1a90096c,dc88f414,d5cc9c64,df6a9e84,6741fda,1f774c52,20b04db1,9ba7402d,9b77eaf5,b8e9e2bd,a000d2df,2022565c) +,S(118face3,ab188a36,581cd1ce,1d434fdb,f1d06f50,1e9a64be,bfed2ea4,ba3f477b,a263037e,c8d5a9eb,be1a8b97,bbfa5624,ce00e852,44828af9,8cfc38ee,1da9052d) +,S(6be81e79,5fd1229a,fb24a395,fccfbb6a,ae4fda11,28f93faa,f74bfb76,c39794c7,edd0f9ae,bbbaaf0e,bd1c01f,af128730,5d5fc5c7,732885eb,327eb21f,62683869) +,S(b9a0023b,6fcbb06a,48f97684,509b8b9b,937f990e,4c3f1a61,27a8a18e,e4c96c3c,e1b25ce1,3e8bda89,ea631d71,4c07adfd,c31fc6b7,304b5e7f,1cc7221a,6597df11) +,S(4e384b06,ee4007e8,e70f22a6,1af73d89,4528722b,cf58bfa1,16eaa29f,e1f2334,2fa6ecd4,8faeedb6,240db0d1,14c7eb3e,63540e31,788f5f55,98c52fd2,538ef0d) +,S(14c8267b,6462dbfb,6ad45cff,58d9b22e,9fb0de4e,3d026999,9357acc4,d254ea52,86da149d,e14de86a,20becddd,e33e99cd,158a50aa,2da085c3,cf675eac,224b292d) +,S(42d0c7fc,21129bdc,97318985,73b6d111,568005b5,cbabcf55,c1828340,4f5de376,8f83e957,92880a3f,dac6738,e65ea463,1399daa4,defbd1e9,41a5586d,a42f652) +,S(bfb03349,2fc28eb,82bdf9b4,417f02ee,f93588a5,b138c520,77250499,23e9f135,c65872e6,9438a5e7,a20c3492,7a3de7d,85c690c8,b20af801,915585d1,98184882) +,S(1a111410,d04e1278,3cded32,b3602007,7dedfa32,6493a780,999c68a1,dee18047,874723b4,c6b63cbd,d957098f,d0124779,3e711a56,fcb8499a,a046f5d6,36d5be75) +,S(a47aa995,3a999aed,9c1d1f77,da8b736e,6d045d3f,9b32ecf,a6bd4225,fa66cf6e,c4ae1566,4da8e033,f0e3fbbe,472e16e0,70a4b40d,f210f7,3d0a6fe9,3dea782d) +,S(52ccf2b4,5cd2555d,5a0a5765,92b5ca7f,5ffa329b,6bb12979,8f2c10d4,bdf34119,92abe502,d23e9f61,f420e4a5,44e42864,2462dd0d,7d7f386f,ff7cf2b0,b3a5043f) +,S(5d2af6df,77107953,e6221a4a,ccecadf0,a2a8d676,5e720d2e,38c386a3,e6b48e4,5a44be69,80ca8082,5d435aec,34db8be4,6dbd05e9,9b8fa176,45888bd4,2260cfaf) +,S(e0f9b457,e184de7e,7484ad3a,dff4adbc,4dfe508c,14341dd9,d2c4f584,807e3fba,d0712e1,3bc4ad8c,78261681,3d00a237,36383731,7de79d0b,1f52264b,6ea70526) +,S(6797c2e1,d1c2643e,a831372a,abf36ab5,fcf88804,9a01f052,a7930792,acd2a7a4,ab005587,69f8d361,2217de,8d4bf205,925bde,7817e97f,d155fa94,8f084167) +,S(f302e07a,8953b3c1,f0b3796b,55bdf133,84809aa7,3dfe4fde,a0d56ae7,a04c2f26,339d529a,a6c0c8cf,f46682b9,c36390d8,28b2861d,6f4906dd,a4659028,c74d780a) +,S(aa4c04f,b8261965,9254f9b3,2d9e25cc,ec651f79,b710cc3d,bdf4eb3c,dfc207d8,520cbe2a,c8c0382a,23d2cea6,6a18f28,bb87e773,6bf60dc1,cca64a58,9fda48db) +,S(cc4bbc6e,7f4b02b5,ebe6d484,6352257,4651fed1,a079767b,fa53d1e0,dc38b5b9,4be5e0de,c97683d4,939077d1,edffcf6,dee4a88f,f7d42894,c3d50302,70c9554d) +,S(6a4bada6,cf1e123c,e80fcf83,2d6934f5,486901f1,6d3ad0af,cc87a4cf,205e6e79,b79145f8,24d693b3,832c6676,e35a73b8,d8acddf1,681720f6,c8d5ac7,f81752fb) +,S(d7ec4d61,1d440625,367b2c5f,a6904b8d,cf6f0d81,39cc3bc,16299e1b,50c9024c,18c402c6,3e818647,7f15bdb6,d514373c,89d1f7ff,bdab83f3,5267eb0c,daa81d89) +,S(4e21e4fa,4b570b40,77ff6876,a1d7e4ed,1db77d0f,56d35445,178ff508,5b197169,dab19080,ef84f0c8,4919d869,36de1aa3,ca85a1c0,aabe902f,b46b31b0,3b350580) +,S(32aa04b7,53752059,7b4ef603,62aa208a,effa6891,240a587c,e1cae58a,28a6075f,ca649475,a58a3ebd,c3802c13,f006335a,7d203ddc,88bbd1fa,f0787839,b9452f21) +,S(306bcc2b,94214994,e86c7fed,4f510ad7,9eb1af11,b824d897,a1cc7564,9eaafe0a,820c2986,abf17343,35089773,5b4da35c,56265a25,4a768346,5dc084aa,ecae6dcf) +,S(37d23716,1044ed4,b395b044,5d70eaaf,864530a7,fd8490c1,fe2d1ea5,61f4bc19,a6a9da7,70558993,ce38d5d4,c69dd25d,134f37f,c28dddef,2e7edc0,c1343b83) +,S(1f324230,886ef594,aecbe39,2d7a4434,fbb9fefa,fe22573e,9302d3c,dc81490f,39e53099,f25e977e,da860f77,6d09338b,c0e75446,42557c8c,b05761a7,c18537fa) +,S(256d4808,d6dd018d,392a6716,2af909f0,51bfeea0,9ce22a76,6266d1e7,61df967,d5643938,c7d9163b,38fc8072,609bcbf3,e063d78e,10cb8cee,32c00abc,6341df09) +,S(58a91493,ff7aa600,1f457506,624ce8ee,b1c142ca,d49f67f1,be099c58,3a7934f4,bde8d64a,79d5722d,6a96d240,897a7f48,8e20f19f,259fc6a1,e4483448,e0290122) +,S(b4a80e5d,eec9391,8f146b4b,e0d91630,606a5c79,1c4b7b87,d4363de6,e2691f2e,a6ff5b82,ca6fa424,efc00b20,7ea90991,fcd5af15,d23140ab,96da6cc8,bd532297) +,S(41bca570,b4981232,f21ba765,4f23d5ac,27f3bab6,9f1107fa,e3dc5102,6f8dafad,5a14cd59,9b0bb884,10ed1475,8445c49,3af3b7c9,2cc6435c,5560c4d7,832709db) +,S(bcff28e0,bb6c242,a7805142,122848ec,6951940,bb4a2e3,5ae05137,d73e8264,43661933,9ff9f2e8,278ef17,329682be,aa801596,e4a12b0e,615fbe7c,4b24e1aa) +,S(8aaa2f44,fbf66c2b,809180,bdbb4e2b,e25ff178,232fcaa5,a2c2563,8c1ea21c,69dc0de1,686bffad,1ceee711,95831b90,c57900a9,baf57ac,2f34a917,6d33e21f) +,S(930a3df,f84583b0,ced82f81,96c39c16,b9318f2b,44efde12,2be6c10c,70b33dc9,ae802936,2b10029a,a81cfc47,1251ffc3,6b586de,da9c1754,4a96d3ec,31cd6d1) +,S(907cf1c1,92b98461,8021a33d,1c9d22e3,22dc83ab,d5768a39,c04444bf,d4e76df2,527eb629,ca0a2e2,7da96361,ee727a34,97edb8c8,68694871,6a7dcca5,13b6f901) +,S(f9d32e84,76c666f6,29e86e0d,3804eee8,abe1ab26,ae2eb396,b584e4eb,e9583b88,d92f265e,9e6c5f4b,bc05a432,6fafeace,1516f823,3e5dc280,b239fa6c,bfdf7fb3) +,S(94772c31,70e50bbd,9952bc69,44e0007f,3d928cb2,c86465b2,ef040fa1,b4f90d9e,29021913,9326e358,2cfa8ee2,428c4307,86cb2de9,6ea2c735,eb71f759,bab14637) +,S(2b49cd38,8cec8c30,e984d40b,f1409c6f,df7ff24d,36cb699b,5f3c24c0,fcc872fb,9e65a427,ce5dcc20,db83a96b,720f29fd,df643b2b,a192736d,c621d92a,6583aa8) +,S(454f174d,8c344479,9bb58158,423d8413,ce87def9,2fd25a,5164807c,982d84e9,bf324810,d9894da6,1eb1e3cc,5a30639d,6500a453,c14e8a40,78353d42,7ac67ee1) +,S(df4461b1,dc1eaae8,5b4b7fe1,e87753e5,546f48f,e39da02f,f1012b24,58a79a17,ac4fd2bc,af8e0b51,48cc5a5d,46373209,8993b377,becd718,732fa339,95412fda) +,S(32973a0,d1be4c6d,1342b2a1,44ffb36b,81fd9b38,c0b7411a,65b8ccab,cda9161e,558b278b,f507b498,fdbbf73b,524c4652,53a0082b,d53a87f0,75d5a49a,bb601b69) +,S(cb63a9f2,d1a11b08,479275f,e1f0bc64,37126875,5bcd8a21,3481be2c,818c69d6,4949d3dd,a31db2b7,b2d42f2b,4709a870,5094d470,1e742f07,b6f86670,e43bfaa6) +,S(543ae5d,a0c271b8,41542353,277e1651,b7b0f587,a5b18ed2,856c2e07,41c28914,22c999cf,aba6f95b,21f87ab8,2f2edb2a,3dbb43a6,ff413506,83835ae8,bbcd0a37) +,S(7ffa63ef,3df62097,a3b61289,4eaf5bf7,4fb39ad2,9ec63f02,2c6f310e,77268c7e,9d26cd72,8fcbfe54,6eda19db,5ac61978,1b456699,59a21628,2500e5f5,389679ca) +,S(72cc6606,b02943a,5bd9a476,6b24caf4,e0e2f83,ae3bf671,5f05b39e,3436122b,f35ff21a,39503637,d05b744a,77797565,1e290541,326d920b,d5bcbb6f,74b56c3a) +,S(f5f21182,de67c3eb,396055f6,a8f64f5e,54043376,cdce9f3,3cffa601,4a348a4c,1fe09f94,8ad7f78,6c184675,3105cbd2,e0f8be91,f9160e81,9201fed3,3208b3c7) +,S(1cfa62a3,70171431,52fe149f,db07b00f,bd8d7928,e5eb145f,b4ff7343,fc19437a,1efe47f,e41677bd,337451b3,92eddb1c,ecfc19d0,5ef04727,12927d4c,77b2a742) +,S(b6609139,733864d3,abbdb6bf,4b827b2,3861594f,ce9e996,4637ef14,f0fb6849,2e807df,ae409cef,b7be1ffe,63351d8d,8de5fbeb,f3be5069,31befc97,d479c006) +,S(13da7c85,bffeaa0f,e295ce6,38de0b05,1b4aaf9b,d888f5c5,5f74fd60,abf2e016,c0477fad,fba6531e,f6369aaa,be663871,3bd6954a,d1e5df1,269c7208,31cd5bc3) +,S(2abda634,547a86aa,1188b2f6,ffaffb36,dd126d94,18406bed,8b81e29f,596526a0,7db36141,2e96e02c,34c0e39e,1201617f,2a7f2100,d5c3cf64,6dcbe563,e2b25524) +,S(4e161f2e,22785c68,3ac494d4,1e3cc2d5,e6b87be8,bd65e85,8aa255dc,8ea8fba0,c81a4e95,a2cfa101,fcb62112,b60c574c,623b5df6,5a1fcf51,e6bf2936,45d5f17b) +,S(586be2b5,740b0ed6,6f5c5f6f,217766e,ad5543eb,8e983ffb,928fc40,9e76397a,f11acf99,8bc2a25,48799529,9c7ea84d,98c6a525,6cbca56c,3ad534f9,26c6b08e) +,S(a76c4f91,1d0dcd58,9417fca9,8124f62e,789e0b05,91a9ce94,13e0b7d,e7d5986f,6a49fc1e,2b32aeaf,6f291184,3995602f,903c8d76,858fc532,9b3a1940,2c2c9b7c) +,S(15f11b1e,804a6d54,a496ee4f,f3030167,eb510e9c,c1754bd1,d46beace,1211a68c,f8968e8d,21bca271,75a79de5,31ad810,ca6c6da7,72ff96f9,937ef824,8f4fec45) +,S(f0169f41,685292bb,4ac93afd,58b2c239,3985ecd5,16acc8ed,ce46f325,74b23e58,6fbd711e,fd488c8b,43151ecf,e3a42ad6,25697053,1df18afb,68f8ad71,ee9aa05e) +,S(2f241e5e,2596d32b,6cdedc4e,b6de5f53,374e358d,8db78d08,9e772b37,6250f359,fe79f0a0,cdbef5a2,7287c86f,afbe917e,4c26c4ca,512f57e4,ab066d3a,3f7e71e) +,S(a14743eb,92bdf49f,5f404a54,ab193100,26f3fbd6,fc5a06e3,e8c6b33d,1f7a5559,3e7e5f24,b1d0425c,ee5c56ef,1e38098c,6d67fd12,f57eb2fb,1ee76c57,41d57c54) +,S(2d097299,db14ce88,8da72472,da686f67,b8ecc812,5618cae9,2acf6457,a011d2a9,e9cf7195,32f71130,5bae1fd4,ce3a8fb3,c8d71088,df35b49d,ad9c16d8,8734a187) +,S(aa7257f0,d7e51fbd,95598b7a,a994fac1,41aa76d6,318cbda0,20d30471,73317f2b,15e00f94,f684c30b,5cd4a978,c6245e6,8d30d959,a30fb39,834e97d8,c18a1b27) +,S(ae524618,e2877095,d52ffc94,67a081e8,b27b4b16,566e2b37,c8d11b1f,1f7416a0,d0275a1f,6d49a7c9,44a07a6b,ee5d5095,7b22b698,2607f822,8ad15253,a546ccb0) +,S(e7a85ef,ff8b0443,eace4cd8,81d768ba,ef4d93b9,79b17eae,fd237e8f,c9ff660f,4b53f073,8f07b360,7d66f720,b1222df3,eee2dd,ca20f40c,630a7911,a0fe2aa6) +,S(daa96eca,b8412eba,75f58a80,84a302a6,37dd7d77,bc9dc502,a2d083f8,35bf242e,ac3dfd97,a01557af,cd1f199c,afea0cce,52c8e3d4,975cb331,1c817c9,fab0815e) +,S(34dec21a,965b7027,44fa7881,4ff6f782,790d551b,7be35c,18cd46b2,e189baca,ee825c5c,5cc289b9,d7f01b43,4de4f0d,d250f9cf,c22c8d20,a1e54175,9bd23694) +,S(dc2178c1,2f015bee,829f0567,566d15e4,d607c8f3,b2992801,4b6a5607,1e61247d,fc86780e,31cf57ff,5da387d1,c3c25a19,36a263d,f6571de1,d098153a,97b41db8) +,S(6faee1e9,354bebe0,1fb65158,20b7e992,9517cb40,23d49d19,2a002ba4,e4782db4,a4915992,ceb8813b,e2778fb0,47766b6d,3958cf72,f18e9172,3f74cef0,1d2276a) +,S(a2bcc012,4112818e,571c8dae,3cb724dd,e45faa06,d04d7128,e9a71dce,22f300ca,1f594d9c,64ba43bc,11764c61,f8fef5c2,e31fda39,3447e7d2,10d004bb,c13870e3) +,S(b8cba39a,c51d86e7,d83a50af,f5370240,cd7b20f3,81aeb799,f951883f,458ead76,3a8bfe74,2b3a05be,27ef835,39988cc4,616365fa,e3738d35,29f9c0d1,c15eed4d) +,S(56e532dd,295792a6,ede9da94,c43e0b2a,25b72725,333f8205,7a352ac9,7a1991d3,a617e234,18bfdccc,8facb454,649a4914,2f0abd64,f30e06dc,838fd80d,7a141fc3) +,S(4803406c,e4049575,19f5306d,6daa003d,2aeddc1f,c1d4db45,15a8d35c,aa39a6d6,7add51c,12412f4,49d7b0e4,b7df38a4,83151126,49660956,da6273ef,8b53fd5e) +,S(bd61ad65,2e44effe,ca39620,2f84e4d5,d81cc579,2a2390f6,52409852,cd79c459,f3d7071b,8bb18928,1d827f71,ab7b1ad,5289033,ab28d20d,643af02f,a2b4ce5c) +,S(1b543175,e5b6f271,58048588,f81a791b,3ab216a3,578e2f79,354da6c9,5e4ea9bf,67a2e60b,321456b8,5b5499ca,e33cd6a6,d5445f91,eadb5a5a,f0e2164f,324417d7) +,S(2035953d,3319ffa5,9f75d86a,8d1b52c0,e8118ec4,d830d15e,d9616215,cb82d080,302cc0d8,5bc1e667,b160bc8a,64cc3bb8,763066a5,6652a0bc,c12691be,c41d7aa4) +,S(bf2a9739,f65bebbc,90413f9f,d311e095,e7628dcd,d76d25a9,8a4681ef,f4f84035,83932d07,cc950bcf,380cea81,28e04322,26b9a4bf,8536122b,fd055517,e7d3b2b7) +,S(a915504a,bb62b4a8,1288c44,8605e8ab,bafb4f0a,ffbcef23,c9c2a26f,f2cb8557,2fec1059,abe1bf4a,834c50c1,edf0e5a6,2ef21f7f,9da2fda,20989bae,18acd442) +,S(318939cc,fb2eb0f8,30d30079,7e209f00,6e28b899,8aecb548,b3b97900,9ea6aab7,5308df9d,10c7d151,cbcbe417,91b627ad,b7204db4,dbd2e01a,c5698e61,bdbda375) +,S(ff9e4851,d3f0c9cd,818facdf,4781cecb,7f622039,c23e236a,7e4b7368,64af1a8b,fd69f241,bac1c6b9,a52d6dd0,6e7bcb6,4a4a79a4,9c3881be,6ef8c83d,3f462c5e) +,S(497113be,a88d4888,2c98ac14,ba0bd0aa,d3c75c8a,58d374cc,86a7fd0a,b6259cc5,9029d9bb,96076d69,a264d2bb,6fea2f15,423ff1f6,ff47c02d,4699943c,9cbfbc4e) +,S(2b2cdb82,6653f563,dfc4c373,96d738e8,3d1dcc5a,ec5f4886,2d5ca84c,2ba69103,d1985cb3,f42e4ae1,7da33b7f,f8563236,6e2f5c89,b849ac73,afc3a7a8,1d049d85) +,S(c55dcffe,fe63e948,af77c8c8,32cb6c0a,c09ced5,5c338bef,fc27fd21,dc63b6c8,edef9fcd,b00fb62f,cc97c03f,26253069,de6f8d00,c13a5666,f574feb7,fabcab6a) +,S(52a0dbfd,371bcfb0,e2c69160,c9cca2b7,8dcf679f,774c9d99,706d306a,30eeb3c8,fe01f320,781275bc,a6c031e6,d71df467,56473d8a,780fc54a,6f8eb1ae,5640bf65) +,S(75c4ace7,6bb32bac,13141f21,615e11e,7608fda9,cba4723,9eb6bb8f,349a9e86,7fde50af,19506ba4,65d49b93,c8884478,dc34ec91,9bd5e22,be6bf71e,a870a70d) +,S(69cd7caa,b220abe7,8f36f7a4,633802b4,85969ac0,e9c4a244,7b0ad782,29daa879,4140a70b,8d9025d1,7fb3402d,2ac8afda,e9e0269,b29d488c,2266c1bd,58accc9c) +,S(b6cf3a30,d2a5ec8f,4480df82,ec6104ff,37355ca6,f16418ab,cad3a0c7,bd8da064,f12006b7,5d406558,51fde0eb,c68113b8,50441595,dfe3dddf,86c17a58,94a6d923) +,S(65c4a081,656d9b7,445131e8,6081b306,3a6e0c02,5339d3d7,cf48e9ec,4e8f59f1,51f4ebb9,4b63b8bd,2cdd6d88,c84c8608,bb380e38,c748ddb3,3dabff1c,f50197fa) +,S(c243570d,e74a1fbd,938bea43,bb17a929,47a228b1,ae47a6cd,15c37524,b034fa66,ca57366f,e3886510,903970ca,e1a5dc5e,bb857007,cd4cc56a,37fc7fca,8aa4cd40) +,S(9290d033,1c95584d,e2bace9b,788c50b2,f7fda83d,d45a4a37,5705400,45339d7,dcb3032f,c4a41076,8b8e442e,46cfb16,b63f4fe9,f94a7d5c,f932d0d4,95e699e6) +,S(295df203,cfa65b66,6afc86cf,b879d650,7075f75b,d1eb753c,709760f6,6ae9df94,2cf505f8,8220196f,9e5478e3,6bd82501,671c6b91,a404fc0f,b1fe00cf,12085934) +,S(1631e6c1,3f89dbca,36cc78db,1056a461,6ce2dcca,62f90b0c,5fcbf232,77d41116,acbcbff3,2c164cd3,b57d3b89,a326b5d1,46b5769f,a5b35df1,efabd2f4,407759d0) +,S(db0b2c5b,eec9f06a,9bb43e4c,de18d978,59a95cfb,9b319d2,5ba619ee,abc49e31,d647147,d8330315,1446a405,85bd857f,ebaef109,22ddd0e,3ac62231,8ee91abc) +,S(2581d046,9e8bdc16,e535c787,1a37c48f,929aad34,b694ac2e,5d264962,11e744f,7bf3c684,3d953b2,dbead1f4,8614646c,d18b0f2a,cdf6fbfd,3ca68498,ab25bc60) +,S(9db20da4,d576f564,372aeed6,eae78eed,f512d13b,13d4e9e2,eb3133c6,13c4b80,40f8b2b6,fa113b6,ed7dce55,d62587d8,a86a43b2,9e0b4876,c5607b89,9144d255) +,S(849b193c,e490990b,e2aa48a1,c31694c5,fa041f96,7086a83,cd1a06b6,ccb5e3c3,353b49a,6ac0c705,5a3d5e31,fa428e2,391165ce,402291b2,5e1b0496,bda41e1e) +,S(ae83dff6,5a1dcb6f,e2f56437,c83162a4,a388a16a,bd387d62,f5c5ed,ea08fe7e,e9c57ed6,5404a00b,a2f87613,4d484842,4a32246b,def6c31b,533caafe,7029eabb) +,S(24724eab,46175b4,efe51d4a,5993da48,1a62c6e5,f05d16a5,17e4f58c,fdb103,94465b42,e4e378c2,1ef0d1d1,8b25d140,fb17f51a,fa4d37e3,450c73c4,72468b04) +,S(c2e2f802,4ac48fcf,41a3790e,e9916018,5a301859,3cc3fa77,c7840552,6700659e,b1fe219,1563f9bd,20c4dd45,615d8cc,400911d,20cfb7a7,672b06,20d32a2a) +,S(8b889bc3,e2d1405b,47a1a05f,fd0c17ef,9b4dd75,4d30640b,e3c4de7d,f70791b5,e2d459ca,285629d,956d5046,54c5e907,6ed92fa6,c95643c0,7d746b78,e03a044a) +,S(336c0585,8f5ee169,fc09fc73,a181ccd1,3bd62dd7,c454837e,1a5d7676,abb2faad,5c29a656,e8f2804,6e855c6c,eb0d908e,38f1b62a,69c67948,9d6a03ce,64a90c2e) +,S(c9a6df46,411961d,a703ab23,605fce16,fe021576,92a9b80e,65b9e4ab,efc9ee93,8b63a4ab,18a4b190,89dbc53c,ef0b0dc9,20c0ec7e,1fcf075,195bccca,58d52f6d) +,S(6cea35c8,b3a45063,75456a6,2c95e8b3,7d84a6d3,e909c5a9,cc4800eb,5bc28367,68198888,eacc9380,4a3233ba,1801d586,e5bcb2b2,78efc7da,6764bd5d,edf0ee90) +,S(f13d4ee6,ea31999d,d8d1220a,13ce8353,7c350046,319a0412,e562cb8d,3e4ee80a,5f7afcc4,37f0b29a,ab11a8b2,14947521,bbb4b622,261b9e73,f989e1b9,9f43a2ab) +,S(7385b644,2e43ab56,f4df8a57,4d0a32ac,6e5a7114,13dcd992,f86c0b04,33830307,6d27608a,8ea00e22,4197c8a1,9e9511fc,7ecd7083,86e94ab9,6aaa35f9,c8c2c5f3) +,S(35923ab9,a784ee6e,5a4e911a,7552fa16,ccefa4e3,dcc90083,e5a19e31,4dfeb06b,c900475d,980cce8,7d5cc091,7a28c18c,2fecd5f5,cd2cc66d,e26deb61,1c5acb89) +,S(d88b6907,3abccb02,2e235e60,4f3e2877,ef979f85,a5b3fc4d,fdb166b,a4155d9a,1eefcc82,69a20b9b,48d30d00,e7ffd021,a9b7b171,378a299,819d6e6d,19d5ed24) +,S(b86c5281,cfb9f3b8,4be4f83b,1d13d33e,1f6abfae,bbedcac1,63362a76,8740a827,c1a32696,fc1f8507,289f111c,85483b23,23d228a6,773030e8,dcf30f6d,57857dbe) +,S(d2813221,9c730094,97c257f3,1fbeaee9,1afa001c,84e4b813,d7ee2452,6454c640,75d722d9,7111d6f6,b6324598,8720ce39,66fae55c,3d81e4d,ade294d6,1269b4ea) +,S(445addf5,bf941ace,6b4aad55,6f174ba1,ee793bf4,9f46295d,19fd8e2,807f8d3b,cbe249f1,fbb39f8d,93079d0c,e84302dd,52212b6c,828a1626,b7446f91,4f6727e) +,S(a2dfad8d,66fd47fd,38fbcb74,b983d366,c57a08d1,b04f1acc,4fdf047f,100552f2,63011d2b,43822a21,ddcdb1cf,ef4dc0d2,5f595165,26939761,953fb738,77586c9d) +,S(c4e84511,6644466b,8c573b8e,c7dd3788,ecf1c6c2,63ecfabb,b13f697f,2b2e3a7c,1e53964,a70e83a8,ed9f5d8a,b6b79629,7368bc5d,cc90e6fc,4e8e6f65,542f63cc) +,S(63c4cc2c,cf368a04,be814d1d,81fa4250,653ebeea,ccdffea7,944801f6,efee1aba,6fc2bb4,a7e573f5,fea2cabf,abd9a145,c7c36d62,11928341,e9553e8a,b38fa90c) +,S(51eb8782,a3445ef6,43f01634,caad6fe2,29585dd6,f073acf3,62cfaa3e,960343c6,56d20f56,8e6d868f,491b6e1b,80fa5c88,e3d625d1,433b1dcb,5ae2d35e,b40a960) +,S(d89ea50d,ab6c4c39,48fc4d4b,73d7812e,a6b59ee1,8e7a51e8,bf6249bd,ec59d068,a1ae85aa,e842ab60,95feec2a,d6ce6206,e81a6e76,7f0b7b20,d41cd28b,6a8c4258) +,S(d121a6a8,11f953fe,a90d8f3,4487d654,fb48e4f3,c5ac4db8,3e3f50a5,cd7bac9c,a5b9e6da,e07a0f1,dc1695e0,20502f55,5fbf136,df11b586,4ecc63e2,d7061a6e) +,S(83f7dd06,e5afbb3f,7b2563f0,faaaa3cb,20c32db1,5bdaeeb5,73219814,caa599b3,c452f49,1e4482c1,1cd4bf46,75d74c5,ab054163,b6d1b837,dd10aa05,950f199a) +,S(1f5ba7d9,b4cf8684,cd073892,4aee1919,1f611d78,a943d49b,509fffa6,31fdc19,a017e13,7a8a199a,e361dc18,527f0135,51e48b02,c2f7f102,a6c1ffbf,fdd0baba) +,S(d25fc73e,a83ef669,c2e127c7,1615df3b,ec61ee38,4a6b3396,cc52066e,c3b70b8b,9b5d55e1,c8dd008f,19b5e989,363ea737,e7d7bea3,f7b0d9b6,951dd78e,be6c5334) +,S(d749373f,ecc1814b,dc8ce6d1,2ebe84c9,e09806a,9cbec814,cf98dab2,4a46ddba,88012af1,84f7ce23,730a3a4f,191d0687,4d5652dc,2be47214,61e9ad31,b39ee397) +,S(8e05da99,971ba37d,38e7642b,693856af,a90d7206,2d360611,6c8f506d,68316b9c,73de534b,5833287b,61f3f985,2723be7b,e8e22ee3,1d1ef4fb,f45d6931,827e3db4) +,S(e71e83f1,c6b285db,157f4a14,825aa540,558a7853,673900aa,fdb84556,ae5c891e,e37980b,c180e3d2,481d81f,f9aa33cb,b297ffad,7dbbdd79,4fc013f5,43ee679f) +,S(bc66d644,dd9da12a,299557d5,fd35993b,ab05ac8f,bdd3802f,25b35890,db8eed32,5fa8c7e4,bdf77750,573a4ac7,1681ca04,4f796ea9,c8379cd5,ed55631d,bfdb8405) +,S(537f194e,efe43985,8dbe1eb2,8e27448f,fd1b554a,b12805fb,3af43538,fe0e37f7,e82018eb,447b2810,1502453f,db4c1cb6,666330d2,ea3331d3,f79d5652,a1d64af7) +,S(4af2a9f2,e0fa4b4e,731dbdf3,676538c1,110f3232,7b8f2766,a7f489de,8aec3b4b,cf2e0ca5,dc830856,43151cc0,1507af4f,d84b253,2f0fdcc9,6489baf8,6c1bd4ab) +,S(81369bd2,a4945c15,389aaea3,4e2855d7,6343e200,a9407ed,d05ae927,5585aa36,a9b4ba4,e26950c6,6648b573,3c0c4e5a,22a51e71,ac3c1fdc,78403eaf,3a667161) +,S(1c0813d7,ef91aa73,9e3a6f0c,e3c7edcb,2b7117a7,2ad1dad6,1aed130f,c61cdd3d,e3390572,67ac3bfc,5373cc31,14bd0f38,ccc3cb25,862b243c,912c0aeb,98bb86d) +,S(8a651923,d2622057,59e5f82,b38bfae7,dc922488,749ea56c,e43f0f74,c268f9ab,f3df434f,14f67030,fe888ba0,185e25c8,38520bf6,6e85023e,e4ff4f04,b056d9d1) +,S(89d98548,30a2a572,dbe91018,e66b28de,835dd02b,f793a469,2de3d720,d70e8f43,629868e9,9e434bfa,98bdc4,f191a08,72e68768,ce8a918c,7c2da42,75e5cb3b) +,S(97d0c83c,5d83d399,c567ecd5,dae551fb,7f1838de,1967e84c,7f053b81,62965fe9,fd716683,73347fbc,407543b6,70734733,df623a55,1766f55,8a02059a,2ce55c4d) +,S(20807bb2,650e6d82,38a66ed4,b239b59e,fe073a5f,9cbf0d6f,e3d9a16d,be427de9,46a25a29,c104c56d,8436155f,64b1d84a,b974fb2c,951470df,17a9704a,be5c1f9a) +,S(3cbb1786,945bedb5,c8ac2d0e,dda1b0bd,ee314cc5,faf56b75,fa878bf2,b218a8f3,ddcec0c0,d05403e8,ea2094a9,6ea910f8,3261932d,701a2ea0,4e93581a,7e4b7275) +,S(961d0144,1618561d,c3504859,7e1701bf,35412ad3,2d04486,704e5593,b9278734,7e137d6b,2060572b,ef66f8b4,c8ce535f,b858327e,26dc2295,6ee6c94b,c83859bc) +,S(2814918a,115ca2d,688f4358,9010b7d8,b8b560f3,6a3dce2,8fcc05e,acd4845b,dbf76f51,ef80e324,8820cb0b,bc7f0c2,4d50ae48,6387d206,c333222c,5f959dd1) +,S(6c4f3b00,c02c19a5,ddb0ab1,798929ca,222a9538,b641cb3c,dd61736,77c9442f,a91d13a4,d3888b82,eaba5173,3ff76fae,8022fb10,8cd61f19,206cd78,7d1c99cc) +,S(8f48304c,ac37d495,fa1a2ff,2178f442,4af030ca,70662a1d,c750bde,5f5d8dd4,ccff6176,47cbdd3c,3d0c588c,37a98723,c2b2aa14,fd17cf9f,ea45ec72,eda8defc) +,S(ae3da559,e3fce253,f5c1fbad,8e12a52d,ee989ea9,8552a192,93f7db0,eaac9405,430b86d1,322191c7,9aed5bb,12eece79,f2519bab,17998346,8aa13b69,94032ef7) +,S(90c093fc,27fa9de,66a1fdc4,d921e5da,6f4fa049,81cb6f91,e085f89b,96561471,1bdad536,4ae198ae,bbb0ff88,3bd5dd2e,dfbaa91d,e989f45a,30befa9,76f2db23) +,S(730a1c4,5ca28743,538fcacf,a65b7d90,b6f4b1c6,87364cd,53dd6585,328eeabf,7420e8da,cc64a059,b46221c6,c3adb4b3,46eceeb8,8effca39,1a1e36d0,d665257b) +,S(341eabe9,66c6ce4,65ac18ca,1eda053d,4e6137c,ac0796d4,36a942e5,99ef897a,d298003d,fdd9f529,c1977b3,ed426d6e,2df46098,539b20ef,c2011a36,b7e49cde) +,S(8f7e1b2,cb538fce,4b4a7775,90d1a95c,2fef8331,9792c0bc,8d5f3493,54fca169,71b0849f,cec62c5d,fdce37a2,61e2a06d,32b3e0de,87c8aebe,e5a95cab,b0c3f798) +,S(c7ea6b43,ce1e0e83,819bee9a,31fba823,3ee03a6b,14988b98,e80aef2c,eace0d56,e9f1328f,dca6a16e,2100ad40,138f9810,17e37e67,7e7ca747,c3a57ad9,24b8891e) +,S(b16ea5c3,b03e58b0,e6c217c8,6eacc4b9,3032add4,30acfd7a,e50eacb9,a0e5c1fb,507fed89,5c14380f,ab9e54e,a3624e5a,cbdaed64,b2712f88,48018b90,7a88f47c) +,S(15cf4de,7c36b72d,f7b98c00,8e928731,a2e71c69,cd0427f3,ac9264b1,5a5fd487,3865beea,6b36732c,5ecfd21a,562ab253,d618546b,c1c24745,8881b20,643d7e2f) +,S(394efbbb,fa740f53,b1e70eb9,d12671e7,55337357,b982921a,79915acf,ddd18218,8f1f1980,6c1d631e,6519aadf,b563dbf2,37b75db1,54baf06f,6fde8218,a0a68eb6) +,S(e6c3e152,27453d32,cd4449d1,ab1ad78d,58f5bb6,f29d813c,e7c6628f,b284399f,89d87957,4b640a87,abadc6a,dc51a533,838a83f,53de4448,9ff0640a,502dfd62) +,S(e2480000,9db30642,f925ef8a,e31c54fb,1340e88d,b6d633f8,415ceac5,f583cee6,39ad28f1,8ecd8302,5cc1fa72,ae4e9897,81318cea,9e506794,50abd959,f19758c0) +,S(1c134120,3c2e7e21,f5b10ecf,402d52bd,33db3278,70cdfcec,f3b277e4,78f551f4,cd6907b,57cfad79,5e14e7c3,b2a06a46,17b7a27c,ff476bfe,38d68d0f,1470dd63) +,S(6b2fbbb1,515c261c,954a0be0,279a1cd6,63daa083,1fbd58c9,c69b7be7,ee6047dd,d38ef59b,4e276fe5,6f1f2fe6,74b6974d,5ef1f4a9,74abb2c8,17cc68cf,78a164a) +,S(dd5098a,8cc8ccf0,7db82096,b52d1fa3,6bd26c2b,57f0cbe6,2ca954db,1773e9cb,a198ec1e,71c53d73,5b50000d,678d7d93,de64a72e,8ad018bb,f515b4f7,c7840aff) +,S(f6dc494,3baa0613,59a000ab,3aed3456,1972d425,34df86ae,3eb8e5e7,cae23c22,7150f3bc,5a968248,d8c71ea8,32b116db,73ff34e5,35ec1e6b,64b2474a,947174dc) +,S(e115c926,5930dc67,bda89798,e267dc48,12c06d2a,a05e4a5a,6519b0bc,7096f84c,5b0dc7bc,82b61275,2aa17a13,c1fe2cd7,6b60cf1e,ceaa9234,ec9e6609,7b2018ec) +,S(6687f498,98a22d8,58ef88a1,bcbfb446,33d51eb2,6c1fc2ec,eeecdae9,e0960c56,fd1912f5,7c0e691,23977524,ba58ea04,5757aeb9,309a5b94,3c993a93,57475ff) +,S(366ea4df,3aa8da52,763b513c,efa3c739,af61a497,6fc4c884,e879ddde,c2457d1c,876520ba,cca3c711,a23186a4,833db7c7,14b3de4f,fc86e8e4,cbd61cc0,9a48f34a) +,S(f7951805,eaddd012,2bed030,f3013e15,6fec02b9,80ba8ff1,1a0b978a,3fbeb778,b255b5c2,db866de0,a145a108,f5eb4b69,271c13aa,8db75fc9,f467843e,a59549a3) +,S(c77d217c,5c7b8fbb,f7bfd244,b2a2d2db,372d8217,43eb4a03,47858678,471d8be7,55573d9b,dd16bda6,ad916820,874d64d4,b260a489,b4a93427,1ea5a79a,f57dc5c3) +,S(c803dc3c,1432ac63,19db169,6d7ebc16,58021b8c,b92c0fe6,a59d1efc,2056f214,ce8e23ae,c7dca471,8666f61d,d7d8bc10,e06d1929,7fbad7b7,7d45526,9e207b09) +,S(676c4c3f,617b661,2affb2c2,dcfe072c,ddee8b29,dad9124f,dd24e87b,52a80b88,6df8c35,be6818bc,b6857f47,f59a11b,e05cebae,ee6c53ed,8cb93fa8,92c49e0b) +,S(8b0c8502,bfa15f59,335cc34,20e04c90,becc2308,12d40c7e,14fc3e30,88b8f34f,eb75d312,9fa4db28,27d20c93,de9c5cc9,4237bbb,a9710371,f767f686,e5ddbbbd) +,S(6ea07148,5594bd90,2d0d526c,28918bb2,cdb7d1cf,d3ad0b1f,a3ebbf76,71a2f90f,3a30be2c,2058cb43,c6f8ae98,1ce8986a,8b4dfc3d,81d49a80,4e40c81a,a1fc8220) +,S(aba7df4,8bcaa5e4,c4fd9a21,6b4bb3fa,27617205,693763bf,71b8b214,9cf83c48,6b1b719f,a0633abc,4580a9cb,9c1210a3,3e5e3bfd,177bc76,39057e51,3fb9b3fe) +,S(ccfca0f,ee5bebb7,26e2062e,2b5cd592,847031d3,5edc7767,414af809,9b3ac2ad,135b2ff2,4e40f04c,adef93ed,ceededb7,380c1e9a,e32a499,467af149,cfb532cd) +,S(9af36417,f3076595,42ea54b1,4671d2db,f7582ff9,b7e659a7,6465ee2d,4db88e35,dc5d07a2,58d4f5d5,ae649b63,e07a4253,8b8b3e42,c65a6ba3,44900028,c84df8aa) +,S(e2f308a3,e4d99e74,d6b37cc1,dc41d9fd,e98a4472,6e86764a,89fe959d,deaf922e,f5f8eebc,d9252e1c,74b9040b,569c9d5e,11d12af5,aa21051,8f87043c,7b47776a) +,S(a62581d4,c4fa4b6,aee11db0,8fb698e9,864cf336,578c536a,8a887d1a,89b43e35,b530ce21,bba9d034,d53dd490,2b76f25b,4391914a,5f87b6d8,2526f7c3,def132ba) +,S(11ef91f5,dfeaceaa,52f434b0,fc03085f,60c12ea9,4441574a,5725aa86,52c259b4,a2c81e79,cb5ad0d6,bf0221ce,2bf7497e,bc91026e,adf0e25e,6269dfb3,2ced7d8) +,S(ff549a04,fb86bf9e,3ad207b5,ac76a74c,2532a1a6,516327bc,96353baf,66269c5c,ef1088fc,633f639f,f0061bef,4c1e4c64,5897ba0e,ee229d44,d99be0d6,95e494db) +,S(11c9ebb8,893b6534,b323909,961bb8ee,4c90c854,52848ad4,18fcf223,c80eb7cd,4b0229e0,89a1ca0e,d60ce2ee,590211a8,769d333,5f4ef32f,4460f8be,940a0dd2) +,S(e86b3691,f8ae48c4,12a6216c,c3633f1e,88667299,f828d6b1,3ff88cac,e060b1b4,14d95d6a,61298fb5,1fc974fe,f3957db5,4aac7130,a1ed873c,cee5cada,6eec0c6a) +,S(e5b9550e,eaeed973,5d8068b2,2c48bd2a,608fdabb,563c0e5a,6c2b2351,24c49d19,506ff679,2ea7c37c,254d7ae1,a459204d,aca23016,93c1598c,2449b758,6d437de4) +,S(cab58ba0,cb15982a,c1ae5b51,ad65574f,55540820,d057e11e,f9c9f9b,a1388335,ae1c9e22,74958b33,2ce0f0c7,ef621a49,4d5b0ad,b04748c6,539dbcbd,6bd4ef18) +,S(715e4568,9bd663cf,e9c83006,82fc7c90,5ae2da55,42b0ea4,40cbe2eb,36e1eb43,58ccbf96,8860cbfc,6b03f6a,a5fe05db,14be0e3f,3d6224bd,ce6eb54f,7372aa85) +,S(df92f1de,4d22a7ee,6d2bf45a,5728745e,f59b6b07,29614536,722c7de7,965c0648,59e18767,f0e22894,be586a13,46950c03,88f1529e,cced0d18,50439dd0,e5bc192c) +,S(885dd01e,dc8ffd40,c5f26d7a,bcecf670,7a791ac0,b2332b91,12e69cbf,11399808,4ad58276,6e763ddc,3f4ff718,569f600d,8c764659,87ebd74c,d506c2,ba886ac8) +,S(d3fe74b6,17a1ab46,c773549b,af4bcbff,917c7ecc,fbedb63b,651b2197,89c1ff9e,b2e6bbee,5d84b593,d43467db,7372f40e,493a9fdc,c5d88fe6,5767f45c,837acf93) +,S(c3730836,74b97237,66d9e9de,f7b6d792,93faedf4,f7d86301,75862d62,d4ada8e3,b669a24,a31f8277,8686d2aa,6b2acd16,872570f0,8e6f06b8,394f498a,dc29f099) +,S(4ef2ace6,422be7ab,6a614e2b,fc43360a,2fdfcdde,51cb31c8,372a2042,2df4e100,86868f5c,37366665,fc6121e0,a8ab3a86,92ba1714,f5b8506f,9a3c3025,eaf9fbc8) +,S(51110764,573c540b,813ebc4e,79d59277,67e30ed1,70a951b7,9ed05f8e,8d142cf8,ea8890e4,9668304b,63fad75e,33f42601,f2649a21,724fc495,61110e79,d7ddfea9) +,S(36cbfeec,5491e1c2,f853d98a,275c1baa,e74dca33,2bd3d830,7d896607,c1cb651c,f67659d6,677b44cd,33c0cedc,d5886ad8,90eac77f,5b393fa5,6cba1077,54489eee) +,S(d1ff3875,e1ef071,eef96f05,bc19d356,aeee18a7,f3892f02,4d07b43b,c3f09dbf,ba825e43,72b4a644,dcb5b8f9,62e0099,ab75ef9e,34b54874,f8d68197,ecbe8eae) +,S(45e7bec6,75819b22,f2761ae7,575ebd6a,8ef87727,a15e33b,3edc7ead,dd58fa5d,3482080e,edaea330,240b539c,7d6a2e42,2cbaf40,f93d5052,28c773f9,6d80fa86) +,S(8ca5d7e4,bd79aebb,bcc5250d,c86ac1df,373eb3ce,1d8cf2ff,5916cbb7,1e8e016e,1af3f417,afa5c1c7,89474f79,a0755bbf,a9a268bf,fdf242f4,c1599dc7,b7cb1e55) +,S(56bf2e78,e7c43841,6324e581,7330a6bd,208edee5,3b5d61cb,a141f9cd,ec3002c4,e8f91e4b,3984a946,29060a4e,534bb4de,f345879a,f4884214,63dd0299,2bfc2fde) +,S(af152859,31540f00,1be4a65c,e3f55437,f7be7d8c,db0283bd,f96bf71c,c004455f,1f58be49,77cf9b8,b7ddf7fb,74f7356d,62b8fe33,6bf798de,3dc435b1,86122b40) +,S(2f4d8117,bcffeaab,7db186c5,7aedcb00,80d67b36,a560c5f0,e323b7d7,79be70b3,e0a50d82,80677ee9,caafcaaa,5d7d1747,3f4980c,73831f43,29b15452,94e71829) +,S(bd96815c,e6b6d0f1,3688cc26,777c42bf,50fb8cd8,cd0aa082,94ad498c,620d1f4d,8a882c49,6592b186,b0a4071c,b0b556ca,27f2ec82,417aa246,ae24b415,8e4ddb23) +,S(cf64bc04,e0796fec,112a5ef1,2c3cd909,5c041b46,2772b818,3e6656ea,16d046c2,6a05162a,eddf163a,fc2cc91f,34f7a7bf,41660b4e,a8ac7af5,698c259e,47e77e86) +,S(3dc4bd0c,2c8253e2,4ed942a0,7f45c2c6,390a9d07,6d334f3c,80dfabe9,282a86c5,e0994668,7cc9c6ca,e2d04840,6d34cd22,e4f8e271,da4416dc,77e59af1,7057c43c) +,S(40e00b89,e58de390,6a56133a,fa574019,51be1efa,6156baa0,45fb3987,94f7ff11,cf675e01,1f20efc4,24b882fb,b7bb9ca5,5a1134f,b628acd9,a597fb97,968641d) +,S(5626496f,1f49190a,48929e9a,403f9f54,319a6b1d,301cf256,692cadc0,41301c27,21702c7e,2ee0efcd,b98a0170,110e3495,e23fe5b9,9674bb0d,b6f09e57,fe76b48f) +,S(2a2c8f2c,a580145b,a9593b87,dfe0dcdd,caa3cef0,20b0e2cd,3792da6e,2f989a11,4aad23a0,e01f6a43,3f6c2a40,f480f945,d45c89b1,df42d67,acf6b0da,3f46bba8) +,S(68a74703,a88b88d9,ee974a87,af7b1be5,1866ea40,ab4cae9d,90a4c2c6,5822b565,3660b266,c74b8be1,c98d3b9,b1f14dd7,e039b476,733a1322,d2d7d2f6,9ad59700) +,S(b50ad45a,4898f77b,c5544dc1,cc8c0515,3b1e15ae,d043d2f1,40bf9dd7,29e413e1,1a59e623,3bea3be0,5713c06,b18badce,69b84693,636be68a,532adfa8,c617a773) +,S(df18b016,3ad015e8,da7e87ad,e6fa5312,d665c696,e42e466a,5e9e2a82,18337c22,532d4260,eb34306e,691f42dd,c215ffdf,2f6cf3ef,cc1363c6,46b8921,ccf277b0) +,S(405bc408,446bb0bd,49eb838a,eaadbf1b,27d413ef,a15fdec9,86e8446e,2c799391,1293bad0,ca26e4a9,f80dcdbf,1ccb70d3,fca9f403,89bcc331,e917d7e4,bf4d0b3e) +,S(1230acd2,75b02450,255fdebe,dd0ae807,38f081bc,5faaeebe,4542664b,ec57bb15,aa31d16d,b145414d,acc29c11,b0ed9fe4,fad90a7c,451d9706,4f7ec6fd,75b15703) +,S(4015c1de,3e09dc64,9ec990be,898db42d,1193e1cb,81956b08,da1c15c4,b9a2af48,d58b2d0e,553dd49f,ab07e5dc,c5a66543,b7dd351d,84375fdf,2ce1db56,8185e67c) +,S(f3da2f12,7f47b9a7,192f00a1,5576aeb0,8bc36211,7fe1246,ad61421,85f79009,865ca0c6,4aa629af,b84f761f,b26a4938,25fdec29,ce1d4a66,9dbcd138,41bb83c0) +,S(15f1e896,f7c7cc94,f3f921e7,6dc1e30c,f0d43b99,e9fa0352,42e56a4b,90a0c736,61e85195,215b864a,6f5bd52c,d0274526,dbc80af1,4395f9d1,ce60bf74,27c18b33) +,S(3fad3455,470a113a,2f773ed1,258111ff,da926643,f7fa1cf2,8e9f7b80,dfd2105b,ffbe436f,a1975bcd,ee4eae51,8dece7d0,cb34aeae,ade738d1,b39f4c6,6ca08a05) +,S(62bbb9ac,282329dc,65ae7b4f,bd15dca7,70a088e5,45850aaa,bc4c09b1,9177f92a,9c000eb7,f6104a03,51e1bd8c,d8ac8f7e,22578291,35eea222,866f2632,2573dd72) +,S(9bf86604,a46cf253,324f5608,b7bc87c8,72939597,131f12c0,eae3482d,b1935e42,e9f2dd2,15cce5af,16149d3f,1116d79,74f51267,1b575f8f,6ab6367f,fede26e9) +,S(a2ec976c,b5e72001,a25f95e,bbd7d354,2f3b174e,80ee3752,db082910,895f723,dbcb75c8,365c6248,c52a83fe,1c79d7b9,37ca8ebc,5060ba7f,60b881c1,964105d5) +,S(dd91f713,ee212c4d,f94b1fc8,c7f246b9,cd162a9c,5c8988b8,f3adff0f,fdb0aded,efd02821,c4eb853b,bb8c55ef,c54f41fe,7e53582a,230d52fa,c18a53d,ca40c81e) +,S(504e6ab0,c47fb3f4,b6b74a7b,1e67f6e8,c28ef108,62c2db35,f16f31cc,e71d423f,e7adb424,3200ab4e,71e50453,2d849315,1eae2247,50ff7a59,52bf2656,65b3ded1) +,S(1a9ea377,27fad3be,155f7ed5,1caf01ab,1d30195b,1629fba0,dd04b7af,c1a4b8c7,2140f144,e531dab2,22cd4137,921b4720,59efbd57,c1c97367,ff2083e7,f2420206) +,S(d76324e8,31920463,d5d94ce8,f9654393,89d97ba3,eb5e91ac,56898343,397b34aa,189631be,df5d46fe,fa8f60fc,a8b22fc2,ac987d23,b21ff267,560863,6ef3a72b) +,S(de87a315,50a6f146,e681d8a9,f9a7cde6,7da28c7b,5cd7a70b,703695e2,3c9bddfe,d33a05e7,77ba9e6d,155bab56,2b8cbba,27f4cc63,13038f7e,d193137f,d14b8502) +,S(d8381e05,7fbc1910,8b5a304,fa984e0c,cc0f5d27,303a3287,9ecfbf73,a1137974,1dc513d5,ac96238c,79d8f740,c855e045,e5c4e567,b3f44744,abb3bf46,ca394e8) +,S(69da86a3,b355f0d8,138bf809,79e314ab,7cb34e64,45be4842,b8f3810f,11b2ad66,7db776df,68bcac9a,c0f8f55e,8ee6a7e1,771d4148,1f5d953e,e9bf832e,cf713cfe) +,S(698f8b8,66093996,e2e357d4,d671d21b,230726a8,84079fbd,766332a5,4e7f18f3,5925e34e,dcab3458,ed959aa,3903ac93,c39b8ebd,1c562691,3f844150,d41ad20a) +,S(37274120,6cb7047d,aa97274f,b12aa8d2,e5eabca2,f3ab0b4b,daa3fd7a,3d5365df,30d36bad,c10337a2,db6c30f2,e8876226,5ccc6a1,7104460a,6f438a9d,3e8e9300) +,S(4e8c8df7,30f5d411,77355739,84a530b3,8ca4012d,3d4c8ce,f6c00689,b72cbeca,d9f7aed1,f5073c8a,8d2948d7,86ce6dd9,93a405ba,393a20a8,719287ce,797163) +,S(1e62c3c7,16e4f6ca,77b6d325,8553a5fd,59f67df,f7295115,cd6e4bb1,19b4b5aa,7df17da2,a7397df9,e314fd8b,6b03d293,ff7325e2,769d7477,ef3802a5,7d8010a0) +,S(c79f25a4,664cae13,d0971832,fee6a316,ff338f15,40c1f3e5,95c707c0,6e035db,5ef7879,c46266ca,7b342264,1594e81,5c189ce0,f057f187,e43a61fa,10330e85) +,S(768a47a3,64304a44,34b097e5,132edab2,b9840584,6e543dd4,755038da,e355cb9b,79896b63,eed7e866,32c33041,d037554e,551f2a73,6f2c2b35,4dd7d7ac,f6562344) +,S(131671bc,604d622,eea3f06f,200edb52,f7223fc9,3fc8d4e5,496af1a9,f72e56ad,5a6614d3,7985f503,2ad7a53,9b99ccf7,7c453f94,3975983c,e948dfe0,ffb867d6) +,S(3b9e6127,48d11bfc,1d2d0081,24e79a9c,604bdb94,6b25ac57,749ca6ef,302d7a58,379e7cc0,fecf689c,f905e84e,8516388f,3e1cb41a,aab8192c,aa024de0,3332cc70) +,S(4f9fdecd,10e8cc9c,f5f2573e,a2fd231f,b1313468,f516af1f,76af0eac,9ad51d76,26d6731b,71382ea2,1172142,fc5e0f5d,d0f7afa2,c9409fdc,62bced0,e8246194) +,S(25f313d7,ad044b0,538bff0a,ead5c689,d5fafec5,7cddd9a8,31b9a4f,59b848e0,f28c77b8,9202c9fe,e64c0580,75a972cc,a4839e20,42c32b66,517605d5,87470c40) +,S(24a8d407,e26c4cae,3f8dbc18,5820f345,81bf4355,7ad036a5,200b9b7a,68bb8d6e,fc6a5d96,4fa25fad,4d09a1a1,a4ec4697,818e46b0,8cdefb70,367e3453,2462b98b) +,S(ef4df8ea,5cc100e2,768aeab3,112c7ac0,6077b754,75cab97,df3ed51d,6d397f4c,fbf555d2,27eb051f,54965eb3,fac1e21b,82d216ec,807b1485,5074ee56,1ad70883) +,S(80c9d594,578f6e4,e8462dc,228cd99,9b621493,63d55cf5,80e1c524,627055e3,b6d5bf04,97b44e3a,7c7e52e3,28f63214,5eedda41,f80c44df,c7ca6d29,77436f24) +,S(35961cd1,57bc1774,40dd41b1,6a81e31e,52349a5a,e4085248,fe4a19c3,b10f7a45,b999ee7c,b32f1051,f0e7eb9d,4689fb30,fac7af1e,b410d53a,85e79f27,70a7566f) +,S(4aa49d09,32a7fc5f,77a76a12,16240142,596a82d6,6b59d388,24f0d8a1,e7f70948,adb5b12a,5e40bd0,a14c174b,13c242c6,c5f25ee0,642a6265,60d293d9,64a4671) +,S(110d8320,a9b2c5d6,5b06f0c0,cddd243d,c83cfe4f,671db970,d1213780,f6c4af0a,a97c2689,5c7b6ea,a3a02564,d2af735c,9b43ceeb,9f6f2557,3fc468b0,467b12a1) +,S(d01abcdc,a363b065,d8d2bb08,388c3545,cc8ee88e,90ee66c6,18a9f575,c0caee80,317409e4,a70e30ac,279914d7,135f9d18,e19fe520,4c83c472,5f86a614,1863b4f9) +,S(cea07679,64506753,8dc24b68,19bc3332,f320f16c,61eb7b85,96e25bc4,1499796,edff87c0,67e97ced,4aa330e4,e9dbec3f,d800934e,ed7238f7,8e97a46c,a6ad9ea3) +,S(d4463e7e,da5fcdd8,8ef0133,a5dbb1ca,c93aefb5,64581da1,3acc3871,cb94ce1f,bb1efe84,81dff341,dc7a4a8a,c2e44ca1,b071bcc3,81e7ecdf,4d4b7edb,6996547d) +,S(89cb575,5e9323b8,7771a2d0,58dc78ab,ad8bba70,6f845a8e,9a45a16e,ffbca1bb,f7e743f8,a24a6728,f8e8051f,5a303d71,f1f47059,202d332c,23f3a293,9ab97e37) +,S(d035032f,8e8e955b,b71006d5,a3b098eb,7dedb73f,a15d0d36,7e01c390,18bdea9e,1ba4cc2,fbabc437,a9d17ff4,f3c59f2d,2a416d2d,c07c0c81,c3e0a180,260bf2c0) +,S(fec9ff6a,e37da167,208b1247,b754cda4,6c6eb072,8d6b65b1,3754e2e2,eb3223e9,305400aa,27a59f3f,f19d1513,3c5a3655,464c6f39,94fd2ec4,562d7f85,fccfb767) +,S(3cfcc8e6,9e872314,5853743f,efd2802d,bb1a05dd,a03a731,77daf6ca,da9007f0,42b23158,fd0c1401,29298d42,a6cce708,743924fa,624d582a,94b682ee,4beb222e) +,S(4438bc8c,f41b7916,dfcdb038,5c9b6806,83362409,69ce8869,c294990b,cd340e45,78154e51,a4dd31d5,14885a18,b7185fc6,84c699de,2862f480,937c9697,6155ae70) +,S(d2ed1c29,faf76c12,fb15b514,6a31cc2f,c799cc4,5fb226bd,c38d3b0,176b5d52,54984b30,96d0c2ac,763654b3,32666baf,82c04562,d0d92310,cce6db16,216bb219) +,S(37f21b9c,d1243170,5ee6db23,eb578ab7,31f4b470,ab07e1e1,68e69bc7,539b170a,afdc95dd,6379244d,cbcfc811,54aa1917,e8093b54,8ec2be73,5867574a,82ec10cd) +,S(73fe29dd,54c8584a,7d25641e,c62f257d,400f013f,763c504f,f0a3ec02,d1ff8067,197ada53,ba57463e,e23b9831,ef8a6a69,d3d2f84d,c7225782,e7569603,fe1d1c83) +,S(56b27676,f0e88c45,3db1819d,36a73d03,95aae3b6,59f612a9,fe28714e,20bc73c,98660256,fb7d7d75,aca14107,dda9e7c2,28459341,ee6de72,9e463c2c,17367149) +,S(fd898f2f,e7f918a4,61f8e57e,f30380bc,5192a5d5,e1f520a0,5b99658e,8d57bf54,6861b3c3,5b0f6943,48bc4886,15eab8b1,36630618,592ac04f,80cdd632,aa63b620) +,S(fef75974,2911ca2,8057e141,6288b351,ccf2d490,634c98a7,a80153f,e9dc6929,9d5d0031,3417797a,83f0ecb5,d4f45890,d679660f,b1b19686,ffbe060e,deff716e) +,S(2c4338aa,18a27e60,d1daaa92,3d837414,f199f585,8d33b66b,471c6562,c8324bb1,13c28f36,25f2b273,8646cda3,5a2a729e,eac1de3d,80430cd1,6a0f3a9a,cb859fe7) +,S(53d6a5c1,deb56159,34416235,c2f597af,f6e10ed5,444d15c5,d9ca82b6,8e1820f8,26a5d559,cc04f53c,6b1ff3c2,4d5a62f,f63e50f4,b7c1b619,9dc54c20,628364c9) +,S(e432c338,e550a635,79ab747c,f01f3ffa,9e39d066,b221fbae,8b44429b,873decd5,297e10af,3006b09b,80d0ae19,3c1e8b3a,80ae9051,3dd9944a,444b2c7c,42d0066e) +,S(a61c5ac2,60f3048f,92cc2af1,6d3f6a4d,696e543,f044192c,9d840962,493f5cf0,1249d4f,83608025,331ab42f,bbe338b4,727a5ccf,b086aeb3,f1d9c96,26859158) +,S(a2f37e43,c3c2ffba,c45ad316,e912b586,2a9ac698,f85ea54e,98fe9a6c,e1fa038d,93e95000,6bd329ea,57397b25,71dc2e78,a466c4f8,76ace5fb,36d945b,a6e9b24c) +,S(b2257994,44c2ed2f,3114185a,6ca617b4,bf4ac15d,40d73b62,44a81852,d30260c2,fd4607f1,3d4ee761,adb6b139,3f87bf8,e8b05156,5561d650,a47efacc,5ef01dc3) +,S(d0607bf1,5317662c,73df9f40,805c9b3e,208ca1e,7fa8c04d,ab9766a2,8c7fffc2,f06da1e2,7e721799,41a9e128,e25ec992,eb030ca3,6161c02c,8ee31d22,388bd999) +,S(596aa391,d4831e61,55d80829,35a85bed,a1ea3190,a499ec6,374389cd,1bd5d8c9,cd9240b2,9845911e,47ad147e,ae55a0c8,639b994,8d72d2f2,72e89fdb,578d4ff9) +,S(433ec09e,19b7543f,a460de41,e70f63f6,6097ece6,dad9b5fb,f4030c7d,bc5862c1,dce03718,a609efe7,1858f6db,184708d1,9275ec2c,76d5e93f,e55a13e7,927cba95) +,S(343b03eb,c285418f,ad522784,f91707e4,f268451a,394e85d2,824c837e,fa48900a,e6595234,643667c4,bb885b8c,1ced3a29,a71212df,f2904549,ccb91de3,75787922) +,S(6094f67e,41b23bbf,4d594e97,b53391af,f10a978a,19244189,63814efa,ccd6488e,ea874289,dd943f7a,c109939b,8fa545f7,58359804,ad81ed0d,26cef135,cd138954) +,S(cd0c3700,bba5677c,8d0ff53d,f06bdbf5,c5adce29,64921c9f,a1591c91,ae0a375,720b88ac,9374709d,1919854c,237cc5fe,dc53b14,3897e4f,3502af17,d7510c63) +,S(d37ef1ea,95ae727e,5166dd59,bf5ee82a,1f215720,79d82e25,6369464e,d9a87cc4,59c5321a,d700c559,c92e500b,1d3a4589,15a88575,df9774e1,4bee7b2,ccf9bad8) +,S(238158e3,d58e7618,95f7a0b1,cdad8a24,3e19bfb6,d1c65929,ff08e766,e62c2b12,1f65fb1,8969ccb7,27d50e46,39c7551c,5b3f25b4,90b7d70c,cc5e4ae8,7293a0b) +,S(260a340a,5245a039,4a2f0908,f2912f0f,63ed68b6,aba66fb1,951128dc,9d542512,d30646c1,e8aabbd5,e758adbe,980715d2,b0b169c6,fe09c502,3beb7f5d,b5422be) +,S(7333eee5,d111e138,f6e0b2d,4b476ba3,6df4357d,b28c8e7d,f232c61a,6c3067bb,d427a423,a4de1e60,e8b73098,b8582e0e,18923637,c44c52ef,fa0b5f90,8ccf786) +,S(c411f215,dfb87aed,be2530c2,82a61e5b,37a0df71,1ce61fd1,25624b44,b7673eaf,ca3d89d7,d136fd46,161fdbd6,3f0b075a,afe90855,51e075d2,391f3206,382a0441) +,S(275b0a1,9dd09495,78298aa1,c4b62ff,11e715fb,6c3740fd,80d7ec03,3f2635e,30dcc412,faf3f389,c9919b6a,f96e7b28,6eb8abb4,ada80525,b9ca7eaa,f3ce74cc) +,S(9f774052,6818bbcc,b068c11c,b400eecb,da60c4dd,22353a3,4145e3e0,91f81617,a9e56fde,8f38116f,cafaea93,35ee3688,50da5107,a5a3e571,92f2bfc,1b55033) +,S(60fb35ce,f1098201,353bd7e6,89b42fc8,9f86dbc6,3eb400e5,3b8d16f6,28ae4358,1906ce1c,6a6f41a5,2f45424e,86633937,8ed56578,ffd94174,f4f85960,ee0f5c2e) +,S(1390a621,f999c3d,1737c72c,3235e542,99ce4796,d65c1ec5,45f60b71,19f4ae25,8f1cb557,b101a876,296881fd,5d30556f,55d739da,5122c0f1,43c04add,3485dbad) +,S(15f372d6,9be09ee3,8d43c453,dc488f17,42f53a7a,7923439,66946210,60f1cfcf,c6007ae8,a836a1fc,b5a4c0f5,e584fb7f,2c468d68,9efaefa,6303bd6a,beecb05d) +,S(bc2b2a76,17dd9fb9,e6d60931,ef2d5755,d33c7174,7e8e28e4,be151b42,14537d80,2582a69,b6e9b9a8,c5bb4b79,4ffeef15,96f383cd,670eb524,2ac4e7ba,375509e0) +,S(5f8e0957,61e307de,26ffd39c,92410937,5dac9c83,7a5a62f0,b0864cd8,a37f2686,d342dc84,7657354d,d524b32b,62f5f69d,5b2ecbfd,71831b28,565cae36,777534c7) +,S(5451cd91,9e849ec,b8dc75c7,9f939957,69a39234,38159544,dea98155,cb001c5c,e00d1d37,f9ec02d1,ae8222a,744381,4f16220,800f84d9,17cea9d5,9a9e2a60) +,S(737b89ae,9d9951da,d2b489bf,f2ff714b,dcfb13fd,829160c1,39875a46,7343adc7,ef9e2ab9,f8246113,726e5be3,5c1da48c,a6b4fca0,53d35dfa,8a3d826e,e48c5ced) +,S(8b80e227,9b0a91a7,6af48413,71ae6fdc,68f4f5c5,58de6efc,1ec0034a,36a26000,909b49ed,6ce8c555,25441ab5,1046956f,d25a3a73,5d979c04,43ae5891,fbd43df6) +,S(9db9379d,346cd59e,ed0c0d44,abc4baa0,3b7af170,9f034c79,151aaf54,69296780,1a8f9e50,918a104d,b525c439,bb16b64,179dc4d5,452c86fa,e87ab757,61e97031) +,S(3aa7c8c0,293e5c9d,fb50b63d,340851a3,88b1641b,b864cc08,fe776500,76f98d0d,974dde95,7c958b70,e0ff9399,d2d03da3,4dfc3437,c1ca557d,2240fdfb,3ae1d36d) +,S(26cfaf0,d27825e1,6014e5c3,19bb907b,7a3b777f,b6bc69da,5cdafec8,40d5b4b5,2eabc11,73729fdb,d31fabb1,722be99,e5b4355e,8c2b4bef,53b21dd8,3cf81ba4) +,S(ee495a13,bd1ba28d,cc26fc72,4cbfee95,3aa72852,57c883f0,cb09d6aa,1bdf3b20,b340a2f9,978013ce,8275b7cb,3fad5c1e,857bc6d7,b43782f2,1e737681,fb39b619) +,S(2e04dc81,831bb465,59d6c354,c4c6105f,41f61301,769d6006,adb290b1,b75540c9,d086cbba,4d221cc3,7cc96b20,adceff4a,6157ab9e,686d1fd5,5d56801,dcf4b779) +,S(557b5b41,b2b2e4c,598460ef,22888da0,aa2ec3a4,7980247a,e8bd465,a6e64c22,6a3c62ef,f80832ab,83a9d698,f61f7903,b7f64e41,9900950e,c7d79369,403d57b5) +,S(a0ea9ddc,e2797fbb,d384a1a,2c26d7c0,edf866f6,9addb763,dc44b112,dc1cdc5d,a085725e,d947778b,40a2baee,98dcf460,b084aeb0,3f96658,4f990895,b15e3378) +,S(1acb89f7,55a51f58,d8ed16e6,99a2294a,b2f4bff9,2fa2d1de,9883061,4ed4b5fd,5b243df,31c3bc95,79c47c57,58eef875,c18bb896,424c0293,22d729a8,b7a32a21) +,S(fbced690,b601e450,2f0ed32b,8c2ac448,31c4b327,a4ad9648,97637b08,2f3d3912,3235804b,549210ae,8cb5bdae,e5b1b474,e682cdfd,8af4acd9,8c0c19a3,cb5c017a) +,S(75339a0,82043d85,54ff592c,186a183e,4597a0ff,48f280ac,d760d134,9dfc6b5a,dbf1aaa6,8bd5db0d,8cdcfee7,de6635b4,b7877ef3,6da38418,5688fefd,dc584b18) +,S(d83caf1b,2994a763,77a2bba0,3c644e48,7f170d5,845a7d17,b8be8bb9,84b0ad1e,e479d930,6d2a405e,f0be6418,3d4f8dfc,a7f58ff,95df1e38,c92a401f,17745879) +,S(35fbbe06,39d9fc5e,d595a67f,442d7adc,ae6f566f,4641fb76,149d6c74,42af49b8,5eaf204e,6217ef53,1ab09a53,e6cf4d12,46d6c4e6,b71ae8ca,4e821474,94d00680) +,S(d5563a62,bd6fba1d,e252a5a5,9c03bdfa,6c570145,71cd1a31,bba43700,2a7c1251,2f83b6a3,2efa7b70,1b4d3262,9e7a8755,8b681d17,cff0b992,1e102b7b,f851f543) +,S(8f2a2a14,a834ec79,107153f0,ffaf8f46,5cbb46c7,5a72d07d,5e2af498,f3359b75,30ac7456,5c946e21,73bdbd9c,dc999e79,260445e0,dad2467b,97234789,a4de1184) +,S(74482ce2,45605bdf,f7d586f3,c2e343a6,8f9579f2,543f7f7,22a4b352,24361b4,b2cae040,9ae59ee9,bff4fb5a,34847ca3,e4acd880,e35e4d5a,5ce47b70,3cc565c7) +,S(ca0c158f,cd362d9e,3724bb2b,f07305a9,5adc440d,24270efa,2a8f208d,7f540295,9e1daa26,5a5effd1,29f62b,bf0f5c60,c0c2b73a,58ddbd99,c832125d,3927e7ae) +,S(9c5403ab,b8b04f47,5eb4ac6b,5d526784,8d237d3d,c36e8698,d59172c8,a9d9e268,89cd0c87,9d02beeb,ffb6dc2f,fa882711,2071cde4,ee71a7cf,669f64b7,d463fbb5) +,S(e6bf2997,5eb88332,64169169,62f49080,29072e85,797fb699,df05526c,c4ee0de9,ae9de06a,1952c472,6047bbb7,b967e6ac,db33a123,24b07165,d2caf737,3fa40068) +,S(ae4ec439,e4392deb,5e1b1565,2310d52e,9cf5c0a9,8753a95d,d7b51e1e,5889a744,1400b900,c3159d2,25ceac35,4e566d2f,4e6f057,f4664b8f,465b0f53,2ba61852) +,S(c6351ec4,27d1d6c5,64c05959,ccee21d9,b086a881,3f4d7406,ba8d0ec8,6cd139dd,b7173d5f,bec7a8da,89c4cfbc,a911687,f39a455a,9293640e,7d473bd3,ef2dba3f) +,S(fe44937d,a54556c2,a50d9538,98abc367,6da5d722,6c6d3379,20092042,d1219cbf,c5c2e2a3,174fffd5,74761486,669b0cab,5a5eb21e,be669ba,c5c5a4a8,46e404b) +,S(760dd500,b18aa066,19a3977f,ddbb6947,d092649e,485f2b6a,d26d01aa,445588a8,cac47a22,6da2825,38126d62,38751a4d,93daf13a,420be353,3fc0f7ad,db68c20) +,S(8bdd111c,e271b136,45d00636,f2d33c92,df570cbf,6bbdc156,69fd898c,ce4ea8ff,884f1430,8ab84796,d61e557d,abb4d15d,15114c0b,dc770388,6ca3ff0c,622df5ad) +,S(406c6d3e,79fed3cd,16d616e6,7fe004b5,4f589594,ecb7ca6e,24210224,c5b4eeb5,aeffee19,f82cee83,d4796668,8545f0b3,b8e61877,f34a0b23,c6a3573c,b98c9b7f) +,S(c645ea95,2580652e,8e05df6a,3d208df0,83e00eaf,50cd7d4d,a7c51458,324a41f5,8b4b9cc9,d3f00fce,332d2ae8,2874787a,6c6c8008,a7577ad5,d225f951,82e8bd2d) +,S(813cd833,dacd8916,76af5b48,5d1ff72b,df03f2ce,c7657e6d,249e79f1,f12d7476,c364d1ee,f5f1d5f2,7438c58d,ee926c18,7162cc71,383e9524,b80cbae,3cea17bb) +,S(fef2337,cf88e025,d70e2a44,e68c22bd,95371f36,14ad9009,f2ba8286,290495e5,b622fc00,8b0a0f9a,9a36ddeb,ce10d871,e5dcd7e9,65ed2784,21ab5891,6aaf7404) +,S(8505810f,22888b4c,c8bb708e,c1e4df79,a3a361d9,5ac2b259,acc18d68,e50b0952,b80fd8aa,b7196e00,3fe24ed,fc6742d3,e7b2115,967f838a,2ef00345,3dbd4d34) +,S(b7aa2500,c77effba,3e93a4e0,b09a0f52,92240fef,4282cae,4c8036ab,2e5e5561,85823a06,1fcf2328,2dde378,8802d211,fb2cda3c,316dbba,d30048be,1295d7c) +,S(6dd2e626,181f0007,6ed53763,32493f55,a77cf5,3c268524,2be805c,7da06c95,2a6a76bc,b3f96c70,78920303,c5ed3208,170fa969,6c5264e0,c3cb1d86,ca322da6) +,S(ff5181a7,ab79b40,a3afdd39,8ac729cf,e49a6a23,2fa46f9e,4ce0bdc4,696e9f9a,99c20ca8,b11b6a05,47e81074,8a34c606,140eb3c7,ce5c843f,60203249,62858aad) +,S(a5dfb758,32aa580a,790fce58,b4c04a1c,9de648f4,19ec33f0,92491275,e8243ef7,78a66f07,e1466785,edfd5523,99fd1935,1ccadfb,e3b25bf9,d5279ed4,1d0b9fd9) +,S(fc5e4688,ea6e4553,610946a7,dd3497e,a5f698b,82d6b439,6a21e082,a9aabfce,d1b32a9d,761df7cc,3d69b5be,d7aac28f,976be204,7b2aff0f,2824fb00,b70d697a) +,S(179fb126,a3cd9931,f135cbe7,2604d3bc,83cd986a,d9a7900a,17436875,d3507016,dc2a57cb,b0bd39d6,c8daf32f,fbe6b300,52cff0d3,12e84b72,c00a7d76,3578e749) +,S(af37b7e,cac16810,9c51fe45,b2d6da7c,3505c1e4,bdc88b10,5a386fcf,e30a6c1b,4dc24b79,61e9199a,f594974,32c9352b,4ca9d735,84dde4f7,a4c0127f,21cc17f1) +,S(62d66f6,b534cd8a,66236ca8,5b7de9a1,eeb49aa6,e65e5298,edd1a99f,96fb1dd1,83c05dc7,e69dcb3c,86dab3d1,153d93f3,e9861239,6e25d3f6,6a6d637,248f237e) +,S(6a40f396,1587f5ab,89280eb0,568ec9c8,6958b4d,d8a379ec,2ce2489b,7e451ece,74972d6,1100a0bf,7751a400,6093ec78,1fe16c82,baaf0e69,74142a17,a405da36) +,S(2838f8f0,c6e20e53,9ecba383,c6e07a2c,5022d436,904e5da2,b91b283e,40bbd6bb,6bbbf962,2b7c41a4,6b72a30b,d051551e,e1227362,b0664dc2,509404c2,819b4985) +,S(21e927c2,82cd4635,c9c19c00,f18ddfe8,7aa9b60f,f3000c3,2019871e,a443333a,6834c23d,e05bc59c,f6fc64a3,af61f049,7c247d86,f76a2ada,7771dd16,999febb1) +,S(d9817ec8,f88f9cef,92cf9df,1fa9099f,3f10ac61,fa641ddc,9f36e854,98822571,53c57b49,4d84c3e7,679060b7,c7c8d4ad,f2db0c4c,c8cabbc7,5c29ad15,80b963a9) +,S(6eaafe92,1994519c,1c61bbcc,c1ad6ac6,f7a2d0b4,fd88354a,6a458e78,17503e30,f29a7f85,f3e91dbd,9e011055,f47a5079,7f55fa4f,46a6b188,ea4694d5,a086b4e) +,S(2bd45f,1625722,2352b5bd,a6d8e2b8,e7d23c3,f8497fe7,348a8d59,97b5cdbb,b5f9d5a9,8ed6387a,41397e54,6b3ff76c,4c6bf446,3093e979,2d1f8748,7a6b725c) +,S(176d02ae,cf4f1313,ff804e22,326d6a13,8b641e2a,3fd4d38f,2c27a35d,f1f456de,5ac13641,d2f19a4f,77097a4e,8eaae498,2afe9494,9188e411,e03ed031,fed9eb40) +,S(6d0bfca8,6296255c,1fede5ef,8d04dad1,2b6625fd,7bc127f7,3f6b82d8,b257ca8c,3c5c434a,81c17be8,8101b5d5,ead55e60,9d9dfb10,c5ce1b41,484d5fb6,f595fc10) +,S(b67d3fe4,f6617324,a4063fc1,142ff4b8,2a605a26,8b8fa146,697db96d,570ecca8,63ed93c7,a95a0ea2,9ffd6090,5c096042,b5562997,4957f47b,2d5bca14,21114bf5) +,S(c171bc24,fd80dd05,4eb3e3a5,5f50c9a5,322989c8,a1213179,be4503d0,2fb1f1a,2ead84ac,7528e7ba,982fec81,4b68ff7f,7aecf675,281f126f,9f41a7c4,5deb2e03) +,S(c4936f57,96269373,21abb8d7,df07e4ae,48ae1f18,ee1f8ea5,6682ced8,ec911593,52ea3664,1b441154,81805582,dcddf216,80eaadf7,4fb324dc,67439b03,aaccb1b2) +,S(b0a38c84,ecc73fce,200658d3,cb43cbe8,e0df114b,5d1ff7a9,33158b67,b404dae0,40c381dd,fc600cfd,ff24d7c,988cd4ce,74c18fe,130f4248,2ced320b,b91f2ff3) +,S(1610da0b,300d59db,d8746d5e,17d71ab2,e7e9c1d,2b43b688,656e570c,60336b82,8923b2e2,fa3fd34f,eff4ad22,7f9f6638,745167d8,fb769b34,b3bb7e12,a25c892e) +,S(f6723495,10cb5b38,da909d65,333adb86,d22ed855,74d24d35,83294cfe,ac88d999,6f726bb3,891187c6,3c74392f,a1e3ffea,f55b9a9e,76e3b584,1d13dac2,e888c740) +,S(3cda21c1,d048a768,d2863f4d,1028459b,c9a91c31,2626940c,f762c074,23d85796,af05c34b,4a15e00b,b6ce97cf,501316a0,85ba33f2,cb536f27,324f5506,54a8f03a) +,S(24e1bc3c,84c0ce3f,52e1443c,1ce82330,b69bbdca,f09724d7,e616135a,d9f99c0c,61385dc5,e5c36e42,275109b7,9c22940d,3ee4c679,99802e67,3163c114,be7fb0eb) +,S(f9511548,94dc4fd6,e2907990,7da4a5d8,ffff1eba,4fe12201,a3ebadec,2620a2fa,d40669dc,1eee21c8,ee1110c2,def5de0d,4f08ca55,6758dd14,b6f3ce64,46b2fe4d) +,S(c6808c80,61dd7e3,f6fb5ae,d129d23b,c2101af0,130537d5,4bb99baa,1b8ee268,2fb3e2aa,77870909,993f9d91,bf670cf9,bcd5abfe,26ea9990,6f9805db,c8707f84) +,S(ca952b81,f79a35bc,effc9f2c,c66c9928,cda6330f,42c44f9a,3191ea5b,5f473c3c,aa53ac41,f34fee5a,2028f7fa,8ffd5106,23cf2dfc,cfe5a1f0,99ef3649,d7f846b2) +,S(679c1de6,521c29f1,9b0d3c5b,ab481e53,d01ec2ca,c719fbe4,16054bae,593c0592,61d4eff3,5daff1f,a4bb875e,bbb42722,9cc996d0,405c74d0,6ef0c6f1,31ade7c7) +,S(6f7ac468,d33618d7,8c59d849,3571abb5,1d445a43,af10fbed,c5d25b13,58170f76,9187ac46,f2076aa,5cf4de93,52e5437c,4cbd2220,d8070172,807e84c8,10a05090) +,S(f4ce85c0,86a4fb78,2f081fe5,379984c3,1a7aab89,ef9ac386,a6a8a11e,596278dc,89d6d9d6,75983a6a,d1dc4c45,a3dafc1,cf951dde,2a038261,b414eb94,f9899886) +,S(18b0b225,19360c19,739623b1,7850107c,32ca6b61,295a8161,fc9d2e1f,8d1e60d4,4d8fd58,98ba10a7,3aadae04,a9ed18a7,8c48bd94,7825f0f3,b42685e0,d391dcc9) +,S(3f75a866,537d022,f6b9b18a,330ecdc0,bdfa7aa7,5b213f4a,876705ff,635d8eb,fd0f335b,b4f41615,7ea2752,2b8aa40e,dcdcacbc,1beaa051,97ecc250,f0782cc9) +,S(58310e74,290245af,c4acb91f,20b29db0,f5195039,24b9f76f,16952141,875d0124,f79e457c,364b374b,43c8d6ee,b408cbb2,94fe8eae,c6914427,83a74757,c8b27f98) +,S(90692ace,4fd3c4cd,3c808952,d5ea0781,2192c807,4619b8aa,4274426e,feb7f6d4,3147db2e,7b3b8506,625c21bf,8803c5f4,e7250b0c,4523a6bd,e25e874f,76d1622e) +,S(154d18c9,6c441173,ba7b8d2b,5099d9d3,92ae7e0d,57419144,229697cf,52384f73,1c196518,31ad8cc5,ea72b3f0,ed0d30f,78b773a8,1f54fc37,29043a35,6fde93a5) +,S(311ebd4f,5f52bdca,290dc97c,73102ecc,421a0b07,4c53c052,11b0bfc7,3b6eb94,69d17492,eca55f53,72b04c34,6696454,ab779ddd,8c7eb07a,34c8971c,b5168019) +,S(f62a716,6976f82d,b62e48a5,1eb45464,c845b71,6436d639,a9aa0a06,feb57d0c,a0b93a32,3fc8c047,3c4198e1,5ab5f499,e3eaa4f1,4bf99a69,b3ac303f,34839448) +,S(c23e0cdd,5e39eec0,d3ad195b,19294bc4,30c11eaa,67c6e87b,a4e2a88c,60998ed4,a521d1b8,8e409682,bf7b7daf,ff45f697,6254b8ce,6c63985a,ad2d9cfa,559208fe) +,S(742ca7fa,a8b4a98f,28040f8c,15db6045,70353954,b862c223,c7979eb2,3443ebfc,251ef412,e97a7e21,292ad45e,46c40774,b97a78cc,7826e45b,cef481f4,a64b838f) +,S(622a14f9,7bd04407,63eb5d52,c15c2f3a,ae185395,e89dda70,3cc4c439,60c5592f,e5db52cb,ee60b303,69da59eb,87ce10c3,c485c239,ae1c849d,32e0e239,df4d4d46) +,S(3d6dbb7b,4e28da6,b731c67a,6c038107,c2ec325b,6b10e31d,9b7d5273,fc81e20c,f0b619ac,febe82f,8c4caf5e,6d4710b0,caf89c2e,1a20073d,66ebe05d,69fc2c9f) +,S(d450d441,bc191b5f,9c2556c5,a56d20c4,48afec13,c7e4b9be,320ddb90,b4c320e3,661be65,b5eef8e8,b357f521,d360379c,585c9e71,c27bd038,f2d63f72,6f6606af) +,S(82f9dd1e,ddb046b2,2b33bf19,2970e41f,c5df0c45,f1375133,fe1b365c,eed1ec7d,cde9eef5,554476e5,e775e829,1d38a572,1d055c4a,925c7eff,35a389b1,388e18d8) +,S(5227c547,834a79e2,d6fb0c3d,720661ac,7ec0e2ff,5a1480bf,3f31ac82,cfb2650d,dca309ff,621c591d,aea1bada,bb1be76d,2fa30a0e,1c83b4b0,d66cbd59,7612c0b2) +,S(3eac813d,7e2c8034,f1d58217,c4372a96,a1fcae27,b29ed9c4,e870034f,7faa78ba,94005cc8,7b8f7aba,143573b1,79aef942,c1519b3,9c63b58e,e420a875,7c4c8b80) +,S(9373c48b,50fb0243,b42762e,3b80994d,61986116,ba2c0677,a38daeac,7dcb21a0,295f694d,70f8295b,cddc1c76,141ed17c,a1cd8e5b,79909785,dad43e92,9247b250) +,S(14019457,db851046,42b51ece,50fb8d94,201a80e0,f29d52ad,1af35e4b,8d82c6a8,c47d97c9,df2816f9,a6147dba,7658b5da,f9588dab,8aa393c5,8f721786,9c498b9a) +,S(1b01f484,ce98064b,f60333d3,65d926fe,ee1cead3,c1497c88,8409be91,2288890b,6817b86a,86c98512,634bf90b,564ce109,13fad61f,c807a256,36a5d6aa,7f2d6005) +,S(5bad5660,f615f36f,6bb9ff3b,19c07b74,9519caab,fffd98a0,4520802c,88b6cb22,4d23780a,e6796a72,324c369b,1987465d,90540788,88987513,13dea0cd,69f90dc0) +,S(7044bd7c,29d2a7cd,d662bf16,90d5ee35,93175691,b62d68e3,f8f66ef5,8304c509,f263888d,52d74133,60ddfb1e,d1c09b9c,871d6eb1,e5833949,13d24973,5721ce12) +,S(186411c2,f90c5402,6445dc4a,4764318a,f3acd811,52c01dcf,d11d13cb,a8c02afc,462b9556,1bf18dff,8a4211d8,89f420d2,122c4ea9,7fda3d23,558b6304,d25b7aa3) +,S(62ea528c,185fd551,745c1512,6fbfd40e,5f8933de,4e1e3b95,92a93b0e,b762ec3f,276da42e,3c8a6755,6be49e00,2e42522b,e3b95e15,39a4708b,36429a94,4f6a86a3) +,S(5e2c7621,efa587ce,bd3c2392,a1b8dac8,50b15316,c42570ed,7270b521,a65d6cc0,c7faa23f,eafb70ce,723338d8,19bebd10,bae703d2,1e72b496,f2f95b6,e83d7d22) +,S(7e27207a,b80f124f,9694f143,9a0cd895,2c67a719,4075d9fd,1bb7c9a5,a22dfa3e,322b729f,e19d75f5,89749527,80f3ae04,48edf9e9,d8c24267,18812dc6,bef5e602) +,S(3de40b43,9077ea26,8d94aaa1,93e9c7cb,98e362a1,551b9b10,d5eb64ce,15986582,ba36c2b,e0f9d3d0,220eb47f,4ea66d01,59236411,2898172,8582d3c5,19576943) +,S(81e94808,7e89846e,6c7e5ad4,feb8f0da,4553e460,e3e4620,d87a206c,9d3232b,e216962e,4068a44,920e6a9e,f03efd5e,afae7f96,3497ecaa,dc741c37,7e9943b3) +,S(3056eeb0,d00a19cc,bb5a2ac7,f320ea3a,4e931187,498ec23c,daadc820,a34f49da,c6803559,271b265c,80257585,1f0a78e9,85abeaac,cb570787,f398766c,aa21fed3) +,S(9b1e1189,752fb763,7a61246a,7134145f,86b973b1,e44a5e7c,c59998a2,77ed64f2,f6793c87,9b8c380e,65296c8b,eaeb98c6,b66e0be0,d03865f4,4a09177,5dcfd332) +,S(807179ba,f1f9ce93,bb1f7dc6,e3c6514,99077419,472b9d8a,1a8cc4e2,f35c0c5,36807219,9966eb7,f18dfb7,d3316eec,54f1a9a7,7214d4fb,ce3f3ff2,935e2ced) +,S(60dd7b7c,cbcab93b,8ecfa461,8cfef03f,a74bdd47,9cb90a1,5e46ca7c,c1bafcc8,1d24d147,9987f779,90cde228,22ea0cd4,4236875d,943eda25,fa25096f,e16b8ce6) +,S(19daeb26,23383b3d,d15b0075,77a5e92f,bcedee4c,91996546,a7c52200,d243e4f8,12676559,3d67fe33,b1c01d4f,cae44be1,5f5f5e31,1149962,83ce8f92,f6485e3) +,S(f42f8e1a,813dab8,9e4db5de,27445215,c0fb1cd8,91c9a96f,ca5ae1db,14e84361,3cd2ab35,55705994,42070743,d01fe633,34819d2a,af95e97,6dbee1b4,e3ba2ae) +,S(1a2b774c,d5d0dd28,26d7c4e5,886d65b7,a219952c,6a413d2b,9fa8f765,73fe2bd8,4e2d0ecb,384a158e,e57da809,d065e39a,27830625,400c51ab,dffdf615,5d88032b) +,S(e9fa7d8,94c55075,1ad1731a,b322fab,fd3d17a,889bccc3,73e44e37,b4c2c880,67528cad,e7987d12,77c61681,36abe0c9,5dfdce09,33129f27,ffa9d36,53673bd2) +,S(5347f349,e54c301b,abcfd8cc,50f6fe6d,8fcd0fcd,861757d2,bc36cbfe,39f460b8,16d08dcc,2a837b6d,f9fe2ffa,b188a966,9d39181a,ed2aeb40,9ed17c8b,554e9d27) +,S(e20e8cea,4450bf03,149bdf60,e95f7ed3,69fd79d0,aff9fb8c,ef6e5287,830c7ddc,fa256932,fcc569e2,613bc0af,5f90263e,6db633f3,6cebfe46,4c70b043,9b886058) +,S(69132e10,b3a919a9,8a7188b3,e9afcf6c,2d53859a,5955e114,a41f1310,55ef8441,e6c339cd,ddd26e0e,ac4a1c2b,39e19cae,2d67e726,8518b750,94cb5e6c,b525d84e) +,S(11e10c95,9bd9f79d,c2819a87,e17c0de7,9105af6b,fdbe3f6b,88d198a7,106c861a,27c29227,4a3677c7,381fe385,8382ca38,d4b98e91,af4250fb,40540828,246d5c16) +,S(785934d,e1b1827a,471d7e59,2a4c3475,3054b00e,b8aae372,444b00ef,d9d894b1,7b8dd2e,a038d4e6,23f0f1f5,a2f75dbc,fe34e76f,6d106ae3,33d88a07,56dc4a60) +,S(f09c814e,8e66b8e5,930f1a49,28b28e5d,206f4108,fe99f04f,ead93096,1cc17605,469bf934,b4059a4c,4a942214,e1d86fe6,dc900426,c7d0eddb,8d89e86c,76d60f24) +,S(732901c7,26982b9f,ff1229a,3e8f7c83,2f47437b,412d0b3e,274a73e4,24ad6480,6b82e2d3,d4830086,cf416593,9b04ff7a,89b835bd,81cccd8a,7a29d47c,b70da3b7) +,S(b8369a11,d23ff4ea,99ce166a,4708ab9d,389cefed,b1843d8d,6fc11f74,7260faea,f4346c36,63ec0ab3,6ac12df7,f61e9848,c2d4cbd8,c8e6e173,2d104d0b,aecaef9) +,S(5499e409,3df85dad,411b8675,c09d0c0,c25bfefc,2afb0228,b94f834a,34ff83bb,7775c877,8fc6e8d0,519a67a8,7d2fe9c,c8abd8c1,15ae1700,ad1a94d7,925a4c78) +,S(fa5bc8e6,fa9b13e8,ad787ba1,497a6b97,5c34a64d,a0da5b5c,836bd71b,88c93740,8c919cc1,19e45de1,54f6d0d8,f22d3b51,169b3f0d,181bb40a,56213cfa,a4ad126a) +,S(a871c481,a84f4447,89ecded1,e2b1f525,9b1d4ab2,b16af331,199f89f5,730cdb0b,c478609,30b85d69,1ae45d62,7aeca01c,9f10a119,500d5d4a,c317fdd7,8de4a103) +,S(63d3be27,66d33bf8,f7a38577,aadd5d9b,234bb77f,d206b056,379e023b,ecd25616,9509d09a,6dad6da0,aa5151f8,dd8e3800,abd8a799,2276ea0d,3c958f76,498ada87) +,S(413ab945,c133d383,d70e81d3,34bda75c,be7bacf5,e49d71e3,7a884489,adb28f8f,c3d49f0d,6c65f6d6,1c9c84df,a4138076,f0168916,393612b,837c1df5,df710a02) +,S(df070f4d,ce208b39,e2614db,77c6aa32,2a50bb26,2ec7141a,b1e26835,911b85c2,b0b1f453,1815fa7,83609235,da7bec0e,f1bf2ad3,b0e71f7f,7c18de8f,83f55a3b) +,S(1ae86e7f,300efbe7,8cc933c,f8cda339,1f0f8f7e,411e6c0e,708a0d75,a1ab1815,d322b34f,f0778782,7d2da5c1,4d6bf17f,f8afc8a1,8051a724,bbd719e0,f5f31a2b) +,S(2a38dfd9,ee86308b,e0c76ca1,8dbb9ec0,fbaa86fb,51075887,9283c070,f31106a9,69cb45,94832b55,abd6b686,f67d493a,9d45e4a1,7d557723,fbbbbb83,7ab30cc4) +,S(2c6d7ab3,b1c3301d,65c79d40,583b566d,3ee39014,345a4553,a77a8e46,95b779e7,eb392dde,318bd27d,446b814e,73f9cbf1,380e38d,fed25022,bd584585,d671e470) +,S(758739e8,2aa2e25e,b1d8e027,b0e401b2,c82db2ca,549ebb9c,e1560ec4,531c5c77,d3792987,c3da2cc5,5760e52d,a19ea1b4,d0c2cce5,3f612760,bfc28414,37090975) +,S(7ef11cac,99fcb66b,71de229b,b34e82c6,e3149f85,ba1ffbf7,f22db64c,6a72588,64d7c546,28892864,1db41465,a134cfab,bc08ea64,11f5b2d5,b1de9f0f,7ae41b70) +,S(a7d48b06,c66ef847,f17b4b3d,ec40eb97,cb91bff1,c06d4a6,5d6db8c3,5561e4c7,2f22aae0,d6eb7221,d24f025d,ad1768a9,a619d6d9,db9d8e74,948d9263,3d0676f) +,S(a14d7354,1bb93625,d80f654,af67febb,d774e42b,6430a14,a907c52f,84088ab,adfe7f75,2b080bb6,89c031fe,c7c11d1a,bc303b7,f1a0ec2,38a4dac4,afbb2a5c) +,S(16076f95,b067381c,9d71cc9a,928f10db,43553332,f747e33e,367cc7ca,ffaa5f88,5c05040e,43a29d4d,e16b5e42,b672f618,8f0496ef,f307c269,13df7c79,ed2b1502) +,S(973450b4,a297ebf1,70630a71,fa74ae2c,8f3f8e39,18ff73fe,41bd1e65,5a5acd29,ba04c21f,e92ea639,99d5d87f,77181c31,ae8ed87c,dca22054,2f746fad,61f63039) +,S(aa29f7ef,d2f06187,108ab23e,16d9f3a7,74ab6459,550048cf,e1ddca0b,45fb5942,431cbd5,c77b31b4,d8b8568d,b092e721,a02d643a,75621eb6,1016b363,9728e2e8) +,S(bba61b3e,52614d14,358dc227,e0c0ea6c,e4dce364,fb7e0500,72d0d780,14642d9b,f33e0e72,6e9ee195,21fb4a80,2510156b,230a7ff,6e4c6b38,cd38b3cf,65336d6e) +,S(911443a6,979ede22,f23df6af,e4b1ab,73867dd7,a47e9268,3e3cd83f,241bfacc,a0e5be1d,31cf0375,7c2469a5,90f3493b,e43a99e2,755af9d8,b87aac67,ee7a6488) +,S(ff2126cc,5698e6c1,2da7f441,b031ea11,30132b86,23994f64,b332a8f2,87616d41,c616d5b3,79eeaae2,b072a11a,d2b316c1,b2c851d6,698b6d86,7fae1abd,482e91d4) +,S(2fe68e9d,de151731,12e1653a,2a6abce7,615062fe,a5375ef6,a2be1e90,67f6d8ed,c24e4b95,718acdfc,cd9f39f5,eca6f2fe,74fe7f9b,ae6aa352,e3651bbe,5d81c9b8) +,S(dc08aedd,90e96f6b,892ee62b,1f719619,6af44975,58d70f1e,7294863e,271ddb99,7250d846,1ac24a2e,e74bc5a7,53d5361f,8c012986,4364d84b,4afe22cf,c94aad99) +,S(e9c21052,f350d1dd,caa82594,b6eefb5b,f8f01ec4,1a423278,fba3951b,fcc7eaae,6992071d,becaac44,a5cd1537,cd066f2f,c432f198,621b70ab,360ea8d1,35757784) +,S(110d5ac,7838b9d2,d33bdf5e,8aed8529,5ceb9334,d409074f,3c26e3f9,f0cb792c,7879e339,427d8425,b597e76f,56a7a6e7,9a8cb00b,374ac98e,9cbec66a,47bceac) +,S(92982af9,ab48532f,cf2ece2c,9ab346b8,7def4729,8ebcc03b,91869aeb,42f9bbda,c6bf5a6e,8639e2ca,772e8c36,5f824b3d,331c7be9,4c13e9a8,ae6a779e,208a157e) +,S(c3f07f47,5246bb78,eac4e9cb,263c774a,3447acce,993a9707,14c1b553,79013162,f1931fa5,d6fd228a,a5781b35,45faba70,df6bca90,936acf17,f81a1155,4897e136) +,S(37640e7a,eef3f326,a598d363,df4f46dc,8f0decb5,ab6e368e,62294c53,ef3fdc7b,54fe19ac,83a074aa,796feef6,8d39358c,7be8848b,433e1eaf,9982701a,3eca7a1d) +,S(e903363b,6c90bd,2bf15176,83411d1d,aa9f0bb4,a22b5f03,ebbee32f,8f0cdf4d,fa44eae0,78b4b6fc,63abac71,ce0a6e0e,16b42d80,94179f1a,657eabd8,7eea2480) +,S(3c5fdd9f,7313d178,312bc477,849ce90b,a22770df,867a815b,2bd1d1a0,600afb6f,d81524ea,9e23ad00,bd7197ee,63457745,75795d6a,63b8b15,a19cf606,72159a05) +,S(40b540cf,43713ef5,c8b919af,6c991632,e60c198a,677887be,33b84c70,7c0ede8f,54586256,7352c824,49ebecbe,6eaae259,8e1cf694,fbb296bd,c14a4a59,240798e9) +,S(67da332f,f57adb72,8eb8b926,5a650e23,bfe5271e,396d74f3,9878c22,6f912053,91aec263,d7b74e09,b4fcffa4,87cee236,356e4fdd,bfa257c8,f3e3be0f,3a3b16f6) +,S(40cea066,fa029178,5662c994,db5b1153,e59fa121,c9133c2,fe1c6d20,91d44d98,61475cc7,a5ff5251,558f258b,aa8d69a1,52ed6497,c8ffcd55,2b66baa5,534df64c) +,S(c4eed050,248cf186,f8e2c079,870a139,c0cb13ed,2cec040e,d98a18ca,9b67ed0,50e9997e,263c7441,9e71405a,4d342e76,c5548e,1a7a3cc2,97e4e00e,91fc476c) +,S(676b60d2,14e309a6,8c7a8470,70d5bf62,8b71b7fd,322ae568,56fd4a48,9f3ee83,16e0d8d,371ad6bd,4713e9f,7c5f329c,72215cf,21a48527,35a0df71,205b733d) +,S(af268996,29117c69,c3beb193,c5cf7944,d4d3cc1b,7481d08e,1a190b45,c03e1fe7,359e17db,bdbe179c,8cb75ead,8a0e3c86,2b1d7d28,4aafd2c,e45e7b9a,c6d83ebf) +,S(62e15cc5,a30d1388,2b3c3890,4e1d11db,97b0a7b7,c658175d,e438591c,ed1ed489,fab66c6b,ab7b5ed5,815c81ca,65cf364,f4cdf8fd,7a6fe8e9,ab5ceb66,3bb4e8f5) +,S(6c7af496,df980977,41f5068,f34d0477,7da16397,c853539c,1b0c1263,2e43ccaa,4eb0e461,5c6fd9e4,3aa05201,88bb264b,d55b3a05,fc2b6c8c,d6f5f51a,4314f6b) +,S(757a45d4,4c662311,289be914,4ccca5ae,6ef89f51,52d66a2a,9be64096,cfc8fba3,732ddb9f,62fdf217,44d7daa6,35ca3e92,c3b84061,bae4c220,13339e06,fd4da7e0) +,S(14978c08,f1eaa9ce,4d878db3,29f0bc94,43301fdb,24b525e5,4f9f27d5,7fc114f9,439d8e8b,2b9fdc0d,85914620,9c883731,26e961f6,82407867,b10bdbb5,3074e5b7) +,S(3f231c93,760d9198,4a8d9adc,abd83c1b,3ae620c8,f067d103,6d1e5e02,2a72bcf9,95eb3a0,a928d3f7,dff3426d,763cf6ed,20d6df2f,c5dfb17f,c53ce0b7,90412bc7) +,S(c90268ee,75cc8e7d,7fe84298,b1db4255,80c3c45d,3643a280,e3d5d0f6,7337b616,f566fecd,1158d49c,c12a1dde,d0b1fd7d,d9cafbb6,ed3fd09b,48689f85,b01cb59) +,S(6457f0e,4d6cee8,7a2c0aee,85306a02,42c017d0,1e1c9807,5b460732,5c1d82f,67bf2f81,262de4e2,ba9d29aa,aecc9315,ff56c3ed,2e73d438,2a3dfa6d,faf9808a) +,S(ddc591c,1abcbb88,3de13bc4,490a66d5,3d96c97c,f1e21ae5,6a430c1c,39b1b629,80ae50f7,b81f043b,e3db78c4,da7b6078,871d4813,1e076ad9,de59fb27,b942f72e) +,S(22b19bf0,5efeb280,44b43bfd,7a6b3427,2e8b3c1,f6635ec8,d6966a,6667a252,47f504fb,ef2cea6c,8692d0a5,1f492560,151429c3,e522c23,2914e880,9ffdeef0) +,S(d5883bd6,c13d93ed,50371ce6,ed6c4263,395c5d28,f589c84e,cb9fbfc7,2dca651e,acde7b79,969cde2b,9a580387,d8e3a99c,45f15d38,f2e2ed79,688a3a95,80aa9a8) +,S(9615736a,4804dbbe,439f2f82,ca576623,a1675aeb,9ea9e40e,f6b910b6,c84af16b,a0967216,67f9dce6,25ce5331,62d45477,31be7427,74eeb1ec,4e3fe578,343c46be) +,S(ea36bced,959bc461,95e730f2,26224652,2472c2c5,70df6832,befa40aa,5c600e32,dd52094,82eb08c4,bc233090,2aa54333,87d06885,a9357f40,246348b4,4d97fbf9) +,S(44814860,ddf61b77,77cad443,18c21686,85c614b0,1c5830b3,b178a52,d85539bd,f3e5fd15,c71050b7,280643dd,bd2c55b9,219e7fda,cfbd2e98,94fa9a4c,9cc7ce75) +,S(814454b,cde86996,56b44c39,69bf0a8f,31b6d032,40098f9e,43d52266,cee66f49,8baf21a6,601db25f,2e18f5fe,decb9f31,9a6378c,adbff6ec,99bfa2ff,8d26b5c6) +,S(1ff790f1,11f7bbb5,b6db5f83,22ac696,c1de09d8,e50b9f4d,641ef76f,d43fdad,145d0aae,c218d6c0,219ce9c2,313b4962,f873c5c3,5424d3b,536c1543,14fa9517) +,S(275cc6c0,6a8faf20,c3c1e88b,87e27d35,661c6401,d3a1bd96,18cb016e,fdbc6d0c,45cc522e,97b61ff7,696c5780,638054cb,5e97b6d4,fc4a813c,7000a633,4e9f2a7c) +,S(9c78cd3f,874afab,23874f0c,8a84fbc8,a6d032f6,7fef6c6f,29c90513,bb6926f5,818a2406,fedf958f,7efafc4a,584ff6b1,7bae1b65,f67d1086,c3e013a2,cc318b1a) +,S(3c060395,f2cfe9f9,e3bb4afd,e5a71e03,c5a92491,323de27a,c9ebe1b,170153eb,344d08c3,8021fea2,6f55c0c5,85af3954,afda21e7,14cdedc6,8ffa3771,43b2ca27) +,S(f4b61a9f,7392b960,752bafd0,ce521e4e,57bcb898,cbb2dd9a,b0f7db8a,3ce5ff2,e412589e,f3678029,15813dfd,acfe8056,2a59894a,4c87640c,6044656c,e8998d5c) +,S(418698b7,6230acce,49505275,a0c01e9,4eb356a2,e3c242ff,470b64be,fa91ce85,cb9dfaf5,4c64ed94,f97e03d,30e07876,9e5a3142,d0fc0902,5e20ac2c,21c4ceeb) +,S(809cbcd7,91c1f309,864ca343,3d9a11dd,2db3d9c4,5350ac5b,27f55e19,b9941ce2,8161347a,92fdcb92,263f1d85,2923a15c,42d5012e,30d7d9b8,623cefa6,12b06bf2) +,S(6410c007,1d1025c9,8ce11509,5359e962,58c6a115,5e7f34fd,30fc8862,f9569f23,d76363d6,2661a55c,6c211bc4,13b1dd7d,63fa6964,a03d9461,e2870f2e,54c87d29) +,S(8394abff,22ef6051,7517e352,12a4dca,103a19ab,4091c7e8,fd417a,98fcfd2e,20d0ad3e,bc0fd15,fd405417,61bfbb40,8e37975d,a77321b,67ad2ef8,35732c0b) +,S(dbec1fa7,765386c1,d7558cb1,f19788bf,ce0e9fa4,7ca41edb,2f2d9ef8,78a04308,5d7c918e,335ef23a,934fc963,48dfd8f6,ce79885e,f4c463c5,b2645c8,48083ea0) +,S(9d6fe17f,3f53f921,893a422f,c9f675d4,652cbe09,a870c81d,8b2ab9ee,9a591cc2,fae9ccd0,b22ce7e3,2e7faed,2d47c36f,25cac5b1,e56ea936,a6811f11,8d485a2f) +,S(622f8f9d,65c4270b,1479e4d6,6f82fbc4,cf23e7a4,d09a6537,22c20d9c,54f85f55,e87650ee,4d9ac5d9,c6566612,1b6e4679,7e52953a,d7c3aedc,2fecc22f,d5b76591) +,S(cb1db853,b615cb5a,b92d0340,7ad7891f,2e7b1d4d,120ba3fd,a1ea3565,ee1d1436,8362a39d,9d425eae,2451d601,27ac2824,3819da08,856d0db2,18f339d6,fcf20046) +,S(5cbc6a63,59d9d6a5,2ceb093f,ca5cae,f32892f7,c9d04091,8245d9ae,ebd594cc,c4c18f88,7436575f,39b9e7c3,27c4efdc,6a3490b1,23c50743,ef03b1bc,34566bd) +,S(37a3cb08,3a9b7561,78ff2128,e7a5b9a1,19577af6,61974869,cf555dac,ee2d11d8,1a8a6297,4d0b6c5a,12155e9b,cf895c95,f6fd2b1a,2776c32,8d6b56f8,32f114ca) +,S(8e0611d7,ae0914d0,5d39e06b,9b359400,f21c3beb,73ede92d,bcaa6d96,8a995b95,ddd4f522,d1c6a964,9629727f,52740664,43e80ac9,7d9c68e1,225e60c5,38129bd7) +,S(9ec34a91,8a4648f0,1c1d726b,51b1874f,36410180,8bee25ac,c159c251,fc115510,bc5ee2aa,b5e43b01,b34ab989,5f4cd71d,1d3e6288,915daa2,e84ed531,4b388b8b) +,S(dc19ec7d,c901e215,f6d0603e,bb5494ca,aa9b5409,67a5a339,8915c4cd,84000654,b55b9596,a18e53c4,b82c669b,92defe5f,bb5e58b0,3cd227b6,3b439b4,ef13bf13) +,S(51bc3804,bda51e9,d0c45087,13599f12,b9a8599d,6e8ce949,5a3f595c,7d38dc8f,ef0d6522,fe3a3c4e,64ee1092,b9ae8f6,e7847bf,94044693,a3ac7cf0,f4aaa37) +,S(13463b32,dff393d3,dfddbe3f,bd6ade13,190e0bb5,83e3f126,344b5e01,3105e234,ea3df1a8,b8270f70,24910f40,a519cef4,9944fcf4,d82a4300,63b2026f,8f019ff4) +,S(c49b3261,2e286adb,606686d9,67dbf4b9,57819dac,9bb75f44,8f1416ec,f900fa5f,ffe45b6d,8c19de7e,c08256e2,96667d89,f290f5d2,25a9e380,c106972d,79551b1f) +,S(10fe7aff,36a8f4ef,79e2d8ac,619ca92e,2300878b,cf21a271,70f89e9b,6294dd28,f67da70f,623fe6fd,2c7113eb,fe6458fe,d0d5471,ab639050,685a0fd9,33afd6a3) +,S(d56037f6,efec78c6,e31e633c,570c5e46,96f96276,b86d0b89,e993f014,53592300,2499b92,4fd99b5e,a56f9649,bd8e53c4,b2f20dab,9fc1de83,dc199022,1f606b37) +,S(a3c1d0c8,939cd4b7,5cce8ce2,f3be0226,589fb32e,55457fde,8e700a77,a60bf003,b9054f66,bf6450cb,782533b9,33190084,d6f5944f,cf4e06f,de72d483,144c941c) +,S(85d0c4ca,e1cfe42f,b5f73f31,42e97e6b,c0855f7e,db19b1a,8668e413,4efcd249,d8372bc,937fa754,b81631aa,33a8ecbc,a25f86d3,d5e0627,d6964ee,5c08e68b) +,S(3092eae2,d41d0ccc,10af9d81,fe8c80f6,9ae27c9b,74b5f696,7a69211c,8d6ef98d,153f0882,f6b720bc,c8ae5924,923e0608,d6163c3b,32d36742,68718d6,e7f35e4e) +,S(4aeb6ac7,fe874a0f,1c24681d,884d5497,3486f293,9b01ebd9,74c34ea3,429be71a,d7077161,c508a7d9,63006566,f652afdd,df87d0b2,8daf3fba,21f206ec,a94a53e4) +,S(729bb0f7,be975284,a68363ef,40003a6e,c770fa4,5d6e6b99,ab0c5042,da563f32,1e0435d5,ea85370a,7293396b,407da43f,c540aa04,24f21de6,a002f555,cccd4480) +,S(96164ac5,1074dce1,3b973689,a39b6795,9bf5756c,4de94829,66bbdd23,9e665fdd,5cf13b8f,56c92710,80c11626,6bce26c2,14a39237,9aa68ed1,b7a05d65,7bbea247) +,S(6d45d79d,9297bb8a,326b889,391b18d7,31af609c,67b31be2,9b4273cc,405e3f80,2d99909a,7b6969fe,148111fa,1b9c9326,97fb465,494a8225,a6c62626,555ed02a) +,S(70091076,b5b81f33,42170f0,4881c941,d2fe9b0e,ff156221,66f0c92b,4f9e8e71,7c676c5a,4fb434d6,58f635a8,20b454f3,4c9795e8,b8860d27,4d0fecbc,ce7824a2) +,S(d04c0a77,c8fcb3a9,a02df253,b8819853,63dd47ca,bc1f8881,88d5e56,87a7db74,302d1b96,c35a2626,22bbc6e2,841b5cf8,efb77374,af428f9e,d69b2b11,6993db09) +,S(3c93d2bb,7ee61cb0,7a25ef65,f3e22eda,6e74d2eb,f3ede111,b4f2a28b,b4f206d5,65ed4db2,b1647b39,7225741e,241310e6,7a47f0ee,4f459ab1,3d29689e,cef70336) +,S(8efd5a54,a4c7567f,bd971cce,7ce3006e,3524dd81,cb7a4ee1,a5c61e12,62961037,6b9688d7,d73db9a7,1410738c,80430ea6,ea329145,718b4177,71e542a6,93b494cf) +,S(e7aa8121,34fa1f75,efd2ff02,273becca,18bf1ea9,47d168e2,cadd6e9a,6c448425,8af9da38,e2471dad,128e004a,d7b03932,2976d84b,7c91f91a,af471546,dfa5acdd) +,S(e4335a32,b3218d51,9c582689,85138591,4b7cd8fd,4e4eabc3,b5f9e0b4,c3212b84,ccfbfb0f,50b5fe75,c849510a,bac5870c,3016573a,53eda160,b14602c2,42ca02c7) +,S(aeff696f,e98cf587,745adbee,3fca1ae2,3f8f5768,56bbad5f,4a26afe,904a17c4,55dfb880,250b9a5b,7eb971a1,fbe0cd6,ad2d375b,88d98e52,6afcafeb,7ac4617) +,S(72fdb2e1,eb120244,4b20bd6d,afd6d49f,46a56f25,63e679c5,2de98cb5,bc999a5d,e29f2,34ad3637,7b4a9cf6,c307b8a3,a779cc22,ae472aac,eb519c10,8137162d) +,S(eda9f183,f89750bc,8c12ce7a,fee54145,42edd9ae,9fefd508,ab588bf1,6c7da0e3,a9328c5,81b0cb02,fc09fcfd,2a57d2c8,fa313ef5,4e205902,9bcf0846,811be308) +,S(744683c1,2a0150be,1d7655e,b5a3fc97,4303387b,e53bcdeb,41dfbabf,ff12f6be,df2e4b05,a459aa27,2d3de8dd,4c211dec,e35eb798,67050285,57dd53e3,5b9950f6) +,S(9f3cabfc,106653e4,65daeb52,e86d99ff,e3ac6df4,5eef90f0,61226cc0,32592ef5,9f20d174,1b78c8ec,d7425d19,fc0a4c9b,1f1cac8d,b97514b5,8585901c,41862306) +,S(9dc15715,9f59c338,d56a7d9d,ce63579e,9e95424d,e6db6927,418b024f,ed95936a,278716bc,3e131fa4,75b9ac00,6e868d88,ce17e6ba,d7ecd202,33fbba0,fb34f0f9) +,S(b6c91d90,b1bf3b46,4b526186,69e1c118,dcf8d6f9,c8ca7473,5a361a28,b53c823e,15132dc7,69e59b7b,fe5e9966,1b82e47b,3ee4c3a3,1c0b8201,517dc567,ff90a4bd) +,S(56604a9,ab972c4a,f18d5f8a,d5cb6d94,2d0c841,a7defd1b,b94b1b25,c31df400,3d2f2a27,adc2eb70,336b4b44,5229e09,a74a113a,f1b21bd9,1e3f2351,15f6a85b) +,S(a5b57de,fcd3016a,917ababf,171c3c31,ed62957b,cd8d233d,c551fd9,6216561d,3731d822,155afc28,8bd7ed39,30c3f6e3,58a46f5d,d9fb3ed2,6d7c7da2,a8dee233) +,S(da179b61,81e27ecd,d545af40,ea5967ab,7c0ea9ad,68a8c0e7,4d4a5aa6,4aafa549,c5c97c42,e74f4991,55191cf3,3118f05e,19633eac,ff5ea8d0,7ec866a0,7fbbef29) +,S(42a0e864,1b594b98,90357e4e,8c32422a,19f368e8,190170bc,6d8abca0,9cf12f1a,bac7a5e5,baf7ddf4,934aaeb9,5078e0a9,c449de0a,cb932b13,a93f474f,52312d85) +,S(74c85e38,944e2003,435bf345,124656a,6a409bdf,fd1c16dd,d1246d45,cadcaaf7,bc18315d,caf237d5,5f3ffc65,41bf9ca9,f39af9f0,cdde6fab,f602e888,dc51bb7a) +,S(8ceda42,698e5995,40091f6d,f50388e2,7c229b0e,76e7def7,f8986b6c,af975e79,a8915f5e,7c524e55,5743c392,2b31c426,71fa938f,84679389,b3738af7,59e92430) +,S(f44e2dd3,ffe43da2,66fbaa1,990d1f19,e3e4e44f,bb565ec8,74af57d5,feeac498,c307b3c1,a90da318,bf928a1a,a8894080,29874639,ece7700d,4f4dddee,d005f6f3) +,S(7e30bb38,c9a603f9,d5fe78f7,453d1c81,30c140b2,1ad7706b,601d6b77,5c703984,49c9de1d,1d057fa6,b135ebdc,f0b5ad9c,f9f51cef,95a4cb7c,ebc11d4a,3bbb6d7) +,S(8e1e53c7,4f7e1595,b4a5f7b4,5b324f0e,435473b0,a61cdd8b,1607c0ef,d11e3c56,584781c3,ae8a8beb,f6cd1bb8,3938fb12,35994977,2d1facc4,240fa43,7bc241d2) +,S(63d0cd75,54bf2c18,bb180269,2d19b4a5,4acd77c,d2eccb7f,360dfd5d,4b9f22bf,ed79b7af,eee5ec82,e498ebeb,467380b6,1369802c,3dd995ae,c844d3d2,91ddd756) +,S(feef5d30,b382dd6d,a0ec0d81,b18ae45a,8dbe12c3,dd695648,cea27c14,7d075be4,20ba81b6,b48ebc6,b185d6bb,2fb7bea5,c6a011a1,24f49550,415eb8f3,cde3aec7) +,S(21bb575f,db07a152,5ff0a7a2,d7d2c189,742df276,9306bc7a,30c2c3df,f2125b94,8ea74299,b7b40a93,3db6afb6,6577ce64,dd10d24a,89bc3907,1f656f5a,71c56953) +,S(dee2dc59,44cad7f2,310afc94,403067fc,5c1c3d2a,dde88ae0,55ba8bec,d6e5cb08,606542e4,5301a6ac,86c5c794,444006d,d77e2bda,11c8af0,6d883689,7a6b6dd7) +,S(4768a2e4,98ca0472,67cef4b4,18e6398c,81289c73,e617a2e8,ca021155,edc576d8,f8c574bf,beea93d7,1a2a331b,cee494f3,75c1bc3b,ea918106,9f1665fd,589dbc3a) +,S(53d75697,160c2b90,aaea7f95,ad24bd66,b5fd7681,f2802bef,d2a71080,74f66b40,4b04d94b,416a8098,144dccab,bcd8742b,13e85b2e,ec8817c7,7b7e5821,2e8b56c0) +,S(832f268d,ad5f3bb2,dafef9dc,f94bacec,b369d4a1,ffbdfdae,bd4fcd9d,77404e99,a6495805,c9b439b3,26e32f78,8b06765e,8d984a37,86ccb4e3,88b36bfc,c9cc582b) +,S(657acf28,15b8cc12,83265bcc,9c826be2,c6d5329b,351fee50,2ed96f4f,bb1a6333,171a0a97,b2809b24,a89b337a,cbeab96e,7d1d850d,dc577a10,ef3c757a,9c2da9fe) +,S(7e3d0a00,a3378c89,741184cf,36e41bb8,758fd131,eccd970,638f60d9,31b8348b,6f2cc777,31f94565,2a3b4c42,29be627e,bb70d5c1,67648d16,df5470f8,90512517) +,S(649a30aa,4fac6630,c7bab764,19f9a34c,6676f17c,2458fb1d,ac48317a,734242cc,fb3f07e2,5737d6b1,a28b074b,880db818,c9623c12,80268b02,dad90da1,c8d246d6) +,S(6b65264f,537fa580,9d21588,fd86b246,4d1818e1,ec7fc43b,94af9211,c835c986,537365ae,4e61460d,c2c1caf0,62ac870c,9536d8b9,436a0ef0,dee6a39e,2bf25611) +,S(dc1a5599,d5cba6b0,2d692eac,304b642b,db32afe2,59e2e8fc,3bdc8f40,72c66c51,bd18d5f8,f99c6070,b7bc06af,568e28b9,2b39dc31,ad49a842,4bff4a55,d11ff42e) +,S(726d39f4,86401794,9e7a5498,8e8fbb53,b8b13ec1,cd5fa3c2,88f0d933,894e193d,f23e9fc5,68c9e0cc,b258dba2,58b3dd65,7aca0dd4,d9cb7bf,274e62d4,f65543aa) +,S(78d76006,857c2f36,889c14ee,90a8f993,79c1e0f3,5344cafd,592c961f,75aa8ee5,76dfacfc,994f3985,70d98c75,4f5e6d00,ae3ed428,49cb75d1,580e81f6,3d7427c5) +,S(d69c3e30,88874c19,71bf077c,89247826,b464d3d5,292196f,88ef0ad6,892375a9,cc7b98de,86017934,c472bc7b,e56f14c8,7494cf5,6f2791a5,d3132c07,26315cf5) +,S(9b4022c,907c4aa6,87631f88,8d47bde4,faeab1c9,23e125f9,280dcf86,7920ae84,c7468b6a,a7b4db67,a9b4a23e,11fff527,19e454ee,65ed88eb,3b89e231,e504c284) +,S(e638a253,84e985a3,5dca200a,5e3786de,52617824,7ed0c9f7,9c9d598b,8bcf8447,69211bb0,be8fcd6f,cdb0ebdd,a8782be8,a47d8852,7bb74b3c,d98c41d5,6aae614c) +,S(e46758ab,e2838a28,42baafad,12376137,7cf72960,d6a93105,3270330a,203134b4,2c7ca1c4,73d0c3a5,8f5ca754,6604ac75,8c460c82,64f5ab4c,832893c3,fcbfc7c) +,S(c8c8083c,3bd1b84,9b9402bb,9472263e,37e7d2bc,53a77b4c,b0ae9b3d,bc70342a,9085d285,6ebd4446,127ab4c2,fe7e5c84,d5c5c114,8ee76a1c,da72933,9ca6578d) +,S(cf21f3d5,75f194a9,3133a382,514ca64a,f998b099,eb307655,46e2959,f71f838f,657df357,aa09b443,c4763432,45d3eae,4fedfd1f,7fa86896,2ffc5174,d61fc4ba) +,S(684aa68,d4aabda9,65adbb29,1056db00,1c41b900,e11770c,c77c687d,ebcd702f,c6f0c4bd,f6f6193b,928d81b2,812c4303,7e6b90eb,598a50b0,742dd21,8d82bf3f) +,S(b9a4ef5c,acf4a82,77b81803,6bcf2672,945ec080,e16e8c3b,19f7b612,c408c884,1cca67ba,9e98e737,b4a55145,7f254d4f,5d793d4e,22b81b35,f4ab48d0,92b9c745) +,S(ff439f87,d4784ca7,490da489,e2757106,e59836ba,f3fe2e4d,f6700c08,cdb2327e,98f21471,84659fa9,a9cdb709,f894236f,18ecdac9,f5834dfb,b91a7bf5,8edb7461) +,S(e1750c62,9c35027a,c1a5f1aa,c9fb4076,badfd925,f5915b11,a267672b,15945ed8,e17610ce,a0b8d837,d1038d7d,9300edfb,5832fa84,c4e630f5,2b01ac64,a79c0e17) +,S(2b7057dc,1c59ed7c,e64f187b,86adbbb7,1d228e5d,eea347c,75c73d2d,a73b3a28,1b136a49,713b433f,f2c79de6,77b5a322,8003e614,2b845470,5ce884ba,329e20a1) +,S(711c07c9,ae61ac68,f1041b58,c0f2ed07,1106c2b1,bc47e104,527d540f,53690434,e9199a45,2f5a3a39,9506473f,be6bb46a,3105aa70,2c517051,7b4c810a,5a194c09) +,S(54dc7650,68c38627,4619d9a1,faadc0d8,c2ad8296,dd0d00a5,f2e53c5e,1a1a0d4b,2e9b7179,3af2f752,c111fd71,c00f4bd0,8fa646a0,428b4813,885d4e4b,ab7e3fd9) +,S(9c5aecba,3f8b3507,db7cc231,c2c1674c,3c3e27be,84757fc,4f1521f9,c3d9323c,413455e1,9e157ddd,17f51c1e,618dd726,d300c023,f0a0d24b,518c93e3,f2954630) +,S(c22c2972,5f67e23,a369342d,9a4e1f6d,dc1bf6f5,88d63086,fb54718c,f5183a,a26ca30b,d97ad611,4ea4ece4,cfdd3928,23c02838,9723d53f,32c3b38,320eb707) +,S(8f87ac94,a29dd2c9,d37aa130,f8b4e67b,da595ca,a22803d1,e2d8cd4,eba4f2a9,551fab10,16227763,6d7ad2c,bb055439,21743078,e02fe0e1,b7dffd6,8749b04) +,S(bc486976,76c0f638,a116bcce,d7ee781b,876ef486,111fd680,4dedb176,8125dbd8,16d7c6d0,19708ccb,510ddcd8,698c2fdd,bc6978b8,7b0639d7,a1c8ec6e,ee3ea383) +,S(5a6ec844,201d9b39,92a46fe5,ad4f05db,6e8cf251,24ecae84,3a28da7d,46e75ae8,9e1538ef,f27344ae,8f9c1049,c12b49d0,2d5341fe,33652a8a,9f2eb512,c74ef224) +,S(dd6b2c56,b13f0ab5,4e0a75ec,526219e1,4d43ad78,7deae379,1dfb387c,541f4d6f,7379c5ff,1b793b97,c8acba99,97a3c079,f1c147a0,f63a2ec1,a0a771fb,fc3d432b) +,S(74e27534,4d7d8cab,e4995d08,6d61d27e,942e2514,3c6e3040,8402a5ff,12a63ebb,7b5914d7,fefb7b3d,2fdeb49,359878b8,355eecef,65ac589b,dd31ccb4,c270d854) +,S(bea186e4,b5e3663a,fb00230e,d8ac1660,67b022b9,b69b6e75,aaecb88d,d750d34d,35807d83,5b75e3ae,670bf35c,d415d37,6fbc86e7,4f99afbd,c60a0b46,9153a0d7) +,S(17ef6838,a07f65f7,cc094d4f,77743c6b,fde12ae3,b81625c,23826228,650f30f0,9d696a8e,a5356fa2,10626ce2,cf312fb7,198b0937,493c9dde,4711dba1,333eba5c) +,S(b3e1bfcb,38c89fac,af3baf39,80b21e47,d6465473,c9d6a29c,8a08cb18,141bcb7,aa33ab83,2a9d4eaf,2a50f9f8,ba55d0b,c5e3b120,69a8330c,23120928,5f6b90) +,S(689d499d,c754f099,83372631,2f307f0d,807f4f6,d67df40a,318aadd5,5776202a,dd4f9012,8a19dfbd,8f5f96ed,df2c7d79,d451f84f,fa63b1a5,9845f84b,759377eb) +,S(4bfb2e58,9df27505,91a73a4c,6ce88397,a2f68f6e,8f866e1f,d3af9df1,f3c96bb4,a9d94c07,29948553,6433f0ec,b4618d1d,af309c6b,73fa4749,aa949e6f,bdc24b7e) +,S(97a3004f,26461f5f,b6cbbca3,13eecbe7,5026d958,a1804c34,6e661722,c67f91d,8b8e9bfd,b9b704d5,13bb5a50,a725bae2,c7ceb6a1,ffcf8c49,8e87c6ff,e47844f9) +,S(a07a76e2,48f87384,48e607ee,7f30aed1,db657b9f,b159ac9a,3d38e8ad,61050c28,7d7749b7,aa6dcd68,931c3c0d,87eb73d9,6bd5f43a,b633e7b8,f77406a9,23fdd47f) +,S(9bcff8ce,3a280998,fe077cb7,a6e4854c,4c834e21,af118937,9a133986,320b8e25,da3214eb,5cfea248,f1f8a1c1,e8b0dfcd,4171b2fa,5e133854,84a6c99b,215c9ca1) +,S(8f1d2dd,bab8242e,fad20574,c0f28976,d2e98df7,5e144d27,e558b9c9,8d75a036,8bd117cb,294db5d6,a39097e9,8976c701,1042af41,680637d1,c8a1d56d,30800bab) +,S(73910449,2a44d0fa,d27b97b8,df75ca46,caefe44c,741848f5,36b78986,8d966991,d31b7807,e1db48a3,380608e6,5f865cf4,445c47f6,c6094819,da2450e4,6b78168b) +,S(e024cfa9,4fdae1e1,2895590f,222b167d,8a41a87b,b1a6b720,61ccac0c,4caf9dc3,d62f1129,cd84f36f,bd1b9439,6f5ce037,fbdafe41,fbebd066,110549fd,50b0ba05) +,S(a378ab39,e3dce826,6805bcec,b8123eb3,ffada53d,883c752e,e46ce4f8,5bf093fc,db9d124e,4c0a8d1f,14cfc406,4498a7a6,513261f3,300ebe0,99a41f0e,701c7dd3) +,S(bea5d211,b808e4bc,5aaa1a96,a9b8842b,5204b60e,24d5e518,4b4e92aa,12d8968f,caf8b92f,87c4b8fc,4692efb,889ccd64,610fd604,b9669dca,e033ae9a,453bbca9) +,S(7ec06291,40b6bfd4,cc4bd45a,8a953fc2,653d73c5,d366b5e8,b732dd8d,5d30428,e96c9515,da8dfae3,a2f4e01f,f02ebad9,8499a318,8905c0f0,fcbcbb58,87360a08) +,S(9f9698a7,6ccc8bc5,31dcd9a5,b21f3f8c,9d143194,8902312c,b5ab89cf,554c3b26,e08acb08,2ab0eb8f,fc31f7a3,1ca8dfbc,d4b1863e,29d155f,4abb8d54,6c59a221) +,S(ad955b37,a45f2bfa,1779e8c8,e6786af0,dc49dc9d,d692281c,da10b25d,7517214f,b2048fe,ee71c152,8c8f5dbb,cedde340,284af2c7,71ee86e1,8d565285,5de918ef) +,S(e7e56815,9412123b,7737b006,f48b3f32,513023a0,70c595af,1749c564,8222e21d,3ff11313,c2992218,cb3a1c01,e333f2fc,ffdd05a0,c381f8e2,24de6add,85aad0b0) +,S(4afab50b,55c2a433,488adadc,ca5d11,2e225f81,9ab817bb,116109ce,71dd3439,d232e25a,e5a8f6d5,68344997,442bdc54,de9cc597,cc474555,5f64cbfb,6252808d) +,S(2f739ca4,6559727c,cc2fdfa7,c66da19,b7d2660f,cc63b74,155057be,d55313bb,c39350a6,10a844f,80730a2f,27bbee8b,a06d7ae4,a279f490,f975111f,eada018b) +,S(f3596671,79f9343b,bc3238e7,bab4686b,5b7aaadc,95848f20,52adfc33,d15a990e,8b5759c8,e0bfb8ff,e298e824,ef18c042,65d7f886,1af8252f,8c9d9d92,c1822849) +,S(b3feced5,8d79e1c4,d0a210dc,de416353,404f533f,5a1295bd,4d888d59,b43725c3,b07089f0,871f7c3e,440ea905,cebf66de,52c68c04,a6aae237,e23c3272,26d99826) +,S(85c74622,bb28186b,5f1bffc9,74d51ea1,8bd7e6f9,1a02285d,6d8818df,b87d2f9c,8eb95100,63263c67,976fda8a,18910459,df0755b9,307e4145,cfdd18,15b799ff) +,S(3823d01,5b240e83,44c936a,c9a5f7f0,fbbe3059,1c20f39c,ca51be63,98ea7a7d,6e6539ac,8f404753,dda08dbe,f7ad4e48,69a67a93,f0efd0b7,b53c14be,130435fb) +,S(b73ae7aa,e97af1d1,b6ae34b5,f6188c62,33ac811e,1ce5818a,a9f20703,7deaa539,cf495bd7,2df163b1,f6908b7,23042bf1,137a325f,bb8ebd78,c0d12086,e7b76005) +,S(f6724463,faac9880,41dc4918,5e27b97e,889e74a1,81f35b58,2601328b,143688a2,a290e04a,f10a477c,7c0269ff,42285277,f1faced9,eff88272,45f2d069,58897554) +,S(9eff8038,1d546c1e,e1b5d562,947f3a98,427e17f4,84d0007f,eebd71c8,261ff959,bca422aa,d4748c66,6aa99f76,eb8e75b8,55f89b0,917ec29f,401caf83,cec111c9) +,S(93384df7,33d0fece,931587d3,410f2520,6bbbd992,5e6fce75,5432252d,8bc1bcc5,9e3beba1,b9a92647,c630cb4a,69b9bbf,80e301be,fb8eeafb,fa0021c3,ae27c38c) +,S(ca85653f,975882c3,71902d14,6f50b3ec,1dfe1fa4,b6e6d5a9,e5068685,632074bf,a64fdea1,66808f60,736f7d84,850f841f,588879e9,5d1adcf8,ccbdc4bf,4f743bba) +,S(b80a52f6,951aa063,1094a2e2,866d3a29,b95cf239,48753ea5,cf5c6f6e,8e082f90,61c95d57,d6fc3ca7,5f92771,61ca211,1f20a67,9a85f4f,2b8b0fbd,494d55dd) +,S(3d5d3037,3a97dd67,fe45b273,2ce21e19,b29587dd,301f3dd9,b411432,e642a3c8,5c8e3a19,896ef1a5,5cf1ad28,41e47dd6,1f207f22,3388c6aa,23d011d8,fd95929a) +,S(b274f8ca,29a87fe2,8a3a1269,ddc35b5b,44f9e4d9,81af118a,187a7c36,acb155c8,410d9c55,bc34c21a,6368155b,c282e449,c5317dd1,c4e5758e,27493fa0,4f028ea8) +,S(f1557792,8cac518,66f59814,a70c14f7,beeaefa5,33d3b535,df19d31b,ce1cacf8,113dbebd,9fef9cfb,93b5606a,e4b48aca,5b7e9c00,a59832e9,6865282b,80b70ecb) +,S(fbe3f262,18fcb657,7fe56753,42765926,59ff099e,f36252f4,cb5af101,622c40e6,4c872d52,f1202df3,e905a0d,3f9c89f,b347723c,99b1b273,8f3dbb83,df0fa2ff) +,S(ef7d13fa,25ef46c5,3663eddb,a677f6e3,b24c7e7c,6895e731,2c6993da,3d9384a2,cda2cc35,114e06d2,1f6f896,666c16db,78fef74d,2ee46fb6,a4a34e09,8546935f) +,S(8e34b93e,afb7f027,cdf8696f,a6407213,91860119,cae17b66,d4f16175,fd7118cc,3198f5fa,27ee190a,e56813e,910d917e,3bb8c850,20b0376e,e55e88ea,eb56397b) +,S(a8291a3b,8e544240,a0f0dcaf,6369b2cd,98ab80bb,4dcbc2fe,e023cea,1fa52399,f8305f7a,b1993569,82b8f2a0,1fa0e808,46a506ef,5cf0ccf4,fcba9211,284e15a8) +,S(bd36854f,90dcd6ac,978c2545,7800489,35c4cca,79a0f9b6,bf461da6,5522c88e,631a3d75,7c05e2cf,4a445b22,73cf663a,332610a,8461dff3,846503fa,12e65ae2) +,S(fad86e9a,ae78aaf2,e55e93f4,b8ee049c,73b86524,e942ab93,f05f9dfe,8b783116,657988b7,20822c63,dadaef15,a5cb3d49,be52946d,53b62ed7,1814ef3,b5aa4b7c) +,S(e1235938,db5e1f30,fa0b4d4e,a9e1925c,6308917c,23efde51,47fb818d,a39bcb2,7641244a,7384acbc,3133fd6e,9ed61af4,40e3b951,751f9d0c,384328f8,b87bb2bb) +,S(40ec62d9,7c9bf05a,cd4bd50c,137cb143,8e3331ac,554098a,57b6a92,afb137da,8b1468fa,f334dcfd,5a43d405,aacd3f31,7e868af2,73498367,4d0e5a06,67186a8e) +,S(f6f5c9e1,c7d94d25,9abe1a8d,745dabfe,59e911cb,c917fefc,e2da2a63,cacb26a0,7f2454a8,550b385e,f49c26fe,bac89a9f,33bd6c9c,2eb05c98,4303a16,6b21ca51) +,S(be4dd8db,c703a834,9e24773a,acefd0d5,70dd2ec,ef07bc70,ea8156bf,d5b516ab,46a7dc2,5d56052e,dc64a0d1,b414da49,dbb218d8,5abe14e5,c753eaa3,84b958ee) +,S(273f227d,448ee218,1e43f2a9,89d5942,54eae85e,54fe9f76,fb67ce81,169e1be1,67cf461a,a6c7ac60,1ccdd925,b4b38e84,1998cbec,cabf9441,29575438,a855f35f) +,S(94ca507b,96c063b5,bfa9d74a,c92e656e,db186570,9a017ce0,e5270bfc,8a8c4a31,98daf409,49c48c6b,8c674361,17aeb669,36c76169,8d39eda8,9922490b,4fa6a25d) +,S(91d6f747,c1c7e012,440cf7c1,34ba64f8,9ef67b54,3a57196b,d2bd6ae8,f5ef4356,e2117eb0,4d4d29cb,5b13f628,f69e5eaf,2befc095,2fa361fd,f757430a,168c19d6) +,S(8e2c4d62,c17835b0,97ba07b,37947515,e710e825,15bc614,75a66ed2,ac4cfb84,7b7f7e56,22bbca12,2863c230,5271ad25,b5e4195f,cb96e5a5,ca2be6d5,273d6532) +,S(55738482,d32c4248,1bb0d1a0,666adab3,8bd2441b,9436b690,77925e15,2d8c948f,93a6705b,ba5e5b36,e73fe83e,e0ea81b,3de393c9,1c209e89,af90c539,9af5ea2d) +,S(7faa0f45,45fa7d68,918396f6,19beb941,43d93f86,c5a26539,5016d386,b3e85086,cde251a8,3de1f2c7,11b884b5,33226baf,cac36791,1ff30e19,25f499ef,27da9c06) +,S(61a766a7,7bf6f8f3,a07ed7c6,6648606c,69134c6f,4ab4931,9033f9a5,e8b7d191,7dfa24d7,6bba181d,7bd77606,c73b1635,46f41751,c05c34dc,ec54773b,4abea4a) +,S(64317c72,4f1207dd,a6009736,6fd2d189,8b702e71,8cf84fcc,7c50427d,7eee171,d1d45f23,b1c5fda9,ee05652,dd30f898,c75923d8,293d6eb4,18a0e892,ae400895) +,S(4c328f82,5923e7c8,9cdba421,92ad7a37,5a328323,71242c4a,e108c771,fc47356,322421bd,92c5142c,efe89e59,4689a7a2,e8e5507e,be8b505f,9dc9ac86,9d90ae6) +,S(360aa32,797804f1,649c44aa,b38fa9a3,5d011301,708ac7cd,a4135c13,d86a6758,ce4b0fb6,6957f5a9,7e4ef923,ebfbd850,4f6d4098,5333db66,1152f1c,ac6eef59) +,S(5b110b6b,d9ec8ab6,635f5016,bc597f31,ec22f7ce,cfeedd2a,1e6f883f,64d2379e,9472fb70,87ab6f91,2b10c6ff,995af03c,5086c034,f0f69860,ead562a6,e409c8b2) +,S(be27b39b,5a657cf2,9ebb1b16,45f5e1d6,bb6e32bf,e3a52b08,a916e091,9affa38c,93fbf27b,5d03ae3f,471ad91b,69e74fd5,a8f2f925,2bd16473,62c4feac,d26d1dbe) +,S(8ec65d75,c599fe6a,bddf3cf4,6ddcb4d6,1e9b5324,f5e7b7be,5407cb5e,28a9df4f,3d52541d,49ce4b07,7b543747,3a219db8,29680777,3cdcbf80,e4b47786,14ca082) +,S(6edaa1b9,ea8c2c45,6c6a34c6,13ad60ed,aed18a04,32e96030,ac7305e3,2dbbf94c,c64c8279,40cbabbf,fcdd4db5,1719c53e,f8cdb650,67af48cf,fd731618,bd304b7f) +,S(3fb5f6f6,60847e2d,e04341e0,26c4102,68d5a1fe,880602de,c07be98c,22640a29,ddd43c38,95e663fa,5aee3227,4a16f532,df3a180f,e0813ba,3ba113d6,f6fbd9cb) +,S(2d740009,d7addda8,a802b263,35d41284,b3b9a119,248a3b,29b4a532,654e84c2,cbe1e2d8,1bffb79a,6f9292f,43ccbbad,e763a56d,6d68cde3,d946f310,dba8f28b) +,S(15bf4abc,1d74793f,6ebf2fe4,aa74e34d,b359ad76,3d5624d8,19c24386,33517436,5efdcb90,259b5dca,39054a98,b6702fb0,f2fd4b61,235ed4c6,cd1f3dc,dab15f12) +,S(feabbebf,3c6ee0ab,9b584162,476c8e9b,f7523c30,7874d7cc,c4a6b88c,b118d423,c51d328d,276502fa,f79168f7,3787d3ac,b4e7bb7e,1f65b421,64ad6e93,2d405460) +,S(e3664247,929c3455,e98de868,60010f47,4258c686,4d4a7c0e,4bec28d1,b9af3188,7cb4bd55,ba579fd4,a3066f83,710a3606,2fab9f87,34311609,902407a5,88454bc7) +,S(d570f391,365aa2ee,29b6db92,2a96e4db,f1820a6b,94fbb8b4,aec45ae2,f97a21af,c0841986,2b0adbae,1cb192e7,bf80dba1,830520e2,35e1e42,569a31cd,fc0c1543) +,S(9cfce5e3,5119ca91,38629b08,c75b77f0,db3cb593,b2bf8dbc,b7d6fe3c,d1eba55c,33891655,226885b4,cd74d8ce,f29e978f,60a71bea,be99a2c1,d2071f53,239e4f12) +,S(186ecba5,f9998439,f6a3dca1,a179608d,a15adf9f,f4d2f386,4268ec3e,e62e4407,ec7eaeb9,bec50709,e8dd761f,6253248b,2fd064a9,638953bf,510a38ae,c7c6d24) +,S(ad52f2f6,fe0b72ed,2a0fe483,3745aebf,acfae58b,b40a0291,21767058,3e0f6b83,b0cae754,85e3038e,c6dc8d,b4e95a54,63e3e6f2,1b99d991,2f521663,3eea0c71) +,S(aa06c0be,7d72350e,6b094df,f4dec4c1,993588f8,5bd82a1c,158f92cd,eaa7804,ed628163,29369fde,f0fac2f1,a533fcb2,a704637d,6dfaa1f4,a3b57f74,4efbeed0) +,S(5f7a102c,4bdf0a06,76e1bd4a,4df17a3f,124bfee6,312b3972,c49fc4a7,14b3e867,85f153db,ab40a9e6,747aef3b,cd30f59b,fc9776c3,93293222,8f534d59,9efb30e3) +,S(31a4309a,64c225e,69567574,e05bb994,3fe01679,6f09a0d9,358b1237,96cd3fe0,9b9862a2,916ad0f4,1e588567,5a1e357d,19ec82c5,b31f967d,af058e1f,da7cab16) +,S(8906bd2a,505e8401,cc89e32,b9362c84,3443b4f,bafb7c03,75bc883b,11c3e59c,ca78e1d0,1c6fca33,b39d690f,5b85c764,ee15dbfc,48fa78dc,5f7d7cc4,5323d187) +,S(41cc93ec,a27c4fc4,19fc1c8e,4568744e,dab8917d,d8936cd3,2723737e,e36b4f9d,c11d8299,bdb95efb,842ba828,a6d89120,1fc6a28a,9f208430,c1e2f748,bce6b7ae) +,S(6e1b0bc6,199c3b84,220020e1,1a698e74,2fa97a58,c498254c,d3af1e8b,23ef34ed,25e0ed2,3f04706,6b4134fa,b6252276,b2205bd0,7a8ba64c,636e0b0e,1d6d0217) +,S(b55741a5,7b9c7270,dd1e5115,995ecc55,8729832d,9f4e373a,6824d9a2,83490eb5,9adffc91,52eca815,465e533e,c82bab6,ec6b37a0,dbb3b6f8,c3bce25f,6e3d944b) +,S(fde1167e,67f0e084,251d50fb,bafb538c,9c375e4c,fd6441bc,59a46104,46ff090f,662451a2,444d39f9,58593a02,e9a94ec1,4a1b8d87,9dc80c5a,73bb68fb,67af754) +,S(bbc374da,188df5c6,5a633621,804d22e6,f7474faa,47a8af94,a1cb78fa,aee68040,c2c74abd,17acf272,6c03bbfe,7dbe06ce,eb1f4e0a,b0001aef,4d8f342c,aef50186) +,S(bde6680d,414ce86,548504d5,55c83b18,c9f94e45,f55b6683,166cc81f,583e0eb,2b1ce8a2,6b5bbd8e,a087eaa6,49f49a48,2891abda,87c2037b,a73409a2,69b5e2e8) +,S(8f9ba006,faf50323,b9637f00,9aa29cb,8e402219,75d329ce,15796428,6c84e5d3,1bb33199,e5c30e98,5f5eaa1d,65879a3c,703b7a50,cb04c7ec,a6c7512c,94180e16) +,S(19f03bc4,3b61d7a8,62bb81e0,f4b84c02,7359a170,de0108f0,e9b9e9d3,95b63481,8239d21c,f31ae885,ae10c62b,8be0ee1a,95db0368,cf0488c9,4a110a76,7d22dd73) +,S(667c2647,2261828f,2653a0eb,e70de204,29231fd8,132961dd,ba3e4853,8e332941,5758f0ef,4362f75b,c4356b3f,cd8cb2fc,3c77cb25,b7d65c8f,ef7b4096,e0d879e5) +,S(86558922,618551b5,c4c66c50,9b81a622,ca376318,7c558ca1,8a00a00d,cf100ca8,32cd16ef,955deafe,e3fedb4e,55fd2071,8e35c1e3,736dba12,9f3c3287,4413739b) +,S(255bfbc3,d0b0d6e,385905b4,af6ee2a0,18109db9,73788509,2d5fb275,f1b47b45,b1b1078c,afe453b9,a35fbc30,c5f605b8,4a1f61a3,1104b406,ab5014db,57e2b167) +,S(acdae8d2,eeab48c1,9507f575,6ba60b0c,e9d5b6be,e2ac15ba,d31e8932,fe89e14e,b077540,ab137999,7e7dfb3f,5e3fff46,10c2a369,2306ac0a,418d5026,caee0466) +,S(162b0c77,da3bc13,a62753f2,b7b19c9f,3fe864ca,66fa2dc4,226c5cd8,ca8d7112,377956e8,59c2f465,2af5159,bdfc86c,df0bd742,ec7f9eca,6e675b47,d6eda222) +,S(9453c9ef,afb6a23e,40ebf013,eb1af363,c28a6e14,d235c7eb,58d3d142,9d1b498b,65e3b737,ede3c00b,5f322b38,9b09a68c,2ff44f30,c7737932,4e9c94c9,bdd78961) +,S(8409ed29,38a5bec8,669e24db,88c1b6fb,b397ba64,d8a1826a,f011e2e8,32e85506,573a0053,1be979e,1ae3f2bc,3d28ce2b,7a3ec55a,bd00242e,73523a2,582500dd) +,S(3b55d457,b1878898,9c486cf5,3d1ef107,4161330c,64fc2250,81096148,f5ea2c45,24780fa0,3e83919b,9e3491a3,7e0b76d0,f5d32f2f,a4c3aaf0,d2e7c955,43476fc6) +,S(d3fa2c21,f4704812,a5b582f,9096fc87,422af325,5c5d006c,63e1e9ff,d2d9ebb6,a6aea607,9ed334eb,9355fbff,27650096,ab19a007,191d57b9,4a8fc12b,a59bbab9) +,S(a938a4a9,9dc45307,29f3bac7,4fcd7241,1e56cff6,f53fb048,c727087a,9a54b374,3949a589,388ef8cf,aee8fe82,fde39e01,41ad91c5,2beaea97,e7494659,1a27bebd) +,S(792220fa,aaf49862,479a6de2,35be75f7,e811d12,7420571f,e46213a3,e77aa93b,5f274791,31fc7585,8b82b021,52057cc4,f1686543,3eb6e22a,de56bea5,8823131e) +,S(b1bcdf1d,57699459,1bc11d27,cb15d84e,75eb3d5b,2f9b4bd6,1c848c14,e9b7f2d1,a2115735,8c35ac77,e116a0c7,77917e62,e1d09897,316e2389,41d8e170,90adeb50) +,S(735b746f,6f0d453a,c45cf288,6941cf13,c63899e1,a41ff3b4,cc1a4c74,a9b2ab33,e4c2b67a,c6bd7917,2478b52a,994dccd4,475cb24a,ed1eb77d,a39fbcda,9c02771f) +,S(1640d0cd,ba4b4fc2,f3670b35,2485027e,2724ea4f,df918b72,3807870a,39fbcb2e,a0a71f4b,ba481eab,999dfc3c,15275eb6,b06d129,48000828,be4754b2,749bae30) +,S(bff651f6,df72e476,a097231e,b496618f,6e7d621d,dfd45356,8b08c718,e138caa7,10dbc188,2d0a17fa,d769f855,bffe1a81,14183445,5d9ae144,e6eddb52,8e67f99d) +,S(1a3fa743,cf429f3b,49e122c4,5c6d6e8d,18c633b3,f9903c9a,207f0405,c2716b69,b1b2c87e,65faf1fd,debc377a,bd9648cc,24abeb81,75efa4cb,5f0a0b06,aa2f1e28) +,S(bc2a9ae8,e2940908,ef5420f0,9ef4c2b2,ae988e5c,c0c0efbf,62f8ea05,b305ff21,ede884fe,6b48627c,84c96869,5944be60,df3ed5c6,66f16b56,188a9e1d,6bb14e80) +,S(8cee080c,e9204a62,502ae88a,15965abc,b2a8f18c,80f6c461,24b073f7,63990ec,3adc08be,7bea0bc2,b2c5ca91,963f4c40,bdfdaaea,318fe3c7,866229e7,e53c8fb5) +,S(2fc784eb,f79f916f,7f57dfc5,8fc62e8d,bcdc7dc6,70d6a444,c13f397d,ed528e2c,56c58a3c,be510393,90a88028,12d03658,20141c,b1b24241,241dba91,74d6eb37) +,S(fcd83e1c,ec7a6db9,1aef0894,cfb2e1e0,d2b48fe4,88bcd28d,c14e7824,6e62aa35,a86c9321,e2dd113b,cb7ec78a,d9d4db68,b5ddbc01,70aa0f67,5586b08d,6694a853) +,S(4e4fc5b9,65584dc3,40cec4ed,87ab0610,d674e1c0,9d76d28f,e28888df,7f9be562,d2344fc3,de7e5372,ebd87d0c,ea5431d3,2364249c,f6c350b6,d7aa2353,26e9ac7c) +,S(8df04fe6,e93afc18,b0508831,320caa9d,b21fb740,46bcc364,aa80564f,6f89270e,d7b37dd,2463e50c,583dde08,ca253215,4d52bd8e,a4252c55,6749641b,71ee7214) +,S(f662c961,3102fc4f,afd27352,cc697de0,1f4a1406,f99a0656,6597b96e,cbc99305,43783b26,759a2eb7,8ba4a3cd,e865d1f6,474b1ae,26eeaa2a,15220353,f6bce384) +,S(2052f92,b66998ca,f172ce,15cde941,484c5ee3,d3ae329c,87f339df,ae944439,3e9ef8c,9f4257d,c563509,6df8efa8,ffd2312f,60684baf,bb9e5d,9cbd04ff) +,S(730aa6c8,9c8abb08,855bc551,1938bc46,bad8f226,4b162386,9f2e1ef7,c2d6702c,7523fb97,799e2bb2,f13ba1d,59510bec,ee682f98,f865aefa,cf3c6578,bf46ff81) +,S(c5773c0,7d65fcb9,7cefd396,b07dfa58,1ab237a6,be3c1739,e6db944b,c7991c59,6afea6af,44ea94f3,ee67d071,4b6654a2,b1b335cb,e914d305,1a60b05d,44cb81dc) +,S(3ef9a63a,5bdce751,48d7c585,5e3e9aec,90d34ca5,1a3b4829,979d67be,c38c83f9,145e65ae,635acb42,e7949060,fe44f350,3535d417,f3ce9e42,4c3b3d0f,b02f2c73) +,S(a1632263,42b900e5,887b1800,196c5be5,11065746,52cb88c1,4011aae4,6d14bdc8,beda5e2c,40b55506,31aae0d3,fd9997c5,3f37169a,2d810b5b,402210c7,7c372cdc) +,S(8c1f5646,65449ca1,f16015a,a876bdb4,4d965993,7ca6936d,5bbb80cd,c2da6d65,7cbacf98,f6f7363,8940358b,60beec4d,1cd1a1d,900f84bb,9db5f784,d4565034) +,S(693ab562,230c1ddd,3493c64c,6f7e2bb3,a74cc535,2b7efc30,630904,e700d5a6,db890cb6,d09d5be7,ddaeec01,299880a1,2e68acdb,dd950118,3c8f5f07,739cf4e7) +,S(d761653f,f7979336,f833ca51,b91b9e90,b2bc04f,7b7407eb,be3c8462,95d59df2,f81a5d74,446e9762,2391368a,ed154b2f,4faefa60,af93d727,8357fd6d,98537c5f) +,S(41de1c8c,a1315711,3435ce37,c2d2efef,24a67cae,59347d23,44bebf0f,a2cecc64,77629b7f,46cf1d57,a03898fb,cc9f4e37,937daac8,12c4df74,846d8c89,60095559) +,S(21f89207,4e3a00c9,39862265,c1762dd3,2662d182,397c1127,4ef144b7,f598b650,e6e30e11,566dce23,b7a6a06a,11e12bcc,978a6b7a,fa9297b,8c978f56,40f8b4f1) +,S(6163f61c,628b4800,dc49f30d,dff19310,369012a8,f31d4a25,27c790b4,c51f068,4e87a17a,12055cd0,4c4bc19,e052a219,7dc5847f,ec984f9c,aebb8f81,7a7065ec) +,S(a68ebde6,43ab3c15,72f5ab0f,85d683f2,6e6eaada,550e2425,f85596db,8e2dd200,487604ed,38a6387a,27e3cf1e,9d4865fe,7fc67e7c,ee26ab11,1f03e0a3,316de778) +,S(9b9fd342,4e065ff5,b82e0c4e,e5efa0b1,d0991087,684c46d5,7885adcf,b352d06c,b11a7a46,570eb251,6562ae87,90eeb403,823380c4,aae99329,de713677,5b5b5e0d) +,S(d80c347e,98db32bd,57ba5728,20c7322b,b295cc3a,ae326fd9,49e7557d,27151fc2,6d734eee,40229d19,465a0e2b,a011af39,62ff5c08,f83a2e17,e5c2783c,a430cb42) +,S(c8aba983,5f814895,e5d05139,7b23988c,7fefedd9,aed9dd20,a9bb0025,49e63ef9,3811b18d,8310a67,532be770,45461d82,e40c0ff5,6af355a7,55ed4708,f1ab0c7b) +,S(1bad15b0,a186d418,bb84a87d,d2fb9255,9aa64547,cf47a93f,73d23953,86b0e301,e432c50f,662da1ae,f7ee8f73,f5d7ac4b,4a4da6ee,5a943d17,7557e64b,5eeab1d2) +,S(720fcf05,dcbb0609,e5b45efa,e055811a,66d84384,16f7091d,7ea66186,922779e1,9045fb14,37d2086e,ae7d6a64,49effaae,17e3a559,571ab010,57f20fb5,80535906) +,S(96a540e7,8fb6647,63d3b129,8a1100b0,88a2c3e6,6da3ebe1,4b6c39cb,f01c4b2c,4debf0e5,c95b9a1,7bec7f14,12018197,88a1c325,12f60973,9d5b4909,f087b5c2) +,S(2f068148,d385bcd9,6fd6b60,b7e331b5,88419085,3942ed16,18b464c5,9c3ca99,596f3fb9,2fa7377f,a9ecc8e5,be8421cc,77339f62,c6f1572d,7a28266e,eb66ae52) +,S(466e9733,ef167fb7,233363de,16d9d510,74d8e5b6,35abaf38,20a037d4,f6b3e45c,73548e1b,d4d5b78b,821fb1d9,94919bac,a9d4e12e,13a2e8f2,d4c5df51,2553410e) +,S(f8a841c,a8c7fb3c,9a334f12,cfed9ddd,d1dbd4ac,764f3c6e,87a42818,a4a8e51d,57ebf669,72e9c4fc,7c435cc6,a85d381,6a969d02,ea85edc5,63c57187,34f0f926) +,S(d8c7d6e9,6719e74b,2eb7ae7,59d82ad2,6aa003ee,58e3d9df,ea97c7ae,6d6b887f,f1bec88e,5e8df038,b069692b,9e44245d,a11feed4,c89ff45f,17bbb6b7,1b0e43ca) +,S(afd5e13c,cabf51c,19c39c4c,815618a6,14a4f461,5fbaab69,624d366d,540ab638,9ced3d42,5c361706,16cdba99,653c00aa,e5212c5e,939c0bf0,3e5a1cb0,a05cba0a) +,S(fb491696,a4a1b9a1,572b462,f4628f66,b8368f3,3ce957d0,6ec29a0,92ce994e,b4fa2340,68741570,a56182bf,4f1c71eb,2c80d6a0,cffa42bf,a3e9d9da,59507de8) +,S(96e301b1,efd54091,80e3aa96,6652a253,78ce4bd3,cf587238,f0367a58,ec45b0a2,1bcdfe49,5ed90efe,7eb853f6,6fdc5b7,365ca2ae,e1d9b787,afd41b9f,c00f308c) +,S(9cde8d26,40d197a0,9ac00167,9b93092a,6eb8b13a,4d9fe2e5,6365a5f5,fc38d809,c86345d9,cf95fe50,40b2b2e6,2bf4267,72cdf10c,988a4f27,836d960d,c98501ef) +,S(d33ba473,10c37342,43e2219c,f3cf4881,2e843be3,c7492d01,80239bdd,20a829f2,ac774707,a5b0888e,b2ffa131,b71035d3,6af5be1d,3a3605b5,751b92c9,9e58a45a) +,S(6b364a32,1b5aecb3,749093e0,1b5229d6,5576e65e,1bea096c,29065a87,e26cf2aa,668ba97c,a01f659b,3687cef8,ac87dcd4,7a8a4f85,4a434f49,9592151c,b8f96152) +,S(d0009cbf,1d0d0673,5f66c16f,5cd4747b,d33b3347,fd7f096b,a026355e,917b5015,41c10a72,3e82bec0,b92e560d,3bf1e0d8,15a22e50,3afb4bf0,e5caf771,569a7dee) +,S(e618f641,a5b443d0,704102b5,40efb697,c470955a,8375e6b,a845c299,f377b701,9d615e53,edf6463,9b3b2d0,8684f8b6,15cf4122,33991a4b,5b7c85bb,f5698825) +,S(789c55f5,d393228c,7cc7920,9e705d29,867a6e9e,750d05da,9bc6dbdd,36c5c49f,8f38e43a,338058c9,39c64ff4,3f8f7bf0,2a7910bf,dc2f9af9,532049df,ca236de3) +,S(8fa4f0a8,1bacc20c,5d402478,23401597,bfbcc47b,973abe3d,71d33e2d,fee792f7,7dfac188,c5d6c17d,9e7430ed,d9038a6,e6fcf47,174347d8,7a68aa4e,cdc46c38) +,S(4d5f8d87,9377b056,afd4c8df,54a48673,c43fce03,d05be56a,56c42a23,356c34a2,b064c60f,a3b75513,577c171d,68acbef6,ac96f665,6a899d54,29e9427b,533b8e36) +,S(7a409ee0,8299930e,ddfc1e4a,db8475ca,9a99bf4f,a178a8b2,540ae448,ac87a3b1,5c4873af,c8a079cc,38a385c7,2ca039d4,4363425e,67de4cd4,15d09514,50f28e17) +,S(ac327275,44973221,dfb8b577,e33bd935,76407a86,77a1a842,bb04832f,68304e88,2b41b0de,3e406560,a57978e6,3359a911,6f993a91,9dd1c2ca,79c9a36a,6a4c8815) +,S(f9168fd3,973728c1,30dda9c6,907912d3,2e6cf9fb,b1c7a058,cc948f4e,44282720,c7005217,a6adf515,d8d3a87a,7e8a8b2e,aeb470db,c014824c,733e9a7b,17111677) +,S(818b9a9a,295d8f3b,bfb69d3a,f4749e5e,b0c1c04c,838ac3b2,9e74f6e5,dc73281a,141d14ab,64b3023c,597e96c9,3fdf393a,b53f45f4,56cd17a2,bd917af5,dca8daa5) +,S(90a416a9,dba0e05,bdd25dce,2dd0b0d9,200aef56,a6c0e16c,748e7d4c,99cac1c7,bc871391,95a2f128,af9c9c0d,56bff605,2fc27648,4e0a855d,6472f0e9,a779e0dc) +,S(678248e3,d48fd800,8e694890,b442d3f8,4f851881,9b152a6f,da24a6ea,88e1efb8,fa5d302b,51a36e66,98477693,9ba9c095,eb8b78c1,8f1bb114,53cb1904,a2185615) +,S(c2333e2e,742bb244,b7dac90a,18c2e65c,1dcb447b,11f8596c,bb3fcb8a,1e85195d,d15b8771,a31ff36d,b46b9ca1,b0ba345e,b877b7ec,48de20d4,71792a78,17ee826f) +,S(7d562291,9c72b694,d81bd71a,e78204af,995a63bf,3e8ecb3c,d9b3f589,c75ef8d8,aa554f52,67d9d3a5,8d35cf02,191b533d,ffdebf32,dde4cf07,252ef949,ec7df6bc) +,S(c5023f92,698f955e,4fcf7fda,288673ba,97b4d275,7f26f25a,c63ccfe9,155232b4,7d9dbce,def550c4,ee4c881f,69010859,c7a09ea5,36a8f7d7,17c1573d,c5db971f) +,S(37dc82b2,ed0e9533,e87867e8,d1eb57ed,707f335,b081d14d,d57aa247,645bb1d5,ff0c021a,d28649f2,3f000ae1,123f909f,1c803a9d,98ef2487,bf5d44bd,a97068dc) +,S(ceae1d30,2bf19dd3,a952ac79,8426244d,968b6ddf,25e16357,553f7636,a15ba8ed,c5a3a752,4d05206,39ecb8b,bf4282df,a1f9c795,ea74410a,ed9e064f,9a37c70) +,S(8bd49da5,fdb92648,f321bfc4,2d8145c5,20b8dea1,46b2bbf2,7a054698,3eb6574f,f769854c,5b5c9058,20ab0765,1a6d8104,e9a9dd1c,7aea6425,2b239ba9,7b0609f4) +,S(d1553a8,9a5226bb,3c5b6296,9f094b2c,1b761aaf,2605b0ba,b3793f6c,6959e8ee,d7b11159,d289d42b,8ca2889,f3dd7d01,e1cd0e5a,745b9f12,ab98b823,3211b2fc) +,S(ccf443ea,d8b17d4c,ec59ab81,74f1b1b4,8b6c3934,6e64a955,c617336e,aa6abc89,5cdbd39c,64510cdd,b342cce2,62915966,f8cef7cd,e10f4a7c,41a0d495,e5bdccd1) +,S(f95ad24e,7accb2b4,ce6afabf,6c1a40a0,172cf2b8,42871778,881ad94e,3f3d8d57,f3142d40,377543bb,6dee8195,743a6d73,e60dc5ef,4b0756eb,68d09d6e,326caf5b) +,S(464189d2,52726cd2,6f5ad4ca,5184503f,c546144a,ce7dfb32,5e4b4147,da7bcaba,910f8aae,acb04646,3c6a2a31,6174510d,8ae8bac9,fdce4c47,6c0dbd62,5196e2f9) +,S(637d373a,7355334e,70c78ae4,99429ce2,a5d97257,c0f407b8,1cb41704,d1b36415,469fa81,5dba5bd8,bb53a5fa,aff5b4c,18e7c28e,fbf21f52,14359d6c,7114c818) +,S(b489330e,2a4a4a6e,a99091aa,4e5aebaf,dcdba016,2bbc38df,5a49d4e4,7eee62b6,e1fed3d,93333ae9,2198b85e,fd68582a,35f6fb60,ff268494,720b387b,b3a7543e) +,S(8f2fbd92,70781f54,9d32ca01,2479438,2ec9cad6,2151c893,64c1cefb,c2324b12,2ae5c8a,2e018e74,2089a4b,12082c73,ba466dc9,851e7226,388e48ae,b1270a1d) +,S(a1871963,e9a65bd3,9e1b667c,55fe1a1b,87fe4215,8273c6c,f338f8cd,9119a828,e6881210,adb32d79,10dfe9da,c46c728b,20bca3e1,ad130240,f0dac7b9,fcc0cbc7) +,S(4a91a506,e8b32ca,13cbad7,99c4e3d7,21fd64c9,7ac8a1b1,e7f4bf2b,cc0ffa1e,66a0ee78,cb63bdd0,1a7c4bed,7bb565fe,832eb2c2,d32f2032,c33935f3,f16a40ca) +,S(61c960ef,2a3a6244,e8e7ee79,d4f5e98,88539c0a,b8be739b,314a100a,375ab66f,13b94913,ac8f600d,dbe9a82e,8987a061,3672629e,45d7d887,822faff2,60fb9e08) +,S(10325f87,f797c48b,2e6c7acb,bc0aa0e0,537fbf59,e74ab9fa,a7630c9b,86a04b72,685c5ae7,26b5c9c0,31e1c830,d513db4,b7fda140,14f8b723,7a9da11c,7ce9403f) +,S(71bca019,c15a3534,e5bebab0,6e1e1821,1ab01e97,dd24e1f9,1f89f834,b2cfde74,102387d9,a8da4f7,a483480b,316f0303,2178e668,f7a72719,2ae7e54d,27314a8e) +,S(7d30b01c,5c93abf8,9a50d14a,535a88f6,7cbb535b,1e58540,661fd7ea,91121fe6,e3d7e70d,1a9c0cb,2d6c86df,53709d18,b1989a5e,7642c1b7,cb381338,f6ed96d2) +,S(6f0322af,c1617968,b2550b3a,cafc8d0b,9445fd7a,4692f933,3ae9146e,fa2d3a4e,ba402962,d311b424,d05f199d,31b07d5c,8534ccff,caf817e0,88712bb4,2e6496a1) +,S(a3719ef2,c34bce90,feb7668c,a07d1a23,e2e6fbbe,1eef4b93,d2995e84,2c74688a,7164f77b,67aadb53,30b4127c,2d71dc46,f11e2d72,25968163,f4ea7358,134e5d56) +,S(3cb0007a,d2f1fb76,aa9752f0,218e2498,b7217440,a6a5136,68e95a78,4f71a72a,2f498749,12e8f469,e511b7a2,5a5046c0,f922a343,24620b51,3f6f0160,6de6b308) +,S(26b62d6e,f46929fd,88f00ca5,a699ac87,e090ab0c,8f02a078,393fb3ad,ae18c055,4fb9e53d,1b643585,4f2c78ed,1a818a80,1ff62c5d,fb0f8f23,d5e4d096,29886fbc) +,S(55e9ad69,68f490d,bfc2e17b,4e90dc5f,58335c1f,7bf30d44,79679acc,8cd7442,d4df7806,f74d9701,378ea804,be9a6270,85767e0f,b816ddec,4dbe34d9,536fe892) +,S(74a87add,723320ea,f1f9c35c,eddb6133,79835723,c74bc043,af36aeb3,5e1cbc45,5c79ef91,bccc2579,eea907ac,85ff8c0a,57fb48a7,c273f9af,6113e177,588fb14c) +,S(d4f1a9e0,2189ffca,c1d9914c,177fd66e,9d9a41cf,d1a38626,aed6b82f,70ba8020,923bf669,6ad7c71b,bfd696f3,9d68373b,9d0cbad,f367363e,2f70a93,4a0dea5c) +,S(593c7afd,c178edf,9eae7fb0,85984992,bc5ca489,16a2a155,a0314d8e,31fed706,ef39bd47,64f3b3b4,cd505e3a,628197df,5aa74126,30d83793,75c85b27,76a1073f) +,S(6622a6ea,569856b4,23e9f68a,78bab680,759a0089,3f6f645b,2e0eae60,f5dc9d3d,e84d491a,1bfc3127,3cfecf5b,65621213,bdf1af30,2dd39d26,d756e75c,4f9bc86d) +,S(d7149e32,fb34d956,1f5b25d0,650409f7,33a28fc1,fa4ad822,eabe98c6,74b3437d,2c249dbd,a1a82561,51b6eca8,a44bad96,1b2d37c6,d01c1d1a,70ceaa38,9b3f5039) +,S(64058ff8,7cadb65,8efbf32f,a68b7b3f,19915f5f,b434830f,bd5ca208,a4a09b6f,71c6dc90,f4d8082f,72d5697e,48fb380b,8486d7e1,5f113cc,28365ef7,d3ee9999) +,S(6a6cbb7f,5b571865,d70ec29d,425115a0,82d1fc1,f0209e8d,47be5e5,a9965dfc,fbf10d18,f3af0e94,b2a6ed30,c610f17f,5bd571a,41d073c4,2b2a4dce,c98ced0c) +,S(3f9a9be2,9a72cf7f,2086d9ff,3701a35a,94a7f81d,4b34a364,916a45e0,d8652874,25b12751,5ff033c1,70feaee1,189a35d8,ba0b8da,d4c943bb,4fdcebd2,1cffdf72) +,S(873be5e6,3cca17ca,95980167,9568b487,3d34c5ce,68abd305,169917a7,30dd206f,6ea148c1,280396a0,7ea5c5a4,17980f48,d076bdab,3df1628a,89da4c45,14bcbd4c) +,S(17865995,f28d4c4f,43e2e9f5,9b20edfd,830a65cd,d632cf9e,e7024ec3,4da0834a,6773c06d,478f3822,86c749c,5ae09a10,910b5666,5b6df747,36d20adc,af58332c) +,S(efe91146,fdfc4865,bd784853,ef79b8d4,d2f020db,3f901f45,38c74c80,bef49172,a81a34a8,dc3a229,8348109c,14d367c8,7abe6753,50d013e0,b1b0372d,2a6ee5ba) +,S(7ee6fb63,36cc88be,3b3c2821,1552031f,d017aa4e,192bc122,973545bf,924e8a8e,a656fe25,846e8173,327ab11b,d8ecd2ed,9d1909fb,21d1f789,588b4fa9,a8ceb0d8) +,S(449677d0,2a78e9a,ce374016,e19e7fae,46efd0d6,4839680a,4d5cbc42,173ee605,47017ad3,3357db8b,ceca2513,c6477157,f3daa99,9cccb709,bbe88340,29312013) +,S(ca9db080,12b9fd4a,cef2255e,83f35fb,e20806f3,9839c2a1,699c5d03,d7b5762,6a1a811,3d82a60b,677d61c0,af995bd1,4c598f08,f915e971,d9f17e9f,8398487b) +,S(d040da2,8dd69fc,67414651,714d4e94,5a27c4a2,9fb44612,d6d87f4f,80e2ba45,a1a72b85,957a01ca,8c8d5d3e,d9ae6a2b,31d2d192,cd7afb9a,4d1e4629,aeb9f356) +,S(27eeb708,fd2d52a9,47f69872,3706b67a,1d6e29b,cc0c86e8,111057f1,e3655608,7f67db4c,25b2e88e,275e53c1,c52eb47f,c2dab668,64b91236,522229d3,1b001a94) +,S(3bc82484,daab22ad,6d887a01,ea9f4b38,bb70e272,b15a7b4d,ab5e3dd2,439d8a23,b0ec952e,6cfe3ed7,4e6246d1,46c9c354,dacbc024,45b1af9a,6a668f0f,6fd52ded) +,S(d0a00060,13596198,8f070ff6,7ea731be,7f97a51f,68faf899,95eb0ad7,746aec69,dde4a735,d6dd08cc,28e2588e,9af0eed7,57017b38,790d381f,74748f30,9717a989) +,S(8efc4c50,51c65e10,56f5ccb6,a4be2014,a9dd043b,641b7690,cae2a8a9,1bbe8ecb,26fd1112,e1aa603c,91eb458e,3874d010,db58efab,5dd9ed20,e156886a,5f39fc13) +,S(e42271b8,881306ce,f166138,7d14f0d,da0db64a,b379368e,fa79969f,432cb110,d2b9999e,7ce9f3c5,8a6c77ce,a97cb9f5,f2860299,9bacdc7a,b7d5487f,8b5c9f5b) +,S(bb068f3f,8e7fbd31,f3aaf96f,de53d134,e3a88b63,9d8d43c6,4b3a2b45,2f8de740,574410bf,903c173e,23d88fb1,3f7534fe,566984c1,aa10f0d0,f54eea9e,7883819b) +,S(a3d0bd11,d728bee1,b166dff1,81c3682d,650fde7f,285ed5ef,b2ac5033,5327cd66,3e290c2a,42afb4ed,8b5a685f,69bdd379,44215104,17a61d8d,bd3dd2cd,805c5f44) +,S(9884434,78bfd51b,d27d04df,b5282a72,4cf82c21,487a8733,9347e560,994debdc,545574c4,359fe553,b694803c,5a07339b,b4e1a95a,b9fc72c7,5d4c8f5d,ec6ce4df) +,S(8cc104b8,58b8fb94,e0771dce,a103a7ae,adfc50cc,dea4cf93,a5f4ec9a,d44acea3,ad73883f,57c470cf,d477f228,8badab99,938b6723,516f97b1,22578f2b,f893b506) +,S(1627b08d,a822d244,ec8fe2e7,d8f02094,111fa362,e7190cbc,11229a4c,2043c626,41f6b029,80fb1370,c1e800de,39507798,8b6f315c,f910bb00,423ff727,e9e04c3c) +,S(459d4b1f,2676fd9c,2aac5937,376dc18c,fd4244d9,dc937407,d641e0d5,491df69,6f22ce37,a6ea6a5d,c9823197,22b0085a,e61fe140,d7558fcf,7bb44976,5de7aae6) +,S(cdfc7b3a,b755c181,72882e37,ff641e2a,94fa4e5e,b1b2947,4cd6e94b,f4f9387,76a11dae,107bced7,c2870dd,62ef183a,d45a02be,ce33e333,dea061fb,d89e787) +,S(5e189861,b1615f76,ac416236,e84b0961,b2639845,ecf6e6ee,8dc33217,b0952afd,1cfc65b0,9194d1f9,71136626,a2c3896f,5a3de705,ff1009c3,49a09c86,ea1667e1) +,S(84749eb3,3d482c59,81cc08bb,8634bad,fe0572d1,42367cc8,57a3c399,821d12c2,146a4fa2,3fecc0de,f00299c0,19406b30,dfbd9ad0,975717c8,7630e726,6e96022e) +,S(d73a1958,e9aa29b3,b1ab0807,2165c06f,daa38c90,6be76384,1851fa3,5711bca3,41f13f90,20633dac,3a5eca40,229ad15b,434c4f8d,4ea570ff,76d15d4f,63ea882e) +,S(1d77616e,1ccf1fda,bd4f0beb,6b60c1b3,1b94576e,bf2b61b8,c085cd79,caf8c018,7d3e5813,cf181271,55f3d084,df1077eb,2bfc9d6b,8ab6ede9,55c0ba4e,5095f23c) +,S(bac936d3,63887dab,cf27ea02,50bd550e,db37cb71,a2a8351f,fabcb1d,6d6ca9c4,7aa18819,8bd513e6,b45d6633,aa1af70d,b1a9c432,ffd1be4f,8a8fda79,a38c47f6) +,S(4d18c5c7,51639d86,b21712fe,b2333d52,5f4bd3f5,e4208537,e1e3bf7a,9343475f,2a60352a,4d8fcb6a,ce01b4c7,63619f16,156868c2,d85e882e,a2e7fb80,16f6500d) +,S(8e473caf,d74fb06,b483d955,ba3e35ec,e99a4495,cc86485,a8b6fada,c4c8eb4f,41708d5d,ae2de832,c7c38389,d0ae46c4,46add069,8e83990f,52a545f1,6ef66942) +,S(91366f76,48ed27a9,2ab639ac,f37aba5c,44e8bea6,1402e075,e307c4fa,ea2cefa8,868fe0f5,565092ad,677eb1c9,8959affe,5af504a0,c929bb58,2f5c3263,114ea371) +,S(1eab20f6,51b63685,a0a8489b,4e3247ce,1592c4db,40cb2f90,7eff1c58,c6609915,c142e9f4,b9522b0f,1db90912,c6f83c7,add6d8a,6bd1de4b,c54503a8,4e873cce) +,S(a0652eda,796ff72a,eaf8cfef,371594fb,e1528929,1320230d,2bc6a252,f4b49484,67e6d40e,8aaca7cd,f2a2047a,fc0a59c3,b4eddc1f,d3d5662f,45bb5792,9e4dc9a3) +,S(83915afa,c936886a,3deb8958,70e926e9,7ee4a6ab,1a5c66b,a1602c13,c4f959f1,86dad7b8,e870dba7,712ca968,1ab63524,2ed55fe0,36a148fe,25b1bdb1,1ac2da4c) +,S(293f0bc4,11454959,86b19fb8,6f738d2c,814523f8,b75b280,f8f9021f,95db6061,12d98ddc,894669fa,86b073e6,5855a0a1,760733e7,b7c5bf5e,868dd977,82a4fdbd) +,S(a829b1c0,d6780732,321871da,2d28ecdf,18d13311,4ddc33aa,8ff4caf0,58fb9ad,c5375298,501294a4,dc38d1f,a8c96f9b,789ee9c5,6533643e,1142bce6,8e1ef5ef) +,S(48133900,866a344,68309fc0,cc18f79,c0e01dfd,ed6a7bb4,e5a4697d,4b9cd462,335b7188,ccea4687,50fcdfc9,a6fa6034,c239fe6b,27cf6460,182a1c0e,c8c96707) +,S(7fe9d310,bbdaa101,b28c1e71,137a7ab5,181dca39,aa8d1469,bc06c856,3c7a70ec,18006c39,538a5141,2371828a,4d73e02,f4699a34,7e887318,57e394fe,75c8143c) +,S(1bd5b65b,d79c3eb,54ee1ce2,541b4352,1b7d6c37,d2a26f21,b51d2c07,103ebd8b,66e81b90,a120f04b,340adb2c,42143ef6,5d8a383,46e71856,673090ef,291d7bf2) +,S(237374f9,306e5714,5f37a1ce,1418a238,73938fa0,8bb971ab,fb5d97e8,e5fa0206,d8410815,fd4049e,f54abd51,fe2053a9,bde7f3ac,f40fe992,21bdcf8d,4b9808a5) +,S(33279bf7,38cee621,c17f75eb,bf78af4,58c1a4ef,a7197456,b57ee679,f2c34bfd,d63a21a4,5dc29462,13750d88,ea5e12c9,900b110b,ce433c49,e9b37382,7de327ac) +,S(ee274c71,b1f43251,11d7e100,5d7e9d97,ed1590d8,95cc6504,3e8ed6e5,5a87a9b,73f2bd1b,1baec4f8,ebbcf9ec,f613869e,8a262d99,7bdee49c,c5b2fb22,b652e9dd) +,S(2f49f0ab,c24536a3,3bb0857d,57c35846,f5dd036,3851a873,46f93d0e,53ab8de2,66b3dcd,d367958f,fd06121b,e42237a0,a9edaf21,79ded853,e8bf3c5,b6a81531) +,S(2d122193,ea92ca9b,46eec10e,2a23268e,9b1f972e,91821489,8cb12571,1e3094b0,b54d4b85,a02f77a1,57a48001,c0a26c81,2c038d0f,b91575cd,835183ff,3a0b7071) +,S(9047eae7,841f346a,374131ee,d4299fef,970f59e1,e4bb1fab,819fecb7,3026ad44,d59d3d2a,2c03be1e,553a54d,2dc61c9,e13364bf,3338a5f0,4e4466b6,86695061) +,S(f689480d,c0ddd61c,ba5aefe3,17aaa497,c2d051ed,d527cc20,16877986,12d7c8f,dac41495,a948d83e,37a9f310,18cd7abf,6d5608f2,213aa5cb,7a2b8f90,98d87398) +,S(4a01c418,be472958,5bae0c45,cf6233b9,ad0177ef,eb6e74ca,ded59788,a22d083a,8a12550b,83de095f,22411b16,937a85b5,a079c7ea,b8137f80,ffa66116,2a1c53f2) +,S(a6c715ad,cdc77020,febc4ae7,c6caf5a1,107147ba,8281d3f3,7945682e,72a5da7c,69b4ce46,2634da4e,e9e43559,72f87511,a26718d1,d232f726,577f0d5,6b49d165) +,S(68ecec4f,aa19ac3d,dd8b928e,8362ed53,3be24406,15f5ddf8,4b8a376b,cbff327d,f725f978,f6129f28,49a1c9fe,b07bc2b2,78fcdf4a,96a6ee3a,70b9b943,98a89f3d) +,S(5701d52e,2cdb7b71,a9ed91e6,95396487,1b656bc7,271299b,62ce0a4a,78dc69ee,eb8e4539,be99cbf0,ad730fa5,fcf785b7,35e1f5ad,f5c16c72,85abfeee,4058ea1b) +,S(8210f0c4,4b2f54b0,62de4761,b7c62d87,42424b13,ca0448ca,ba999eab,73b26409,1c79890,e4149248,b9dcd496,1da563f1,517275ec,79949969,8c6b864f,c03f8050) +,S(64cb2793,4ee57641,9d52cd81,6144543b,e4319d16,fdde7a7e,2bd824c,113bc1b7,c3144c3a,518eaebb,51a55bba,d87aba0a,12d3add5,5a5e00c0,94a2e227,80f0f6b7) +,S(37eb1010,acb889,932d8536,b86648e7,c124a8f5,1005c0fd,ec40bdd3,6369c82a,1da5703f,b387312d,d5a337c2,2d3f63b7,33dcc994,38109c2c,4807fc45,c02a2717) +,S(84bbf980,b54d60e1,ccfacb7,e861aded,b4cd7bd1,a3f7baa0,9a1898fa,22144d2b,3820c4d2,7b545166,2515064c,dc9b4cf,813c2435,e84a4a67,ba47068a,e6e09045) +,S(29e74c02,6b43add6,939ae05b,dc0a5e0e,b7d05bc0,536e23f8,8fed55e0,6f93f1f7,f0f6fd9c,798732c2,1dd1c550,3cfbd56a,71b335d3,aaa22359,75fb0c89,9571186c) +,S(98f3530,1122a0d2,629e5adc,579acbf8,8c0aea34,c3450ea6,784c4ce5,ee9672f1,427b899e,74e0c5cc,c289304d,b9a874c5,1d401369,55dc5b03,e0713bb0,8c3ec3ac) +,S(16af2e5c,4c37b50f,5f2b6e94,341e365c,90548d68,2bd9af37,1d849126,ad2c6c6b,1dd1bef1,6077f6df,32054335,c81ff474,33b7c1c7,d6243dbf,6a2564b0,fb9d8502) +,S(56998d6,bd5b2da6,d452f951,5343a9bc,4ed64463,adc6b8df,6a3edd64,e75e1cbc,ccd52462,9dbda3a3,10f3beac,7b3d3bb2,f1bf3c50,bca242ba,224861c8,1f26760f) +,S(f1732044,ec59c52,86273115,3c53aee0,c7f1c4df,e6e55cb0,e7e37d62,c1e11ce9,16a547b9,a61a6c10,4df1d1a9,de99f54,b42e0ad1,104a6a30,e6e616c4,dcadb2a2) +,S(6e5fcc4d,2df77b2b,8d2f95dc,56ddb885,6030f9af,aa51d86e,20d4772a,854b8973,11939a24,26c1ad6f,90db151e,c5c9f036,3f0b6898,2464fe92,c33aeedc,77347660) +,S(74a3ff02,98c3cbde,ba066554,d6def895,3954af05,f0f72365,680b7b8,4c5e9fc8,23b5f011,e50dd2b6,9c5ad6b,b4dad524,9c6a8abd,f134c232,f40de18c,3c65206) +,S(12a40a59,169e806c,8e32deb6,7e64c615,77a3ca,5c56723d,ebc98ed3,11983bc1,9d97709a,9c644c8e,3fcda745,a70cf3be,c405d230,eedac78f,96792bce,a715c081) +,S(f25dcc0c,5ae3f442,7fc17acc,bf888557,82673050,c3594abf,cea7eec4,7a4662af,52a20297,bb9213cd,d1b4f1f3,4f6168aa,ec2d326e,d9aef5eb,5b497c39,e0642e0b) +,S(fe31ac7b,ee45ffd7,99941eb1,8d65cb2d,38618938,c6278e45,4b87e41b,3c7d0f90,a5f1be4b,e0373cea,c3137a8a,c5b5cab3,e1209c93,2d49b245,eb99a0c6,469c3e64) +,S(c0ff7403,2855c2c9,ba06c2fc,6c9a8fc5,29b4ebb8,be082951,475196b0,ca4d6711,2c53707e,540e0c03,27a10980,25e356a,81fa6a48,b1e41d78,b7fe5515,b022173f) +,S(5b23e392,b87bef43,a3c08956,e1930c10,cae049e,b6f041f9,1bf3de75,4a84f984,c905adbc,337b9e7d,78781dd5,deaa0590,18e20bc3,5114c842,72343879,7a37987e) +,S(2100a6c5,b6b96ad6,37e13430,8d92e2cd,97902da4,7a016ccb,63a20cef,e72ac25c,a1fdc3cf,93560ea3,8418c470,679c5389,7bcc12aa,dc87ee6c,3429c68f,690f7e11) +,S(d57874e,509198e9,ee6ac826,b101ab2d,fe952895,ab288184,55f2d85a,eb2c3387,1c7bd36b,cdb6debc,99228b,341abac2,94dfd768,c9e00e73,8aa58339,d226f940) +,S(ff91057a,e46817be,b3874656,42afecb2,a290d31d,f18c6da3,d6313565,99657c4d,a2bb1559,96ca6cbe,2a375c3e,510df603,69d0cd8,f66d6571,9f9866f8,c6e73675) +,S(7f20e461,ee306c4d,7db625b3,49906235,14aca551,21b7890f,244de5e5,84d18b7f,8cc69fd1,eeb89a9f,9e126be4,3983ed45,d88c22fc,89f47006,ecd57431,4eb5d1c5) +,S(7ca32320,75421226,257670e4,5f277f4d,32cc7b4d,53588423,317203cc,b787696d,1e940799,8f25b7da,8f1212ba,c1dceaae,ca7b1952,26655535,6a98769c,b3da15fd) +,S(bcb7060e,f2685623,9aac249b,f603ce7d,b5c253a2,c998e44c,4ed60db6,730d5450,e03df58e,6d279025,955a4f52,dfce586b,f427e376,ca72e09,36d80c31,5047f57) +,S(30387990,3157ac6,fed71113,a004284e,82fdfc7a,3e08c0ff,1ff5dbc5,dbdfc04c,7132084a,1230ecfb,200ded60,9a1666a5,2f574014,d29475e1,6a061330,fbe19e7f) +,S(c5b3aa24,1147d664,a0b80f33,5dfefed8,a8f7c1a8,c6258686,cb16e3c,c365a249,fb5143c6,5f8907b9,a44f10fd,27064fef,93ee588f,9e77a65b,1cf64e4f,956f5748) +,S(11d8bdb2,b750146d,d78d8c55,6e6ac45f,4d34f1ae,35332673,cbb46bdd,3d76d9a9,1ea28ad5,c92761b8,7df96987,6e5b3243,9fe97661,87b5978a,d7515288,f30a5970) +,S(d6db4c60,742914e,c9c7bfa0,7a716cc5,f5492aa8,5381f31d,f76d089d,a773814d,b0ca5fa3,bc5d1fa2,c62a657d,77215b49,82f72e89,b138552d,bdea8166,359b6a3d) +,S(d28a6123,3b4e073,f1242c4f,5292bf70,9e1ae15e,a654bae3,4239133c,4a8a86e8,89519c8,8c44b38e,ad5c2ace,52d01de1,d74ee0de,5365567,cf1b21b2,2ae8b95) +,S(ff32042b,6a943772,d6f5794a,43420218,2ed31ac2,447167ba,ec82d19b,86751337,16961368,e20f2550,383268c3,9fe62fe3,b5d356b1,da2e4231,8f9618e3,13655f0e) +,S(f2c6177,30a9870f,5999ed69,d34efac3,589baa96,9f660cf9,ac839eee,a10e374c,fbb2480e,b6f191c0,15ee3c58,bd950aa6,7bee7569,1681250e,502e1d76,b6ec9069) +,S(dca14b70,e5e33022,eb559d90,1cf3a533,4c40bd45,7a43df85,e87acd40,90342539,7d038e51,30f77ec7,efe84748,4145594f,87d613bb,85a95715,9d0cd377,91678d23) +,S(9cbb407d,acc7c2df,2d86a258,d5ab2b43,31a18bea,9480f5e3,7727aef7,644416cf,7ab9fb64,c5f54f6a,4e5529b6,eb7834ae,80283bcd,c3f6b24a,8a014d02,b3b80b57) +,S(4552c48f,2d96ef41,aaf27778,a7ab4945,e4f2a2fb,7e1564ee,c375e50e,3516f555,e63da54e,28b70a99,5f35a1ac,3a25e384,6efafcbe,4e8f73fe,d84e095f,126524ac) +,S(b4cfb90b,168dc850,36559181,3d2d084a,9866512,9396f76,879280f2,38e4af3f,cfca0080,37006c35,7fd89c5a,1d444d19,5fd72d4,17fee670,e7b743dd,57f71b00) +,S(8e264996,e4e8a858,a1e32c59,b0df640b,a096401c,e77be6ee,ccd228d9,67dada3f,c9f5a8bc,89322e56,838c6d8d,859b6012,6d0a40f2,8377aca6,b5b4dacd,44931d0e) +,S(34ea02ae,49a4dce2,5ec2dc07,c71e3400,390b3054,83b8f30a,81021eef,5761ed99,b4b6f9ea,c41bf9d6,c4bba143,4639fd57,b8735d27,6098e374,d9324319,3def4c1b) +,S(bd391dfd,8569db85,b567c36c,5e6c378c,c152ad9b,c23d1fd6,1af23e29,543a56c3,9bf167d2,77e6bca3,a8d3cce7,61a36abe,91fcad0d,8d6ce398,877d3748,f2f13bf) +,S(67b295aa,440c8807,95369b98,c67d1d5c,1b9265af,58541994,7353c0bc,47ea8483,c94a0287,f2983c42,14f3baca,a8c5c791,d4d88fb7,30eb5b3d,4309f5cb,c5706f23) +,S(755e0335,284ad31b,5afb5775,fa191486,32b29c84,f38cafce,1b0b3b4f,2d073a42,c4506c75,c8cc96d2,8e31766e,a8ed1cf,531f4f7c,73888831,65f825d2,2b74c47d) +,S(e4b0cb3a,6149079b,5e47ccd,bfc4f351,64e575c9,20cd9827,a83f68e7,e5ba0a97,1604e71a,afa83b19,61bdd7ae,e4be5113,f9e9ddc2,29957255,cfe40341,9e45e5f4) +,S(3baca490,3147531c,905a2c73,277e4f39,c27ff6e5,41f6f2b,3ed4f730,3af0c4a,cf36fade,87b988ee,a4ccec6b,6b70ec01,d057173f,3aa7c79a,6bf4d412,d4bcafbc) +,S(229519e8,2a4dd2e7,ae77d713,21fbc8ff,f31191ee,6604823c,a6aefe03,19d06d95,a70e9af6,14ae7a1f,76224b8f,f5d1fc26,2e34707e,a6bfd26c,8cd7fba9,b5627e15) +,S(59364b22,4a53ed1a,7dbe9753,1b3a2600,2f700045,b0576733,8ee87a9b,2559dd54,b08cc507,70f5f3d8,851908b7,ed79ebc9,7f4f7342,61de0752,e14237c2,14eb5f6) +,S(d4b681cb,f3467c9c,649fd640,7991b4ac,3c66bf50,26ae93f9,e9b0238,9fb7c1f2,6df1a03f,4a5f00f4,8356bb9f,b23f1621,bb18a8e0,5afac4ce,4edbb01f,99a27000) +,S(49784426,fb036d23,a289f4f5,b3b92535,76da111f,ffcefdb6,a4163e55,2c56bc,76de5ca2,16ce703c,6a62ea4c,a0f7ae07,3744a22d,6db67389,9b0e93ff,a69e2a9d) +,S(5b213b9d,3f84b248,a98fe326,929b94a9,7bf78521,106a83fc,adba632c,8ed4892f,8eec203e,d015749f,f01402b1,722214d2,b58af86a,95384ae1,c39a7780,5623a204) +,S(6bb55cfb,9e3f5468,966711b8,6343e4af,6e372d04,ee7f570c,6a12005d,628959ef,75359562,9d633c9f,c2432ad5,f4c9f00,c6f54005,cdffaf82,438e3e58,70d14154) +,S(d760efaa,3a9e5c7a,967174a4,705baafe,d230dadb,4c957cf0,c025ab55,4b2eeb43,c019790a,b1b8498b,58daa784,ba02b7b5,672ba2b6,13d312cb,b4563f6f,e26675ce) +,S(f8be7bdc,6a361b6b,2844c60b,af7fec1a,216d75f6,96418734,337f9ccb,ae9117c0,df66b665,21e3dccf,639a323,5d773c21,4364062f,c5260323,3007e2cc,457d783a) +,S(6bbd2558,84348c88,c75a8155,6529be50,93b06a4,885c5d32,f1047357,a11434a2,842f9093,fd41b2a2,153727ae,ca2cbf00,a494ab7b,eef1a2cd,8696e972,1b1491d1) +,S(e692623d,cda3bde3,d32c1c01,f480d21f,9ccf8f1c,416a7dd5,17f1aab,12d3f3c6,30dab6f8,71f4c6d4,c768e086,fd6287ad,3fd000bc,3b04aa70,35cf441d,44764b89) +,S(86dbfe13,5db905ef,9ec7483c,6f51b75a,71726a1a,27e5131,8d6c0b2c,b0b933c2,371f23bd,45c46d3c,18056f23,10ab6afa,1259c88a,3a55f8ce,cecaea71,aea083a0) +,S(7ee329d5,9c625a92,594e620,4cb48559,458514f8,da94c7ba,fd2a4835,a4f10239,80a58a2b,e17f32da,dc80038c,7ed57de4,c7c561c6,69bf6786,57ee72ae,dd2bef04) +,S(e16a922b,8255d2c9,6ef776b,cda14285,b1cad5f7,62f75465,f8c82695,cf1065c2,44bc0e38,df9ce403,a927cb01,849e166e,6838468d,c7a8bd4e,6ec3fbbe,1f3465bd) +,S(5311e064,23145aa3,10737d38,41adf49b,988c1ca8,e8a705ca,3ca67f98,f756fe87,21c3f6ef,73bcca3a,c376e20f,dec775af,e22e708e,7e500c24,23114b4c,84ea8678) +,S(c09eda1d,dad1ca36,a9aaefdc,d16c5f50,a6ae499f,2cdefa2e,e5b61ab6,69f7fdf3,2220cbe5,bc279362,c5506404,e1df076,52624966,e3222b7a,62a1f7f9,faf00500) +,S(8888e104,18fb5c16,fc3c2b7e,b9ea06c1,da2df71f,c647b989,e71662a1,731628b4,7444a776,fa8f5bbe,959c71e2,c919b761,a2f8fdcb,5e66e5b,65e561e0,928e2d73) +,S(5c70258c,c1030231,d897c9a9,199df5b5,8b920f59,18141ece,d84bbcb8,b9b6c243,d627669a,e3dbb6d8,57d65a42,ec53bdf1,c688492,d189b1b8,67b75c3,f003ff90) +,S(eb58739b,878ea9f6,74b16f8a,406e7135,1ef06377,d9be32e8,1f657648,60e35ae0,752ae84c,8db0c7f4,e956d2b4,5750a5ef,24ea454,8f275f0,52b59ead,e3405ab5) +,S(996af698,ef26245e,35e4845a,dbf9c45d,6fec5564,c1fab0b4,8ac78f06,9840e0e7,a86b564c,ee788008,bbb04ee,e3d66c42,3c6910e7,7988aa54,420f3a4d,3137a1b5) +,S(bd03f2ea,a505bdd,7f39915,23f3e3b7,7532335a,6b5a11a1,4e303542,c00b8f4b,345f765f,cad902c4,56211eb0,bbe520ad,aacf55d9,e9c67787,aa02f18d,ccd88ea) +,S(8480c77f,3dd59c6,329c221b,ed8473e0,8cb0446d,c4e9bc6b,f2dba8d1,7ddf0f1,b055a135,a224f1e2,965cff1,a4f0d764,fed265bb,c644c696,2f3570d1,9af6e360) +,S(f46b6845,fa45e8c4,576b7c74,cd1a308e,f1adeedc,1d539d21,1158318c,ebd4c584,e1ed2665,34a14e05,c1ecf136,8cf8d6bf,fd9f0258,a5f0a53c,8abb00a3,e953c425) +,S(596db19c,38d91452,ad238f05,453bb773,9883df63,a0b545e2,47e5947c,d9f52a2e,bcb35b45,b172aeff,9e4fc5d1,714d6743,46bb4073,6f571291,e6575d34,f8b0d929) +,S(4cfbd998,f9544921,e5f1658d,e3ee95c6,df85b3f9,309f7a85,f6e4d08b,7e535497,ccd54e2e,437e4aff,7fc2ef17,3bed5ce6,b7d6e34b,4b386f36,72140d72,ceba71e9) +,S(c3f056d2,357ffe13,4403cee,6dd5ba3a,a7d2d0d,91d83f25,cb2cee44,34e57f94,1c31cee1,595b3682,fd85840e,312a61e4,40cbbf68,55418b30,bd6b24ab,c3bbf7b) +,S(e272370b,82ffc486,53274eb8,898409c5,9338e024,202be5e7,e18b5ec5,7f824680,d2f4e6c,619f0d,71e38990,f4e52881,de27ee31,ff7ad9cb,11a7f735,80a546cb) +,S(81537bc4,6a5fe897,827aeba4,6e66d576,6cd05a35,cd3fe1cd,9c06a2d7,194be59f,6706c254,125be3c5,92ad55f,6fa6289,4298f23f,2f4f397f,3bc84f50,79bcb8ae) +,S(50e161e2,6bc89d2c,816030ad,45559a3b,49c8606c,b28b6307,6ac6a051,9226d2b2,98478bc6,3f8d6be9,2db02910,67e5e359,e865d046,a5dd853a,fccb7592,72985c67) +,S(76ce7272,fcff02f9,bfc355eb,24286fab,88ba08ad,b15e099,22724b84,315be56,88f98fe7,62e37fdb,b72c1526,59528cdc,fc4c4203,c465e772,38dc8618,78a5a14d) +,S(77935c1,3a7f5f47,13098101,6e10ec54,d5ca10eb,492d4025,365d5265,ef7e6ebb,3c15e7c9,cf230340,44444126,5e74456a,4f3b72dd,7aff0ac1,aa76c67b,ce77dd0a) +,S(b37c3ecf,5813b5a5,2f52fc4,42049653,991d9241,e8677d2a,f9779fda,43c7a255,4361c742,c070b356,387fef42,1a9cdf79,58dd47a0,b7c9add5,57fa425d,626a1786) +,S(90c64aa3,28d43534,271e2f37,3460d8af,d17f9585,516b909a,6a7bea2f,1b12d2c6,79394191,a37a451f,e439e538,5e876c2d,ac397f0e,dfe29114,d14b9363,b76823c4) +,S(a314f637,2362ef7c,c4bec6a7,9396c318,568d9f05,9b6ca38a,c5f56090,c33e5e5e,b3a401e4,f7741130,95179507,2ce3b0e,53d2f51,f2dcaa9,d289e25a,8de01519) +,S(15c25f4e,80a7de90,8c49fc7b,649afd24,4c5a4be4,dfc15b2f,70099f73,6ad003dd,4aa9fb98,39855fca,c9f8bb26,b6322c95,e5d7adae,5aca9bf6,de073949,eb364b86) +,S(445e6d34,90f4ce76,22b6713f,584065a5,e0998d47,1b7603a,2527ed85,5d67d7a0,ecf994bd,7ba618b7,6eaca0,b852e0eb,be7b7f86,70d028e3,f52d1b2,846ce8ea) +,S(def695be,1ded66c3,650e9918,e942e4c,bd420fab,3a4708c2,43ab4e3f,1bf2101b,63569e13,532bf299,a0cf8d0e,a4addffc,1e782a1e,98a2f7c0,e0b64f50,8dd0afc5) +,S(eb364f1b,89938b48,2d32271,551f9529,5013185e,3ee2b534,bf01a288,9a534a88,9e6091fa,b439d0,d96f6a9d,cb468573,881234c1,6bbf4c50,32a6c950,99e6e6c1) +,S(7efe80e6,5c0134b8,49b6c58c,7d4c54ac,873e43fd,1b47f9d2,1d33f9c8,ee26646b,5411262d,63357cc8,d8280243,41d1767f,c25a0972,4c8c7a7f,3ddf6701,d12478e7) +,S(5f412876,3774e9de,6f2f25d8,a1d98de9,edf959a8,884643a4,fa18ac7a,26d6308,d3f6eff0,e336d4f5,abe35a12,4c47ed4e,5dbbe6d8,7d563fb1,8ea89242,aa454411) +,S(c63e3b34,bafd384b,2b60328b,4aee3a28,c7b3ed30,8a7cde45,87aa6c75,6c49c2dd,724fbbfc,11d05623,a5cb449e,a2f9f65f,a3de167a,a811bfcb,6ab9c3d0,3b123ad7) +,S(cc92795e,a0be5e79,757a86b5,147429eb,ca7a7c7,d51a8d3c,93650178,4f6ba5b5,92053ab3,db369d61,3af1093f,50829c73,4618c1d3,610ebc57,420d2824,935ae2ff) +,S(ba73d310,b5170cd1,57bbe14,63bfe944,ce7cea80,1b1aedb2,da3db11d,f1c7ea5c,4114e55,15806ca6,323edc6b,f0b75a92,834c72ff,9579d1f2,27fdadd6,d773c577) +,S(6047bc6,fd3a1c7b,9a36036a,94139542,7d9432c0,f652259e,1d52d709,e5088b22,bb119bf4,5d8ac9bb,1a918e6b,95cdf23e,6e2ccbf0,171579f7,ecfc9126,6d236b8a) +,S(a0600a7c,484559cf,3da255c4,935d2d97,1628fe8a,e75b88bb,1f3c4eca,e68f78d5,a439ac58,42bc6ee8,be096973,d87598da,349929c6,92e37852,e57ac941,eedef402) +,S(bfdef77e,1efac235,c1c49f04,290f89aa,c2e4632c,85f40481,dfdf5c59,d479e2a,e6e451cf,d76433ab,1de85511,9abaa5c7,8e4499a5,fa48ad77,f098c825,206dc7fc) +,S(81ff778c,373975,fb041cf8,ce4bc337,e2c977f2,d6bb2c61,9122240b,8e21234,3fc02add,e92c9928,e94e0ad0,218d6204,d71ef295,4c32227d,96b30b5b,9a61f640) +,S(84c4653c,d1af54f3,fc59dab4,5bbaa470,48f8eb13,4afc8f5b,60a8974a,cbf03933,98ff808b,a4682139,68b73ecb,67fe0a32,85dace7a,19d300dd,bd517e3d,b04ddba9) +,S(9d7ed86a,69f39ecd,c448de07,55197029,f81ee886,7c9a61b9,62d13eb3,abce35ae,d9b27e39,41c6bd1d,87dab6e9,32e8ba57,1dcd2c58,67177ce8,e7ef0fdc,668fccd5) +,S(540b7fe1,ee263e6b,3610bb96,1071d817,b9cdd162,77aaf28,87e7e5fd,df72f5b5,6638015d,591305c1,7a598a44,ba6871cb,8d1d3628,3ea25c5c,846bab2b,cd910340) +,S(4799c5ec,f1fb2112,f479abab,217ed0dc,e936c6bd,14215eee,6bbbb34f,d811cbe0,abfdeb73,4ac738cf,f607cd93,de58c0a3,237201eb,da47a808,3bccaee6,da5c5515) +,S(70a58362,b360c280,626a8698,7e4f2aa1,abdc9f8,f0b8c216,bb88b0cc,133c2312,5e37daac,d2835f3,1d924659,e51858ab,68e3a874,947360eb,c520767f,ce4d46d0) +,S(f345a0ca,857102b6,e225dfc5,7ae1cbbb,dd5c2737,116adbd8,b3d1f74,7d132b01,16fcaf2d,f7cae2ec,ef25da7b,3d51afd2,8f5e9920,5c0d74f0,c1e7b360,17eb2fb8) +,S(c3f4282b,29f253d4,fae8deb7,941484e3,9d2555d3,f96889b4,551e7d8a,eb2a209d,fc562248,8a6e83f1,6bb1530d,2a35629d,b25c8280,2eea7057,d22d109d,4263ac1d) +,S(5542218f,606e7cf3,9cf646a1,3677b0ed,4ff61aac,1dcea3f5,da5dd4a7,d4727632,f1bce63e,a11d5176,f47e576f,66817f45,4b51840b,a79695e6,3a1a1cd6,fb6c07db) +,S(65e81ed2,7d6b839e,5c3829f9,24beda63,98264de8,b2223479,43881582,4d124b35,2a17e09c,e4dd6e6a,32d85d71,e6cc2378,b53b9356,ee5790f6,8fc3040c,e6b6179f) +,S(5066b022,e43a5f83,c4290064,9e2b611e,750a5ded,7c89b8f5,892126f1,e112edf3,381e92b3,e407c6c5,d1c0ab40,6fbe1a99,57643da9,a2118cb1,3b8c6243,9328d9e8) +,S(8df78ac5,c5ff1cc6,df1e1dfb,58ef889b,17886433,61bea73b,a805c3ae,a83e2373,dc668ddf,5b39eebb,7b692997,f22140c1,8347e14b,edb6d343,96017e09,d37ca4d3) +,S(426c1767,7d7b00ee,af8d7d30,1bb11cea,1cebfa58,fc54bf0f,de719937,fb484434,4fcfa5b9,ab7b71fd,560ecbfa,985db2f2,418465f7,cbf8acd8,fdd71af5,7f9519d8) +,S(4f7f0061,bb90e396,63f6aadf,70dd3312,f781b2a2,3867df3c,566e18f9,b4a511e1,1308473f,d8956b35,97d904c6,cf73c05c,fd7c075d,c83848b8,571e666d,dc44b3df) +,S(7393002d,d2e85925,3b23db69,6c140258,8272a847,d834982c,5b22b256,93685107,b61532fc,6706f7ad,78548e76,b334a836,c899a49c,46afa1f4,4579b5cd,27641528) +,S(c41dff65,e88e5c6f,fca3b0ab,6ae69bde,c4215194,cd7c57ca,fd9b38be,feab4e05,9a9ba27b,a0b7e217,d31340cb,acd8506,7f052d8b,f92a4be1,cf59fbe9,6241f0c9) +,S(f619dc9d,6dcc39d2,9155082c,2ed9bc60,99296a8a,982327f0,60fd6208,5765c518,87961d3e,2b850ffd,f080d5aa,cceb1912,120ddbc3,4e0ad8d7,96e74afc,aa4871fd) +,S(6becdd5d,f02a7bbc,d1cc811c,fb83901c,46aa8207,35e81c29,a8d4d4ea,3f5cf99a,a45f7dd1,8949f842,2905c7ee,836004a6,5bb106d2,fb623d68,c2690c14,f181e39d) +,S(cd2390,db1e7c53,f424a893,c2529660,69a8f151,6f60722a,524578e3,e5427196,b817ed1b,457633ab,a3439454,6ed410cd,8140b9d2,e7e679b6,3322eae5,f3466e90) +,S(96cd9608,7f1cbcc9,b017ad2b,c7824285,4047dc3d,f98e7951,2fc09fbc,e3cd33ab,dfdb9090,c8a5ae70,13b8faa7,855554d7,3df381d7,88fd5569,d3a7ef7d,f729d625) +,S(99cd7508,5e9abb74,5fe03e3d,b100f2c5,2a43acc9,4127bd8f,83314baf,70d72b4a,19c98b68,2ded269a,57e50e3a,28b9cd65,344000ed,dac3d3e9,d8ac8370,662ee1c5) +,S(f53c2afa,647496ac,6c1220e1,4627c138,186286ef,b776449,55f9238,b39fdb20,1598c495,106a200,58fe1fd9,b29140e6,a93996d4,fe4cfdd6,74ec10f0,75badbd7) +,S(c127dad5,3b9457b9,51192c79,5793734a,d0a84671,ff6ba236,f53cc40f,769585f8,688e6264,da4e9d1e,fe66f5ab,db078c56,98696ef3,53b3bd42,c344b3f1,3d3ad744) +,S(882bc4c7,651634c,930384d1,3daf5a91,41508df3,2d34818a,e61bb65,40e92bd7,5c456414,430eece2,fc6e95b3,7700f608,9815f5cb,12a09ebe,8a87e370,85bcf255) +,S(4cbc141f,55c0b001,cfd934e4,dbbc2c2e,4b5dc68,72e3388f,2388e54c,e2a91bdc,1749d8e5,30d21894,221b2aa5,96541f1d,e700bbc1,e3427140,24f0a9b,9c0766b0) +,S(bff11777,6bb9bfd6,bbf872a1,3b9b6a62,32465cef,f16c3c75,441c39ea,2975528e,9e7412e4,ae492669,58dbdc9a,b7b1f4c5,d2edefc1,d4f0a483,27f2fd69,f992eb34) +,S(251416e5,887b294f,c752a1e2,3e991f11,90b8798b,11c97033,e470bfb5,b7bb6328,e6981dcf,15fb4b98,ac8a37da,267f1bb6,a2a38b86,3919d20f,72b5bc34,cb5e329c) +,S(bfe2490,569255d1,a62318c8,416e9114,66dec59a,bcca5df4,e64c2f48,46d050d4,f78bf673,577508c8,3846bd5a,312b9284,2283c47e,d4df7651,79d33bda,ba6eea54) +,S(e50d0a78,40779b75,fa121def,456865d9,3d7bb9c5,d566d790,58b1b56c,3fdc7b15,2f2688ee,4abcfa52,9424d4cd,eb40a8a6,a6de26b1,be8946f1,e4ba429b,5b32a6c8) +,S(b3a9d7ef,235df6ef,262e177d,19bd1121,167a056a,3957ffd2,a3d22d00,9a199bab,6a7adf,40ab5386,21fc3447,77c97416,66537460,44113c5b,a73455bd,9658753b) +,S(ec7277c4,20af5d48,3a6247d3,a1da7243,31c0e35a,85d6057d,55a3e526,bb7962bf,2dcd3e8c,5abc47d4,56bfcf,a8086889,89354e10,8188fb0b,c9ab4578,7b91d69d) +,S(91ed86a2,330ef91d,e085df2,a947c9de,f1284b8c,76d9b432,8dee9342,bd297242,fcc226b0,c46a36f3,ac56ec31,bf297360,8375f0f7,d248c669,f8b31ca9,9d056713) +,S(e2a09eb6,6e76b287,36c5824f,829afff2,439d973,e5be5b4,f3c55cea,e83bbda4,6b217b22,123bf3db,f35845f,315264c0,4a67ba18,a49abd08,6b2acc76,ca0b016c) +,S(78501449,bd76ff1f,58cdf2e9,203de4d8,3325ce45,1bf106d,2f474e91,bb0545c1,d0bbcc92,acbad044,218a830d,5f461332,cf488003,4b6f89fa,2f58b708,63aaa585) +,S(c3626c48,95df6e93,2c79d5d7,eac22ef1,d7679f1b,1df1259d,2be08aaf,7217d978,a594df74,250bcb50,dd9f294d,e7322b25,f72cf935,700856e3,c31fc5f,35e61b67) +,S(5c6e0358,ec09945a,c4240f22,3304f744,63269e16,c4f87dbb,99bbb744,bb4afaae,e6168dcb,d719ad05,8020dbc5,b03ec4c0,61b1fd87,d530913e,6df5d498,69e340d7) +,S(4a3fb364,d55fca64,4cc03c40,5a5956b8,a794718a,5b43cdf0,795e5d5d,5f79e7c0,4c4e0c11,5f88ef66,545280de,af9e3d59,3ff7d1ec,d8f20779,70ed84a7,8d660d28) +,S(fdc828e6,e305427d,c925de61,6f57e13f,5d0c8777,b538e511,49cdd304,1b022d05,de9e1037,db0dab0c,fedd8544,3b926a36,88e8bc54,7420b27,c65e2c6d,bbcb1662) +,S(6d70ad6c,375119a0,f4b2b65f,51257d7b,e73a8d69,ab944dcb,232b8fd8,e7021583,31de3a22,c8e8034a,d812a7d,234cad97,978aba7a,1c2996b7,aee623f5,858770e2) +,S(faa9dff,68f63fc5,7ca8c39d,8d950c2f,78a90317,c5d7f787,6ffa035,fcce8dc6,419b6c29,a7c02ea6,c8b7ed5b,c9b6fe89,1b3c705d,2ed2707f,3ef7995c,81a17de0) +,S(53d9472b,eb9a020,e84e10f0,1d5ed8c2,6219d24a,eab4cd67,dd30f084,8fa47a12,624f4c9c,64c02832,9b6ad395,dd51f960,41eeffc3,b3238764,57d21f85,d8c674ce) +,S(598daff5,aac2831e,21d5eff6,319e563e,3208ea18,e3ffe13f,2bf19444,73292f02,3db66869,2538e2f,e3689a41,dbb05504,bc86dabd,e033fc1,dbd7f84d,dd4e18c2) +,S(eefd321d,41fe6468,a7766276,5932449a,d3956209,c4c6a548,c4392db9,b4e39a97,6a372971,d5515d4e,c691b3cf,e73ccf6a,a491df97,570c9f52,3f29b108,c626c319) +,S(5a3a8225,49ecb78a,9c5aa12a,49e02c5e,10c168ac,e053f85f,30921724,96177ee4,482a65fb,f57726d9,d4ad61c6,75cdd5c3,25b6e59,899366a5,3ddbf239,96016448) +,S(e21f7d4d,b2343eb0,1d23d1c,5ec76db9,89e1e624,2fabc41a,b204ca64,838eee55,fb64c87d,ba7c54d6,f1d68d7f,a49d50b1,bd79d699,a75227e8,4363ed30,430b2605) +,S(fd688c92,f80983b8,496689ae,fcc0820a,a3d91fb2,aa4d599a,f48de5b0,98ed491e,7f946da9,9169612b,dd6ad8b5,d686052e,3ff25610,21432c92,f8728187,29e860e7) +,S(65594f34,947f182,bcd1703c,dbb1ddbc,4bf59b2c,2fff23f4,1d363631,cd54af0f,e8d98a21,a603eabe,cc1a1b83,9ccd553e,fa5eb258,5dc94e10,d134f40a,63b5bb1b) +,S(4f47f3b9,8bcf3917,464c07cd,be99d2ea,adf31166,8199324e,d120d087,e14789e7,279da4fb,d718e578,b10d316b,9994dd05,ffa05431,f85db2d6,6d4327d3,68aac28a) +,S(32cd8b52,c027e4e1,7991ccf5,6460f3dc,1d2ea6be,6434067d,bd4880e8,a09196dc,1d3066d3,76961716,1882da20,e467e035,4ad84041,f391a042,9e94d8a0,5d89807) +,S(c454b400,c7946f9b,b35003a7,c51e8037,dd03fcda,f0a19b14,f8daba3f,310d8bec,dffa7652,86aecb65,2744c9e0,21229687,1c305d91,6279b414,1ca1a,acc021b9) +,S(151b7159,4fce7438,2ac83025,6d98abbb,6ca309b6,64ef0235,53495342,34f7b4f6,fc61aa0d,722156b5,dd7ffd24,38100589,1bf236be,a41aff71,c3f1964f,15978a28) +,S(59716aa9,6b60ebde,848783d1,a686e9ab,e337b87d,104aa3f9,4cc7af46,ea8b8710,2e3062d4,a7d290eb,f53ee38,31dd8e80,354fd671,62a01a4c,73c57fb3,4582d345) +,S(81838542,7622429e,832e7a50,b1a670e1,2a626c3b,97cc69f7,abaadd5a,44a92395,18a88d63,d42e3ba2,af4b6c36,9971b0b9,35363e5d,77417116,b58de2d,8b6afb42) +,S(c95cf1fc,af7dd741,479a54ca,40a0e264,a989f0da,99b3a1b3,c4f67284,c8ae2a75,14b32e26,99662bee,51ad8534,fca1925a,a835cd00,9807c5e6,915b8283,63872f76) +,S(9362c939,ea51a649,2ae2dc2b,c01e4bfe,ccdf4612,97932668,2435bf44,e9c6ea1f,944684c5,2cb534b1,4871f48,41e889ad,933299bb,474b392d,a1e85ffc,5763c2e0) +,S(8852fd51,1e5f5e93,c6c3c7b8,4b0544af,cdb7d0b8,497d4bfc,90cb7322,28a77040,b0ea5bb9,c338a6de,7333b4cf,ac29f997,36c248,405facd2,6ce438f9,cb997a13) +,S(59105318,491ab266,2fb94506,532ed81b,74c8f82e,a13581ae,ef6c0c77,80696ad9,3417191f,bdcc1dd1,43323ff8,6e6051ee,921dcf69,9eda369a,afec66ff,a06097ec) +,S(c78bb701,8e96901d,3f13681e,ecc24df9,65b124b6,43f72904,ddf00ce8,bd28a127,ef07ce8,1b9c1cf1,26108dd5,f96ff86b,e0d49bdf,ad3d518b,1004b3c9,4c79bea0) +,S(9eb55ba5,2b5d11ae,3d419ede,5a5480b6,c2aee921,6f9aeb4a,96e51934,e8e4c11d,50094963,25b94022,2642ca89,1fb4697a,5e643e50,19670934,99937432,f020eaf) +,S(79ca2986,d40c7786,dc4d3e6f,71c33233,ad0b65fd,96822383,c11949f1,ab42f5e1,275db48a,fab1f0db,188e1298,4b391ce,6872e216,85c04c0f,3e62d42,d1e6d310) +,S(a2cf65b8,fe2a7abc,b78bcdf3,f25db18f,432ada89,1ce7d99f,faccefe8,e9673463,418e9be4,f6a1dce9,200823f0,5a6a0e31,7924a0f9,44c18b2f,1602a2fd,1ef13a72) +,S(7f6881f3,9f4684d1,3bf35c4b,c350b64b,28eb3c44,2adf05fb,c5e2c1e0,307fef19,20ac47a9,b954e805,db6fa20a,4e1a04f3,36c058f2,1946aff4,d4c24f63,6bd608eb) +,S(abf40dcf,72704e6c,65502d17,aa384bca,5834a802,62ec0de2,fd46ca2d,d9316ef,f605192b,a8c56b66,f3bdb35d,9c1df4d9,94662b41,85e8e6c2,9fde9d27,45039564) +,S(4fbb0d5d,ada948f6,2877c665,9cfe5f57,c6d5be5c,8cbb7bee,71cc575a,f4c92989,d2290911,45c718d5,243e1ef,92b8f7bc,2c77af95,f8666ce8,15900462,35d1c3dc) +,S(6c62710d,d0ce5eb9,5196e202,7c3c1d12,5a25f329,878b1f38,fa883146,b8ccffa4,c70ee1dc,174a6a4b,908b54d,69c94ec,5829bc8d,f6513c82,b0fc02ce,f566dde7) +,S(83ac175e,e220c800,a40adc87,df8450a3,963015a5,2c9e9497,602f930c,37af6c12,b7dd932,95601178,f6db7b5f,98046d7c,e42371ab,34e5f11,31f7cb31,59d37994) +,S(c823727a,348e275b,f52c18b1,43653c3f,8f0a5c0a,e8f48432,a8016486,ec3674b5,760237f6,2222cf21,fe1813da,4cfe9437,edca8286,cf3be63b,5bb05560,fa71235f) +,S(388b02ce,506784cf,2ec7e315,e765f126,23f764a,7d1ef836,fe360355,cb3f0517,ed0998cc,9069f336,c938b639,d6a74e8c,672a7d2a,2fe1dd1a,d7e18969,e7e57b20) +,S(517d4da9,e25f9eaf,7ab6efcd,cc00e6eb,7bfb975d,e8287b2b,d7d15914,4b7a981a,2ea7196b,a14b60c0,78444a20,2b67fedf,8fd119a3,7a39738b,17694cd4,c0dd712d) +,S(eac89275,54b0f71c,4ee80260,4945c5e5,578fdd50,ad68c478,2295670a,80432bee,dfe1ac53,dc9e18b7,1a930e73,cea36af2,8c8326eb,3615f858,fa1d3884,446f59a7) +,S(f77a0877,e7ffd2e2,cba9f0b2,c419e886,73711125,7cee4480,f6529851,6013ce29,fb245db7,29acfa2c,145011f4,42c9d480,5fcb0be8,b7f27dd9,9d532f6,aee2d57c) +,S(747d96af,94b3ae3,4cbcec25,fe8f4b74,e8d2077e,31ca2520,6d0d5613,3a49bd7e,b13d780b,8d322848,de5463af,3dc9c6fb,4cee70e0,da4731db,14916252,4b6d8d4f) +,S(9bf6ae06,6db68c50,4ef9b1cd,6d123efe,1d8608c5,3a1a2276,f1f44493,f8b5bf72,5b0080f7,694a756,f306714,aa9d8b3e,617b7c5e,84d862be,470df13d,e79c8994) +,S(91d0275d,e99c876b,d6de2cd,481fd72,13d9f6f0,e41c3444,4790dd80,cbc72e72,b12126c0,8b03b040,60183216,d1468246,d32d834c,57e687a8,9ce42ae4,d4eba7bf) +,S(e3cd4480,6585252c,8eb09442,74222016,5ed4cb90,462310ac,ddc769b1,b9a111e2,d8821a94,f1bd3def,434557ed,4739d625,c74548d1,44bd370b,180fc4d9,ee04afa0) +,S(3502269d,e8a68ef1,a0d74a0e,1423de94,99b84d3a,1fbef636,d9f38801,ed00d64a,9c4b6259,8c1bb627,449800ba,d9e93c7a,265114eb,99f9b5,7bca5b6a,72e3b302) +,S(244e51da,a54a3c4d,69f7a53e,6ef82bf4,7907bb40,7713f5e8,84694641,1daa2ec3,61f00ad5,f30928ca,a20cd38e,5af6b3fa,afd4def2,f8433609,4f08e82e,d46a0320) +,S(4f00186b,5d6f0420,88ac1221,a13e3aa4,60190cc2,2bd8fc26,4df81f44,1e508032,fcf58149,b8ab94c,67b30d73,4a3a5835,c7f89e44,6aa8d2d9,291c5f6c,b17b2e3c) +,S(10a96b69,2f522f4d,58d1c9af,463ae371,73e6f72d,93aaf756,6267b3d2,f62a579c,fcc7a656,c9d72dcc,1540a638,51328135,85d3a0f4,ba5242f,f5aa35f1,88ee3070) +,S(ee66c2c,2b19242f,4d7a22bd,df36fe3b,b5c151f7,1dd8a81,93fbae52,23064f9d,9d4f46db,7639d9a6,95d51d1e,44b08d6b,4791e443,744042e5,cc9e3933,cc27aefc) +,S(872337c4,e34a3dbb,f4b274a0,a47c1398,f78ce842,fb11b994,b550e9e2,e21934c2,aa8a7840,d6dbf62e,d91577c8,8b8c6baa,69e01f94,5294e3fe,4ccbadc4,c1d64221) +,S(e2eeb213,bfeb413a,9093be1a,7f75820e,5f48dc34,8515ef1c,7026c116,9be224a6,a49c846e,9132e039,9d66da39,57cebf1d,2e673831,3a89f682,c28d2230,1792d36b) +,S(fe264a9d,63932bdd,5cd4629a,dda37c9a,8d2bbb1f,5809d333,80a561a9,66af74c5,543b7920,c6c27b7a,515b5adc,b8d144ae,64118447,dee21638,1d6cfd2,5627fc53) +,S(13806a30,2d32152f,a1ee8060,67b07cc8,fce1e67f,16f21859,e7b60de1,37debf51,ffcb1150,7be5c2a8,90237923,5335b575,4cd83460,423ece53,18be988,c7e5e978) +,S(db67e361,f9d91cff,1d8b99db,b7bd2584,f1b91cfd,77473802,f603ee9d,debf4dfe,6407a133,7604fbb9,35fbdfb,9fd6e2a4,ea6d8f28,a63e7524,172cebfb,d3331e2b) +,S(606d4f47,d1d4cc58,3e30f214,e1ee57cd,98e68b6c,91c852ad,cad6c32c,989d8bd8,81911891,8a074dd6,ebfb95b1,c97b4fd8,5ef0887c,15ae5e88,ec6e97b9,cba46701) +,S(51d60942,e93fbcf7,e230c116,77528c0d,3b63f7ee,64c1da65,692aa91c,af482ecc,b82db22e,3f104807,6338369f,d77dc11,d982296d,e630af66,36cedecc,108ae433) +,S(2553006b,b8474473,29108ffd,cfd9c91d,22b7ad2b,6a0e7bb,72f98a0b,770da376,6173583e,e6b238be,ff3cd6cc,9bba1b48,d89dcf6f,481868dc,773eea98,59ffa871) +,S(52e35836,fb0a1c1f,efb092fe,3c95bb32,26bf9aaf,50fd1ddf,29ef0ba4,b100d794,639078d1,cd1cd22d,135ca950,d754d3f2,bcd11a95,91abb6c7,c4a5177c,53adc86f) +,S(332e02e5,5c089c84,82ee9863,a4dff4ea,b01a7a83,4747ff83,512fb567,7a8ee3d,b1edbfc7,9c1f9264,10c4cc3b,8919b4f4,e89bad8f,34135af5,f16b1c66,9a28b87c) +,S(d9113a61,7d5a4a75,2080931a,84bad37b,ce2f907b,cc05adf4,16750e8b,8951435a,ab1f66e5,8d3a5887,2f664b56,6c2468df,f9d4d76c,a73111bf,57e10d1a,f7df7aab) +,S(71999a85,799030fa,b0575523,fab4111c,f4b60351,e03f8703,1f5a852a,f22131d4,eb171070,d6124255,9adbd82,565c8dd3,fba6b8c0,df939501,4223b2e6,148668f4) +,S(a9436d74,a39c7193,368ccbf0,d24098be,41309668,87ebb8d8,4213e0b3,436c23cd,7b93ba5d,e2ad9b42,ac45ac85,43f7ae59,7300e745,8fed1359,bc392015,540e7a19) +,S(f6288f25,57359179,cd3659c6,1cceef6d,c5a69631,174f63ac,115633ef,83530b2a,d54f0f2d,51a365dc,7ba8b630,67ae663c,b4102e2c,59cfa616,b8878483,6ca85722) +,S(bf685c41,863c9fee,dff2fdd4,ba47d726,1f0fcb6f,b0432a8a,3b7c4f6d,6f52700a,336b1d57,43ca6d28,52e20cd6,ab276441,61b2ed82,ea4e0051,d88ea92c,a66828c7) +,S(672eaa18,1009f3da,3fe74eb7,4b479e24,4b73b54f,206f7342,eaa865ee,f945b00f,3f056594,a113cd63,810adf1d,b76efaad,babcd42d,347282c2,ce66ad54,37cb89d0) +,S(299deede,3b6722e4,4c5e7600,214f85aa,4dd70ac9,df75cfe6,c020ec58,c8c859f7,92ecac9e,4a6326a7,8b01c0e3,6466723a,3d00593b,6597b6e,e16924cd,60105137) +,S(e4268a68,7e6c26b9,2cec18b6,8581bf03,8b25544e,2040d505,7b9823b8,b01c07d5,35d1c370,95a9cc03,f91db5d4,250a904f,b9f9daed,9388b5cf,d6a3699e,b03c30c0) +,S(7164e9,bfa6ade,a42bcc27,db38cf5b,fe908499,eda21bf2,27063fb6,369b1ae1,a2367f94,fe683e07,1cb7ffb4,287cce88,b11336ca,98e6769e,178262a6,b9103d9b) +,S(84d8d32,a4be7402,1c94d3b6,c0913724,b2db26fd,862fee1b,c467a37f,b98b299a,46b92145,46603cb9,1cd5ff05,a237079a,e290b496,19d868f2,8143d660,94e61cf5) +,S(60372ba5,d0eaaacb,c1445979,74a0553a,6e63c4d,15001b76,39f5d05b,84f626dc,8fab368b,c4d011aa,edf7d98c,2e6a0359,5737b1bd,bf701060,d30c9f0e,a8e8c847) +,S(453c17f5,5364f812,a7da0f75,d7c074b1,81cc0901,a938447c,df55ba92,a7decfbc,53d465f2,6d3d86b,a76ad1e6,f147d208,474989a4,64ceb6ce,79972cc9,3e2e2c3a) +,S(cf1f79b4,b765a894,2b967271,85d0c2c4,dfab4c4d,d679693a,4b35b343,c411cdc4,b89916ea,4ea34abc,63b9292f,591b5c8d,5ce802df,9d4f2be,275ef244,7e1ece) +,S(74b07994,b7fe3a27,eff2f9aa,72f8746a,299f9eb7,81f09b15,f3ae595f,a0c4ac37,5464345,f4873a6e,9f4cb569,acc8e551,a9acff9e,5e0a92ca,e2c3f800,1888f905) +,S(f9de1544,89b7a06e,40115de1,fcb7897a,f6bb2b91,5a1e8971,8d5d5ee8,68bab74f,789b5c55,2b352db3,4345ca30,328f542b,ad22e5cf,d98e5b8b,e85646e8,d47a0e6e) +,S(c011f3d1,897cfe72,827d2cc7,c04a6aa7,496273ac,11f0df10,27ab4d69,aa745c5d,8e31fcd8,3842ffbb,a600e771,feb0cc2b,1fb257ab,7c19fe61,67802313,cdec95ad) +,S(16567ed2,4ea1cb2a,15418d66,c70c0587,386201f3,4dde86b,82f687f,95229648,fc4aa805,45366f8c,3ee336f4,51397e3,7f78188e,b6dff3ce,d80c7e7b,6d9f7cf2) +,S(8cd33d56,9acd3607,979b3c17,bf5c2175,ef6f3428,7a25c18e,89a1b38c,979d50e,f4312cbf,f301e942,61b7da0e,cadda424,336b1201,82ad73c3,c907be8d,840f8614) +,S(646e22ba,39927176,4e1df1b3,16767718,79d7a16d,587b9e47,5232a331,42ea2a5b,55378afe,5f29feb3,2a3152ba,4d83305e,f77b1025,79154aeb,7bb8b8ef,c5958576) +,S(2699d984,462e1fa6,208a833b,8af2e32f,58cf2d02,7707b4fe,2e3f888d,82e8e2fc,ed6c46a5,c5121755,5f236a62,21399a40,5fd87fca,f4cc6603,fffb440d,54b888c4) +,S(be4b6631,3fd3e2fb,163530c7,2fa4a41b,e36d04b2,638315a9,1d07de72,c4ced54c,a7a71077,83a27b72,4e8aa644,a88ea181,c770cf6f,489829c6,6660c44d,45fd2ddd) +,S(1f2ad69d,a1438b51,fe02a47,9cf865e2,18bdbe01,259b0818,1b6e7e6b,762a72a6,d4da99d5,7aa328df,3c587a45,2d756bae,fc09c626,fa5516bb,c8781b9e,b1ecd29b) +,S(b1adb241,721a1622,35540622,f8e84291,e1c2702d,70cad33a,89aa3806,f7acda43,e6cd9324,12542fc4,25b8f16c,c0820f3f,26f33e11,1ba0ca5c,b5aeaa54,1fa3d9c6) +,S(b604e2,f06df266,1163604f,2a1941ff,4d6991fb,84796c40,ccbe74e4,cf68e207,306936ee,e887427e,6005b265,38af5ca,53b3cab9,a3aebaaa,96556c46,7db96e88) +,S(afb935fa,1e30617a,9b4f26b2,e7b150b3,f33566b4,7b5b4a7d,6223fe3,9c0dced3,83624f43,66dd82d6,8e4cd94c,464b6322,db0b1774,9fa1125b,a0944503,b0c63b0d) +,S(5cc7252,a08ff892,93022eca,b56a5e9,cd2eb4c4,71161d15,5d7a5113,8b12d235,c272b6cc,42461529,b31943fd,fcb51a59,7a0eaec3,ae8c2754,827fe1ce,a182bcc4) +,S(6c17c206,7c72a1ba,410f2446,e4ae2012,6eccaf88,aa4fea14,522a7607,143c1122,7172af08,2adea428,2f6a3cbc,7946db2f,c0170975,50ad8ee7,f4c514e5,dcd693eb) +,S(fd82afcf,c55d226b,274cd62f,385e882f,716210f,9a14be15,baf7e17f,b98eac8,4aeac666,a1153851,6d66390e,6c7818d3,3de26fa9,3d234eb8,5e4d5b42,853eb3c1) +,S(3d0121e6,c758dc91,8ce3bbca,1884788b,20717075,1e80742c,49b202d3,c2f8012,ca6b47b,306cef6c,662bf21f,77bae3c4,25009561,72dfc630,e2b1a6da,e733413d) +,S(488306dd,3bf3bb5f,24160f1d,67b8c053,bceb8da3,cb1b05ae,7ae9fa72,e3f7b0c2,2356a8e6,77ae2f06,6135bd88,1fab5b4c,6aa57769,3e2d476a,1b2a4db7,fc6c27be) +,S(d7e91488,6786009e,eaf12d14,a23ec6e7,fe41e406,aca5a5b7,47010ee8,8441d6b2,c98389a9,143a8fdb,df4a67d8,7c05cd4d,fff75fae,845e7e62,26c61aff,3dc4dde6) +,S(873a2877,9c45280e,3d196725,5da756d0,ee5ac567,cbb7c52d,c8e654a7,ed78a1f1,9bb9672e,e76feae0,d52be301,983c182d,ec99b228,defb2166,5310a4ab,cae7eccd) +,S(410a7c98,85f531ab,46d99b26,b6fc2576,97723e4,bd9b9c57,6544542e,2cad2ff3,8bc9e686,4f139032,cd443148,4f43abd4,3234e3eb,3825a0a7,db8176be,cb5207cb) +,S(39269060,b38b4abb,107c2230,6f541353,d8627901,3399b368,8b650ad4,cbf99144,780c2949,aad303f,ef8fff3f,b9734551,b45639cd,9437935f,d93f7d95,bc9d1aa4) +,S(bbc52d26,36e861e1,3e593d4a,c6ad573a,e4698ede,f101b3e4,f4aaca54,325b9f9,4a311f44,9f16bfb6,4c5c554,5ba373e9,fc41b7ec,beadb4a6,a929cf0d,79f37922) +,S(bb74e659,5ed6d931,9716b8e6,120f0cb0,57dcce87,150cb26a,cbdf5b1c,f86ccbcd,9f2385a3,bb460cdb,8ec74db8,fc5e6014,f4310665,c5b69e1b,cf96203,1afe085) +,S(67e64d65,badbd97a,bb204cb4,f9009f5a,973700d8,34f6b6a5,395fbaa2,c6eb0672,a122f76f,67490b28,9977d730,df544f7,d725dfd0,93135ba4,4bb348c9,e4dd3303) +,S(dbd294ba,e0775f43,f58ee677,6240eaca,b9b29ceb,92fc3354,de4d4b20,95548050,1987ba2e,3ce8ef0,5b71acbf,4c69f706,e2cb4d6f,354f0fc6,53a7a9b9,5dd1c115) +,S(45c946f3,93658d3e,589fdcbb,6895c97d,60352342,3a3676df,680b6bad,de6cee1,629c7238,db2cd3e5,29e5b30f,a8ba5629,dcbb1ccd,ada1eb22,294f98f0,4cae2d00) +,S(33ad0e14,44be7775,3fe47875,2688e384,2be7ae06,7d38e473,6b7dbe0,c106e14f,d89eed78,6518775e,1ef441d5,fe51c4d4,b2a1e377,eb1a4cf7,804c2e1a,5175f1ef) +,S(f9f78161,4cd463fb,6e358274,e47812b,4b0113d8,3f426aa7,85756c6f,b9e7853e,5eab09ab,51247c76,f87f592d,77e0870,238877dc,a47cf6b4,5fe72940,ff4469a2) +,S(ed3015a6,7a1fec82,f0f7a59c,45cb69ae,8aa0d883,39a05f,f6959c9d,b7d761c5,b7c94a9c,28389f1d,17bdf197,307411fe,1c395483,da8a097a,fb3b5fcf,e392e16d) +,S(301af330,de741ec5,61b71fc3,c5048a42,6b55d58f,800934f5,c59aa8f5,914092b0,3d3137d8,262d196d,872fe1f9,8acba295,fec02ee1,30aa4c19,8c888765,357b67e4) +,S(21e197a7,85953a90,226c1ab0,441e35a0,fd8444b1,92c0e5ad,65588063,f40c1246,6811f94f,18a9569d,4df2ffa7,fd8d75ff,5f66ad1e,62da2a60,c0084381,4437a2c4) +,S(325fcc8c,27804b7c,e73d6687,70db7f5d,3ed4b6ac,feb04003,c61d6262,8fd41385,2110e8d7,24e3a03f,46183536,b208b595,8586202c,2e69b954,d3ee1500,21ae7d8) +,S(48597aad,ec69eb0d,90f60e6a,abf83129,1de759f5,eff24d81,8677248b,ea87d945,c3fd850a,cddc2597,499be90c,24e249b,328728ff,5443fbd5,6515a6f0,4111775d) +,S(58648599,8ac44bd2,e937796,d8dfa60d,c56d94c4,d53cfb77,ee0e380a,53ab8f76,2f47f278,6a285454,475d3c9,ffe9ee44,a93e15cb,b17772ec,67a30943,d3191110) +,S(bd2761c5,722288b1,409aa7a5,db7690d2,73dba76a,3847d94e,3e3d3a7f,2dd35597,42590713,6ab6745d,5e573412,663d4d93,29c4a284,4430899d,68e5ca64,197ad58c) +,S(fac9260f,1d420371,7e468769,1af8c270,dada5d97,5ceda9f2,64deffe9,1990b52a,9ce17c1,ebe94ab4,e092d1d5,850194d1,7e6a87e6,7b283ba4,ba68640a,94193314) +,S(82e65b52,e4585ec1,4bc03591,249cf4bc,e5391f69,7b813175,b3b4b403,a64d6877,627e196b,42d327be,48526318,2dafb37e,222578a0,ccbcc443,7941eca4,a82ac893) +,S(b9473eb4,dd002597,464965e5,b6d95842,543cd14,e18c95d5,b45bb654,eedbd6da,1b6e80a5,377ba31f,b5b6fcac,633321e7,f6e5b2ad,4a54e143,e963effd,6805c3a9) +,S(31113d99,4caaea40,40182db0,17a880ac,64b183af,1746b820,2f29fbd0,d1bcc524,3f476b72,eeeb7c27,f9d04cba,71ac54aa,a25ec4ab,15d77e17,8544a651,653e83ad) +,S(d04adc5e,73e21fc1,8c3b047,4d34f8cd,1cdcebdc,5dabf14,e258af57,860157d2,b21150d6,ad94a07c,d11a81c7,b741a2f0,5cd6a5ae,aba194ce,b874bd19,bfb6c326) +,S(4e59356b,f280f51a,c492751b,3b3c7c2e,3fd1fb58,679b4fb5,5abeeb65,bce6ac2b,33a1ed9a,1d9c34c8,42b95e4a,108c7985,21c1f06,91f3716a,68fa5c5f,89dc73f) +,S(53d76685,9ddc778c,b4f719ad,55f74fa7,85d52300,65c06b1e,4aafc560,39ba3547,168b5451,29170fe2,c53abea9,68a25dcc,2719090b,e0814635,a1dc7267,9d83a01) +,S(7e9107a0,d2830362,7e53e06d,6e82efa8,b1a037a,328df546,a6d04c30,3037a63f,222d8b81,2a99860e,87fa24e0,aaab4ddb,b903cbe6,39c46cb6,3f2144d7,f8856489) +,S(6775b2d7,b23dc08a,beb65049,db8552f5,565a092f,fad86865,c17347e2,a744106b,a6f23c87,fb639e66,9830ed33,34c6dd42,6bab0e23,aadcff44,1d4c73d1,a61efda4) +,S(559885b6,a54fd0dc,b275662e,f66566e2,87a17219,e9c02f68,8c1cc8f5,6f814673,2ec87df5,917d1d7b,f217621e,82c31844,d2bb138b,bc35f873,5b52309a,baf800c1) +,S(6fb774c1,2971b620,b40a17ec,74dccc9a,8c711844,a44a3e4d,e8310d47,bda53428,68ab0f6,57b823e3,35df55d1,ed9632a8,f0825f67,8a05d5eb,9e115ea3,e43ff4e7) +,S(623c155c,2787396e,815ecfdb,5f03bdb7,282aeda1,7c9298f5,306ec10e,21dd0b90,69382be3,a4bae926,47252910,ad1ec62f,f4bbcde5,6259cb52,10ff2158,6b111f66) +,S(c42c41e0,63db66dc,9b32c21c,af94a158,14fd5b62,aaa975d,3ca06925,f6d6ecc2,e93159a3,ad6fbcb6,38f7b09d,40601189,cafbe5c5,90c70103,b56fbd47,d36ccfba) +,S(1103e98e,7a1659ac,4242ad9d,6fb012d9,21696e58,413f71aa,e19fff6f,1c334fbf,9f2d4667,ce5a1285,524d91d9,265d7a5d,da9f5ea6,cd508cf5,90076d57,a975bc62) +,S(9e113cd5,9e7177b9,19859144,598263cd,630f72f3,4da00ad9,84964043,9d82878a,6a09bef7,6e13f2f6,8e70ee90,5dd5af4,495f5965,859a1d83,ef149f67,2643c9f7) +,S(c03c5ebc,d04bf8a2,bdec182b,32d8c726,1913652f,e4547892,3e0dba7a,1fe275ed,f567e3c7,4b9313c4,11ac9411,11f1b62f,74a16f79,e7d90817,b54d4d89,958cda21) +,S(205c4c44,7b84661b,cc8ab2f0,221343f4,140c9efa,fb107c59,b5095b48,25f54b24,94a10344,ac5f48a3,600309ef,8ef94242,a8050865,3c018e57,a7734d9e,da18a55c) +,S(e393821a,58c9e9c5,6e45cda0,334bebc4,359c4b3c,1a60bab3,f1dce2de,c1da81b6,5469cb0f,4edf5f47,80df616,3a6b7074,7b26291e,8830d113,79d84aa2,15814e6d) +,S(38fc36b7,a866b165,a424f0ae,74ca34bb,b05922d5,1bdb447,5df797ad,4d042e2f,a9279b50,4b3edff3,aa8fe039,3415c21a,556609bd,8089383f,f5dbdd34,291c2b1b) +,S(1c4a1aac,3c3247d9,99a75a00,305a4092,c5f34321,d3a33b66,b110331c,85be2b27,a10e4138,a835e3b1,16d7b6c9,46c752e8,dc92c39b,21677968,147a3cab,fa5a0f1) +,S(41d70c82,207c3b7b,716a2d4f,784302e7,e1034555,a79965b7,d951ebac,b7d62c00,7311a36f,cf3de546,37013e84,b2162c35,3eba0387,3d296427,220e5942,af398bac) +,S(bada1cce,dcf3dfc,9834c49d,200fb82a,b13cf2d3,d5da9ee5,c9c35448,352e660a,42e0d3db,511cbbe7,942ff10d,a7d49805,972d9373,a75545b7,206e490b,6c5dc651) +,S(233c0c68,4b9fe726,baf2b7d7,a0503e,7aba8b1b,3c4f28d9,4d095107,2b429bc2,a7bc02a6,2b81154,c3bce0f1,6a0b4f77,d412d162,1c713372,11ac1c61,a8f6fa28) +,S(a675f208,a0d48078,93525e1f,b6c5be3b,ef24ade,8d3ab14a,afac550a,fa6362cd,3f8edef0,3e0600fd,1fdf10e7,c5562ddb,af4266a1,52bfca59,e1235d7,c9e8223b) +,S(4adffdf7,a8a92b65,6f747fe2,92e6bfd2,cd3deb68,ccfd7f01,5639d779,7d21e48c,4d4079af,a6e89720,3a50015,92e43c6e,97fa1e57,11f21bef,c9df4274,441f7d81) +,S(c786e96d,fa658a6f,a9f1fbfb,a15d7021,835ebbb4,3e8ed3a2,c7ea573,c2944dba,81130470,7a10b1e8,74f5b856,b7223346,eef3c562,8959454b,d536494a,f075393f) +,S(10df82c4,64b75895,2c54f335,6fc24ace,cda4578f,d34ae82a,8a1eb2e3,d0830349,dae5c271,86031dd9,2eff2db9,6af91689,2a131cb2,44534495,c3562cb8,dbc5e1b0) +,S(55532c4c,c4483aac,26b049d7,df1da7e1,ef281c7d,bd99d21b,72626443,f2c748c4,58160e32,da446337,d0642596,c17500f7,b0e64081,1017bc1f,4452c4a6,8d2c2789) +,S(fe994c5,d63149e0,d31f6cdb,fce5b941,239c4adf,8d5e6866,37990411,d88ead47,200532b8,4ee2fb18,b2c27cd5,9c3940f3,58c6a2c1,d96ad043,4d826c8c,2a457dce) +,S(c7690e5b,3148cd96,592e654f,2eed33ec,a69d2684,545cbadc,6f6a7e8b,4d3cfbdd,98e0018c,36423854,6dede771,b78bc4b8,c52d956,d26eb22a,e447ab3a,144cd394) +,S(8f1f0986,d273476f,b31d4ddc,de949584,97ec74c9,acc6b0eb,900e4cc,2c98cac3,31f420f4,b9209657,1656b663,a06804fb,78597071,6c138106,119ef214,43aa765b) +,S(bee7ab1c,c23f6101,be01ed60,574ffca,70fbd4db,ae73e5c7,128da065,9f78c042,9187835b,66b2b634,a87d1baa,7666bda3,57dd5ed,26871976,8e0ea9a6,ed102dfc) +,S(8093581b,3205e5c1,90e9d38b,5b5ac422,b48fb5a3,9176bf7a,e1d377,c764f74b,3a3e06f3,4c00cf7f,6216e67f,2d55236d,db54640f,192897e9,fd68820c,bf22ce39) +,S(fc018da2,70dfe007,871e0be7,f5edfb7c,30fc30bd,bed5052c,78a7701b,50954702,9483d20d,af9fb123,723e0c17,7905e94f,462831c7,dceb0238,6f0942e5,188f3a90) +,S(f4ca4cab,7f06af06,d0a8bd7,97d6eed1,7354420d,65d80e09,32f6eaf1,ca12a39c,76770553,69f93094,3f368b0f,2ef6e412,f3d5a45d,1c7edc3d,9550fdd4,ebb1950) +,S(fb03fae2,87265749,787de276,84bfdab0,4993112d,f384113f,1dd41e6a,b438bdf3,ae8829f6,80f60534,50113930,2aba238b,1dc295bc,6598c060,af8393b5,1153b479) +,S(b76268c2,6b873f54,9438a569,5e2d5e24,a92da29a,ca26f18e,143e3290,69638a45,bb4543e,23abdead,c3377320,dd8ffb6a,d38967ac,ea90afd3,23c69373,eeb2407a) +,S(87db8064,9a5a31a6,487893d,f487c00b,143c09c8,fe878621,b592b25a,6c3d8646,872a4547,520d307b,a537d42a,ffbc8e9c,e04d1c80,e3d4f506,b001b0f4,79e92972) +,S(fb9295d5,a7c2cda9,c08b0f39,1fcdea4d,b768b086,dd170d8a,966516fa,bd476acf,62496929,a85c828c,cda71d2a,ae70c429,7bc12f03,5a99ff75,7d66cedd,5fb5135c) +,S(96f749ed,a1fc306,6d133829,774293e0,b179a598,327c3bde,a2e94200,770d12ba,c16915b8,af011de7,614fda0,ce1c4a3,ffeabc2e,2e891e4c,a2d9c277,247fc8c1) +,S(1564d7b9,77b4eb29,e7b23ba7,a3cf453a,8eaadc50,87448fb0,fd9310ec,653ec66d,6d8935ef,a7d41cb7,5c5dad07,c3ca864d,89e49f0,f74d4474,af85bf05,c408009f) +,S(93db7b68,9ed6ad1d,bb61223c,dcca7280,9cf4a49a,14d94f3c,7cae77c8,f1298340,9088165,7b4979f7,26b156c9,d34430db,4a0af993,eeb996c,d091ad5c,4f7bbaff) +,S(2656af7e,d8a2e718,9849cd,793baf93,1c23374a,a3b5596,d8c88841,2b6a5ad9,dca0f4b2,7c7f1547,97346dfc,589374d6,1224048b,ead5442c,9f8950f1,63689045) +,S(a7dc8558,c0adf996,b7f57c08,1b509e34,7819131d,42647498,ba819c12,6d26cbf7,9fc494c9,2bbf6116,14527eaa,1de4708a,f0c19847,3ee9164b,6b9de909,f6a4497d) +,S(1f6d4701,effe09fa,17ecc014,a7a0033c,143fbfac,ba4861cd,d7ee2fe8,5bcb2cda,84c5b017,81ce481a,e610bd8d,96ffa58b,b7a158e9,d1cccd79,7e6436dd,b1308de6) +,S(eefe37c5,d547b779,d905849e,dd1038b,f054233b,f2d1af47,1684e5c2,a1e69960,b5f00dee,8b1f7960,aa068db6,78b6b41a,f8c3e14b,27c1f43e,10f9b34c,fe8eefef) +,S(8d4e8462,60602ee0,948ba5c9,f0506046,d0bf3fd5,e1b93073,bcc8a6b3,30af96d0,62d0e36b,bdffa309,f1257b23,6327506,5a5e7999,b314dbed,edc75800,b35534ba) +,S(da22079d,352d3527,5a80b95f,80b7b8b1,3eb6d178,310b6889,a94cbf2b,9a9a898,e8b06b65,37aae428,cd25fae,d0c1af8b,827b296,886de122,c6690a19,fe94df72) +,S(beb411ff,67cdbb5e,58da6353,172813fe,e386c7,95550395,1ddc23e5,d4e579a4,919f8f30,41f53020,4d3620bc,b0bc80e5,9d87ab73,355c046d,cf2986d3,c9995866) +,S(b0a5732b,76b4a526,e8e742e3,528891c7,3a1febb5,c7657a90,4bc1f95b,96d462b6,a5e4f134,93f9e24,75ac7dab,479092cd,fb59a931,dd042add,3d875e22,76965a9e) +,S(5a87a782,13130193,4ce6180b,714e99c7,30fc8bd4,fd4e8c59,f5b6aae2,f3622561,a929d120,68a64953,90c559f1,ed8ff0d9,bef92431,66117208,d0e8a08a,de9a3d0b) +,S(777ba7aa,6c50e927,64ed93ac,daf56285,9909b031,7c3c5ab9,38ebba26,d62a1748,27a32172,d7ff61ea,b6a26d00,c252f99d,bcf614af,1434641d,cdbd5f4,10e6657e) +,S(ad0f9f5c,8fa07d5d,3c18d4a5,7dc16bc6,3be0dac5,9166fb42,6bfca8f0,65b76720,d2c9c778,3caf2c93,f6c3980e,60ec0fcc,1f1d5ffc,8aff6af,a912b5b4,245fff6e) +,S(8904706f,17aad850,7a71f0c0,94f981e0,5e5a42d9,7f5cc3ed,99b4f635,660e227b,371d5f58,a63ec71b,3cd8b601,ee622586,2822a2c3,99ac70f4,ce293846,23ad8198) +,S(ce32a220,2e276dd,3f5b0a10,38a70f21,3c29ba7,58934c4e,27ee3bc3,c9dadf00,e43d28,80486b34,65e545d7,6618d80c,56874afd,29ea4ee1,e79dbe5b,b1ec1f42) +,S(3d031c0,c717447e,19266420,cef08d59,ac2aed4,7e84c84f,8980e8ed,ee59c7c1,86eabd82,d6a5f57e,cdb52825,a8c726d5,4a9faba3,6272441b,22627c4,a321d970) +,S(9dc08947,fa3983dd,44730aee,d8e94f2c,78eefc44,df126804,281f740,53330b43,58838246,3fc02261,c0e771b9,3d4a90cc,c2c19f7,2893ffb,22fe6d5c,6c5e7318) +,S(f9fb51c7,29646acf,94ecadf7,30989d5e,669ca4fb,3b4dfe66,dad9838a,f239057e,d4a04a8f,f44b86c3,17ce4350,1a2325cd,46b5decf,5f4e14e7,17ef0c30,1241f8e7) +,S(d4a1c33e,816419c1,884c2838,abc7148,c61f05d3,71fe3de8,9f06b580,cc5e1006,28d8f049,a1daec88,5d186da2,66e2b8a2,893d90c8,5e720d03,a53cf8bb,f8a10208) +,S(1b1c6ab,74436126,203ffd8d,8e9c58b3,e18f2767,3a72bfb4,ae4c9e25,ce17c570,ad28aaa5,eaf7128,fc8788e5,b9c1c13b,a4cf16e9,f651da6b,6c43fd1c,cf2903dd) +,S(3d791154,b2c062fb,e1f6ad1,dcc17bd6,b648aadf,cd573cb7,d29f9e47,e089e1c3,a578f2d,a568b0b,e95e1189,7bad8311,3098787d,62756c99,7dc3d795,8e0d3745) +,S(6daac2f7,ee7b01f7,277b3a5a,44785b4b,c6b6adf9,b112dd6a,227b2b46,9f27940a,fe9504e5,75c1e349,9267624f,2b2e603,55befd7e,d66d7fe6,80c521b5,e0d1aaab) +,S(ea6343d7,73a5966c,2ea66806,ed59079e,8b216a9f,4fcbe8f6,744808b3,2478c26f,15ab94e5,cc1f4a5a,33955f6,b30571e2,5104c615,c0aef2bb,6a8f6693,64639f6f) +,S(ffc78cf2,4b436203,dcc1b892,c77fb336,463a8070,332783c6,1824acb3,f5cc55c,7bfe0b6d,666b28c2,3259c4f9,2c0dd94b,fcf53921,91d617df,da1c651a,1fcb81a3) +,S(db38103d,5156c309,67189677,9317879a,f31dcfa6,b8d0f5d9,1f2bc691,6090e6b0,b5b3e45d,9bd41082,cd3115ff,824ff027,78f47a0b,d0ae71fb,32c48d72,cd540c84) +,S(4c08de87,abf89885,2791b455,126e7e54,d660903,f407b842,7b4fcd70,53e0b000,a9f83c6f,dcea99fb,fcb301dd,c31146c8,25c02978,6e5019e8,7b1b6db0,731b9189) +,S(53b6a23b,8f93200c,41bf45b2,bd0d20a5,e6fa5db9,a3686a7c,c669815b,993604c5,31bbf5d2,21023fc2,fef75f0a,f7bc33e,b4d38323,cbdaa511,c40ed497,ef42a850) +,S(b39ebc0e,53b74f35,6f573a40,1df6f8d6,fe1e4fed,f7d976e9,949da398,a45b464e,9d58ae16,a633ea0e,86bad1de,39f0b203,c1ef0b24,b5f1d824,48fc606c,a97fdff1) +,S(182e4920,f4a60741,a0b94fc3,e3ff0bef,39f1d459,cd6c18fb,16b072b8,de0bd416,6d048d0e,ffdf4e60,8097cde5,46955541,491721a3,d6e051ef,9279c5c0,22a32fb6) +,S(7a39e7e0,a2da209d,8cbb9797,5f12acce,840dddfc,5acf7c5f,fe778a11,829e1003,c24aa083,20e6a786,1c161e14,f37b1c7a,65117e55,2c252445,20b47b67,66fb410) +,S(62e6173f,2273d3ff,d9fb640b,87d5cb15,e5df841e,3462bc5f,6b94575d,a110914e,7c424010,4ba37e57,48404997,689a01cb,851343f1,ea8259fc,938483dd,d70ac5d4) +,S(3960d4cd,96de0126,5c2cc88,68e94d66,40e9ac8a,f2abfcd5,2108848c,ad62467,fb24aaf2,85a54405,f75db03a,464bbc29,3bcaaa44,344c763f,dd44656,fa7faeed) +,S(463437ab,42694ce9,98ac17cb,fd4d9034,ab7a1be0,35f911e2,864441a3,eff8e3e3,370056b1,24b894d6,3631087b,194dc5ca,fcd2475c,a95402b8,418f1954,d47599e8) +,S(65774018,fd428788,e4234b36,42c8a354,770ddafa,c38040e9,49f194c0,ff7ad3a4,462ec7,cb17abb6,5200a88a,9874c7f9,40469a51,c48c1fdd,6c0938ad,67741467) +,S(738feb40,e7f16fc3,19ed6649,2507406e,6501308e,5112dff4,db9d12d3,bc0f138a,4923678b,84470212,cc5472de,2163ac3c,51ed5419,dc1b1b1e,78dc0946,f730b940) +,S(546841d9,7985d80b,a0eb3448,3dc5d17c,441b7eb5,d24b6216,ab98b14a,d320cf36,719434a4,952ee43a,b1006ce6,f7785734,c6a5c018,383eed75,e3660f7,94eb6829) +,S(31143de9,1a4b96eb,be7efe31,56b6688,5d39ce66,fa8ce202,57626dc2,8557ece4,d8d8bd18,36e5c388,2273143e,721bef10,b0c3005a,5e2fd3a7,e471ae33,ebfae7be) +,S(ad8076d9,29feddae,a52c009,f3967726,a0a94301,dfc12d59,da63c47b,df6566fe,39eedd66,13fb7141,796c0353,9f560ac,e23f844f,d0d3d422,5b36e41c,b6707602) +,S(b01a4f7b,9362be2e,78f5cdbf,d9e35f21,4d296a3f,3e233d93,2cf33c71,95b3f613,245b535f,c58254a2,157caa87,38e855ac,fa9b071c,1b6182f3,5260da9d,18e385cb) +,S(50f3458f,a781d513,a944ebd9,6f6b791a,1b0cedec,1421f9a0,16a7f350,2d5f429a,4972c646,c1ad5958,18766bab,5bf54ea9,e9c4fe3,19810f1e,27f46cc9,41594045) +,S(d7b606ed,e8fc3a20,925e0a59,5c9462d9,4e04b5c2,b64d13cc,19a47d1,ccf10b0a,dc39a8dd,d5447a0,f07b5e7a,6ea35286,ec01679d,ffb6eaea,6222711a,d57cc63f) +,S(7629836b,73691a1f,f3ae6c99,7e06f597,34fb9625,2d1ec88f,2af15cac,f89c199d,296e4034,8eacfd71,7f64beb5,76736398,62114296,5fc818a3,ea89ba52,1b1a410e) +,S(88f6a162,7baea31,3a2a5d5d,aeda2f4b,4becca6b,812a60d,4b5b4e22,6c822a1,d3acfe53,d6189ab8,31106ca8,2388fc28,5b567e5a,5172050,5be56bf0,187534eb) +,S(8e93c72f,cfeae58d,fecd373e,dd3f31ab,3e4fa28c,f53681dd,ebf37d40,c376283a,e9c82571,2d0cfc0d,e6f35e77,acf0597a,7e2437e2,80f13420,cbe93acc,52901d71) +,S(b2264df0,eaead63,111d7b05,8767cc7f,36d386c7,edf21792,e8aef135,9958b2bd,242eccda,5e4324a5,40e8d098,cad23ecb,88955bb1,126314fc,5da973ee,b1d83313) +,S(9f1c9e90,7a6813a8,da520f6,84553a4c,aab650a6,7eaf4f0e,f2ec212b,95a885ce,416dae6b,f47aeb47,453fd0f4,7da6375d,136b6ee2,450bfe75,504f3619,84a0f355) +,S(dcc7585,132b95e6,a4a24450,d557a0fc,3ec93506,fd1f5f02,17bd0f7a,6943fa1a,c62ca95e,d976d1e7,2bcad48d,9bc3a316,a35e8496,952a7a07,760ecbc,8903b001) +,S(e3c674b1,eeb380f3,f08b1d64,32f4dddd,77cb602,915ac478,4f3c769b,dc2a30fd,fa8b08f9,8bb4a1b7,568c9d3e,754292b,1a35cede,1b377c99,fcee16ff,a16bbe5e) +,S(1152da70,2b7341ff,69e8d3e,6f5ce8d3,bdcd3a03,27df54bb,846ac8e9,18e747e4,7c139d20,1e2ea5db,984cc8d2,4b66c64,8adbd0c9,48c0b085,d59c73ce,b4d7a91c) +,S(3449cac4,abbd3ae5,e09dbc5,c89258a3,df93ead9,1f62fad3,a5add3f9,87a2f83b,197ecb64,5dc998fe,eb9b0df8,6267c7c3,f7af9647,96fea60d,88d4de89,33171e2a) +,S(ad5cc468,11c5a39d,ffa313f6,578acb00,cdda9ce,b3757479,9f2afd6,a8df7a19,4fdf6093,c8fa8a92,7702982e,7e638948,b982d84f,ae6658bc,fa839354,6d6e76f4) +,S(acad447c,b57e8f5,f528a113,347e5c5a,2097766a,b4664c70,3f496635,759a7799,88e1b4ff,3bf3e967,d2c6c948,4bb727a1,d13231cd,acc45463,d421431a,b6fc46ad) +,S(b74286a7,e2699aee,9802563a,4da514cc,d74fd001,48534822,9214395b,36158246,8df2b491,ea018b23,b1c7fb54,b7a05db,b79b0ebe,1117e2d9,ce73e70d,d097bf90) +,S(86bc560b,19d583b3,62c1634a,139bbd16,db30e823,75913cd6,fb688e4,38ceca4d,2126168,75c3adc6,c2aa16ee,2e028052,9e6612b,fe4b1aee,e4961feb,f530423c) +,S(dd79faa2,e97dd468,5f3ff8b8,d5e55598,73736de3,9493a3f4,4e679516,f51e495a,2cb89020,efaae785,5376d901,4d1bc374,21e0ee60,29ac70c4,65bdcdd1,e240e57d) +,S(caf6318f,825ca3d8,6d45c681,60d897d1,76875e26,bcd36d00,82b4e1ea,e6d8c142,d7abc304,55a5fab2,68c6d17c,3763e586,5b9e266b,bc6211b9,48b5ff3d,19f5df72) +,S(c49dbf15,70c3f0ce,1afd166f,884af550,1f26905d,2f726185,7c026405,efe9a2bd,54eaad70,8bdb7b2a,59f5d69b,5be6ed79,5fbc4137,945be17c,b4736649,6e8cd3c0) +,S(a87447c2,83c88db2,15630cb7,6029132f,47dadd57,5ea6f9bc,10d1b36d,8317a91a,8489d3c3,6334d65,fdf6089b,df19c3e8,7eecd697,516e1756,5fc8b977,be82c363) +,S(7467b357,7d21b028,dab4100b,ebfa734d,36345024,adc60b1,10b8f96b,c7860889,b2978a5d,dea9765f,7877d8ff,fba66c0d,f7c8e0f4,6854deab,21908da2,8572b1a2) +,S(6af133d9,bf2d6b57,ef69e0e7,5eef6d,eeb82d31,af490320,bd26f4eb,38ffd42d,7f4a4d1e,ce23c530,a4d64c23,cf0bf8,a46c59aa,74dce4ac,2854c6bc,d11b056f) +,S(faff2662,5a41c80f,c0889d4,83eaf50c,596aa571,6807b118,1e94ce5b,581b0a7d,32f3d057,4afc487b,43b129af,f83bc7dc,d495402b,90fdc30f,736e87a5,469e8aa7) +,S(8c6983d2,8047ab24,ddb292cf,1c8836af,7e75d7ad,6ce23149,e022cb64,2439ba2f,70a10314,447eaa73,924fdf58,fc607dc1,c69a69aa,29b84dcb,156fec4e,568a5bb9) +,S(bfdda2aa,b23a37b2,bc129bb4,280a2c45,926360c3,2719872c,ae1e81b3,1b3d3d02,e8319769,b7d21199,9e5de1ae,76021c9c,2bf75ed0,4c9a6c2a,c52da4f4,88cf78a5) +,S(80e24bf,3559d05e,c0cf63af,21dd7adf,237c23e7,ed930c7b,4124ad4,46871de8,c8f37f91,4e78e037,602ae9bf,ea3511fd,2c95ad3,6665117d,64f9fbbd,ecd10063) +,S(7f56d940,2d6fb0ed,dc6ce187,2ee8e55f,45db30f9,8defa84d,f7fb76ca,aef5e800,f43b9e6c,b60ce85f,44682fae,d8a48e5,3d9599d4,f19b4757,74f7d6fe,2fb2554f) +,S(437e7a08,900216be,72f14ef7,33127d49,9130309a,73369d2e,58fd4187,a0d428bd,3f0a4c4c,63dc779d,69dea37f,786a5157,43b3560c,16d4e56,4a1d7802,f40dec83) +,S(3bb8db7e,8cb3534e,d7f70f8d,eeb1cb81,3ab21dd0,552c311f,f98f38e3,63321626,9ffd98a4,b3c271e7,83ec8c72,98ba83b3,f4f0a5bb,61ce1edd,5c1095ee,eb16a569) +,S(21de8ce4,6aaebc6b,4ac51620,e2c78904,f9300b6,2930fa79,699e2782,5dc2310f,12a21855,50ceab27,aeb2e7cf,14710b7c,b3dc837a,67a1e4d2,6950e2b8,1942b9c1) +,S(6c24ddca,e4245972,5268369c,545bc910,ffddd8c3,49d83fec,eb27af78,cfc0c965,6263abc6,ed17a124,c8b2c5e5,c91b157a,13512939,b9d60e48,929fe6d8,4d032338) +,S(ddc0dfb0,49f7b6b1,cd1d03c6,f8ed2470,ae320f04,bc6f13f5,a88ba89,7bd1f91b,57c5f0df,8fd22e02,da44cd05,74fbcc1,c8b4a903,a909f906,aef9208a,89eeddd0) +,S(6fc5fdee,78c61421,a3ec2284,583a56d8,f18e66eb,58c54dde,e5209a1f,3e3761eb,baeac905,6101b825,8b08a807,72c977bf,60956b2e,d98d1b25,e71b2b7e,10e3d25e) +,S(1b6735d6,ac2f1db0,1c3781d0,cf42e2cc,3ccbf030,2e3837f1,3f6655eb,ba0dfddc,621e8c0e,cedfd28e,608c3da5,135d63fb,93dc6919,2a6154db,bf63e315,2f7db68e) +,S(1a875a0c,ecae6600,4bbdab3c,4fa5a57f,925079dd,671bd9aa,e8ac5c51,b21a5e83,2317a0c0,81c17bed,a15e1148,f44beb72,d4e65fa4,96408778,8216f85b,3924d9fa) +,S(51635c0c,ce51684d,9631c8ad,f6c9c4a9,3f66dc04,a372c891,294c42ae,2be5a84a,5c6cf3f1,bbc9c21b,124e78cf,ba05b2f9,ffb9c902,3895d584,48622259,635d3517) +,S(c548df8c,b685f457,71c564ed,a3e9a77e,a4734faf,7cef877c,b0bd70ff,d85afe0d,2675d6b8,24f99a19,8825f1ee,19510492,9eb633d0,367c01f7,c922bfb,c2cd6dc2) +,S(121592ee,aa39a310,3c02502d,72e360f,f500853a,7d2e449b,16c5e443,f42e700c,b5cfa2c6,689d973d,e0578a39,bc687720,acc0305d,6ad3b678,1d36941b,7f0cb435) +,S(c2a8b66d,cce99233,b3d83699,b20f0c60,21a83ee1,46a491e6,d7e69ebc,92a3e046,e0f3aff2,64228803,d8c1d729,88780d2,ae8c344d,f9571b86,70254b39,b4243705) +,S(b2b703c2,56ab219e,528886a4,4d6b7772,5cfc1b5b,17865ecc,c46e2d2,2420514d,b6aff027,b4408177,8c6cfaa0,123590a7,4615394c,aa83891d,15013d35,ba28a9cf) +,S(d249c36d,fbf43f5d,c6ddb196,d78d4cbe,898d64cb,3b239f89,1e8c4245,ab647afb,4e58c9e9,4199e0b7,8a0179c2,c82b6442,17eb3fe7,80c687e5,166f56ec,f812d092) +,S(ac3519a1,92c13eb,b37cd560,1a141d80,817226ec,7c86a053,42655c1,997b476,3522765a,afc2fe6b,2af9b489,27809189,74c2bc57,58ce502,13777ce1,a569083a) +,S(e9b69596,8983ee86,340b96ce,efd9a289,e86e6d49,3f057962,77b99067,af83c70f,983a83a,e1b08fee,392e51e1,c12a8e12,731d592a,517e240e,ea508f7d,b34059d5) +,S(e11e982f,10e65120,ca357106,f273c5b2,9900454f,81456781,36f52871,65444dd6,e961b155,81ee9ec5,1e6a3616,b7182da1,bd2e5db4,d08dad5b,46bee558,44c21850) +,S(f63f4434,bb0c17dd,3a17c75d,2d179e41,10a7810a,847bd4eb,37827997,94e57b14,480bff24,69c2e268,a51b2147,3d6cf7ca,23a3c61b,513267f7,c25b092,7dcc8549) +,S(cd8ea46,d65bb2da,7234508e,fb48a828,27678525,d102fa85,6d26475,eadc1a69,ba231ab9,513f90be,9cc8260a,fc63b05a,5aaa0280,3502532c,916d99c7,20b7b2d0) +,S(af9a2285,ec491b56,9cf53c8,6ec188e0,5bf18d1c,d7e898c3,c881a5de,481bbe13,a0cca7f3,714f8d00,92af7bc9,62abbe5,4d106dd0,a6089607,35a6d9b4,73d9ed58) +,S(5d90a039,55f41998,62e5cef1,af05ddd9,114632eb,abf27d6b,9b92c6c8,cfed8640,a0025e54,482aa49,11d8a556,2205c2ae,2a0f75c4,6f3faa55,7463b9b9,cce1281d) +,S(aa1f071c,55541753,3a47b490,c5603aed,2d2e5282,71acd0de,6ea7c5bc,ba66a348,195d8b00,fd90b1ad,15e46620,22d78bb2,47c1e9a7,8ab3b018,f341a005,6267a167) +,S(4225728f,ee2495d6,73f64d5a,cee2e372,2713a3b4,dbd2f098,d20415c9,3ab513e6,76c17939,461504e6,e1420d53,c5b07449,ce7f976a,e4de178e,69552755,75e92412) +,S(669c2815,b3357084,bf7bab89,63753b0b,ebbea33e,5b731ba7,5f969890,3a281eb6,23fcf486,e2839e2d,91fb08a9,11ed7361,81de7406,54c13306,575c576c,d0459c28) +,S(7b29749b,393869b0,d7f0977b,340b9e07,76a20ceb,ff6d8f8e,f4650348,11773665,a0d68cd,b6033ab6,a4c92113,c8f07110,aa5cf600,2335d2d5,2ca9b956,2874832b) +,S(6f096ed8,56f38c26,25200774,77ef7ade,19fb616e,30ed560a,ee5b4987,5f43a7db,54453b3d,1ffce3dc,b5e72ec9,3f15b57c,6725b271,d3fe8b7d,8f30ed00,35845b6d) +,S(1354de01,ef040d5c,681318c5,a6dfe7af,5c8eba0e,ab581674,acd5335c,e33c4bec,4002513f,ed215b53,c65686ad,8366cd7e,38711fd9,98d27750,bfce7e24,dda317b) +,S(5f8afb0b,3800c535,47cdf93d,61ae5c67,233c2525,17f99c38,8e97e7a9,1a90b561,7dad53b7,a64b7068,967fc0dc,e7178a43,a06e56f7,7aab1a57,7910d69c,23540671) +,S(901d50d9,b88abad7,84e75135,85a81d9f,a1d167f2,c9f377b8,e2598cc7,b249f3d8,7242b591,3c80db3e,748c63ae,47ee6229,2c1bc29b,e9f9088d,fb882259,405c3dd0) +,S(2f5e27e7,4c7e00df,c0bf6401,7d1a888d,1bb7a3e1,3ff66874,f7c306e3,806a48d3,87c3836c,7fb767f,4b5ac585,62c48a18,21dede2a,7d63fe40,da75d967,cf9191d0) +,S(8b2277a1,70464589,1d8b54cc,43bd5fc3,54fa6f1b,e7a062e6,6349ac2c,40eef8ba,ac3a007d,6b3278de,1c043476,13b254b7,69c9e14a,c2f50f9d,5f025046,2e06081f) +,S(4a6273a4,e9f28e9a,82c3532b,e7d3e564,66e87273,ad1fcfad,7ecace6c,54890de4,6d8b0fb2,1cb99844,610a325c,9592cc1d,e7c8b32,d70e19b7,ab7df472,8fd1aa51) +,S(f07330e,2ab0150e,435fe3a6,8c703091,4e7fb52c,307d58d5,d5120bfb,891f84d5,25b6ebc5,4c1d9206,33891a8e,39aadebd,988bd98b,a29b04bf,6ce4c283,a4438b08) +,S(3a30b22d,6f1fd617,9fff2c21,d6635828,8c21fc8a,94a274b8,993ecb91,eaab54eb,94035c56,6ea179ac,d58eb0f9,d12cb41d,67b94fbe,65805110,61cd9806,890946b) +,S(8c4f39cb,87d7f65e,591fa10,fd46d08f,fc5de3e1,67d8c9e7,718bff95,b112a5a,726c4bb,c64373f1,9399db5,18b5f823,3faef361,3e363b84,ad76052e,bdc8f2e6) +,S(38118e59,63a1929e,74f6d98b,c80e44e4,d9b32254,6a0f1eb0,690d08f4,f3bd4bfb,23167e00,c29513e8,e82d1140,bef5bf02,b806a652,fee592fb,1dad0811,604a4b50) +,S(75d4246b,db065274,550e9784,f3c9437f,3aec0fde,3af54a0d,61430cdf,2626bf5c,8392f570,3896cc62,d66f8485,9f7f269,4ff40a81,9505447b,7d79bb98,77f8f621) +,S(ab3bb0ae,c1f390fc,8d1bd3fb,4ecdad66,3db868c7,c4fbe0ba,6cf4f059,7068ed87,91382a2,2dcfe0c1,b51148ce,bad2140,24cf099c,e3e5e3ee,867db7ee,d070c7e4) +,S(d1453e12,383386e1,1976cae0,8a448b63,1a977dd8,47c19d2f,d7a212ad,5090011c,7044d595,fa8f68c2,4a972658,590d7ab6,dfc06ace,b9d8c320,205b858e,ba0402c5) +,S(894afc53,b0d1bb6a,c948d117,7e83c42,b4ff4084,e593fd75,d0660680,2ec0a4eb,5c5eb493,73e74fc7,39ca4fba,1940ebe4,6912d896,7cfc036c,7402e8ff,8d071d7c) +,S(f1dbde60,43133dc6,8699e89a,3dcaddc1,fbcb5ea5,e815eb5,8e7a6b87,dea2e6e9,96a7b1a5,b36e5492,68168c91,775d6107,a3f87f9,fb5c8b3b,acb75dad,5dc544fa) +,S(ad9126ba,6d35d780,dd2841cb,2ba817d3,f0267446,ee99abd0,ee2b4910,a4450b8,f77eaa1e,66c0f3f6,88268d92,9c9ee53d,6dbbc20b,b74e864f,d7831cc9,3d47280b) +,S(70d5638f,d3fc43c7,6f321157,f9715994,3b797d8b,1d366f5a,a5a7f1e4,ff1ff7a6,ba6f2d41,7af1c5af,dac8c83d,dcc289e9,4d6f29b4,2631ab7b,19414bdf,4a9ece36) +,S(e43bb23e,1f82bcd2,708730b9,3d3ed915,e3b4ad84,61904f68,bd91a065,80a4ebad,3b528db,117cfb49,99941b0b,63f51ef3,926a6230,dadbfcdc,28fd1d6,2bd44147) +,S(9daf3516,a015bd59,b648fd9d,9143e76,46b2e3fa,df5e446a,c57f2e22,9c9dad2b,5ec57ad4,808a9f2,ed297f7d,a7794e2e,3f1bb14c,bef58047,e0bddfb1,8ff11149) +,S(13970b21,3115c499,5eac245b,33633c53,1f2be101,a541f129,7403a727,67df16f8,3444e05a,7e49ecfd,633c96dc,99a0fc81,cc3c359c,440ffcd4,5df61c5d,1c027e97) +,S(12aef793,66978a2d,3fab4377,7debd5c7,4315b002,829b49df,c80fbb4e,1eaa94c1,e3f5c1d6,ea42b741,8bb3446d,c23679f8,e7a96d02,a8f33d1d,3404126f,71f9e37b) +,S(62a2ef7b,887de5a6,19c753f5,e0bc45c1,7c47b8b1,ffbb0ce4,8b93caf1,d1ab4b02,7d00482c,20c25e01,ad6ae35e,89c263a3,5d0fc816,952a96b0,9f2c2fa4,b8fc9bef) +,S(e6b03f17,92df5b1e,ec324ea0,898c031b,d745221e,791d2406,2aa917fc,de6f8a87,b4ee4b18,41153d22,1ec0ffe0,ec05b1c3,408d71c,5d2ca29e,a01ef9c2,e669b205) +,S(dbc02e03,e03e2f14,53ff6410,afded1f4,f0d51461,5ee00f75,d041ee33,c4f35783,6a3a332d,99ffedd3,d442b44b,aaa9d12,9d93e372,36dad034,9c47bd83,7c7674c4) +,S(f11be23d,6884890f,78ccbcaa,c1759ceb,5e7f98dc,19073aba,b85d85be,5fd23ef0,9afda170,dc1270d2,e43989a,4ffac7d5,c848ee6a,51e03b58,c308a4fa,39e2cfe9) +,S(16ec4f95,1db5c83a,c2c26209,f2577650,e9c48c44,224b221c,c09b0b19,1c1c5552,e3959034,d259e9f5,163a44da,f87ffd63,7a35b220,eea5ec6c,301cba9,eb09dc54) +,S(3cf701ab,8991e981,e9cbfe30,7b3aced5,c2147c47,f76bc2a0,733ee544,3fef3f99,1e6a3069,d4d0bb8c,def98d49,cd303b51,c45617ed,833be051,ca2836bc,13b8e1ac) +,S(96d093fd,1a8efbe,4f93c544,d0d7e397,cc83e114,4574f804,570fa3ec,58d5669c,2a29438,a05fe50d,b980db60,b343b06d,1796ddff,7e7fe39a,356cb608,69c05ccb) +,S(a6457eee,21025732,5094d3eb,6f6ea05,21e83184,adeabfa7,b6cd1206,9a9dc9ee,83e436a8,b234778d,9c7be0db,88639177,1d7a48df,19c29c47,682fa2cc,30b5e7f2) +,S(1b366505,1c858ac3,5890e7dd,b4aa7984,dbacbbe1,f4d2b62d,5337b530,da9bb0a5,39d3c2d,42c5d292,40b474e7,2e94a64b,4612f5a,68f5b6bc,586db5fc,a41025d6) +,S(e09325f4,68328cc4,d69a71d4,8ffe0380,bc118cb3,b8f390d3,4c1e56fd,27f4589a,16cbf183,78946fb8,3ff9763,41c6cc3c,9b2f451d,7661bc3f,3811f7e6,ea89a01d) +,S(6a8ea7a9,ddfa0f9a,8473c47e,f5667e44,3e64e03c,5c33a9a1,f0f1257b,40e1ce62,92806471,56238c84,9c0aadaa,2e9efdcd,e5a56a2a,78803f7b,66210333,88f525db) +,S(480b30ca,dc57c623,9ede2763,f113b46e,599076ae,ec687c49,33343178,c620f2ea,b5aa1b8a,ffe1e5ed,de587df3,341dd34b,57180cd4,752a1bfd,d06e4c2c,273b4433) +,S(134be6f0,b03ea43e,98e2364,46a45253,ea5822df,46227aec,b24b09d5,b25a34b2,d4841d54,b7fc1736,b293d314,bf6352f2,c7b08ece,4de652d4,2c1b985,d1fd78a2) +,S(7c84e23f,c54de6a1,a4ff6c9a,c7c88ac6,732d019f,a53b1a9a,a6eb2ab8,a3101f31,4ca88bac,a8d52f44,3703fa27,4fddde3d,ae5924bd,26b062fc,6f7fd0d,43ddf5ad) +,S(7c6a349,911f02ef,2aebdc3b,ce77f639,94c4dd2a,a842b567,141c023f,4f2d92d5,9b4f2f9,6215aad9,c7e0edf6,efcd8aa8,74dbbcd5,4a0c4cd0,fb7e01e8,ba6884af) +,S(9e1dffc6,a919c9b8,4e3d818a,5ec60f7d,5a2baba7,7d2dd65e,137d2ba2,8a1aed3c,cf26f543,bb7ef705,e2d3c429,f0ea27,84e3daae,1a71c556,38d281fd,aa3b1738) +,S(e24f6abe,c7519588,33ecc765,7446ae36,937e310b,d5754c5c,343eecf3,6e140079,c38a0399,774ff24d,90f8e599,183bf011,aa3c911b,9a66bbe6,920522a6,7510e62d) +,S(517505bd,1fe28c21,2fa85f18,99823b01,bcc3bd1,748169ea,54f35ab7,870f0e1,da94c34a,5de41881,1184fe92,8b3f08fc,362aadf7,5e7abf87,5d5f4798,fa712f3f) +,S(a02217de,4ec87155,b877b7c9,dd7425b9,79627f0d,ebe127ce,27d4f3ef,fb988a8b,cdbd866d,7b69e8eb,9321d07b,2a5c9d8f,6eec8be2,f19a6d24,4c987a1a,12752bd5) +,S(2e595023,c8ba084c,1cbb2d05,96ec35b2,7c366bf,cde27666,35d7e820,8fcb0ae9,ac08f27e,b8fd5ac4,deb1f46b,23ac1c5c,aa02b918,9761e6ba,d7c1ebb0,f412d8cf) +,S(ce384358,fba557d3,b76df62e,d2264cf1,e0bc7b43,bab30be9,fd6f65e1,a82b6c2f,a3cbf24a,e067ad85,ae0fc86a,6e8490b6,1e44980b,52f29a75,4a3f7e4b,a79ad119) +,S(9715da8,79cb1c5c,4291e00,fd2822c1,7f067d63,664170fe,463e86c2,d25e46,c5179ad3,a4846fb8,d6f290b9,2f957e14,cee99f6e,12fc8066,ec4dfaaf,a82edb99) +,S(19f61bb0,4cedc19e,5054eeff,8d0bc384,6cf62a35,1af3ab95,e03e45d0,786e1aef,aaacadc8,db84d7c3,f869931b,bd33d295,45fb37cb,7e474fa1,7a69a683,117c05b8) +,S(2a69afa7,581777ad,38882f6c,659ff4da,33fcdc17,a5355583,d1f8ae37,7dcbd718,878eb429,d42dfbd6,435df1fa,c5e0ed4d,e7b2fe4b,6f7dd6f2,6a3150a2,213fa619) +,S(c3da1980,cdf257db,f2a5eda9,94267691,a5e1e679,79d4908c,c06f7f50,71002381,2cdf4de1,90ef2995,a984d882,598c24cc,35cfc47e,5cbd2d53,53d880cf,a944bfb6) +,S(19294eba,9d19c03b,497551cb,7cc8d8ad,3e3b2130,942ca8dd,c8bc5579,1c424d2d,5523ac45,e676daaf,2d8da00f,5e9240e3,d904a536,63e6b704,735889c8,84b680ba) +,S(d8b3b307,41ee7ff8,2306615f,2d2ef361,6e3f7cd7,fed9d56e,69300fb8,5eab6bd3,7d57c12d,e65bf3c4,6dde736c,373ea374,d090b240,6e1d97fc,8049e21e,aa10a74c) +,S(e2fa1bd1,164528f0,87c72a18,e9843e33,43b376d9,b5616b74,5e0c3d00,eca95fd1,72dcfc41,15b35406,8bd3057d,506d592,771eb3fd,60a2c2c3,dfc2645f,86b249e5) +,S(ac587775,bee32b7e,90031ad8,9786df14,8e4d9662,55a06399,e43c0441,883fd6b4,b6d3eaa,6f6a50ef,ef84c578,b241591e,4a718eef,fb40ac34,99a57079,b74c45b5) +,S(74976cb0,77d481f5,e6bf700,6db57a13,f362fabb,e6aaf25b,6e956452,9d093bbc,bb40be31,7cfde25c,75ea859,2b622e4,9d42a0a7,30602241,219bcc84,a5f4bfe1) +,S(e71e6967,f32647fc,2c13a94d,4bc1410a,cf9728d,1f543522,681d750b,2620a668,33c4fc82,720210d9,afb9f1fd,51671f3f,fc1df5f4,e61a5ff8,c59f06c7,91f996de) +,S(bc36cf57,161e9b17,828e4557,74204c59,805b35e3,abdf4ba4,daa9a5c3,fafad6d2,df34c492,3018e879,bf459cb4,528d2983,340444f5,a85efc29,71e260df,29cd8a20) +,S(925251b3,9c8761c6,317c2066,717a2e8d,89e43acf,89527ddd,6078fa49,2d040f95,aa7a084,8b2633ac,ce551f1c,63312895,f4ece420,5e224665,2c486beb,b8131f10) +,S(4ec27df3,d9e755ce,b93e1ca0,e0e43f44,595b529f,6460e3f4,e6cc3765,3a2bbb21,eee3fa06,257b4be9,387ac7b6,6cc1ff6a,aae43583,37d6ed71,27ff753f,1fb179ac) +,S(6f733e9c,b86c3a17,5bce6c08,347577eb,69cceb17,3c19abef,c94b6646,92859812,2a895d6f,c4a7a4f5,610e8b8,9e7361bb,db728625,ee31e6de,927c74f5,b10ad0fe) +,S(c631f4ec,f205b1b4,6bc0fce5,3680e6a7,27f9e64d,5ee3fe24,c37291a0,d3a69b53,f0de9e0,e4bea2a9,cc01a5d,2f9aad2,f5af7ab2,7c2ff98b,983dd2b6,38dced4c) +,S(9326d449,4fcb3049,8badc221,6d3a90c0,131d31ea,cbca74f7,2cf7da2c,bb6aa2b8,c3f268ba,4c9a9ab5,3f9edb88,74f2786c,4e4c065e,ab58487e,cd8101b,7132511a) +,S(538c52d4,8fa6c492,cf546349,675d6a2c,ba10b442,8827dfeb,69f0303b,1b7ac774,c1b1db4f,d6d50f3e,c7533ee8,cea0d47,883b57e6,dd4137c8,2132f846,3b81ebf9) +,S(5e58a25d,8bdb4576,d178fdb7,23158d26,508f8486,ad553727,907901d5,6e99a680,97c1f814,8880cd85,51c9f1e4,9ae58eb3,d1a01285,bfa8248,44bc794b,7d83ec62) +,S(1e9830ee,b75d6c6d,c70989d4,ccb85e62,34a1cf94,ef81b65a,49b25753,cb6c13c4,d0780a7f,9607e530,d80dc068,68b1cf8b,82d3047a,2977d204,65187ed3,13c94c6c) +,S(c5b441c2,f7e97a03,dd690cbc,ac605772,1524dce7,fb5068f3,f73d78ce,50fe0183,9bdd2242,e35008dd,4f907600,64eb3b29,427ee9b2,bbeeb548,62878688,a916e410) +,S(a5f56816,e9448d0a,aaa7593e,e3145678,3be74521,b129f13,f11a276e,d419492,8406662,65c275da,76ef289e,d36f8af6,6ead9be1,48cec081,7c21987e,9e8af9fc) +,S(c5e85955,44004f79,2260d553,25628858,ce50c95b,9362d868,90fdfd20,8d1184c4,6a5f02f1,c0f381f2,7fd21eb,928f03a,c8524dc5,9bfc1bca,d025a290,7cf939d1) +,S(d5dd810,9e691f5,8694c87b,59907ed5,ec18d37b,8554799c,1481ac78,825d2ac9,ffbaef54,fd35a5ab,a49f9946,a11e5ad9,2f29590c,20e28180,9f4be3e4,b156dbe0) +,S(ee5d42a2,c705bae5,a11d9d09,af3217d,2ec16588,64a60a56,d8e4a1cd,4313c61a,f08f0e08,89c015f5,3a2a74c3,3dd625da,b329181d,1d0f4fa0,14ec01e9,5d113d88) +,S(90409eee,78af819e,249f62ea,3b4d70a9,26557f8,731e50ed,532c0b30,4616d615,17aa7a7f,8af635c9,c4ea353c,56c89da9,70df599a,faec8916,ec9a6d82,cdf957f2) +,S(5f19aa1b,a6d6e3d6,9445e8cd,71c95e3f,a3ddad6c,ff0dcb4b,9e09aee5,65ba9e46,f82b3170,c2953397,a6cd29fc,9c87bcd9,76cbc7a3,5f953948,5a57a940,63c2e570) +,S(5081942d,1039bfcd,96a759c9,27583c45,8dd4c013,59fea307,40c65fad,d020606b,f6f204b0,97cecd15,b2619aef,c25328fb,226598b,fc9384bd,de99a4d6,567e9b8e) +,S(43eea7b1,acbb1450,c9a49b0,262639f,702612b1,b184ac15,675d6496,a5df1a54,a31636f9,ceecfbd6,60f78f,f6cee471,d4366d7f,ff863db4,9a5a652c,71b94797) +,S(f2860e98,a30a6c14,ac43dc9c,61bbae1f,b8ecb294,36c8f0a8,7dd43c01,486706a1,bc83bfae,9a4effeb,4beb025e,962108e5,4a5d7979,cb9ae2a0,7cc44295,b95a2e9c) +,S(6b4a8c28,7d5c7af,63ad8d34,9751116b,60a613f5,7cac229d,7ef0d9c8,166d69c9,48333ada,f4810cf,94c78d43,88f8842d,fdc9fd7c,d391e456,a592d8b2,200bd6c6) +,S(d1efc808,393d4498,50837323,9b791d0d,a814e888,2958da8a,87136d93,bf1b7d74,13247e74,3c323631,9e557476,4ad4dcf2,b91dbc97,2d38244a,fabe4c0c,d08a9924) +,S(d3fd7a6a,fdc7332d,f2e6683b,a05ab787,e3c48262,ce837f9e,d8ebae1c,1f6f7ab2,3d25bfd3,3ddd4f74,8ff395a6,b4f36d19,cdb28ce6,b56aaa55,e783e9f6,3d74e70b) +,S(816f76c4,c5ea8733,5f220c54,28b31cc6,89fd8267,e498a675,4d6a2620,a60d9aac,d3b61647,f6624bb3,9fbb672f,51b66613,8a441a3b,660bb223,1f255488,806e79c4) +,S(1e344f97,98f11372,aef5c6c7,6b32a568,16198e18,8e611026,1dc78338,2522cc93,474e0218,9bb4f698,15e304d4,8166e3cd,717a1bc,a9cf4e4b,1f5c5d23,a36e392c) +,S(4d3bcef1,d6cff8a0,e0582d11,22eb7f67,28aae077,e9ef7960,ec519ab,3c6d6087,29f1b01f,a70e6812,3dade19e,d5d2689,6c491389,27a2da1d,3c628965,bccf38e2) +,S(6d5d596e,467ce203,297cdfe6,ce4807a6,1686a8c9,f0606283,5e0fa194,894d027b,ef58ab41,1d6a002c,12f469e2,e9f8ded4,4291b270,4b7490c5,4c70c94a,cb7b24ce) +,S(86f6ebc9,c25f6866,f14af018,88486b22,6c89b1fb,64bd9ac6,e523e503,e2cc6819,b0725647,4d9f3b4,8d4055d,e15b72ca,ce599bfc,247ce9a8,4b0d5e72,16b30425) +,S(520115e9,a47c3df7,23f81df,8422c03a,ea0084df,b122759a,8d6a5b75,540cb339,93b12878,44f22aec,9d5ed727,3d204d85,d3bddaad,73e3545e,5725b171,2b8417bb) +,S(19c9ff30,e5e50038,7e9be1f8,efddca98,7a72de0,d5cad8ce,7569d4e7,2b381009,b43b0c98,402748ee,16b362c8,b68ae79f,8493a7ef,293b149e,3faf7247,83ee3661) +,S(bdf0f8e0,928affd0,87566820,3c95b3b4,e6baf9f,f1da25c9,73814c27,551ee4cf,5f701bb6,8f8a6795,cb4ad675,e00b5ca5,761a0eff,32a1d3f0,9b29d5b6,3885163b) +,S(5c609591,37a48dfb,f778dc26,80de17ce,390ec33c,ea5cace2,a969ee9d,1e413e1a,670078d8,59a2c138,93946d1,e052552d,fd92c380,5fdf2ed7,8aad7795,2ddf2f51) +,S(98f22ef1,b9a62928,c5ddbdf,70e71c08,eb910ff1,fa6a6a1,56de82bf,bed8fae,f87be19a,9433d279,8088c882,5d122e31,bec9102f,c580fa2,24d40f32,2a2db1e8) +,S(d1842bec,2bfc5fc0,d5208d7b,40e04b76,88f26add,9b5a6845,751147e4,b4524615,f0405ace,6dc9bc88,48d18586,b713ca3d,67b76ad9,4f2f794c,55fbe9d2,f72ffa56) +,S(732cdad8,e0aaee77,473c0140,9702cb39,555ee048,357fa448,33ce8e3f,5f50bea5,24666502,448268a5,bc2c693a,85a1fea9,dc5f010b,a9b0cce7,6bf36124,bca1cb0c) +,S(6c86ebd9,5200b1ff,dbb6ce6d,e9fff6b7,1b6100e3,1144239d,77e7201c,db2e8af5,39c687d5,abff0ec7,c7ccc4b2,a4a16ba9,7324430e,a1ef209d,5ea126d2,cef24539) +,S(655d63c1,47441ab0,e65f9893,dd38f3ca,22d2d8a,a7b2c87d,a2e2293,b24ffe0f,d19ede94,b25ca138,94ab8fe9,842cae29,92cb58da,592c19eb,57c4184a,45121281) +,S(8efc14d2,d5845886,ec264438,449ff49d,ddab7567,69999bd3,6191cb39,efa41b72,9f1052fc,416db1a1,d9797e66,a816b403,475ac091,ded4dfdc,e262d527,3c535293) +,S(31a7f0b9,1686e695,d1fae6e3,8fcdbeb4,246fde30,f2ca80d5,2d9fde31,c728eef2,9661bf7d,46248da3,8ae1ff52,a8aba654,351a1f58,4f3bbfed,1875d439,3612190d) +,S(9dd959a9,8c862275,93dcc957,e369b2fe,5cc1d411,d4162ad7,d8e22b64,633adb85,78ccfeef,d95ede71,32a7011d,bd39b9dd,f77e38bc,47f7432c,f90d6583,5a6e665e) +,S(51beca99,fe3cedfd,1ba44caf,58c0fe4,8b926e72,50e5ca7f,8a187cb4,909b1892,12f38fea,aa9de148,7c14eff6,96cccf6b,c7cb23a8,6f2b7e0f,10fa971f,3545a0b2) +,S(1a84e21,3ef9b9a5,9f9a4fe9,d21dc1cd,1ec7a102,fd91557c,1129921b,781e6b51,aefbd931,17a42a75,13db0e04,782aa0b6,9cd79d36,b074f026,bfb7682,983cb78c) +,S(9eb14847,2d02a287,cd197450,78d81963,3943183d,c76c2090,9f68b94,12eeeaf0,6fe4b5a2,d18ac52f,9a129a91,1db00993,ca505380,2054b5c5,48f35380,c6d467d) +,S(9ecb3cc8,da5475cf,1a66ef54,3286f07,f5be1196,2c1fd420,b394bae6,c4256441,b4160952,e3701895,6f25c5d2,98ce90c7,91797571,267902a0,bba53d2c,2fe2cde0) +,S(541e567c,b2160fe2,75e9d479,1beb8ad0,4c07d6b5,12b43d49,888963f6,d6696ce,2444e184,66cc09d6,aec704c6,ea8ef670,4ed1488c,dd8107c0,c625b783,6534d6f4) +,S(8c061b6b,b6b55fc3,7c6d805c,808fb3e1,6fab1cb3,a05853bc,4933eb39,ca7b3580,20430304,c3780c29,a977f8d3,54424539,67924c2e,9a1353da,40716ef5,a0a0d37d) +,S(b9b674ab,361aacec,bbb69f7f,7c2b1361,44e55da6,1566ed97,cd58152e,4d391033,7841975a,4cf0b5b7,3bad8433,10866275,8a8eb93c,3b5db58a,15346083,f3d10386) +,S(3453c3d2,27e1dfc5,3e22487d,cce25ab6,18a3d25a,48f6fd1f,8e9158ec,dd6bfa1c,aeef1768,b754d998,fcbc75db,7a750396,930d169d,bf933c1c,15dfe041,17ff63a6) +,S(f36f7b9f,28463b22,d2c43e29,6b96846c,1b3401ec,53490c5c,35ec197d,da2c440c,9876476d,e2cfb7eb,b1cdef50,a39d20c,4ba5000f,9edef22e,ab7b96c6,f0cb5585) +,S(77c64190,33ef6119,ac3edefe,ed519632,ef5dccf3,f46066bf,6d5204e0,66788b5d,980cc59e,a103486a,9c8cfccd,213cf704,3e6aacb6,abbf3293,c833de88,e5b2716a) +,S(818911ee,6051c4d5,19fb7785,d52c6f27,a82e2d79,a4a55623,909f3d6d,b549e851,5d031307,a2d66fce,4b607967,f662bc0,af855112,11cc209d,8457ff41,968fa325) +,S(bf5900a7,7c211a75,231ebe58,17f91748,c957f5ae,b98377b1,9554fe90,d11ff226,d910b2e3,1760f0de,838cc159,7da6915d,e6c3fb29,80bc0e65,e87a36f7,749cf1f1) +,S(654b4257,11f03dbe,75b7d60d,b578d75,20e7cb6f,4923f774,8799b4a1,df06fa16,12c9e75e,26d3ab4d,645a7a64,d97eb6c9,356a3951,fb715bbe,9e42f500,a0c3f44c) +,S(33a425f4,f178af6d,48b78873,cf70da66,aabbaae0,397e6673,7a9c6074,15ab3d2f,1e5aaddf,d76b1b91,14016f02,1812d7ea,18decd14,ca3e3925,89894151,92178cb0) +,S(cb088930,f0ba3995,d7542d48,92ce47e5,5d8fdd5d,7adf60d9,3651240b,12fe7636,aad156ed,f0b25c30,e4bc3784,a1b7857a,4cabbe5d,2ceffb72,ca2cb7d2,45ddb024) +,S(ffa9e81,afb11dee,83a54b47,fe9b41e4,de4191af,7279d19e,90e1c528,7c205c0a,405233e,b20a4848,80210b40,18c098ff,a0a17203,c5a13b12,5ec0fe92,1d1c3567) +,S(92ce3be2,8fd6c9db,be1cd4d1,f58005b2,af0c136,89181c52,a67c2503,2649a6af,cdb840c7,7e0fc2c3,d4b959c6,6fc47142,622c8a16,b30168a6,c62ef368,8bd23932) +,S(46079065,b64bd3d3,3e3efc91,374e1443,69adc4a,bcd2bcfd,91ebed0d,88f78cff,b09653a1,1c0710bd,b737611d,e5d80e67,a516dcc6,2ee3f63f,e2d6a7,f3794ae4) +,S(5cf961ff,de982138,958471b4,b316cae3,6246ae74,e1309400,a3acd118,e4736c93,ab8e425c,ab39325b,b94925d7,795d8799,18efc449,e44c9f03,cf7bf487,fc32b185) +,S(d8fa1009,27c1aad9,6ba97005,f8a24013,bc29082b,ada0e0ae,f6f72ec9,8abc4240,38d88e5e,183b2c09,d53adeb5,8d0525f0,83a512c4,1dd64cfb,a7024602,f39e484c) +,S(cdabe8c6,7d0d4627,54cdd3d5,3e70bcba,e2ec925c,a46a4536,ce3be9ae,e0b37d8a,c2032dac,527cd15a,a1d812ce,1c658cc2,a0a379a5,2a30613c,2737812a,6e683830) +,S(394fbdd6,7069d83,8fdf87f7,b1c179d9,1a491ca3,680f0103,46de3299,37e92374,5ceac741,828ac862,7fcd587c,69844243,d17ba038,901cdb42,36e96685,d589a693) +,S(84eb6d44,103f56df,96617c7,11c79dc7,a6161189,157a0782,74fec78,fc5f6c37,57a16660,4d1fa3d9,cb358e7a,47984a00,6926df57,4e06a313,7b3c7524,2e882320) +,S(295dca03,657995e5,d432a606,da12bec9,fec8f4f0,582d75dc,5657c973,7cf1051d,c4df0ad7,b1e3a29d,cca4120f,478a2d63,f18fc67f,bd201be4,e2fe05fa,66ba2d6c) +,S(b42d81ca,1bdfb038,d7888194,deda7307,eb846bf1,738d8b7d,89663bf2,8097fa7e,2d913cc9,93ed5118,1082c85a,42495133,ace8bc6c,65530309,c6e15794,aceff5cb) +,S(48484186,4f6d8f3e,94977a3,45bc0db3,1330910d,4c555032,da8da876,912df644,7a78a8c7,68c9d9ef,b5242fcd,b7a5946c,5fbedaa3,2914339f,8b0c0ac0,eb8a3146) +,S(7376d600,9a7a76b9,dfb7e225,c0da3186,b683fb13,daed9fdd,25ac6606,7e7d2316,fc733036,dabd7c4a,719b699c,da115547,8a52d69f,387b8a94,28744144,c0502901) +,S(9be9c65f,5fd6cbcf,522eb9ca,91427f68,152caa2,a152051e,3919307c,9f67ab8f,14da6642,fa3b7c37,41c9f953,d1e01c09,267b7885,8414fe5f,24f47c4,b44c413e) +,S(7d0ae5e4,18d6c6df,45f6d26a,7e962335,4ea1a338,8f183eac,85b1eac9,1962e2f5,551eedf8,264763b0,913307a5,14fd9e09,479f43a8,87983e69,509a3688,d09308be) +,S(d91d965,d3b85441,acec7257,d444cba0,6243b34,14e9665,9cc62cbd,89aea7db,54e26ec,9c82bf54,f06cce16,2cfb924,2a354c83,fe530937,9bbe733,6010f44f) +,S(44c8fe95,aa48f8bb,6c0a32da,a6263918,fc2df7b8,6a68f277,6bf405cd,1bf0566,87fc1fa8,3fea76e5,52f53612,45e54053,9d70377,cd865915,b6b78acb,f73a6e03) +,S(c7f8e825,5f2ddcfd,f21c5c20,ea84a527,2c5f6c59,99843c96,3bce9e0a,aa7ef398,5c1cf086,9c1f790,b1e59ddd,ec9729dc,2b73c6a1,be333dd7,e423a0be,bee50243) +,S(3a8ebd85,a2bd4b1e,6c0373d0,63e9cc4e,a91e6e1a,f4bd7af7,501e0160,8fb7f4d9,4d9351b7,3c3f6f36,1b86ae94,ccecd211,ee3b13a9,522d799f,e78c87df,4473f23c) +,S(bb01a4cf,ad90f3e0,5355f0b6,d1b28420,786c09dd,9db0ed5b,38a56506,4da77e9e,1742b511,43bc276f,273afb9,8473ee3d,3d962050,7462cdf4,a8c641ef,cc2eccde) +,S(eee45594,1a04bdec,a02e7e85,1d86987e,798c27df,adcfd5d8,2979960a,3983f4b9,3cc75025,9b5d215,37570928,1abca8a9,29f5609d,56c8dca4,3d1b23d3,cba3fedc) +,S(d2290ec5,120d591d,2e4e2796,3d10c0eb,e73d8b9b,600587ca,84173ce6,796123ba,c4760011,4c68baf7,b4053666,d8bd494b,b4ef1786,c1d7a522,8a656f10,1c837304) +,S(21e359ca,9b7326bc,b3380282,b9017df0,3cdfb7f0,af95f326,701bd8bc,25dc047a,68b866e8,555206e9,7cc43461,34c3a61d,ce2a50ab,2b514935,a05f8e04,ad95c70) +,S(b4acba20,94b35033,5095b208,9126367f,3203efc3,35caa43a,51857181,f4987e42,fa0f72af,77db4913,af6d906e,54eb33f0,a3e9d20e,d366c878,3b7c513c,c5165c16) +,S(5ac6b2da,18754c30,9ae46ac8,3592d673,ac5d61e0,35ef1b4,512aa9b6,7551862a,e93b1d74,105974cd,b6bd3043,c0dedb8c,b4eaa81,c949999e,68d52fa,4a3941a8) +,S(4a53cad7,2a894cab,9b761157,38ae78b0,c36c293,c60ba8d4,b87300aa,792c51d,4b0dcfda,b890ffdd,cf8a6a71,15f2a351,d883ad8,fe3d15a9,118f3e04,43f840c8) +,S(5edec48f,7d8c9b4c,af3371c2,6e054392,755fa073,1e660971,4e089b04,2a07bc36,b18b8d1e,407f934f,e526fa5d,38b3a408,76bab92a,2bc192b5,b7c206ed,6ad040e0) +,S(986b120,618abe6a,d965f9d9,6f50fd7b,29f1b897,8276ff8c,562519ab,8aa92890,2c981569,23ff1809,1cb47459,bafc0d51,699740b,ca59dd7a,14e07b9,432f681) +,S(8c61517b,397d36a6,b30f0894,98d525ff,bbda959a,126e9be6,f67b9831,e5e7372d,f7608f24,130ce8cf,56a7b762,c1563519,a4be88d1,79e90f1d,b432ac05,d472d771) +,S(d6abe67b,e30fa40,b642483e,a6ae7ecb,4217a07f,35546f97,469aae99,a286b8f6,b5e5675c,91aa08d2,a5a77349,5f1ad2bf,8b6b9dbf,4b35dc6c,262ff1c9,8eaa70ed) +,S(26be12b4,ae013009,45c8ec05,58edb030,e19a75ad,872104f6,8642bf5b,c30f7934,1086891b,3ce97d8a,a568fe54,28164f25,4fc15953,c97d40c8,f32c0ec6,6ed49fcd) +,S(3f0281e9,1dfdf1de,69d5112b,1b86ea89,d737d09f,1cbbb71d,2400d0e7,719987fb,27451e9a,2cb336a2,998d55ca,ac12e16c,fffbbd5a,3703897d,5f566ab4,5f4aba92) +,S(b84b8115,7b1782f1,e4b641c2,a001daac,ac7d53f5,b3f1fa5a,d0a5ddc2,732af3b0,a0c8f7f4,8fa49815,7a6c590d,4ea18dc2,c586b332,2a303061,c19edf44,ebba25ae) +,S(790ab328,fd86da4c,66f0989,296229fb,609de28e,cc8cc6d3,d315eb89,fdf31e38,cdcf83d3,44d103c6,736bb5c6,375bc2e4,3fcc46f5,777d6e5d,cc407700,15d29aa0) +,S(d5fee68a,f9b7f182,20ea6525,6a591f24,da79a642,4ea0fe31,88a0b658,9006fb51,87b8608b,1b3d0d71,c9ab2c9b,84654408,af6551c7,1e8ec6d4,a8f26cb3,20577532) +,S(410f9801,4622b22d,62eef39a,3c5350c9,e80ecef8,48c4295e,2ae279ca,9623e777,53dbc737,5766d9f8,ac0b8b7c,e4b852b0,3214fe70,24386915,84856c83,6376821) +,S(6cbfa6f,fc7a6009,75edf0b,c260bd2d,258bec55,382e650d,c464b16b,e5f34eeb,de72cf4e,33028bb9,18ed3a41,d885faf7,e1d5901a,ad7a325f,801f1a36,2ed730c5) +,S(2a75c02b,3325ec0b,ffa42250,e224a4de,e0c4c12b,69b71039,4bc3040d,80e5c504,ed666a2d,8ac26964,f0445d21,f1719ada,fbaea128,9edd69bc,94ae6123,a2e6b8bd) +,S(ea2bbd57,6c0b20a5,6790ad87,29f25475,24ef97e3,86663aba,2473994e,fab39134,d98d55fc,daedbd5c,3aab619e,1288634d,f526f873,19743f81,149ba85d,535172cc) +,S(893e9899,fe1b8a92,439c1594,634ff44d,1d0a60cd,8a0183a,b810bb8e,f80d0400,c680717b,aa2ff029,7baa807,d7290190,37c73d0f,a5a1878c,9fa2a6dd,d17cbb2) +,S(d75b0a2d,1e9a20c5,398fc3b7,cacc79ba,fd53a14e,ebe23196,e4bdf4a8,f8546422,37a8efdd,618bcff3,3dd0c0c9,f8bf3192,2e131764,305b610c,88a2b74e,44672981) +,S(96c84a8d,5dd2ec9b,44a5b2d7,af3b65e4,9c07786,969452c2,5e8e64f5,a264c14e,292ed1a0,dafdf3f4,83a2a419,6e1b6b28,4d7daf88,88c7268d,70e556fc,ff55341e) +,S(458895f0,77782a62,43abb775,7daec5af,264a71e0,6eccaf8a,3b23baaf,fbd7343f,809eb056,87bb618c,a0f4e1e7,c8d05e48,95f18393,2e949b22,b9ddab0c,55d32b93) +,S(59dba4a8,d7956515,7f639316,75fecc7b,58a0e91a,6c9c3d50,7dae6d40,2e67a9df,718094a2,83e47265,1ef52d4e,db25b0b9,9e069f,391ddfb0,d9987596,d2f4ee2f) +,S(a5f92445,b7cd75c3,9a4b3199,96baf00b,f855ebf,ab3e19bb,71d4346c,878b4bb,9bb1bdb5,baa4d56,5b9c5077,c86b96ec,953ce381,17cc8d53,7b0f3957,a582ddd1) +,S(f146eff,2a9ee1ec,a3f26d6a,17c89639,a1f3505d,2776e340,ae89449b,99c8b198,1674daf7,a66f1a89,7b5378e4,add6a196,fd27795d,88969a07,a210d33d,646a64af) +,S(e67f5967,d98c1d3c,3a4d0872,12d3b65f,6f8df216,5dc14633,92c23ecf,ffc17e1a,c3dbbcab,d1971eb7,a8b088c8,c71d65a8,328bf43,58f0e685,9025db87,e5391380) +,S(32e8d775,ed37cc2e,6f69c85b,71c95d65,d40f033c,b5eef362,86d4499b,fb6071f,2fbb1d8d,a6364791,95ecaf52,6f63eb86,e4604973,edebbf82,b796d88b,ade44334) +,S(b98c7cac,475ee4a3,c1815a17,e460f76e,e5334b27,e1ea319f,be8924b5,819a473b,d7f1bb1b,a653f20d,c7145420,d8c8c339,d789ee60,9b9ff0ce,73910b94,3deeb88f) +,S(d9830fd5,545dcca0,ee37a402,9f406cd7,50bbaf59,e60a80fe,da976bbe,ff9027d0,cffab795,e45a2833,75e7b861,728421d5,f9e22d03,44f835a4,c55207bc,6479b947) +,S(399fbb5e,4f4e27ab,3e737a32,d065fdd8,c003ecaa,84a2430b,4a7b4d40,eb6f9721,93f7b541,121d13bc,480f7868,ac9d8302,6706d2f1,a46955de,a3912735,c5f02e0) +,S(64e067fe,17127128,6ef0fbdb,b2adb4c3,395a1ddd,f2ea76e6,261e6cf0,112c6227,8ef6afa,4bac7536,a23f08ed,eb8656a3,47a13f25,2dfacd37,c215cc3f,473687ab) +,S(57eb5e46,40721263,97f0d12a,532aa1ff,abef7822,4ba9b10e,8fc95e1c,6075a071,8a700d2c,80df0b4d,7e2c9291,9a51e565,8dd6ba5e,59bf1503,7bf7a0a,935545a1) +,S(b83adb94,ba1874cc,c61ade9e,43093cae,5bd86ff5,e86615c1,abca14cb,6eb81877,93417bf2,1fe01c85,5c6f7782,a5cdb01,a5d13b29,d719f0fb,a2373ba2,8bada7f1) +,S(7a90bb49,71537bc9,3d1bed23,891e43c6,e350fa37,ef8e73a2,3fd46ea0,5ed879bf,ee0fa59,3a51af19,70a6d8b7,22d42bf7,ca253572,2324a59f,c041b3e7,305fa3d4) +,S(195e4afc,6c95d6d0,8273cb0d,fda2da3b,4696b569,650d4230,4d396fb,3e653831,44075199,9dce9d6c,f10ef736,7888dbb3,a713423c,f2881cd5,76a681ce,6fee2c8a) +,S(28ec566a,29bd09e2,f8b228b9,ff2ec49d,56660734,f2ea864e,856be0ff,fd6f60ee,5b4f5e34,298b5a56,a6826143,8ba59d25,4922078d,f36dfdfe,d4e8972c,647fe031) +,S(1e005b72,be1bb77c,80512581,58e940e3,544cc133,a76ddf49,b681422c,1815cd22,9c523adf,4ba5d753,93e432f,491f8e1a,435165b2,f40f79d7,889d82f,8951a25a) +,S(f54ae39a,d074c399,636f0dca,682b9405,4e87e87,3132d7f9,cf79ad85,fa82586d,db2e9b90,1c2dac2f,f4851f4e,b0ffae7a,4c0cdf34,ae9f964b,841c539d,84040667) +,S(bc8dafb8,d385cfca,3643fc75,c8a93f9,792d2b9a,715269b9,ec40d581,5936e6c6,dda791ce,186ff28c,db7636ad,4073996c,4a2e2875,80da17e8,90d03886,1c14aec9) +,S(60b6ea82,627f5414,16978e7d,3c9d911d,9d9de92f,3baa0975,a8de4e3a,8ed3ab2d,64693ab,fd095109,ef89cdb2,204f2f3,89dae035,f451fe28,58fcb4f1,dbff0999) +,S(9c8d1352,bf291803,22730718,5ee65aa8,b14211de,6d73dace,2937cc6a,1ee79134,3c6e0d66,48f3fb6b,23e6e4a9,5df3911d,797afb50,9c12e90d,7eac557c,7b1a9505) +,S(bb2a8344,2997babd,6cefa2a6,1c9d2fc7,a42db3d5,bfb19334,c7535bd5,630be896,20de4f27,69596e65,edcd695f,61a0d8,3c8925a0,c8707470,9e84bd41,615ac75f) +,S(ba8bca72,496a6046,7b250a38,cbb536e3,b9fb9ab1,43800655,8ef5d186,2b66d50a,81abbb33,e835f864,3d075858,7ce59671,7e08c1c6,75af4c5b,eb80429b,9dc46aec) +,S(529fde52,c4d1c978,405107ba,d862f7b1,995ffef5,cba4a59e,d71b366c,28e17b46,ed7c2521,d39ca130,60d5f509,d0a8b0b3,40eb78c0,d4e4fc4a,83318a65,226d0a05) +,S(6e0e10c9,4445acc3,593efdd5,4b8ea1f9,db4a45a1,4c2d0a27,edbe3fc0,7a90e91d,43537a25,d2091290,f753460d,8816ff10,41308e6d,fb04b7e7,d5a108d5,c9fd83a) +,S(b2f90714,6fe2e01c,5cbd73a0,c0a358c7,a05aa730,97a060ff,491f362c,75c20e90,d0e680d8,f7d27eff,12b332e8,a92b846b,4242a746,9b31740,6c6af499,5ab51948) +,S(bf631a7,933e3ab5,f7b8707e,55a9498e,31ec3f36,970bb9b3,f5efa0cd,1a3f28a0,1030146a,387d4fd9,c12544dd,a448133a,49b5a6e0,d4b96933,cd47e89c,608dd5b9) +,S(cd7ec470,e9d5e3fc,a4c344f2,9edcd4df,4b7033ef,5e7ee99,de0db6a8,43926034,3aae77b3,bb008cb6,e982d673,7f78e920,f3a587db,bc106c0a,25c65d45,df8a4f6e) +,S(b3ac95ff,8365813e,e71199eb,946b5888,7dd34b1b,a214482f,dd3b7fa,3b8ce6b6,e3d9bbdd,aaba7887,8e763360,abd370d5,9d941ba5,cf758d33,3b480f00,ec5e7672) +,S(7fdc21a8,6962fced,e6f9fbdd,77e60a00,4dfb858b,5b149362,dae4b4f4,a4ab84fa,2ec0f21c,3d1c6d60,f22817a2,954d02b1,ce6e8b91,d826c11e,f8e542c4,245a55f3) +,S(6f019691,def39afb,103e524a,598bca92,3c99e44d,7dff4866,f76fb6c4,47e6b40b,a225b484,cda916f3,559e5782,3b519827,8bd7300a,c31dace1,7a797582,2a2e2a31) +,S(cb9a979f,c4e8d887,f03956da,9ac89637,579813b0,c3b27874,82961a54,e54c16a5,ff42bdc3,1a837d98,b7d37a38,db3c74ee,6109e868,d06b7c33,d5562dde,b11ddbf2) +,S(2ccee51c,9d63f3e8,99314da1,656cbb15,635928bd,309cde4b,69699860,c0e28736,dff9a128,adb8b4fb,7bcaa1eb,6bfb390f,226b2ae0,b72443a4,5982d559,91d379eb) +,S(a239538c,c5e0b53e,879f484f,7202a52b,d52d1cdb,ca7ae7d0,639850cd,b2c4f57c,6cc1f9c5,8998e347,2c6db0b8,6b1d9092,d3cd0c84,267bea8e,75a172f9,f4879dd5) +,S(e77796ac,c619974a,63476635,7bb3bf33,6ad1e87e,8496bac3,378db956,7beaee90,3eaa4b63,c9679050,59d8cf67,7b7095c,4064534,1c592ccd,ddb7626c,10586f0c) +,S(52c332cf,37646a2c,c1bf25cd,26a6131c,3b243688,9c44d804,d2762fae,618250c6,2279bab0,a19f78a9,43e695d4,53a0dc3c,f0312987,6ccbb70b,1d61eae1,e92729bb) +,S(d68826da,36e5f78c,bf728468,88bbe6ef,f6e55d34,f8b47a9c,8296e662,4ad9bbb3,88ffeb15,5f70c6ab,9b83f9e8,30e2f449,7e661dac,889803a6,d30a2ddb,11bfca5f) +,S(af92bd8a,2a5b0034,ea074d69,a1d7a517,808d3b61,58f5f7c2,d3fb08e4,eb825cf3,2fef9245,a4a3c837,d4b57ded,52009294,c077a801,8f633313,b6db2d4c,92c724b7) +,S(df86fa3f,63d95d73,98872011,c7545b3c,f5f27fc6,a821bff4,5d09afd1,bf76d895,a891e766,12953c4f,37a463c5,ce449574,b1906c63,c192ba4c,67f4f78e,d1e93a35) +,S(a049a35e,119e27f6,e272774e,f470ca50,9a1da9b,a4e5d781,6e64a13a,23383c24,4cb8e2eb,ccc82ca4,a2f82841,34eb3a05,f85a2335,a3b1b117,92886029,96fb3fd6) +,S(b3193cbb,f3c8f3b0,b47b1a0e,5689461a,8da801c2,4c8d51ab,fc2e67b,1d9f331,2032a290,3f0cf0ad,21b63de1,565170a3,edee470,a4dbbabe,5f3d459a,3827c7ff) +,S(ff3cd387,554fb3a,89142ff7,3e97fdd8,884964bb,2f457283,e45b79ae,ef1d692d,24475b62,c1ade1b0,ba36ad93,27916e19,637071c,22fb59c1,f2108fb8,d38ec5b2) +,S(c095d24c,42b058d,c2f77e2b,463a2c7f,1ddd1dae,dd6f6111,11ba78db,26763204,d2648519,61974d6c,cf66de22,1028943d,ceccb181,ae03cd38,fb5aec22,fae54326) +,S(5365a446,389f54dd,8279826c,e1e7df5d,b4a9699d,b8208efe,80d1eff,2d883ee,74625a49,b7856c1f,b157776c,cd79270a,2957862c,a437bfc8,75986264,401e714e) +,S(4c073085,e96134b7,75248412,c36b3b33,77afa275,24c83369,a2477b8c,9851f15e,fed40d9f,a44f64b1,59c290e1,63d1add6,92bd2782,51de71db,e302cbfa,67e508aa) +,S(71edf152,ab95a066,2b7e5190,8af75f38,d03d27b0,3a3b6607,4f472b7,706a3114,c3e6f145,dad44a3d,5cf056d6,2c608b4c,840608bb,aa15a101,c9bd3cca,e511741d) +,S(1b7d41a9,3cba67ad,c145962e,7b2c6353,bfbc8eed,34eb4c27,bfc181d3,1ac0a802,b165e7e4,23c5d880,1bc3bd1,ee0c6778,50986b35,9dbad06e,aabb2f57,dbe553bf) +,S(ce997626,cb41ab98,58f591ca,c89f7a73,bc1df836,716ee74c,45c4c781,eef4ccc9,be76f81f,a8e4b053,f63be23a,5e72ad6b,7aa359aa,e9407b60,98bdcadf,e367b167) +,S(5b0cfa70,aeccd544,cd634d10,a2bcccdc,33e4525a,54259ba9,92c40100,698bbf2f,ec50e655,163994b6,4881369f,b3aab550,65df1a5b,dc6037a7,7c01e56,904660d2) +,S(a03873b9,695ee82a,42b72a90,f0cdfc68,dbedbd2e,a50d5ff6,e120d811,ce8d5097,5947c8e3,56e64f71,b36fc1f7,7ecfc7f,a31c0f0b,cbb05102,775648bc,f2435758) +,S(d6b91cc6,6dd31e59,f04c6e58,bd7448a3,fac62753,68579214,11a8b42c,66084ed1,fec7fa6d,778c0b63,e7dfd72f,ef044da0,903ccfc7,1786f0b1,85edd004,f691a0f2) +,S(896a1313,e0a96d35,9fd42841,7790baef,a40647cc,f56264a,ac3b72df,687b5692,831d4b47,52f5fcd3,4942ca26,95dc86d8,4fe49c73,7c2bd46a,f892eef7,304117e6) +,S(779e7400,8e564167,56795a4f,9d2021b7,94aa9689,eaa37780,8e3a6061,b5bdc04d,739ea3a9,4f38be31,df57c052,362d1872,333d2777,c6704c2,e69271d2,9f78b123) +,S(f20988a9,3a3273a5,a015866a,c4de930e,507b5b48,cc5ba52f,a2a71e9c,185e72a5,6c861907,8fadd612,c0535163,dfa4cf39,648b59d6,4b056bb0,4e06695b,3b51213a) +,S(7e8520e2,3151c78f,9f48bd10,5aff4087,dd90f9c4,2ac33e24,19499ab6,8e5b21aa,995827b,43c276dd,61403388,27b2fb9d,9fbb46ec,af10b65a,a8025971,608f38c9) +,S(98f0e4b0,9e72ec0f,d80ce3ad,eab29913,fe84fa49,1786bd79,7f6832cd,7ed4dc6a,58c42bdd,7ca43579,b45df8f,b2a6db3d,41f75a3f,89dfab0e,e000383,c9e04a54) +,S(31cf38d3,dec1162e,e75eeac6,6827aad,22fa3ee9,abfda002,b6956600,6fe596ec,ceeb4b04,fc6c31e7,7a6260ca,bdf92569,92841221,d60ca74e,81309472,8fff4442) +,S(60766d5b,50cc4d46,a1234c92,1baeec1d,29900e23,4493f174,2f06ada3,ed9dfbea,13debdc8,9795f421,6f796a53,74b87aaa,bca4f73e,fda2ecf,7d151870,179c44a4) +,S(1b0ebbaa,35e8ecb5,a76d9c30,ab88fa10,b211ce3,e7c2b428,117645b6,881c7895,a312adef,e1c4a34c,d9f75d10,bb2ceb29,79184181,bb955439,e317cde4,202b2f83) +,S(b3129f71,c3438602,c9c24ee3,2f997341,26dbd76c,60cf7713,200ffb68,e486fc94,bd4beeb5,70966285,6a15002e,a25046cf,996a1cc7,9a570549,467ac179,b4f145f9) +,S(2925ca17,662f0905,3927d40f,f2fdee1f,66cc5c13,c3587e78,fe48effc,40cc075f,6d37757e,64f0438d,7bfb3658,5df58dbe,a8ab8cdd,89871670,dbe221b7,4c416185) +,S(8d55b85e,fce6bd0f,ff8906d1,6497d35e,4b69e701,da7845f2,aec1a049,39c9ec45,435416dd,9fd01388,b717ba9a,df574456,785cc0fa,c115dc04,8a242270,4a3c77dd) +,S(a660a9bd,b419e19b,16823b5e,dc3fcdde,f1021b71,4debd17a,9a0619a3,aabc23c9,ef6d4bbc,e963bb1c,2edffa5c,ef70e330,bddccb4b,3b23cc52,d5b4a689,e0c76c32) +,S(8896427f,c92bdbfd,59699ec2,222b4bbf,2198e160,94945c77,1f207bbe,4cdd6b0b,bc6081fa,abd2df26,b087acbd,a2c67c63,2eb1a8dd,6fae2454,6f3fa747,be421ff1) +,S(47e5d9b2,3f429484,61ee9f38,2f14babb,f93e318f,32d67063,ed20e917,9894e993,bd17f8b5,6084d3f6,62facae,24e93e3e,29205f21,68903ade,4f7476a5,ba70e8b1) +,S(ff352870,69bf1131,6f530ef3,b32a487b,3f11e6e,f8518c15,b1202a18,4e6d5487,8920338,ccf36f98,4afde38e,1a74528e,86fddfc7,8d7a6964,cad4286f,231462b6) +,S(2a713d8f,eca88def,b5fda7f8,8de9c6cf,9b97bf0,4c070173,aa47dad9,197bae2d,5ba64900,f7d18ec6,8887bd26,d2769b0,26d22e96,1007b58c,b27b8983,a6e7adb1) +,S(853d813d,3133ed7d,a85065a5,755ca0c5,3f32f156,154853b4,b018668c,b165ace1,fda8017,e00d20db,6ee4c0a,5790b504,afc376ad,170d74bc,1261abcd,241ea020) +,S(d5c4dc15,37b048d8,6631fd14,7d896d6f,f403ceda,7de8883e,1ccc006b,6d9ccd99,9ea2829e,64213434,eaaaadc,43ed10b8,28e706a,5001d7df,47146058,8bffa8ed) +,S(f649da82,d50fa298,8c598d5c,caf1e7f7,2bde2cc8,8073b55a,2e43b6e7,5d44905e,4438f4cb,d3e1938a,b461b1e7,b94d8f6a,c6e287e2,50d06da6,67aacb1c,609bb6cb) +,S(adc3515d,4fb7776c,b1592a69,13254d7,afcb20bb,8a4d7529,7ddba70a,c35a7193,49b7bd8b,3f280916,c6024e46,afb45e6b,da5bb15f,3d3497fc,85e9a46f,acec3d80) +,S(d78c46f2,603a00df,b45d0495,c1e2b346,963dc82b,84512cac,c2227acb,383f75ed,76b02870,2e7a3da8,79272759,1e2f81ef,54ed02f,debde8b5,38f9ff1e,4335a21f) +,S(13904467,59e0fc27,c2a499ec,384e0906,bf293dcf,c13ca16f,d3bedfda,d320e466,5320c884,b74bcdc8,6e0c21f5,40c16f65,dc61f19e,9ec5e8ef,385fb637,ee7a3701) +,S(93700603,543ec558,3fe48141,310b184,aa8faa04,6058467c,389c10f3,b98c42f0,8e0acf55,bfc585df,4f8cae06,131753ee,23a7bcca,68354182,61450e1d,e1a136ce) +,S(bdcb9434,4c556618,a247c935,29c5ba74,c68f25ea,a5507148,1431c00d,6926884a,c29b7b1b,ad6ec5a8,e7046cf7,cdf99c6d,15f6a3e4,3c6ce718,9ae2acbd,531bb17a) +,S(839ac85a,9337818a,b07b5611,f67eb16,6342c1a6,8aadefc4,6842c023,336afb08,88b30690,e79fb157,3e424c80,75bc810a,fb9d57de,5464a253,79d06222,ea656b69) +,S(2959c32e,bcf9289,9882e003,c8a28e71,3d491402,4d24d878,ba8bed88,47b949c,ba2643c3,95fac027,6b7c55e4,d2d2f530,318665f1,ec2065d6,eaf32c05,123e04c0) +,S(71116eb0,5def3abf,bff3e235,a0306605,b18aa465,b47167b4,4eb3486c,c442f3aa,2652a726,35be8336,f9b51607,76b3af84,26a23716,871fa64c,898520eb,822d6630) +,S(400c1bcb,dd3e3978,3ca06e8c,2abe8b0b,9b45034,a1655cde,fb748ef4,e2a477af,1471c86c,c8b27b48,1d4c45d,1533a5c8,d46fc3cb,ea4788d6,c48dbdad,6f7670e3) +,S(2a4abe28,5cf94456,aa92216a,dd635abe,71a7e825,712d775f,d61fdc98,a4c9288f,3c0d2483,3d6ffcad,b471d234,4ee8d07,15c09719,b18cb581,8ede730,35d89c15) +,S(cb0113a,1832843f,7e32ce25,15b0b23b,8a803ea7,50b500b6,3fb89f6c,e7bb1884,816d7056,b775f13a,cfd94a6,f88f442e,519495a3,6e74d8f8,359a8a03,16583bda) +,S(4d7be7ae,5c4271f6,c1adeb7f,4dac8467,beae22bf,ae00a71b,1e353be9,5ef172fd,cd7e6415,5708d20a,9fc3b0e9,85517642,f677281b,49490439,14845a36,afe6ca56) +,S(bc285658,fd724cfe,e6ec8c7e,35f9197f,e9083bf5,439fd4d8,d9b262bb,7a3c38f3,80c10d7,59f76b4b,8330c96f,38a1af24,1d1b0db7,4e6befc4,4f085180,c1c33729) +,S(a829ee43,221d9955,38ce8aef,e80c49ac,dc6e71f,4293750c,c0585c1,69963f04,144f6b56,d996a18e,627d4c8b,8115b2c1,c369f410,ec8924c1,73382302,3758ba33) +,S(f5450bd7,efc9227b,e7d28ad6,75ee14df,1b2378fd,308e6c5e,68945ac9,a47d82d1,20201fb5,cba463af,cc46e6da,caac8417,63356e64,5cdcfa5d,9d810c48,272cf8e0) +,S(7dcbdb69,46dcf79d,454095f0,b61341e4,45243bc7,c2262817,374fea5,37a1a380,bd2cee4d,c7ebc71b,46fb3bec,bd6787eb,d2be3128,703a884d,98359c5a,43875977) +,S(f1d6c1db,cc8d33d4,fbff821c,8c788d06,2d906063,2f44a786,585a6526,20ce776a,3696a3c,8473bd07,76e77226,8cd09f96,3dbcd143,e631c32d,5d83254,ada29340) +,S(f1688e1a,d5df4e43,67caec6,f2234534,f65aac3b,79a94ca,32a786bb,9fee4b49,efb620b8,e2164685,c9a3837b,5c6eb70d,759824,96541aed,eb80aebe,4193e34e) +,S(b639e284,3ecffb0f,66c2819c,73787e10,527086e2,5d3da074,e037a915,e06a5813,61fde1dd,63ff304c,8ec99d4,67ffbabe,e8000637,b9856bec,344b825a,4f198407) +,S(11a4ff89,d5e63ec8,6a0ce18,53dde8a8,875c9a9b,f563526b,cd25b830,6e3314dd,9f7ec77c,9a3f88cb,7f64b1ca,f2b5c7cb,d70d65d6,dbdba9f2,68832f3c,a2e117a4) +,S(323db783,26abfd99,2b13d67f,3ae01415,77162203,c50322c5,7a7933e8,7d687d3a,92c8a67c,ec834653,d0f1a50e,a7834b38,631d83ec,ee38e50,33ed927f,7e14253b) +,S(2907fe12,c8433ab6,2e6283ec,85b93342,ecf14d16,6d90cfdb,b4061968,aa35170f,160f9790,66291ed7,d51962d4,be02d85f,8a92ff8f,258a9a07,55b8a5ca,2d57c2c2) +,S(67cef7bf,a58519cb,6c5cd8c4,f69d5cc8,84cc77a7,854a4b6e,a40b6dcd,57e43e17,e8071d35,e590dfa7,4d4f4da2,82033f1b,590b9383,70b571ac,ebb3bc11,b9b48482) +,S(81e40522,3d4ccb14,3952867b,b8398cd4,e5ab92c5,d91066b0,d1fdeaed,55c71165,55357564,af12b507,b2e24e6a,425697b9,e6356b82,da36f111,2b5c3394,183c0d10) +,S(4880abe1,47bcc598,a3743304,1afabe99,fc525daa,564c4b05,2aa60c27,5c814628,b6d944f1,ec69e7bf,2cdcf621,864ba76,a1df44a7,ed15ae15,290ddbe5,b91f585e) +,S(fa2bc507,19131dc7,d5f23fe6,9e60377e,2d2f11c7,f8a9a451,82aa69e6,24eef53e,9b0f2017,5f287d80,41f58930,6cd022e5,9b63bab5,1b26abfe,1a295ac3,46a2e9fc) +,S(aaa18fe1,25e781a8,901ac351,38d2bffa,83cf7c3c,99a4c7d8,54b30c70,c9483e8,6a8f9e1e,a40f6383,6008a0c3,596f7644,c044bf53,9700a142,ec5e3c97,c075b03c) +,S(d473950a,8465711f,71a6f1f0,22f4bfcc,1c16ba81,4bf73c2c,1eca244a,da4999f1,6eccf9c8,aafb09df,46ca0d36,ee9028dd,1df62bdc,6ade77b8,a5d410d1,a69bc775) +,S(d7e2b17c,f8e1895c,cf9fb163,b56f4be8,ad99133f,f00f2ce8,8ce911d3,3b8e36cc,b6557693,ed9371ce,69bf397b,56c0b566,21d38958,ebdc0b96,ca488570,1561e6bc) +,S(3f1e73f2,a2192809,acaecea1,71d175af,683e796,e1337db2,11b6b34,8ba924f0,a593bd94,96308bb7,76b63703,bc11e30a,c5f01c17,c8b9748f,3b4c8015,56f52c3f) +,S(4cbb68b4,27899c92,1c0d969c,94341d8d,161f3b8b,3fe4cfca,2b583a63,eb383dd2,6b3c29d4,97728ac7,b45cf7ce,ea618789,95935bea,bd146e1,6c756f61,4698b6cb) +,S(e41b826b,52ff9bea,354af41e,3004b7b9,edd01e13,8cbd466c,ba4cbab8,d63bb4e0,75d5b642,47388aa1,51d4d8d5,2568a804,fcf66ba2,42b3f56b,dee0350d,ecc527ed) +,S(d508dd5b,ec38f795,88bf2d9b,6bcc9f8,aa96689e,91c1381b,9f8db311,94588028,9b144547,1a2ee559,6584c927,2d779fa3,123a760d,9faeabfa,1e39d3b5,ddac2595) +,S(5276f127,3bad7149,ee5ff022,2769dd6e,973018e2,a9948070,fdc82148,ac637de0,73f778c2,caca737f,acd3d877,14e24d83,964dd47c,f22915e6,212bfb09,8e804e21) +,S(2e9ebbb5,9d108d21,71d28c27,32af659d,b534cd10,c5457cea,3fcef018,4d7761a,229d20ba,cbf0104f,b385621f,dfe386df,4f40c287,7d956046,60eb3923,46937bff) +,S(ad819539,5b94bb1f,4e60ab85,932b24cf,2c79c20b,79a972bd,db1e4201,c49f1d1f,9226c45f,4d161a1a,c5c3c0ba,a0536def,3c6052a4,ec22dd24,cc803a37,b5d791a1) +,S(f5d4baf3,93ee5acd,944b2057,78cae170,8a622f30,68d3147b,62bef05a,88fee96f,9a187396,9eeba528,9f5fca32,6bbb922,2eeff5f6,6d205a0c,78b77dea,ee17d1db) +,S(1a0f5e1c,b2fb5d01,fbcbfddc,da83693e,9619ea60,1669c728,7710733a,e6ca778c,3074e8d1,61da2d34,38be57cc,fc437742,533e415e,5f0c888b,834a2fe5,5d4fd6bf) +,S(a78f6f7a,110cd16f,99fbe16e,9be52782,248518d8,e621f478,2167887,f81cdae4,e3f78e8d,507f9af8,11653ab8,5f2286dc,db34d9dc,8106e9f0,57610267,411f02a0) +,S(c53e4243,b26ebe40,a1abffdf,3c42129c,47e92cb7,32bd66c0,3d4a4290,c68b1c25,bd4f96b5,b5801b82,300b2132,2c39fd2c,65b2d084,e657ba2d,7db5df15,ab960e34) +,S(a3a1ddc8,56957468,2e9b8a57,50bbc738,f72dc60a,1c09c95e,a6559b2a,736535e4,94887a0f,a4381d9e,dcc4faf5,1525ce98,fc43116d,29f68c99,236e4940,6842a741) +,S(8160ee7f,738f54a0,698806b8,35ed4bca,113bb568,b23fd331,ef5f1cc2,80b6230b,382ff30b,f13f1e28,95a38af3,13fcd099,249b195c,96ac42a6,6a929fc7,a907b17b) +,S(68552ddc,6b219554,dbabd276,e0f2a5d9,33610bcc,776bc40d,7efdc1c6,1b992e35,eee09352,c82dec92,b0ae8d8c,d6918ac6,df620dec,86a0e4ac,abfe8025,52a0ab5e) +,S(919fef57,f308255e,1fa802cb,5acab880,c1810c62,c79a4ecf,c2251a2c,cc02ef51,cb38c163,8f7890f2,d61a980f,ed712ca8,97296366,7927ff7,39de824d,207ab566) +,S(d7e493e2,e2c33635,ee8d22f3,76fa8de9,31ed4eb0,9771746,f48ba201,307e04d1,ff7e6d72,f712f2be,2bfffb43,2764f677,62917509,3cf6bfe5,eb5cb7ce,85c1a8b4) +,S(6b642a8d,f4131ddf,7f31dc9f,c26b96c9,286e1f80,de2af96d,52e383d1,ffa73a41,1e55e667,5f0ee13e,76818c02,ce424d8f,48cbc930,b25dbb85,363019c5,fc29979c) +,S(7ade4aa8,1df8c53d,1e64655f,bfe0ad88,4057e0b2,1c88bb2b,4c8d5f19,34794191,cb0e9802,fbf1027f,dd8d2167,f4f4680c,f9e18f4c,3bc3310a,c4014745,530a06fa) +,S(6d578cb3,1ed19dc,812fd360,a367996b,91a7ba42,7d2f74c3,e2a1721d,72e1c017,4ac9ad2e,aab987ed,dc994b74,733fc710,19301e1,f691999a,5161cb15,ba11e9b4) +,S(df95b5f7,7bb79814,21892d72,743abe4e,828a7544,f9f0e774,b1f5ada7,a054978c,4ccd011f,a966604b,32f70bd6,1a3c1515,c6d1b261,a3ce5c59,7078cc9d,f723b32) +,S(d7392d17,1cf72e1e,ddea0be,a242edf2,c418e9eb,7dcbe1b3,aa07ae7f,a11ef08c,4b696f78,20a9ac8d,a5f52c8e,9d1a39c,bbb3d3d9,fb5b38c8,1b46bcfc,90e869ef) +,S(f01f2aa9,82842315,98f414ae,f87c9d7b,6eaf21be,c4dddea1,3967677f,5d2a1032,7c3be753,da5485bf,13a4cd72,a9e3fbe2,28fc6a22,c502b19d,1b6f7d18,149e2b3e) +,S(cee8f811,4b1829ab,a47e9b5a,54de7cba,1f6edfe,624f30e2,ec4979f8,3145242,4b01f7b4,cebb1125,20bb0ab2,7013af9d,11d19c4,14b0c29f,d142c7d,5b903a09) +,S(f4215bb,973b5586,ec051388,203b1c99,cf69b555,6b1591d2,fc711842,759e9832,5d8a5ce3,ece7c011,df3d414d,e62ecd4,2d716c73,cab02e29,621307e0,658e6fe5) +,S(e39ecc23,90c9464c,32b08759,9a44586a,da09af95,ba8a3b30,2cb015d6,4a49b18a,bd7957c6,e1feb061,f5535231,4f5c5e5e,c8245f28,4638f390,d079cffe,bd2eea7a) +,S(9e6bbe6c,402e4cbf,e298e789,458fa9a6,68cfd407,3efb3d25,4699278,760589,989bf3f,9912b242,419c848c,f82c3fb6,8690ab05,bc23372f,eb9a850f,b4dd44ba) +,S(67504bbf,57824cd9,8a3bd82d,34fcb59,3d20590c,a90b5652,c4ea4695,1f48905d,93ebbf6d,3678478f,56ae5a54,cde812f7,d8d40928,21b5e82,71669dd3,f0b263d3) +,S(4e5bee50,503a28c0,9252b9bc,dd28af66,cecae127,2128e88e,fc431373,7324657d,d6891df5,3a4cdf2a,d7ab610b,817b0f60,c2502442,2e40269,a7da80dd,2672e0f3) +,S(7481d5a5,bef3d397,533e01b3,640b0809,fd6ff946,a1e5481f,b90f0b3d,dd05c21,21ee7275,9c217d19,3999df2b,e3cddff6,fe59f26a,e570e0ae,58868441,f37e342b) +,S(778dff4f,dd32f251,6defcd94,188f2440,26b9f789,ff4eefd5,84b2c15e,2bc61d62,996a2edc,f43e10d6,93cc2d00,c6f4506f,45be1dc5,c762fe20,3dce124e,34e320e0) +,S(cf531271,3d65d471,929f6108,12db63ac,b1c52203,eb879ca4,a8ee9f62,774580,38e28f4c,881391e0,55fa7148,2c92c097,c842dd,74a58d6b,5753d6e1,2f773b19) +,S(99702d01,9420286e,723625b5,62c8152a,2dd5f1a,eff84437,8a182cf4,25582031,8c4af2b2,654f1631,82d08bd6,e7f8b6ca,d5365b9e,d869fd23,e5a3c4d4,7e5990c) +,S(68614c88,6b59c198,c49245c1,e1232cb0,b4bcce31,e0a2aa15,9fb2331d,ff1dce66,49c870bc,7ac78e22,b635c2b9,6f29e641,3b29c6ec,8ec8b3b7,8fa6597c,90180c7c) +,S(f497a9bd,3c0e923d,5d622ab6,afeb9e8b,d9b4525f,d1f30cae,2a44d0b3,e13256b,af4d0273,e088adb0,b7de7724,b387e109,d49d20a6,eceb369c,12e07eb4,f28c9e32) +,S(50a764f7,f5e29cba,ed7ababb,97d2ace2,22c06c65,9ce87d77,83b5bd0d,d165bbbe,4abc57c5,4c9f1d54,e73cead6,d77a85a0,8be25ba0,ce96b8a5,1b4fb460,5eca949c) +,S(fccfe1e1,e312e6a3,92e83cb,97274576,56415255,b127ad54,432c93cf,4ae29bc0,e681795f,d8340902,da0018a0,dbb8a424,870e4bcf,7de95f0e,b2c7e98f,47a46c58) +,S(66de61ba,48c1fd44,80d5c78c,3f06c3e2,45ecaf25,e4c235d5,8408c90,e1b62ed1,bf3bf086,a90221ba,711819d0,d80194c,c45177e2,57b1408e,7e649f15,a92aa6a0) +,S(4373e7ff,e3995503,97bdee9,c9d3d70b,39f47446,45fd3c1,63b2012d,58e148d6,440a1376,16096124,42c7bff3,5f9a8aa2,3ac64e8b,bd5ca839,bd3c5a39,b84e6fe) +,S(c8774ea8,7d83fc06,c36ab357,b1fa76b6,c647cc9c,ebf2e125,3f3ab303,9306ef1d,ccbde78d,2e4d2c0d,ace4e660,efdc4d1f,a1dbb44,4cabb0df,bfe29de3,191f7249) +,S(748cb6cd,c57d89d7,8842fae7,731b1e28,3b59ed18,cb761c88,a4d2e4c1,c3359fc,62f5b6c4,11c72d4d,a412148b,8b038b32,8f98aecf,ece537a7,237b9f87,646b9a3b) +,S(35a83610,30fc10f3,53d2fdbf,cf67655a,91b86555,cd3d9eba,f962996f,ecf55cbf,6fd79f5c,df8093db,5c7f3a94,52dbe6ae,bd1ca410,199deb04,761ffffc,77ec9fec) +,S(cd05bbae,d0a8d78a,2e05e9d4,1c33cbd2,8d59d384,75d42389,43f9cc35,3a8a30c7,9f7336dc,8e77fd55,bd0b9e8f,23eedf1f,d0c16f69,921994db,dc2588dd,ff72a8f8) +,S(da3fe760,2547c831,2d4f515a,5ce530be,29379325,41c6de36,364c4b5d,ead43c58,df60bf1a,d2fca43f,6d482df4,61fc180e,5e3cf692,995bf8c1,7d32a263,730b3ddd) +,S(bbd7996c,25ba5c24,a14742a9,745dd2,8c18a598,8279581b,f8b5958a,8092051,896a39f1,310be1c5,9de4b86c,7c9bde10,8035ba39,864a45a3,69573d16,4afbc2d) +,S(bf7c20dd,64ba5f51,2a996bd,428fdbaa,df1853fb,f814e6c7,a415fb64,a3e16070,afaec0ea,2b18c89,93a1a565,f3db58dc,748df9eb,4d9f8a04,a18cdc23,4710d5c6) +,S(919d0aa8,10928129,cad99b09,85bea5ba,7d4ea114,9f9d5d65,2b6c0e0f,20464903,60d9352b,d053b01c,83caa121,63e8c9a3,e2153cbf,b335943,7a2a788b,7aa02dfb) +,S(5e7c2a9c,6ab8251e,8f8749ab,e0ef107c,aee593e1,a8632a6e,1e0e0c4e,d3cace9c,74186f42,6f03f806,36d79258,e9edf593,6e21e0b2,d882d933,c0241ae9,7d761582) +,S(2815184d,af1e838d,86d63a32,db5339df,24731743,aee62add,21e3a6c2,c2b0b1c0,2a4951e8,3ec61221,b1035c6b,a7d2cbed,f6ef93e8,cff69e01,295e09d9,20e05919) +,S(e3086e36,91432a20,8602458a,87d82955,c8920ca9,fe1c079,3eed878b,282ec3b0,13db4219,50388269,cd591c5c,d8e07ba1,b532f01b,485829e2,aae4f55,f05e4362) +,S(8264d534,2db3261c,d7e294c6,eba040f5,461fb9e7,e3fa13fb,dfcec29c,20f2fa7c,4dc311ff,10b92db6,b67f47ad,86fd74be,24e3dbe0,d6a74842,92f35d9f,6e95eac1) +,S(9edbed6,3c4b66ce,a8c2ac6d,89622d61,6838e1fd,9b93c363,c2bde528,a629b2b,c1706a02,5b1f9419,2dde89fc,63ae2a81,ea015ab2,964beb58,d5ca7ffe,84266644) +,S(68006753,672e9ae0,79fcdee7,9814a904,80c170a7,f644302d,e5de7982,7684e12e,fc1209de,88ca7c3a,614252e3,153df13a,6d0e8db0,4c82d83a,fcbe65a4,5c084398) +,S(acdfba80,9e519114,a11b1634,1835d7e4,5b93a6d4,7094846a,e1ecec00,18bc4531,a4e57d02,51511f2e,5b729309,4c50ebef,4f8d3cb0,d930ff48,20d0623b,d636d664) +,S(978304cb,e99eb899,5ef43f94,c67c471d,6d42ec19,f83f9323,3a44b9f2,e2d13896,ab26782d,2c1dbf16,a90f90c,8e49d250,1e1172f1,3e1bd20a,3deba979,85fcb110) +,S(8c8b561f,9c857510,88478c03,866b347f,46e06801,82482343,923d7e27,c67f49e8,e7908d27,79cc5b19,dd00f2f0,4ab52474,5c35cd6d,4b85932c,99614fdc,64048cc4) +,S(d4a7ebc1,987b1abb,5d02e598,190f73a,36d1176,d7f0f7a8,cb9491c1,b86a3c55,4f321dec,9c1832e3,b0d0c974,798834ab,6a410bfb,398ebf58,177f39a2,22ba4e50) +,S(14bbfb6e,7910f522,69e544f2,ad3175d2,3a36b7aa,8209c24d,1fbb4277,9508c261,d16147c7,2a1df442,d8e831e5,aecd54c6,8bc3f225,4d0f51e4,9a375053,73e8d08) +,S(d24ad71e,81de43d5,7096e101,6bd4d99a,46e52e56,782d99ee,838217a0,dfea0f5b,ae574f68,e07cead9,f214976,67a18c2f,fbbcbddf,2bfb6c95,3b7ba673,7d08903b) +,S(ac96889a,f0b46b7,6896b763,8e1a13f3,dd24459e,8601f892,c3367c7d,8b52931a,b68a8631,8672c378,d99b0b20,44b06190,876ab100,eadb12e6,c16c2ba7,c1ee2381) +,S(36b4da52,4f4ad5da,d7396445,1e79bd5c,20973df0,efa82bb2,da4bf68c,55afeeb7,5cb7598b,576f0db4,db1093c5,e6c9723c,f493bb91,450a0017,9f79c8e9,92dd6136) +,S(98c7bc3a,7054f928,d062ae65,b4140dd6,293f2fb6,cd16fbba,e00d39d0,b11befd2,82d134ac,3e614e4e,62b1b475,bbb5fd80,a5e6d3e4,e4572dc5,7cb666c9,a06131da) +,S(95bb18cd,991cdf72,1c627d62,aee4655e,aaed0b6a,b1e64537,fa89a0ac,f60b4a52,c37e37ee,5b87a5a5,e61824a3,ea519f03,dc3b0a77,f755485,d337ac79,f1f9e8c9) +,S(41e45ca2,b88a4679,6df9106b,c8b53180,81674c34,9646545,e5ad9b6d,e5f6cdc6,151ba666,b0fdb7a7,18110f62,83e3cb8f,8e40fb8b,fa1a1854,75958a3b,ec10d197) +,S(32d15f16,dda923d5,c2f1bf5c,9c003b33,b77d2450,95e5ad31,2ec62956,ae092805,58d64c72,96ba6976,d61774f,f37a0d1,6316cd19,3ac0d930,bdcf4924,cd904095) +,S(41c4e029,817de516,8dc04b2a,9bde3850,7ae48602,dab08db0,3272c694,6cf099eb,303738a8,7b888601,2f9e2053,5bb8b610,92f6222e,96968afb,98940d85,98181458) +,S(28b8ccf,b14a86a1,84fc3c3c,a6a7dbd8,763415,91a67d8b,4109f026,1dd964c5,899f98fd,5e0c59be,69150d8c,5a917d6e,864fa15c,63072769,f75f6353,8cb276e6) +,S(f2776367,762d6468,c9cc0e38,d3921813,16dd394c,eaeea519,786b4353,a5044586,1a873421,1b170183,a117e420,c41d2725,84acf219,a415778a,4eb0c34b,bee9a68c) +,S(7a1a5f53,6e96ee57,e10b1337,6bb1e895,d0703c6,5adfa4bd,f24937da,98bd7144,860921d5,67fbdd1f,11aa3ced,103453af,8c3f5037,b92ff10b,ee70ddc,e4323206) +,S(d82e79dc,5d6de6ff,8863e039,60401bd1,610500f1,57fd2b41,f20689d8,889c3f76,f1947dc2,ca625df3,af5ec97d,32e62c09,2139d108,948795ba,5cb164b9,351bbf34) +,S(6a2e184c,23ee235f,93f036c4,3875db01,22416a6d,26ef54bd,85a2b465,defd0351,6c44297d,724eb2d3,2f58a197,2f52a7ad,ee49d30f,c8f8424d,7f26c6e1,73dc6868) +,S(ea0d5281,bd1417c7,2dbedbd4,dff37c49,bf143417,d2a40dc2,573b4b3b,2ccddcde,c7a35ef7,685faf18,c5a4cfcb,2eca27b7,46b21d65,ed71aae9,15185cc2,6d2b54ee) +,S(d5432c9f,8ed0b4a4,c3e42dd8,28098f13,11d2cdf3,94672331,51fddbf2,a6030974,1e047ebb,8cc01a43,2ee6ea04,578513aa,17ad2bef,7fc7653e,936b2d22,bf8f6c3) +,S(c99ee053,655c9d53,1fdd2298,3cc03756,299f47bb,5e1d0a4,d7b861fa,c3b5e332,61c5187e,4e12f8fc,617a5fd8,746f28c3,368b6b19,1189172d,8c56e2f4,679f6b7a) +,S(f41ee431,170be2d7,fd488c3f,5f21f3f3,aae5e501,1a3c4ebe,d0f6db8f,63e11e55,f767b289,118391c4,4d27c1e0,76b7c70d,110cb938,e9c5c62f,1af200ad,7e9976cc) +,S(505a65a4,29388bcd,55561f5e,fb3090b2,2d553bac,2f8cee97,6c0685da,40006e41,c72c9e86,6b4de925,3d463d7,e7bcf7d3,d6e7c351,1fe6c4b4,7fc436f6,d793e0ae) +,S(ca34be0d,48bc2931,cabe71d7,9cd2bc23,ffa928a,5d532d67,f3665acd,375dc01e,263008ca,4dcf002f,8fdd580a,65701694,bf4530e8,baa0438d,b77ec246,75b4db4c) +,S(d52c25e,9a76600,b16dfa93,cf9c2df3,38c806a7,d8cff18a,1d262662,5fed6d7,80309810,6055c3a4,d5d1e5ac,945aa815,bb8ca3ed,10b5d54f,156e4336,39c4ac77) +,S(83e43bbe,62e39426,a0a74ef3,831cb4d2,776d7ea3,d5a2d57a,8280bae6,ae0bd8d7,a1c2c1b4,ea1140c8,cb4ec2a6,98a3f727,666eaf81,1ae9b89a,9e09db39,d1a257d2) +,S(12326a97,ad8dbe89,3181d76c,6d7507e2,74d62cca,1f0a3517,30e9ddd7,198de84f,79e7823e,7cfa4df0,bb31e9dc,ac415297,edc6e061,4fca2f18,1ac7fd46,d27fff48) +,S(1ad3375e,c82aa917,88bd787c,37fef8a0,2071509e,aef62e8a,dd5c5e4c,b096cea4,f9f9f10e,efc1fa79,454c6d55,b894d65b,ff5c445b,f4e9e46b,8c82a4c2,a94d5a71) +,S(8e8bf9c3,a752258c,278bcf19,7aeebae6,fcc198f9,2310b13d,d114c1a7,d10fd2c9,e2f41d5,b7d94378,5f61f572,763e6e88,df7b321e,9baf0445,482d9f22,f1160195) +,S(c44cd33a,144e2926,b7ebfb93,d7d9ab56,3888f6d2,694efbbf,a5665e10,f6e0ff7,c2d4afed,f77c22d2,88f9cf38,a057df90,baae8ca3,1e074d11,bb8f89f4,e9e1bf4b) +,S(b960f0cc,bd7d3431,4138accd,aadc2efa,d5b60071,7c69f1c5,92900a40,ea68b24a,e0cbda14,801794eb,19401935,3f8ab80a,f525b8eb,2b64e5ee,62afaa5a,da4680b1) +,S(f7104560,8fe120fe,5d036260,5bc3de58,76e24b6,20684413,a440cf56,6520559b,2e208f0f,fea3f78a,9a283f9a,6b601ce,db4df4b,b2fda7b6,306dc8b7,3d514f35) +,S(83a31aa2,cb10fc14,ca8cb2cd,b21cc163,41cc9862,67a5f1cb,75f3f90e,1a92c59c,be18918,400a6e32,b4fa3469,ea6e3613,251ceabb,29cbbfaf,2c16af07,fc5413ac) +,S(3d7b800f,8802e521,341f83a5,efdb355a,b60669d0,adc15531,72c62097,8106f6ab,f9b179a3,aae98427,e02d4f00,89b3cee7,250e30e5,ed72d59c,198d5ae7,1d639e72) +,S(7bef4e27,9064400c,48d4f27a,a754deaf,8af74b10,d5dfc497,98c38216,803f50e8,bab0d71f,d02c67e6,b274693f,6a4f402f,831aa4a3,5fd83014,fb07c5c2,e62d561d) +,S(e6b2c83f,2a6ea201,f56a024c,482a8076,2f2053b4,2e4d2901,4a5178d2,3361bcc,75d1f7b5,209cafe4,f98e63ac,53052a40,487b3390,e4ab73eb,ac63acb5,cc3dc88c) +,S(eb4f3b95,f12c16a8,e5e13446,d9b8ca7e,92c56bdf,565aa4f9,bc1c47af,914fd145,e3776908,e3f3228b,ba0c0523,7eaf1963,1835797b,ffd7eff5,61b30fb3,9fcd6307) +,S(e2926c0a,858b9732,82c1b34b,4c4ba4b0,3099797d,d29c5fb7,4447f28d,ff962e54,2730f3b,e59e862b,37ac50,e5375d08,920cb62,b87ee8d2,f5ec9975,886359e2) +,S(8bf4efd6,c11d7251,b06a5e08,99ff2e80,349f8022,387f3200,6d9de060,bfbf3f68,5514395,457848e,a79ba6c4,39a7c151,b497751a,a4a1784f,114686e,e351afb) +,S(4ea97c1b,920d2ec5,3c2182ce,d6f7e1f3,df49e673,1a14ecd7,d67aba0f,fd077c78,5e958afc,d3894757,e0aa89ed,ba26e035,f06e4b11,da13675e,29d382c7,b21fa9e) +,S(1b12e81,3c7c19be,18576f93,69d938f4,bc81bbfd,7e9eb443,cf2b9ef2,b8e2b3ee,47220a1f,718c36af,8eb8a9e7,ecee3899,ddc49127,91421438,8760d6d1,699a5ad1) +,S(7c6c144d,4f839904,ba40fba8,b739913,54f40bf0,f5810329,c4e3b961,ee6a101d,6eebb976,3ceae5f4,f1ef2473,a50b795b,a6375c72,df67d15,f310b5ca,9706b5eb) +,S(ec637ec6,bea71803,2bae7631,9227ae58,9581d3a7,131323ec,35f0d9fa,27a3e285,c12b830f,f273fe72,4f3bfdef,4279ce4a,8ae6d0a6,de5cbad2,b0a7b4ab,643c79db) +,S(33c8d6fc,d2b37103,2426910,6b9adb76,6c76f788,9627a9,6807572,e0af0f84,b3f01db0,7ed82f45,252d494c,af735e6d,3934ff78,c89c57e6,6c42a663,e5d6a792) +,S(35ee32e5,f7204f0d,d48b1a80,cea0a418,1d71205e,c373827b,2afc25eb,e3ab7e20,d57bc815,684adacc,756291c6,87d0eab1,63067976,a7c3a2a1,98ef1d8e,bad12935) +,S(97362395,200d807e,623826e8,3bdfa37b,e98793fd,6d7057f6,370720b7,5089a6b0,c908e9de,cd1d54a,172973b9,1706fc6c,c3367d75,2216c2d8,1085dffa,5627f06b) +,S(bd37e01,eb944b32,b379b195,16256ad7,4061760e,4eb44361,5e8e5fd4,34eae9a,dadb545e,2a613e54,6067cb6c,179fbdf6,d94b7b8b,c799adef,391b2957,2b93f57) +,S(b332b57a,4f070d20,35986e86,d82cc6f,7180293,53bd360f,d3f883fd,68e9c5ef,eebd3a05,933526ab,ba9e63f8,cb24ffa8,550e50d6,8cc7a4bf,215c551,ab89832b) +,S(fe5bf27f,9459e640,7489bb32,2012d1d1,69d40635,74dc05bd,6bdd6c38,cffb61a3,72c6318a,3775b8fc,5c790d6e,31bbfddc,7ee07a71,93e5f137,e3c3e098,bae25da9) +,S(f27cbe27,ed93086b,517c5859,9929310c,ad0e05fd,482f1fc3,af041852,c63a2a23,cce74e61,4e14bd09,8f11674f,23e30be6,b3276f4c,f85dedea,b3cbfa49,5a716e4) +,S(b328535,1a1b22cc,51b7a590,3582dc27,518bbfa7,410dc36c,e63da663,daa8693a,1b260487,7d3ad6e3,db75a0b5,d6b89df,df507809,c203b4c4,cb0712ce,ae2e3d2f) +,S(bb47bb09,70dae4b5,4f4c3aa4,ad4c966,ae42691e,ae39f1ea,a6711d6b,5f04b81e,2edfe19b,b52b7b0,2b4cf349,aeeeab0f,67524375,7f35b6e7,b920d343,e71561d2) +,S(fb6c9735,d4333142,5bf6ad83,50c7241d,b82e35a2,9cbafa37,d822304a,c1b3dd02,946a7ec7,1e0e6dd,a4d4c315,2a6e7489,8671dcb6,8a219781,3e2491a7,6a9e3357) +,S(c711f224,40cb6e74,a60509ec,23daa2d9,fbca44aa,9a093475,524e31e5,43575a3b,e4259800,352d0d79,c5e22d3e,2bf59f4d,e4b42484,68d15c47,ab5a9cbf,854294b2) +,S(9c748d45,a07e141c,639ef97e,8887ccc3,aa84bdc,ca0618ff,4f43b1bc,7496c83f,3dab775e,c3001657,e71a9d46,bf8cc120,9a74b9d5,1025f97c,4dbb9457,e932b5b4) +,S(9d5e6479,81a9278,6db60938,4a462621,23070938,d50e1bed,8df9474d,bee12513,30f2517c,6ff04eb8,9a6ef21,e4ff33b8,e14567ef,e38871bd,b9dba6d5,584c8b0e) +,S(4d24d6e8,91644ed6,ac1aa619,f9eb2b58,a9932c5b,3e8c82cb,589694d0,14b1d472,6ef1a21a,9dcba4d6,850e6593,3ee1a259,91203278,2f478fae,cda13d6e,5abdab22) +,S(fa226c4,36b389c4,50143041,da93c906,70258092,a8de85cb,d20a0dcd,284bc808,524d2992,655c77bb,59258257,5db3d663,a7a345f2,85572ff6,e9dd1dd3,21bebf6a) +,S(d4e659a8,e9af7543,2d9ec769,5dda0371,7bd79ff1,9ba73f07,ad0bf13a,45ad3b77,5f4a2de8,db9814f9,9b73ec63,6c77f847,1aa48356,ff67c8f8,3f0b6aaf,1ac7ba9e) +,S(157b6da0,1556b23f,b6c46b06,145727c0,21d6e573,782bcded,d594ae46,598df23,737d45d5,2c247718,e720fed0,56352768,ce111425,72730890,5a84a545,c53c560b) +,S(d97a6087,19c8572a,78b73938,5479e4bc,9a2b249e,a4f064a4,550ce127,fc4bd45e,f11e233a,75ba1651,144368b9,55bd4dd0,f4ba1f2d,2d0bce2e,82315e5b,78e0d76e) +,S(d2fdeec2,9b5f4ef6,374c2b87,57e4867b,d2e036d8,964a2ae,15632ca4,6f79a294,2d2c1502,a935f5b5,960abbda,9db42aea,c9f58f0a,bfaccddd,f8d59881,e2953872) +,S(fbc6a2b1,b3c0b039,9abc55fa,835bbeba,b0461db,41f3d9f3,160d0154,72861b3d,54421d5e,a5ed3abe,f22df1a7,26a2b5da,a298b41d,acc69bd5,a72952a2,13f928c4) +,S(7ac224b,cf7efd8d,b214db6,a6601d51,829d57d7,28c4c3cc,398ba57f,5079bf99,edf12fdb,9e281367,5e7df40b,1cc3c572,55213edd,c0fa07b,4e3f750d,36d6935c) +,S(f2bc4452,4af39f04,afb480c2,f7addb57,a04db86c,3691b26a,922b6ce5,a1724d9a,63c372e2,4a659127,ace8f54d,33969635,1d890dbf,7e2a31c4,251352ed,53c3a0bf) +,S(5ac48ffd,bf27b452,ca37dbdf,83f2fe6d,8f704040,f3a56180,ab991228,a74ad88c,c7ccab4a,e859e7bd,982310ff,2b7eb408,678b6f21,f52ebea8,41021f3d,fab6f091) +,S(daa3d659,a4defb4d,3291a16a,d669a43e,b6891e90,dbe0147f,568b650d,1213750a,af36d811,9ce1ff85,5dd637a3,bd475b10,50216093,aedf5f24,2c98da62,29bdcdbf) +,S(381d3791,30d4beaf,aed138d1,4072bbcc,b8d71d6,dbb13226,ff168f64,3bf55d37,fbfd7b62,3ce32a4,4335682c,d5ccd4b4,aa4430ce,d8fe3d34,9582bba,fedaf9c) +,S(757c7b23,ff6b6ecc,51ac84e6,26ed70ce,4e6e5c74,e4b65f3c,fd17c304,e19b1ccf,56848ab7,f814a047,2bd286f6,b386af5d,34b27c4e,a3ece71,f153dcc7,7e4027b8) +,S(ea498d11,ca35804c,d6103185,ae468bec,6c2f4f6d,ab025173,b1de4027,551b913,ee939bff,8d30bf5,9e3341e3,58acab90,17de8fb6,e2977847,f4322ceb,ca8829c6) +,S(9d119046,59ea5dff,30105d1b,5ee3f8dc,c9291bef,15844057,66e07d44,72ee1418,45355041,4d4715d,e8c087d4,f05b5f8b,a424ac3,49b3ceba,bf806b9c,e657e139) +,S(97bce776,90f8790f,e7d82b68,b7dc1b38,f3baded3,f7c67655,1894fc4f,cd1b834c,fcc18c2b,4f743ca0,e00f4b34,509fc237,c030b689,83451d5f,e7407b81,ed04f7b4) +,S(5339f056,abeb4926,f46dce7,3b8d735e,c6e9c4a3,2057c22a,49c86400,f15d7ed9,5be6a0b9,37e26dd9,f6db74a7,74fa10d2,cbae30f6,bdfafb,dfa2922c,58a8e37e) +,S(27f22d01,4dc5d3,162f39c9,7de3ef62,f2275b5e,cc6d5e32,6ab064ad,f762a446,6aebbb58,d671179,d712926e,d56cd280,8393fd85,dee45558,300a0f8a,a2986f09) +,S(94af2fff,61741cf2,5f158308,e7333e3f,678bf1ee,56adfd56,629312e2,2435f9d5,33a7269,79df6672,b13198f7,e674330,806f2dd9,50d8e82,1774f381,d9ec24d6) +,S(ae8a0e18,486273a5,36d526ee,3974031f,f3ed095b,a6835a68,2e943dc7,e19b37e4,23c2a51f,69df1826,9b21413e,505c0785,576fbc84,acbb2812,fda146c7,f5e8c8c) +,S(623fb527,d3d99023,9f720cbc,64478e0e,a0b84b28,5c0c3f3f,107b3e3d,7dc430aa,3ea48a8,d1eb543e,ade4a55a,f909e62,14e47d26,9471dbf,4d98a3e0,39c72849) +,S(1ff42295,d85e98be,f7aa84c4,47ec854,29f01b4e,c87371f2,b2025ba7,1e31a768,d9500f9,6e8c697,7ecc51d5,7bb7dfd1,3cc97017,58bb4196,b0b11d1b,3c24937) +,S(bc808b0b,67bedaeb,2e7a4bc0,d328efbb,1ff35dc3,b51716ca,3e501a3f,956aed3f,6af0de4b,26a6378e,6d86378d,d1f54243,929c37ee,d5c10bbd,86b80c3,ead8e545) +,S(e8ab92e0,17a9e956,354203b5,5d7b15fb,acc666a2,79158016,33a91865,b5bb46af,3e87cbd3,66926e66,3f5faa,426a9db9,811a9db4,de3a4bd8,79073b7f,c1e3197e) +,S(a7bf0061,c383040b,6e89ba95,b57102ae,2c291ad6,72bb5027,3c27fcd,f90613ec,79ac8ff2,4bbc79cf,431f4159,4852ad4e,2f0a9f86,ca72ac11,9d4e3fdf,8746539f) +,S(6841bcc7,22b705e2,759ba4e6,83d6b83a,19ee6b4a,375b38f4,5722474c,ca41894c,dac48021,5c168519,d147a966,451dd63,7838d236,5667803e,80658faa,1029a7e) +,S(d67e6d5e,a1606817,512f1db3,9033829f,69089a41,902189c5,20f0202b,8511479f,9cb4a747,7224f93a,8447152a,9fdf4c92,36a1b698,2e9196b5,a4355715,b9fd6ee9) +,S(61b3a7a0,53c477b9,e03d0a96,8ba38de0,b02e42df,162a13fe,8ad538c2,840eed06,94c07520,fa19457e,8d98fdbd,d9a9bf93,57642cd8,1b48fa58,b4b14a89,cb6142ce) +,S(cbd26d0e,a00f7dd,4b0b26ba,7358b2c7,587e233c,3a13c86a,d5022ecf,c865e4ba,50e832c9,d84ff55b,7ba79035,559bc889,53700622,59dec3cd,8b3eda3f,1f2b6e67) +,S(17a6f57e,d3d729d,c5ec018e,1b69394b,1ed78e59,6c7a5e31,bfe5dc43,f9c67e56,34f16cdb,c23e46e6,bda5db2,7538d7e1,f66751de,3eb05543,96c66a54,36bdfe9b) +,S(eaeb62d,93fa13e1,ff9d9a4,9eda40ce,dd6006e5,ced0e8b8,c02f7ab9,98f06f31,7e225365,b4b39204,b01c8890,4476c141,1c166f75,1726718,8ad917c4,9a719ad3) +,S(d09999b6,c35d5d71,55605a17,e7f82d3c,dd8d68ce,9be252e6,99493031,a39c7487,9165e761,8dfec3d7,cf733fcc,e548f672,362637aa,8687f47c,b1eb5c18,a780b061) +,S(2b4cf8d,7fb166d8,a6931bce,e67f580,870c61c7,635632a0,71166fc7,4a11c693,7974e2d5,164771d5,2e7a121e,2b015565,b3a874d,d6313721,ec69d3aa,b44d473e) +,S(d5c0045f,a411cdea,470d85a6,66aafa44,49ed682f,a1903c5b,c9594d19,5cbebea6,ffeebc77,5b24e736,8a8b46a3,64837466,85df5c8c,b40bf2b2,291f370e,94c6eca4) +,S(1eed08dd,d9569712,6c0a4039,c6aa5ae5,ab4aabe2,a88142c3,b9aa763c,632b5e38,d180547e,c4640035,ca86d925,10a70a64,5dcbf2b5,d3add4b0,3f6d0fba,5f4c2f8a) +,S(9591b04e,3de43104,3a6982e1,29a2e79f,f525888,846689f0,44e50b18,ce14413e,cc4cc696,73279c51,4aa4fd63,474050b1,930e627e,a1bd9d55,867d700e,fccf8155) +,S(690a17c1,b2dc7ff,520aecaa,380b19d6,d4a28669,83dc5df5,8ab2bfb7,6c7b0600,bdd8a858,e2d989ca,79fbfd46,60ffdc0b,e0231562,711b13d3,47cfd37b,7a53d4d) +,S(800a632a,aca6b505,f9fddc22,14efe53e,4e7ad2a1,a6c07d90,27d8109d,893851ab,bf242683,e0c1a24c,9220c6ab,deae8baa,12c6203c,a0080856,bc5e5ac6,4c3f3261) +,S(6dceb824,c48159d8,57a92334,4c72b4e5,cf2005c5,6fadedaf,5a8b780d,3ceeeab7,e6b961f7,6162ab6a,d44f3fb4,5aefc843,bf0d714a,1a50d13c,68036f42,30a1ad10) +,S(3ef5eff1,2b76432c,4bdfd1f8,23bdfdee,f60b5d0f,5d0b4051,2a3e22bb,665f2b0,8741e43e,9f78066e,d57d317b,d50252fb,11d8d235,3c2c9d57,76191c21,8798b0a9) +,S(4ce8d33f,a53f2e1d,aa696e9a,2de694df,2192db5f,8e6fe88e,b5d51340,83791c17,a023ff40,69587bb9,49ebb15a,d047f141,9985b521,ae915f54,bebc6dbf,5320558f) +,S(da030efd,a3f6363,926abcd1,182f183c,43c4a6d8,8bcb0519,3d137827,6dcd3fbe,c14f27d3,2251248e,3c4b8613,481e7c48,f1493b6e,5c0716c7,8d5e3b97,876ccf3a) +,S(65c12034,87b729bc,3709759d,beabdd79,ee7f50d7,ed2cedfe,f2c2b7e9,97192f40,f440d69e,d59adfbe,e087ef70,9b75b95d,13ac0e06,20683d3c,6d49762,ddf68a01) +,S(82c052fd,dbd6aceb,1f429f21,eed34d44,f915e949,7190aa6a,d487bd6e,68d91c20,90dfd944,c7c20ec4,4ce35d2d,4036eb97,894f5b93,6bef62a0,f2f65082,b0f7678d) +,S(43e2f20e,cab47065,e71abd8b,aa511163,e17e3efd,3e17d790,ba924de5,ab402255,6b1ff657,e37b65e0,bf2c5e60,47e36c8a,2b7ba965,79bdc711,c3ae5935,d2c47bed) +,S(27f177cc,6722e5a7,70200e2e,a9198bb9,f227251f,8efa1988,ac7342b0,985a3853,a76767a5,3743db5a,1062ccb,64452ad1,606d5065,9df8c0a5,64f049f7,764d6a99) +,S(6b1ce20d,d15cf54e,59aec7fa,c1919791,c40c926c,55801801,75c09ac0,dcce0147,c90a76f2,627d2510,8b89df25,23f069a3,6b102201,c2fb7e9c,932ae678,4a28906e) +,S(f9df6109,27b5ff70,d55d2a46,ebc6a734,df165bab,3bd27398,24a60727,5410f62b,4da454cf,7a381056,581fb115,d36161a4,4beeef74,26724d,d4f5500e,3a6c1612) +,S(16bd87e8,2f87778f,6b3f1da1,a04bc048,3b14de01,420b0074,81aab07d,ad806cbd,13a50b5d,886047b7,6898c85d,cd1bfb4,87642f95,8304d54d,12c03b25,9429170b) +,S(f35175c6,2244f0c3,ddb104fa,3ae57557,424c2d0e,f6a20246,e2fa48d3,2908dae7,dfc1ef36,8ffb4e8,2076ae27,7788444b,33880ee5,b6d5bd0a,9a2ba79f,30c4d1ff) +,S(6a9ec43a,b8a6cb70,465ba668,5e15fe2f,9e714c0e,31f1f227,186d95ad,2faeccd9,ee752bfe,4da4feb5,e4c0266a,57929e56,62483704,6e927e73,9edec593,8d538708) +,S(92e3b0b1,3df6dea4,371601ba,3d92f507,2388a23e,302edf74,6da973b4,613d2292,9442966a,dff82878,f6e0b8d9,9e56f99c,68eea310,79b365cc,5f057eed,ec38496a) +,S(35427db7,f03afb34,d13ba232,420e5d9c,4a8d16c7,924a2043,a217fbd,4287230b,5cfc1908,108fa47c,95ff8e02,634351d2,523dd990,aee1700c,7cda57c1,b106a734) +,S(a61be939,d3a33b8f,65b8fb5b,897598a7,ee25e71,5797014c,fdb087f1,90895825,fa6b7a9c,f2a4a71a,857bb126,44fdcf27,c9f4ccf2,7bf6a0d0,dcf8179e,af1a3396) +,S(659868b8,2a9422d7,1da877f8,59956376,b999dc3a,657278f0,89e1b7,a3014222,9ecb6c01,fb97f691,92402a76,13f7932,d8a82252,e6b97c66,5c727d9d,e6b2ac62) +,S(12667366,d27bbe3a,d75f00c7,b28fcf20,86e9caf6,e8b5615e,eee0f180,526602ec,dbac0f9c,32895bf1,21c90190,d5bfea81,84289a4f,a0cf498c,3a3084db,1d4a833f) +,S(74af3ac2,60461898,c502229a,8eb4e7e0,962c8f38,897e43f,6e421ca3,3240b7db,72f03ec2,7c24abdc,dbc9af25,41e10f51,5e470c7b,19ab9680,24eecce0,954c84cb) +,S(9aefb23,d88c5745,da9606e7,ce81d4f4,5a39c8d0,4f5d5f07,62653594,d3a34732,f797796e,5c1c0a56,9886af6b,fd8a8299,29ae1897,ca43314b,cb6ed78c,6c0b0572) +,S(93a3da8b,1f686078,1849ca06,24c2cec1,796f64f8,4f46da9d,34766eb9,dfc1f018,e5c50d0,fe7d2f53,fe1053a2,985d2b15,25125981,30de3cce,2ebf300b,4b944c0) +,S(ed8d18c3,f526a062,bd6095cc,249b7d10,ee09d072,435218be,f2ab6c90,c5ed66a6,42084909,f4bfb751,5ec6da47,2cba7678,7870a9fd,bfc86fba,669e31ff,233a72a2) +,S(dba838ae,b57fad4a,6ecfae8a,acb50123,decb0f60,b702a9cf,7af7d78d,814845df,c3213cec,8f225c2b,fc02519f,dce1f67,5ad59b20,91381f0e,feef93b0,3c6536b8) +,S(f1a033b8,64caff57,21857094,e1038fec,7879765a,3b977a4a,c6616162,68c1d8fe,9592b8b9,e4cc6a7,ce173980,e68fc405,88a83788,a08c6027,8623ef61,ba81b652) +,S(53967cf9,7058ad43,1222e9a,46caeba2,d8fa447a,6b0295ab,f40b8aa1,af1f0097,e8e86c76,cef5299a,9a15a6d3,4985411f,2a71b8fc,99f7a76e,230052fd,d5309017) +,S(2477d3a2,bc3fd88,6daba319,8c6fa6c9,5206bc1e,955e9d4a,c6e5916e,5883eae3,baddd174,ce70e285,1e7ed788,cb81cb7a,3402276e,d94e6e72,f20789bc,ec4f5257) +,S(b483c05e,22824454,52f44e9e,287bc21a,634018f7,babd1252,d7a6bc70,24d9cdc7,5d7cd9d,23ad04b3,3a7ccdb0,38676342,5b2338bf,48d4f910,853e9100,e1f3aadb) +,S(6ae41ce9,6c8f0a33,674f74a4,587db25f,7c368fa8,83abe414,a3f6bf13,840d46f8,d52f2dc7,d4fd791b,36e6448f,5c8f746,759e68ba,994de0d6,48c6b1b3,58476871) +,S(bd1a4d61,e19ce013,d06740be,c3ad88fe,bc3b2391,45563be4,41768f01,45f4c450,88c18e77,c5313848,bd19bf27,374deffb,1f40e479,9687791e,675af225,1141fda3) +,S(1d2fccee,47b4553b,215dd2c7,f26412d6,73319507,43136454,35426bc1,29b358d9,93e52147,c13791f6,aceab8dc,95df1637,83d985d8,3a4426d2,f825d126,e7b8c564) +,S(322cdebe,5aef9ab,957b355c,e8e4fa7c,23f23f83,bf311785,f0fc40be,ce0f7453,2eb8c80e,561e419e,f898f772,12eccab6,e6c4ffc2,5daf67b8,47853a6e,8475d19e) +,S(c7474f42,5491fe9d,51a9e00a,a42bc188,50d4fa36,c19d9869,6939962e,61e207b9,8dd394ad,799a69c8,da550741,7352e7a7,92a941d2,10b3f65,f634cdc3,1f42a875) +,S(ac33b339,1bddf66a,6d04c62c,da618bc4,1ad217c9,7d37526a,38d12e28,9fa9dd30,602267b,59fe438f,ac57d14a,8dd3451f,acde0be6,c8984b58,7cfc1b24,34ed9688) +,S(158e2a30,36f71701,2020f476,dd869974,66f157a2,27548e65,688ae79c,3bf8141b,fac16be0,6033e61,d34d1d,1e2c95ca,6109dfa3,64232edc,8f8f62d7,19ce6303) +,S(88384c6,42d1bdcb,af5b472c,2f7a54b2,11ae4947,433d5d35,add21374,33ec4b78,3c3a484d,5b8793ae,203f90bb,476b4d25,773b268a,8e89dfb5,dcb17576,166b3e7c) +,S(21e3c1d6,32299e3b,5da75f6e,7ffa2958,e5d686c2,6322491a,2597dd44,f6973d2,9866fc69,7b9399b7,4307b1ea,e27eda12,590bb138,b22485b9,de6e3cfd,8d23bba6) +,S(abc484c2,6d06ec8,bba4170f,727055de,2611145c,8e4a33ea,56507b60,3477d319,4f92a638,17f6b635,d2d944a6,b9194d40,c4ab7041,2a8ccf05,e2fee038,58d87592) +,S(7a98d6d0,202f4230,a12fe9d2,e321bc55,a3a3b35c,92443731,cc8112f0,579b08fa,bad00e1b,578de9d3,73f0ea77,85502035,c5a04c98,8904923b,f0059a3a,a8ec6285) +,S(282e401f,57ef51d9,f9a10959,d272e0da,e9898f32,d2a3e059,4a65c901,cb1ae10f,6bb8b543,e9461164,a66d55a0,adc51ada,4ac311be,c6625276,5b2c1639,c803037b) +,S(5259a2f8,3dacac1c,18a9a64,d9834c82,e862169c,7a1b9d24,2b521c4a,d7ec4274,196fac52,458c7d1c,3dfae8b8,2ca130ba,99d43a40,8bf41da7,d2e9d040,291f165b) +,S(cbc4fdda,9ed1707b,59db2171,38e9bc1d,eda499c0,78f22c28,4309e184,cf906081,2929df0b,24074d42,75e8a861,8f064466,9ca0dd45,752c7d5c,8cf32661,f8a1ebe8) +,S(96b294a7,ed8d4916,21f10b04,3c2a5ad8,88b92c76,3c93f375,f6d31d99,64b9cef8,f5502e33,f1416c8,77cf06f2,5752998d,a30ed434,365b8239,617ab3e1,65948a96) +,S(287e1f0a,a510c8f6,273362d4,ff8d96f0,dd27113a,b45d0bf0,1af5d5,d24f5038,4b5ddc1d,6c9c4423,1f27ebde,bf4afa29,df337f18,2a2559b0,33de6830,cd7b9e14) +,S(eed0e323,3475ee14,5160d4b7,49210f47,c58d7b26,95dc8036,eae0e6aa,91a545bf,22407aa5,430aa089,3f7218f,2ca23ea0,16eb04b3,3c967e6c,d4c68ad7,16e4378d) +,S(1417cc87,72c932b2,b1116b4d,ab4e86a6,e7d80fc7,b082a6a4,c148c50d,177299a8,66e06245,56f09207,ab2d944d,167590d6,44afa2b7,b598b92b,65706271,d7b50e30) +,S(af6029b8,93c549c7,3544e849,b01ff2d7,b991fb98,2b8a3baa,b9f1b8ed,2b24bc89,dea2973,a97bcb6d,3257121e,9233956d,43ea9155,8105559d,ae17db09,fbc14f2c) +,S(dbb5544d,d28d2510,8a91dfa5,9a3c7538,1b4173c5,eecc8e18,b5065fd8,fa4fa570,4f84feee,755215e9,15abfbb,ff46eb6,9148efbf,39f69261,a9d2a345,3aaf1bd2) +,S(50ee1b42,be9598e6,3fcb0467,18786633,18b550ec,16645f70,869b231b,674a1878,8f4fafc5,fb1e714d,f52c0a10,55016f9f,3ca57c9e,48fca138,68464b8d,70c6b2fe) +,S(77b88613,4bcf9ab7,a1a6e0bc,82137906,d5c24607,a6d4812b,a6d1c8d9,55a5669f,2ffe0de,c5426e8c,92fc247f,a024f1e2,86668e7e,d7a24c33,2c887946,4cbfdfcf) +,S(2bf83837,74a9b9d4,7acfa6cb,6010fd44,620f51c4,e076d5b7,e798edba,21d7fb8c,5f336533,5203a820,a9f75f58,61bf2d0b,fcad07ae,9e297433,79d22b3e,a75f40f7) +,S(207b1218,9a6c2653,69f66738,b2e61d3a,c43cfedc,bd9f94fa,2b883991,ae69e350,c43b15c8,c08b4592,70c887dd,d15cbe95,d627a3e1,4a1c7afe,da2b0c69,549649c2) +,S(5ec76ba9,63dbe3e1,d054ad89,7a00c7af,f60f043,d2472f6,d3369e87,45637cbc,b66d383a,c4ec579b,8350a1b0,b2751fdb,f2ab329f,6ad63cdb,d6d46e35,944009ae) +,S(d010ddeb,3959bd8a,7a7ac178,ca573326,b578e940,b46f5808,12398722,42e13c94,2343d4e2,a380fc9f,617ed8b0,903b722b,a707c53d,a2140021,403ac617,d71fe37) +,S(49157637,c5c47498,5590bdd0,e4a8cdb9,f9bfd422,99812950,9ed25a49,7dad0da4,2564d49e,5c53c818,770c8a36,6e92532b,59fb90ef,e7ff4dba,c6baedc6,b792eefa) +,S(7e39cef2,8285f9ad,1b5ea712,78720954,f4933546,bcd7f9a,b4c7bcc7,54147a9f,6bbe4096,c4c107d1,c361befc,75916c87,6a2a0da5,dde637bf,1f125a21,5408e78c) +,S(45457311,84171f1d,aa931d3c,16b9926,59357877,84a4655c,54822c9c,1685761a,a13710ad,597e7da8,f4b12c17,9afdc5e0,5fc4f05b,e204567,9314149,9c73b421) +,S(c0bbe693,23e256fc,f69f0427,74c59091,287bc0be,82f0b5a5,6ea8f957,6d647d8b,c22981fc,6a015c20,525a0bf7,a9ba8ac6,dab6256d,d763614e,ea250c5f,fb433231) +,S(bb224b39,ff7d27f8,1ba86e92,a6897776,85074fa5,48b5515,987df332,15dca58,73bbcc60,c3adbb94,651cb73b,b311f690,6995d611,8b8238c0,4519de94,1e6bd47a) +,S(94489617,8b4bb641,9cdce312,5d863395,7ea54002,7f759e39,a8846551,ad3a0866,4a16c110,7730cd80,55fb7ddf,93c6deab,e3282da3,8a35d79b,3238e8ee,c8917935) +,S(9ae267ae,a964e8de,68398609,d6351619,4019778b,2341696c,7e44f446,dc8fac38,6d175dce,e589920,851c02cc,3fe3dfee,e9398e53,7742249c,e2745713,fee236c3) +,S(9e237d91,a6ce503a,65dafb47,a9fc5f7f,6dbcf3cb,b026ea73,68403187,d95afd67,64d491e6,df79eadc,74c198f6,fbdc481a,330d030f,851c7fc9,63974047,ddf2d12f) +,S(a5c5e0d4,920f0e3e,6973b71b,90ae2b32,2fa16960,b850eefa,1e516b4c,37252d6c,1aae183c,52ba9f14,f06c57dc,b483ba6f,740d6bfa,7ebb72e8,266895c,e6f6551a) +,S(a6d0cd83,9a198c9f,62bbefc4,b91b696b,57a4f876,6a16fac8,1131a9b1,1b36bc1,97981c96,9f758543,2c810b09,460c07f8,8520e78,3e68529d,7a1d3bbb,e0a86e85) +,S(4a75be64,16d6a87d,49e393c8,a26467b9,4b43887f,a90a25bb,139626e8,58b122b6,ace3e92a,c693f8d4,210932c3,89d4275d,75a46c6f,a9a76358,39c26288,1b8f83ba) +,S(1559a339,7f1e1195,51d8b4c0,fa53b5af,c693ab8f,843e6b00,1a6fc435,5967d7ee,8e450f28,78b2e9ea,829e965f,ae4484be,7e98f39b,a7b0ecaa,b777914b,848f324c) +,S(33565a48,44d9b25c,109eb9f2,9546fd5a,3f30d4a6,157a4e69,6029420a,21f74deb,c8141513,c4e370e2,400b8df6,208e867d,9bcacdd,d87cd975,8f91913,3ba97557) +,S(b49c8814,23db909f,c68c73ee,3995a7db,89e919f2,dc697855,357053a5,7ce26988,65878108,879801bb,ae412aff,72e83051,bb13c415,60499b94,8e0831d3,c2e11fb7) +,S(3a9635b0,b82585d2,37068f72,76291c4f,cd3d211f,80fa7256,58e28dfe,920e3e93,a1711c74,ba4e1a1f,f0a9b6d2,12c8b995,7b6c8c0f,f71da246,154f13f4,719f0713) +,S(ce6dc56e,6f5c496,71a900c1,ae531e3a,a8246877,98044497,fc543013,2572bff8,1af98ef7,3703f8a7,6fc88e9e,c9134aa8,a9e24326,314bf4d8,2a0c85ed,af291f8) +,S(a945a79f,1627e79c,9ce1cc5b,79ad02b7,c07263a9,11f8f78a,ad314049,92bea11f,f41aa315,4049b7c8,c9bef95,f3462336,ccfadf0e,16c1f129,26a5c9e3,7a443bf5) +,S(3debe447,a5f793d4,210e1607,642abdc3,c3a8d446,5a553a45,d73ede0f,20819dae,c0463782,dc5383b4,f7f81557,efddb90d,30138670,858c4197,5a47e6a5,565e339e) +,S(dba32245,a37b5636,9d7120fb,a99880a5,aa590299,601c6cff,d33238a0,395f8d2f,d589ab1f,ff442551,12aa1283,3deb9b43,947059bc,9cb1b32,4d8a29e1,1da82b2e) +,S(9c52bd5d,1fd61e1f,8e75f23f,f6e8baea,a8b7b5e1,5e780870,ea9f8dea,2b75cd56,e6d0a620,c116a7d2,2b2f797c,da7119be,556cd834,caab1007,e9a8ac02,f8945859) +,S(1ec28a0f,24e8910a,85f3c583,415afad6,dc5e10be,cc600749,8cbb40ea,b80fd383,c616ac82,bc6aa8b7,1a3cf89c,b82d7e9d,ddb95761,dd64da13,290f6bd4,a4ff907c) +,S(4fcefc4f,134d223b,994c1274,bd39655,878a35fc,2f50e405,ce11c76,1a6833c6,50c62036,fa49f62f,ab1781da,ec17a13c,4ec82c57,7993fd20,c5c56d70,145c2a54) +,S(85481ce2,90bb32a6,eb0fcfb6,9cb9fdda,580d8808,5b09611d,2d8747f6,ca657e20,ad2f9361,85aea05b,6a0d20db,9b6620ee,ee718c2b,2ae1810,42f6bf1a,2b3a2453) +,S(11aa1424,7760f682,3c11cf4f,12c013f9,7b1c9eaa,5ff0a504,334d2e41,f5daebfe,dda53fb7,b09620c8,fbcdf9b6,605710aa,f807dad5,c7ee4e9f,c7dc9c34,23302646) +,S(908c4f4a,15c58b2c,a0512eb6,b07c67d6,5b08b99c,13d22358,a52bbe24,b3823dc0,5e708db1,d4b37459,e33db06e,21a45fa6,5dd5c959,22ee7b60,7162a77,d89fc674) +,S(d192c334,65630164,2edf01aa,d974fb7d,af13ce8b,2c8975c6,ddde145c,1a2784c9,96bf7877,ced69d6a,a71f0908,86e2dc9c,f6529297,a2f8500d,d683b6a7,ebe4504b) +,S(8fa0f7a1,97138152,75f6c886,245902ef,b6e57515,c28732fe,d49b7f57,c19c6b9b,c09b428a,e54fe6d2,effdb332,4b1fc1e1,11aaf4dc,965b72c5,f97a8a97,18fdb68b) +,S(e53249d5,4d80b59,31d40779,4c550ff5,d6cfc715,13e0f419,4d7b42e0,62e74681,face5c4e,f404cf9a,275846b,11339448,d9133e1b,470489ba,64c190e0,b73735d0) +,S(9a1c943e,7f7178dc,c4453de2,d578c4e6,ab80d538,70c03001,a7a4d5d6,fabca0de,6ae6fb2a,1a7d87c0,99f6eef5,dea6a53b,a296824b,d8ab0848,b44d1216,c2c0789c) +,S(f0d4f862,dd60a74b,e06c9478,1b14b9db,af5847f0,baa00a97,72b61857,bb3d192c,6f48f413,90f9cdb9,edffe12,859b82ff,f8f7b32b,b655f3af,f28175c0,8f1efd8) +,S(1f474fc9,f6ee1699,7a7f37b5,f10f1d02,f2445e12,ae17324e,cd31d2e,c6fb8e1,cbb396e0,4b754b24,3dd587a7,d71eb673,c41b0fb6,329013a6,8ba95dff,c6d0d9c4) +,S(dd871b68,1cf78706,61bd7b4d,1ab259a2,1636cedf,39ac276d,5d36f086,fc9ad4d3,89456fa8,cce6295e,56cd18f5,9d9b83a6,4e4983ca,b55d425d,730726ef,12958dc7) +,S(5223e3b8,3809df92,8db9f4fc,d2b81408,96ed1b89,e6480fe,8a6b815b,bc7a33a5,95b640ed,128da08e,a10148d9,6f53b9ce,e53077e4,64eac3ca,1f604225,75b12182) +,S(65f26a8c,88fed562,12f11676,e2f237d,b4c500e4,a4ee0715,ae2e332d,74c48815,78df921c,545b864d,7ebe6c36,bedd987c,51ac9d73,795b3c8a,2a125d2f,2fb8cbd2) +,S(b62376f4,bd858d69,dc5d2757,b67dfdf7,1d3f770f,e96a0dce,3c61fcad,ed0e2586,c58d5af0,d669832f,4ff38f98,298e9240,c6202343,4e829b0d,145093ac,9ef023f0) +,S(a3297102,6001a6ab,ac0e84c,bfc4c829,4c607d6,c2147833,b1f726,752ddf07,b2c820e9,35502858,eea3b657,c15173fb,d1d45454,3c4fa17a,591a20d1,802d5c65) +,S(3b6e214,94773849,46056d4a,dec9e5c6,86f9873d,76accfa4,b4a377ec,84081339,d7e8ac79,e03d1cd1,7c83ad60,6a140b26,dfe67ed1,254a46e2,9c527cfd,c6afdf96) +,S(ff6aaeab,11cd4c80,ea69c3c,a10f09a4,40b3e51,abf56ee7,2c337414,f3220264,71d8a65d,7a605e01,852f0fcb,1bccfef9,147007f5,7c6b83d0,ef127b0,fe90bdf9) +,S(a0800062,64942e,b9bc70b9,f40bcc7b,52c0d43a,b4d608b4,ff65d73d,75fd4a87,de229122,80c1d66b,364fc250,5b3020dd,1482e43e,c4e67ad2,f2e49ca7,df9659b7) +,S(7c2b8b50,7e2256da,15afa166,84dcb7e7,c437b925,6c042450,6025a551,cafadd5c,747b5b36,e247939,7dd719aa,6ce55c0a,218312b7,26adf84d,eb7e3820,57a0b375) +,S(631c89e9,ee8a3192,c593ef08,baf3fc1e,d30a47e4,6a4ee9b7,e1c6cf5f,d6a0a5e5,8d49bbec,85a5245d,ecf6b084,fc65c697,190f8220,cbb84525,a344263c,ae10e2af) +,S(7ee8cbf4,a0b12cb9,d598835,bcf13fed,72e441e3,bc4b515,4182cf7b,f2818b3c,ea3b208e,70542467,a1e09248,8f34b44c,3821f0dc,169c6037,a7299ecb,25111774) +,S(69c085e5,86fad3f9,7b94d5b4,63b937be,5a95905f,eb33b25e,11ef9e8d,6b5ab3c4,5badd881,779a04f1,3a7333f2,dfcd0fb3,6167d168,b86b6a8,27640559,6e5510c2) +,S(951c09f5,563288a4,e25284a5,a694aebc,1e4b3d45,db0f0ef5,86ce87ed,237aa05f,a0c2704a,fddd2f24,462ac715,cca72894,7de034a9,2c958111,3f55c58d,83911c24) +,S(ba30b632,6ad18aae,6d87a1c4,6af749e4,6d639106,76f25f8a,673d0249,5e813e42,6c174bd6,3def5d0,2ce342b,1d0f895c,ef792f42,a97768b0,d091a92b,14f5192e) +,S(53a1d69b,77ee7d09,f9530860,31e93038,42daf062,c1ec9f19,1328b346,559fea0a,baea6eed,b33605f7,4bdac4e,749650a7,256bf215,737d1081,2c805ed5,298de5b6) +,S(23635f56,f8122da0,91d7e3a0,1125b99,a0f87e98,a717dbe1,f6d9528e,82f9b4ae,1a326517,904ad591,43f0f733,8c98f11c,2ea0fc9b,54e9eeb8,c41e469d,ef0ed297) +,S(c574946f,79574d9a,32c588bb,5cd8fee5,dc60403e,81b11fad,cafc69be,67c0eb67,d2598c1a,8568e4bd,a477d9d9,909b083d,f55a7116,9ccddf5b,666a8b61,96e2f73c) +,S(966bbcbb,4d397eb1,91ea2ecc,871fb24,b0c47469,33df7b03,124408fe,583db143,11741ab6,a38217c,e55bba9f,1c7f41cb,2e69e54a,8a78cf02,60bd3d2b,22789b8f) +,S(6ebbecdf,69e6e137,ad70cfd1,741ed404,4b3620ff,15a07f8a,769edc8f,c1aa1667,2ac87d70,baa106f3,a3490b56,a5960f64,fd80160,d0c14d64,ca1d40c5,f244c57) +,S(815f7f47,8609fee,733b7239,b272afdd,89c2f984,5da8186f,4ee8be2e,2e3e73ce,a972e06b,388be908,86c1e324,e1d2b953,18e99ef3,c0120906,f1508732,f839b930) +,S(24799358,53364be7,4675e3e3,c141e64a,febf3a04,386fa41e,f19696bc,5d3253bb,d6233c69,ec254367,673bedc7,1319641b,f9c029a7,2523f8ba,39dc375a,df245804) +,S(db32eded,dc803ff,d5a1f3e7,8437efbe,8c098fd8,e05f2aaa,c03e0daf,50ba5622,30ceea35,22ba7bbf,2ffe9c1f,bb817fb0,748efb45,65d01eda,9f9cff5c,b5afdad9) +,S(c5fb9cd8,8408cd00,33592de0,e602ad35,74e873be,4442d0bf,fe3bf837,51601689,a604a6eb,85233ccf,ef57fe7f,8a73c430,10e94b8c,4189225b,fe97637f,e7b97935) +,S(7b74932c,71dc26be,429f53eb,efc29905,bdf088a3,f2cf4bb,9828b701,11798163,e07d2133,c628a82e,4a22f58d,710b7d88,892cb999,2f921c28,3772310,c72909ff) +,S(308a025,4f659ac0,7c4e0850,738a2f16,df89ca15,fd64b35f,8f968413,b00b2819,4b4758f4,1eab6491,a8b50fc5,17f7767b,add40ea1,7b1272d4,1b1adf09,5d33c990) +,S(26a78f16,95b595f,63ff1b4c,cd52acca,ae650319,e67554b3,a77f85a3,637fa8ec,3db38db3,ca1e5dec,c73f2192,c4af6ff,66842a38,c76d62c7,c5958fcb,67f38097) +,S(bc440e62,f8524e7b,aef0af7,38e60a61,b213ab6e,713fa9c7,66d28785,891f15ec,175add64,8d472b3f,1547970c,6de2a57b,d2d3833d,2e847810,253b3712,f4d740aa) +,S(f2300d54,ebe04aeb,7a9409c4,3f2bce46,72d9937f,cf7e2a86,c4e8d55a,ef2a4e26,59e0e44b,9e090bfa,5291f436,6a3a5336,a56dbc96,65ae1aeb,e71e8c7d,e2fe77af) +,S(4d34ac85,c64d7d4d,97d40331,3fc19118,ddf31d19,18196594,d2f7a08c,db951c1a,551b6581,e6a1949a,4bbc211f,30fea215,5da8389,a69f6681,96f947e5,f7c8f7f4) +,S(53c3e6f0,fa2795a,adab1a45,a0f30f00,5f0310e,2f989d7f,d1f4504e,d03f2c04,12b382e9,b867a8c8,55461627,b7996676,880784b0,19690280,e709e91d,93048a32) +,S(259b0a65,79eced6b,2dcaa804,ff86122a,24e0d338,165a3013,9ab59f30,343f9ed3,27195af8,5217e109,33e2e1ba,57ebe333,9910c84,9b4e8f6c,af5700bf,93395635) +,S(fe07b39c,f9bd07e7,980b45c2,bd791e14,450eadeb,f6c41206,e73c101d,51093908,a8e47a5e,7a7cd98f,4f5e0afb,b5cccf03,56491271,c85fe0e4,9ae12558,721c66fe) +,S(7f38bd5a,87e2ebd4,526bfa35,5ced4f47,87c404c7,74e7f481,85d40d10,894210a1,4073ed4,cc499ca9,e7f8ff5c,f91f9c4b,782b6e6,f6225edd,d6f69fa8,b0b7fdd2) +,S(8796a424,9a251ecc,c0b3b44a,37edd05b,e34efda1,20926343,3a099e7b,8ae40a82,c02ec680,2860ecd8,f6ac62e2,845e8470,ff60cc55,10bf0179,49f95517,c1dd25d5) +,S(cadcc04b,9d4d8e5,22c153bb,def50fc,941cf94f,bb3b254,61422a4,7e6891b0,4ea1718a,53d64935,ff01f0c3,37ed2b7e,a31f9a15,edbbb60d,bceef362,8a454259) +,S(f2e614fb,346faa61,ec752d79,f9518b1f,e8f535bf,75496cca,513fa961,77f571a,1831227a,b5a35867,82b30fe4,720d2467,68f8c358,8472100e,fea76526,4581fa0) +,S(cb10686b,d361e64e,d82d6aab,5373f62d,b165d3a1,30bc7022,cb3f37ab,d61adff1,d969d37d,9c3db8d4,2c60a24f,44abdf65,b19fc6f7,56a452d6,7ef1b099,613019d2) +,S(6e903855,15042422,cc16d104,962352f0,2e86847c,f816468d,5754c70,fbc6d3cd,cc49058,80b7c15f,6f718ff0,ec2d8544,62e636c4,3e20dbdc,ee318a87,2d52d9fa) +,S(2c0a40ca,38f70b73,ef4da636,185c8260,e50643ff,9b5a83a0,fc0d410f,5526ac12,3f1eda92,8c32cf57,64d768ef,7a6afeb3,89dba8b7,e5bbe5d5,29b50410,5136ab15) +,S(1da89240,4f7ac31,136097f3,ed3055ea,d700aac5,a87ad4c5,49246211,f0ab0d0,e20f1baa,6ca3514e,ed4ceba5,9afe1875,c717597a,b7dd3c37,6d638e,287bd49b) +,S(5113fec4,172e4cf4,4eb27c6e,932e1d93,f16b3ec5,8c791b3c,e22c9bb3,634f76cb,7b129bae,b450023b,ebf81c01,bcd486a9,b494884f,b005b2e9,48eceeae,a6911760) +,S(a8d236b7,bff53a1a,fe23dd5d,63433dd0,a267e05f,31bce172,f80c5d65,c24373c9,698101e4,33e8a6cc,45b07552,7aa4ffae,3714324f,d5da0ff6,4fbc7123,773dde9a) +,S(79b2cfbc,b5a0c79b,d2ba680f,a1b594ef,4b2869da,3baba7b2,81cbf373,9d6f89b6,df45bb38,a21f4838,9e9eec46,f34eb6a9,78967e6c,5d181a92,e989e275,45756aaf) +,S(ba0eca95,4ec16133,1245f4fe,d70b725b,97393053,84fb962b,d1a0a014,cc403bdd,7bb5626d,2ee7d5fb,ad9cb623,7ba48440,26cbc27d,651811f3,92682622,2df76258) +,S(69609368,c01a1920,d3f62310,311cb7d9,cfca4659,1f53fc31,1f0af251,1f99fcc7,73ee24fd,32b08bef,f4254bf4,51614b2b,c0269e59,c6caf25b,bedb4919,76186894) +,S(c0b4d69b,d2344ab6,df9d8427,d480296f,5e0333a6,4a447302,5eac698b,e916f676,817dd44c,49b24aaf,627620c,ff7bb843,a84c7eb3,cc7e77c4,f65ba06a,14abd07a) +,S(80fd0f21,435d42a3,5ba377d4,e2401afc,dec30b21,db770277,fbab9841,3c5d9f9c,502f305a,a3350f4f,50d418d4,9b19768e,4976020d,8e158f2a,6cada628,e79953fe) +,S(7e18fb26,a881189,e3862fe0,9006e1a5,e07aa6b,39a5ef66,4f52547e,1cd7ebcb,dac9006,d99e8a47,d3c5539a,508f3f41,c649d475,4a53fc43,2dace107,1112ca84) +,S(a5b8503e,3f7c067e,628e5f5a,e65a0891,74385de9,69049aaa,26df1906,ed85af56,e9cc7458,fda4c95b,6b502498,95f4bdfa,ad9ed7d,346609ee,6549fa16,6e98dd1d) +,S(d93f866,450f7693,689bc9a4,644b52a9,3d006ced,d284332,4dac7fc0,bc6ff548,94c7526a,14b30b8c,b5a2b33f,c6508dce,fa141bbe,b6aba116,cf3cc169,ca094b08) +,S(424ec330,e4f5dff4,31ce33ed,1ef8293b,b8cdd070,12b5b18a,67b3f4c4,d766bae3,94f29933,fc5ee8a9,27295c4d,8d28b3a3,67c60d6b,13247616,a4dcab96,b58e2dd0) +,S(58805d5b,10cf81e5,b114c372,69dd5dff,cdf7e153,370a8305,bcba9d3b,7ebfe952,15e7b2cc,3ab0ab9e,a36df4bd,ce66bf72,8c45e295,d4a6c94b,e366f86a,ab39df5d) +,S(dab0c80c,a05aa70a,e626f81d,7b85c06f,b418ca69,8067b9fd,83cc6e0d,6a3949e8,4c728c4c,527f9839,498aff2b,91e8a344,aedb11cf,7ab9486c,ab3c7014,3dde8e3) +,S(55b54261,cd493b2d,7dd46f1c,78ad3983,787a37e7,ad8092d8,5cd6a55a,b870e09b,bee36be0,1168a67c,13faf147,6a614b6c,bf7b149b,4600c93e,4ec199e0,9f7fc63a) +,S(ea4f2da7,a5cec770,d986ba06,b1f18ec2,b3907a44,47fa2bef,4c9fbc10,d92afd4e,18f9565a,41583c3b,f7015986,ca7c94c7,4222b81a,9ac26eec,e7954baf,cb470072) +,S(5d835d26,54e489c3,d726f54,bc06ee3f,11390023,fb8d16,61f76b2c,29cfb78e,83091f39,9d1bfaf5,216add5f,dd4d60a3,469aaf82,ca6bf5e4,1070c03f,792dcb2e) +,S(f5efa7d1,484fe717,428e9f54,88c12db1,c775073e,27d028bf,7def8c3f,4f558774,1139d67,793faccc,70c7f48f,c892c314,988d4767,b9d6fa2a,2f2b632f,367453a4) +,S(132950c1,6f24a24f,a907cc59,704692ed,b6a5d254,79dea8d8,38cd71a2,a5d6542,b1e87d14,db8725f4,e2c2522e,c2f3f290,11d664f0,e6e85368,6c142c3,bfefd736) +,S(e479b0c5,478e49b2,c9e211c0,8e610b4c,1f1917fe,5960ba35,9af83c9b,4640d05,66ab2af5,3ffbfca,fdceb064,452c8ab4,b112ed68,8bafed44,1b66ef80,92144364) +,S(41b8288c,19cfecba,562b30e4,93a4c796,dc3adc21,f0c7a9d1,6adf4459,375edc5a,3ae93bec,6f438174,b3956d57,d9dcf29a,d673f6ca,74c96120,c22018dc,fea42398) +,S(56696d31,6d3cb87a,a3eb312e,1cd41768,2d0183f3,b91f605b,c4389d59,d86052e4,5e96c041,e495e90e,2812c09e,81d431c4,eca7274a,2204cb,a3a00a0e,650c6b21) +,S(ea36425,bc35c1f2,f0d96a49,ce4f4446,72848c5b,ec47d7df,6ac5cc30,d3968ebe,b00381cd,a5c19740,a266e63d,d59fea3b,d3d3d3eb,c899bf9b,da8090f8,1eea766b) +,S(84463c57,b01dd5c9,b98e0e4,38e221af,58c0e077,20540b7,da0b4d89,b3c36502,deb3a24f,9a0305e8,812fbaa2,f81e5fea,fd24c375,6a529c3c,c2bf4aa3,8d87b30b) +,S(13a22d5b,d23428f9,912df3be,eb82f4b,411fb39b,1604fa7d,4db63862,293c2310,99a19b77,c6912900,1047d70b,7e84ed80,a8427709,67384cbc,da11a158,6ddfb1db) +,S(de017231,52bdadcd,21b028b,4cee806b,89e98728,f91784d3,a418d7b1,22aaeb57,7ac0a9cf,15ff4a0c,f7d8a0e9,d2fe1469,1a08d526,7e3475a9,381be3bc,64771e65) +,S(1fc63549,9d462327,afc13d0c,eecddb5e,e99bb085,55076d88,7c064e8e,e40396dc,841f309,e47fb335,d2691c43,248a151b,426f1205,ccba170c,7c644615,54258a55) +,S(323e5acb,f821f131,7ff1dddc,822cba0a,b3b2380c,ea2f1b76,903c906d,83491dda,afc25ce3,b13cad24,6f6d9a2f,71e97d1e,e31bd2b5,967a5cc,7ebb1caa,adc7ee) +,S(57b1ec40,5c187317,ff9e70dd,2fd0eca8,cf2b94f0,3d7737ac,dd1468ab,61f56384,247e6f6d,7e2e70ab,a8d50794,36b1f6a0,b27865ac,791d1f08,c334013a,4ed93386) +,S(d6f5f80f,80586e87,5cd322f5,7836327e,225aceb5,6d8a83b1,6cf3bd12,4b581074,e925199,b597c7a0,a179cf34,519ca3a,f35b6d9b,24d76118,ace70f99,f1932979) +,S(2fef6c2f,eaa8c4e7,1cd31179,e0bfaa85,95d26471,fc36be60,1df75cd9,94e73c02,eedc9575,5bbca159,2271bcdf,d9ec8bc3,466e4b77,36d28abd,e6d68ff9,b9820f06) +,S(e488b041,358bf98b,11cd31a7,77a7d93d,e9cb3a61,c49fbafc,4bdabcdd,7b895964,755147d5,ba8f1d44,4ed0eeb3,d072c11d,f448c132,b9e06f4d,66f92ab3,7114a1b5) +,S(ba2591b6,35e7747f,20553589,11e7165e,618b6150,222a70ab,afa66bc9,a931cf35,3c60585,b16b1d07,7bd578f1,85e76bf6,77ff788e,a9b2caee,6c64ef9b,143ef487) +,S(ff4b12b3,cb0ec8d1,750c648d,6ed2695e,a41f8e82,58ba8b16,bf4727ba,6120ccf4,e2cbc52b,f0031efa,74c1fc8d,25466888,41c695d2,393e19e7,287bb34f,afb689ec) +,S(9e42cb1c,aaac0c62,47e4028d,501c84ba,6279b39,dd17424,73c2cd10,9bd36063,c9d0d646,381ca19d,528d2ff2,b04aaefd,9f8095a6,8811f8e3,e85b5ff1,5a5da5f) +,S(610e8f14,eb180ac5,ee435530,812941e3,ed7dad5f,c7bc7924,10f296e2,449fe005,67632a19,b1567d77,b0b5f013,77c6a05e,9261ca50,d010340a,968d8507,877fd4d4) +,S(f4c4230,443f3324,7be7bd5e,5cc12a0,27f0ff23,ede41c44,beacedd0,64789752,55d7b7c6,866f6bfd,29a410e9,8d5d5e21,98719d60,93e2bafa,697a8b5f,734d8bb8) +,S(66221ff,1d344797,1f308b89,a26e993e,c4d1c05,2c2fa436,3729c9aa,8c9dad0d,c0c78a0f,be8ba04a,932a7d6d,604f0fac,4ee01452,fef801d,36d3ca93,c4b7a965) +,S(c3ea4e8d,f8ac15b2,1dd251f9,7ebd19ca,2d91e97e,b13085fa,98294915,6aecfcf3,a7286bd0,3bc8f0bb,a3d28b6f,c513c4d0,472225b7,aab70f62,18c1a735,b31f1547) +,S(762ea616,8b3056b9,da318ef7,53ae0cb4,ff57eb15,8fff58ec,7e4fca2c,b605a49b,195d761e,9caa7603,ff1b5ab9,85d4bdb9,d128ba93,33d6cd94,f00c62f2,9452c8e1) +,S(50cbfa1c,f9a07c2b,42783077,8cae738c,3c3a0d5,617b8c6b,81914720,25712a6a,40a37fbf,97da5646,a653ec25,eeef583e,15cc1db,5bee9ebf,addf9706,cb14e689) +,S(bb8b806c,6798d001,f0d6b31d,1b17cf31,7a5422d4,3a906a79,294e5243,e22ae3ba,46b763df,b7a7a967,75b6b3ac,d21cfa37,a187ab39,99506c99,31623acb,841d4dd3) +,S(5491fa1d,88f0c9f3,6d87e074,331a9a6d,c17a5f63,b1e3326,500a5bba,1f0081d2,6c206f15,7dfb29d0,3b0e5878,57d1abb3,5f18b260,45c58da,87e8c128,7f699a83) +,S(c9d2726f,5ce823a3,ce02ee66,262d0673,f04ee272,dbc16cc0,27068850,cf472435,ff62f77e,60de3ae1,52c7f943,c3eed295,fe6a7aaf,8e6ba0df,bb60a8a2,b6081aef) +,S(a0d934b4,68151a34,cea5ff0b,d002dfb0,ec51df7d,ca5afd35,56acd53e,39515256,2f27f413,ac43711d,fc69e5af,785546f5,8e0da1d0,c9e89271,c8933b21,5998a999) +,S(342b7a8d,a3664884,1d8198dc,5e17b669,f4e602bd,5dfb28f0,95b7751e,4ce8602e,cf36fd4b,24cc36a2,806f8926,db6951a4,4c545076,70ee674e,8e2fefb7,e33f65f0) +,S(1f0993db,1084fdf2,6b2fbcfc,cf0c8a24,124c2474,92acbcb9,6221b788,18542b87,fbf92437,f6feeffa,4e04267a,c8dc57d0,c6d521b0,2631c20f,876fd9f8,b00793a8) +,S(f8f4034b,d7fcc9b4,256433c0,c2b40f9b,2f45a117,3a371707,f6ebec47,e456d9aa,cd895dbe,d97ab95c,b3c98512,c46a538f,385b9b26,5438f7f9,8caa245c,c680f54c) +,S(c80f3bbe,d409d5a8,cc0502ec,d7d95d8b,69067e61,fd2e8f7d,45f06ba6,7db89a33,dc803aae,6b936dc7,27773f6e,17c5d2d,af87a1f9,464320c5,4fd0cdd6,d7ef5c1a) +,S(b19fd3c7,8ee32a3e,dba4d6db,bb1464b8,5b3a5865,7f0c06f8,31af5b39,de2b436e,242c72a1,91f17614,8ee25c12,e0f8d4ad,52837a48,9b94b16c,27c8053,43c8e523) +,S(c88c52f8,a658160c,b10614bf,c744f668,ac46b774,94592a1b,99562a6e,e6482099,5a2f3a43,bfa6873e,7a198ad5,4fc0e3cb,2047f268,6396231a,a158a5eb,f4aa3170) +,S(b5f02d99,8f8f1c5a,8c8995b0,6879c804,1dca6f17,3666613c,efdbb82,820164e0,8e39ef2,207f5d31,2e36ce55,3569d2d7,2204a9f2,500ccff8,50bb67d0,a0802585) +,S(4d4e728b,5da0713c,18fdde5b,290d24ae,f7150d42,f9e5625e,f05bd17b,124f8302,be413caa,b7c77064,91110243,a20545f,8f9e5357,49ce98d5,cdb41384,5471bb5c) +,S(92832d03,32f7ebae,b67701ca,a0a2bfc2,b36b6403,742f4ff5,ff2ae46c,242dd226,cacf8955,92bc2fd2,90dc5b5f,b4185159,3e4a6a0,709a51f7,32e8c554,7cdc4114) +,S(2807a982,b4fc3fc0,8908fc5e,b3734a83,b2e2035d,8c6e3036,b16f9ac2,f4bba58a,ddbb9f8,3a9a6ae0,9945ebfa,9cb7e7a8,49798032,8545379,df582f93,72cea69e) +,S(e755ddd9,139cc4fc,b266477d,645b4efb,b02088da,752d10af,aee5ff8a,45df9659,fa7daf3d,605846c6,35e2534d,746873ab,cd502ee4,27e62c45,ef66401b,c816beae) +,S(93c33dc5,152a9bf8,31c3cf7e,ea833ca0,485f852d,52a255f3,55d7e67a,c1964f63,4a3a36df,13c8cde5,48feb589,dc56eb16,9a874272,c7a0becd,d40554db,cf4d8f63) +,S(70d66e2c,8f934356,d6720d9b,4809b984,6c7ab1c4,f8604990,d2e559b,a59c24c,24e8b668,4ee0062d,7bd79b3a,c96e0316,dcbffe2c,973ff6bf,e99590fa,192603e8) +,S(c165111e,fc2d7105,f6bde2aa,7f682287,2d803fa2,ec904380,27195cc,147904d2,c71184de,f408b79f,32086d4b,2b0e5d95,aed6e0e0,eb99bfb2,7e917abb,8d3a5e74) +,S(12144a63,67cc355e,e75486,357b0c79,ff4fe703,57a2f89f,3e3f7e20,ef860204,f2bb05e6,e55171c,c839fdb1,2b49ba11,dfd53af1,7a5a9602,4327f93,940b8491) +,S(3179dfa8,bd134725,3988033e,70f806de,fde9c6c7,aa4a6d43,a5cf110d,6fda7828,3133a35a,ffd1f24f,579fb314,2e72590e,475e931e,8766d462,842972cd,70e49344) +,S(51fe3e70,e5f21b21,1cae97a9,d0fa49bd,166dac17,5087ac3,a93219bf,d17ee77f,f3309396,5677c691,2a987cc1,5b3f016a,4efc22c7,6f89f562,4830f09,a9fc9bd1) +,S(2d7c98c,a224ebd2,a5167017,88018bf2,1f29444b,6eeead79,dfd9e503,7fe1680e,abae552b,bbeb09d9,dc82af6a,eea16d50,613c9314,be23eb79,d254a16c,decdc02a) +,S(c356823a,37dc335a,918a5553,bb0dfb9c,704ba647,d6cef22c,1e71bc9b,dedaa333,d8715c0c,a0ebf8be,d79ea3d0,85a70d2b,b40efecf,7dded60e,13d0577,cc235e3d) +,S(91af0d4a,56a75616,e9cb1351,4ca27ef1,b7411d9e,5991be14,c1658450,71a2b3f,f6c845a8,76657a63,ed37bd33,46ca60ef,a8fd151c,24a9e35c,5893f969,2580e26) +,S(6a32ae36,93ee1e7b,77fe8418,7266e6c5,cb41c7a7,37351cea,987a4f80,a26cbe00,2816504,dc3efca2,67e4bba2,5d4c9dbb,e8622e99,4a712503,37320925,ed5f64db) +,S(5851d327,5e18fb4d,79292e6e,2bd6bf29,b6301e08,7b418ac1,43afdf70,7d880901,1e17a9c3,dfa8c3e6,c1e9c34a,785321a6,e58d8024,c61cd02a,8b83ad41,a2366211) +,S(233a98a8,9fec3399,f74d99cd,7d5d4894,1be8274d,8f7ecfa1,f4f3693a,fb26a654,e9d5a9ee,fa5e6cbf,9ffe590,bd7db1fb,b9e08125,93f42238,65298e9,eb42d7fd) +,S(8751bf4a,9676e2f9,5036c3ea,97749d8f,f452f67,cd1259c8,4c39e8de,9cf796c9,4f883d63,bfb0a01b,e26b31b,53ed8755,49ed6c1e,4b67a160,7fb68be1,7b845711) +,S(a21126cf,7330697d,714be16f,27986c9d,cca4a0f0,3a12b6a,d54ef31e,d7a3dc23,3b0e984f,565d9825,2c523913,d2d90a26,b47973a4,8d8669f6,8dcb4c62,399b9777) +,S(8123c441,96d17ce1,c6c1a9d6,2aaecfb4,cdde74b9,317599ea,450e62f1,5639c3e4,406c585b,c9aee3ea,dedc117e,d58b1c3f,db5846cb,6eb11592,469bf958,6872b068) +,S(6f8e1a45,c18ebfce,2e2f710,efbd7ffb,4f107a32,fa6a46a4,caaf8ee2,37a22805,b36a7c4d,712315f9,a89b5ac2,8d1a5d55,5ead81,d7c43b8,8155eee2,b3ba8d3b) +,S(51db2e94,7e75c9d5,4ea07ea3,35942071,5987090d,b81c3b99,40b85684,2b0f0bcf,70967acd,454e6ce8,ad015f45,e0578940,c95dd818,70268d0b,9782a595,9a1462d4) +,S(84e0b0fd,b16e03c2,cae53675,4eb3452c,86ef07a1,ba278abc,d5aeed37,f71a3151,5a8e435b,53a4b51e,2ea659b7,1f3371ea,dfb28579,8b062eda,300664b6,d3b204ed) +,S(ced68408,c2b01401,fc039059,5140ab68,14142b7e,d69a64bb,e6ec5d85,be833367,76ce2478,28d2581f,6779f723,327fa83c,8cb10451,fc34625b,d069885,3cfad07c) +,S(8d860f70,a32921af,6376c310,bf5093e0,572e9b3,44e9204d,f5487554,c4f5484c,6dd24078,cb9f8ea0,eeaa4f4,3f3cf99c,890966c,5da8fe0f,9cd70128,88907cfa) +,S(6223ee77,4e56b9e3,da6e008a,eb3ba06a,40bafa1e,84383ff5,65f98286,d9095d37,ebcec7ec,f750cde,9ff7972d,172340c3,c324d843,f31db269,c3f35a62,c5f15f36) +,S(326943a5,5e7b7ca6,951a78dd,afd00e10,c8ca7f6f,3c01a038,ffc4fc7a,20fe2c63,b3bc5a8b,c87ba023,ee22bb4d,3f92cd81,787f2af2,4ecaebe2,67fe0a86,21c5d201) +,S(f69b5d4a,eb0b550f,851f601c,92698789,f9f94821,47a0ade8,c8a19fe0,5742731f,2a74e8bd,94469645,c8a328b4,24975dc4,93adc83e,4baddba,6c41e10,3b58e90c) +,S(f69a5a88,b8f13bef,a987194d,6b00a79b,7e576749,3d180fe0,32a1868a,26d853ba,6eb589cc,9c51900e,a6d99110,206f60dd,cbdc368f,5ae8dd48,cea05218,3415cbfa) +,S(c00ffc9d,8a57cfcf,9624a812,dd2181f7,195f459c,3b858a19,864393bb,1d1a269e,3097e10a,d6abfc0a,3fa039fe,952034e7,6bda4fc5,c5614092,b124ee3b,bf55f87a) +,S(9c021c49,d6671103,cfddcc3d,8e54848a,addfefa1,d6de5455,e5bda021,126dd183,4fa1ad18,81362f4f,f0587b52,a7a1b483,2d14127,434ffc4,c5bb90e4,fce50834) +,S(59aae0a2,923bc36a,1a5bc8cb,ea5bbbc8,b34f1504,4671a046,eb3090ed,3f4b2345,659f89e0,faa1577e,36175240,2cf1736,a18b070e,4d4b0fae,9ed08297,362cb246) +,S(7ba1ee89,479254b1,f32e9e53,517f0961,79d17d81,3ab3666a,75d4bf7a,7113f252,6530b40b,7e66a084,97168778,61cffd96,5eb71e62,e8b0ad7a,7d2851aa,15a26dd8) +,S(4b0e5728,cef356a5,c6d08616,47c268b4,c8a12d8e,89c2da7b,78e9db87,7b606719,235ec085,a1f3651,11b5f03d,7237dcf3,d70e851a,6dab8446,10e45fa,2996e70b) +,S(54285c70,315d9a43,a040bd05,70c35713,68504efb,fd103098,79067d6e,765d4499,de233654,e7c05b5e,f144d25c,6d539157,51e83ce,7f88dedb,7fbef11f,d6acadb6) +,S(ae15f764,d20e4eba,b95c3463,402a2159,fcd21daf,fa831b3c,e47bec08,9bd43da8,474c4cb8,afeba9e9,3f1d0a2d,28911298,939328e,5e364d44,68c64cf4,fec2eb78) +,S(6de8743a,68c42b81,ad069f2b,fc1482c0,204640f7,74515924,441ebd9c,917e3974,7ed602bc,16300648,86ed0369,21936ee,aa5e9764,ffc294e0,bcded12b,bcc86f55) +,S(7e4951,dfae38e6,f9869fd9,6d058847,2a38b0f8,827052f8,46195e21,44213a47,6fa2e60,a3883383,f8efebc,f39329a3,b7aec31,2958510a,dbdd5a72,728035be) +,S(1f7eb5f4,47d53537,3d29770d,5d7ed36c,a2d2a4a5,550d8bc1,849382fe,3847df55,5a351374,da5a804e,3b995d43,49560f7b,aa417dab,936860c5,baa252cd,1753f25f) +,S(dcc1272e,b31560ec,64a4b53d,24727bde,da576493,b571b5b0,aa7bb3ad,e8b2dfb6,567e08e7,bde60e6d,a614f321,a9cdba4,1b860f41,387b3854,603a8740,f93039b2) +,S(3f4e219f,5014414a,3c757cd,28120043,3cc199b,fa843c40,b344b32b,87dc7e7d,dba2099d,839e9c1e,7d7d4c0c,9444e956,168e2bc,4df1dc52,bb5b4da6,3a8283f3) +,S(dac6f264,74fee94e,dfbe9de,cb2fb88e,272ff622,4d7f8b86,3076337d,6d37acec,1bfc6855,5af0f07a,c9329ed7,5549560e,8d3e0c67,753d2673,eb6706b5,27a0de10) +,S(82ac1fb6,5a975de1,4bbd5709,9e2574d5,ebf883c7,7f38a7c6,1408dd3d,5e49b33f,a6d9dde8,b43656b7,9ab5d880,f3af2ca8,b70da7dc,251a7299,cb236b1d,75276c56) +,S(19a59ade,a0da1340,36a533b8,ff202a58,55b9182f,b19e8b79,caea80b0,9e263706,58030bb4,b17da5b,1879a67a,12c1d929,88cee2a5,d8915528,26456762,9a99f256) +,S(27e8a699,eca192b6,7a66b1be,5b290e37,1ff8e912,5afef253,134af2c6,ae709ead,54ae6059,58d036ec,959d789a,5316c70,a09db19b,179e5d4f,effbb057,abd87eeb) +,S(25e6cdbe,5d7e37ea,fe2b51f1,95cac707,a2aaa70,57fd5e78,8fc926cf,76e65466,576b2c22,cb6ba6bd,6acf0eae,79b52ee4,1fdebde,25293347,d624973f,e9b66be1) +,S(a0114d87,cc03bfbf,97e96821,2b69c53f,12910c87,e87e7a79,109f83c1,7042dbb0,869c33a4,cec89d65,633bbe60,a3cf7b70,1e5c83eb,e7c229ea,a4c279a0,4203a9f9) +,S(e8017e4e,806557e4,61ea997,f5f46e72,9fb668d1,e8faacc3,5804c35b,6d5cbad3,eca21b4c,294ed18d,d0df0dbb,771b8bd1,659c2eae,2c843f8b,bfd3aad,f44a4070) +,S(948209cc,528dc6d6,a406c996,7d7c191,19ab5142,679ac9ba,afc5098d,4d7c83e,3cc37cf5,1aecaa1d,ef14a2bd,cb6a1084,f3e60da0,9fdc4fb0,9d9f9fa5,84f14b25) +,S(10f4d6e1,c141dc53,fecfbdb0,b39e3e8a,c7f5279b,dc231fdb,55b25551,df90fca0,4f5e59b0,9c6daad5,80adde67,1583af4d,fae40d52,6017d5b2,9e798bca,6917e735) +,S(66361888,5d081bf3,9e9fc4bf,a0922dbf,dbbe8eae,451c199f,9aa844f0,71a327e4,f31b98f6,48940706,13a086df,12416779,a5c16ad3,7cf885d,5f1fdb37,1be94cce) +,S(6afc24bb,ae6cbfca,b34fd467,f23a31a4,4a0a35f6,203dd7b,a881ee5f,f340db5,7ab76f2f,6bada7ac,1e01c930,90c741fd,90c41fa6,943aa804,ff960b17,3ab28cf8) +,S(3551d572,2eff7d0b,275e310,d1466a70,2b828d8c,fec039aa,ce629aa1,2a9c23a6,b58af71e,1f9a6cce,c48d1fd1,18902a21,7f1e7f35,3ee9d794,8133d41e,2d2d61eb) +,S(e6e8cceb,f6096fcb,8f21cd9e,d428260d,c3867e0d,9c4cacc8,b8900fff,7bd4c1aa,d1b12068,f85e64f,7c9de5ca,f1490bd8,6dabf18b,4b78b5ef,531d9bd4,f64f13a8) +,S(5cd74a22,d46e7769,15b3c84a,492fad11,8790534e,dd8d9bb1,e117a6a4,78f566cf,397b2429,f978404f,ec96a4b5,28db5a,1b0cf9ef,61f2fc7d,470f0554,eed5ee08) +,S(abeeb656,151fc7a0,fdfca1ae,fef91a7,ae156db7,c433178f,be6fd700,991e8b86,e2a10216,3a8bdd0e,8254f459,b573d182,eb55f2b4,969a3f80,267b060,9f208a8c) +,S(3f9702ac,3b96bd4,ac9412cc,8f40d5c,99f4d7b9,d211bd2b,18c6f96a,ebd2f958,e077e28d,8f171626,9488fa5b,67a54800,b0d5a519,4384ca56,f9836b87,68e9821a) +,S(3c8e54a0,d094d63d,60aecab8,675349e9,f229995,587cefde,eaa1f50,cf3032ac,e77aa94a,fd252860,3bff0189,f11d5f93,fb26fe86,dec719b2,f8bbeda1,3cf38ba8) +,S(8e88168f,41689167,ead8ca79,5ef784c9,8e3cdc41,43a0ff8f,2891d476,98387bee,fb4bf21f,343fc6eb,ca6fe337,ccb7a7a6,899bb29f,d2f60480,ffb0a187,e875b00e) +,S(d5c7df6f,31001177,f2e88aa5,43276617,7a598335,cf6ad98a,e55a6d66,1b75c1ec,2edb20b5,47b7c233,23d5c4e3,295921d9,9d98854,e780f4c1,e756021d,79f1b035) +,S(262b9c58,75087b02,490291f3,963160c,c1f5a3a0,fd6a905c,25c98bb9,f7268514,c7e4ec06,b4cc77a4,ee551a5f,6c90ea97,4a0b2193,f1b828c,305a0fc1,b22e5b81) +,S(cc94ea5b,a4fdaa06,93976b76,893dbd92,f602bcce,822ff271,7a13bc2d,6b31e7b1,c81c01ad,f2ff92f,5c2cc42,f3c30091,11e6901d,36c9af9f,9b408df5,c7460932) +,S(b21abb23,4c435197,5b73471e,3b2eebe2,f537b95d,1b19361d,31ca4e63,336b0066,db02da36,73e62e9d,e96e1bc7,b79ef4ed,49449c29,7f4f0330,227dabdd,5b4c3d9e) +,S(ed130512,5af211bb,28118dc7,fc22b8e,8bc2554a,a19a8c7,16f69f11,a03df1dc,fa146b3c,2e0eab2,bba69407,9ee3b6f4,2f64dab3,9c19a1a4,256283f5,bc0886ec) +,S(42b829a,96989e82,37e48200,20eca1d9,61e487d,a9c6f9ee,60586dad,8fcd0e83,c2e164f0,29b6cab0,14fe76ad,82ee7372,78124cf6,5f251c9c,c260e239,50ec4014) +,S(15f09133,fe57a223,e2c9ad79,dadbbc7d,ec85df2c,6af39fd4,a156eb0b,1602a13c,563206ac,b190bc2f,c7b24d2e,ff376cb8,64102efa,12f7be73,84898cc8,76a12b4f) +,S(b8446387,4262c03e,312eb0cb,e562f460,8cd4f65a,75b099d0,b45e0de7,8398f5bd,da730acf,79fa0282,a3a29b99,7a0ea45,ba0896e7,598be8fb,8298aaa6,9b94640d) +,S(6a926c00,ef4c32f2,52d9f336,29fc708b,e21f571f,1f320ae8,6e6c46b8,9511fb95,9106e0c8,2eb9fa36,4a84a2e8,8eadc9aa,9113927d,99adeb61,a2ac5527,5de9a9ba) +,S(fd6cbc21,9ec03dff,8f3d00e6,9de0c64d,30ca5a04,1556d0d5,87339b0a,925d064,742ce8ed,a4b47eeb,29883606,211c453f,fc15ae40,174e1c74,656a78ee,f3a85e8e) +,S(6fd7f1b7,61116218,68e1038f,d5f341,c43b61bc,b6ec53c2,8d84b321,ac664274,f681256b,947a9492,5b8402e4,26ef8d53,20c65a29,3a7758de,6b7e3f45,a9d635d) +,S(c28c2cff,1e418550,f73fb839,58c1ca6d,4c616c3,74a67978,d4dd71c1,99902ac5,537d774,83b1ca9,50174ee,381023de,cc210f91,3a66615c,b242829e,e3285285) +,S(89458f8b,7db2cd74,346b8b74,759088,fbf81591,5fa1e97a,3f34ff90,908cb183,9b5b21fa,378f50f,dff2e276,353179a,c0a6e43b,13373940,c2e73e20,106742bd) +,S(e66ed94e,793b894,552b3893,88a657d8,55ccbb2d,f9ae0061,2cc07244,bfd434a3,8a6a17f5,da95e907,7b03192b,eba324a3,5595b6d0,660851a4,7f9e2259,2f093275) +,S(8c7e4ce,f5dca16e,620d6690,ce3b9337,8000ca08,e73eac21,deb5deae,83359160,29a44639,f9a6b8ef,990b72c1,5ca6f539,31000a2f,394b59c9,36542992,7959c505) +,S(a0d1611a,807750a2,45c68132,2f7adab1,9b81de3,809a9a82,ac038294,b732bdb,c6e35357,246fec0b,ed0c5491,24f13f9a,a01fe39d,e7630357,110a5878,90d9bf95) +,S(c1cc130c,474f5ebf,e4b4e26e,a444d5d,7542609a,2bc65a68,9c6453f7,9dcf6ab5,deaba85c,f0f7f9fa,cac2415d,9f82c62e,9caf457e,fc9149fb,55bd8f2c,32f74ea7) +,S(d6dd2a36,763b77e6,259f1305,43c8262b,784a268e,45adcd26,efbd6d54,afeabd68,2987d048,9549cdd4,c27222a1,9562b005,56dac521,1e67d052,e76266bf,fbab179e) +,S(885cf8e4,ee0498f,29a7f3b6,a2420629,4a941f56,f3d852e1,4641a604,9415c49d,b1002bf3,e34ce44d,54a18be5,3737d98b,28ad0f7f,31d9bc37,ce31279c,fc039b2e) +,S(8f0c57d0,3d85979d,5bec7346,1f0a3b7d,540fd0c3,8d8a6775,fde2ca35,ec8a0d91,86a3f4a2,cc4f934a,8b833cfb,dbb96eaf,159e00ee,caa0871b,235e4f8f,97bf542f) +,S(53456583,d2f4d9fe,1a13883b,7775b363,3993c9ce,6bca547f,d05021a2,d36cd366,92cec0bd,cd83312c,455690fd,d715e41e,c29cc70d,f5eb2e17,7f0b2caa,f3b5214b) +,S(a5ac3a28,fad5cda9,200bef2c,454b73ee,bbc853a3,e8b2ff77,111ea25e,5f3b5359,4951843f,6e23b9ba,60f326b5,d6b13f1f,f49e8b3d,b399be4e,46cb3ab5,7ef10bec) +,S(2ec53b3e,6d91835e,d236898f,8857a64c,4d898098,9af6ba60,392b774,6eb99ad,e21f4abb,cc05952,eec3fe34,f02d64c7,e7a91658,b0b11b14,118c3489,7bb2a2ee) +,S(5863f940,a45c8f5e,a2361500,84c588b8,a7f99d26,84121d59,9073d38a,69494c38,db422c38,41a2bb32,98390c98,e9f4c23c,da27c64e,a5481870,b33a2bc,866852d4) +,S(3492772e,d177b4a2,5f9eed03,7094c52b,aa72dee7,1c5b315b,70948dcf,a1975a64,c5a26844,26418929,b5bd1488,49b3241b,d0eb5243,61106911,1fc32cdb,29087562) +,S(4405762c,ba4f63b4,2401ce63,120c3599,af37ac13,d2de044d,26d830,9e664a4b,3143da5a,8319bf4d,32941d58,e9bda807,74c58380,ad8c3a33,460bfd85,36d9baa2) +,S(4894f457,1324691,8f32111,e1bd94e8,a43f717d,74e8c465,550e864b,9ae2a16e,9c89818e,6f09fdc5,b36c65f7,12f26be6,40598712,fefda799,4b200967,7de01ea) +,S(620abc9d,4efdc1a,55edc41f,29834528,ca87b333,a8678e8c,205d6817,cb7ec3cc,f524cc99,9e911d67,dd0e8bd4,3e003ec1,64af288f,3135a602,4e93856f,8110f867) +,S(d69800fb,9fe61ca8,97f77226,d42749b,1274176e,29bb85a6,226f91e1,e8c62a7b,43baaafa,e10649d3,ff2bb0cf,10c58f8a,f01fd3f4,1a06c245,a4e9c483,8bc9e3f9) +,S(87a12e5e,d002cacf,f55901c0,d374f81c,ab9da24b,80e1fa9b,25f038c9,38344721,36586bc,17aaf4d2,5d02ae3e,e9f98235,f9d605fc,1954be4a,dbbcb917,1f736d72) +,S(a0af0d5c,bfdf4fa8,98a3ea89,867721d6,3178341b,ba30f091,946c72af,bb876624,100f795b,18dd85c0,9af012b2,5d7d5d1d,5118d02d,3837fabc,ceab0b23,99f98e43) +,S(ac94b41,7becf857,1248a94b,a853f4f9,dd47284,157e0b9b,1756c4ca,fb692086,cf94bf3d,d0c7f89f,acf8f678,5508e510,faf27a33,10915d99,80b9fcd9,62f75c92) +,S(649654d2,966fb2df,b917367,e2ea4034,fe886725,3711bc40,8520d5d,579a3481,bf8ac886,a7550c40,29279fe1,c4d330d0,89935427,d6967412,66d79ec1,f1a2780a) +,S(5f7776ad,e73826a7,fd2969a6,1511141f,cbf6fb11,23c8d7e4,3ff93835,ee1860c1,9faebe0,2140468d,4564f7c8,bfe4f097,dd0ba493,8656fb43,ea9f0f8d,22089e5b) +,S(f5dfe7be,f4c42f3c,e91fea18,10402c5a,9072b001,286a7371,35a00fd5,c71e2f17,9787d33f,821a0633,ab1982a4,f9240b53,38a5644a,4d203b1c,6b5cb212,3c837b4e) +,S(d3432817,3f33fa7,e517d6f0,408bfcb4,6a882c0a,6d78feb7,44f731e7,4e1bed23,bc1e6ff7,cbdaca91,edd419f2,e80e617c,506bf8d,8acd4548,8267938b,813a281) +,S(a4420846,95528dde,2c52d5ec,cd67266e,3024865a,c6e812e5,1ef4f780,505f9d2c,4a721caa,63d62b9a,c23ac717,7a27e27d,d54e5ff8,aa204bf7,3e6b3131,3ccc31ac) +,S(b3818c70,ea29c1bf,db63ba44,1e42c842,11f9d2e,4d6b07cc,79938d3b,b294b820,1b2c711,a98418b8,15abf79,44fa75b7,db8965c3,1779d4e6,1967f009,8c005d2a) +,S(3854b55b,def18a47,7e87f62e,d7607c6d,aa2e737d,e0e5015d,de7e90e4,570d43b0,2865de79,552c68ce,4841ad3a,69376a36,9d74d55a,98c35d25,f97656a2,fa22785b) +,S(e2e805af,78bf592,6a37fac8,7429f6ad,88c45522,e58e5c9,2bd2ddcb,e893ff33,c2206185,254ef80d,fcc7365f,1dee9a3a,cdac0ebc,d0ce6a5d,4c9a6875,f07a46f6) +,S(37510b86,df2d8e60,10d40e34,77af6c24,47f2a41a,fa35ed49,224bee62,eb0b77c1,1f30b802,6a3288d9,714b33b3,7a09cf20,cb754f09,730888d2,a09869ac,1e905ff9) +,S(14b2bcad,c5272c56,8930c574,d745fac7,d190558c,121df6e0,c2c9cc1a,f9662fcf,baaf56ed,f70fc0b6,520bea13,a8794d2,d397e935,65841028,6dafdc16,96caaf3b) +,S(2984937c,e3d6a155,7a185609,9e44bfb7,28dc6d0c,bd8c628a,23a383ca,3f38082a,637c5e4,9b0943d8,e09960fd,2375770c,5d4dc4b1,3ea460df,d5ba49ab,fd6339c0) +,S(e64f46da,d9b9e7ee,3d2878b2,f604728b,8203a591,d02e7d23,721fc436,165918c0,f7ec0e4c,9f66adf9,98b8e41a,d43fe3e4,7cb9be23,6356ef3,ef5b9a23,711e1140) +,S(3f587c9f,1b88ca37,d32af584,e510609e,ae113e54,8d07fbb9,a34f6916,908f686e,37712f53,41485518,241835aa,d31c45b6,f5370c6b,238380a4,ddbd0755,17b2b49e) +,S(8218250d,b1ee7484,b8892bdd,53be130b,4b5d3db4,7c3c9e36,5a17baac,5d8654a1,f19955f2,a7f954b9,2050c815,8e801222,8e77405f,c9f0676e,76ec2e4a,f3b93bf) +,S(5ad1a4a2,55a22c56,e8d17acf,786356f1,7ffd6453,262980f7,188879be,9e1eaac5,fec5d2b7,ac26e4f2,d4d7af01,b49295c3,3a969fd5,28e3aeb3,90e86bf9,85093dc4) +,S(1c92ee58,c5226166,c313b491,5c731d34,739068b8,f0241dde,6f0d7151,243304c6,5dff29a6,1197aab4,c1ac8a25,625c4dc1,11729680,15f03488,b8a4baaa,d541bcdc) +,S(fe622f9b,fd9c4ba8,8c80c82d,d1a07bac,c1c9da11,996240cd,50b6a41,f6f8fdc3,666e59ff,e9efb9a9,b7c36539,ac948438,f1de235b,fbed8fe7,3a084076,39f6b901) +,S(b2e8301d,ee34bbc1,d95de73f,b947bbd0,325bb3a5,555738a2,8fbe4e3,601a40d,6953963d,3496413c,53ef500,6def0fda,607d9a9a,319cb93e,22d9bfd,a0c3b807) +,S(1505e140,4644537b,56da7114,5efd34d1,566ee38f,dd4b549a,34ff312d,5cb9bb96,d6440284,c1ba972b,413f8c12,7fc40001,39954fd2,5ee4993b,4dcd5e3d,a2b843a6) +,S(7a524409,67918e47,53b451e5,243c6996,c053fce6,1f492995,8d2bb84,9fd1088d,e089d973,19788a2e,853a3067,c4a98c59,4fce75cc,a9ba908f,37780e1e,567b7284) +,S(69eff8da,8efa75c2,ab052d71,e898a975,c58a074f,c46fc6b3,2b385e41,93ff5a30,30e873ca,f0e7d1d,e58713db,cf7c5c9,6c9f068f,e0e3d1d6,c3863d44,8da1cca4) +,S(64a5649f,2da4eb15,1be3fb68,b1210cca,61b32492,60225ef5,53426992,95e6d6ec,8c53c12e,8fbd7c,811d4a85,95787105,4719c5fc,368845a1,6b8babba,1d92f56f) +,S(ca23d56f,46ce3458,d95a5b24,d998188c,3ed76a22,2034b337,933c4298,8c804fdb,efcbc7c7,d0d11fd3,ef1c0ac1,38d1a2bf,d0e94a85,a0700cb3,630dcaa,426a4c43) +,S(630b2d2e,62bf28a2,ebf80f2c,2bb10cc,82014ee0,c48e15a6,4cd691db,dfe8a55,908eba92,e889f132,4da0f927,9c1bfb74,dcf16786,c9c8a964,79757a79,d4443e9e) +,S(29b5c3d2,57674ebb,1cab5fd0,56534261,5a059eae,c8002aac,c000a857,a7b7c840,e7724381,f3f1cd4d,198a06aa,33b7fb9a,d6acdd57,45f900d7,be34fd6d,4f6dd41) +,S(f4b9c47a,2454985f,e732c151,3216f7aa,f5de769,89344c0a,4b8b46fa,c15508db,9c51095a,c45d901a,75229288,fe5d49c1,1dbab43b,9a030cc7,c6d71bf8,9d097378) +,S(af0dbf55,79f3f1f,91847143,99a09fff,75c8922b,48213c42,1cb17d11,2ab7ac71,56e7f5fe,e96e464d,50cf98b2,90a04917,430bc2c6,72a411a0,842149,8fe23d66) +,S(7ddbb2fb,f5d68e,6acf574f,1fba12e8,323e06d0,b6b80cb,1b9e9368,5543a8e9,888670aa,f057a051,1738d69d,162ac2f4,9074e5ae,d28cd6a3,a30edf9e,e874d7ed) +,S(43612257,2c25dce0,4a0273a8,a83890da,3a27848b,103d5ee9,1f0bb33f,ddf131c8,62cf1a80,7bdfeaf7,7b9d90bb,ec403b7a,b4261e04,62a16c58,5c9e1435,afb177d3) +,S(8691a20c,6df3b947,e173735b,d764ce9a,4a7773b4,4b4276a,873786a8,8e5b0932,974ca0c,6644983f,e4288afa,a80c03de,fa8d9215,c148a63f,1a1d4aef,365d9e81) +,S(7376518a,528c1190,b95cfdb,ef241485,c84f34d9,3690041a,e4d8b0db,295fe87,fcd56fa1,3d5cbebc,ea197636,ad3e7bb,f9faf472,56d44489,e7cbad3b,ca9e01e) +,S(9c5e491d,838b7471,87eeff8,f44ebd70,d6087ba7,fa2b957,8302e46a,3e5113ed,3e312d47,a32d61ee,f88dcb4d,aa38b024,7327ba59,cd377798,75bcd10c,2aa13278) +,S(884a9710,9e6e95f9,9a52d8a3,7b91480,d33a95e2,4f385ecb,d9666bc7,ddad4c63,f39408bf,4f27f2f4,ef65b195,b231edc6,c50aca83,60d23ff3,32b1c3e7,149e8d6a) +,S(f99760ec,771c8f39,d349fa7d,19b0ff65,bfd2ebbb,f2d4707,eff2d646,4beca7fd,d71a5750,a9737ff1,bdd2fbbb,9674905,5508c2eb,ad22aee3,6aff09f0,1fc9d996) +,S(f2cbe279,98214502,77f79ae5,22da1671,452c8e94,27562e3e,5d78fc17,9e758e2f,8334d592,9b50b714,a50ead97,6fcd8b12,f9806edc,5da45d8a,a226e029,282ab52d) +,S(df67bf7b,861d0636,30784bd7,f9a472df,6c2db3a4,7af8d06b,ea3665,cceb76fb,e939458e,513e55b8,7e4b90d4,3f073e47,620dbdec,d7ceb425,1353f4cf,a8d20624) +,S(e3f17365,4bb1e860,d1812852,c67c0095,50f82b34,434c5326,d5864884,bf64fcb3,9f07baf6,ae6b8c28,e8a9d807,22a97f51,bae7c98b,daa09578,5a2d1fae,3f359139) +,S(1cc073f8,ac4fe62f,e311eb31,42bd357e,45ea17,a844528c,7261bfb8,24642103,52303125,ef059a48,142036a1,ab6353cf,90a021d8,30a936ee,9cc4ffc4,91f514b3) +,S(f6b037a4,9394a077,7483c0ef,326e694c,be4b01a0,3accec75,629f7224,7fce7f0,f922659,25e4434c,4054ea7d,d4bdebc4,d3801c39,be53b037,715c6ec2,88b34db3) +,S(74966556,eb8c4cbf,cd364f06,b2bac116,5b914c76,d394dbf6,b5f2f7ca,14e54207,8ef7ffba,85b9eb27,f444de36,86ce67f7,75c8eb30,5bae0c6d,1962c839,a88202df) +,S(44d3ad0a,bd1f2ad,30957e00,594f7738,18777896,9b4237cc,d61931fb,a564ff35,af69cb36,28168fbc,f194f55e,e7691ca1,88178a44,2e6bb250,84c6ea77,a3d41748) +,S(7914f911,b6956f5,cb0fa063,bff4ee00,cb67058,3dd4eeba,daa4e445,97f816a1,a61b333a,e72fef24,a47f48df,90b5384b,b25b5f8d,5530a5e5,117a4f45,43948fc6) +,S(65a31bd4,10c97121,dcf656fb,55a71c94,ac34ba43,c3219b1c,86f19f56,bda94c38,a2e19092,35d8b549,b1926524,132a5220,e26beb5,f9d87ddf,f46aae23,dd8834c7) +,S(eb092b73,5b789bfe,9a466b70,3801b511,aaa33260,407b8750,cad24563,abaafb49,ee29705,18088ea6,132314c,999ee924,5f50346f,c7a9d114,169fc20a,2e6b6a42) +,S(38574e2e,8ff7d427,3870b6ae,d859322b,deac3824,bdc1ec6c,e34d88a,8d92196f,a0a6691b,4d770ffe,e5503d61,bba954d2,f4185860,19aa60f9,303f3e89,9fbbc7d6) +,S(5e555cf3,adf0d5fb,530f87cb,6fa753bd,e2c09d9b,d703a899,f27d2a15,a051a64e,41bba138,c76d1e98,90ce88be,1053bd3d,559e7118,4b900aff,c048a494,24e1768a) +,S(4e8518ed,92b06242,b0f28b2c,e02582db,e5f908ee,fc660c63,964f5e88,95b509c9,9e4fa860,cd07c071,fea0ccdb,f1b9284e,393d9f61,45dc4ddd,5ded2dad,b8897e5d) +,S(507d72be,dc881de7,86103317,77afe208,69619a4c,f6cd3012,e04c8cfd,2029b562,2f2ec47a,963f7c86,de8497cf,fa70846f,22dad843,29643444,706487c7,d9999da6) +,S(c87295fb,299c6f1b,410f1128,a1c88eb3,4467d0b3,df7dfcd2,18fa3819,58df06f6,2977ab13,5abd0c43,ef791c18,5cdd6b59,443ad076,5f190cd4,77620227,dc38c479) +,S(5f9fcb3e,2d7f842e,22ae0d41,48d74b9b,66b8d98f,fb66e4d0,1f279be7,931731ef,523a9ed2,a911ec36,87619cd3,f7ffde07,e11a2b19,e90771b1,8ff86170,a747193) +,S(42d833f2,b9717832,1b9174ee,75127d0f,5a850a63,52452942,56fc4257,f90f74e7,fcb299b0,ed234bb5,4f0c9ad3,e9a87bd3,f4a83bd9,916c9050,6952df68,f39dbda8) +,S(cb173f92,400cf477,47ec4ce9,f9852778,6636247d,55279b52,81388daf,99b77f68,f9d99960,1e669f8a,d8283ced,317eb2bd,5aebe201,ab97a62c,25573a0,65b28e0e) +,S(a73a52d,a2ed0dad,e9943a25,8e6a1f0b,6b2b772,b010d81f,a6eb3bb1,61877d65,71f7bd19,7e9d575e,25a4c592,92061743,2cf69ecd,f33705d0,3429966d,956a2e58) +,S(209411b0,398bdbaa,7412b2b1,49162c31,da88d9c1,5dd4db67,8ab3e19,c90a8415,1392e77d,af6bcf59,3162c8b2,2e8ff0b5,4ecf8e01,4fbdc743,dda8f061,ba8a24dd) +,S(74590b3f,a03daf8d,537d9eaf,410b6c61,780f4146,44e7360f,7d6e2710,3c8a6d9,d40fb53a,1f6768ae,b4918201,54dc85bb,62c5ee68,614f1e3,b6cbbdb8,e182d9f4) +,S(cd77abfc,78148f0e,1acc919d,e3afeee4,2cb6fae7,5f68ce7e,cd31e3a5,adb54544,a46dc809,f9b1d0ee,4ba8872f,95166de3,87b08a0,b68b3622,492841d3,f4c8ee1e) +,S(ad1d5f2f,ef4890e3,5d1916e5,2dc6bac2,612d3b0a,3511ce92,94262b7e,fe2da353,6aff87fe,3778f197,ca8b1a67,9b8f89f9,69fcaaa5,4ef0a629,c0dd311e,ae83e568) +,S(de45c27f,fdb38ff3,a91c0dda,56076875,be8a1369,23ef5a55,26af8829,c9a17705,43564551,83b6ec8c,48c1daf8,d8f0cacc,4b3bd932,5d6e5adb,89368834,2ef5ee90) +,S(deba00f,aa0d172,a6bf1c71,6d280e2c,8c8e35ba,9c15f0cb,ae574940,fb78883f,2b282f66,c9499232,dbe30521,da2298c9,7a0dfc43,562ac5af,74eaac20,1d2dd708) +,S(eb95be9c,eb4d5db2,ae9071,e5dca616,dcdffd15,762dda32,5d13b576,f6532b04,c21f9054,d504aeac,79f98cda,de167ee,60e8cd52,bd44e4e9,3d66e2be,a9867741) +,S(a2849585,a2d9d78b,9da83fa0,cdf7f4b2,62c29e29,876297fe,3ad3bcc3,691acca9,a165f5d5,9ba43cba,816ddc9c,b33c4d14,e4f768e7,96ce32ed,2f711127,7bb8c720) +,S(e5a492b8,cae88b61,c72c8772,eaf6de20,40c89597,a4c4c703,85c28e29,62bdad2d,a0dd4bd,8cc5136a,184fd7e3,aa025c2f,62f85693,163e726f,cffa37e,2be168c) +,S(875a7369,7940cc11,b00b28fd,c72b31f6,19c9018d,5c261af,f1cef7e1,be71b61f,93718642,241a4e8b,22760240,2b4f4e1,fef54882,1af31e69,cd45afb3,427fe8c0) +,S(39a301a4,69836ad3,f98d7086,24b53106,fd9d9aff,c1253059,f45617d6,ad6c0c7b,a7f00229,6ff382a6,4bcb9dd1,fd9afb5,4dfdc2f2,bac962c4,8bb76603,7224a403) +,S(8bc53451,922203aa,caae8513,4deadac8,10c585c9,f9fb44bc,57113a31,9474f090,a4bc9c8e,8ea5d122,54a6cecf,aa46b791,68cf14a2,280c86ca,177871b2,abc65b8e) +,S(796eec76,37c1fc11,3ef31366,dbefc78d,ba5735a9,28505c0c,e2a22ad8,b447b1bc,11e91c1c,f9195b5c,b8948081,7d8ca5e5,f0fa07e0,19ee5566,90da195b,c5eda060) +,S(ac52e134,1b531c25,60efb2eb,1c0c79b0,d1f3cb6f,3bcc4b16,6a7f701d,7d5a60df,4415cb74,b2ca5b76,985a1386,2278f53f,871813e2,905e51a,cad23265,64efe34f) +,S(c231c57a,ed49f271,2d571e10,fea59a11,c4d427c3,4a67b024,b4713af7,d2288d69,bb4ec242,6026ce7b,56471afb,c4ed8772,dada1335,61d07981,907d278e,70ce398c) +,S(1a1b76ef,11f3d64c,5670f06e,7354fc4f,a7c17129,75ed3094,b5a6df78,c8c03034,600c7a61,188e6ea8,76b8bd21,b121ee22,ba9d50a2,d2ce0fc3,d836829d,1f829430) +,S(82b4e49f,2d9d49c0,f409ce6,13b65a5,c031c8fa,adb3ec8b,62885760,c69bc5,67b8cfb9,56b80bee,5e5ec168,6cbad5f5,cddf38ae,3bffcafe,17d242ab,896fca10) +,S(bb3201,8ebb358d,575cf58f,c08426b2,f7116d40,8cd2d779,9acf6c4f,55de461f,8f3205b3,291c8da0,b0ebab8b,ac292913,12ad3a7a,83ac3ff1,6e6f55d0,445f22bf) +,S(fab9cc75,60a02c8a,e916bfe9,b61cce9e,32d37203,8b42b58,150db6a7,cdd40a22,132d8021,8e3b6ced,e6b3060,5812823b,80c7f0ba,f369caab,8b3b7cb3,bbb477d1) +,S(9f96535a,bbd2b21a,bf41bd19,549528fe,1353724e,cfa3870b,3df3256a,661c7e47,b8acdf49,a9783748,40232e1c,9a0f6854,1547b7d6,d1d60bb5,c321a1b6,54fee431) +,S(60d4754a,2faf463d,f7b0cc2b,ff4e6495,ea9fa9a2,e2f1f4e9,d773301b,3d406daa,43d16225,6bddfb93,3588da3e,511ec648,5599ef3f,7db3a1c8,899c21ea,2fc91936) +,S(3850610e,10a40ef1,5aaf4d4d,b11ce214,7c82a449,ea965cb2,5cd9ad46,45ba44d8,c10cdca4,aa919f20,4ab148c7,2eb4e6f3,7939c70e,e134433f,5c70e45c,fc30be3f) +,S(68089586,3a26181,a6966055,1ad8d431,9d325533,70839d17,fbfed5c7,fb84fab4,a0cee277,97d2ff7f,fb7a6805,604eec37,4ef4182f,a163c53,15924f,287bd447) +,S(aee5d57d,17a9167e,9d3ff19e,8eebeb09,7675b709,e3a89ec7,38280b9f,ab9404da,154f14e4,f991644d,aad6d858,940a6126,5a8f1c1e,ef6071db,5e138081,5e2d34c9) +,S(8f3362fa,659c58a8,2376ab88,c921fe2f,2c8a5de,f36c057b,3154800f,bd493950,5f88cf3c,3fc1ccc2,2105f3c7,8ba7b8c5,525a9fa7,7cf76976,8906d0e8,caa64408) +,S(2bfce32a,9d69a14d,324d8f94,15b42f87,25f5befd,ba3cc6ac,2a5c7778,f23187a3,f7e88e0,51ea8e3b,788e18e2,95355b2a,75fc3c3c,e62f7797,d3b02681,d6a3b63c) +,S(62984e62,5d026f0a,c6c82fb0,46dbc152,a05c9a22,3f55663d,5cdd87d1,e094022,1dadce42,d6b68fcb,19439f33,2d2db167,f33861de,28cd303d,c94e3a8b,7b26964e) +,S(15502824,b02a10a1,d7b13137,4175bcb5,6b70f796,fd3d0713,42bdee98,99d8a057,b391d51b,b2b89dae,5b687e16,e2ce1351,2296130b,e86a7d21,c1d3c6b7,b20eca57) +,S(1bd98bca,c0ed80d4,f23422d,c32c5922,1164ce33,55526ea1,61e1d9fe,518c0e11,6b0afff3,b0fa5029,b4e9731a,fe772fca,c0e30c84,e6c652e0,f22dfd41,a9cf0ef1) +,S(4dc9e532,d5543e88,a59872fa,24b99968,e649977f,9ea08bdc,303ca4e,d574bf40,7c05536,d9181687,133dec90,43cae3af,42dbe034,af05a746,b6de1ef8,20276947) +,S(3e92be78,d7c7db61,1049827,42b0d213,672cc543,c27628cb,f5985c19,5685f3a0,171c3afe,c69648e,7bb7912f,fdfecc4a,78cfd246,a4fe1263,e5eeedd5,330f84e4) +,S(57b6c4f4,75bb9ce2,2086a5a,dfd5473b,73b0f6d6,278afc7a,16854e6d,32b2842b,4fb4aff6,738f05ce,31ec7934,3638a717,3806d347,c11afd82,e39d492f,b961ebb) +,S(571ac8b,835c5f4,a7457344,e8572910,309f0d3a,26b849a1,b3bca2a5,28771b59,317ae805,3aa2855d,aaec95e1,72f4005a,6ae09ce7,187590b6,41fc13c4,9bb4cf9f) +,S(534c2141,e38a7880,bf146951,7d4ceaf2,a25bf5d6,a538eb1d,4161461a,ae54c4be,59dc6548,1b056dc8,c3e98364,ce6b76f5,fbc9c501,6ff24e0c,1c7bfffd,306b03e2) +,S(7a761f86,3a224193,157d3d1f,8fff8a05,e5c13366,a7ef7604,2cd3a1ff,f9f936f1,20e86bd4,5e93b784,f433d6a5,8056c6a8,e8d1fdd9,e924fd37,bd5b16fe,fa0ece9) +,S(c1497e7a,b9373d32,4bfe813c,32aa9dae,f1351351,c86ed382,fd3d4c5,6a54f62c,9401bb9,1621a327,2c233004,d6a8093d,f812ee66,604eaa86,32085b3e,482eccf8) +,S(2dd83787,e31e7237,f49a570d,adc675bb,147b91e1,3910f22c,e41bd16f,edf3c0bc,10148349,6883687b,7ee844f6,d60ee90f,1aeb7c0e,c9f83293,be96eb2f,5cd6d46d) +,S(938f1399,18a0fe3,55ddc7ec,d6dacd34,1d9c996f,9ab4f9d6,90b435e1,fbc0a74c,30c71b30,e7a3c244,b8a576be,9e527e6e,60d1834d,17908e6f,a0771daa,92517448) +,S(e71217df,430dc65a,d188f6,861b00ac,c3214125,447d8e26,7dc5473f,9471284,8f27019f,114e542e,96eb5121,b7c3e094,f18f6287,f2cefd9e,6a5290e8,5e1dbac0) +,S(ca2ba87e,4c040efd,c06ca7fa,50cbe414,b66bb2e3,ded2bfdf,7744f81a,91b102fc,24848b82,4019bae7,4cd7604d,101c4819,6e808ecc,79db885d,bed68354,ba3f138) +,S(c267ce5b,633c7f12,1be2b297,45b4dab9,ff488b02,c8f89ba8,706948c7,77167ad7,16184a77,954c3b5,f9e330f8,e8b308de,1489ebe4,bb9ffe59,f3f545da,e7748385) +,S(1eb9af42,96d58c44,bd6fe2ff,db05e0ba,1b5f581a,af842883,5a47a050,468f8b33,f88a1128,95e53e05,4e514117,5a2c54f6,a235cb08,3494a7a,991fba4a,fd0bf1b2) +,S(ba342b95,76bea3ec,15aafca6,2f4f505f,c35bc2ca,64e2f4be,22323b77,1ee39062,91be5746,1fb662f6,cc28e73d,f0dd61e5,20cd3ceb,2d6fb0b3,39a76e5a,39114afb) +,S(f3a8c7f2,86117118,a4714895,eda7f401,dce4be87,dab4d4fe,b55068b4,c948b350,1dd2f669,31f0ec62,74e8bd53,97cb6b50,d97f9238,2603c931,8ff1c6b,18893bf0) +,S(3cc304a4,3aa02bc5,25437a89,977b8ee0,9f5f997c,56c4d317,f531d22e,4a60f55b,9ce121dc,cce749b4,78823adc,c9a613b8,aaf78f5d,c2eac8b5,d5ee6aed,592c7bae) +,S(e5be6c29,b9f12f42,1f499fb1,13e54bf4,4a577fa6,d8d0dcd9,6b509f65,1b4f3587,7755eecc,721bdd9c,c6e8c96a,d398cff3,c03e77c7,9e34dfac,1f51873b,8771d40) +,S(f933bc46,f296b780,4284de6d,5bbeed68,bae90bdc,cd731cb,b9519c05,278c7fda,b6ec0484,faa4c53a,630a8b81,e1d567dd,543a4e55,4e89ba69,d72646c5,7ab3740) +,S(e1d21ebc,297edcc2,b595976b,2f65b2a7,a6797cfa,3e5abd27,34e2a962,dd2f507e,aa31ee8f,4c80a0fb,9e52f32,c7e4a69d,fbe8d297,8dba479e,b0c9f4d0,350012fc) +,S(c3cf0aa1,8e45aa16,343c52ac,41b12278,f9899b46,e17ef9d,d7b67f75,84a1eb72,174cf510,70418a6e,f83b3db4,97102ca9,5bd99985,f2554e5f,c32cdefb,ba47e411) +,S(e6a90aff,6e1f0311,34f93967,538040e4,92120644,8e8e2106,dbba6f5c,701700f8,93895ef2,1d3513e1,19228b95,86289c26,f3efc024,1ac2c963,b394cb87,265638c8) +,S(e2b695fc,8f1856c6,131761e0,9f75a558,94a4a7a9,2837dd29,f8e8a474,7a9b9a91,b580a2e4,240724d,5c5381df,27a17d72,4d0e638d,958c0a27,fcbba34d,da5361d5) +,S(c0660a14,6db599e2,15f813a9,f267d6db,4542a696,9b08334c,6bc80558,ae518063,6a901346,6bee774a,54ec2f97,47d7a8d1,e157a13,fcde8cfc,57e48d84,374f6ee6) +,S(5c41cced,2b091fa7,df1f8e30,3d78b117,842511eb,41717b59,f776e05e,39daacb5,dc4964e4,d91fc985,af5c0f87,f0026a6e,290bb1c0,b181fe2e,195f7001,52509f40) +,S(6abe8574,49cbaffd,d0e5fdf6,450484b5,f8636170,5c8a0a59,a3612dc0,8d0d52a1,c669b059,3a5fadf6,86b9583e,7fecc9f2,c5eae967,9eb5be36,a2018337,64703bdb) +,S(560dc0ec,2d407e81,4b5034cb,8d26c8bc,7c86487c,f74e2fb9,a076b521,f68e22de,faa241bb,ee929015,b4183152,5aff5062,3a270bfd,6026d94e,c3106e3a,e66783da) +,S(f3ef40ed,8d82c02,a141b953,e8593f06,b74b244a,b85edb18,eda3e693,3c8f90a3,aeaa6d25,6db6b12c,d9a6ab5b,d6d0d854,62c0d298,5a772648,db46b614,3050d4a7) +,S(413e0fff,df030385,248b1fe2,1bebedfa,77c1cb86,d665790b,21914da4,58a4479d,6fa9db70,80ab1736,ee7d54dc,e5d1b545,dd17e3f4,45b39038,595fe180,2b34b443) +,S(ed3c5ee2,cf1cc502,37e5c654,d903083c,6fce29e,cda0f427,5a6e1ac,940b8183,fd265e79,3474e60,109cac37,a867bb81,d8ba8b8f,94b13f08,c409ad5,362492c2) +,S(b98e14a2,3f5e5d6a,a99ef39f,18e234d4,42102e72,2e330d2e,e654b328,e2f3bf49,67a60b41,8e820ef9,72ffa57b,1e383b1,35585920,20434df0,e443c318,89734499) +,S(31bb6293,28793b42,dbafdc9e,6a418c51,f0a0cf0b,6da96879,11a6f046,c146e475,1bdb131c,b14a3d85,a532f889,89112231,341a546e,c88e8a25,8bfa341a,7826512) +,S(79b2d26f,f257ac80,ca67a639,9be17ff1,8ea0c10d,739b106a,a9310754,6ba0b252,e09448ea,b102b1cd,654b6e1e,7e4754e1,c63d11c2,46b0ec5d,31df6175,6b99e850) +,S(ab8cbf8b,c3a740d3,c1bfc2e6,efbd7ac,f444795,cf2e311d,edfd5c2d,124d55da,70599847,895f335,a8bd33f1,811201b9,a860555e,8cde2a27,4c348b4c,6ab449a5) +,S(f6b7c2ba,c5468fb1,cfa0785b,f67972b5,36367ef4,d3dc9ef9,25e88085,524e6021,663be56d,c325b2e2,3753bf15,1f6b2ea0,2d6a62b3,a3d5f565,2734401c,9c661a3b) +,S(f5d2e04d,229d784,d7af5af3,ea65a35d,637b404b,c431ca72,1bec7fa4,dee33377,16c90231,e570a434,700fd8e7,cae5f8d,fbfda2e0,e234ef23,a2e82452,a0a953e9) +,S(4df218c9,4277fac3,3ca43921,e29fba57,6f183e74,fa2ea781,88b8245d,eddab853,7828e929,6c589e6b,1d80b036,2c9bb0c9,2c2a79aa,378c597e,8a64b985,d6e4d108) +,S(60e1cbc2,78d4a0bc,b7973b32,964da674,9e2b3448,24075a0d,1db93e51,ee3414c1,cec0aaa2,3db6c3e,6d6c3189,c2dca9de,8ce91791,a721ecbc,1f09c7ad,468ee8c5) +,S(1e7a9c4d,a6cf3251,559d58eb,bafd1a7f,ee686c72,8b1ad271,d9da3b15,6a9f3737,794e3bbb,cdc0df3e,b9669a10,8a32d7b7,f3fb843,388cc55e,aa893f64,ce1b960e) +,S(e8984316,5ee703c2,a413c7,2a5c8ea0,605c0b4b,58cb844c,85df83c3,b4f361b0,69fd6f89,5cac1716,f0bacdd,5a880f12,f964c2cf,1cd402ee,27ccdbcb,5188b64d) +,S(2b95eaae,6078c535,32a23225,eb9821e,c7bf864b,75187df3,2736459,f0797e4e,aa6e1922,b5102e69,77fc23b5,ac2de98c,edcbcc37,54c928b1,7c7d124d,980666fa) +,S(403c1933,59ac9027,7aed0f41,f9ebc507,8ae553a6,ec3b8a4e,4f66a841,19d221a0,edab5156,8667e7b2,c7793e17,839e46e7,85a6c7a0,8af7295,8e25b411,13829ead) +,S(fb182399,c535de2d,556ecded,54e42f29,8c0054a6,1dea2477,9df1c7c3,bb53e1b5,7bed179b,73268027,4fa6b227,d13763d8,4fa62dec,2e351ac2,d3aa59d8,8961123e) +,S(9375a9d3,ecfff9b4,b672d90,45aa4872,f61c3b8e,4cf86a38,7daf74cd,affaa521,41c7bd13,f4e491db,77a42bb8,d65ba77d,f03acc6c,cd789759,37486d08,c3f691d4) +,S(abb9554e,1b68c554,81d8bb12,5b426a4c,433cb110,79254f8a,ddebabd2,9f5be0c7,946d680c,1bee958d,32089353,41ceb7ee,5b4a8168,a6368a92,e1ab1050,5d0e76d4) +,S(56e8aa51,37b38531,1e5e1097,4df857ea,b4f7e53d,11102021,6463c212,ebcb873d,b51e1981,7eee5672,afe7f688,92ada73,abe703ac,4e19770c,97dac300,8d3b1632) +,S(ac487fb0,4b00962b,2b098cfc,4f22eb28,e5007944,d32a136e,5988dd47,d9828f5,bd305529,5f4200e4,c5e6238d,76665bc7,67ad8402,dad13d8,6c6fb316,a214a5c) +,S(1dd7562a,ce273114,660ccde4,5f41d690,11621bce,56cc49c7,2016f19f,d94e9e9f,a8e8861b,ef664d9a,c19391b6,5bb97715,ef677199,a373f255,876aa9ad,d8a93043) +,S(c198019,cda66df3,2bd528db,e3869d6,1d1d7cae,57ced846,eebcf1e2,bcceb8c3,b0a9c52,ae2b2625,7699d3b1,861474,4d66f09f,8b795d81,acd3e5de,902b247a) +,S(950f54ab,3cb421f6,95404b53,9b1f4936,6b43e61c,7bf9879d,168027bd,f58dc386,e14586c,7f005f5f,21e122bb,2a35194,d5d2fcfa,4898c279,cc296b24,9b48b2a0) +,S(5b20af8a,31b69820,a56d0df0,c7374c8a,37805449,81e0c017,83b4ff49,2bd40ed9,7e49b8a1,c5bbcb32,55991da7,99613598,cfab9d8a,82f731d0,dc2f52a1,6ec39c55) +,S(eb8a10cf,3777670f,437f55c0,2ddd8681,63da41ff,5b534c63,ffb23ac9,ecaed755,99c18d8d,df2ba9a0,d46ea92d,8b983f50,c16f14b9,86b955e,a577f332,10533df2) +,S(12977f3f,d75a9c72,81358c91,73664b40,8d8ccc98,45153ede,c62b189d,8da2b176,f24f505a,75761c5d,939ad836,17f0c6,dfd8a2f3,fea04721,9078e2b2,1aa317df) +,S(7a591539,ff4fc3ce,2e2936d3,50d753fb,131ba419,8d034c65,e76d0744,c159096f,c95d8b25,52b3920a,6341ef43,5e3e797a,446565e0,652a562,7e0674c7,ca243425) +,S(993061ac,819fde52,ae500ed7,3277ecb,fd08930f,8adff61d,f5f9c3c6,cca49640,d54444ce,748f6058,10051838,52f0073a,8a5d1477,f14111d8,b623a316,a67ad06a) +,S(cf807c40,c5664fbd,910a31bd,ed3cb7e5,2e54d1ff,ffcb4b43,7a579931,6f803051,a5d21e6,6fa9b5a8,2882b77b,ca66b6e4,163d579a,d245d089,602274f4,55ca9881) +,S(9c0119ba,461d003e,c6fb7a01,2bb32b89,ec819d97,8fd4cfec,ca1c3b2f,1f14f0bd,b41c5fa,ce1e9a54,f1605e84,61b5e6ce,c11590c0,15838059,2c511360,f4b537c4) +,S(56ea3259,5d97b7f,d7f9fe51,b525d73d,3d77d483,f8bf8460,8d874d25,aed3da3c,f764a40,2cc9278a,f1ae6369,e1723bf5,f0a15a47,992f8fe0,ae33752e,473c3058) +,S(2851e3cc,2fa6752b,e0a65326,46aa8445,71736e1,d22a01fa,ab3becd6,50460acd,ad778ace,631584df,da4730a4,20242779,81f9f829,cb18b20f,8ce727b,d62d64b7) +,S(1674559a,528fe0ad,5aef46f4,eeb4e0ba,34b8c2e8,c23d3409,5ec1e164,ef351979,afaef98e,ee2ada75,7be9675f,fee76686,d2350972,a9d1b80d,fbbc0719,efc38b21) +,S(ede70ea,37946f71,848d72fc,7a98102b,f9c167f3,219671ab,1843b5c6,8ba6d7c0,920d6108,6929e5b8,30c4fa,eb155b4c,9d324001,59d748c9,d7e74980,d54be37b) +,S(fd3b1f22,c5037c8e,93f4f9ac,27ea723b,3d3e861e,694ef349,dfe51f83,50ac9fa5,cc02effd,6df18244,fcbd177,a624ff17,b0da8fec,fd60624a,3d066be0,9c466cdd) +,S(72f037df,352a4619,729bc550,e23ad7bb,6f2d7977,7d39ae36,bbc1d45d,d6e864c2,c4bfcde1,2a5cbba3,7e047070,5937c2c9,da702040,bf49cb5,c762d60c,e8fca76b) +,S(f17a9b25,601ec8ef,e320558f,ca832789,d0d8d558,76ff7c53,6af0f84b,ca799a61,c90583c6,2a863567,b0d8c41,e47c3d8e,7e196a1,9269a409,31a1eab8,f1402837) +,S(ea9fdf49,9e201fbb,b0a26a71,1b9be2e,dd17b2d2,b96390c,4aa2dd00,83bf5c86,64322654,c8bb2a83,ab0cb743,eb907234,d8503fe7,381e17be,c17bad5c,d33b4df1) +,S(8d5d6f0a,24aa6e3e,7dff42b9,ab8b22aa,656788b1,1e18ca35,b4ca6f19,1d50de6f,d509a2b5,e9800d5e,a7d1d047,e945e693,2e5c1923,59bb0210,1b2e8956,33e0257e) +,S(25ebcc4e,84a1d22c,f0a8c980,8252d96,7dfd528a,808ea293,ffcae94,50e1fb81,3127af8e,4012c2b5,c92e428,2e455de1,681eb1b2,6e660fcb,4ee8fef,b64c6101) +,S(c55c17a1,dcd8fa41,8a3edb5e,c2da8678,4fed0840,522b24ed,4bcb85c8,cc45c20,7d583091,25261489,44b56fed,17b07906,9d156fa2,e9bdc462,eeddeebe,68f4f463) +,S(f4297f59,21a867ba,1e58b9e1,def633f1,18e058d5,a7889721,f0e4814b,7e63ecce,a39f359e,35a123eb,5fb66d81,f117858f,b0557859,aa2c388,a8298d11,43f137a9) +,S(626b0a,cbcf0e7,daf7d218,74f72be4,8d824883,4428bfee,f82ea516,c2d1b98d,74ae6867,1c27a642,53a36590,5247cbeb,77173b07,2e429de2,3ce09730,8d54ddc4) +,S(8ed35ae3,c02c5db2,acb516f3,2d3b6823,61964f2e,701889ab,26dc9512,ed40172c,aef4c71c,e241be56,63a091d9,e230463d,237e0717,78b7b6ba,a63688c7,6c694334) +,S(5b082ab8,963510de,46c1cc49,4ac6d3c6,dfa25f33,8627a00b,6b98121c,73899ed,cd8b2b84,185718a1,c4686ff0,7cad18ec,fe3d4532,9537910d,31458086,c280bb32) +,S(deaf505d,b08a282,d5274de6,43c5719d,f51827e6,2ed035f1,74279276,7ddc1158,c1067344,5e4c0d47,ad1ca85d,713a5916,1aef6960,9294d738,103b945a,e99ed1c4) +,S(eb62dcb4,d820019c,e865129a,28b98b5,be6c6e16,a80f7c76,db3a15ee,31ba7aea,e78eec22,be4a175d,68b2257f,c5adbe46,fbe31c3d,5eed4736,2304d80,ae4577a7) +,S(6c58cb64,7ef638c2,337cfedc,a9345837,597ac142,577b2230,7d231a3e,5a9173cf,563008a5,7b823427,60bbc400,5f604024,92f0bcf0,2ab2430a,5d7accc5,b62cbcd0) +,S(106d8978,775a41b1,12f07815,7c3bc5db,bb5980d9,c745806a,b5ca5ede,8b468d51,bf960349,6f7d7906,141bc4fd,b1766102,e8dfc49f,decb469f,75dbc54f,21338dab) +,S(cd6124f4,21796b6f,44c34982,8b536ef7,44bf30ec,6ca08142,e959a35e,c0385224,97ccdb9f,2896e815,19bbe9e8,ae491e61,e83417c6,6db8b6a9,bede3aca,f6608ea1) +,S(2918b2d9,b0bd83d0,b8d02815,59219c6,bd708e2f,2139ad0,1815b1ff,ae60e03c,f322596e,c56984f2,e7b2ee90,8a9bb56a,d213f84f,3088aefa,67e372f2,76e2a233) +,S(6d3fe999,acc04d13,2462f14d,680a90c9,89b747f2,3601d779,507c36ce,8c2acc7d,a6c7413c,36b6399e,58a443b4,e4137ea5,551a9fb2,c5397457,9d55b48a,5df0e30b) +,S(bd74ac79,8b320aaa,e3e51123,9354d4e9,280c99c2,809e88be,13980305,62d55d52,73477881,9b9067a0,78b40108,38ae59f4,3f6ef064,ba35209c,46a9f0dc,aaf84597) +,S(303f6cbe,866b4574,9d282217,1f571fb7,8c54dbfe,901f2f43,681ebb0c,76e5700d,b13dea58,d3dfe08,7fd043f5,8e63e565,85230d6c,273d9e3b,22145e39,afd6ea4a) +,S(3bbb0824,16a2e3bd,e328f013,154f18c1,4e840030,707057cc,f4fa0fae,ff56181a,18b214c7,823b0cb1,76375146,7a49bb8c,ddc0047f,782e3802,be12a119,ecf0f480) +,S(ef42fcbc,999a3f80,b4e7319b,1fafc2c6,49f51845,2e423c55,f57e5e1e,f8338adf,786ffec5,60464882,48641155,38aac187,ced4678a,cee2b9ea,eab6ae61,ab2061e2) +,S(afb21e4e,c095bf31,34276f4e,f1a4883a,6038c20b,a7a87ba6,6288bb1a,3bc6f77d,cda832eb,73dc0e9,fb77315f,6cc7a313,2212c7b4,1075a290,d5917033,62363bad) +,S(329c98f5,a40b81bd,7d121b90,78b50bdf,bc16c9bc,47744368,34a5208f,20d39d63,dc14f7d8,4bd2a1e7,22fdab98,1044d6e5,98515df1,7da5536c,7a95866d,8231a) +,S(6929a4df,e15e7ac8,e8a9c5a9,3544af51,aa621dc7,ca04038a,9c9cf603,8e081754,e1333f46,e4d1f151,f2b8c341,d2ff90cf,d36cf73c,6f441b4c,5c0ae272,6a25fbf3) +,S(f40fbdb4,27d2d68e,854cbae0,24ea5980,5948ca40,e3fdfcc3,3efea0a4,57e2bc24,33493d84,41c8945a,9e291b58,5e12789,34990a7f,5fec49db,ea1ff605,4bf8802f) +,S(220417f3,d9fb32c0,1439e473,d638856,9b169c38,1057b780,c9de7d12,e30dd796,4cd93672,5abc4e39,89e64ed1,af9b3d4b,4732ac76,a6c34d6b,23274573,8d765a1a) +,S(dcbe3dcf,2c0120d9,4d6336ae,6158bdf2,859cdb03,8c76ea3c,cad4ed11,13ed216,670823d9,73c74725,ce929318,c2ea650d,5feb7c33,c7831a26,821f2614,7db7d8ee) +,S(34de2319,c535a31a,87fd9b70,33c363e2,8ff754a7,9e0669a6,37230443,228ab3b8,31c65b12,cf6f4a9d,662238b0,c8ab52af,ceb96acc,35b90b2b,81667b8b,dfd9895) +,S(f0fb2bde,a5626729,720ff432,542c5e41,abf0fbc4,772aca7a,75b882ab,2b364acd,114edca0,74520c9e,2f5b8059,59c5273f,25d2e621,d2f55709,b42d187c,932b6bb8) +,S(90477ee6,a00742ef,78662c11,f3725077,dbda7b66,7ba55b55,f9bfea1a,4c5f88f4,467196ec,638d137,33971505,f291dc0b,b9d0f3f8,f284e3ab,9035273e,d9c7279) +,S(ecdef6b7,455a41ff,96cf943d,e489858c,b7abc526,e41d463e,b24a56f9,dd6eeada,1116e7da,9fe72782,e8c656b,9f677c5b,dfb3e46c,98957c30,49efd7b6,dd5d3258) +,S(58d30bd1,d8dbf5d9,885b6e7e,4f28ceb8,381415eb,3851a031,ef04b073,65e16598,9cb96ab0,546246fb,f5cc0878,7b99db0b,26c9bdac,184a0eba,728fbd26,bc880480) +,S(a7587d1b,771b3421,f56e342a,cca98e7d,82c7dc60,765a481,53379da6,fd341c10,9499ba9d,8351d194,213ba35,43d4b563,aa28bba0,9a6d8811,9b55f389,90742929) +,S(8aa99d89,9db3c7e1,c28bfc5e,18abdfbf,d9fff46c,560e4fc0,cff65ce,e18ae6b0,aacbc2e2,bcc4ae58,1e354d29,617afee6,20ced0ff,859c62b6,669cf2e0,565a9bef) +,S(45d81a7a,b4158aa4,2e45fe7f,3966d278,75f8647b,defa0c8d,a761ebef,894ef249,93a76905,d0e785f2,db52e09f,573a461f,183f672f,9f10005a,eeed6e0c,d40d31bb) +,S(de19bc8,6fddeed9,909eff4,80b0760b,66a1a245,82e33be4,55b8061b,225942f9,6eb2c1f6,f604056a,15c4e91f,789e35b6,1a787abe,aded0f30,abd2525f,19486d00) +,S(653f0e92,977b7830,fa546dec,44f05549,80f5a9f6,61f2cecb,7e360efc,41d16380,58ba9f7a,eb7aed3,40b54d7a,6f9ad0aa,ab5eaa2a,7715d8ec,48d52ce3,c3c57128) +,S(c05441fe,2ddce6b6,64270b69,83d44d5c,251efcb8,2bce4665,9388eb3d,537acce,cc82b7bd,3a049b06,98feacc8,11a1c9fa,e95181d2,50c0c62a,55a6d662,c9587d65) +,S(7a569bc6,a089fbd,294dd5d0,b10f3a7a,31b6bf39,42ee97d0,49c9259f,7adf0a7c,2399d17a,f6207b8f,20286fc4,78896af4,5e596b09,7c97f662,9bff0c03,14db53e5) +,S(1c4c7a37,4e14ce88,fd08a1b3,10025711,7d96878a,e173d29e,1ac53a57,1d6ae794,919f9b82,e827cc78,7352f0ab,99770e97,bfe1b600,40cf1034,b7c5178b,3d1104fe) +,S(fd4ef218,a09baf70,57b53f65,2ca1e2e5,8386e867,521dc998,1bd4ffdc,619c31c1,b1d2e716,64fec6d9,3cc8bf17,70ab5f10,a49a0497,ac1586b7,b8299f7a,e92354ce) +,S(f012612c,1f933373,ac30413c,1b2cfb9b,6582957e,b74e4de5,29c0267a,e7552a41,a38b2418,e7ace7bf,3a15035b,a68f82b5,aae49192,5783066e,f0f0263d,6dbc86fa) +,S(8e0d504b,c9598eac,c4bd2726,8b3ad24c,a22b7534,32eb5a31,d7e54948,d57f6f4b,50f59455,ba1ea3a,5a0cc105,a1c40c4b,72637a31,44bf9438,a1e3b52e,7b30911c) +,S(8635604b,89ec22bb,b3b4e266,3e76cb3a,976cc78e,c7db31fa,fc16a7ab,411ed197,8a11d457,6868d117,4f41c40d,4c82d27e,3960d57d,4b1309a4,531c2617,b1d90227) +,S(aba7addf,c234513b,3e861382,654959c9,984628df,72b2a896,6459b3c4,86bdbd2b,ddec8263,bfdb4c38,c9e7fd,e4693b0d,962c6e5f,a4f9eb9b,9561e81a,f04a3a3c) +,S(12aa3b40,44f699c4,8ff6c598,8a7ce56,84f3af85,8cf2ebd3,4d59ca7f,f7501895,76397e3f,3c42935b,6a42222a,525c2166,7662ea00,25decbf7,8a856391,a03956db) +,S(e01136bd,da38f328,af447a50,43a48606,a1ab5a86,b3bca98,b13a53aa,c7061098,76f3fc47,c1aedcc,bf26ec5c,4f6ad56c,fa163212,65844d01,8d2f2b94,184b64df) +,S(639cb266,f0672340,d0a789a9,41eec287,b60c380e,f2f62f96,41b67137,4b286aa6,d381e7bd,5dffffd9,50645e56,63c36d91,83210038,d70df2ca,4bbb837,e8eff508) +,S(eb12f18c,89a6d2e6,5e07d20f,f7acf3c4,b903ce68,5237aca4,5692c0e0,f6a4714e,d26860ab,e6f97745,dfb01cf,f6225c36,bf62e5dd,24088d54,a6d44384,e9eed86a) +,S(8fd06b6d,96f37c6f,8e69187c,c5ace64a,6e36b45e,37de82b4,872731cc,8781e941,e7dc3254,3b40599e,852d4e9b,e35a5438,ff68b063,3b81c8ff,c2f3298e,931e9e98) +,S(d248d914,4ca3f10b,3fb66763,713492ac,93b42781,9119683f,bf0e0f08,1bb6b241,e7a2ca15,f1867e9a,d19ffdc3,f1a20d0f,2469fa6a,e04f94be,a289d019,c405318c) +,S(ba2150dc,15884df0,34a64e20,89023947,687d1322,475dd073,b163a4bf,4eaf0740,af92a566,a320a0a4,34095dc6,f02f765f,4ebdf04e,d81e2c04,a86e6e2e,923f8c94) +,S(fb12f487,225a6843,31e39309,3133f377,a6f841a7,f6f90ccb,18ce3d39,48b56616,e3358a9,406905b7,d6bc0a33,6a89a5ba,e62136a5,4135c3db,bb32f115,4cf92b9b) +,S(bdeb3e38,7c36bb9f,c45a1d62,f7128217,20e6d0a6,55a285dc,da87af3f,f59e0644,b23fb389,3cdb280a,43275691,3c1de5fa,6da12909,c0ebece7,12c9da49,69a3cb29) +,S(32f3ecc5,925ccc13,f753ddc7,d5c0c576,e80402ab,ffc6dc77,6e8bf74d,15735007,f950add3,926bebef,9d8e3a5e,4d0ebbef,24b54dfa,ae7c12d1,32b6e973,dc67c050) +,S(94a725ed,e57e5162,817d95b0,54e2732a,3afe3a6,52ae3e46,ca9de38f,6dd9f0fd,805f6634,f8ba79b8,ecd5f46f,74b741a4,de5f9678,d29b8cba,eec73498,27671f67) +,S(22197e54,d35357fc,ad20f6cc,986216e7,f24e6dc,cfd9bb89,3e5c1ee6,9a99b3a4,b3e7edac,abb1d1c3,d375f361,1f04a927,9d2995c9,3e18e7fc,4b5dca90,a2a3fe17) +,S(a51664bc,5a1edd2a,ee8ea644,7beef61b,419e20ad,ac955847,5e1d666b,1b4dd52d,b8a95fad,e3aeac7,bcd8670c,78dd1b2b,5dcad225,277ca5bd,f24f131d,94405c39) +,S(896a11cf,f9db64a1,aef51088,baec42d0,16dd5a99,98262f71,a005cdc8,ae8cab78,7a7263ea,f64962db,bd09a278,a3958708,e61c4858,1a759726,c225471b,20899077) +,S(fff75552,46da269a,2124d03c,677f59a2,18b995aa,e69c85d4,3b29f81e,5201a757,dbbf1558,6670c191,9da69467,6e8906f3,80eb3f61,34c656b2,a4ccfc71,4b3223f5) +,S(89da8ea8,56f946d6,6e9b07f3,db5b2ca7,49a07e5f,78b59c1b,e52e46b1,3793e198,25889e02,d2013d86,6653cad2,7b3504d1,4e547343,fec74a37,a3ee71a9,646a36b3) +,S(d260dbae,6ac3e8a1,442ca7b9,8f7118c5,7d6cef72,783c0b3b,a4ad7e7c,3a8836fc,e00ee7fc,95131cd3,3a446bf4,c21b85cc,45a8e61d,2d9d6cf0,287996e2,77b7cb6b) +,S(bacf90ec,75ff002b,c1a259f0,3c9debe5,9f5f9dd5,cc0cbff9,e8fd62c,4552a619,82dedfc1,42202786,a7a12a29,22937c0c,23bddd23,4418979e,78723ff2,6a9e5e88) +,S(1ec23fa,995a22ef,53a91dec,a5b2faa9,514b5ef8,faf125ad,da61f84c,5b13a397,1568ab1c,cf75692c,b7d41c53,2dd4427b,ed7043e6,cdfe01a6,2f9bcb47,cb97435d) +,S(48225de5,eb07155b,dd86e759,9e172a3b,b96f69bc,ddcdb051,af2dc769,f4450b1b,856ce939,b81d976c,6a6c249e,c0d087cb,36e28082,ba050de5,4948d92c,6693f4aa) +,S(e9ac9963,16c1ff8e,a7d2bbf4,148c8b3b,a869d4e1,290168f,b3831d6b,3bbd164f,2b1ac664,6bc87e3a,e6914792,d0bda8b8,5cfe1107,3d0447ef,e4a65acc,6eac846d) +,S(8af31ba2,af0b68c9,4290bdf4,b4b80345,5f52ee89,f4ddbc98,1dda1000,9c1a2ec2,a37cbc1,a5efc09c,dc944f42,a66a305a,b302eb17,21ce5088,a7deb46b,5223f0b6) +,S(1d211de7,d75d4389,4cdac235,9b0b9e40,6b71b8a9,8c0583a5,7d7a0056,b3e88779,3ae4bfde,20f83eae,96982e96,62d65443,4359b2bb,df249a85,c7c83b95,56d7679f) +,S(be6beeec,18aa8d77,20100975,3dc7d745,c6d49f9b,ea64ebfe,b8fdafc0,92a192ac,c9e14aa2,4bce41e0,f444030f,ddbf035d,e808bc06,63a70593,454ba287,4ebe50cf) +,S(b126dd86,555491a8,e2ab601b,2f133960,d86a7f9e,bcd2c88a,cbd8764f,1afee3b2,d22ae79f,fbc60439,baaf2c2e,418edb77,70837ebc,a909322d,b5580c30,27c20821) +,S(857b9c62,6350cec4,f928d456,7d30cad8,6f1cfad,142b338d,74a137ec,61212791,9d3dc070,f610ee55,cfb9cfaa,4bffda56,52f7fd18,7f354634,ed4f2dc,d27f9ca9) +,S(bbb7d30,3e242e87,2e94e3b4,27197ebe,5252c363,43ccd8ca,940202ff,fe5775ac,f2b5b210,a40d1fe,140f8638,3a5b0f9c,96885d5,d9857a3d,252523b8,d59d33f5) +,S(3e90a10c,a61bd12a,fe9caabd,e52dafbe,8bcd332c,e0ff8bd,7718b685,89e26447,3a4d342d,fec7d557,7cc52bf9,d7c60537,50150146,8a05baae,7b562dbe,b626a952) +,S(dc1f2531,d5e0d304,66b963fd,7d09524f,c66e6bbb,3855b6d3,141db170,9af05fa4,f1644b11,e8291f92,4884d3ea,cf89d857,fc98c3fc,e49fef96,7986e8e9,d67c9b0e) +,S(2b4714d1,fd0aa7ab,6c103ae9,19493efe,4a503d5f,beba56dd,93a8c9db,485c1dad,d65bb3c,47efcc3f,7484b6c0,9f51605,30542a81,d1192ac7,5d506c43,16f41220) +,S(c9ffd7fa,3b14fce7,c2946111,e940ab3c,8199b7e5,40bface2,5d8e3b0d,d1a15176,3b40f328,a4539bd0,a0b71e5d,91a881c8,87b31e11,453d9f5,82066f44,ead8d5a5) +,S(e019b0e7,6b4221c0,e45d387c,6ee41bdd,ed5e219e,a7069b73,d92b6339,2657c39e,792691b8,4c8748a,cf10475a,955aaf5a,77328c6,f03c2e9,bd1b20be,f363f368) +,S(51e07e1f,e8dc56df,f6394d1d,7f2887a6,9e7959bc,ca10af77,cd54064e,6268929d,c09b86d6,6837e473,574bdf95,f0b99851,b97a821f,6dc622d0,d9c6cfbf,18db5ceb) +,S(c5c19c69,9a9b6908,4625d3b9,5c6598cc,d1bba7a0,6d4e2f91,88f1b77b,4aab720c,af066357,107d856a,51c699a0,259774b3,352f8c12,988201c3,c71bfe3,c5d8280c) +,S(7b51ad32,ec4a6df5,f9c952e1,fcabd8dc,7661ec53,2631331e,5205d231,533f8d77,e1346672,ebbb97d8,569a12ae,fea65246,e1902f0a,9cd91894,a4b8aaad,5a02ad35) +,S(be3059dc,3789e16f,5ca8f6e2,c469f834,bcd3fa73,5d84377f,907cadf9,e7eb895a,5a6fa277,ee5d317e,81819fb1,11f40778,ab437567,48eed726,238ab5c7,f4d6ef06) +,S(cf75a66e,810f3284,52e09fa3,15451289,e1cba33a,ff1013e,4702ff1b,92b6f587,a0658bc5,8c894702,ec5c366c,5a6b18fd,86269d5a,8117dee3,601dc40f,cc93f17b) +,S(6356c70,7d5228e5,253f09b7,7020681a,fa64dfd6,3cabd703,91d7f892,d9822737,3241ba88,cef88e8f,98d19fda,717904fc,737a9c77,45838ba3,97141964,946ac7b5) +,S(90d7f09f,7b8a1232,236b4459,b031b0ff,d5e8c903,36a35f04,94a89615,3baf8554,4a612ce4,b18b7ae0,f3c557e,c4ab51bd,7c32f26b,24d0ca7e,accc748b,3a2db676) +,S(170265f9,5a3f936f,57a39e1f,a748a3cc,902b1b20,4306c49e,f4485b15,555f80af,d2f813a4,b329da9c,68104a55,301eb7cd,3ff6dfe1,c4aab9d9,d2fb03c9,e7ae2bee) +,S(2d6316de,37598fe8,ed6e3e52,ac47d442,636a6553,64274692,5a468f08,54377eea,e064f40,7f0d3b32,74a61d82,d7b75006,6fab6447,e66f2d4b,20439303,cdb3a107) +,S(8c89678e,73f3085a,1a766e14,f566625a,cc29dda6,3eb7bc9,ed1195b8,5fa2092b,12b42d8e,91c9640,b8b2509a,157229bc,a66d28b8,157742fb,a12d7405,eec110f5) +,S(ddeb928,de6424c,f9ea76f0,abc208f1,16731596,29fdb2c5,c8e6ed28,38ab6b11,b1395663,9ac1f06d,74aef36b,61916872,7709eaff,d8b76905,ca404459,325839b6) +,S(485e8e44,35c46bd1,d0c2a4db,19b958fd,4a87511a,ad4aae65,eec4f5ba,6cbb38ee,e621d1d8,736d6df5,df2db5d2,36887c27,a93733b8,d3232dc0,95d0b2b6,d0be516a) +,S(bc527a44,2547aca1,91fd98fb,84ce7b3b,6210378c,46f7bd46,bfd375a8,1b61206f,ff7c1cfb,d3c21616,85d6f405,e6f19e8b,6785e6be,ce374189,4efc149b,b3031707) +,S(9911194a,7a75269d,2fda7214,21e4e2e,3666ad12,3e76004,b5ff9afe,9ea89ca8,b1f350ab,c87d942f,1aea75fe,6c144ea2,fc5cc040,5c38af56,9ee45413,17c7bd4) +,S(93226535,e27a96af,7953597,4db1d4d5,4a65d3e9,331fc3df,7f028fa3,288c3189,98007e66,60fc6673,5e8e864,afc62171,49168a86,27d35eea,2d02d90f,e6f15331) +,S(752d352b,2459fb97,d5a0c46c,3fef99ed,50ebfe74,ceb1c881,b2fa518f,3aa59e72,c6e99a8a,2544731e,d932a164,ca0def49,dbfe4f29,f8894133,ff5eed02,66c4fbcc) +,S(ab37b416,dd06a595,ae6fe33d,717c4ff1,fd1de2ad,6c58e2b3,660e872e,aac7aeb5,182f07fd,61ba43fd,e11ad355,d7027fef,714c9b9c,364c0b72,1838ef7c,f85d9470) +,S(d2fa3ff2,b1cd8909,52a0d380,d43233f4,1eef04da,aeac6ceb,46dd8e6e,572d170a,85f3c854,3eea0e64,b8a9eabf,18057700,6c3a6f70,a790cce6,24a3f6f9,5752c520) +,S(e256c5b7,99ae8dd7,1daf5a7f,3dd94f94,e040d98,291a2d6e,9b398889,addff0c,b4375e5c,82517974,b515ae28,54c83443,e8bf9391,cb975013,727e3bc5,1473b133) +,S(30056648,afaac00,c1d77bd7,e7b5235a,fea2bc8c,58b34a6b,83e630d2,3036db6c,16ca5c30,6882fd6e,f7d82f93,b25ad01c,eb3e9e69,b8280f0e,e3aef2e2,ec204600) +,S(8602fe69,d4b1f32b,e8422928,200c5b5,816f08a1,759faafb,29861e07,c5dccef7,59a5ca0,35490ebe,66409e2a,283f4c9d,f6e0a7c7,9dd1ec82,f31f7e4e,4f23ead0) +,S(53bb9f5,ed205516,36ab170,7afc75b5,6ab3a75a,3d360c15,3b0b74c2,d7d9d64c,77c6c1ec,c7a53dc3,8c6540d4,461757c8,b5f7b66,654fd754,fbfa8f5a,a5318cbf) +,S(badc41b2,86982d76,e5374b3,dcf023e,dbc1e187,70cd0b2e,2916d436,108a4328,b1694651,a69dfad,924fdf5d,526c25cd,e732078f,31128556,3d42ebb1,3329e2fb) +,S(15b43026,f5134b3f,1ad441c9,793b9e57,a318d455,fd6f10df,e4b0bb91,5d36600,43568550,60fb010a,6d5123e8,b446a1e7,cfddb6b4,6e4fb18f,245a4be8,f9975a1a) +,S(fcc64bd,c9df17,4d4e8e18,cad6116,a48780e2,a180f7c7,57f532da,9fdf37e7,ede37062,35eca482,b935410b,6d495f53,12b133cc,238eeb6d,e8e5f593,65601951) +,S(f394fa79,254fbdc2,7a1b31df,1f868c48,9b48b6d5,1afab542,2da5b1f5,6f3edd2,f56d3d7d,e7f8d9c5,fd45d6e2,cc2af300,fdce3293,9be5b975,9d81cead,e2000e7d) +,S(3c7c8c54,6b853a5f,97f92932,5558793a,e1debf3,3f680d5,6a79bdef,d4608d91,575771ed,f26feb38,a728354a,6c4023ce,4b019d65,3f7adfee,3c83cf58,9f2fe4a) +,S(51d61258,43b8d621,6c0880d,f04f34d,9acbb422,d8194a98,dcbf222d,cf27fc4e,2d0bbd0e,ae299afb,93980894,bfbdbdf8,6edf9509,ea408286,ef602cf0,ce3b33a2) +,S(14b17f35,ac7b5914,e08babb5,5aa37cb4,26d3bd34,f2c1e4f,45acb493,8ef51a65,a9090e25,cd8273c3,15d1ac6a,15eab027,7981f6bd,a85fb082,2b24cc88,2918fbc1) +,S(59ceb93d,d78ff6a5,f45c5fcc,7c1ecd72,43f2d8af,e4ba8a3f,fb03053a,586387dc,28f4d0e6,38ac1fc1,98aa3548,56f4f19b,479ff825,5d150f29,871630ae,f82f3777) +,S(273bc0a7,eb63a0df,eea8d7ac,b24a5200,a7086078,388db5bb,37a0a6f6,acf24656,a971405,a287160e,22909b67,357fb63d,10af5ece,f725b1ac,17c7fc73,759936f3) +,S(c9b5b690,3a45e529,3a298219,cca93e0,52a2719c,25cf2f50,c4ff7f04,5f346475,7db09fca,ff1aeae2,dad001ff,1fca6166,a607eaff,bdfc327b,9b63e2a8,e97f665d) +,S(90044bea,c8459e34,edf7c40d,2a101b45,66728d1,cf0055ee,c8ea07ab,e39307f0,19763d08,77d4a896,ca9ecbc0,56d405b,5a6ebcce,1ff6ac26,593be19f,63caf6cf) +,S(6e0898bf,bf6baaef,d085f41,da7e6b93,6b6c9a88,3728dc7,8ce7d71b,fd597b2e,4769146,91587abc,c2f21e05,4542280a,f7260a72,e822edca,1e63c089,3bea3dd9) +,S(e94563b6,e0156145,ca2ef19f,58de9727,7b806969,a249629a,4f024b99,8a023792,c8949547,a4d25901,f3980cf5,333f65f5,8e1797d8,b42ccb0b,dc550e6d,5909927f) +,S(3cd027e4,173c2799,54d06c3c,ec05c0d,161a3b73,348db0d2,8c03d097,8921ad64,f0d1a3e8,ebc3387a,ee88189e,c1fb3f6d,5e73e895,7b7372d9,32b00144,248271ba) +,S(4c96f51,2b4f0758,38335d47,db599db9,a2dfe1d1,6783960c,dedda119,693d5686,4e840262,66897288,9bd54c15,219ae871,e6426b67,afa949c5,e1226bbe,1204dfe1) +,S(8b03ca2e,458873,963ba6b,c9dcd14b,59fb1190,3f2330cb,22997bb4,19002fbd,2b29df15,c6be49d8,27981ffe,aae26930,7a461f84,8285f561,4f910508,eb865781) +,S(f4217bd2,32229dbf,39066a17,c2524838,38098362,f0891b69,275dede1,f8e64f0d,7581350a,957f480c,89246800,86c2803e,99ff5037,938e3e19,22e3f9a6,7098dd96) +,S(247274b3,d5095d63,132673ca,dbf0e418,898468d3,9a30c538,a46a2719,42846bf8,4265a1b7,7d1dbc68,956f2441,9c4d2b70,9e71f6e4,6e24e336,a978285c,22a84f11) +,S(19c25b9b,97f40ddb,23d62bd4,a298ce7d,befdf39d,327aca47,61815c0a,28d4af9a,a9b5d705,94cf4c7e,b7e947e2,101b18bd,fb9f2f20,fc3bf89d,f5a63d7f,61d3b3ce) +,S(fb69718c,baf0c5f8,e20ca98c,2fdb18f5,59df27e5,c2a064fd,ffb2785a,73bf27d6,b612c590,4e0b1c54,7beb4e07,82ad2716,84eb895a,862b59b5,cf6476b8,af52107) +,S(9fe6e793,ed1aed77,d8381352,84890e3c,f817ca60,37ee80df,6646a3ce,9c316a6b,17214a01,99370a88,41717ae5,41d35a4,96f8f041,e9b3fe88,4188f6f4,e30b0657) +,S(c7f7ab4a,394f17c8,47010e9d,f1764fae,6159b140,578f70c9,fe50703b,aaba62cc,9673f262,c875953b,90558dec,8ddd04a2,6d7d3ac1,672e3d10,c1a3c656,b0318c19) +,S(cc2e30bc,2d63d4d2,bd0f5bca,8faac99e,a6add123,82d014c1,d7bf8285,7ede2297,cb87a21c,f1efe789,fe72ca0a,b6acc5be,63e6973,2ca899e6,fb9e05e7,72d4d8ff) +,S(6fe7070d,a78205ea,1f12661b,4538d0fb,60b4bb4,9c1709c9,e53de22e,c3c25d6b,2f6b773d,492a82f7,f9609cbe,e1af3c9b,2940a12f,1e615c1a,801c02b2,19e6b8cb) +,S(1affe9da,ab5da7f7,9b331e9f,91eb7e3a,f4dad51,2317ca45,3ae13528,66013d8f,2706d2aa,d3139097,73a0febc,191c7a0a,df2ef168,c65e759d,7c034bac,49c8a92b) +,S(13566dd2,d0cdb199,20a1f9c,aa1ab581,c3ddf2ad,125c13cf,efe199d5,bc338231,b403ab04,67df46b,2efa5b8a,4cfa8bd,97399c87,12ffc55e,cae8de52,d4f6f28c) +,S(135fae69,9a969720,b1c0d899,790afa99,83074584,da3ee8dc,1e011336,dbc3636e,b4260b88,2dc79423,8cd0fbe6,5242147b,c96690da,c391e3cf,d2c53ecd,2ae9fc60) +,S(1b05d97,744364a0,5432de4a,7d840834,3ffe211f,a543bccf,71a4b210,3bb0489,d61c9d21,671b2481,a4ca0c36,7d4ea919,ae1b331f,a8aedb87,cc6b6c98,85616a9a) +,S(2877f026,83a5cb48,7014da9d,419c8b9c,920f0940,718e2d06,d7252de5,5b46a84d,849f9fb2,88d3fdee,de734aaa,3592ef01,483e02d3,62a5e0ca,2ead6c0b,42628038) +,S(8a7024ce,6348d2fd,84be71ab,b363bdb8,86ec6a2d,29d9cd83,1934270a,27370b78,8f520972,9e4e1325,363a68f4,ad53737b,688c63dd,1cec6cfc,bf9da51a,98b29c0) +,S(5ac77dfb,2309c061,8f68b320,bb6eb76e,4b0f0792,b8235fc1,ed768c57,44fabb1d,fab11baa,beafeab4,43a14a82,f8d70228,57752732,7b016b56,32b924c9,ccbb1db6) +,S(aee4edc,93413d53,45e0df68,99fc2193,be318a8b,f279f0e0,56c0ac42,a60759d2,b6a87499,1dc68ba8,503beb0b,8a6c09df,cb9efb6b,a44aed6a,3cd7befb,506119b9) +,S(b51d3e77,741d0d44,3a67b5d5,67b45aac,2008c25b,5196c71d,c9f910e7,b76dd2d1,431c7ea3,cf4f577f,950d22e2,74b7cfdf,2c2934af,ad0215f9,459a802d,ddee4c21) +,S(803a2ff,c59c2a94,65d8935d,93d47653,86e5beb9,c8e702a,12d7b565,98a09841,d5e02ccc,5d8ccf6e,29a7fb76,5a257dc9,c902c900,a4fe16d1,53e9187e,290efbeb) +,S(22c17725,44eef514,5636a398,23e874df,8c58bc6b,6935598a,440ae9aa,5b738075,a67f431c,688d4426,c519be32,9b1dd50e,2c64648,4d3612f,35d52089,c98dbcfd) +,S(ed67feaa,5aab50a9,ff71c434,855bafb0,5191f036,c691c8c5,563395,d2053b86,b2d13cb6,4ea821df,f8829ee1,57cb5fca,81dcce75,d091719c,73cc7785,c443f0a8) +,S(f8cc5ae2,3b670b9,3c27ab8c,7d8055c8,4654b427,f9e6b733,b083fecc,c7c5d375,7dc996,7bc3a2f2,f516aab3,682f8d6a,32b84173,ecc742d5,c8a15c5c,72eb261b) +,S(838891a1,fa46e300,a20fa3d0,cba3fe09,3326ffd7,bcdd7c73,b6e96da,5d591332,d46717e2,c5fa3d52,a268aa9e,a85922e4,547ea986,3a37b1ae,b77d75b0,d48a8fea) +,S(92caeb7f,400d043,6d36656c,8ffd5d45,6097cb51,cf512c00,1fe613e,8dcd5544,2096bc03,dfd088ca,25cb9aef,29b24b99,2b2aa00b,e3429cad,c0976a3f,162e47e2) +,S(2e6226d,574b687c,20dcd4a9,683697f8,afce56a3,1e11cdef,6f0ba6f0,dceb89b4,d9c4d7a7,a7aa5f8b,f30f0930,d6c3bbdd,b1963b1d,8cf24796,141bddb1,ba8ffcf7) +,S(33aab3f4,17d936de,b8c1f07a,9fd5024f,802fa5b3,a593a6b0,9fd42871,75f4ee7d,4c13dc95,7311dfaf,932eb4cc,68c82550,3b185530,13008dc6,878dd092,50edca9c) +,S(ed74a882,a947da53,fd62a242,b67dcd04,50896a43,e9882c84,ada77f47,691e5fc4,454a18f,a8fc6d8d,e673410b,213875ee,35190221,9f7cf88e,f363be08,571030d8) +,S(b5d3f084,56db930a,7d8b4728,2caaf807,be7bca65,bddf9738,67a56224,39723ebd,a89e0271,28d5872a,f4d6b4d7,c5a7efa3,b0339a32,89a12918,2077c106,b61e1a4a) +,S(5e40e90c,1a01e008,d5fde186,283919ef,eb859921,c3ec07ca,e34eedc2,b0f07967,e4be6ef4,26eb3c94,70ee3084,f431c68d,82b2df48,5286082,82cc1b2,afe77900) +,S(2f4b14a2,674a743a,4aefd302,7fb214f1,a7678336,3c9e7c8f,8ebee72d,c5f29830,11b13461,b6578710,677bc733,3d28e773,c78dec4b,27ca1aac,a17121b0,de9868e6) +,S(71909162,35890bbe,6a8f7a99,5b1cc3c,a68b3ff9,7551d09,59a97835,5b7167c7,f9aa3992,124fa99f,167f1351,865a1456,8ed9eb92,c7cb2050,5082d228,4b1532de) +,S(8df50d7d,d3cf99c7,b0269ae5,e70546dd,bed3f05e,260bd834,575d56e,e65f7f0,835405bf,3c84c4ba,5e253fef,f306bd1c,c1240ef,8c03da98,d7c092db,3a2606ca) +,S(5e0f6a7c,e9bc1e0b,852841ad,52045b02,b4fd545b,f2106c82,17a76bcb,441173ee,ad70f065,4d75c88f,e6654d56,fe65c57b,857d91e8,ad6abff,148f3577,7afa2aa7) +,S(27880a25,21a78fca,cddd0b78,5a3da1f4,2e832641,8f804a2a,42fe3c0e,f69b43b7,ac9f930,12402aad,c55c12bd,e450700,b0208d85,a6784586,d04f1c93,6df8624a) +,S(6578c4a0,dc25e068,97482b12,3f38cef3,39cfd6b2,ec06c89f,6da11449,de5e43a5,8a249d9a,41e6c1a5,a776ddfd,ea93ba78,15f2e908,b8b854c2,3a7e3ff2,cb99bf70) +,S(c66e890a,71beeba3,301bbbef,2bcf4cdd,def8e634,dcf476f4,6907a280,df3dd33e,f3510cb8,9c46f493,c4a70976,34a9c502,11532929,ddc883ab,d43bd360,1b028dff) +,S(393f0dcd,24b47380,81197794,58bf5e48,b2f5479c,8efd8925,a1f78bef,6bd16665,9898d880,e24f840f,f1b4662d,3d444c29,6527cfe8,2b6f1b4f,f0e5928c,bf09de74) +,S(337fc469,43942ce4,f1601877,874366fc,a8726f4a,65a9bb26,c6c2c013,856a3adb,95df242b,2d4446de,b2b792a4,d36ceb2c,add17365,380d78c6,3b23b101,1b3be914) +,S(b7edfbe5,118cfeb1,4c1aa23b,48154dbf,5e9d1057,a2758516,7fb8e030,a457874,bc1e5723,dabdfd76,c98f408d,1d8c13e5,7dee979e,83b3d610,981b9718,f1e61eee) +,S(4dffac46,6a507b9c,2e2ee5b6,ca81d8e4,d4e8aae6,3d73395b,dd29b024,51436e5b,af227fa8,ad0bfc48,eb469596,b9b2759b,f41eb169,1fb8f896,1451489,ebe0d5d7) +,S(553ab99,3448879,b42c72e2,97d597a6,24416a45,f5b35720,c93a303b,c6dd0e88,5ba2d3fb,222a03dd,c5302b25,ffce74cd,58de90a1,c3e41928,19717c28,52ad1b39) +,S(b351ad4e,4c7df853,8f6f71d4,e95554ca,3a07932e,7a812309,b0b0c807,f98cea2a,5ba5141d,b3d4ff44,7efe06c9,c624d447,1aa3c3f3,47af74af,49929de8,d8558c70) +,S(844b9bc0,ae73df50,e5b80fe2,fb24a35c,dbc91c61,2753c2e8,e3765e1e,47d44263,80eeb80c,414c3a08,a42d89b8,87883d48,84b38bd1,40f7bbee,e977ff5b,c4c57b90) +,S(f64b4ef6,8fc11491,38ed4ef8,ab2d6336,3d494b37,b56649d1,5d15777a,8cd315b9,c6f83010,5dcfc707,f435cfa0,b6bc32f3,8ce8afb6,28bf9139,dfc47279,cafa56a5) +,S(969ceb7a,441f8be1,f16c94bd,6065db17,942f88dd,e5506742,7cd30dee,cf9ba5c7,a08ae62c,6e6758f9,724baa45,d35f3e03,9f636265,d841b61a,f1b31d20,bc8d65f8) +,S(e465041b,78c33311,d4397b30,9a8ba4de,6b312d10,ec2ca906,583162ca,1c599102,3f21d5d4,416f1954,7af1ba97,6687dea3,520ac304,43c180ad,3892d46b,86618f55) +,S(87b2e548,b019224f,b1021a06,522073dd,46892847,308fffe9,910ffc28,5b702bd0,6e641d35,9e7ff12b,20123b72,f0e5ef16,338c3418,38c2f4ea,6dab94c,7c3f6940) +,S(f832d7b3,590a59d7,ec2c8a63,7ca0347a,893fe461,4eaba097,8707c353,8296ee14,3fb3e845,4624fe35,326062b4,a6f30c85,f0e7101b,a3532455,7687812e,412233e) +,S(52aff21f,fe1819f3,7f8b5974,ab004393,6e99d8cd,8342b7bb,ad46d333,5e4d6651,66d79c3c,c7d08828,d8646e4a,6a44853b,4a49df0e,85c95e85,d9c995c2,d09b427c) +,S(aae62778,8069bcdb,fc91bdb,946cedab,63896817,575a471b,315a47cc,d567c678,f254c548,832d95f8,4f20215e,ca4805fe,356e806d,9b3b7338,7dd36e85,214b70bf) +,S(fc15d494,b6580e0d,e1c769c3,95c5d047,202e8d07,ba94bd1a,f96064b8,d1a4bfbc,f9327fc8,75319184,c1876748,bdbbdd3c,bfee8baa,bf46844b,af465d4e,ec6be335) +,S(aacec857,fa4bc62c,82790a4a,496206f2,d79a31dd,e17d2db2,d99619d8,c3d880d9,6dd1e4a2,adc502ac,150293d9,42a1cbea,a576da49,f1de7d15,de70bd67,d95c5fb0) +,S(c7ba3155,bf34fb9a,2441832a,27396e1,99836557,9c9cb856,44c3ace2,9ade66bc,afccc814,243a1fa1,345fa46f,ee4b4190,96082bf0,7866fa8a,2a887d84,d24192f4) +,S(cf7a0525,3bee95d7,711d8f7b,7b301f5d,8036a487,a55e3860,900b25b1,c4599115,e8a4a9be,7b9cf99a,5dcb4db9,8249350b,7a71a12f,a9582620,eda5a35,1a8a0484) +,S(a4336248,6b999ad1,623c4c32,c79ebb3,4e8d6f3b,484f808b,9a088ffb,2885a11c,edf8eef9,74d3e5ae,2a991a28,6323597f,5a161f9,2eeb9256,207be548,f9b38d16) +,S(d3cdbd98,8cefc8ac,3a442587,51364a10,649243a8,d4a63927,f4fa3b10,b1a7dcc8,f10e26c8,11f4a219,da4f948c,51e8b81b,d8bb357a,182031cf,40ffb464,d5f7d7c4) +,S(fa038534,28dd093,26977fc,da344269,fe3c61fe,35567eef,909a2309,8e5ceaef,f31c5d30,9e234b3b,44fbb52b,8c973aa2,bd85afac,1f9f0798,788721a9,380d8606) +,S(718c2bc,26dba98f,24f34af5,18e18870,5510c0a7,4e228cd6,9d4e39d8,a00a577f,c41d0d81,8f093246,5675a326,d0615b0,294b8455,909af0c6,e557195e,11225152) +,S(378ade51,463d949,1ed22ab1,834cd7bd,6b99a123,52c65e18,70d5005b,e97e602f,76469796,d7758ba4,b3bed1eb,9f8389a2,2a421f5a,20f8df71,72821a8a,508e4c1) +,S(40bd7df9,1255680b,b50d3d08,fead6815,5f807759,87e9cf80,15e6359c,9f138b8b,ec0417d4,2eb1ab50,a469a853,edc65ca5,2fe00ee7,53b30b9c,56536e3b,36144e8a) +,S(f01b30bb,985dfb53,7bb4cd62,18cb0b00,b5a77215,4d84a802,8a4969,260d963f,3cf483df,d6b58eb8,46e8ba1b,f06c2e9,6784255a,2afbf68,613f39f1,44b82417) +,S(2392d86a,1bf9a636,38eaa5dd,76a7c6c9,eabd50bc,9f2ba568,183c0995,f7195900,806cd3da,ac23f93c,3b11cb5d,a3bc4482,ea49ed2b,444c6e64,dc557e46,3ac5c033) +,S(b0e7747e,c9496fb,aa7798db,e616fa42,5b0b7acb,7409265d,c989b8e9,20087133,32fa615e,d0286b64,b83cbfb1,e8c4b133,85527655,48071401,89f42d93,330491e1) +,S(8d1342f4,2f6dc3cb,9bb741c1,9daa08e2,25fb6352,ffe860e1,76a26fda,a0601624,82d35ed7,57cb6f31,81af31fc,36f53817,191fb9b,c9338a97,3757d0bf,50d79d77) +,S(ad09dcc1,d3ebbbd6,ecd7be45,d7eec5d,ef743851,2ce076e3,cfc4f8b9,449a2ccb,26bde63a,e1f7fbd8,46260a64,372d015a,fd3d5ae6,125dd801,523a94fc,8421d04f) +,S(128f5199,68435c1,a27591a3,2edff533,d12a725c,f0c7e121,260cbb74,925cc292,dd8945f7,42f1d013,92152dbd,1e4dd8e,53277da8,bab68acd,8c7c8d73,f5d7e190) +,S(118c1167,196e8eac,e519d83d,17ae1e30,36ff1fa0,cbd1cc58,41cc3763,d1d8a931,eea348d,54f47b73,d5d8c2b4,7eb7604b,53beb345,c82ceca3,4f8639e1,45b2e3b2) +,S(81ee4bba,6a84edb1,83e1f2b7,5103e453,2ba9613a,b612e0f1,27009ee7,7be3bfb,e58208,d152059b,73b42039,e0a7a489,df067fab,1d1c2c04,9eed00cf,893f4847) +,S(494a821f,6f4b2d75,7e5be34c,fb9949ba,b9271599,3e060005,dd807c83,adf04f2f,8ab15e9f,c37d368,3586a1ed,ef9ddc59,8dae7206,499cf53c,31a8cc4b,d7ba15e0) +,S(3749271a,da87c292,724a3ad7,2861a7df,9757e31,3c3156a1,72cd3735,608c865a,aeffa1c1,aaab4f09,3998b4ef,e046aaf0,f404d590,d6cd762f,1aea5745,1f8aa3f5) +,S(103c8721,321ddfbb,cc3ef6af,1ea8fab1,3de6aca0,294dbc79,3a1e4216,563dc1f5,fe9cca2d,b459596c,462fb268,a8115880,16c2894e,e8839caa,362e4813,e8e827cf) +,S(ddbfc655,6aff403b,10a643fb,f62a60ed,656baa39,b10febe6,92140bf6,7b78f2f9,1cd4169e,cc8ac589,de57b5a6,e02e03df,f3cc7bb3,45993d5c,4ea57e6,852a8417) +,S(d025f583,3e51a9c6,a1c785c5,1c579528,5af0c297,c0fdb82a,f555fd59,88dbb28,5170614c,110f31ce,d88424fc,7d569f4e,e93d5017,a8c676af,c7261ed3,340d22ef) +,S(3f349cbd,8ebac9e,c570b0ca,29fe8ce8,dbd98eba,103f131d,daaf193,4fe78516,ec9641f3,175ed56b,d0c8f26d,188f9fa4,b38d069f,cef8f4cf,71acf66f,1ef7dbc9) +,S(7624599c,61e71532,a177e838,ba92d789,5160e43f,ad798fe2,9170e6d9,bbcc11ce,409e8cbf,6aea70b8,21533902,150148a0,7e45dd61,c9c8d24a,b8cc3da3,f03c49a3) +,S(8a1e1b47,3c699dea,aa418ba2,85cf7467,51af1cb0,8bf78228,932dc6ed,845403f4,1bd300a2,7a9a8da,6ed2bce3,73b9d39e,661d02bd,b4605740,20934bc6,abf3c483) +,S(eeb91c38,d9b834bb,5e3945b0,9655b988,96efff11,1e3dde8c,add6ef2c,7ea51b09,899d841,24f83b43,e2ea82ad,3a6411dc,cf36fa86,17bdab35,d83829d1,456c56be) +,S(46360f69,8c023375,6f050969,60b3defc,2a1897dd,44e0e159,d185ac04,3315ef47,ec02a6d3,828246f0,684d2059,23ba73ee,10cc88c9,575fc005,6271fb8c,67e0a4a0) +,S(16e5cccc,b410c20,e8de1e76,e5b71649,64cabc26,f629f8be,36eff4da,66f875ad,a80de48e,e079d9c,bac312e0,70f10d6f,fb875c90,7dd3ff57,c9bf8b90,57c0fe14) +,S(c315230,c8ee5bd8,429efc06,bd089f49,5f4c5a1e,2fb188bd,81e41bfb,85acc82f,71430e8e,cee9c6f5,eb91eb14,20e07b5d,736217e5,4bc25cac,9767a749,a477599b) +,S(7731eb8c,1684092a,d9d2ec69,b50339d1,19436082,c9116366,8ce2bda7,ee80c0c9,e6636efc,22a4c339,f8100dea,a227a709,42d18222,8cc58d13,ae4d613c,a879de8d) +,S(2c1c200,4a5f04c0,b83d143f,ede81755,67d4d54e,b2dc4ffb,de00b83d,9802f68b,b3e2e434,30d409cd,26490c1c,818b24ed,b10e835b,d6292422,45c529f7,6e299159) +,S(2d984bc6,a2031a3e,1a57d0ae,d13d798d,fab45382,d29e4a7e,8e029fdf,2a9d95c2,b169c34f,9932f02,8320ed87,4a74da8b,5cba81bd,f20a9454,feb315fe,a0926720) +,S(f61abdda,f7673f75,74e966f1,c77096c7,7f6e8659,746e45e7,2c9fbf3d,5e0db5f6,1717dd6f,86edd17a,b242212c,91878ef8,9ff1b865,b32b4e24,cfdab7de,de90937f) +,S(a68f5871,bfbce14a,1097eced,68a9e906,c94599cf,b6dd4176,ef946fa7,e5552c3b,cbc07a08,86faa82e,d231eb0,739a24e3,62a717ed,30b0512b,96ac8dd9,56ab05f2) +,S(52035076,1af3e786,60906105,36a2ced0,6f8209d,a0eb2757,cba705a3,467ccbe2,7a01b944,5f63cf43,cba95191,262b1b53,ae0af9b,4b172b78,3970f84f,f8ace09c) +,S(bc8f1537,9d4b9862,a437065b,10f6c28c,8c3323f4,51f2847c,63251000,c9f144d6,894826ed,61d85e90,58c00e74,cc731dd5,d62684b1,ca996c07,ab176df0,e4b951f7) +,S(536b0cb5,81dbf6,ab3b364,64a397d7,2a513bd8,a7bb8237,70a725d2,2eb12a98,85bc95fe,6e160f2f,9a31b7e2,74c09023,90cb2f4a,22f15ac3,3d0ee72a,b666f5bb) +,S(267840ea,e2f49fe8,9889bac7,40eb797e,ee42f922,c1821a66,163a580a,a0df90d0,2c7fe7f3,4e06f09d,a1a2b1ba,79906a0b,18c3d51b,d9b6011f,688c69e9,1504a00) +,S(d8fd79cf,6beed8c,fa57bedc,ca06e367,e0667e9d,a057222b,81fba682,979808ec,39cab613,9cef186a,248562d4,fa581384,d6c81de5,a0f7fc49,140d0822,f6126034) +,S(601407de,9ecff4d0,836228ae,eeaa612f,2b659706,576e2eca,74bc32a1,d3d14b7b,6cfde694,2f0e4495,1e25ff02,2f2501e6,7101828f,8088c7bc,a8ef2b25,88036ec3) +,S(f518c5c,bc0e8541,48c40253,d500a2d,1ea1d25f,d31dc777,d6365050,d3b26804,8dcc6378,2b1ce6fb,9f15c8fb,70c5fd0e,53e4d80a,cf38261f,49a558e1,de637b6b) +,S(16a9bcff,334e35e2,80258378,b2e25d9a,56ce58c3,b3426bd,da82978f,370ee6f6,c7b6656e,baa3864e,bfbc5294,fe9836a9,9fdc095d,ceac6a32,642e6911,a6f3e933) +,S(9d940fce,5ecdc659,30c945db,7151b823,a9259d0a,2a3991c9,f71e8b00,bbe35d4f,32f533d,d96f2e36,2109a96,48ef55b2,e5887387,80de97ad,c7974227,b23fe647) +,S(19e973f7,69c2d02a,8bed34dd,b7591828,5036e724,22227a81,850f3d31,3128f586,f2f5fab4,fe79c177,752ee60b,cd85e625,e459b50e,de702010,a6fbcbd1,5b31aa6f) +,S(ff07bc26,473271d6,4371a4d2,9b59f858,b1b01e40,472bb4e0,1769ed2b,66bf2097,3eba7660,492ae09a,abd7bb8,c5d80e33,44539ab7,276edfd5,b599b02f,27c60b8a) +,S(175f786c,93d89acb,8959d846,934c21df,5dc4f6ce,a9c1e150,e7da469f,d27e6605,343366e5,7f5b9f7a,407cd566,7ef1f0f2,464a2938,61fd5f2c,b0363a5b,dc9c2f9a) +,S(a9027f8e,b662a7e0,d70aa1ac,d3e0b9ba,d4e0bd8e,8bf8c883,40b0a7f5,cbafa761,2f9dfc2c,57bfd835,271d63ac,e3cecdfe,f6e19e0a,fc19ac0f,71ef9ec2,7fac30e3) +,S(677daf40,728a6c89,6804ed3,1df283e,19b41c2d,36a3a98f,d4b93fa6,6699983,1affbe57,3a561872,37dafd1b,bdcaa594,e499b298,6af58591,c6a2ea3a,2016c039) +,S(1105aff4,d4761b77,68db74ca,d9fc7aa0,14c5417e,de1fe641,ed1dcdb1,9b5a3690,bfabb1aa,76906ada,4a1ea463,f4caff44,a41afa71,b82e2457,d2756ddd,14946ff0) +,S(3221d033,16be670b,e05ecc94,8b537ca7,9318eb65,f93ab3e7,32e7f36c,bd06249e,92f7b5c9,85ba3fd8,7b14a093,74d4ef94,130d3642,517369e8,f9de5fa1,c8ccb803) +,S(ac10037c,ad83fcbe,6aa7acf2,3043ed,831dcdb5,66921f16,246488de,6e012fc8,d530eaa8,ebe1d47c,8e57892d,9301c4a4,29b223b2,7344e433,f2bf77c4,d9a20205) +,S(b3ea670b,f5001657,913d5d49,ee1005ea,65fdd33c,4ad81987,efa0331d,b29a3e53,6d758db6,df4275e3,fc148e91,6536505f,6393daef,c54c3b0,b708e0d0,8de3f1bc) +,S(42762d8,bf60f678,924b7cf5,4e8c513b,fa1223cf,98e124d9,18d88cd9,a54c8d88,96be42a1,f0dadc84,64a3522d,e13f10ad,3272505,f7d4fc54,e6dc1a33,ef6b2eed) +,S(7b9e0117,167c51ed,c3f7d2b9,edb61bde,aa90efd,88349510,c4b1cf1a,43a9ae6e,c43e0d1d,8a673cb,1f0d9d1a,e3a4c985,bd47a068,2528ac36,67976881,1ead7a4) +,S(1e807fdf,c69acac4,ba5be7fc,9c617005,d34ff896,dae25e6c,428abb96,3255239e,7db7d6e8,8bf3b869,fe4f7c11,65d85faf,55bd677f,5670ebdd,89d2f8b9,f56d972c) +,S(9aadd434,75384190,a6289f2,32cc6491,fb7a1d86,b04ae9ea,94dfd2c8,449c3961,fc491907,3ffe94d1,3b945382,eb9c482e,9da5a764,d9aa1d1c,c3d973aa,5edcd3f3) +,S(5012b7eb,481fd85,db13c3fe,2bdd06a,720eb4c9,805193d2,b99b4bf7,39802f26,db8555d7,e2cc1858,21920564,3c288352,22086161,1a611dcb,d1e98518,7c46cd4e) +,S(78f9e5ba,91071270,5160654e,2393cd73,85e4681f,8efb4a45,cdce5ef3,d73cc7b1,24c4512f,911101c9,d3a4fe24,b7468585,36cb8137,e13578e,95cc016b,96d86e20) +,S(91a7d927,4de2c0fe,84a10579,891ea8cd,f87fcf5b,a0939411,4612efd4,6bb9f826,d5a5e511,b85436b,89e46211,ec69dfa8,d0ee87eb,7c0daa31,24d48462,10e6c40) +,S(3940b4e9,4626f86d,4592b96a,4f27f874,c37c6cbf,5940de,37dafc1f,35350b69,ecc6176c,43df3f71,cbf0160b,697afeec,1a9a0d69,5ebdb7bc,34b0efe9,2cc68b39) +,S(76e7ab54,8c63ee6a,30c736ff,11762061,283af0e5,5a7dbbd2,23fe467b,85c95d8b,f266c922,fc5e61f1,65bf521c,33235e05,113140db,6a481b0e,e4f9976d,2696fdce) +,S(ecdc2e5d,b8d5028f,f93de09,c9f5a6b3,c439b14b,3c322c53,94622a13,80f04067,e70df9f2,bf6b0a35,9029f937,5e74aa93,4014e78d,e68e29b0,9d96da05,5ff78112) +,S(ccfe93db,de087d5b,9194b286,99243dc0,91d4dd5d,7189a5e0,d5621311,9dee9a94,2b0a0a20,cfef0c73,addd2dc6,d9b4ba7e,9e44f2c,26d9f376,8ef90241,b2d907da) +,S(4e82a200,e64f5b3b,3e473e50,e437c224,e21bf875,ec8ac364,7e599ba7,84f02574,ff696d9d,2d9cc0be,217394da,85201a1d,208e4309,9b9372a8,19f6d069,88839c0a) +,S(a292e105,6f3f0a1e,e816a49f,51ef4760,91324316,2e3c734e,802550a2,c942c17f,479a2e95,7a05a686,1c08df3b,221ed2c6,5d192181,189269fe,9ef42a8,e71fd6ef) +,S(47279a82,8311aa4c,b6138c9b,ccb2fc6c,c4b9d27e,2e334389,1773fc1,ee09f461,2480a805,496e8bd3,e02b36cf,8081bc5a,254f821e,40c0ef48,291ecbb1,6699a10b) +,S(b903b4f8,2126fe06,44976643,5f0982f4,394db57f,b473401,9536740,595562fc,e8c97572,bfae91fd,61cfee63,3b24bece,e587291,f65a6aff,b71c6a3b,615e1361) +,S(16b9e3eb,eadf469d,368ab368,431afb79,214bc728,5df165e6,c3bf98a4,701b05a5,26e74ff0,64cf5de9,ec3d084f,8d75337d,c04918eb,f783c65e,b50b948,d48eb003) +,S(4927fd2b,c17b92c1,3b3ca52e,759324ca,353e8505,ba81ac24,9003091d,1cebbfa9,95a6c16d,c4c52f20,2883ab4c,a9c050c2,b2849b71,e19e0df0,8ff495cd,f62d73ac) +,S(70c503d,93e47,10262c8b,b1630409,979b673a,79ad08b0,8d855365,f51ffcaa,2ad207aa,5fe05144,95baf3f0,b0807efb,d10265f0,5de63d6b,563e4ac5,e70b89ff) +,S(cf598642,32972f7a,a6cf12ce,dc5aa95d,4bd0f96e,38ed546b,9ba9040a,e25a9e6e,67f2f83a,f5f09b52,caed83e5,1b9d6de0,58a6e9b8,96d1a6ed,d7ab4d40,30332027) +,S(617b9e5a,8d0b8c44,b186aa60,281cee51,dc224e2c,9e1c4f07,c342a180,78b271f0,b64d8d5f,bc2907bf,90b983cb,a6126586,dbb7e7f3,d95993e2,2bc1b8f8,9472d200) +,S(d52e0c90,c69cd94e,3c849ea7,dbba79d8,6aed2a3e,3ca3f106,d2baa2a3,59c50534,36c8390c,fe400769,fd2b2fe1,b6af62d0,7fbd667c,fcd9a132,b6b4f974,a7e454f7) +,S(ea474a01,36d16bc2,fae6f568,9ea3c035,aa6580e6,b238f42f,e2ab19be,81330a46,d09379ce,aa89765e,1164f438,4b0f0ef0,c1e8be86,427c7455,af98e4b5,c9ee8145) +,S(4e5dd22c,b6a4b205,97f71375,cc49ee10,ba6b82cf,b06cf065,a25d6f5d,bef51d70,d4ff2ed0,55279f96,344dc16e,10e3410,40378ff8,b8d912c3,a17cbfb0,70588cf0) +,S(774587f7,f3038136,131fa9eb,f1eb3407,9e473a8b,b9e5acb7,317ff5c9,17447878,9d3779a1,2b067b00,d2a2a3e9,46f8078b,e6279024,d94c83c6,28c0cd48,145f510e) +,S(ab807569,d1a3630c,e5447b36,c205e601,a6a23069,4d2c0786,19d9b97c,e0ba6611,2b9eef15,54f8ee6,e11af6b,6a1d045e,d47b8821,ec84c6da,366afe10,2730e9ea) +,S(91602928,ed3cea8f,4faa254c,28962b68,c4437602,3076a5c1,6bad95ff,3e328049,764faf56,2d8de3c1,89b7fef7,62012be8,112db4,a3201692,95c7e76d,fcbd3be9) +,S(6c1ecc2a,258a44b1,ca1d964b,c86c5600,49fdfd98,b362c35e,3c830647,cf1266d4,1f9d3edf,5e0e8550,e4534c33,5b07d731,19c49c4e,29397f6a,938fc1bc,ebf8fcef) +,S(e176821a,4006b429,999de3a4,ada09166,f6e5deaa,f09fa613,60bd3733,db8f7084,7d07d1a5,390325d0,27b05e18,d90e7659,f5ef4c8c,c7c6dd00,c7a5427,4ec91842) +,S(2ae0b70e,53536893,8a7faee5,da5d8dbe,e5af4873,32caf51d,7bade79f,eea50df2,e70be2e8,c8110c31,c3eb5e36,31dc5a5e,bebeb184,e6b9f081,bb7236dd,cadf903a) +,S(1c686fcb,d7a751b2,d420614b,56d37c8f,81c9a600,335fa911,835dad8a,7c663e24,4fe2eeae,7ea1b639,b893329a,a65bbfcd,b9fd8f07,28614bd8,6a5b0712,76aa576) +,S(b369d7e5,c31c9a56,f480b44b,3354be,84145c3,97dbed68,d87a4c3c,be31dc5c,50800690,17d31473,59bab021,c876d152,c17ea8e8,b5c95762,c749a2d,29adf3cb) +,S(522d3ac3,42a0ff3a,9a8eb5ba,54ed4dad,fbcdb48f,53bc6e1f,2c0c12a5,61cb1e9d,32ed883e,1e1f562a,50063d79,45075ad9,9ab55ba6,fdff0d58,9d2b4a4d,10df82fa) +,S(7d001803,7b722a7a,17d74696,fed9bbb5,f3d5f6f,d8a623b6,9c952a2e,f2be939e,81ee30e6,deb893d6,274c4b46,8533d845,38073ed8,68b101e9,515ebd84,70e368de) +,S(c76b074b,b228dc24,1dc9b704,75fcc52d,a3f3bf0a,5e954910,ca4e6f16,bd298983,4fcc807b,4c1e37cb,6a6c42da,b939a7bb,6f1d5ec2,87320d74,408622fa,ece22266) +,S(8497f267,99c7f525,83c620f6,e284a9a0,35130556,9d7caa1a,f118de41,c51b05e4,3b861f56,16ce6234,c6847273,16bfa629,7cac9d5,ff562f66,24b26146,413960d1) +,S(ddb10ff0,a217ab76,241a587a,8cd46cdf,ce6ff5ae,e39d2d85,7f47eeb7,6d2bd68e,a4110196,fd0813ea,19846dc7,12537cb6,8faf9333,19e7e49b,553e523,f07b004f) +,S(47eb53da,455cbbb9,a8330e12,e0210d80,cc565661,348fec72,529390e2,a75b812e,88e4a8f,91ada187,5734dcf,42b85e2b,a3f5fc53,1f1c1df1,300c3d5f,e811fb70) +,S(eb0a8903,42fb2710,a4c7811e,78384918,dedea7a2,9bb7da46,e49211bd,95da1426,8d69a88b,d85e2edc,d8264cb6,c44d8218,1ce8946a,818c9d4a,6f757bf8,5817ac56) +,S(d400c8ef,655d3879,579ba4c,488c3e55,af5af95c,1701bd15,482b2549,9334906d,e7bafda2,5a9f5934,6bcec6e2,a9408f18,e81b76f9,7a9d721f,496c27f6,42725e5c) +,S(bae81c3d,1772e104,66625f8b,ef08d4a4,5f07892c,72bcee05,fb7e382,2a6261fc,4ce5f14f,74f28b03,34a6cc64,452b9049,8460493f,3b64d9be,2ecf98ef,c0270377) +,S(7f575b9b,46bd0f74,555a363c,d80122c4,232e8c53,a6624d8,e13b5c06,74986961,edc0ffd5,952fd4d3,c752271b,7cdfaf3b,4cefecd8,66d722f0,3da1e97b,49aaa080) +,S(a86871d9,1292f7fa,7249ee8,e77270fe,e7bddafd,3255b4a1,16851ae,411293f3,c21ee1b0,bd897d82,566cf438,b66439dd,3dfab0ec,3c7a4038,ccb86039,3b0b0187) +,S(c320cfdf,9cbc6579,8c8b33c4,d97d690b,64ae90c9,a5070646,8c8791e9,1ee4a18a,8f1a295b,2a3c8c5c,3b5bd8ce,e3380a04,819a8658,7be87d03,73a0194c,fafac74b) +,S(169a1b4,f2eacec2,be263ced,2e0576b4,ae77b863,525b2a9f,f8fc05d2,c07a8fc4,7703f867,d997a2ca,bb697f87,b97ea986,78777183,aea81417,1dd0946,309e77c) +,S(218de686,ed51588b,1307d8b6,54f7f6fc,e673cb37,553d23b7,b8c23367,d6b7ea5f,98325ea9,150a100a,f5d2af49,2fa25b23,40ee9606,1553c3d7,edd4d870,5288b8cf) +,S(c7c2e438,d12ed0ac,6363564,8bf2899c,d1b39b1b,200ffeda,4ef9cae0,5d8381e5,93a36085,fd09ff08,b83d50a8,3b140edd,a63e2442,e4bf4d1c,7ae44963,c1646f41) +,S(12e834e5,605d6e35,8cbe550b,8fe917dc,59194c58,66b265cc,50b00e3c,38fe058,6a44ecf2,17f46865,2e0991b7,df3b3565,444e7e29,3a2d6378,61a8f3c1,5ec1517e) +,S(30f33c39,af77735c,749fd328,e228ed67,bd625fbe,79dc3b06,ab31c173,777308fe,29a00f66,1c998f1d,bd62935e,44794420,7ffd7b1c,24f63806,9206e1c6,5c3d9604) +,S(c5bd81b6,b057e687,19c47964,d55ab996,6c7ea99b,25c1c2cb,50d6fbd9,af492358,5a6b1332,8562599e,e87c475a,1e7da886,c460ec67,ad81372a,7ed39498,41225e5e) +,S(1fd0e769,9d931a80,dbcfaf1,46b5cebe,b9547f8b,b7fa75fd,b2bac9ae,ac0908ab,11770838,88607506,bad87ba6,38c9ae26,d79a9dc6,6746816a,b9f21d64,fea96838) +,S(ac14a06a,4679e9af,b2ea3aea,15f2749,bc9610a3,b576a506,f96fa41a,76df97de,5aafae08,5b8a0a7d,48ebb339,f4dec906,21bf5162,dcb85100,eb7524e3,a65a4921) +,S(ad583074,13a4eba9,ceecba6b,c568bfbb,30566031,c06e8e97,5c5d992b,9ed2bd33,c2bda9bf,d5c87e0f,a663a40,34162dcb,29b61800,c1dcf02a,c11fe615,25af1772) +,S(5a8bd45d,6fd468dd,41ecafd5,aa072227,6d0176be,81b92061,b4277b73,32acfaab,878a8d5f,7903d74f,6abe28f8,d94d4767,3698a7e,6acbc32d,9e92f9d6,bf31c2d5) +,S(6690c9c1,d9666be4,56d3540a,6a2ed706,372256f0,43265478,7b54e56d,f28df74a,7ad591,23772578,999c90c1,24704c13,a7193b62,64240aef,63d12d88,340762a4) +,S(3c051303,c113779a,6137f46d,38d1175d,8778e460,8b1e0abb,f7bc4539,80b64a2f,9d4d04a0,ad1c772b,4a523c13,cc48990,c733eb87,993cdbaf,61dbf75c,4f6a96c2) +,S(1fdff503,66319168,f5dc381e,8085ac92,223b3484,a8b362c2,26d1f00c,976f9f04,5cb328e8,56aaeb05,62017bf8,65da44b2,94ad7404,df11e117,8426b79c,25a49fa6) +,S(ae83da7,52ec2098,a4a593ac,f99dd58f,cd48da14,361feaae,6cd992d3,96b4fd8e,6dc92b41,f1e1474b,a259e96b,ec4f2b36,108745b9,a500ad9a,edd9c828,4c3d129) +,S(c0f86e7a,6c0fee54,a2f73d2b,6b1522e9,fee994cb,d5089886,d98a4748,161811d7,4aea0b92,2441c184,c347243e,5ad5a064,ba00768d,52d7153,a5e0838f,f497d551) +,S(8e5b23f8,85d683a6,a6a657ed,d2d2f403,1320d4c0,83340126,d2958dc2,4c5f5ba2,25c6db80,477f37e0,ed6c6e3c,c96b1c7c,f9a7ca16,8e940e8a,b2946c7,3b02e61f) +,S(6672b4db,bb16c672,2592c239,7d9ea25e,f081d48d,aeb42c89,ae6c42bb,af09b3c5,a3778252,e239ae3a,f64e3b91,7f646181,4f71753d,b4bc958c,b5bcd3ba,4b5b1a4e) +,S(e0af1a1,b894fe1c,1f7de814,1a393a3f,b12b31e3,fcbd8f2a,356e61f4,402d76d0,37913973,b4de9a2d,23f4f795,709fe825,8eee8aee,afec5996,83d924e7,21fb9b0e) +,S(94355dd3,c3d73a1,cabdbe7a,295cb015,335a5a79,dd301718,10c245b3,d0c840ff,31e96abe,22a16033,56681d3e,e5e8330,628d8090,bfdcb925,79074cb6,82845475) +,S(fc340c8d,1e3e2849,1470dfcd,1c2fb445,e807e1a3,9c525ce8,141b292c,596d2e36,738e7213,7580eb3,615b7eed,9b069cd2,b644447,24696a,7cd22257,7a931464) +,S(c0c4e03,61d923fc,4201872a,1ff525c6,1697412a,7bea7a92,596e9204,f1af90c3,25c4c2c6,d6593ef7,ff5f04fa,a5b0b2ca,736ab33f,5c36dc63,433821b5,382fc4b2) +,S(81afd4a8,d666b97f,dcdf0d36,f2dfdf7,bf7c3322,69728b75,26dcb3aa,df51365c,b7fe7653,2c8d48fb,8c3d0382,68d57839,edf80cb5,732ae303,5c1b51c7,cb8d3efc) +,S(140b32fa,62130c2f,1d49e39d,15f9c64,f5cf54af,3a0c65b2,298e91e3,21b9477d,bac2aca4,c96d4363,12107b2d,8996875e,6772eaea,a5070920,39c1171b,9113b516) +,S(17418ab7,46f1eaa,b98725ab,68bca72b,9cc645d9,cbe0835e,4bf91a7b,3939b98,dc964031,b1292c03,117a4ce8,b3341e23,da54a539,fdd31126,41706257,bb9382b6) +,S(8f0222bb,6cbf7491,12b95780,b50077d7,be2a27ec,5bb6dab4,923cf36d,3a12618d,8df2a149,abcd276,31265890,471094cc,fe6bd8ed,b75c2364,6f7dd54e,30c4c6fb) +,S(e3965324,1c543ba1,2d0ca0ad,88c26ace,b265f42a,41d2b7d4,f252ecf0,a48275d0,44467da5,18786654,5722fa15,36c187a6,f67f2e8f,5a424336,b0ce8bbc,a53f9cca) +,S(6a4b614c,41c4a6d4,ba4f8c53,26d08bc4,ecbc72cd,d2415c3,b7caf285,acb07c1d,76dd92d6,3f85e1dd,685faa18,283f8667,2425de4c,95a7985a,cf5f74c2,7b29b576) +,S(afdd252f,82037cb1,928d896,74f3ff64,57b94412,b563a4e0,1a32cf2d,1afde412,d57f319,300a6f93,1155b0b8,3dd83a5e,d2b4a0e0,5d58786a,8024627b,73360609) +,S(65adaf88,4297a087,6ec0d433,ea82bd5b,9e3590c4,921fc2ef,d1fa0b12,cc74808,30e4ac9,77b97c4d,b7516c02,df65de7c,d9e8ae08,6146716c,3da4b26b,eca17033) +,S(eba0dd63,c667395a,9e9eda33,93f5d101,8462b957,1aae6a09,cb723e2d,a45704e7,8314c569,49b7c144,197647da,baf857ca,a164e385,62c1cf46,bb30e7a7,a8dcb680) +,S(d3341d4f,1f967f0f,10932a5,351c6c22,c748af09,1d547cc,2766e6f3,1a9f570c,9694fb83,74177e3d,80775206,f58b2e12,32b87c9a,21f060ec,19152435,45502951) +,S(1596b717,8dceadc1,b5f3a5de,89c089f,62506b6e,2c6e49a7,f1cc4a11,e502079f,97157538,2aba92cd,8f009de0,9dc143c8,51b0f3ea,31067381,48a34858,8c085d49) +,S(138c0bbb,17c63e1a,a3e65b50,3c602d8c,74178847,8dc2bcce,65b84cfc,95f7ec41,bdf88a3e,34f69fc2,415fb95d,a4b6d3b7,f159651f,36a2d4e0,b4063e5a,ee86dafb) +,S(7d99662d,e6274432,65ab2842,a4ed79be,480404b3,1b847c01,c557e277,ee073176,e2ceda2,bada9b63,ff2fc022,44124d3c,b83dd4d1,f3fb74b2,763ecdb6,46e4cbf0) +,S(9e3f4ea0,b1db451b,7d713eae,35802229,fabbbfd,6f6d0ab0,af7483a5,37992e63,a9023199,10301c3d,78933143,b54e87d4,1419524b,16c9c00c,5550fafd,e6be8b65) +,S(108c8cda,d6ffc3d,b0863a66,43f0a4bb,efcdb0c7,202f630f,f971a7ce,dec3ff40,847ab4b9,8fba1fbd,15f6bb2a,4b3d1038,726c2d66,f4c9b8e9,f740af8f,5067d95f) +,S(5258a6a,7c85d4f3,e650f0e5,1e2d8254,8a768c0a,f276da55,27ab0050,6e97e710,e5605a14,31c8941e,4f2aa3c7,9ab94e3f,ffed156e,ba2159a2,7fde377e,e2ea7e26) +,S(c40820e7,f46acad2,5bffcc6d,745aa3e,7036f26a,b6ae85f0,e3cb8f95,29dc3f3,6ddf9217,88249ac7,6ac2c9b0,1dc5e62e,91587d15,c76fe26d,6d7c3b2f,feaf3b12) +,S(c135f50f,160d04e,43148abf,d76509c4,e55aadc7,554e4ea5,823e013e,a0490da7,f9a597a6,b26a1485,a7d5a91d,486d099,93de9a4,6484edc8,72f8f4be,710aae69) +,S(484be5a8,b903230f,991c3118,38d3ebdd,9759f5cb,11a9d0a3,9bb11a03,3924268,18f80a36,a3d70e67,5bd65253,a1ad3e40,a3152d55,c1141315,57f8585e,315ba462) +,S(af67562e,998a4032,77fc5827,cf222258,cb2f23a7,4dcd0d4b,315564c3,eb66da9c,dd5bf89e,c9b2c178,6adea201,d36f3a66,771b3f2a,cfba7acb,c30024fb,fa73ad6f) +,S(38dd6cd,475f2808,938d92be,8ad0c955,f3cf3255,c3602b99,3c177e06,553af411,1abcdd02,d82cc0f,680362bb,f898bf89,304d681b,6bc3afcf,65454ab5,8d44214) +,S(ee37f0ab,3db1f9b3,2da0031d,48f53766,3530b68a,f47bdb87,679426b0,d90fa6d5,6cdb12d8,136fc9c6,2f025cbe,7882ef21,4e7b09dc,9fba4cf9,b021c4d6,610c0397) +,S(670684dd,fcc19f15,ba9201b,ca36d143,47dabf31,bad07e8d,68e6fbd,2630a98e,77bd28ff,a9699737,1304d4f,82d29d1f,a69dc123,6f2ee438,cffe3f2d,358ce706) +,S(1654f447,78026345,64e3608,bb29004a,812ea39a,d96830f6,66a92f5c,54a79359,11d91962,3f81fda0,36d2d021,607d9750,cbd30359,83c4f47a,21fc8116,ca93cbe9) +,S(ccf0a89d,429a0274,7b000326,d62825ec,6978f24e,8f92f490,e8cab1ab,ff90bfa1,5f047694,375222bd,5968dbcf,a331db73,85b4df25,72791c53,42c62467,3d84400d) +,S(45d36700,32ab11c7,897d648,67ed4d03,a9504461,bf28f3df,7e1276fe,4c1de796,67e837fb,37108844,2338086a,d1506453,ed1f37ff,fb14e617,93908c7c,2a8e6fa4) +,S(9af3b6e1,627a2ffb,c18ddf33,b668fece,bbe7ebe0,986df82f,1b2fdfa1,56dbc565,55e9562e,882f6629,1eae4c6b,5a82b0b,b5bc2cb2,b8f884bc,3e45a126,aeee19e0) +,S(ecfe9d5e,d3b9fe15,c320e05c,7e0f3b1a,5fdaa9a4,5e1ff99f,88012642,a5d45b4a,b3cc1fd0,e0117151,f53ec671,e1d207ad,5f2b0755,8956cf28,2be5228d,db5d48bb) +,S(6e482326,6ef64478,dfa30c6c,f3a951f9,fd9d3108,dbe80e5d,3cbf2217,70f5483c,97a3f599,906b1738,372212da,80309562,d3d4179d,d2abc2b6,41ef2f4e,6561095e) +,S(3de89149,f6c939cc,5419e4ba,f0baa93a,390f01a3,4ad0fb7b,3b170e54,60a380c6,e9a07758,1c4617c0,b996ae3f,b250b723,874b66fb,85a6d826,cc5826e5,bb068491) +,S(d4d28193,53ace188,703643d3,84622505,d9020459,a600349e,69016cf4,faed2e25,9a494bcf,e15bcdb0,97513682,ef09890a,424d6bc1,ad1cb73f,123ff5f6,7babb364) +,S(f694a819,fd0f2035,1193eba,c18e2db7,9c219191,2bfcc60b,6af8e067,2281095a,d80d1652,1e43f18a,4b663898,bfce8670,6f53436d,a30b0663,9ee6f99e,ca87e667) +,S(af8595b8,8de7c459,7d1d1614,ac897de0,5dd9ff05,593dd3b6,cbac81ce,d2e1fb5d,e9dcce9c,83ee7217,857d5ca5,a48bb720,69d467b6,897be9ac,658dfbef,3d40e6a6) +,S(df4177f6,a7deccf4,c618b710,b096bb4e,b310e4e2,470b5795,6a633154,8ae8123e,3638e20,5d42ebc6,7184e567,c177f479,18fbf9b1,e4f69435,487b289c,35c7fedf) +,S(ef50482,30344ae2,70ec6d30,f4daea23,ce7b64bd,b101638b,5a52ff3d,6dbe9fd3,a6eec78f,e38a2e6f,a9c062bd,4ce28dde,c5d25fd5,a3204281,ae30d79d,99a2658d) +,S(f89596f3,ddd57abe,3344080c,a6d85d0c,492261ca,7a698aad,ae00dafc,75615954,f8d7d2eb,45dc2b9e,a0979550,8d9da016,20b53a19,b4150ca6,36bf0f86,ab3dc0dc) +,S(a7c2ffd7,50b99bde,92ac1419,57d8df27,56ca49e9,3f4c7434,b24899f1,24fb3cc5,a1672ade,aadad853,47d1440,d573e3dc,91987d6d,ce55c67d,665402d5,f8b0a289) +,S(463f5f25,b5c63801,a6b1accc,6662e6de,5256fce7,37e1c875,2b4a880f,19ceeee9,858e4a68,39eb48a7,f1a7de4a,514fdb46,1f4203c2,65e308d0,3fb9770f,1f8f13e5) +,S(4c99bf38,57073c27,cc92314c,f260dbf9,e0f4bb7d,1a5ffadd,a808783d,3bb602b8,aa107422,ac7dbbbb,f6e8064d,22a5526a,96bcbca9,9dbaac33,c1f35b2f,c6df568f) +,S(f6825035,64438569,aa7a5a4b,e2468453,8d8bfb88,f7e983d5,33ebffd,f8588520,84ff2ce6,9d79938d,fd910bf0,25a2fe8d,e6013c03,74784b73,168049e,c851cf15) +,S(62ea02ca,16b2e528,2f913a,36463494,c00df046,8afbeb34,cc9573,b71577fc,36be98bd,2c83e8cf,e0fc1aad,98ffd9e2,9ccbad8f,a25b9da8,23de20fb,fe91f9b3) +,S(ea34600a,7591c57,d0a7e351,de6e6d0,2c72220,62a980cb,bcca8966,356a2984,25eccb4f,a6102f52,60e4c545,57aa960,b427e372,80c35b8,edad5f52,1bc93aca) +,S(5b76cc79,2e78f177,97b32c46,92f2eca5,1ae1b7be,a753ce98,8e58d116,6c667027,2e01ba25,799e1b9b,3416493e,3fe9fff2,c46e634c,2175a30d,7458429,3ea60b5e) +,S(62a52d8c,d8562624,48ce5315,28213ad0,6fc6044,b6490db7,c27b7662,bb66f07a,e8f5e0aa,aaa65c7c,2b51e665,f3b31157,54ab9fdc,ac492ee5,fbb2a348,d8db5376) +,S(a276992a,5e155e29,d091e05a,5f0513d9,ff2dfbee,6ec1ffd9,a91f55b9,bca641c1,3d480cf4,e3f6efda,6cea9cc9,d769b16c,d1f3d64,23aefe9a,abc82b8a,adb22e48) +,S(bdb5fd64,bc99741f,a2a672d4,a895aacc,98886a9a,d38a486d,ed1915f1,f0b515f,d9744595,ae6e1e64,5a52a094,75ad094e,6af9655f,185ab90c,c03262cd,39794f93) +,S(cd6c6829,9d2b1c60,9b70153a,45259261,91b9b9d0,9fcf0682,d312960c,c3f82c04,2178ce3f,1bc21a2f,7accf32a,b20d625a,182f8733,e460e8b9,e1067dfa,fee6b36e) +,S(ebbfa9e1,8a4107a2,475f99a8,672be581,f32426a2,d774acdb,efe501c0,af97a0f1,1845a5fd,d71baefa,64cdf1f,d1211158,a70752b3,adf2b4d4,b5bf1a9f,7a0abdf2) +,S(bd5af866,4d51256f,455a3190,88b754a5,34223135,1491f763,3e090bd6,27414fa6,f8b5bbf2,2154786a,29f75090,fca2e149,60f84b47,50ea8db,d7c309d2,52233f3c) +,S(34ef0b38,5a8e776f,1c3ff95a,5852027a,ab6d1da6,6201548a,fa181c81,55382b77,958180ce,9afc501f,84d4d3b4,eb556ca2,e6ae8dcf,f949db6d,33cca5e2,9b357280) +,S(4b5f6663,11e6956c,e186fe3,85f00069,c0dfbf67,e4130bda,64e0e89,1abaf471,a6cf3571,2e790d5f,b500324,773281c,43f6d008,f6578ab2,b48fe4de,1ce3b545) +,S(cb22489c,bac94ccc,887a1d7d,8836cacc,c8c2a43a,4e09595c,39cc6064,ca04546c,dced75ef,d7ee6ae0,18ff2690,9abc82ca,da74e823,c62e4268,606334e2,969bf94d) +,S(b069007c,4a50bfdd,38ebcbe4,31a952ae,5356d63a,9f4179b5,e4cda3f,fe478c42,bb90d5c8,e66c6194,ec55acc7,6dae5f0b,dd498746,2d24a265,c314e93d,618a0f41) +,S(18722ce2,9d9cf99a,e52a420e,23fd8e85,e1582d02,c520d4f1,16c2b82d,464091f9,9fe257cb,5cd5f644,183c8461,ac2dde6,94cc84e9,76d9c623,584a9d94,40fea12b) +,S(a1562afa,6420b34f,92a78951,e9ab1bd7,8772a181,636df487,81bf4bc0,b16bd196,ce4435e8,7105d006,9b353734,5a503e0f,a692d3a,8571e8b9,66d9a722,48ecbd1c) +,S(f466db58,b4fae060,b12b780b,df11c7e5,ea8a08cb,cc50e68b,f5d85926,b9f3cd97,c86b4153,45515a2c,9a831ff1,d6377a8c,cae62456,f207df2c,42a1e767,684f79a4) +,S(686a1d05,e2bfaac8,e31def35,21876c81,27be2ad1,34ef3dcf,6de52778,37278176,111404e1,7f2153ab,43597a74,be1c278a,998b3695,5f4d465f,271a6a46,8e9e8986) +,S(d8433d5f,e5ec423c,73bb3ec4,95d06cf5,3a77474c,1e97ff97,f72a0457,9a60926e,3df114d5,a9d63dad,ada0ec4f,f98cb8ce,f1ad419a,e2c23dc2,f24048b4,1879be1c) +,S(3a9a0aed,4581937f,fe49392f,488053df,349f0194,9666418f,16e56fcc,533cb73d,c9db1a90,2d6676da,251b4be9,7a643bdd,d55c2b15,95ce51b3,281cc866,40cb558b) +,S(b35a204a,28884708,3091abf3,34be3696,b1082fc7,5caeb0d5,18387aa2,711a4190,65f951c8,78232345,487e8e,376c22bc,e5d9e8d5,ac04ecbf,24cafef9,4de358f8) +,S(81ff6fec,11f48691,59a2d23b,b2a6a9b5,68c5e6c5,1df9905f,ff73e1cc,a2c505a,c7b794cc,d657519,fc05632e,33e23474,654f1344,6ef1b4aa,1a1da18b,4acc1e49) +,S(3588a9e1,7feaaca1,a62fcdfb,3952beba,43116167,bb238f10,a41fdfa9,bc316d8e,acb24c1a,58ed9a0b,9744fa76,df4742b9,b440347a,4b4446ea,a3e55234,102d4789) +,S(7eb13fdc,9588b724,e7cddaec,498a8b15,d57a49af,529c8c9a,cc8303b5,e81f91c0,89f6ac3f,38351f7d,e4b293e,f61a87a4,2c08a4a3,ae0c160a,563ae5af,dc62dcfd) +,S(2f68c6ef,b363459d,862710a0,a0ae67c4,afc3cc00,85f02e21,ca4d764,3c76e00a,f8be9930,3a3aa7e5,c50d3f53,9b88bfad,60f05fb0,1461d7a8,225bb21e,18616cd7) +,S(b11994c2,5e3e6d0d,917ac215,c5f39606,3b9b764b,5dfc2b75,ab8ef880,3b57d802,4a7ae35e,c525d91a,cfbdea6f,cc9afbc9,b3cc8c80,acb4385e,9bc20158,f9f2b55b) +,S(d8e7881a,e1e4d04,c431c097,25dd4cd9,b4efb4c4,3896256b,7de47fc6,3a3b30bf,ccaf57cc,138f0bbf,5dbde16e,91d14875,c0d5ea,3842e864,be8de17d,875fef67) +,S(88e02abf,a37ffc97,f564cf3d,8a086c8a,62c05720,802319a2,30ab7cfe,b448c478,ec2d3169,15dd0c2d,6f03f851,97a96f9a,6c0772ee,df0c4524,c08f58f2,39c89308) +,S(ad258ffc,b42d127e,a875b181,a8883a5,31d18a64,d75a6dd4,4111d697,90752d1f,acf5ad9d,bfbb14cf,a25748e3,96bf23eb,aefe1bab,6550b234,90ca0278,276e9db4) +,S(a2bfdb6d,38159e5a,604d564e,af29cf09,a0a8ac79,1aef5a63,e1c05da5,fb6a0c39,7a45c5c,a7ee7c0e,74c05914,1e3d898f,ab62a8c7,31ca0a66,a937ef55,51dad999) +,S(7c7bb792,ef21cd53,bcf33a82,6a1ebf93,e9f3357,51131f9b,36f659d9,594f453d,bc98b32e,173d91ca,e9daf137,766c5ca5,6e0434f0,e2eb070e,7fa7f8b2,e7364635) +,S(40a2000c,dc0c1c9e,4c037a3f,3113b48,f26730ce,11e03b1f,d2f07217,7816f8c,1966929f,210afe16,9daee99b,7b48eef7,27e1703c,8bf42006,922c0496,888b690a) +,S(6427d169,cfd7e9fc,1b310f68,e3371720,28c17dd7,c6d5a32f,4ed6d41a,634f3f1a,b1a71fdc,6a030ca3,d7dc2ce9,27f3b9b3,ca7169f5,2fdecba4,bc85e32b,4e52fcff) +,S(723013b4,24fd897a,1e8ab77d,ee0618c9,3c832117,94f8b822,9d7a9e51,1ba8194f,21acfca6,e5e0cc31,479e5a97,17494692,9134f2e6,ebcef2ac,c7779251,77e9aede) +,S(1b18b7a5,43a284b8,3165bfa8,ca947da5,376fc4a0,8f4070e0,a20aa905,fd12acb9,713ab4fd,9e0bab6c,aadd2f63,1c5ef168,7cae85e7,6146319e,94b19a1e,f6a69584) +,S(65e5990a,4700f51c,9d3e61d4,26c92f88,5506817c,d4d60c66,a341cf91,9646ff81,2ebdd818,f69cd135,1405c63a,7160ad4f,17a6a7e2,d4353db4,7b554eab,3e737819) +,S(eb131661,eb78d37f,92a851f4,506c43b5,1f2a155a,dac7eee3,b1dbc29b,a0b1250c,45f2f418,47d2258c,3f78a2d2,794e9aa8,eab23395,8debf0e,b1440d56,dc728334) +,S(f20aaa98,ab7d6f1,d6de080e,ecd0bd28,b14cac9e,7f27c931,5576b039,16777203,4d0dc753,84c942d9,347f007d,543bc399,ee01e84,7625d5c1,a57cdd67,79c4dfba) +,S(9994a963,ef21ca0e,9657cbcb,3da57f3f,e28ce389,60ae5dd2,812b2949,96969047,93d75bb1,35572b75,4801509e,5b64858b,c0a415e0,3968efe4,2e558786,8516362b) +,S(4696ef39,95e5818f,d7894737,2fd68c75,fbb455fa,8477863b,b2687fca,fc2cd7b5,1cdc53f1,c52112c2,f58a6f66,7c1e4e9,110d83f9,d765347e,a724c784,d8e5d5ee) +,S(7b052f1f,e1af9537,ab3bb5b,3e0e510f,7e101cf0,999f85be,c403fd62,53e68d25,69c7f158,4b6c36c,f7d881a0,fe4efa5e,3f879753,641ce0f4,3e73bfe4,77ada27c) +,S(99452d74,3311867d,1d86c1b1,decd1ed4,7192a58b,3ef98cf0,7816823b,1296abc9,ffabb50d,a1a0451d,36b811ab,5e0c55d8,751a1851,3ca8bca4,8d6b3ffc,61ba36e3) +,S(40c6fec6,5ded4688,31f72de9,fb5c7f67,32c0c170,29f19b36,b00b0f85,5a12424,17aa0baa,eb3ba6e4,c5000e96,c3eb620d,ce1dfd81,b35a3e79,b27b8246,97dd5741) +,S(b9bd9e2f,c55ce5dc,2e46e4df,56401c72,e01ac3d5,201a3cbb,a6609fef,ae2e827b,f545efa7,f95e9a60,72cb9750,6f929b4c,e0360c8f,a9f058e6,5b87bd55,a72abdcf) +,S(867c0fa9,f885935,2756e3e4,11666eb2,59a416b4,7c2ff329,e30be462,13178921,6fdda875,4a50ee1b,d229d4f0,fa8876d6,9caf9fb2,a6af19fd,dbbd2a81,5dae486b) +,S(1cbe8374,3decb58f,f2fc9668,7ba45c64,812507ec,c2f71d66,eeea12c2,92fb36cb,799533ce,46d2c091,d0b553b5,18c82317,f516049c,4a4f50be,909c875e,b0bbe21b) +,S(c654f9fd,57426248,fd24097,2595d71d,80cf771f,cabed8d4,63bdda8,340398cd,898e9224,c9e94d14,3f96702d,c296bf50,9b2cee37,da574bdf,b7c09cec,18357a18) +,S(49e8e14f,4a9f09ff,48725eda,85ecae6c,3fe3400b,81012e00,991f6a69,2d75083c,815230c9,284924fa,57d08944,2a30c61b,8ce19644,7a8ede69,fb645864,ef35977f) +,S(43a6ecde,ed83f1fa,8946f584,99e71bd9,978f610,b46d1613,c15fcfc0,f79786af,2995f70c,11eb448e,68eb3d10,c84b36cd,7605e249,1df1fa3,2e9eb57c,c0275482) +,S(96861d91,678e5004,7c491950,5bbfc70a,e342c3d2,361729b0,4d0bcb5f,d93eceb5,6845ec37,9bee6269,464b2e9f,156ada30,c518bb8e,105153e1,c3b3e948,d38078e7) +,S(3c72be53,c9f82add,504a1955,7b9560a1,7716a058,26063408,79aca60,c55f4515,e584b72b,cc4744d9,6a00dc44,b03ba61f,c2269731,a8178755,2a6dce8,25d31b81) +,S(ce4b4d07,deae1fad,33192544,448ac5b2,77ba7f70,27b81a08,d7f84581,4f71787b,2013299b,2c744a5b,da6b243c,d04d95b7,e515848c,dc28eb40,892d40c,210bd1b2) +,S(37984db1,6d288866,78e1804b,9c94ebf8,f3a1aa05,1fefce96,65712f98,198ce116,20a25966,8ed14a5f,fc3aac09,6d2351b3,b6cb19ab,da4c833b,4a2a6c68,55d1ce59) +,S(ac01bcf,b02e627b,2c9c931c,f87beb2f,4ad7328f,9caf627a,2bf695ed,b7353acd,be4eacf4,77c92348,fe0feea9,3075e93b,bb3633c6,6747524a,e387df82,176ea252) +,S(d5d6af83,1a81b72f,efe5618b,ea43335,bf1d81f1,73382fda,860260d8,1a2faa83,865f9ee,4ff0fc6b,fa761709,db4c67ee,a3213d07,21b2facd,fcd8fa57,8945698f) +,S(3c16399c,4de35853,a6dac8c1,8eea4b40,92a22a8d,5e69ed0c,13b9c2a4,3cd5e39c,bffc2dbc,c2ce4b04,6a92b967,d1a04b5a,2fe40be0,fd9930d0,45b51f8a,15b53edf) +,S(f67018d4,23e50a73,68045b0d,ce803e35,a26d9a5c,288a3a7c,c25ebb03,dad28187,ee97afc5,1c73531f,ea8998f5,53086a59,cc67c6db,955baaa2,8f57153c,afc4e772) +,S(de67026,529a32fa,b3ae79f6,ef9ece7a,47008d2,46f89053,e9339c4c,dcb53b30,4daa8700,4b055005,90611f78,43d258b9,516f1fe8,61cf06ca,d466e000,d3a68783) +,S(a133627c,af6e7ed3,1d267608,19b69f45,7e75ecae,2169284a,48b5ee16,b5dc8c10,755ef12a,fb5c071a,36dbe2b7,1f858d87,31c93d81,d271c999,8f632982,d7e97ce6) +,S(d255c1e7,ccc88c4c,33887c9c,b9c15a2b,52b08471,90ad1420,5fb5909e,d36059c7,83e3e1ca,99a386e8,4b119391,2c20593c,f9573996,d42cb7c3,6db24a5f,cb413080) +,S(aca6c69b,9ea17803,4af67422,71b8062f,77e6dbe5,1df2a570,65fb3057,ea185b8c,40cb09f2,adef414c,816b22f8,d7a59f8c,f5197fb9,b31614d9,ac172436,d0f54647) +,S(fbc19c84,3b656fcb,21d99c3,5289d3e3,2bc58fdb,c2404309,a9d8831a,f2365f24,cc22999f,203a4fae,59eac72c,28bed6d9,291f204b,707bffca,ca6d8359,1e403124) +,S(ea308c88,c366677d,5e575457,cd3e6978,5b491a02,c542dcae,5dd5e149,2f839c55,c1916831,2f48555f,b80845fc,ba89eee7,a7967807,d10c6f6e,b516c190,94873ac9) +,S(d911d62a,33fefc48,abfd4409,7ee2d32f,d7e85816,2a8a00d1,342646ac,8dda6cd2,f160f933,41bb32f7,401d153b,4a2decf8,b793fb5b,4d5520c9,6d9cb9e,cba79aa3) +,S(bb75b497,7d698442,7b0ac74b,939ab3d8,fb94304f,602e102,1fdacf22,27022a4e,ee3cc171,8e9190df,9b45d8d3,54eeef9e,11639423,dc091128,ae09e451,fffe3468) +,S(358e7639,b4031852,b983b5c0,a6c0d33e,5edb304a,3f8bd15c,35d35794,e2cf90f0,5da4be1d,2e9bef5a,5da3cc59,d3c4f85a,e6624ee3,17395ded,398147a,12c56c45) +,S(e098fb9c,440a5cdf,bc570270,4b57eeed,f3087b7,e196522e,4b194618,f3c874fe,9a5b80e6,b22dd111,1f824c36,4830e723,18b7825e,2f2a0fe6,ca460d0c,34eb6449) +,S(62d607b2,d1a16e4e,cf60480a,be9416a7,15d70b5c,56734e7d,1498ba03,7632528e,70c5f4d1,4f5c900a,96291a4e,d0f795ff,439d35d5,2c5bddd2,ab10571b,1d7d20c2) +,S(a630c5bd,ec76f869,40842391,cba6cdfb,9109940b,e1034b87,c6a1e5e6,9662857c,8f28f55e,beed2883,3e347b10,92ff8938,133558c3,bfeac1f6,a6b938a4,c783b79f) +,S(e2a164aa,e17cb0c4,8ae1e911,872b0b3a,7c0e29f0,93cd5e18,97145211,d72147b,23ccf99c,afd1bfbf,a7ce1ade,1590d609,9a423b26,381f5761,c19ba373,290e6193) +,S(742526f5,b95051cf,2ee34994,8385fa72,425162e7,e46bba3,febe5ce8,595a8b37,d106a3be,638987e6,870acf8d,26d4f78c,e6aa0e9b,63e4eb19,114fc97a,eee3a12f) +,S(ce7837c2,31c32444,10dcc790,de465c06,75404a1a,68d23fe9,b69d887e,9c554f45,2c0be877,20cfdb11,8c37b2de,a2c355,d12279da,58f75570,7e738867,146257a3) +,S(601167cb,2788b146,998f0b91,d582cbd,27f4b866,40db7ec6,7f26214,f3ab9212,50525e40,1f2da57d,1f605f34,8f11ac23,19ad1827,41d7be11,46538e83,e03bbeeb) +,S(d2f657da,6f7c3c80,9d2e5291,b1161d46,393009ce,e2bd22ae,32b99eed,f76fc728,6df58d32,b795b6de,2a9c3b15,f4f1dc9,4e6e6757,e01891e2,79acde59,d13e3e75) +,S(e9fb6b74,f84973fe,7c7a0924,e0133b92,bb4c22d1,ce9a94e8,433f0c72,2a86e00d,f4df6cd9,df43c150,9d4b9580,eb87298a,551ebec5,2438597c,87dd46d4,3a8ad2c4) +,S(98d46b64,e43f3384,88c63da7,35af1141,e8b41981,b706ac5a,7aa1c0ac,1182afd3,3b2ce203,5bbd2cd7,f3206b3b,6aa3ac68,31e0e2d4,7f9e57f2,3e780fc9,cf865733) +,S(b358a4c6,a7130b1e,a00d8403,7164e68f,c6cf96ea,c6580ee5,b1cc2452,8d2bb5b,3bbb25ab,4645c17a,2a6f7e64,2d3952eb,86462564,5647abd1,2e80d965,be1d3854) +,S(fd8807c6,c456582e,d03114a6,2b42316d,4d0d386a,aee634cb,d33f2f82,c1ad6f05,c67d1611,e45c57d6,1f8d721c,437c0ca2,189488bc,f363aab0,f25314b0,14f896) +,S(cd53fa2a,1f989ceb,cedfb7a5,237addfb,2efe9469,8b6509c9,3081710b,f0db107a,47e61ca6,4d26e617,8192e993,411d0540,bf7c37b5,8c748eb7,6c1c197c,87c3f844) +,S(38cfdfb1,1b60a68,b00a4096,8f2da5e4,4a60868b,de9af728,fcb888b4,9a098c66,65f4f191,92667492,d717cfbe,bafd0076,59c08392,30da216c,315f2cfa,d3725184) +,S(cc179d39,1c6ab4f3,7fae6380,35886e2f,82038bca,768d1396,13fae8df,a167a271,a12fff68,84a967e6,fdd6e14b,4083c0ba,2a2bcf49,f7d6071,d708c70,4722b1f3) +,S(cdd61b33,75fd00cf,430d9d54,202c5c61,465fe7c0,a3f51660,ce74a3bc,58068c,46e5334d,bad31f3f,6c4bccbc,6812cf13,5c039a5d,d51c6516,49564f45,45f13ab) +,S(39ecf8d5,4fa9c3b,fef7d5e6,5ebe0e75,288f17df,4b33036b,d034be2d,fa5bdbbd,21991cec,ef62e421,70da3bf9,8b2f9bd7,790d5b13,25159727,a53a0735,5ab1d956) +,S(7b621836,342994d2,3185da8,67d47e69,a67a184e,925a3,524f5e7b,63639263,b08c269a,1569538e,653f2beb,3e6e348d,c61537e0,7afc5f13,f56d1f74,518b274e) +,S(28e5ec3b,38359a6e,7d3a965a,c5713365,44b91ea5,c9f350bc,d315c153,72133bb4,5bdc5a02,62734535,8621c1f1,492b3434,be731c25,f82c1a32,163ecf09,7f548465) +,S(37ac3ac2,3f6b2a1,a3a5a99c,707a6b8d,5f05e80,133ac522,107ae5ff,414d33c7,460c947e,76eb51c8,42bd0e6,6ccc0937,87f61bc3,554538b4,c2065fdd,533d0b02) +,S(275f5ef2,a4546ba0,9d96d138,e698cd32,78cf27f3,2ee297a,5ff8dd41,f16bea50,ca91a3b8,5b0a493c,a49168b4,c9eff873,66212b9a,c030fe6d,a9be42b7,45d0464a) +,S(6c43669f,a69bd51c,63cacca0,21c69bf7,9a94ef9f,3f0aaa92,3be9380,a6702e34,b416195a,1419771d,82fc2ce0,637cf5a,29823d1a,95614642,c93a979e,5ff3fff6) +,S(606c37c1,271b90f7,482e6ba1,81bd956c,44a44189,346bfa67,539c188,ac0eb61f,f6af64cd,3f04e30a,1b4a7019,c6caa84b,823bd00f,587eb58a,e190ef25,322154b0) +,S(e4136e15,b3fdf609,f779d0c0,70ce8521,2babc592,577361d0,47ada13a,2a83d43b,1af23c84,ad240ac8,50da2ec2,721531e7,18776ddc,5847edd8,b4d79d52,26e53125) +,S(a338d942,6ce420ac,c9fb29b9,cf572af0,72c0d144,46dc2c3c,75b9d5c9,f7fa244d,c88a4399,f6e3ef2c,619cd9d5,215d305d,3715b962,b02b29ca,231446cf,8ea7c40f) +,S(c454d1b2,6f77ad27,a168d032,fc1a73ca,fcc4aac3,ace31f2a,433599fa,7107fd9a,989b6091,ba2ec267,380c5139,47059d4d,2773109c,1afc21a4,3be54ea6,ad8f19ee) +,S(bbd7bd30,5bf1b36c,6cd6c180,2f41525d,75675d76,9352dc60,1a727931,ee6f40c8,3c3263d3,75bd412e,1d7f7d5e,72f73216,6415ef3,52d1fcf0,58e6c046,ceb46abc) +,S(acae6fb0,5d5b503,c2e3d841,19ce3bbe,1380b363,e5d8763d,3c520a3f,df39f7b6,6fab4b7b,daba880c,9167ae8f,5feb9aa4,3ca19f28,77ec5021,df36ac7,db730293) +,S(c9d4ba53,a44403b3,b06915f,6bd9bb43,4716a639,453797e,5b8e1cf5,abc78425,749cca45,6abc2a6a,4e970589,42cefba5,a2f55dc5,39bf4f3e,be5088cf,ae04bf70) +,S(3408e460,99f1a176,fd52f70,3c772f1d,a46d32db,246815d,a21826dc,c5657e61,a93bd344,de7afec8,2ea2842d,40fbcf60,732be8fb,738b8364,aaaab796,1e20974f) +,S(5e061a06,f97f61d1,5f66c3ff,17372621,4ce82af,3e606b4e,9f64fb62,e405376c,609064a0,bde996b2,d909e50f,726ed7be,b4698ec7,5e1c9c45,3ba18815,2915cb1) +,S(b12ca67f,739f4284,3a7adf58,d2a2f3ca,fd245ff4,b766793c,c79cdc31,45579113,b1deaf81,34f017f,b2bc20cd,da75fcb7,d219c353,98ee9887,612781a0,e3f3d1e5) +,S(95a72f2f,c241fa0f,c9500cea,d9cf069d,23820078,f61d4492,508d0fc4,34fc223d,832a3979,1fb9fd9b,79748643,64643bcb,b227c39a,e4cb5051,d136263c,293cd453) +,S(ab8ccb01,4b672660,b867e544,926749bf,7172a0f5,ac6317a1,a18b7d15,f039fc94,28471e3c,a2d6e77c,87700c4c,7e3df1e9,2fe91efc,77724df3,2f20ceba,1ba000fb) +,S(26131926,5261c0d3,ecfa9769,fa987347,1b9d4ebf,dccd830a,96bd160b,61b47278,dc9ab665,485133d2,59d7b604,5e1e4f52,9b099e9d,4db9f680,4935e712,f8402f66) +,S(87a4227d,2303f5c0,acace6e,96586b68,178dc65e,2c99583e,8e427ad7,167c4a65,5bce1d82,216355d6,5bbf33e0,9b3baec4,fb0befff,ebe48b24,cc01d454,7de6db8) +,S(a6576ea2,39af87ba,392a225f,bcec3045,8920b494,68c54ff3,92d2f509,519ce85f,deb950bb,6a767b3f,3603be36,6234480c,1851ae4b,1980f902,f8fec863,dfabde82) +,S(ed41c3a2,48285ad9,1642f6a6,feccdbb1,66298fa6,467b0ec0,ea256570,c8e343a4,dccf3578,aafbc34d,8ca5fb6c,b4482de,4b94dc65,a8d22845,ac800947,dc1042b8) +,S(227756ff,800f7eb5,4493181f,83050c32,9f27a35b,891a3bc1,ea5f0e89,b94e77e7,571c9345,e9e95238,3c7dc62,69aa0fff,46455825,a032f33a,154a89ed,e13a09c3) +,S(6f3b91f1,3f2d6787,454bc7a2,2ee780a2,3c251697,c0da9aa0,a03dcc3f,f03e2b0b,432b396f,c2dcd370,647eadde,ec058a01,53fac955,4b3f400c,435c4755,5e61afe8) +,S(aa79f0aa,767db1c0,3893c9c9,c75a1f8f,457f3f36,72c1d2ae,31e58658,a916fe5,4da2c69c,8033860c,14f8438b,8edf290c,5d02f2e5,153b68ed,fb945043,a6e6a1f0) +,S(48f2a720,df970127,2385a961,5a215d8a,3d41e0b4,ad439c9a,9d0453af,4699e527,11669dc9,26f70e96,e76178c5,7d698d05,b6e7da96,eef4e986,c4f6e6be,216f22ac) +,S(561d8010,a81a1191,3bb2436b,bbe0ce2a,6f1af6c6,fc064d57,59edaf45,c7f9781a,bfb2561,bc311bdd,707aee1f,af3d5c9d,faa9d564,a5121bae,9989665,b074f026) +,S(64d0fc68,6369a225,a15cefec,431fe434,1a424c78,85bdf2,51cccf53,9e266fed,694fdfa8,12f6bffd,b1c75baa,3b843d02,1b69cc8,20f2a8b8,69908a00,ac7050c) +,S(2b80d86d,341d05f6,218eb96c,fb227834,44bdcdf3,65cc3809,1bcba0ff,fa8b3d09,152eb516,2794fd0f,abf030cb,1968faa4,100e803c,e5b8046d,c36e3075,9317a8a5) +,S(62652ecc,daf7ff5,3aa255de,ecbcd653,7840a657,dd53e58a,514ec1bb,98c9b5b9,2a05c8cd,bcc4a512,1d2cafd0,6289fa14,178e91b5,b1fa1190,e4c7c13f,f50cef6c) +,S(f23fe7d7,69cd7bd8,5e0d97c5,4163e596,a0e7dce9,488e8f67,4ca6f3ca,81726ce0,eb1355f6,ecac2b79,dd299fce,c0f273fc,3767a3f3,3ac4777d,cb871a1a,99077e1c) +,S(91d4028d,1ea8e320,5718f427,b427c21f,4780a944,55ec46c4,2fb2a1cf,4772af1e,7a529f92,3756a212,24dcd316,bf9a3f6b,f5bfbc54,3b015c10,54ae51be,5c2e6b2) +,S(7a8fdf03,175969a7,80475dad,c43e5c66,fa75846f,63cfd62c,e82d2153,d185670a,b7b58ebb,fa0b2d3e,ec2a2638,accd965e,c7db6cf1,c847c1b7,9f0714b0,c1cf7dde) +,S(9d72d9af,5e9d7b2,7fb2b867,4aa35438,946c4ca9,eb9ea4be,e20b2eb5,e7cdb89,324214ce,d556acd2,3ac00175,f120d59e,50dc95e,96e6fda6,ff348bde,5ff7e701) +,S(33556ab7,bbf601ba,44dcb33e,aa5efc82,3c70f507,550f3d7c,22f4ba62,cf2d6bcb,a21d830f,233a657f,7857560f,c030f053,656aada8,f7812424,f38a2409,7505dcb7) +,S(e002b33d,93022868,60b39e1c,2820ad06,2063c344,bef98dec,3a9a0428,20e2c507,3133f829,1c81d970,f879d1eb,2128f21d,7540e135,31189576,191ac4bb,d83d99b7) +,S(9eeb1972,ffd49c0c,7982671c,59071b20,422a053e,394db993,8ef7b3d8,98795c5d,ae48763e,5ad78988,7a756827,4a17708f,8afdd8be,bc9c0316,73dd9485,319763c0) +,S(60f821e8,ad12907f,e445f049,141c7718,a495d1ea,3e39edbf,f0a73018,a5cb6854,6dc1b291,62b025ae,2a285e59,a5b406dd,927a743b,483454d1,20426fa7,50adb95d) +,S(5b8bcdc6,40f4a217,6d0661ef,f2ca5d6c,b1aa2069,557274c8,287fba59,dfd65a41,42ab52dc,cad04998,63e634db,ebaae018,c999eee4,c3cf05b9,4f18d218,23f21256) +,S(e764e748,4ec2a2ac,6843df3b,5316f29b,701b5191,778bda16,a23a20c1,69ed0cff,e1007e10,4ae52971,875bf7ea,9e9d9431,94c2e9b5,bc7b2844,7b7acded,de7d633c) +,S(37f0d948,48742a8b,e73ef1ad,495b88f,ea95f7ee,b343152d,85f9e442,771a22b4,bf960e80,467cf81,bc22380b,af2f57f0,d5938ccc,55f3f691,784be72,7fa68bb2) +,S(7ff13c43,7f2189a1,18b2095f,be268dfe,e1375a3d,f71e88b8,4cf5b94d,63b04612,10295e49,1f0a882e,aba663f8,f0202223,21c422d5,f3b453f4,8ab8bf4b,4319930a) +,S(74f6853e,f4a2d018,4cf113d7,62fe2a1c,33ff2729,5414a5bf,3f381989,551ceaa4,629f116d,37c1809,f4e2ecfd,19c2627,6deff6c5,b89249fc,d4f6e82e,58eeea79) +,S(d54d88bd,abdcc56,c1bb8cbf,cdaea6ac,16949256,f78d70f6,7a1416ba,b4cf51ce,996afb9c,5b36f588,812bad4,95c368da,f9e96035,4bb7dd1,3f457a6e,da159b59) +,S(a860ca66,3ecd7482,c862fac6,f6a7b0e5,f5f6bb26,ee950db9,2942fc89,4b6fbacf,3445137d,2047c17d,65b3cb88,8e1b0ba3,619db023,bd989a0d,c585a59d,14da7b9f) +,S(d794dc2,4e0e36fc,6f38fc8e,7a68cdac,8d547d42,b9667241,2dd7e6d2,c40f9aab,22a9a90c,10f1b80,e277be34,3c492125,24ebc477,1f838070,f2be48bf,cec3a7f5) +,S(7e28db65,2115f5a4,575293c3,d792fc97,9ea1adf9,dac468e4,60e5526f,6847657f,8025944c,16a12ac9,25e67f13,3835bcbd,33c338d6,824b1fba,f0ee001b,d79d66e3) +,S(d3f13a27,524f0c87,266f3d46,14d965a1,3865df67,5d20c5aa,99a4411c,dc6322c4,9a1025a3,845a4bc1,9f7cc175,9377c7f,e46ecaf7,53263433,baed836f,77e2e841) +,S(d845636c,db18d557,1759f6e6,bad6a60d,3a67141c,b0bfbbf9,33e628bf,8344c053,40de706,ef833427,80e5120b,ec6e61e4,a8a3726,32818317,729e60e6,3ab7e37) +,S(f40f53fb,c672573b,c020338b,71589d53,3709ac32,b38cb943,ed0ca0ff,e592e552,502145c,5f542a77,652a4ab7,d79791cd,e92f3e72,d9d0190a,2724e114,49b64e0b) +,S(2065a8bb,a0d61dde,921a0741,21ae5678,8766f712,bdb3c4c5,776af9e3,774120be,fd12cac4,a85d5b10,1aec6ee1,4b1301a9,950df948,86427be5,55f52736,3ca29847) +,S(a9b1e8dc,410466c2,df97cc8e,bbcb3af5,f981726c,2daf8803,ef06ef2f,a23e038f,b09dd4e2,77b1d10d,bfdd06e1,a42baf37,a5157017,ba026d98,fee13512,4a1c5419) +,S(c54ce1c,bbfa3808,f24b2661,793c3574,a58aeb0d,128d7e5b,ddcd98a6,d8c9bdbb,c1a2291f,d20e8a23,f4012b54,37a7be7d,5af5f776,bdbb2c53,193e07da,bc1a3212) +,S(41ad2d03,31f57724,6476d0c1,f2c46216,6156296d,8bfd3783,eec40892,835ec421,62777bb0,f8b6ba08,128f1727,9c237286,abc5d2a6,492b9c67,3edc903,7b0e3008) +,S(a8eddde5,eb761183,ef5cce4d,a7958b92,db28bab8,2f695fbb,597f6535,50048a3c,7f60d3aa,95ee5ae5,f4cf10ac,cb5729e2,bf89ba7,6b1070c7,ba385f41,a5912685) +,S(f1db8d40,2cee572f,6eb250bd,ed3d978b,1346ce96,d65291da,977b42cd,36bd073,9bdd0bdb,a546ce4d,774f79fc,3561c0fb,ca11f4fd,b46ab1c2,a7520913,f254f42c) +,S(55cee66c,7ebecc0c,7f22d03f,8f166b99,ec7b5e6a,776bcf60,b5f4d452,c861bfc7,772832cd,55b13c5,890c7ba9,96731ced,5a2e1c05,6ac89469,320c08f4,43159d36) +,S(61427868,7710db98,d4347d4c,aae4c70a,9efbfc7e,bfeffe5d,6f33bddc,4aeddedf,fe8b32bb,d0c7a7d3,b93dcb7a,99a5cc8f,e386bf89,7dcdcd86,ffaac641,6550dd85) +,S(9f3ac763,c117bd99,658f5379,119aa025,cd422ed3,b1ed2cc8,545d6f93,39baf4e4,41b2409d,cec0065e,4026e879,84b99d35,4eed93f4,15e8981,256e8734,a4eebb74) +,S(8510bf74,8f5255a1,8f408565,30f909d5,2bed111d,6347da9d,8da2a97e,751d4a98,2ed99b6,6af7cc01,37329730,1b0b63c9,f8732547,fc632eb7,7357e67e,df5549b4) +,S(d81fc0cf,9646ae0,7dad1a3f,e06adaf,1d3508fb,13af2309,c200c2e1,2228807d,cac833d6,c94e674c,a7aec186,42e4a501,ffbfed92,dfa1015e,c95740e6,57978cd5) +,S(32aa5e70,972a899e,e25e6c6d,e43c32ee,df07ebcf,e5ed13e,5095f7c3,3bb55622,38e82901,990a1e42,38639a42,66a93fb5,4368df0e,befe19a,7f234424,a8b68c0d) +,S(68f7b02a,ea38424f,decbbfc3,498c6193,62c732a3,b048800c,85d042d,b284f7d4,bef680d,90660176,f3d3d009,9f6cf818,a277dc5b,3d765a30,b7a4ee9,cf3bd46e) +,S(9437ace9,6b566bb3,87d9946c,2c32c06,f62f1158,dead214f,2b721c6f,b6e8888d,f8dee3bb,331e1e33,9963b7e2,316a1352,c8748f42,44463ffa,5bf2265a,243941d5) +,S(af40e909,85e5ce8d,dfb6d6d4,222d3c57,2ffae40f,53de2c06,55a74cc,70cd8dc5,2f08f237,3fc922c3,f0ed9d6c,b9538f4b,c661ccac,ea2f4975,50f47ec2,17d8e626) +,S(382e5a07,f1f236d5,ca1a68b8,f0fdb813,29e0393c,c375df88,f87914d,cef93c64,e24ee731,c0a88fa4,8ed3dba,87e97096,e0ec2224,dd657411,a9f1a9e8,2b0a6657) +,S(99fce288,c6ef1d18,ad630097,8ba82dd9,1c779a60,b266109a,288d51c3,978fe565,294c9e53,3cd42a54,c071d5c8,acb7edc9,897db8ac,d25b5f10,9eaf8dac,42a9c1a4) +,S(748326fa,c8dc9394,2de0a000,933dc18c,6ef92cfe,bac46939,f4405d89,627e6727,adf2d561,45581b4f,e706ccd1,8dc82bcc,14d76fa6,94ac8a61,a51d06d2,89e36d2d) +,S(43fef689,67074a2b,7e944b76,8f8b1ca,15aac3ad,c8f5590c,f1f02c3,afa82e90,5313cf6e,8cac44d9,fd548032,dbef3ab2,26e93880,644468bc,799c87d4,c0bc3f99) +,S(404341da,829f537a,c425050c,5ba93ca7,baa8a8b7,dfe51c23,e2ce7c72,43d57659,f91a0d59,bc35db64,b250adca,3cfbbaa2,2a82cfb4,d684e8db,e17484ee,af009f9b) +,S(3af33cb6,b4d553e5,50fd35f1,a0b569e3,eae05737,7b7d735b,545f7f00,d9acae67,42aa2cea,deab8cb3,b1ee9c3f,4b1b06df,e157cbfa,3912035b,585980bb,cf85279c) +,S(2e96133a,1da8a378,c138583e,86ba1de2,3450b285,3559a431,654ec9aa,1f64229f,3bfa5a75,4dbd936d,7a41266c,97472020,6cac86b4,d684bc1a,59dd1f27,fed8e76b) +,S(adc4b672,69fbb719,92bd6e22,3cf9ecb3,c9388b5c,45ffadd6,94c72e2f,b355984a,ed177eea,ac8cbd88,2a368fcc,4908ba4c,8a4054ae,3411d75d,b06939cc,72522a7c) +,S(68ac3244,49eac1e3,df997282,65a0176,bf6c6115,64daf79a,135bc6c2,5578b6e,407a75bd,b1e5e6be,a9b815ce,833c0be5,f5c462c5,c71a086e,59fbe0d2,5e7b1fca) +,S(5176afcc,b4235cc5,ea41eaa7,b657a77,bb383bf,aa71ef8d,d33990b9,9c2acab9,cb363792,9d249fc6,1c0931c,8a27dbfa,c8371574,52c40306,c3291814,ceb57095) +,S(4938cd76,e1aa6b28,2a89e883,8671e4e3,82d7bc76,dc4653c8,46323cd2,51d18542,2bfe67eb,6da39ea8,c8160621,158eac48,550c3730,664590a2,731247a1,399bc42f) +,S(9364dddd,dadbaa52,efc81971,75041c81,e7ebb48a,f20b82a8,125d85fb,a7fea192,ee568f7,53513b91,cf6720,2c45c4f4,181e855,ac0300bf,d7de30e7,317a6ea2) +,S(bdbc0937,243e563,df29781d,3b14d4ac,a664fe5e,70f3d9c1,39ef1b69,57839156,2a84b153,549c6d1b,27dd9ac2,1ab86f34,9ace0619,6f814d08,92a1958e,d137bb1f) +,S(b616b635,adf7b64c,43c4e242,32ffb330,bf28ee8e,48918093,9584c26c,28c82f2c,27fddaab,e5d47957,6344022b,68744822,eec7b937,d29b0631,93c7f6c5,6385cc89) +,S(55a3849a,50606886,abf6f0a6,5a3e657f,46031cd7,4c117365,8f27aa14,326f3cac,4a522c0c,17fcd116,61b11d9b,f88e0ad,c7a5761e,e01db8ff,a7bc3dca,a7976b00) +,S(d53e472b,439dc5dd,c8ff479,ff678dae,95b2e207,c92df108,728c3783,f8818542,3f3f7ecf,df3d9f89,1c723161,75a57931,4ebeadab,3c4dccf,bf2b834,c762d30f) +,S(1e27dd,f6186285,41f5d8a1,6587e2a4,ed38c34d,8393a6c9,fc0a7c07,cef36053,280b223,da8d01c2,12315c1c,ba7dd8d9,96d3202b,91c4eb4b,26c802e5,9494378c) +,S(b6d9d97c,64ba01fb,e8a9d29b,806d8a6,42413bfb,fbb4ae0c,10d8fe52,7ae6415d,894875dc,d912f8fa,845614de,a2b09796,d402c738,ca1f3c9e,c0796681,d715b8e4) +,S(2c97985a,5fd96164,e4c4d9d5,9a9fb52e,b2e6df0c,77ed4745,3dca6eac,7550756a,b3526bbd,de58e408,a4f45dd6,61f5c6fe,2f82d2ca,3e2172e1,c99d1fee,93d44c98) +,S(405deafb,528991e2,ef924f55,b7e4dfd8,185de449,cd6f71d6,53025999,4caae657,e959b7e,59cecac7,f813dc1b,a15bb71b,4a4832ca,54026e18,479d71d9,191c3ad) +,S(4276ecae,a14c0556,b4573b26,dba35226,4fff2c3d,12a3e4a8,4937ae9a,3f687bfa,7611836b,d3b335b,66f92914,6df0de13,d6ecd47e,88369ffb,6c9aa493,e67dfc71) +,S(6fd734de,6d2fadcb,d7b19f56,ae7153d9,1ddb396f,e0c1e51f,ae31fe80,8a35556f,aaa647c6,92865772,f31fdc1a,3b430ffb,e1647e10,3cd5d629,19bcc905,ff7ae633) +,S(4f0a22c,ad6ebf6c,e6b444dd,35a54e38,70017bae,eecc14cc,3f7ca88a,6d4e27c9,1386d40e,680060ca,bb46d678,d2be7209,418d6f72,d3917e20,7b833124,29b43ea1) +,S(873ccb39,5c10f57,6e50093d,44879f2,687d9321,441d8a7c,993c1083,ae7b0570,b261d029,dbe15f4,ff70ee42,36f558de,8984db4a,608d45f,4e28d001,e564c5e2) +,S(75d41857,5be3709c,5c732073,24f36089,b87532b8,e91db4e6,70a89117,9d25e039,47e29f54,fa62ef44,139db763,4b1c8f5c,e027b0d7,e1ec3501,1e8c6dfc,dcd1a105) +,S(b325bb90,cea81ac1,c79df75b,e7615ace,9b2a9d4c,fa1f4504,1a47e0d4,30b64b67,3024fffc,2005699d,5351615f,baee8c49,8a319a19,45ac8132,71c609b4,23e14a07) +,S(436c92bd,a6c7e124,5aaffb22,62036329,ddb8984e,624f2469,b30fab18,1269ee2b,2a9f90d,88c01880,62a152d7,e7ed5acd,33f12e92,4e36fab0,bc0602f8,2c1d3e3) +,S(c0105c64,4e51d333,c7ed28b3,c94292d8,6d9c04f1,89b3827d,f1f22fe2,99bc51cc,d73bc012,1233ba52,ef9727b3,1249babe,bf63cacf,ece0192b,5cbd618c,c48a9d35) +,S(9f2a01b0,46109d49,d11ee109,5e94c281,1cb6f76f,7773141f,632b3a9,2e5f3f7e,1e260290,fda1caa9,ea315380,781f633f,21c90765,2815251a,fa70b169,e4b0da58) +,S(4d805499,23dc1905,7fd35a86,feefb937,f2b621e,48946e53,b8390620,3aef584a,2cd9c060,d66be813,12a3fd9f,ebb9cbdd,4fc23431,c3e0531f,4a026f50,a40dbd30) +,S(76779423,b5e5acad,55137380,276c4033,a865ae5f,9ada0f30,dee6986c,444a1526,9a6fc30b,4f4c5093,b343c8d1,aa204ef3,7c2a6d5c,712ad8d6,39ef545d,1eaa9a57) +,S(1ccc1998,33f8b121,18227adc,2f27c3fe,8d328b26,684b271e,85f8368f,40378881,da21e917,94851bd5,a8859173,830ddd0e,988ffdd7,f7dcb263,f6755eab,e2d73f75) +,S(afeea14,e8306fb8,e69689a3,d12efe72,949b6b03,8c4cdc70,c95bc351,1f999030,cafbd04e,79378032,47c71954,d8c2a11f,d60e53b,35045507,8f6701ed,621e7d53) +,S(cefa268b,e551b02f,8fe50481,44920abc,3d03d97,3f2e9368,d2d2cb42,341c11b3,77440b02,64eb1972,91d2d69,ebdc1de7,66915a09,aa01615,e4001d62,7219d491) +,S(8625c163,58bfd43d,888ef97b,e33d9938,c62f7f2a,9e7b9735,26dd14ca,7c76abda,e1351920,59085272,3ea7b55f,49c4045e,2dda5ceb,c1a31841,1b6cf38b,b97bc1c4) +,S(43b8caf5,d4f72519,19630044,13bd459c,f5913edc,ff303fa6,dceb3412,f8e39c2,7d1df179,13186dc0,d7957f61,a3232180,21a6b50f,61a86f33,72623f5f,d3dc1a11) +,S(163fff8b,cece557b,6fd77b4d,e22e5b55,a6ed51a7,76dfe2b1,362040bc,9e7e4fe0,29204f73,5bc6428,3c510e0e,2192299a,7f6ed56d,1a0cc569,aa37f895,c0c4646a) +,S(fdbfcee1,69aa6724,b5839a55,e1c54856,86503b51,d1320b37,dcd9af73,2bfc4497,d7f75ba3,7af2f969,31bfa612,446c6807,a207af9a,17269199,77b0d71b,16b11a0e) +,S(f1981a9,aa585d6d,102b3a7d,e3509e0f,ed002866,b379b4e2,ba9d175e,4e5879ee,bad6366b,71a7cd67,163b6313,3dcd442d,24f9362e,5d0b9791,2a8dbfb5,74517e1a) +,S(dd3de17f,1cffd240,424096cf,effcaeee,87bf4d30,4a41d5db,6953102e,4b91853d,d136d363,1b9b968b,7c7d1a16,b2302e7a,7770e5ce,afae92a3,8f6e1299,6fb04718) +,S(b1d95fc1,4e35f77f,7e64f62a,36b26218,86397228,35ccadb8,39fa7d7b,834bdae3,75611c0a,920e0251,345b3213,422959c5,ac66c495,14d50c35,de7aa7ff,2a330a6d) +,S(1eeb92e6,75f25a35,9ed16c8b,51a5c130,d2210c35,ce954430,ea2cb3a3,af69187,cdefc1ac,40fac4de,e42ba496,eae80bc7,680e214,4117e6da,c2b3bc12,ce9eec45) +,S(aeef491a,fabae168,9d58c2f3,808b22fd,760e8607,c043c10b,591ed211,6fbb5ce9,b0db916,30810159,7e79aa7,82d8b643,d739bda2,c45ee36c,4f328108,4e55a33c) +,S(c56793cf,822c3da5,300c6c2d,cf06b5ef,413d51af,633ec77b,b9b68b1d,d3079e43,a423e25e,1eb466da,f521c5d1,6395805f,a2da609,fcfcffc1,2728add5,61eb2c0c) +,S(2aa824c3,c8c648eb,8bd0c151,b30452aa,c097bc38,a9f53db5,a8375631,25887e06,20aa4bfa,3bb2c5c2,a113299f,6c61102c,7586deaa,938a33f8,4a517dc,4ba78ada) +,S(4a0bb8dc,1833942d,9ae3428,ed493cb9,5716b50e,c96db120,c18ccac4,f6c3dd9,d0526d5d,c8be139f,53427e50,17cedc51,6b4960ac,bb98d4a4,f07fdf26,640b78b) +,S(2808616a,309b64c1,5d061adf,ae65711a,a561f8b8,345132e1,5b18fdb0,e476240,d2190f22,7320a55e,ad2dc736,671db631,9b18d6cc,b4d2bffc,cb4b692f,74eeaa0c) +,S(3dc4b015,13a95221,32ef431d,33435ba,8cf9e6d7,7e4ac75e,54848916,c23e7959,eaa2516b,9b13bc99,1f4b8ba,fa90a6dc,a007fea4,e26fbe0b,a2c5d1da,326d5420) +,S(473f6157,50af1d8,839ee0d0,eb5dfb8a,c14ce65a,e04e5f03,99fe8666,bd6efe6a,18d204d9,1b27527c,50823d5,222c4e4c,e3e193e5,a282daf2,75d2b43c,ffba8412) +,S(3b87175a,db1a5e49,1cf7565a,28250c51,9fff906b,ef0eecb,e8e50a7d,a190aaaf,fc58f2dd,16f1a5cf,1a728117,dcac3dbf,3a3963f,3859a518,2616b65b,59e96403) +,S(12f1b577,1410d1be,d0c4863,360e37d9,d36643d8,e0cf6fe7,8770478f,504174fa,be29140e,6b5a40a1,40559972,7e0727f8,ca904c3b,813897d2,bea089d9,dc2f17bf) +,S(8658f35b,902afb85,408280f2,3b4d98db,9526b57a,1e6cd0e9,37d8c629,ae174a3c,4060349d,47a69720,7d29e83,d8c82197,d32bb9ae,8c83879,1e09a7b7,1c3e7c28) +,S(530545eb,526d9657,2ce6cfc0,22e1c0a7,b9965c7c,3c2db355,cb5d414a,6c1ac8c7,99243b26,17f8ae2,898b96b4,1c3c65f9,96a9f8f5,83ff341c,671a2d5f,2d04637a) +,S(2e808732,bbab8507,e65936f3,fd1d1662,91ada8c4,c0d865ff,849e0a1a,5f08d265,96dbf7c9,53fd2f61,7e149f06,89b66431,88b091d5,1227a1a6,a0ebb140,18a79fdb) +,S(4272e028,b4b9c90c,44526fe6,b25f5e84,4b8baba6,34ceb2e2,33447413,cd5bb35a,6b4a4076,fc3706a7,50b0c824,93f5e363,f9fcdb64,9d683a1f,fc3bc2af,fc8470cc) +,S(78712f3,449d07ac,7f8171d5,42ee8b40,4761e054,eb0362c8,3b30cd52,6f9ac60,c7ff5ae1,38ca3c13,79457619,dd76061b,7b59778,79db2ca1,5b07ea47,7aa41bf7) +,S(be40166a,60ad9af2,d1bdfc7d,9b0660c1,640d4f1b,640ce485,8fb22eda,65d15a21,78c49afc,1d992bdc,b70bab6d,d3619305,a32fe90a,2f2b1b43,38d77c80,b208cf90) +,S(2fd5831e,6bd5a79b,35bc75f,92e83e4c,9acff5cf,61eaad7e,dacb149f,46d5e6ba,82f38222,4b6be0f2,f52318eb,7fe44a4c,4c0c1b05,8eae3f99,dbdea80f,a70ca3d0) +,S(32fc3fb,4574a651,472e0328,c15a71e3,bf9a12ca,15d341f1,c5102dab,2ee6de37,7e9398a6,760df809,e5eb57df,8fdc3234,eff1aa8,bef57008,c36e7953,c07f25a9) +,S(b9018d98,3452e952,7944f2fb,3354487d,a82f8b90,e52689d4,edb2a91a,a8faa6bf,e9cd0e4e,5c5efcbf,9ca25cf9,f271f9c,a2c46b4a,322cc966,e7789607,324348f8) +,S(a74ba662,32afb3e7,d5c22ad1,c792da33,f1bc88dc,244a8ce5,d4d582bb,b16ced23,444c5512,b49c2c63,4cc0328d,20f7321,a88db1ee,6d525be3,5d2de8df,cc381377) +,S(40f6df83,6d5e8c94,332174e2,2fa43556,d06f48a8,f52cfd69,820c2c46,2185dbfa,852c5b98,15ba4ef0,18f5d231,195fb62d,afafc08d,fbf9159a,eb5f6063,ca353424) +,S(e05800f5,f7890a14,6bbbabb1,27924cc2,e33e3c81,eb88606c,6bca020f,1aa71747,ab905ec6,3af1bc11,897a44e,89c2c2a8,3fb7255,c0e7f76e,8378e59f,1289158f) +,S(7b75dff9,a1afde87,be8528f7,9df63d70,e4df925b,a15f01c5,8e8162f0,89ee735e,bc057ff8,bdc9e37f,554a6ad2,3ebfeb2e,5d64adb7,69fa0082,2b2d4902,ca82712e) +,S(2fb81423,3b01e312,7ceabacd,a9ca518e,b1ab993c,bff855a5,20a96f52,afa9a0cf,a7e4bc57,b53affba,9e2cd875,9665cd9,215fcc,35dfc402,4d1db86b,9605c4b7) +,S(f346a33a,ec17d0e6,a10262f2,fd8185eb,f80a1fbb,f6b06bdd,1c04f18d,75dbaaeb,c09caf81,120586fc,33a6a0bc,97ef5cc7,56d20806,1340a1cc,ba9955ff,4a059e10) +,S(d128544f,a5f5dd38,62a759b8,5d538baa,63d112e2,f8c343a1,1bb3b8bb,ebf548d8,7893faee,b73f0530,bb67e8e0,9c2806d7,e303dd5e,116bc9e5,93e4dcdb,eac031f8) +,S(69046ec4,11c06822,59de20b1,a2a8f84c,58c56765,2ddcae,a26f533a,9c706f43,c17a9640,adc07d61,4a264ffe,272cd686,99b9af9f,6890cdc9,ac02c761,637dda8a) +,S(7b50f61a,9dd7b9ef,7af49c17,6ca5555f,eadf3b67,90998365,29379dd2,a3c85b5b,c08e18cc,bea8a970,7bc34d98,6b36475e,e2e24695,2304df65,bbe0347b,6052416) +,S(794a9728,9db4743e,c91a8560,e430b14,a7d8312,1fbacfbd,ec37a9bd,c749d3f,c57a5b9a,f0cb23a3,5e9b092f,386cda86,bf2f8242,1f74dfa1,837047c3,ae0d2235) +,S(fd8d1485,3d2fa064,c4682ee1,1c319a8a,49fa9b23,2cde9d1a,9a44b2dc,93b2f251,8cc4001d,f0121ce0,ad2119d1,7aaba363,ec45345,87fa10b0,c94a5043,f641b91c) +,S(7b5fbad,8105fe06,6962a72e,39a9a4fb,fac27794,e39a6660,133b9ef4,a6877557,b9b4c9c,1200d879,6013de67,958176c6,dc04ef69,b1021057,de8d3b40,564fbcd3) +,S(2c7ffc8b,40eda03e,20e64678,68959141,c66f01e8,b7cb050d,c60e8a48,6f6e41f9,cd0f3510,39aed3c1,56ae2b0d,1a117f78,c14a704c,992db297,60d22700,2f71ff7a) +,S(79533078,d81a6fe8,446dd750,b59ecdc3,8904f13b,48ca89a6,5644aa8c,9233de64,d7c95bff,77fa9894,74634aab,3b8f86e0,ee0bf92a,3a338fb7,f89881e6,e1fd746) +,S(be96c5e5,d3fb03a1,801a7760,16bf3824,aa16010e,884359b,d5e30658,5f13b214,d156346f,158d0c1a,2ef96a95,86cd8d34,20be21de,6997904,8299744,b40a5d9f) +,S(165c53d1,9ac89139,c063d934,511478aa,bc296cb9,7201dbca,fea4cac2,16a4fa02,4b002644,1e6f1369,d3603780,f33f74e8,42a812d8,b4e7ff7a,4aeea468,35f67348) +,S(508fb72e,dbd27f3c,76569185,a18af8bc,6242462e,cecffffb,3352ce3a,da5ccb5e,e1698f3e,1d53607b,4911423a,f2167466,a473a8f1,e2226849,f4dfe551,dfd14652) +,S(e9be0fb7,8e95dc1c,7b79f4eb,7976367,a85034ce,ea8642cb,19106dad,1d10ab92,b7867a7f,51f89779,a32a7b8e,273f9659,fb84367b,90ca3ff6,afc2cdac,7f596c45) +,S(e6ea5e6f,97116554,2de16c66,1f15d6e1,24aa449e,960b393a,e5337de1,d4c94800,bbd62bdd,1c235fea,60be143a,9155ffa8,204a1b11,3f19f4e,6e683c7d,e234ca7e) +,S(ab3f8a0,5b8f5ff4,149a390b,a858092c,9653d159,6d84bbc5,6e4a7a8b,fd54d7e8,41008916,311de07b,16c1b49,c6aa65ed,8baaebf,7a4e75b1,5aa1bc34,37483e53) +,S(515e02e9,52a347e7,5e0c5eed,a266242b,48bf33d0,70048562,c20feb3f,aecea1e3,797b3ef8,f6c35440,58517c56,ef5c6464,fcb63353,2bd6d2e2,83487a1d,8a403b36) +,S(520cf598,b3552fe0,a42438f8,55aefb81,3a3e10d3,f4985998,492e06a2,42ef46e1,c69de50e,2bf9658a,40567066,3cac0e4,8c8d2920,95ac1df9,9535b7e9,209324ed) +,S(26a8e655,4a2cf338,33bd27fb,d96880bc,bcc1d360,2a76920c,37075790,1c50bb1a,ba5a4560,5ddc5236,2a0d09df,3247a507,9c87e652,c4ad35f2,e19ecc9e,ec1ae4af) +,S(bd06a5a2,362ac91a,759dc578,dff3a3f8,102a67ae,a86ac11,5ddb2e14,bc1bba44,e8751dd7,153537ca,eec17988,98337cd2,abdfa554,52c597c8,61c364dd,78f49de7) +,S(ddbccf92,da0ab07a,e99fda1f,4a03927d,66b0bd21,f1e54fc5,afd4f329,35a0cae7,26fc18c1,52755bc5,d68dc3f2,461d60ee,b4dfc02e,a04b4779,6e7725b1,23acf8dd) +,S(650e1616,2a30c776,b54130c9,9fbbf567,32e2bdde,f667b09b,9b7f25ed,93c0737c,14972f76,429eb04c,1ebb0583,8c54fa0d,309fee09,a55d7eb3,700be0df,5801d56b) +,S(2920d280,41ad7365,cc0e33c8,7a3d6f3c,f9fec9c3,b00e5698,55ae3b83,8cf08973,3821fdd1,fe36668e,16f2cbd0,b2704fbc,24354f08,8ba19a1f,67d1b11a,b70c2d68) +,S(3842fb0f,1b26bfe7,535c9f5b,cee85ba5,6cd491dc,346829a2,a178ce65,c5294302,8e02342a,cb0e1233,9e638018,a125622c,5f66ab52,86a74a6c,28982c25,aa3a0fe2) +,S(9c21d89f,f1142d24,1e62c1df,e0481268,c2273d01,f153af5c,d31b3514,5b9b41ac,f5a924a1,d60e1eb3,72837535,4e252740,593c96f4,87328e9e,2a80cae,15fabdb) +,S(59320ba5,c9088701,f354a3a1,93391880,2829ce91,be9b4c14,c9018fe6,4fcd387a,610e48aa,705e2e7f,86a6a12a,817984a1,7bc60f9b,abc0ba9f,775f3446,8e3f3815) +,S(d800691f,83c2903b,1add209b,35d796e7,15b805a0,9bbe6120,3bf68a08,a13c46e5,21d194ed,bcb8bea0,cc35a9f2,328f1689,cdacc58a,73f65a28,56811e54,d96e5576) +,S(865588f8,66c21986,7b9643d8,7f1215fb,90fe186f,46478e8,522a5da6,724f6e8f,91a6b315,a7ddca8d,b4ecfbc3,9b55eb81,393f4c51,f573fef6,e7ca0c9f,cc551e7d) +,S(9dfe808f,cf7f574a,ddb251c0,4b053d00,8915f8fa,5a975479,d43c719a,b67aa4ad,4d40cc00,ea6720db,ff1f1339,7bb26c0b,281686a8,726fa430,bce0e4e4,ff01b01d) +,S(835f1c87,cf8d4420,72728601,ab6aef63,cd0d73a1,80f81f07,f5d57cc6,bab5ef7d,bac2d1d4,c8541f65,be0644c9,40a18f7f,d2c30360,2083a455,4d70a111,1c5bf07c) +,S(9562dc71,33c48e4,b46d73ac,d42db4c0,b0222c4d,dcd0e76e,b4f84969,348fa46,7cfe0965,96f691de,d358c00e,a292975d,465ef064,e9437556,40bc1d4a,33c3a0ba) +,S(21afe3b9,4237473c,dc032588,c4c1b7ec,853987a6,dcd1fce,2c48bbb6,8d0f3b45,1751c5ef,674cf88d,d5385943,b40a20a4,6d20cbd3,9876adc4,a4a4bba8,477e78a7) +,S(89809c4d,572cc5c1,2241ae09,fe1cee6f,71aaa292,c9ff8d6e,c3eb8a92,8e144ebe,462c023e,1710ed77,bd47d22e,e222598c,68cd7c56,b004369,a9356a47,ed6809d) +,S(b7c6164f,b9e175c1,5724c596,988b496a,b9f5b0d9,dd45d0e6,4a0f08cb,9000e3e9,1a13e8e5,a23b40a0,aba44bad,5cb4d37d,a6061157,aeab7a0d,d327242,ab2ad11f) +,S(62088450,24eef2d5,4fabe8f8,fabf519,72908ac3,23596378,c377c458,9719bba8,26216b3,a353295e,a1877547,b826c240,351f227e,293abcd2,e3967fed,30391f5a) +,S(dcfe82df,4049089,f3f8b275,120ca438,998fb22f,e11d40e0,9d09c4ce,c12ad036,388f9754,39b1c412,10014136,c3b58fe3,30ab524d,d7d3524b,37ce9133,5cb3bf3f) +,S(324ec5b0,12de7919,2f27f5ed,166344e1,934b3527,2b197d28,9a634044,5dd4bce1,99944794,579e12e8,c5c0c11f,a8eae5f1,88cb8cdb,3ce7814c,f89e3f1b,a3d3de0f) +,S(b3a70b0f,af96cb56,7dc4245,13ab7c6c,bbc38634,faa0c286,b81b9754,454a363f,b507745b,97843c90,170f8ffb,f731fee8,4532c1d0,6b2a077c,2aba5d94,189545ed) +,S(c4a6ff4e,cdf1ac83,29a1cdb7,b5165d88,2a1f1823,d1c38006,1b53144f,56187fce,6f7d0fc0,c08a7ba7,386f9a59,330996ef,b13d9d21,eb6d3915,4c8fb919,66159919) +,S(61d9ee96,1ef58634,5c4a73e3,a8c3df82,eac28aa2,6d740cbe,1833dcf6,d5a38811,c9e4a482,1700107,f2d4af3d,fcc74e68,8123b589,4da1c2bb,1fd926e7,11330892) +,S(67ecbd0f,4f4fe300,49390655,5289c9a5,cb6ac090,dff38502,75f7751,a84c6172,e422b1dd,10467cfe,921028f6,71cc75cd,2be5d8a6,75e644e5,d3c40b3a,2836726d) +,S(47f6c669,70898fa8,16dcd4d7,4553c644,2ce5bbe9,cda91324,ee3bba7a,868ff0f7,e56b9590,838bdfaa,1c2be1c3,95f775e,4a0b3982,d0eee531,26ec7ddc,9e3f77a6) +,S(e39ec9af,c8dccd35,4b155dd3,1d1750cb,ab096807,f89c8afc,fe61e6d2,e348cfa3,df3fca08,99158319,b93bac62,88c302f8,a59e175a,cda9fbf7,6f0ad59,8358088) +,S(2d1aae84,500037f9,8e08b64,341eab03,e0f1cdf,5a079b46,738746c2,18b3a0,747c23ac,8173adcc,de767d2e,ac156384,ddf40797,131a6167,c32486aa,12c89e5) +,S(ed1bbf04,d4570df5,8f584158,1fc47665,481ebf59,cb88322e,497d128a,678c2b4a,a40765c4,772da2d0,b3c8f107,22ec3931,ab3fc8cc,c28b003c,bea1a0da,279c8fba) +,S(bcbc3e1f,7bd268,93f377b2,eee4b76d,49a8a603,738de309,5353fde3,deff55f3,fb697a08,2f2570bd,1e9e4ec3,fc7f6c81,2a27a7e6,f7b8a53e,30da80ef,f59ef2cc) +,S(4f98b2d9,2f0b5d57,51ed3784,94cf4de5,65cf632e,982a270b,2746a5a6,3da9333d,43857e7e,437bdc02,6dcdbe68,d056784f,a2cc606d,7ce09a0e,12978a74,5b67e529) +,S(9dbb995d,d0667371,1731bf05,c8029035,2b413411,45318de8,2236df5c,87728582,c0a90e4c,6fbc0665,f8cd9fb6,fd59ea3e,f6ae9a16,9bfb71fc,5fe73e3a,4d665f86) +,S(83692208,1d099344,3d979c51,90940e44,5465624d,3a945c05,7885cd00,5ce6b9e,49be5e40,2e1d05e0,67b16279,855bc1de,6f0d8aad,35d8bc0e,142dbe87,33a14e13) +,S(f713e920,7a699b68,12d7ee9d,1475ba85,a6c56af2,8b73ace7,cf67ed6b,55650e97,a5a2c2a2,45012812,29fc71c8,103db717,48a51f88,61765d31,4b9ec278,3d0aab45) +,S(919f2d21,256ae682,fe514320,9c6551cc,d165de1b,8213fdbc,9c06578d,ef705725,9780da96,eeaac4e8,c96f3d6a,89c222cc,9b16b4c2,e8faad4d,96cc0136,a06021d3) +,S(1738093d,197a5ce3,cedd1fa7,e2a8ff03,959a6c23,6aedf9e8,9dbd74c4,d82b6e48,74363112,d16b829,d371a0c,f1b3bcd1,2000254e,196ea80c,a9d46570,1ee4a1d8) +,S(41242a81,35811b36,d4ffc40d,bbdeaa7c,cce36135,3c4fc9f2,d23191a4,b9c46379,7b894326,789f3071,374983c7,cd2a5ad7,e0ee49c5,e740dd33,817a31ed,97c388ba) +,S(894a6ec9,96eaa8e0,9e077b34,7b4f1e1,a387c930,a526c469,aaefc0c5,402d41a,a080fb43,c8e6bc6,388fa766,2398e096,b65032e8,26c5a9a8,47793924,4dcf5e41) +,S(a71f2131,3599cb7e,8c1058c9,52a5712e,661d01d5,79bc7ee5,1fbadd35,34ca5d5f,afe5b47b,663ebd7c,d788e0f,d3f963c9,ac63ee24,b7495e61,4a5d6553,9ab5f859) +,S(8f330e77,82eb62e4,4ea389f5,7f1c58b3,458c5d39,127d9783,6ddef8c1,27fa390,894e6142,bc359171,999489e1,1ed08224,4a46100,136fba84,e2b8732,e9bb626b) +,S(d2f0700d,6124c46f,a64cb709,1181cea9,34fe0406,21267334,c85ace2,cf05fc6f,8dc30ae9,83a95b74,2d800490,fbd8c290,bda64daf,f82d8fa5,e69243cb,43556cb4) +,S(c2478e89,8c075873,ba6cd5e9,6a730e1c,b6ade2f2,7fc9e7ec,93da9201,63f88c32,c6412063,9921d8c5,77dced53,76907410,82b1b4ff,4434bd,9a55b6c,8591ed5c) +,S(c5bc11a3,4e701898,d22e2920,2806c880,b24efa7a,c6d4ee36,cd440386,e4463a10,2c2b89fc,48feefc8,8bcb4ef5,68d16b44,cd7d8c7,485c9703,91c1c243,bf91003e) +,S(4b3930e8,21827b05,8c487bd2,fefa3458,6d0d3f20,5a2236fe,1b735d63,ac8c62b9,c38a29ad,c9b9941d,dc92a0db,4ce5f312,252c1f66,8a3189c5,595a371,19321c6c) +,S(fc646e3c,eab5a96a,1785da2b,1b50f7db,f0515091,76ade1f5,b057d05f,3aa3b8fe,b2014537,dbf2637d,6f683fb1,6af00d5c,63d4ed59,cdbdd673,f3bfbd48,e9574dd5) +,S(c0ada793,e2d9ed24,8ce307da,a6bebffd,3df2fc27,d2001dd4,5dbfc7be,c5f97a0c,6f3a787e,d40f073b,4965d52c,40700f66,da93f679,9efceafb,4894788f,5c9c7fd7) +,S(b1a45f3d,f2d45a,e21e43af,31ec3159,e8877d91,3efea814,b66f6fa4,a227b157,d988122a,eab167b9,f89db9e2,dd82405b,404f8a9c,a9acfd29,81c8bfa4,273ed248) +,S(4e19b9e2,ad3e421f,1b85a174,89d8841f,65672fad,9a17ad70,ca4fcd12,716d7a68,51412d39,59b158c1,3905c267,f5cf66e2,364aeb8,b66a11fd,ea6f5471,35db6dcd) +,S(533ee2b1,379a6ddd,6e5b3a2a,3a197e7d,eece722d,5c5b9c66,5e1be9dc,f3c09adc,b91b7477,fd0eabdd,bdc4047a,9bcad0cd,9da8496e,bd328fa3,a3ab20a6,3508a6d9) +,S(ccdb933a,816ac55e,c8fb97e1,504fa512,67408fd3,77aeeaf9,565ab66c,a2033b94,20299202,99b57beb,5d3817f5,26aae569,b490b24c,d5834dbe,8b05e8bc,89110de4) +,S(770d7c72,2e9964d6,84dead28,328b1925,287184b4,6e3abbdc,534eb87a,e0ea5873,363c73a7,bbb9b2af,3c0cc91,6f8ffe74,837a99c8,58b5464c,9f253764,e4a78285) +,S(d440dafd,b1d0609f,7c2354d5,74e711cf,852b364,8827fd41,88228ca5,98f71eeb,57d438de,c1aa78b7,c872cae5,c6803a2c,9844809c,7bca1a54,1be6f779,893aae1c) +,S(1602ca76,35ee0795,4fed3cea,d3e54470,41033887,2f060e19,990f3cd3,501b951e,1ea7f857,4b72d3e2,bd45fe36,c828f18a,5810812f,ab6e0936,a7854ed7,c7e32bd6) +,S(9c4d2a24,e4ad8226,bccab8ee,96960b1b,4722d2a1,88a429ad,f9d194ca,6687f7e,e3a4b46f,bf608018,ada2383,5c70fbe,cabbd446,78c9e5c1,35e91138,7d66b01b) +,S(fdf84be7,5be40fa8,db537848,e2fc8ba2,b7c58824,74fea4f4,6e8fcf15,f33d3bb1,2af57dd8,60ba0e6c,dc3606a9,a902420f,9283f721,70ce32d8,39c33673,5da1ff77) +,S(6083a785,fc5aedbf,34615139,e2f97964,ef65d254,a38251ba,203f8ea0,26eea81c,bb4d48bb,894fb656,22cd752f,6e3bc6e7,670a4bd2,64675035,8481561a,2c18439c) +,S(e03ad08e,5b4b9e01,5103e028,668f09a2,7d2f5254,25c6a985,6dfee667,6afffb82,f53acd57,1ab23ddb,d6b104b8,71d957c7,f254bc40,c37017ad,f7350e18,7a24865b) +,S(5a382a4c,88656b6c,4a5c8dcf,4052b1c0,a0bbc0a9,86289ab0,e212fd24,b852d9bc,912caa9a,32a10900,eadd0eec,423f710a,3e0aaba7,93f7b675,912223a2,6ba14f31) +,S(37dd526a,b5392b03,3bd05ff9,3952a31c,7bb0cfe1,f02f4f57,3b8d0ef0,c05d5ec0,7e329228,36595c82,14c8a776,15482931,98966225,4d4315c,c236c156,254e3249) +,S(ed4460f9,cd4bc957,aca653a0,5b6f0935,9dd7e19a,6d65c60,ca585ea3,ee2e1263,733af30e,6edd2b2b,317bba97,d24abd7e,41af6256,e7353f97,58357ff4,1a701829) +,S(eb01d9cd,50ff4778,b29e5096,93388ee1,12cfbc35,2c1b1382,7b3195e7,44a3bc3a,24877b7,99b7a2c9,db23047a,3194e9cb,91e5dd50,d0f1e252,b6f3bfca,f5b4d110) +,S(9fcfa274,b180ce82,14624545,22bb9289,1e0a8fc9,71949bfe,7aa25cde,88dc284e,6787be0a,12a76a23,9de45596,2a11f7f4,4051fbbe,3ba7dfb3,996c60ee,97be2b9) +,S(c8a0d869,87a7a854,99bd5663,30a07d67,70265d8e,cd3286ce,c9be4d02,6145bff,a65c64e4,af865e6a,893e902b,b06c43d6,10bb8181,134a4b71,d136b5fd,f42982a8) +,S(374294c5,932d3f74,a6e74731,6c6a84ca,dfda6d35,5edd914b,70b26161,50628735,ac47d048,8433754e,3deb79c6,7056d828,14d73bdd,703b299a,ca910180,e518672f) +,S(baa9e3a6,2b4bf099,1fde27ad,4b043b50,76a184cb,4f9a6da9,9b56ecd8,a2ab99e5,1e8e836f,f76043c2,c187ee45,7138cf3a,270e2d3f,5bc96979,c12c34cf,9205c63d) +,S(72f85ea,784a5ef1,71516c22,13abca1e,8017db34,4e00b397,4cb509de,a124654d,c78ec627,6cbc5072,fd75b28c,8d395f13,e84731f,7767448d,e06c0ba7,372968bf) +,S(c9173d63,bf5a1301,f0750b1d,e3cb7061,bb9cdd36,296b422e,d23513d1,10b61903,d26a6a0a,ceef78eb,73c6b031,a5455d2c,2a9c4ab2,d916b7cc,7b8e627d,6d581c56) +,S(865ff86a,58fb9853,8bcfe496,26c0bb89,e419083d,f21dbf6a,7b13e041,d5cd3f18,f0bdbabb,8118de57,bce9a90c,83529ec8,abfc2812,ab0088d2,8ade4bde,fe2fa383) +,S(3f14eb28,fd9852c9,bf4d4497,4d794ef1,c30f7748,5c7bb766,6f32fcb5,5ad910ad,e982971b,ec014b05,a9b5657c,a0bf45b7,adfe19d,22726075,80b42eeb,f4dc5217) +,S(61dfae27,c7bb68a1,ede331c,6499a7ed,e242457a,77e5a606,cea82e9f,f450d01,973739f2,c1e4ff77,cae3cf59,b481e730,5ebe8196,c5b62b9d,a96ae224,9b83efa7) +,S(e319690b,e944c297,f7c1bc1f,462ac3b5,a74fb913,9b963384,ac11046f,4343883a,3dadda66,538ea9c8,8fa0c02f,208ede8a,b6ef3480,82af4a32,2ddb5fa7,96d2efeb) +,S(f3db5e84,a9015b39,1617fea6,58143553,baa1975a,ab017012,38dc4243,7d9eaf9b,df55628b,c50cb2b1,be2ef193,a7f90e6a,3bfef4ac,63aaeee7,39907906,547d8b62) +,S(83a7dcd,58742725,8d17657c,ec64b5ed,4807db49,911296e7,10cf349d,c4fc709f,e5201a27,c37cca5f,2f7bf74a,fe000c0f,56643a5b,bafe9f91,de181e74,1d327183) +,S(b95b2363,28f51c80,b376dd90,a0f92d08,1e395132,deaa8f42,c142f642,3d3611ee,c111a08c,a6dbccad,2e784498,22816422,f2200f6b,bb24842a,f96c9502,13479f55) +,S(c3ff0645,921f2b9b,2fe590de,dfbac094,8475bdfc,a6446177,6422cca5,6fb549e6,e07ecccb,4b972834,e2711423,c0fba72f,eb0bb7c0,71a9e206,bf7715f2,62f03e04) +,S(96a37acc,527ee163,51c46241,1df94da3,eb0229b8,6a6e34d0,234bdcb0,5313c10a,46014617,fdd3f8b3,a67269d5,20a49680,9e5fa57e,76da4ef3,59ef862a,c58380c) +,S(b135c091,ec98a07d,b624fe48,4d336b85,62facf81,50346e2d,d0be2cfd,618d1e0e,24456a71,e8f2cc29,19f53594,6d7aaa79,e3d7dcfb,4af2feb5,ea0a2ad3,a23ec070) +,S(71d26219,81730b69,b0411b1c,f553c81,6f35a34,e09d086c,4500ba,94812017,c25357f,8915a2c4,98fe0d60,ca979ecd,8bd7ded3,ad6bc9ad,262db1d2,c3d3e7be) +,S(363cae8,ab2259ee,80283084,d98dc16,60c0934,68e3e854,dd86d9a0,d5e97884,756c60f7,c5e113d8,6e92df38,8fc9a1a2,a4889d86,f7440429,7661365a,ccfd8ce8) +,S(aef32d83,81ba3804,6e5b3305,6764ce3a,726c4e5a,ea61a17,ac114599,63f36247,dea5fc8b,d4ceba19,89640462,a957a8a7,44ca42d6,901716a,734e6f87,9aadb81e) +,S(65980f89,e4d0e342,d4b4fcf5,228692c0,9ebfed11,52d951c7,80963e6f,8c81313e,2d594cdd,a1f0b9db,7b3d8815,f7402a06,acba8e31,b9b0c597,8d2118a2,5dffa75d) +,S(f979280d,7e35cce4,8b9372cd,f73cebe3,6ee08388,e98e6069,fbeeb168,52329433,9181e8aa,bf7d4723,4cb851d5,6b3ca08,8c5f31eb,6b1b8c7,2879cfba,bd3ecaac) +,S(3b9f877e,286a13c8,a8463db3,b306ad62,c152065c,6708bbd5,68931e8a,2deb537f,12436d2a,5269a319,4f605dc1,4a34fcb0,445be9f4,5cc2bdc1,b96d86e8,b9465631) +,S(f2c70f82,1f86e94d,426e3e3c,e31ee519,f5a95b6f,38b663ae,9a6aba4e,f7bdc4e5,dc534655,4ba850bc,fef2485d,51e08c3,ab546119,49fee2ee,4dfc4e09,ff203b44) +,S(e2fb481,da8a356a,ab82098a,f622db2d,6f0a4349,2428dbac,922c1350,65801f15,5f735bb5,bb805980,d85ae242,4855bb2d,5de0c1f5,5018e1a8,e65bc2f4,86b7742d) +,S(d99e2001,33cf632a,f66c382e,d8ef862a,17092764,2c8f1f40,bd3d7bb,f0070324,d00f12db,cdb6e1ed,d190a754,fcbefdec,ee459be4,d5a46d69,afd6cbf8,4a4d30f2) +,S(dd765b6b,cb2dd356,f5965a8d,38108610,688fedc,eb3ce48d,352b095b,aa0daa,636258b3,58171669,f0dc68bd,3dff2a6d,bea6e5ef,20060913,66b12082,e2d7fa0) +,S(f549c14,f099a957,6267ad6c,3adc985b,9d0626b7,3f1f5849,d64ceb1e,266a9965,45a17dc8,30118c3d,28e73a3c,3d026afc,29ecf50d,198afdab,dff3d130,8f32f3d3) +,S(20d80860,90a192a8,51eddb84,f79b2882,ad7ce8a0,9374b365,61e6da34,427e8226,b48b6947,9febc104,880aa8b4,17344206,b19dd720,e5392bac,7e1954d4,a341eec1) +,S(b9f383ff,2545078a,c22cf9cb,83fc9e00,e9d37f30,e03ae03,5694437d,c1de2d7f,14f8b209,d1128a44,20dfb93d,3dc9ccb6,7ed22dd8,ecf5a181,2cd687dd,64a2996b) +,S(2ba0e5b,cec7a4f0,c6edd1c8,2d2f5927,2d97f4dc,3ecf353,8d3854aa,8d6f9739,8b10b217,6e56e5e6,5b99a617,eb71da00,3bee99af,b80e5ef7,3ca8c332,5ca7a75f) +,S(28b45a0f,3c308ecd,c0f7beca,c62d42b,500b704a,9af39931,b8debae8,8cef27e,9a3f95d,a17888ac,19eb4e42,1279c400,a60a0c1f,70a11696,4cf6943,9fc858d8) +,S(d8993bb9,e73af10,26ab41f0,9ec5adf7,437ce08a,4295cccb,283657f0,7a9ca3a5,ad8930d7,817534b1,e8407db9,bb8a608f,538b2bc6,9827a234,743382b,4381ddbd) +,S(77cd88a1,76bfed38,d7dd7152,32e2554a,a644b79,64a85f86,dbd6ffc6,69714e82,4394630a,42436802,1d0a0681,87fcc6a4,dfee0fe3,6db3bf2f,dac6fc58,34faccf5) +,S(d2557185,9c0fd15f,1f3666d3,aba99e38,89419099,ce7be94a,81ca1045,158f2da,90e94d6e,ac00b9d9,19832505,75bb2f,3242e7fb,fb429dc2,a90e3231,d1316cf0) +,S(f4e26c7d,4ccd80e2,7620917a,fdc72ca,94178f54,547eb330,77baa95c,d92a981e,c8ff014d,a388dcc4,c634304b,5973b274,785927e6,190c5557,773b9a0b,ef7d7005) +,S(da3a12a9,50dcd18d,c9e531e9,86f85a53,e7ce5bb8,8f2b5869,9830c44d,8c14cba2,7380a5b8,c01209e9,a1face4d,798f63ad,519a67fe,6bc90511,c763ca19,7e8c6b41) +,S(3565fae0,daf5d9ef,609bede3,6e19417a,45d8c0d2,59163f71,b4d9f54,43756fcc,7b1ef713,a88f9965,be7e6799,4a936960,c44f67ae,d5fa798d,8c0286af,e9da257c) +,S(6683fb20,d435a139,bd08c35f,adcc8aa5,8fbb8f48,7f9576d1,6f41d086,3a4e3de6,6a969f08,566afbc,dc98abfc,9d0d4d54,5076ebaf,efc9b966,957f1dd0,af52209f) +,S(900de92c,cbd4528f,57a72013,77dc1b51,7af67416,1013a20b,30d356bf,e011f508,cb55db4c,8799575d,9dea64f6,9fdf081d,959210eb,32b26bee,b903bf0b,80264c60) +,S(9d84bcf8,1be8a9f5,df2c6e80,d1b5679e,476e39c5,c30351ef,dc6b0b41,61c17613,8aa0cee8,cbc22e60,b71d9066,3533c2cc,a02b8d7f,7df93ce9,897154c6,2fae046d) +,S(6280fba,a3c3c8e4,4fcf0f55,a783eea5,2ebda748,501730de,71781be,abadd211,45b74c18,f0c18d3b,76cc1089,8741246b,202fd272,cdd0e866,5e1f4d86,ee527f5a) +,S(a4237add,7a5ea66e,8a1b48cd,7d5ef195,d90f25e5,6f2f148c,6d4eeff1,805b9024,d512d16e,632bd9ce,6cb1b2d4,c9a41e36,f9a2b83e,73fc8631,1e4dfa1b,b3bf71af) +,S(51effda3,e84027a,47afb48e,dc5c1937,9a685a24,ded2998c,c2b74422,b1e83fe0,346a9d82,cc07ed91,d785c6f0,dc32b62,e3e7877a,892007cf,c015444e,46001f19) +,S(87ac6bee,837ce155,29c005a1,6eca4540,de1480b6,91bc0ed8,90fed51c,de923cf4,9a9aa52f,1be1a33b,7280d0a7,3c19f5c5,b6baf99d,3c9c2d54,4a8d9bf3,a25ceb71) +,S(c8fd7df6,a3b0c0e2,5a931146,72a0af1a,1f995f1a,109e6e83,10b0d433,5dc2666a,3a853149,9b28c2ee,b5baf17d,dba8f57,3cf6e269,f4f21b1e,72bf38c7,79d239c4) +,S(890f9eed,47126c8a,355658f9,296b1845,b142eb17,4c2270d2,46293ba2,997e5a54,f294c38a,1c929ba4,2a9234d3,249690d,10a990cc,137bda3c,ada4b3,6d4e4b79) +,S(9329dbcf,45adc298,65c8defb,ee2ce008,a3474855,39826516,b417b9d3,bd47c86a,469a6cde,e1b0c094,f536fa91,f7617890,1be77c00,896efc5d,94cdd787,3886959f) +,S(6fa5326e,7b161c7c,742188d1,c47263a8,2f1f78e1,df83c664,2546c9ac,70660332,86cfd636,11879179,16d51a4,eac57709,5b8abab2,1024ce5d,35d64b4c,78559375) +,S(ece2e23b,8915d7fd,dab9e58e,8489b053,24eb1485,d18eff66,ee5013ac,3e0556aa,6a94e4cb,8fdf0549,a01621b4,438c2757,fe9753f5,13dcbb35,5655f9b2,ebaaea58) +,S(891b613f,413c155b,c2dedaf9,96d75e1b,54a5b5b0,3705808c,f575cdf,1f697ced,11904787,c1fb6f8f,8856aeb9,f7e05bae,f599b78,d7450bf9,13288e95,ff3f871f) +,S(b7bd8742,d1af6cb2,9b55a307,dd3c0318,6923be55,78ba2797,e38a7154,8d6231c,269e9a33,7a9421b4,cf45938,1961b0a4,3e4a0f6d,f6a0f10,2d7a831a,d7d4cd3f) +,S(7c6f5db3,1620a83f,b4388d45,75d244ca,1f38a0d8,611300b5,d4fdc9c4,34a16432,d5c0c35b,e4a371b0,3b85214e,f5e472de,e6c8175a,b140f05f,6e52b766,aa313f7a) +,S(18d303bb,d2bd6f9b,7f941879,6a23fbea,5ece2078,982064a5,e040c95f,c534ad3b,76eaa3dd,b73af546,7b1862c5,7b4385a0,28b03b7c,66729fce,94885373,1ed2dccc) +,S(31c0daf3,31aa6248,de302243,a768aac0,c8e27da2,c2b8e0a8,7fd74214,b49bb78b,e8e1f975,b77550bc,d404631b,12c72d38,55d3bf5e,5477a588,b11d57e0,e71e1ebe) +,S(940aa62e,e3bff798,327e806,b644a972,fae9eb09,dffb8394,61b080b4,708f715d,2853e12d,56898ea6,8e922497,3660a29b,37ec41c7,339b8059,2075c7a,2836c1b5) +,S(66db37fe,3bcfd7bb,25ca4a1f,b2ee09df,5c748061,1c3a6fb5,d0f079dc,cdbf9b7a,a6d37fd5,5d58ee33,73898711,69794421,9cd7a2f3,3becc8fe,761bcf83,ce603b9a) +,S(fb04bfa,a93a8ed9,3d755351,98895c8f,e90d545f,8eb1d08d,5d7282bc,66026e3f,e77f3c9e,afa2791,b4db2f69,3438d051,47edc983,a8541296,a8cae9a2,174e03b5) +,S(5792afeb,7766365d,e6b36beb,aafde8a1,8e556ac4,207965d7,9e18c1ca,63465c78,95fa5ad4,4b93db96,2c26d740,d2aa582d,da19b761,480ecadc,212452ef,cd885b40) +,S(186c0feb,6298e341,a2440465,547ad137,c56593dd,ed82b608,6824097f,3f83f8eb,b3b58cce,8375d9a1,e63500d,141feec1,38778c46,4be1ad43,7c63256f,33ac3b6c) +,S(d39114b7,c22beefe,6796b6ae,3f740a39,9e3c98bb,58b647b3,5cb23ead,76eae678,1df690f,383db8a3,86284ff8,f914925d,c688aa2a,8ec01a2a,243eb309,e79aa071) +,S(6195550f,8ce49ce2,f762011b,2e8feaca,509a0628,eaa93151,4c779616,721b39b3,ee8208f1,6d86fdbb,c75c265e,88090c85,aec112be,a1d803e1,211151d6,cfbeee2c) +,S(a8429368,37b33a8,2d41a26d,e11a0fd8,7af231bf,30d3eb64,73aa064e,acfd8740,18524c63,c0cf7a0a,b4e0eddd,61717f6c,3221a8f6,3522d35d,4eccee30,b6ed82c9) +,S(bf42ae9e,a64351a6,eb1d2c64,57d23481,f913de5a,d3c00359,5eb8cb5b,228fb202,2d74804a,34413cef,8d2cb488,ea780cf5,15faabd2,36a9db67,91549577,70a09d3) +,S(f1bdfcaa,ba133809,f915e0af,1a08fcbb,dd9cb3d8,b62f545d,6b71b44b,b130daa2,51fba8b2,2c7935ed,4241a87,f19c2b76,bc1a288e,3e53855d,c532f0b8,1ee382c9) +,S(7bf32637,4c6adf01,c7796f59,a11e5c3d,103e3339,a0cfbdc2,dec57f5e,69429bcd,8926e57c,a1fe7442,72d2e89,d037feff,df263831,e40e9ac4,8473336a,269f6b44) +,S(95b652a7,7f58b0d3,4c6d25e1,c294907f,a22a3ee0,f8e8478a,4e8458ef,37791c2f,e7dc4caf,b5bfdaa4,7185f0f3,a98876d,b50bfb35,a77a8b11,b522196,9f255845) +,S(d9f8c6ab,693f8058,8c73e2a,9221b0c4,c8f1d1bb,5e1e58e1,8468a48b,c74f50e1,cb38d48a,89c1ecc0,23e0e248,e1991ac4,3fbddf5a,9beeb53b,4cd9c49d,41f42a9e) +,S(43f62528,287e50,5cbf1a68,18bd99c,9f307e95,84e0d73a,f9fefeb5,b6dff92b,85fbb4ea,b81a0409,ce43ca05,3dfd5a1,9756fb5,f4b964bd,dc409efe,696c2ace) +,S(425a68ad,6d20661c,ca7d688,6bb9c66,f37dbf29,30ccc6da,dc34025a,5ea7a92b,7853cbea,d7816579,fa98ab94,875ebd2e,7ceebf73,20b50b2f,7e67f0f6,dfd2eeee) +,S(929ea74f,9b75c327,a7b26127,8828feca,821e4d8f,c5e308da,f3169a2,bf84bc2,f19e6cfe,d8c966da,bb070d42,3c62289a,5193146e,4297fa35,5908663a,a36b0578) +,S(83da36be,b1bedbd9,4a4ee417,f9faae5c,c20a9763,2c1ab2c8,b997f23c,f6d35c31,a91def1d,7871aa84,eed0bce6,12bf6a82,98d0ebb7,536d8e49,f6757a48,aa7a86ea) +,S(a2e1da8b,4318fad3,52c8c285,46f0a8d7,8fd6cf6a,b506f8ac,2d6746c6,75f2d5b3,584489cc,58b08663,1cdd1b7,3e61cac3,52c16814,493b611e,ffb94a71,2cd85699) +,S(5d7c1af4,4b257440,22b82ca2,9923a180,bb7fc209,1990b111,12061b6e,9eec4d2b,b40ca0f6,a974223,3a7b0253,9f0dbefa,1bf23dfc,cd59c747,c290f525,2e960b02) +,S(e2831933,6cce89c9,993bf230,ae4311ed,48fb0913,b5f35da2,b7531418,b512a75b,660aa9d9,8bfea898,810107e1,711abff0,88881efa,4d9d586d,91381b11,67cc2a21) +,S(722c1e28,498d3c21,66fb0f1b,f44e3ba6,181a962,75efeed6,ac83b36c,12426031,27a135d2,3b70006b,480c3aa3,bd057bfa,200da08f,f9eff741,6bff7885,4a1795be) +,S(f3cd71bd,f93f2100,c534d788,ba607845,cf6049e3,b94f5274,84e8608d,7adb9c99,b8e86285,db09b729,dd789293,7cf5fdc,989e00f4,5dcd4916,a6860bf8,d77cecfe) +,S(36341496,d986b096,5e5ad593,de6f88,67aa6130,889714a3,dc0d58b7,19647318,8cbeb984,a3f4bb5d,75cf77ce,14368b9b,77dfeeeb,7313f16a,8a573953,c7b898a2) +,S(a48443b4,3783c58d,4b7b2f27,17efafc5,e5ffe24c,a7c26bbc,dcbf93,538fbdea,33bd2bf6,9a64a742,c461fc0b,b0ae8770,9ed47a9a,26e7d05c,b71e4e2d,20c894a5) +,S(d4364d96,71f2876e,843dede5,9991ac5a,cf92268a,73212ab0,54b1c196,197dddfa,b30038a0,fd9f7387,fb37754e,9b050e80,e0f28596,d251d627,5149149e,880f6d43) +,S(ce277a60,19ac0b41,16b9d863,5a2555cf,30ef3408,f1a15769,91e48d0f,9465d250,5260ee90,65c89bc,7ef55fa3,d5f5d7ed,594fe592,322b7e97,965a9a3a,5654e710) +,S(587ecb1e,7c08da9d,75ed0249,b1281762,e9c71475,5c3ae35a,f7d66b53,c83117be,c6dda341,cb7d88b,b4a1b13e,313dcca6,1ec58063,376d38f2,cf142b56,87bafcb6) +,S(d87f96bc,69510c4f,19b84e93,cd8dd0b2,eee4fbb6,c5c5074f,ea76a209,e059f41d,a9b83947,b557c4b6,41952117,45ddff77,b5952798,66fb4095,6b5361a1,b463d326) +,S(af9f0d3a,78454c,eb8ca65,c9d7a324,312c01e9,dd8a00ad,e923f2f6,41fb0ead,2d3003ef,29a5ad10,20262c54,936411f0,f8082630,8506fcb1,e1848a7d,5d16482b) +,S(efd0467e,f4791ec9,9380be87,394225ac,637f906f,800abf9b,1ad5b3cd,cf9f017f,a14308d6,b0d16772,f36da4fd,d77945f7,1d82276c,ec4dddc0,de24f760,965c5725) +,S(e892235e,39ac312c,f30dfb97,97e88446,dc1f9a3,ef5cb8eb,d540c64f,d6b6129a,5b291ebe,7c055f52,b9fae6ff,cdcc6dbf,f84cad1e,4d35f495,4dc19b3d,64eb992) +,S(3158351a,542ff38b,12f82b5a,daa6ea3e,6e75caae,600b76a1,16ebe3f8,c9bcd66b,2006c258,a327481c,d324acda,b8ddc331,6a6aca81,44dba340,527babd6,4de975e2) +,S(f17bbac8,c0a7d2da,bbc5a5cd,4b28e96,4ab88639,546b2b22,d40c519d,25dd448d,14f9f488,e76663bc,278961f4,a33e11f6,98d6f5fc,1eaac638,79ccfae,1ab40991) +,S(9aa24eb3,44e010c2,d6fd3efd,fa03cfe6,aff67d25,2f08dda9,3d00332d,3065defb,494cc5bf,e60fff11,f42190dc,e607f067,7e355a9,52ccc682,6845111,322ac050) +,S(3f36168d,77711926,deb0f7ea,b6dad80b,8c755db8,e6705fa5,61285f96,84f1ccc5,486d57cd,b46d998a,5d064f9c,68511657,e53e544a,ee8c5521,87a1cd16,4121c6c2) +,S(fad18e89,219c449,87551525,6150e4a8,1fa2b23a,b6c1d90c,2e2f9152,ee8cd054,b285a7de,4eeff44b,751b4e51,f252f3a0,be7c2223,a715e301,23e9bcea,495ea7d4) +,S(1cb1cf55,9c56951f,58147d84,9482dba7,8dc6050e,2897f389,e30aa87c,519dadb6,b9e54a71,93a8e255,b2cf1fe1,80fe54e4,3e17470,60e9128d,bd527abd,c7ef1f97) +,S(74e68afc,9c8d9e0c,92675d9e,2fc12803,4ce7d22f,e31f5332,d18817a3,bd05efda,1d8442db,d55e8abd,aa1de803,f4fb1295,e9a8710a,3f25a242,7af9a5d0,b5dd786a) +,S(10336317,ec82d4e8,543dea2e,b8cb597d,3aec0e70,fb2971f8,7c5699aa,e4576de2,f2ccc066,5eae8645,54816dfe,c82e1162,226ab207,a17c6085,62925f5a,ffa3e021) +,S(b06a55cf,57668bef,6c51bb66,ac8ba7fc,6714c864,ca788279,2c8b759d,290342b3,7311f47e,5b526dbc,e4bc7833,e4c5b45a,190e3517,8f0f8137,2857e7b0,fb1f0528) +,S(af83a357,81306453,e576c819,d1cdacd2,689b0198,4f108d2b,6d9b8148,50df5523,14f52176,909c7e1b,eda13d20,7567f31e,161a80ac,112e4016,ad7c0bd6,20ec0ce7) +,S(f8f56d54,54faf536,3ea98913,827d57f2,a8983112,aa8809dc,594af919,3ae5c4a5,cc9d4182,bcb00a0d,cb73bfcf,da46ced0,ecee167d,fd7bbfc8,899063e8,d659dd7d) +,S(61aa26b7,415001ae,d6b3afd0,1c690177,879cac31,93a2e410,4148df74,733c4ea1,972510d3,697b93ad,60711b39,f3b3c237,771bfbc0,b7238e78,5a786707,dd179f23) +,S(781f196c,dde0f8e5,10ad45ad,6be062aa,1315c246,85d0ca97,21533c65,627ad492,6f3248fb,e7e61cad,1b01ec2c,fdb4dc4a,b1f4dc25,3666d4ae,27a88d50,c566d18b) +,S(c422d61,7f84ddc6,4483d55e,19228dcb,395f16fc,e85b5c93,2778f62f,ce8917bd,2f3cef48,deefbbe9,9477389b,be898cb3,90499b2a,615899bf,1e910e21,ed337652) +,S(c325955e,b56fe9a6,66555a32,72f637d7,3351b65,da5059f2,17748e68,4da4a4a8,3fa27721,2364140b,5b71526f,ad963d01,16889555,bdd42fda,c2b451c,fb70a3b4) +,S(e393cca1,49142f01,9be9a4a6,e8597354,e34f8d55,b400fa4e,8ac6b4c5,7e50b7a7,e40b69bb,44d6d1e5,22cc30f7,26b7a262,3e5b76e,7b190f07,10325a08,a99fb2ac) +,S(33e3686a,e4e69510,e939e53d,62fd669f,f1a39af5,c6179364,a190ae11,a600cbf1,cfe60b76,1306222e,7052b0f1,f799380,ed564d47,1f6418ac,dfb13d98,47f9154) +,S(1c35b5c8,3072f4d9,b3b294b7,69ff1b8a,ed2954cd,a013c7b3,34b53fec,c783b251,1c691a2e,782ff393,b0ac6c31,94f4cb0,f8dbd5f5,b51654a4,3914a458,6b855318) +,S(147255dd,3af5eb26,119e3d86,b2bed206,43579099,742c4ccd,974f7fb9,83e47fa6,5e0a0a01,7497235b,4766b44e,2fbe8902,aa0e2c2,69e7ceb1,d65c0f34,7a97f7f9) +,S(9524d71,57304a13,71d46aa,bc43986a,5ece70cb,ea008aa2,b8c97070,6436b237,a343af97,db30b94b,3d8d366f,1cd27b11,83c9f44a,75f0aa93,8c4932aa,52f6ea55) +,S(8502e7c6,e498d868,3816188,a99d0f35,79058887,dbeb3c03,676b3b91,be7481a0,28bda608,a9e18df9,c304896f,94efa7d2,46ee528a,6061afd0,322e052b,e7cfb68e) +,S(b89a0d8d,a21903a7,200b196e,46714aa5,ad49c5b0,8fc84de7,8e72ca76,2a3ad3b9,953bac1f,85e4f631,38464a99,e6e3be5c,328b3c10,7523701,c60aad8f,d57e6bee) +,S(49bf791d,67125d38,496d8ae6,ffcc25f8,97114f6f,9fcd5541,9876dca,4bdd7d7,6c2976ec,1b9078a9,a90f55eb,510b1a89,17efca39,d2fda494,b9013d07,7f4e05d8) +,S(c63bdf20,1ff5b07c,14273727,ff174322,422b6497,9ca8427f,5f868eb3,a1fcf05e,c4135e1f,1b5a09b5,d628674c,21ead97a,42957d31,92a44de9,b785986b,3269a782) +,S(58c8c84b,e9f85bd,b26f99b3,cde715b4,4b057d56,d5411c3e,a3000829,27ebe551,15de85b2,1467bee0,d4e0b0c5,114fdafd,410cf720,3ab35f1c,1eb2577e,fc2ec620) +,S(5fc5177f,e0b59e31,e4abef85,31f3fbaa,e3399bb4,126b6119,c7acac83,777cf9b8,adf27f69,b613fa62,3cff72eb,4dd10b4c,4009b73f,2cb885d9,57ab8c78,ca705fe9) +,S(1017a9b8,5116ce3a,498888e5,7a408f36,12a6e8b,b18f6961,d6e1d2e4,38902928,24f7a939,5e0d3c0a,579ae611,b733248a,640db7da,929edb24,b11bd617,3e573658) +,S(d9ea68f4,6af94d9d,232a5deb,c485fed0,d719cdf3,2afe4617,524958ed,751a2c47,e59f2193,db2fe578,642a774f,c4fc8515,f638d1c0,ae8081f,e9d3c0a0,fe20410e) +,S(61d975c7,e4d7e262,5b067179,667325c9,a32ef6de,a0bcbcb4,a825d89f,de6f7aea,b7a00d17,5a2d827d,37de6c8,667bebd9,da92ba42,4efeb706,54092342,e644db9f) +,S(2ff5cd3a,fefe0c25,bbb8245f,c9399409,83194bf8,f4599f3,101e9d79,b7f8d9bf,3c154b7,11964aee,5fe9175d,deacabe2,400350e5,3ea1ba23,20d9e675,5aac8fa9) +,S(cb438486,954c4a00,effd88db,29e0e61c,f9fef94,5b42bbca,8939e0a5,dad9e8a9,920ab096,41789957,6c3a8ab7,249ae2cc,73d1443f,5c650ad3,4da9d473,221de71e) +,S(9aaeefc2,889948cd,f59fa4ac,352204ab,46aa399a,c848041f,446be421,e0e4758d,8e4d2899,2ef8d6d7,3e1e118c,70729e7b,4e0bc28,69d7b5da,72df7b46,38fb3365) +,S(ace47cbf,846e95f2,9387dab7,6ed4e272,e32f6215,1e745738,69f2bfbc,720c78f0,a35997f8,37b8e86c,3b4377d9,71098d88,95d6a008,b9d65552,b1385a4b,49c53d3d) +,S(66610f69,1558942f,8285a9df,3081e431,5c946a5f,df958f03,b2ffde5b,c591850f,be93a2f6,53a8630a,ef037f8a,624e623,8f2ad9d7,3ff4624e,f4240cd8,d3495a98) +,S(db4bc8b3,7a12e950,706e148e,4f07df0d,a24d1de,615f2201,2dc1befe,f1ad95ca,fd55628c,c260a1a2,e56b95ee,ebd6b854,f548dfcf,2c4a6b99,7c4e95a0,a52c4894) +,S(a2a7aebf,58a9a58,24d5a996,da18958a,5fc23d8,452d13b2,b254d4fa,bcba959,d6440764,1642f25c,8b31a117,cd7ed90b,dcdc54f9,e652a818,bfa032cd,18bf085) +,S(2d8846f3,fa8a7a0d,408f8ad,bd76366f,4bf7bade,c255e2fe,595e4e22,cfe86684,2c0a7297,228185cd,3b21c10b,5c7f490c,b01bfe72,9513eb63,f2716d27,f0fbe19) +,S(27ba20c,a44821f,d6ebd41c,8c29e584,6237d8bd,13b3eedb,a82b5aaf,10a6fc59,68d65fe7,b511bde2,f922f119,4bb411a0,c000b4fd,268c2c86,e14279ae,9a63e42) +,S(c2f0b611,3a6bebe9,22ec3e97,a3962280,ab0b6713,76a6778e,5ceb73a7,e2894b13,27b90863,65989917,68a9635a,7f6c674e,71a433fa,ce4f1ec4,cd775277,89d290e8) +,S(8420787c,a0df74fc,5c81d19e,64f7ed56,8bc54a2c,ce1c5714,1706888d,bdf377f8,4a94b5e6,ad402877,dc4c0df,38c7fe41,d9e6e085,e70431e9,99c2b724,e35ae74) +,S(29d08c36,c45715f4,1eb5138f,a5c2f002,b4021f2b,bdc49592,e4242443,1f4d5f0a,903d61f7,2e81352f,582ce3b3,ead7b6f9,e0340c23,6925882a,cdb41285,6181bcab) +,S(ccabdbe,f68b6549,2158d4c8,91dd1d23,efa7a84a,a985252a,3a1e895d,757e5f10,94a0e915,2addabd3,d5adad5e,cbcb38ec,e1a045bb,9d7295a,92aee49c,a6f0bb4b) +,S(5bd30e4,9e2ba9a,745c6ebe,434b8d4f,1d8c34c7,6d478ffb,2871466f,a3ff23e4,1067b3c8,5980ea3a,dd1a4cba,8bb0b96f,ad988cc6,4dd8e206,51eee853,915226ae) +,S(eb233898,8f12eb2b,5369d9f1,56d754dc,8733745b,30967e17,697e69c4,4fa80493,c258bfa5,e993ff4a,4a9eb82f,ce1530ce,25fe74ec,2bbc2639,683464f8,a26b5667) +,S(4b44ca53,f01e1c64,8ff41a97,721e7c3,b0d62b4d,b15c5bd5,d84621c,4dee2ace,d8999254,b359a155,99e59761,f42639ad,27caf87f,ed4ddc57,203fef6c,9abbd922) +,S(ce5ef1f7,6cef6b65,35631e65,d4f47924,df370ac8,ce059a19,5455fb1e,b156f7a1,74c9b95a,a4dc212c,3e127bdd,266aa89c,a4773f27,5607dff1,4438647c,f0e50a60) +,S(563d7e99,40325aee,e66557d0,b14b7e8e,14f86643,de2b3300,1bcfa7f1,ef788bc4,ceebeb99,9878a305,1a8bd9df,bd6cb2f7,3ac18776,ea78df41,30fd22d1,bcdf37da) +,S(ff929868,fb5a1b53,6acca702,f5dc1e83,efe8cb96,f96a3303,d107c6ae,ab5dbee3,82828150,fe8fbb3c,f2bfe03a,3c79fa5e,67c33d97,b12faaaf,572b1455,6ae11969) +,S(1004e4ad,487212a5,8af57ea1,49e0edae,6aac884,2f488bc7,1b75a5bd,4a20204c,88d9a6,164cbc21,52d60ee2,7c8003b6,b39e418,b10c72d0,504a6a7,d7b8b2db) +,S(28dca143,206abca7,1c48137f,8bebd26e,6c79666d,ce164fdd,ef1ca7ac,8e141a25,ec1dea42,575e5cc0,804f6da3,21ee739b,ff244cb,2b299413,4b8539e3,88f7ccf7) +,S(cbb81690,a7e511bf,56a5190,b9366345,7b4fe8f9,64b8fb57,36df2067,28e1ca48,c2d2686a,5405dc79,d6a2deef,95a97813,4a434309,c5303985,f173015c,6571e5e) +,S(3e1e663e,378c44b9,b61d04ca,bfaf65fc,df6b59a2,ae83719,11b11582,978f008f,bbf4b3b8,2010fd76,70d23b07,6018708e,8f78d70a,b2da1efd,be668c9b,d5125d51) +,S(7f742a3b,9edf6aaf,cfbbf368,5a622318,1a6c3b5d,588b74de,c2d2c049,91d97784,238a4f6b,5cd25489,1b8aa5bb,41f253e6,6a59a020,bce98966,ed4c75f6,b7939e32) +,S(f073f95f,f6c809d0,9271eb48,abf35b2d,b760caa6,54b0969c,e327cff,f806f43b,6a7eb8ce,9e297e07,170e9287,7fc737cf,bf923cc1,e72efdbe,5b3b4920,6602746f) +,S(855f6451,5b98ef1,67d3a11a,fec74625,cf3801ab,75df42d2,1b33b1bc,c36d074b,6e8cb794,9990748b,f54a9291,e7ec374f,a31bef56,ed1812a7,7b2ef00,149938fd) +,S(f0164c7,f204384,d3235b4c,cc1bb9ed,bb10cabc,d69c02b5,aed1dfa9,56c74d49,872fc547,78580a6f,38792974,a64399b8,cd674622,659ec31a,91fea06e,77e27118) +,S(16e83238,e95e29f3,ebc297e7,fbbc77eb,53431f3,cc90f809,1e540457,aced09bf,3f3c0ff5,754630bf,88ec765c,a5c04da3,f6ca4ad5,e72d9c0,715cddeb,69c4f8b0) +,S(70d371c8,8b2e47a,47982dfc,bc98ffd8,324b6bcf,2f1aa2a8,f4815f66,dd4949bc,34cc039d,3c69b4d1,833375db,e7315340,bab2452b,2a82163b,dec73702,f4c8da46) +,S(db250b65,6848570b,5a59a2f2,d45e99d2,de1b3813,46fa6ce0,8bca0b34,57c27d10,2859a0e8,fde87061,d7ea8786,f5667aa8,b2633e8c,c52926cc,c5427d64,a7ae6494) +,S(d6ecb3fd,b1ef3350,a2a831e2,321cfe9b,6b22b38d,6a8fa0f,b256f2cd,ac73f949,ad83f35b,c1b5c568,49436cfe,6ff17f5e,8abc6891,e24f4a0c,524d88e0,6c3f1028) +,S(ee2059ff,a2c5bef0,646bf76d,ae2f3bfa,193b8a28,bc74cfbf,a96b48,921ac0d0,3a8f4693,15d6a6e2,2e57edb7,e5897039,153e0283,8d66b1ce,1814ac74,195379e7) +,S(6dd7fa4d,bc12da89,1669cf7f,b1024a8a,551d7281,83fd221a,7a0ca9a0,8c2aa725,67fe6a0d,fca0fc02,1fc89584,d2a5f19e,ce890708,490c79e3,cdbd43ad,ad24493e) +,S(15102e09,b966ca25,1a9b4609,16ca1229,7ab64d60,980582e5,e8bf0e4d,80fd6c35,7ebf61f9,956109c4,3cfb52ad,4e60078c,93ea653f,17c7328f,9120545c,48988be7) +,S(a0697816,4a0511f9,3a48efe1,de74992b,54679aaa,a99e328d,6771386,945e9039,92d24154,971add65,c40e6f32,a5b5fd01,765effb6,c8d64676,c9d97e8b,f857d630) +,S(ac925df1,3a9ce7db,18b9071f,f81880f7,c8ec97be,4b78a31b,27917d71,da0defce,6347aee9,abe9b2bb,1f1e3ab2,2792009e,ee009011,337fb184,d3f637f3,186acba6) +,S(74f3c7b4,e237db77,9229cb2f,1fdba8be,9ba990ed,6dd84976,ff92646e,55e21091,44e9a71e,a07e4254,c4dae620,9c437873,7c56187f,23f42224,3167e45,932055f2) +,S(78f0a024,f6a5bbaa,f3eaf550,92a55bae,73348e82,37dc095c,11ee34fc,3194eb00,54e9b6e7,2f758d54,23d5b9bd,b329262d,6745eb32,c93c2571,f86f40cd,1cfeeef9) +,S(83d3e538,92d722a4,8c006910,a22f32ad,2ff7bdec,d9bd2ea3,a2f315cb,550a1bc3,a4f3c8e1,732b23ae,9f21c03e,7c3711ff,687683c3,13455107,68278332,8d9a25d0) +,S(15deb2e3,f0f0b65,5edbb7d1,8d86cedd,7242a693,a271d853,b468d57a,52cbd647,7cb1ea70,8e12acb,6bbec5ac,26f513cf,51460493,9db6cccb,ba712561,a6f4a80) +,S(6fc5c841,eca2637b,67fcd5f1,3c3dbf40,3b00e4e5,270bccad,617c58af,ac54195,afc3fc7d,92f0f77c,5147ae41,8aae93d3,b5cb7785,d65e623a,391d6a06,1f82d4c4) +,S(154dad09,40e83686,d0942998,e220f8b6,bd106af7,beb9bc66,1f1a4c2e,29300f20,9a47095d,b2a357c7,16d8773f,18c953ff,dc0ed270,1cd881f,f3088176,e61bd7ed) +,S(a498ef6b,89b882d6,81ea0647,f83d53aa,d1fb39e6,6bba74bf,8008a43f,197b301a,cf4d289e,f723ad46,27edc96f,5315bc2c,9ad39c04,4e8e6785,222ca142,3f5c2881) +,S(5c01e4d2,465c3326,1828c45d,bbb2cf69,79cdb746,fb659a6b,44f0f2f1,f388fa3f,315dab9e,5e53f939,610e9729,3e686d33,e46f8262,5ddfb45d,46728b03,927a6837) +,S(d058f58b,255164fe,e6d60472,2b32624b,2eb523b,6c7f1e6a,7ce1c248,fb3fe505,21761abe,1bcb844,39645310,7a3dd2ee,28bb4dc9,93dcd0e9,a09d5176,1a7c6536) +,S(eb89dbf1,67c1352e,5ea2a7fb,206663b1,8c95d962,cec35412,3b9be6b3,51799ca1,9566074f,ec54174,a49a5f84,e4965174,408425f2,22d485ec,b020740c,74b08ef1) +,S(19ddc300,84dda580,db5b1230,b0fe9508,5575eb10,680181ff,ee0d521b,17b39cb8,6af18172,bfb03b77,db456836,b9617f05,bbcbcccf,f6ed2dd9,a9c6e734,c01d188f) +,S(66240aec,7e72f707,69560e0c,f31f2c41,9a8efab5,32f17f59,19bd56e2,93c41e13,16fad661,3600a79d,41eba5b2,d0721dca,afe94372,fe83b20f,7178e29a,e6f3949a) +,S(3c75905b,9e7c7751,9f4617ff,6010c39f,92b852fe,89dca73d,cb3f15b0,23f7a286,799ffb8,94fd4f3e,61dd489f,da746fdb,ae955eb1,3c8dd9eb,e4f73d41,2feccec1) +,S(9719a34,e765cca4,68ab3453,3c6dedd1,6247af51,b73295f6,8b936914,c03f10a,4d4e7f2d,ee3aec6f,71fa8978,f532e995,c0e1533c,5cf0b51d,f35d8f8,29cc10ec) +,S(e32f292e,e5c41e2d,bd262c45,eda0b729,713207c0,17fa5c47,c8bce6,ca550814,105716c5,5995ffa6,998f2209,b9d0b37e,f2bd78be,527f6c12,b707faf1,ef73a82c) +,S(76aa4115,595e7656,c76300d0,a60e3316,fd9c1b60,d41920a6,128e59f0,74a9dde5,f3ca0754,b6daef99,acd6e1e6,fb36d93d,e068c0d2,26b843a6,e7e111e9,9df8efda) +,S(215186c7,ba018fee,747c2030,f57d1105,945b021b,be053da,efb1136b,f0d6f0a9,62994ba3,62d9a8a0,7432690,689a859e,ef498860,3d52352b,e27e0f8f,d02e4de7) +,S(62e16f47,4d3ce3d8,a21f0c8c,875eea7c,111ca0f5,21c03f54,6bcee790,ab0d48bd,e9a8c8ab,99f916e0,4141972c,f60843be,72088d1,e044b27c,6a84b21f,c787abb) +,S(372b5966,8b00faaa,a714e7a8,2462107a,3d1226e4,988faafe,988d06a7,dfb27bd0,c6d349aa,6a53d0bb,185e0f59,a4c137c,8622be1c,5df205f3,4b090080,bf4e4035) +,S(b11cb8c,cd6302bd,e6005ed0,9a1ce2ea,a81fbd9c,748a17e8,fe1c139e,d2d1d725,29ec84f8,e8d627a6,b81a63c,4b13abb,88d7e5d4,9e56e2b9,a3f15f40,60efa38d) +,S(652b5427,f45d07c1,8cd9afb6,7d5743e2,836d78f3,528917fe,2a5c6162,c4a06d81,3e93d9e4,25ce53a4,915bd12d,4327e89b,64a7112c,5ebae53,35c631c9,64b2e5f9) +,S(c0812ee9,89fa0531,56847bb4,edd517a6,7d6d7d0,90ab5955,a59326da,f3833afa,2450338a,cf923109,d67b0501,3557f310,f3b0550a,8f1cd5fc,6eef8a5c,14b46c27) +,S(627c169e,fb0d9937,8ddd0fd5,a73afa16,2a317e56,7d957695,41e52a41,d9344ca1,11dfbcf7,75bafe74,eec503cc,22c8b485,90a17079,580acdd9,c51158f5,efd0cd7b) +,S(69916299,5b83ba3a,6bf16e2,97e8031e,74dc9054,c05ab59a,335a8296,d876a66d,39e45d50,aeceb888,8a1d64ab,9cb3b127,71269b7e,a14ca4eb,2179d762,4ee6d953) +,S(6693adae,579636f3,2332a418,7e49ffc6,921aa51d,852b5136,9a96c8e1,cc268574,ae73a660,580a4005,50865060,dbe9ab43,2f304ca5,506b9f4e,7e17f602,1456bfa2) +,S(ccc178c,7168ac1e,e7bf7579,f75f9645,5ca2b558,e1e709ee,de86df5e,5ebe0789,81c63b04,eddbf33b,432e00c5,9e76d319,fd1ef2f7,d6f31349,1f7a3c10,431a2130) +,S(d80687f6,89f7c28b,d6ef1531,c4e4b283,c6e5dabc,ad7fe5d9,6dc20d30,e1feeea2,71e24cd5,9d2c33ac,2b298946,bc90e0fe,d229720d,539a6f5,e128973a,9bd6c5fb) +,S(c53a6911,88f785f3,efc1fe1a,d142a259,cbda5f76,f3e9de36,895a8963,ffefcb74,7a225bd6,a348728d,951d55bf,257de9e9,d88df32c,ff2c4391,f4ddae8e,ce357cc0) +,S(d512c64d,1932fd1,5636740e,2bbd302c,3d8674e6,52a30d40,ce879145,bed9b7c1,52e336dd,3c7eca6a,469bc97e,a330fa03,1cda3c57,a4354ba2,acffcaa,a1e6b424) +,S(384aed3b,531098a1,99312d65,74b1b1bb,e79a8bf0,ea4f7a86,c5114fda,b32061d6,f2290bbb,2bbe7b53,eb64f87b,17a9e1,49356d9e,de3c0be4,28a4dc7d,709ef731) +,S(6db6c2c1,1fbd5b92,31a4e34f,ca2f9315,dde00dee,909b8d53,d7149c6,6e3cecb7,cb2f0b26,e1bcd464,6e6ee074,8efcd499,f535a8ba,f61a38e7,aaae3511,3c781649) +,S(6bc2f0f2,c0118efd,4fbab4c4,90c56da9,d66c0b1b,ec88e8b1,c8da967a,95d1ae60,a568f40f,24e51e2a,d01c13de,4490f34d,5a5bff13,e005ce77,94a59128,f6d871ae) +,S(12e4e92a,aa40ad9d,281316d2,358bb0d6,c69fac28,24114a9b,a96091d1,64ee29cb,f717cba6,b07eac9c,34b8821c,218519c3,886d5cc7,a22be959,54b3eefa,8819bb51) +,S(6dee0e1c,b887e155,e67996de,92716821,7874f9f0,a14c8673,1eaba91d,272705b3,28d9f2fc,23807874,9dd40ac1,8ace2dce,18ac3980,7c7a5922,43260eb8,ededbc3) +,S(f9d667ac,ec2120aa,50c2b6f0,810b54eb,4928bef4,779e2311,7d12eebf,d093f139,29c9458a,52d4cde7,e32a265b,fb537b3e,5a5fdbe6,ece9be95,b645b960,c160166d) +,S(e026f66,af79f4ea,52955b52,bca16e2f,b2cb05f4,38568c06,ebf1ca25,e6f5be17,6319ae60,3e733681,c8caa501,d7715b98,6244c1df,1c42d391,d8d47e15,a681df15) +,S(1ddd29c9,bbb37823,1185f631,23d5e1fd,39c6b03e,44e2a542,318a6f3e,8325ffb8,22d80158,cee2f596,8da360e5,93a2a86,ce1ed25b,77a4d66,a2e7592d,26c2c715) +,S(138f88f5,f9f46b81,2246373,6034958a,d5476a0f,348ca538,f789e980,9c799f30,adac6393,3e2de680,6fc38d7b,23ec5214,43ab505d,cedde216,6accf786,bd4e4aa5) +,S(b516a9a9,4630ba5e,7469d5e5,ee0f03c2,51bfdf5,a1983506,79baca9a,e6de6f6,9c184956,7ad68859,89a2013a,5a902fea,66d398e4,6c85203e,b7a143b1,90b42587) +,S(bb1a5499,548ee5a6,79500a49,a1466b11,9d56918a,735c3e07,31939ed0,2d47abe7,b946e966,2df43be8,6478e809,ac690d4d,b25398e8,de13731e,89867f80,63f8021e) +,S(394ee032,8be13bc3,ffa069f3,92b72070,36ad018b,503ed70b,9bbf9f7b,458faf36,3a494b0,dd538dc,fa3a10e9,70b83c4a,2169b4ea,255c6423,50f7ee72,40a6910d) +,S(a021889,ce4c941,606c0226,2b423afd,f44d6a75,483dc4cf,797b3512,8131e2ed,d8ae98ca,572b5a38,cd10a763,6638c47f,2867710,373af6a1,bfab6cc9,64b26547) +,S(99e2cf77,a0f389ad,a6c21457,d3e94ee5,95fded19,89c326da,3cef2e49,670f2572,8144a88c,a90a7685,ea3155ea,8fa5cc0c,c282fc25,532aa5da,84494b97,94810a1c) +,S(23c4b50e,80278869,b77c62de,8232a70e,52a4a3c3,4d0d6114,78989746,54e57aca,afba6a63,e35b15f3,1a24e5b5,844b0f3c,b247deee,a764b3c1,1075c3b8,c65bb0b5) +,S(ae0ea240,91b09648,6bd06ec7,ab6dd488,fd6669be,58c2e91d,e8486560,47493d5a,63e13a3,aed0b2f5,a11e914a,3617b1ea,abf62d4d,731eda05,62251d76,939aea63) +,S(d9e9ec51,cea0b150,28199afd,70fa86ef,dfa90e86,b9613831,9cbbeb86,c6573bf2,561519ee,f8dd5ebb,df47d4bb,c24eed76,5ff4342d,6ec6e537,8a2952e7,db51354a) +,S(e674a628,7472d602,8c0b888e,1dc86429,207e38a,af61d3e7,60708721,c1a44613,c145e723,eabf1dc7,f09fcef,1ae24116,1bc0d24e,9c96c83a,3c4e76e4,cdbb9e7f) +,S(19a43fb6,ad571142,42644af6,a3ce367d,329f44e5,bbbd8948,9368620d,944f413f,29a616f2,5f2bf4df,e516574,cbe840de,9ab9ee1d,abc86ca9,6413bfb7,a79a4095) +,S(cf1e1a87,32eb52e1,660186f9,6aaa4cac,9248d8ef,2738a6e7,5e600f3b,658825d,379dd9a1,8355ac8a,94a9614b,e3f51540,c17a76dd,3e3f853f,252f0e75,164dd346) +,S(342147b5,8a1ac1d0,baba5b2d,e924e7a3,b804e385,466f5ae8,29138bc9,5c5b386b,9d8792c5,8917aabb,6a3cbc4c,7f18d2b0,768dc9b9,1871bf48,8ebabc00,f51e2bf0) +,S(1c24e35d,35fda6b1,f6ae6b43,7599ec91,dff1fbb3,b3d26976,783c0539,a8b9af32,58591ff1,68290b12,d729c621,f5da504c,e697ef00,7d922152,9a76ed61,2dbe8608) +,S(d0fa4d47,a29e1101,baa08cca,73e00d6,660e2588,6e1b5cce,ee1c2a5a,9fb806da,918cb1f1,608f9e40,37a59bb7,28c25708,db898d76,a8b2e2b9,d4450c64,3606212) +,S(f3307ffb,7e72413e,2207918d,8a93f183,d5cc93e6,ae07d196,a6d22f1d,253b2499,8a44b83b,feffd6d2,78442d72,51929c0d,42b690a2,d91d99bc,c5dff056,d37e1f27) +,S(77e612a6,9931080c,7d910573,fe55582b,30eb4ca4,c7b7fe1c,9c4eeda9,b296097f,cc85c0f3,6f020bb0,9705f560,15268e36,bf61db2b,814b51b7,c958f1a8,656c26b8) +,S(fe3b3fdb,b8d768aa,8248087b,70e6d0de,592c95e9,b9816996,a3b4c88b,21bb9605,23b44ffb,20e8fc95,ad3c035e,3f52fb53,51291965,95fbda63,8a192cf9,43630e0d) +,S(e664460b,253050fd,8814a2,b2bc0f56,fd8d2f53,94673a67,9a76eee3,f7ae6e80,bf0a7515,a0a6351e,62bdf527,6974f06d,be87345b,438eea33,ddb980fc,788eec9c) +,S(b8ab3266,6cb96b06,a363d87a,a7ee820c,695b7372,b9341b,292dd0f1,d5fc35af,720da144,39ac9d53,c480dc25,5eb45ffa,b9e406c,8eb5bae5,1c145058,8120f900) +,S(38242b07,d1904c72,6da9ca1c,f1acced2,96c1c4a9,b37671c2,e529917d,a651b99,3d47a793,688603a,d6ddfc87,1c85a19f,e21ac51b,d292ff7c,69e219e5,7a0dea85) +,S(ae9a9354,e451abb4,454766fb,7eaac21,5982008e,6cd47d7d,df5a6289,27131913,46d291c0,7f99fbb8,2eea4c66,525602f9,6af5c16b,f4c31ca8,c26a831e,a39985f) +,S(59e59fd6,6a89a538,f5277950,816bf2dc,7070f70e,98d04b95,1b83a80,dab205a9,cec6b519,4d1122d6,dd3e39a6,fb3e80a3,2d829158,3ddf0bb0,3dc3086e,9f247f4d) +,S(59aade5,c117e92a,97ba1785,2e1ef3f6,d000620d,a8f82e2c,1d4272d5,34a8e22a,6a6b6ab1,bd9a69cb,181538fd,eb4a9e8b,eda75811,96ef31ae,deaf516c,e68c1cc3) +,S(f29d02a4,5b464774,fbc1bcd7,7caaf22f,12efcc9b,2a569966,b9adbe8,18a9f075,ba87956,5e0a1c56,fd03175b,a781110,3f34542,ded10367,6d44f706,7b8ab418) +,S(db630bf6,e9ff0092,eebeebb8,a5bc72e8,774c083,cafa0519,2e6d913d,112181a8,6b764e8,2213a7de,79b9abe7,edabf502,d9ac04c8,eb5a4b26,9d22b666,f657685f) +,S(45b9f064,71b848c7,48ff3fc3,34d425d2,57a71abc,27c4d002,dda26c77,1b09d2b8,c2119389,e4cecaa9,c0c72e4e,20c95cf9,1acb1698,c0bcfd42,f8620a9e,d781de57) +,S(d4919e2,3a278aa4,25bb55cd,2fdcde2,eac63058,4cd57f50,390c6a9a,1015ffb4,f8e9f461,950f17fd,8c46f04a,3a6f3c52,5318cb93,a0aa3f3b,bf90c02e,80e1c288) +,S(ea000677,2a76378f,3faa3c1f,c7227cc1,4b11764a,3c9a14c0,4f18f9d0,b55acc46,eafaf0b5,9a308182,8e6d07d7,2e16509f,bbf76fbd,e1473e35,18b795c8,87ff84c6) +,S(70b539a4,4750f763,be1145b5,b433e98,847545a2,8fc72986,2c17045b,f0d6fded,d5438ebf,18eb5feb,fcf6edae,4fcca2af,e0208adb,2f82648,2af428cf,bc761464) +,S(10b4a235,99ce2be7,fdc31f8e,ad91523a,47b8162f,8ed9387b,4c208657,25fa88d3,773ef1b3,a3943b86,729661bb,6ce6f4ae,e8c7165f,97a88fe9,5df9e027,3ccf9e7c) +,S(67d7633,499323f7,cc378c5e,2e62cc6a,5f34ff83,e11e6061,9ec4a404,d63b91b7,cd7616ed,60f0f4fc,1006dcf1,850807d7,e8730954,30db6761,cb7cbbf1,a9c2958b) +,S(5744c77f,8371057,61b1c782,1c9d9c53,14219e1c,5df80ea0,f772f9fe,ff157aa7,578459ee,13ec92b8,b685acda,a153f24,f6c844bb,e195ad58,77364ead,7a9e5fa4) +,S(7c6b254d,39ab709c,cd63c2c2,56c43483,183b1b27,25ca49a3,19753f68,6486ad02,5669fcba,d8662be6,2d12cde6,30102f3,70f7ef0b,5b347fa8,6000ae6f,497fad6a) +,S(8ec715c5,bda8f9ef,3b197ea8,a182a3dd,6cbc3b8a,88227e00,53a2eefb,b2006676,e59ecc81,aea7f2a5,4f659bdf,a317bada,3f8ccb7b,134ae21d,733b9710,335e73c9) +,S(fc7eb1e0,95d0b18,58d22b5,ad36fbac,1b513d86,2bb3c9ef,61b55a5e,985e642,7206dfc3,10056bcc,4071e9f8,13495744,dd903d72,2aa0d6b7,3fb35394,4b66c85d) +,S(4954bd00,308e205b,90c191ab,6262daf2,81939084,668c43dd,1ae998d7,e143f1dc,8efa802f,e67f72c2,5b4fc279,4e23608,7b343d89,255272d6,3c3968c8,7f26237) +,S(f27e6c84,f60858e8,2eb53d39,a6860189,9172da9c,e0d1ea70,9225effe,23de6969,90533e33,321f1f5a,ce37ff79,b4dd3109,a1efd6eb,de502aae,4dbdf58b,1e697c74) +,S(166f3aeb,cd040509,85df120,edf55c1b,f6eed0b5,fb24173d,c7d9125d,d0b2b29a,54b8de8b,c24b1cd7,8f89820f,d4b3ac6a,1588ebce,6de99b9c,81773ba,5fd32e20) +,S(c0797522,8dabaaf2,b46108c4,88ebd104,b0bfafdb,b344b5e0,72f6cb6a,f58f3cdb,bae0280c,704e0d0d,2d421b20,828cd00d,9b388f32,fcadb511,ad5ed4de,281a4a29) +,S(81366739,2085f96c,6a39c9f5,ff60b51c,4991a289,7106619d,1ab0de9b,34de87bc,d7b8599,2464c1e1,9f575cfd,de5bec08,987230b6,20d911d5,d6dd3d2a,8a75e079) +,S(335f446a,f3964e77,8f4985a5,c19e371b,876494b4,467ed700,482558a,9cab3c65,6e8fa42,24cd52c4,b78af9de,b7efa726,c26a94d,85bfeb6,fdb1b97f,674cbe6f) +,S(b6a34b42,bf5e4781,df14fe99,1a14b414,fa488da2,29314366,1ba83ecf,1e80d60c,b633c9f3,cd359dc9,2ce47287,670fe80e,131315c1,6fc17811,f319f1e9,82f88e8b) +,S(95f99013,a9e937e6,ff784b07,23287960,5eb4532,e16b3881,25a18012,17ee3ed9,2d0fa2ee,1aed211d,5b90915f,f3b2116a,28528f19,35b6b534,333b102d,177c08a2) +,S(9c0923b0,d681933,bc8bca36,a6af4058,682c5661,95d3a211,a1ef602f,933f6a45,a72df8d,a9a951e5,a63f0424,4974d74f,fb809cf5,fe7c24da,9c1715a7,2419c7d5) +,S(931cd34d,e32188a8,802b6a73,204eadf2,cae8d8de,52423daf,daf042cb,946657f1,d84b7406,d58c53e2,89ca15bb,4ba78db3,6bd2947,34d0ee9d,6939c15a,9f28b856) +,S(24be4b41,f845c43b,5fc594ac,90e3e4aa,b49cc79c,4b0a8408,1803c27b,ce62fe4,c6651cb0,be54ab0,78940179,6dca2448,3d9349ee,e45e78d4,b786a636,83861bb9) +,S(f19a51c2,ebff1d77,81b0e7f0,a29947fc,3ed9dd26,9f0b9cb9,c27c3f7,500c81eb,8e1cfe92,6128173f,556b3ec4,4c394ba0,201a4f93,e2db054f,63934b2,479a301e) +,S(f6e7e4cb,88ecad49,a1653a6c,5510571a,cec77024,2f490774,a8dd62a7,d6e16363,60842dbb,b8ae082e,9538e725,1a3dd7f9,8edabff3,5444719d,97134a3c,236c97b3) +,S(e7b7bb26,af8cc2ba,6e54e923,6af55e40,7ff704c6,1264cacc,74d96b52,81f2ca00,3abaca16,e20f74d7,6d11a942,415987c7,8da5ed50,3d781f2f,aba6d534,cbc3908c) +,S(c8acf1d3,89a29f6d,e0d03835,80a0a562,aefcaa99,b184f910,f2c8370b,bedc4c16,924e9b2e,2c6463ac,e8eda0b3,feee2f82,73050559,1071bbcd,72f6e323,31617359) +,S(1453b2dc,efe09d16,373ffc2d,42e79805,64ff194c,6b9944dc,b12d3cdb,1d84ae27,2d7faeab,7ca11212,a1aa9d4,a462c04b,8dacd2ec,1f7ee3b8,28fcdfb7,a26c6e17) +,S(ae92e090,b3c6ae15,68a12c6c,882d1b4,345f0a46,b9ad364,bc869243,dd533f4d,3f50449b,a3865900,ff63d944,27a0b967,56c00179,5b5f51cd,5996ca2b,19ad7abf) +,S(3086b503,ad8afe4d,fe2795f7,c972e0c0,8d6f040a,1be88309,606fee4d,b977fd06,b8631fad,80689ce2,7f62db6c,d6a56f3c,d3dc110e,610f3732,fa3f2c10,a4d588d9) +,S(7a17def1,e9c2b175,9944eb35,262908e7,c988f602,2440e151,928dfb44,462e2856,42171a1,f71ae8ea,d437a1d7,e1ec3394,b713044d,6c895930,2535787f,b93fcec3) +,S(97975e9e,b0698b70,995411da,37ce2a87,91198b90,e104476e,b86c4a77,dc5ce9c4,b8999b7,69b36de2,13cfc81c,c2fffc3,65e5dbc2,db1906a0,ec88e931,cd05bd41) +,S(839fa603,a2ec722d,1253328e,15f7d187,55ee80fd,b6bc7b09,bbca59eb,316d1b22,4e43cdca,1b33fa9,cf397ef3,91d40b46,fdcfa770,b2be8e9d,9ee22d61,6e12dfa9) +,S(ccfb8b97,7baefebd,eaf49c7c,1ddada20,861e1c0d,acba4caf,4e30f21b,ca3a05a7,7d9bced6,62579237,a348071,3ea1af91,256e9d62,1265fa27,cc80b5fc,cf75f99f) +,S(8f9f369b,3f325823,e8c9b16f,f2142ebc,3c6f7bfd,dd28c4df,63d1c92b,581cb6a4,114c7d9b,3f54f549,c10d93d4,25843477,9c297e2f,3f07b208,12335fe2,5771b12c) +,S(f0deaa5c,324c5ead,6f6f1cb0,cf1dac32,ef342606,3533435,65ac164a,ac8f0f2f,ef6dd597,e2203c03,f0ce0780,bcc1e963,621c1460,7a4ce616,9ee6624d,11c2eee9) +,S(638362c2,18c9e0e8,72dafa8e,fed86fcf,da5641eb,7cd01725,9a85103,f04fa408,3c224389,bff1fd09,338ea28c,7c9a93cb,32be8749,4a6c629,5c1c3dff,2b582877) +,S(49acbef2,64708117,a53f52e6,84bc15e9,d004baa2,fb3a756a,72d35efb,49871759,b678efb3,fa09158f,d1f9c74a,87a56883,b0a8316c,d4848ef5,1f35dfc0,8c4b5bb) +,S(a79d63c7,b718cd66,b393e70a,f032bc50,a90209b2,5f5b07c0,303eb8d1,1db618ee,ecf7f89d,2f6f9877,9b5e390,ce5837ba,49bc2b3,a7c1047b,7a7c852e,89f1551a) +,S(c922d543,f192f654,3445d3f9,c36a05b8,2ee043e0,92afcae5,a21b9b17,a06d0257,cf77d5eb,9e555f90,34ce1c14,63f7c4b6,a0202d81,deb02ddf,a26113ba,292554e7) +,S(dbb8f077,b411a4dd,faf0d89c,3dc20375,1bb20e16,2052ee46,915528e5,1f461387,a6c0d5df,91cc4ba1,cbba0588,774d47e1,7ef97281,63ca8950,7ff6b779,da12b7e6) +,S(dea21a21,eccb1733,14d76fcf,dc6109c8,88a633d9,645f86e4,e59ee237,cb18110c,a1390d1d,69a304f1,a2792ecc,675f2dae,1ddef908,2f2e3929,6b9a068,3933264b) +,S(f088ed85,750dd58a,cd03b3a9,93d88760,34f50780,985f7552,114f957a,ce8904a1,b810e652,f596cb80,c369f61,f632bc3c,fcfb1fc2,b906acaf,c1f39d02,5e3ae4dd) +,S(b85da431,16b898e8,56fe3c18,b60a48b7,c2ba9f65,ad67c31d,f45ac3b6,608b774c,357d324b,474ae7d8,97398506,c550a1fc,5353a00c,7e6f1245,c0f57683,80ac9e1f) +,S(eaac0d2c,276000ff,899dcb3c,61b41663,70123276,14585bea,7704de95,d164514b,aad696cb,1af2f12,1ba915ec,64afc13d,a689719d,8f188424,25d6068e,9bb06a69) +,S(7a3cfc7e,51fbf61f,ffed3430,eb9ac40,c84164b0,21220837,29f20ed8,eacac977,9015b896,e034d2b6,684f7352,185e959b,5c45406f,6187930f,82f62269,d3ba70a) +,S(5a9def12,e06f0ac4,35b9f853,53db864c,77288050,c349ed7d,a8d8b109,b001a856,b63b74ba,868df816,9dfc30a9,1efbae1e,1617a230,3ed20239,9ecf5798,5ec4bf99) +,S(b937b3d4,287a0f84,5323cc72,95b4a201,ba9d97d3,2d968533,7caccbdc,ce8623ed,6f2ad251,a66e5ff0,77384746,9208db13,2a396dc2,17e781ce,9aa8d556,83fc0adf) +,S(d44f7fc2,97e079f4,ba0689de,dc743d4,964c6ab,8c34bbff,f95bf22e,b7d3c209,b5afe3b6,f6b02542,e6ce811b,f4bb0fce,79e7916f,fed8845c,dd83de07,9320a2d1) +,S(5980fbb1,6be7acd7,b090a2b1,c83dbf80,9148cc99,75fd6834,edf564c5,50fdf2f2,72340269,8d22b946,ae51c9c8,33d5b44d,ee884a02,e12a6d4a,23957483,32abac9) +,S(94733aeb,dce57a89,16961f41,3eb04b5e,71f0a055,29baf93f,c9ff178a,12b70511,e591b62e,5cf92ea4,306e16b5,acc5958d,a5516bf5,7a7dab17,db38cef7,44302c47) +,S(1172b006,3d5ae491,8699e756,75ddfc59,fb5cc8d4,f332ce72,f99fb99e,c9799d96,2845be1b,b97830d3,f9d04a3b,36ae381c,5654bef3,f3fa8516,3a7b9738,ed867ef4) +,S(29afd093,5ca567f7,eb4cc1c2,ebbbe8c3,bc405691,b41a2812,b7c71312,81bbe691,77e9a59d,c0aebd28,9cf2960,ebe7fc19,236c1859,7882df0f,a8e6e0c2,6d92b821) +,S(191c7ed6,72c36def,576f645c,6b475eff,793119e3,ebc3a29b,71eee3c9,cb52a635,642bdce7,90d0f104,54ebe4d6,282be83a,443f8f44,faba4c76,5b1491d8,c7c83210) +,S(237eff13,89c20d30,9902a738,fa4543d4,c2a4a2b5,6731603,500997bb,40d28eda,973d696c,ba9eb05d,73ce7491,5c1cf3d1,5a998608,7ce85854,f7bdd157,3d5c7394) +,S(d4985b52,80673074,53ec0edb,f02b9d4c,b1ce9a0c,af7c675,77789b8d,f3b5ab33,ad8fa145,94c510a7,830f3353,4ac94a98,cdf2fa30,b6a1b572,9222969c,e27eb1ea) +,S(3baed9b6,25f5d0b2,6e0132c6,20a9015,f79bd8d1,8e5ce170,20fed78f,a2238914,6ef88df1,3c7a9023,1180edfd,d041b950,3ad89f22,4ec557b7,2e900bc8,fa820c19) +,S(6e2298a6,102268b1,af97bf67,c0aba783,5463165b,1df8a824,530ee5d7,86d354f6,c3864e52,3bb5cfe0,a64adc7a,9e8926e9,876516a4,c83767d8,5ebfc39a,e125c19c) +,S(f9e87f15,2412598d,775131de,abbd0272,4d658849,cb60aac6,92280e63,8e835e9,e843a3dd,a30f9685,70fcf86e,86206c22,af40ce3a,3beb620c,aa167e63,271d95ac) +,S(f9925b7e,80b8b8b1,b5c56f80,74bd5ee1,9e419678,2c5a33d2,c59f8016,56cfbb0e,3e2fda0b,50aa7671,5810a8d2,2d4778d8,66bd2515,acf87b79,7b2f4875,dee19719) +,S(6fc34efd,5d11ae35,2cca3254,c5f8a040,52b81357,556d4d67,dd02d22b,91f4e49b,f14c656,ec946492,a6af3f2f,56fd7355,71e41b2c,dfeda7bd,ed567658,202f6e61) +,S(ab504458,4b38c846,e282038,1f02f55d,fc6a5648,1b1830c1,e4ee94e3,d11af8d9,4ad3821e,3f5219c,aab31787,2a8fbccf,f0f445d7,da30f05,d9523f55,13eee3cc) +,S(2378d11,716b6d34,85bd5a57,5c5b2c96,1b817abe,e21b7d45,38244933,5ce7e7a5,33682ec0,8c59a158,c4ef12bd,d2a46d31,6abc6dd4,f81a1fef,5be40577,4e03fab) +,S(cfa95425,8608d9b,9c568a1c,fd4b078a,ff49150f,a4681324,ac56b6e9,df569016,e200a3ae,2d82ddc2,a71767e5,842ef30c,86cd9b17,7c5e52ff,ac316e50,1e7e2) +,S(585542d9,a3a582a3,bde74fef,112924c4,e00cafcb,61518d87,f524211d,bdb98993,2035bc19,7a0ea2b6,8d1d1333,b5aadc61,c9dff2c1,e4dea034,1539ff15,9a3d18ae) +,S(fab2433,905e5b46,e47103f2,e353d503,cb141e61,2167cb4d,34946a5c,cd2c06b,7097d735,3f17734f,8eff6993,77916c9,884f67db,42f7a96c,62a3e1d9,9e341547) +,S(b10db548,be55521c,de5edc26,fa39716,154e365d,a1b8b7fd,2265d78b,7edee8cd,389efe1c,7fd8b4a5,4a42e651,b5c06a2a,7c153664,e52ef30d,90eda2d5,9e9690c8) +,S(218a8a36,273fce14,85c0c9f7,1910aff8,64910b00,6254af75,e78a6b5b,3d5c7bad,4a1984e8,e90d4695,b8dcf34a,55eaf568,b0fd34cc,528a147c,bebb052a,8e6e8604) +,S(e120bc22,fe6dc81f,dc3ead1b,a2ca966f,c5702ec,479793b1,5f0ebae3,b6c5ff3,9f92f1d5,e8aa56f6,1ef20685,c8085782,be180658,c7d2b9e1,c020c98e,cd425835) +,S(e83373fa,f80d4560,5ac4da9a,c9cfa220,b2a2c656,26857035,a228c93b,495be15f,8b915652,3c532657,7945021,d6c1b1a6,3b1fd090,ea93cf01,90fdb791,a2397a91) +,S(b7d8a393,a10590ea,91d2a495,eec07262,f2f43e29,74f7b2e5,6ba6ee92,17e3e74b,4ad6671f,58b2c7ba,7a940613,5986b3f3,5a6e13ec,8243b0fa,c8bec130,2afbad0f) +,S(75a5ed46,b2103f5f,ee808803,bf419bbc,232cf5d3,84955e8b,1d4fbaee,5194ca35,51b9670c,4c65e969,a5a56e15,25f33dc9,458c317b,6faf484a,186d52d1,757e4857) +,S(6d8d67cb,c309ecc6,3c1e04d4,aa42683c,775d5f32,51111500,9166c574,b0dd66e4,e127b8c,f431cf09,5939712e,c96d299e,efbdeeec,eeca3d2a,9f6b3d29,fb8f72fd) +,S(51a6d684,463065c8,7d3e0fee,ac72e4f3,1e5187a4,dd14d59e,ef71ee93,85fb229,7fe1069c,b384178c,ae2241fa,6886e1fd,286347f0,d2488dbb,f4d6eaf9,e722a90a) +,S(5140ba9e,81a272eb,30ac5c96,a8b054bf,870b1785,9519cdbe,4f2e6573,2a56e6bc,3b6a2c0e,7421eab3,147b61e6,d8252326,1819bd94,9e3c805f,ca2a12b2,e13599a9) +,S(b94c7812,6c60a3b0,48b28f47,f9d461e,27ffdf7f,93a3ee70,ae38962c,8060166b,bab7aa94,385d224f,f20e7c60,7f7f11db,4ec3526a,c226cc96,16af6a3e,356208f2) +,S(45046678,76689fbc,a94ebd79,ddb5d655,3e97b788,c91cee0,b62ee75c,1fd12ff3,635b3d75,a0621530,d7ff26cf,f1878d52,2864a6ea,e82b220f,d35ae5a5,edea1895) +,S(45f4025d,7b88ddaf,e39566e4,27060b7c,ac59ae7a,526ac3d6,a489424b,d677a54d,d732c322,18307ace,354ade14,21d13438,ac4c7c3,5b5021a6,cea9137f,b47465ac) +,S(c6e8912e,a197f39b,817b743d,deb3320b,558af332,96e0ebb,58c258c4,f1c0d5cc,6e0c8ecc,fd97ccd,deb08f4a,73ca13cf,b48d3633,afb74139,36550e0a,c23f04ea) +,S(6fd13fd,c7d3809d,6a3bf6b1,5208d0ab,5f476e99,57a7fc71,29824154,a05a7dd7,95922641,32be31b4,c34ea614,df6b8c1a,c386dbc2,1318868d,b40869a7,17b862e6) +,S(54fc0732,968b0207,ea2c115f,d11bfb57,b9b28164,4644d82f,45af1100,6b63d0b3,318ef9f3,b2173c45,bba5ffdd,8345a08b,66c8e183,80ef9dbb,b5d80c1f,15f95bfb) +,S(9e6ac718,6e09f698,1f384cdc,b9c48703,a8ee3726,d6d8ee3,a10499f5,e17731e1,95b4c37f,ec98faca,b41c628e,12f606e,79829b17,96ef3dce,c4aba99e,3882bc0a) +,S(85732ae2,eb7944a2,6609aea5,607604c4,c30f25ca,c365fb2,e01c7600,40542ce6,928a62fb,b082f38b,52890540,7b20f9ac,1f4841a7,bde217ab,828780ee,94749fcb) +,S(3ea5ace,80e47aa1,9bf1406d,3559fd50,85d38504,93752563,de66393e,37a652a1,db5fa543,142d36f,fcc1cc8,36b1f4c4,e82d4980,f2b277c7,bec53324,fbdc8e9c) +,S(7d40f7ae,f1866d87,8e42f9c8,d5afff76,2a427567,f6130f73,439d67fe,d14be54d,5bee61f5,31e4ebb5,679c9645,d565cf,f93b391b,f48c5504,a5054e23,47859d2a) +,S(3dc80cd7,478ea38e,1d6e1e41,aca892c4,4e4d8339,acd72fb4,c27861ae,3e7d8664,98412c68,68af56ab,19876499,fa30c8b7,8bfa5d19,b4aea0ec,52787690,49b7e3b5) +,S(2dd92155,81bbbcdb,a1900b90,9018ea30,2e40ec35,cf2b74ca,6065e8d1,f3bcc057,cdb59ee3,b5d42deb,5a4ffe56,46f5dec0,218d0e9d,569cdd3f,b96610ab,2a382fe5) +,S(a245a185,ed85c547,3b78a561,76a32e45,b35efe75,36a1fef4,569f4f70,ba510ae5,93b66fc4,6fde9554,1363bdbd,117073cd,f3f5e406,75fc5710,34bef6bc,47a2519c) +,S(5136c2e4,5004c1fd,615fe81a,e4463153,2753c670,86d1bba0,b3a35bdc,47bbec08,1743f5c5,d0a58608,a66fab55,69f7134d,7fe49fad,2dbee1a6,d01c581d,18f97d85) +,S(b65423af,618b242b,71e258e8,c22f975b,621a8900,9e0a3f12,f9f8314d,7fc6ca54,e3c39b1c,e4159306,e730c2ad,4ecec430,720355a2,815b63a9,720ef623,b91e4230) +,S(d6db49c6,4e68f6b0,59cb5a00,3c826a59,bea1e9fe,7622a2e,6eca605e,fe9a7858,cff0a39d,83e246f1,efad5dad,72c5df0d,62e9cf8f,4da81a5a,68586187,3dfd758f) +,S(ff2f739,8e5aaae1,a589a82f,e8e36315,34ff1081,cb083933,d08473b4,bd16f03,1559e2e8,49dc5aeb,50f3de13,1478fa99,e110627,aa0c4c5d,43ab03ca,dde04cdf) +,S(a7c9398c,5938a3ca,e32d2947,d8e3a58,e42a669f,5cd9b219,d8acf6f5,2cef9bf5,43e2a5a3,dae4bd5e,64a30861,7056fce6,cf86d0b7,41c3b46e,3a3ed90e,98d2d51c) +,S(faa9724a,357b6806,7be30aa6,4fb85879,1969191e,346d5d73,8a85b27c,c6608d72,ea1f8a66,8f4881fc,4ecfc556,f0ca4e12,b93ee6ca,54a0fce,b2fe51ca,174d9713) +,S(28301cf8,328171c0,74cd585f,6e5870ac,815de8d0,9c9f15c5,5540de9a,b29a86df,31910e6f,15585710,74e87f41,e5cc9c73,4ddd15bd,4436ec8f,59806afe,7901c2e4) +,S(fbde2380,ae0cccc4,e044ca59,92be8e11,5fc782eb,c1d49bc2,cbdfd1f5,d7908a09,c1a1d67c,74777fbb,68919bf4,11de555a,6485436f,7e34062b,480b7516,8a03dba3) +,S(59d8ba7b,6c71ba1d,191d4cce,662483cb,9784ede7,d1908e81,815d0a48,4b84bf7d,8a32e968,1ecf963b,3c23a9d2,f382490b,1f229b27,a663f4a6,9819c33b,f9f6149f) +,S(6c3a61d7,1c999ae0,604511ad,23f620ad,dfc7891b,925eeed1,6a5ca37f,b41b47e4,f7115905,c696c2b3,e2b82a30,9728923e,b8eba53c,363f1456,73676b59,9b50b9c0) +,S(8e53027f,8e137bfa,73eb5167,35382ba,ab3468f4,d4227b19,a45c51c2,ef3d8339,2b5ea7b9,542a83ab,a1c402ba,be13437b,c621067,96e83b7a,2cdedc52,2bcff513) +,S(113aa35e,6a5f794b,a56b04a3,d639b1e1,64a790b5,8ff310c,fbeab588,f93be16a,227c17e7,d95583e7,fdcc3ab7,b24182b5,1bb11e91,9f28fd7b,3a2e4a40,4f333962) +,S(16c4c83f,5a06b2de,9d3f39e7,1f0a9de7,af6e8fc7,b0fecaf3,2c82f1aa,fe9a5343,b4cbf71e,c3ad4635,87f8e355,cffe1ea,a19f1dc6,d233d617,776a69a9,ab8dec03) +,S(4d97594c,613de84a,e685199a,ac639a56,e5c15a0e,c00282bd,197cc2ea,90f8fbb0,b9f39a44,24cbb1e2,f77afa90,ec7266ee,64ea987e,80a32b34,483c1f2e,b0c5844a) +,S(b679693a,b3fecff0,819e0598,65406521,1f9aee9c,1ea44417,eba86ebe,32414ac3,7bfe1ba0,ae17291d,71aac3f3,66e5a927,56b53312,a6818d1a,78b7d9ef,a5d01b2f) +,S(a97c2730,a78cf5b7,538b518a,87d8fc55,f95a367d,4e021d23,79f163eb,98b6eb9a,aed1e51c,3ce7e35e,ff69e7d9,3fd3a968,59f0f23a,7bbab9d8,3b60cabd,cebd34f) +,S(7dd4e84f,6547d66b,5e0b204c,ed1d0258,4fe92ed8,6b504ae4,eb1b3d66,d43b8ca4,7956148f,de975510,5e3b5126,f82e77b,89a77b68,ffc9364c,bfb596e8,187ea99b) +,S(5e856d1d,25acc306,e8c1a2b7,a9ccea1,beb3008d,c224b38f,e2f31376,65d07c3f,7dccf6b1,55c12be2,f3da02c9,12fdb666,816558b1,11a2a545,9d88aa28,9d855e6c) +,S(c85ee868,7f507429,e5c26af6,7ef1fe45,e782661c,1fa03aa3,ee9dd9c9,302e5dd6,732de6ad,d071a0b0,b77e47bc,14e176d4,c85b39d0,ac5b4ea,55f0d367,dba5ab5d) +,S(a97ba3a5,cc2d5148,3f65c65b,483b3e4f,3c68e46b,87bcfea1,42aeed8,4c42e42b,f4eb1271,3024d1,b7612c3b,7dc3dff8,ca336f23,5db7daf9,3ca6f7d8,1bdb4a21) +,S(3c0396cf,6ff0150c,5b6bd528,4a05d0a5,3b735c85,125bd49c,f62db5b6,4eaf54a7,6ec02c02,f8d9a61e,6bb38d64,daaf3c7d,5324462e,37e2df8d,4ad12bfa,37fd2cb2) +,S(e36fcebc,e406d2a4,ad42f7dd,cc00e9f3,cf385eeb,58cee004,5aab8174,82d84f94,7c98182f,6edd358e,76d66de0,b45ae9f6,5eb75092,1a25194c,1911bd9f,7e6a1a6b) +,S(171ea2ec,b9641746,7d7edcf,ecd6d85,8577322e,6ebac130,5ab57f33,62eb4e37,9f219970,753a7b9c,e4f0c6ce,5745596a,aca8df7b,a73660c9,10add5a9,d4c533d6) +,S(a81d720a,bf8047e8,ef67bf2,71a13f47,636a5f9e,ec425649,1cbdad65,39652f9e,92b37c88,275c022b,635df6b,9246edf5,5dbd8284,eaa4cd7e,3d3ce6d1,c0ca3794) +,S(fa3b6973,4bd9939c,4b6ecd3b,f0a06327,2dc11345,1bddd717,f17b745f,bc3f99b3,f38a4e1a,bcb35097,7acc8f2e,d7f73f75,d406e7f2,22fdeea,2c12d8b9,e5d2dfa3) +,S(c117681e,b55bff67,feda80a1,ae88b4be,c806860d,91916619,288a7ce0,b31aef86,d94ae124,dca678bc,b69c9421,f295405f,d6dc1fac,de96a2b4,58ba5fd2,72faa032) +,S(5ccc0619,92744a57,683de5e3,7b956fa1,fd7287d,b4516fc9,f8635be3,a0db42a9,af1f73ea,4d2168e1,7550ffc,dcbba288,8397931b,e457ce6f,3f8082f8,cfc5f03) +,S(858b019c,8a93524f,6c86738d,cb10b534,d8caaf86,5c0ce75c,fc9b83b0,7c661a0a,7c59d30,1ffc8ce1,b0767ed7,91f84bc5,60bb8ca,ed3464ba,698a53c,160ec570) +,S(e1e217b8,69da0c77,599dcc38,40fa1d8c,a8d08b1a,4ac9a882,da1476cc,cc76fa56,83f0ef77,905f0801,4bd86e17,63b8c2cf,ab2018a8,9586620a,b49a15,9fc314ca) +,S(15a1ae40,b4fc51dc,554b75d4,db0c2bfd,62dfbbfc,dede18e1,4edbb689,91525cff,4f0453b7,e4e0e99d,9663e5c6,bb018007,b52c8e14,d78a28d,c4a888e4,8c4326c2) +,S(1b9a142f,fc4d03ea,4b079f2d,b05fad98,8ddb2d32,b359967f,c173801f,63320825,59bda7ed,5b691c20,4fc8f8ac,f53be298,ae628954,a8134d0f,dd097e67,be9ff9b6) +#endif +}; +#undef S diff --git a/external/secp256k1/src/precomputed_ecmult.h b/external/secp256k1/src/precomputed_ecmult.h new file mode 100644 index 00000000000..17df1029672 --- /dev/null +++ b/external/secp256k1/src/precomputed_ecmult.h @@ -0,0 +1,38 @@ +/***************************************************************************************************** + * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************************************/ + +#ifndef SECP256K1_PRECOMPUTED_ECMULT_H +#define SECP256K1_PRECOMPUTED_ECMULT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ecmult.h" +#include "group.h" +#if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 7 +# define WINDOW_G 3 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define WINDOW_G 4 +# elif EXHAUSTIVE_TEST_ORDER == 199 +# define WINDOW_G 8 +# else +# error No known generator for the specified exhaustive test group order. +# endif +static secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; +static secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; +#else /* !defined(EXHAUSTIVE_TEST_ORDER) */ +# define WINDOW_G ECMULT_WINDOW_SIZE +extern const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; +extern const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; +#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_PRECOMPUTED_ECMULT_H */ diff --git a/external/secp256k1/src/precomputed_ecmult_gen.c b/external/secp256k1/src/precomputed_ecmult_gen.c new file mode 100644 index 00000000000..248fb077e59 --- /dev/null +++ b/external/secp256k1/src/precomputed_ecmult_gen.c @@ -0,0 +1,1779 @@ +/* This file was automatically generated by precompute_ecmult_gen. */ +/* See ecmult_gen_impl.h for details about the contents of this file. */ +#include "group.h" +#include "ecmult_gen.h" +#include "precomputed_ecmult_gen.h" +#ifdef EXHAUSTIVE_TEST_ORDER +# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode +#endif /* EXHAUSTIVE_TEST_ORDER */ +#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u) +const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS] = { +#if 0 +#elif (COMB_BLOCKS == 2) && (COMB_TEETH == 5) && (COMB_SPACING == 26) +{S(7081b567,8cb87d01,99c9c76e,d1e0a5e0,1d784be9,27f6b135,161e0fd0,3f39b473,ad5222ac,f062cb39,21b234a7,15b626ae,f780b307,9b5122d1,53210f42,d9369242), +S(228af17e,df90d1cc,a40173e9,478fa445,9780dacd,c3f15b90,fda5d00e,1faa1b51,8ff47c4d,a4ba636a,f656da9,12a81f79,6252496d,1e519886,b2c2b073,25be2b4a), +S(b515ebe0,f48fb34e,9e01824c,d90553af,db116579,96667847,5ebaa700,242fd722,4cf08191,510fbf0,51f9e19a,198f11f6,ea31268c,2a6d384c,60557250,f0553c50), +S(c37581f1,35446ff3,e80cde04,ec987f08,5af3af9f,71d87494,99b03ba,dcb8f78c,9e46324a,8d8754fe,fbda7c34,2446cf72,b7472708,25cfb92f,a22a4e73,4f1e9bc7), +S(768392e3,b2ccbbc,21792f2d,6f43c63d,efcc249,bcd549cb,96abd8ef,4ae59e90,5d061a40,ac3f93d1,82f0f7a9,914fff5d,90bbacb9,1965882c,591e89bf,c49da994), +S(a9db5de9,2d96c715,8ce5ee00,3d186cf1,976f6a76,f1be0714,726594fb,6c1ba564,743df2a8,ee73fb4a,47b3d0f,2f2b8cab,5af5227,f232946a,82676e4e,8bb70c8b), +S(58921d8d,3712f640,657e762a,737ccd0a,cece1459,a2ba8323,20b43903,d4953f93,78c26959,7e422c02,c01fcbef,484a9d44,9f635c82,849bc2a3,2a9bf6ef,3e6f1e7e), +S(bae41760,ade541bb,60028015,f6906b78,aa41515a,d995dc40,afa091da,77ae8b9a,716ff74d,ad6dc24c,77ebe31f,abe19792,41d18b0f,43ff7598,c6ea04c6,6899219f), +S(e836ff6c,6f9e02e2,4e6f6bcc,2f2460b4,9de88730,6d69241f,b22fa574,7e100f80,77c41df1,4d87b6d3,de74deca,ad426635,f85daca0,ab966a4,5a26a972,32105c5), +S(c7f17d19,fbbf28e2,543fceb2,4268ff6f,1b85e189,79b09991,7457fca0,9ba1b5a4,23a6d4aa,83ee15bf,f1655575,3e4162c5,8acedadb,4c4abfc2,54b7018,f477514b), +S(79c337ad,8835046e,572eea35,df76276b,84e99172,7bbc68a6,8c0b743,28619a,af6cf2b3,9c6b51c9,f1f92e42,6598dcbe,39da6196,2abae0da,d5fc8d0a,aa16a875), +S(1e77739b,12d20887,2bfe200b,d202972a,544804f5,2b0969c5,c22fbe1c,b8b23837,880c7490,c0455322,a0f1e67d,34b3fd1e,33c1e7da,83b9b047,5aef7bc1,332ccee5), +S(b1d314c1,74d493f6,c36a893a,830d90b,f1e86d0c,6deceee0,edb77ff4,31e9607f,8a4ba010,ec3e47cb,29d8f056,e056eb73,3b6b35f6,4c742d06,9ab832f4,68bcd3be), +S(2498aea6,471f748a,f14e50e6,bc17e0a3,ee09514d,fccbd174,f8a21d02,dd0fae48,55a3949f,2e4188e2,b3d344ce,6f0276b5,99b121bc,358e8fe6,bc4f03f5,a8219d08), +S(42d0778e,27e87710,dd19285e,d531af1e,7064386d,11b1b3c9,fb788bf2,b0c112dc,37888909,d943825a,9610e37a,362549f,547b7c7d,ae64a27e,c34290f0,b4fc5fcc), +S(af09a9f8,3a21b2fd,69ce14c5,495c680e,df18e426,c1ca5a1c,af56246f,d6ea5bbd,8eae43ca,8e591017,62c4cb02,9e5cacd2,58f0fdb1,ddbef7e2,c5765208,107c96af)}, +{S(4a7f72ed,ebd8df1f,13db15be,3ab296a8,d67edee4,37965f03,eb501205,3518ddea,1f8c4dc1,2d0e59e7,7d30a326,fd4ecbf8,aacd5fb6,7dc7169,898a9708,ac46b972), +S(c4d4f8d4,949d1ff6,559925db,f4d34972,af16062b,d59493b8,b1e0d546,c2870874,cd7f93e6,c0ee3fdc,4267625a,a6620540,4f6d80c3,d0f7210a,ce6b52e,c350706e), +S(773627f7,dcc56184,7eabafa3,42fffade,325b8ee2,a96f2f77,cbe675a6,2942277d,fb0ad731,9bff4c9c,270d93d1,89a4c380,218ec9df,1f564228,641ab35c,46526bd6), +S(ff443101,befd0bd9,e1914864,3eceea06,b9cf711b,1405e3d5,3883a29f,906063ed,aa1b7d9f,59cbddf7,bc1ad03c,44c4295e,efb406ca,7960c683,eca508d1,b2a9a2dd), +S(cbfb6813,a6874b65,9234e866,c2875f70,e45f9f76,3d634752,3f86040c,880a2e56,ed85d1a,6620c1a4,85ba3038,d2ee6590,4e27206b,eaa531ec,1eb5b886,8232cbca), +S(4e85c77b,27788563,aaeba139,975f7125,f3c933b4,8d67ba6a,2e964243,bdd7bb51,200a9d9b,3400c87b,1fb98422,3200aeb8,e6a5af1d,58c061f0,d059c0b8,d431c08a), +S(d58178ed,f0ce32e3,39a524f7,ad389f7d,8817f41f,ed782612,45218816,2a67d4f0,4840df81,5dab9596,93f9284c,54bdee72,f4861d39,3944c648,ecd76ec5,6dd3225e), +S(670f8f7,9b66496d,13692558,d56d4cd7,a1eeb0d6,9e5133ab,4f0a064b,7152fce4,1a72206,6f530586,927c2e39,370d11f3,e251bd9e,eee10303,406b7592,716333d6), +S(10b41abd,ed4de2fe,b7a40050,e61e5982,89a8cf3,6eaa608c,f2a82c63,5788f1d0,532d168d,680e9c74,4d5111da,6aab902a,9a0f5283,7836b9d9,585dbc8b,1a407de4), +S(76abd21b,103aea9a,f04b4040,297894ce,a501474d,9d38d30,8ed02cc7,137bc7c9,b5a432ad,9e92935f,7040897e,3b04152f,693c5f2,cc1e1d53,2c33f70d,185318e1), +S(4335e10d,5e4f02e6,f1b58a0d,ffb473ec,15f735a3,bf96c140,50bae78c,37061db2,1301143b,1f29f122,afcd0230,d46b6b38,b154e589,92b7eeb4,16088968,a7d57485), +S(2b3966f0,7e37e771,ac4c68ad,b8eef3c0,977cb895,2f47676b,e658aa86,76057f67,5382a6c5,bcdd1a01,6d79d817,80faf650,c0a486bc,ea8fb592,1cd3492c,42c91c3e), +S(f7738800,b7fdf237,dc7f03fc,43724011,8b53aea4,4d7953d4,276f3b4d,bf5c0ff8,c1de7924,ef8dfeed,c4fb409,f1a15d4c,5e8ab42c,90ea9c92,867b5b5c,f2921605), +S(5cb07874,ac4ffb86,2da619be,4c8fa38b,e8b261ec,3ec73a12,cd4cf8fc,4f8d5dae,549d1896,4931dabf,ba4553a2,461f2660,87733454,ea8eec6b,f671e3de,60c70340), +S(5cc85d41,7b2ae9ac,dedb1b44,ce78d8a7,8f56b878,1a4b3af6,635a55c1,fead3be7,66a48c79,301e57d4,54cc8644,d2e778a8,45d85762,2c10eb98,d77eb873,e58bbeca), +S(f27211c9,a067b01c,7fe7fbf7,7b5d9b0,eb0f2475,9d541457,6eb24ba4,19fd3db8,e26d28eb,89f7b518,e9ae0b88,fadbfb9b,641d3a44,c59c6f93,ec28a541,486e041e)} +#elif (COMB_BLOCKS == 11) && (COMB_TEETH == 6) && (COMB_SPACING == 4) +{S(629bee58,a391595f,eb20c534,4933937a,cdb2eba1,86d49f8b,845c1b5f,4ca87182,8dae4162,73c6c068,2e2aede4,76efa86b,7612c07e,f72070d0,dc4486f1,47e95085), +S(6fd5e13c,a94b874b,28cd574b,726efdbf,143ab108,1089b846,7b5b2ebe,6c6a3c8f,4a4db306,52c9772a,868b2859,57c5a005,d83f6afa,6e65d87c,700da998,ce651396), +S(609b6576,191514f4,83f5b428,500cfbaf,96871b8b,3348fe5c,1a131768,bb266b6f,90abb9c1,1bf184d2,8dbc424a,bbf74eb8,de4e0582,2ea5dd93,7d1e8b30,e5f695e7), +S(b5ec0263,27cfd922,23a46abf,a755e6fc,547806ea,333666cf,a43865a3,f4ae647,143353c,cc733d02,617f7764,7dc29c65,67a2e245,aed27120,e5fc11b3,95ffb9c9), +S(ac1fff6,cd869ed5,ca920544,1ceb990c,ce304998,10e27587,6536dcd8,1d4cd15,67a7a012,3e5ea292,85dedf0a,9f138b80,58a1d23c,2a233c5d,783bec39,b6482126), +S(c1807552,644130a3,f9b8aea0,29fdccdd,59e03e27,ff2cb1f9,9d13cf0d,42da7b13,85e99587,f77a25b0,bc64b882,bd279fa3,5be0262e,c2f5253c,70a43261,bd1fe361), +S(42919187,2b3c6877,c3b91266,79266e49,9fa37a8d,74d094a8,8c4a3638,89c2717c,1e4bd2df,a9757d42,285cca1d,856b49b0,ad481ad,828d826e,8921f744,7e04d6ad), +S(d4b10124,283afe03,4b278e5a,91daf61b,be608417,fc845e1f,9b9f52a5,43659f2,fd070859,75e2bad6,b34e0396,47b81a87,cab9fb,fdba802f,6ae3cc8b,67cc98cb), +S(ec4c2c4c,722a54ae,edc37acd,cb6ac490,3077bdf6,3f2c145c,7eb25e74,87c046aa,327bfe37,d745283b,a385dfd0,8e30b61e,2b4e5499,4432be41,fd3f0d31,c00e9ed7), +S(559e40a7,e151eeeb,46442b86,aaf4922c,12030adf,7279bb2,2bca24c6,67566a05,5483756f,60d26b97,82033592,cec21681,c5b5496a,c47f600,2013e5e5,f2ea82df), +S(c1d2e92,19c0138a,9f0a34fd,acc92f4,eafe13cf,1c004b6a,3175133d,6cc7bf12,8fa653f2,a20c1262,be59c7db,20f12579,b2adb1ff,54d84ebc,e5ad4116,3d2ebc23), +S(1becc6c0,e4861825,576624e4,fa622c01,139d9cb0,50c12062,9b87ae6b,9622245,d8516472,656ea10f,5b23839d,43f64e,85fc727b,faafcb6c,fc9c6e89,bf9c038d), +S(c483c2b3,8ceefd35,a9fa9e7a,da242c,d618cd6c,8b3bcb62,e39d68e,c1effab2,71964aca,9101863a,d7c865f2,41e814ef,3c20face,f46246b6,4a742026,471b2495), +S(3487162e,40c7efa6,92bc827f,9af9121e,af5ac549,b4ab6585,6353d699,a94a3783,f5b29042,28833bd6,e3ce0deb,dc0396ca,42701752,f930f437,d042cab2,8f135c1a), +S(eb3b21fa,f733f15a,b94ee0e4,3378e9b6,47571aff,d69292ad,a1b107c8,ad511d5f,cd95b4ad,b8768858,cb750cbb,4fa64523,6b6fde59,ceb71dd4,73a7fe48,9e5a2304), +S(21c8dd7c,34d3f333,758d1d1b,72748fe0,8695af46,3d0bd9ad,e4a6498d,1d01e9df,634d8671,7b885f36,a54b6691,35c3c026,667f3cb6,f2577701,beb0d3bb,84f07940), +S(608e33b8,14998177,5d78e286,d5c6436f,99623417,4e887da0,a95274a0,d120b57d,5d094ca1,181f8dca,87d1e043,f798bfaa,f1004edf,a470fce0,7ff8b124,328397a5), +S(f77710b4,dbc5f7fb,ac6b015e,956ed26a,6bbfb540,6a931a30,d4215aed,de610c7,7508a762,a7333ca8,ac244d6,47e47647,c62c82d,387d8df6,175fb563,1de83d54), +S(f37040aa,b0347fe,976d5980,cbd83db5,4d8cb90e,7f2d2118,85159911,af769d61,df228dd7,67fa0d5c,d44c3f6d,b09e662b,99faa5c6,688b088d,949ddab1,6f11e42), +S(7bf929f3,25374a1b,a0cbaa50,db47fea2,a5d1e3f9,3c34bddc,ea5c2250,d8252071,8fe2d2bf,b23a6755,50f16760,a6511ae8,4e4d316c,45d7cd62,4411ad3f,c72805c), +S(261bc0f3,a69d636a,b82248,6132bf91,2ab7ca95,e9a4925,b3f68bb4,745ee63a,68f52f7,df1ec349,77856c74,7b280907,cb3d456f,988ff7a7,225c4ace,8457a804), +S(60ef138d,e7086d09,711defff,68dad211,88d7f878,d616efb6,dbd3d498,5b730243,ca7c3297,3c56b178,b0cfb8a,da98748a,c3d06cc0,7fe050d7,3a6a9695,52500f8e), +S(8bfef3d6,4be90cac,8b83bf20,906b4277,75a6d982,23d5141f,b74e3851,50bc5eec,ea8b6b4c,c7c8d9ba,809ca811,3621c72c,b82006d7,81ff5f25,32010fc9,57858324), +S(9ca85f3d,4ba47ab0,e9fc0a28,74cd10a4,a8ba9aeb,ff319405,6140fea9,6e395ff3,41182ce8,96554f45,93768fc3,a656981e,69719f05,5469f9e4,ba79de22,bcfe8a8e), +S(38cd0c79,437b1299,9567999a,f54d4f8e,82a6354c,8a93a5ef,56ca2ff5,8a1ce180,c96f5ed,d78de5,9f560716,82b60b13,f06de5f9,49206258,80544bfc,73dfa76a), +S(be37e05b,9369b159,6b390290,3eb8fa0f,f221f599,1270c5f0,47edf62e,a1d0e6e2,4fc860a7,1fa69a27,fbefd8c0,906fc68f,4713fa2a,b37aaa2a,7edd3c8c,d100963c), +S(aa640e99,b091512f,85faed73,a3ac8ede,ee120513,b661f812,9a046a74,d624aaaf,dfb48ad1,a01fd508,e5652406,b681cc9e,13d0d600,68411dae,72d68061,6f6b94ff), +S(d08bb931,f008a1a7,38a16200,9fbf1ab3,d3d455dd,47f45cd6,617e81,8b8e0245,18d92218,21c9a2ed,bcaa5d26,2b7aba18,1f7f1e,7f2007a9,ec6f7d18,f038d723), +S(4e6ed1f6,c39c894f,eaa53e1c,e115fda,75fecf8a,55794628,d9a2202a,9dd5c719,1bb97d73,2e0e137c,e9c94d4c,763f9a6d,e1496548,904460d,df1c3a2f,73b66c1e), +S(867e83ae,610a24bf,401119d,8e1af6dd,414a7161,52b2ffdc,50f71f77,2fa8409c,d5d21ad5,ef365994,b3ad0533,92df82a5,6f677cb3,8500781b,a769dd50,1f6d235), +S(6031361c,6dffc505,dc7e1887,bc75c1d9,5a9db023,8b7240e4,c254f855,b35686fa,b9a9a979,c6b8c576,11eeb783,8b4ac2ae,66506bb0,a203fdf6,3efa9b59,98c7643d), +S(8502d0f,34684503,68784822,f4510c5c,562ad30f,be29a792,f0667e83,b6f95773,cd0e6511,763674b5,57fac9f1,bb62f9e2,3163a0a4,cf08cd52,a6d10064,d8b02ade)}, +{S(840e41bf,13203a96,f41ea041,1ec034fd,db0dac3d,53b6bbc9,4f8a3a78,d0371235,71b51550,a79af319,56c9b3de,fcb167d0,c3e318eb,a852eedc,78490dc5,fdaaca85), +S(5678a034,a24a1607,d78036b2,23eaa3c3,845c9f9e,7293f656,7390354,2f714d5f,57f624be,ff5d1774,c6962dd4,d14cc565,acae170c,7aaf8c6d,b0552daf,e3bdf48c), +S(722012a5,57ed9c9f,9d737a87,39954469,ca12ab29,9dedbaca,507c1259,7a27c6f1,6c28881e,a0e62453,80d73a7f,499f05a4,d9a9c04f,c2ba11e6,9fdd0b6,7c5d5ee4), +S(70c638d9,3eeab892,8bccf1e4,82368eac,a03ca8f1,b30f7b2d,34258539,8c95c014,f8635082,3dc2a200,67dfb293,891929cf,18a810f2,5c85c169,159a4b44,b190a029), +S(2ce4a530,b5f6c77d,c0c4d891,6e89b24b,c25c04c2,723842d4,29300f82,5e260458,6f306154,4d1195ea,98b972e,91a962e2,95a2a4eb,9be03949,a789b01c,f61dd705), +S(89e71182,851bb441,c0af4e31,cad89dc7,3947369b,fef12eb6,b1dfa71a,72498c51,20b7ffd5,878718c2,2b5bfdc,ac422794,63aac0da,4bcdec2a,8f3b538e,3a9f574d), +S(f01f06b8,da0ba34c,e1045e83,adb95fbe,b76f134b,35235539,6b07f8de,9dd25869,afa0fb5b,45ad1f24,73460f17,5ff4bfd8,f162262,65c423fd,ebd92bc1,72f3aa7b), +S(f0c217c8,1dda2201,1f46648a,e096906d,71fba006,1b4dfdb9,85dfe59c,9d8f1894,d5ddd6b7,bdf2a6f6,cba166ae,4c01c60,b012c9ee,ad954a46,6f631f9f,928b3fc), +S(bd9acff2,87cc2a2b,396aef61,b0937a49,c43a2366,a2c3c461,c1283987,a7b6f53,828de0ad,b9067b2d,8f8fefe6,ce3a5c94,e7d63ea1,7c891d2c,5f266e8c,a5fac116), +S(ee314d97,2b9c10a4,fec9f8d,ccab0015,d4923e52,d915eae8,b319911c,7a8fe379,82057aef,ff05c496,ba8b4753,c4e57832,aba9a724,adf70a9f,1b3765ef,952ab52), +S(d39fa7b,9b87ee2a,aa32454a,13470406,c8024c39,cf387143,3364de62,cb94c103,5cf1309,530f9e09,c9b38ad9,3a778ec5,533f60f6,4a42e31,1cd97c2f,c984b9cc), +S(5ab1a07e,5f6aff68,16780e5a,23c9faff,b29cd7d7,5bfb8984,4834fb6b,c6b34a14,deac47fd,6567023e,b5ec7a94,a0133bbf,158c0425,c0a6d288,23558986,314d54bd), +S(b1a4ecc6,94bb5212,98e80464,cffacd32,331ebc7c,4d545141,a129b522,a4818830,9772044f,3722ec57,d76a049b,2afce2b6,319f0bbc,b17c7f06,175a288f,3ce3534d), +S(56015e42,81aed744,a0859e29,eb913a7c,b44ebd39,2ed8c0b7,1eb42f9c,9c93c8ba,8f973650,45f7d8a9,24a276ac,20056895,fb2b0aaa,4b35468a,a51f41f,722b9d33), +S(7d99a5c5,21543229,c8f9c7b,50dbaa64,b200bf86,47c71b35,a0105dde,2b3a8e0c,eae09ef,3ffdec8b,9a30291c,244c0a72,6466c26d,fe2c8d30,174f57fd,ec6aba60), +S(ab7d21f9,1e7dac68,afd6e4e4,794551d5,55a9f42,59825109,5b25652e,946ebdae,8805a806,710ed7b0,fb99ff30,130c074c,6a0be3d2,abe6e155,f9c07496,f8b92454), +S(b31a5f85,d65e5200,8f5261cd,fd6d36f6,4b2a1f3a,6f08d7b8,defc7e84,21d0f7db,2e6d46c3,3733b3b5,597a133f,7459ee2b,570ba333,4d1e7648,1980dda,1aa8d2d3), +S(30af789e,850c8ef8,9eeb226b,27786679,442a9a0c,35cb7337,98345400,29220fc5,f6651170,c83e24e1,eb6e8da,ffa0b0bb,a6c53676,72558d44,c5b77176,3d9b5d7f), +S(8d87f808,98fb8007,ffd5093a,bc6bad2d,23e09e90,e6967031,48d5418,4c60e0ae,3d14332c,21df527f,a2e98243,d3ed4bd0,6634d799,9f62efd,e8d6c919,8ed716a3), +S(a961c219,eb9ea127,205af30d,909ef732,8cc599a,b2080966,f615796e,1126dd98,3e235ae0,37b10074,32e5cee5,56778856,1d552e3e,bf40bb82,5b527cac,8e1e5b9c), +S(b9c2de21,40cea728,2aec5293,bb77dc7b,550a72c8,84389c05,310651bc,7570f2ea,74171cd9,4a5683b7,5bc7c5d9,b4c8fc10,1fecc3b1,b7349ce,840b6ca4,877fed21), +S(cd041ff2,e8191946,8fd7ef0,c33021d2,9533cd75,64772252,c686f718,7e33166b,3f54a9af,e8597bb,faccbbd2,9280e60,93d31bc5,b366aff2,2c95e21b,fbca6041), +S(adfce0b5,8a9cef85,e690b84a,c7ccc6,8f5aa4de,ada5e265,3720412b,e1f19ae,8ae2dcdb,c6ce83be,825593d6,87f9afbe,a88af079,564c60d5,c9b88898,897515ea), +S(833a50c2,cb5507c6,60bd450e,cde341c9,64f2809a,e400215,c52dfaa0,9825df96,de85e216,493cdb4c,4541f720,201f4c67,1472b6a,d61cf8ea,3cf54ccd,a4584b77), +S(3475027a,628ea423,2d689d70,d45e975d,39d62303,282b16b,1f94a427,3d7ea746,97c3052d,9270df78,6efbd2e7,beaa58cd,f864e28,905e3ab5,507cb9aa,e3c69160), +S(cbda2707,e61d9e40,124668ef,7ed83973,dd293dfd,221396a8,d27e7aa1,392edcb3,fd5023a8,af8eff08,f0e3c8b9,b6a22a99,b3ec3aeb,7e0104dc,1f8409cc,d83d8a02), +S(963722ec,aced2105,2bf447fe,619a8532,dc78816e,2e17a111,3ffc601d,9bec0381,f31feba,259f7d0e,3c326c69,53aae60c,1e0479da,5ca839ea,77c6f1a4,9419172c), +S(fc531e1d,49d2a984,83c861b2,b299b8fd,b26831e0,3bced6da,5c4449b0,18363be7,9f9cc9b0,8d72ced1,998c6329,a17695d9,c94cfc76,ba9f6943,1c5dab83,60f2942), +S(dab255f5,b47d96d8,ec5272b,5cde4ca4,33070920,84aa4866,d53b674a,330aea2,feeda13b,a544f090,b790514a,42064cea,509bb3f3,9dbd4567,6bd75414,37579d7c), +S(ac5b161c,fcc42998,71b49d1f,8cf35bd4,dd6bf98e,5f84f2f6,420bc363,b9cac257,4511d4d3,1fa26d7f,e56f671d,7467bbd0,41358b36,b60775f8,65f7d491,3d17b685), +S(b62fbfcc,2aca0706,b0fe67f4,ed5d96b,4a65b048,f73e8f4c,9782e1ee,36189e31,6549e8c2,f77bc824,4e1a90b4,e42ca64a,5ade1768,a0996d69,8d7b047,7bfbf862), +S(56938443,5e509000,5cf3dd18,ea629078,e15097e9,da7bb5c5,737cfa0a,a40e8818,f86a1815,4f379054,11016994,9b2eba6b,477c32b8,b68091a4,4b14990a,5e8eaf92)}, +{S(7c028bd1,75367939,74871a6b,cc957d95,3813331c,87ae606c,17aecbdf,a704ebb4,4fea040b,a0ef0319,91ff9b8b,7829c0c3,93895439,d506c5c3,1a1a3fd9,e32e7e59), +S(24e966d0,bf1227ca,11eb8fd7,8dc5369d,2bb9b681,927990b6,dd02b948,fc18a169,72b7fa7c,f929a6b1,c556a372,4149a279,8d57f504,4b50a1a7,922cfddc,17308ca7), +S(a2b7db3a,265b30aa,94823577,6d5ea839,c4fe564b,97a5e3da,313f7fc4,5de617c5,5e895546,a2778162,4a91ea4e,c104c911,85f3e954,f8378fc2,bea41a3,f1cc9e15), +S(e365c695,449c9976,cb67ede3,325d9229,ee526349,e6b255f7,f4e72184,6722580b,eff99cdf,a0920505,ac37e46,b812d47b,31a29113,e491208,a19e3edb,557ac2e), +S(c3d90905,297c3a65,2c6c3d5d,915cd9c2,d741f472,4a47c8cf,35e5cf3,cac9dd11,8e9ebbd,34a7dd02,24fa6e33,193cdd72,4906dc81,a5aa41ee,4a34d3d0,4b2ee5b3), +S(6e4e23cd,ee4388d6,e8b61f8a,af7678d1,a62b3e1a,3385d278,895a02a,de4c9f00,f69b843b,ae39cf41,11fe9b99,a0287057,5695421e,e1ea690e,2e76d937,e7e32c01), +S(92eb38a6,3743088a,39b58cad,4eb4a27e,a8b08c27,444d704,6d2aa5f4,89713217,22af8d6c,d3567a6d,cf7403ef,e0afea02,48ea4266,1577005a,9afb5f2a,19611864), +S(b3c84323,e2d022fd,d2a80d07,203f4a26,f5d32dae,62842072,9663a994,3a829d08,9a899de,82329d94,83b88e1e,1bce53ed,8714cad4,c68cd491,1b71bc0a,e3839821), +S(daae5199,57a6002,8958b22e,6dbbee20,c4bbd8e1,7ed589e,b8528f35,7a4dbb40,afec8a03,321586ec,ac38e941,7fa8e342,f0542193,59decf5e,56479a39,c32f92af), +S(7afb9a56,89fd1344,cdbc5c72,62dff7b,718c2e47,a6e19ec,665af795,86ed0161,d1c2c9cb,60a191a9,a3db7e20,2ebc2eff,444bbaa8,d81ba086,6f8825f3,8c765f53), +S(8d0c4a2a,e72b54c6,236d997d,61a2a24f,ddbd39c7,ee16f1e7,d7c45b22,b4bfdac8,15a58f4f,fdad9e3f,b4d33c7e,170747cc,6a5abfdd,bfbe5814,ef0c3611,6a0a9e91), +S(24d8c0ca,53400126,347e67f3,72f19298,595b6d33,76ba2f19,2fba6dd1,7b57bda1,7c01404f,bd316814,f10734a1,559049ca,d6f20e90,d6b13ed5,f9542630,db77f9ec), +S(4c2b7a58,87a49df4,f98cfc72,22fdd832,362b8cc4,c5f4fff4,d0a20674,c9749bde,c2a1cfcd,e8636288,31a5c450,fb5cf552,c76e581f,9274e5d9,888a3a68,c37ca349), +S(2028e381,f42cc2f7,a8829308,bb72881e,94e5b54e,3331d848,898ccabc,bf971cb,16debea0,203f0709,d9b55b0d,2b8651b5,cb085d8c,8f56708d,c1fe4d33,a616dfab), +S(d11e0753,f72b7c4e,641ed50f,84dfa24d,a0baea77,98fcf062,8b2696ba,a7ec2529,55af37fe,88324646,777387e5,a9b18059,ace20e9,becd7488,5e43fee5,fa6809e2), +S(72309865,b8a1a6f3,9d6d561f,43ddf5b7,f2d022ed,95df130b,2563eaff,9008a95,f3fca0be,3ce7d9eb,e1648964,58eba87e,934d000b,a535f223,868dae11,dd5230e), +S(adca4785,cbf38a0f,28de7b36,daccc761,89b8b918,f3fafa7b,abbbd9b1,4ed5485f,880d76a6,fbcce864,657edb9b,349f124d,1b22c7af,2b0ff833,40d7a0c4,84b49de0), +S(bb43e0c0,93d58c6f,3946e58e,4727d7e2,d223c84d,513c4e2,222406bc,aafb03c2,c00f7dc8,fcbd55b3,6a95f2f4,a3a07b7f,9599736f,af099a69,e2fc2630,a2aef1d5), +S(179eb588,d1c7aa5a,24e51f5e,6d86e4ed,2e6f0f98,bf956b71,ec1caca1,b7f775cf,42f461c8,a784f643,d5a8682a,6ec9b470,455f0ab9,f269140,b1ad2376,95f64afd), +S(9144fc75,b00f8608,714f027,16b30575,be19dc01,d3689e8d,2665d967,6a077d11,b168c324,7dc6c31e,8302b6df,a2e7c053,dd849538,f9d45b87,14d889ec,cc789704), +S(d6cd2a7a,b7253b86,34231eb3,2793f062,bdf103b2,4fade912,6206e745,a3b429a7,9903e507,dc5e3a61,d73fc83c,5c4ba476,6ae92655,9b208369,bee55948,4bfe444a), +S(264845ed,623bd3f3,808ca51e,517def45,1fbc237b,e47e3ded,70c3769b,391a9f83,cb5022fe,3d535f4d,192e73d8,5d9ede23,78e0824c,e560a97,d53aabdd,f8717377), +S(2df9621c,cf3e67da,54c47ddf,81e3ba7e,7b50e713,cc7d08ac,d64f47e9,85c4f334,8058f6e8,139d8e87,cce4a389,c470e3d8,45da3537,ccead4f3,abbccf42,a5fcc49f), +S(ccfd6c4,c5966144,32d2efc4,1ccfa0eb,3e0b44ed,a4558128,c3e4d68d,949a5cac,bc77b87b,5f50d3a9,6b28d5cf,fb371b4a,36cc1360,15c548b3,f98d661a,beda8acf), +S(4e2e6052,cd35d585,6531fcf1,73bf124d,3c569bf6,6cc54ed6,9a520d42,cb836296,6381d100,e5d9ae50,f1821122,b8e91a5e,f365edee,556fee1c,2fdb6d17,3fd29c65), +S(6603d715,ed0f8725,7d9c3f29,cf86ad4c,aa0500ca,fa16a708,3168e265,b87d0255,9d2eda4a,6195e2c4,a4576e4d,5d02383,a3a01b2c,f94ab8fd,fef2f338,15807d31), +S(f09ef30d,fade81df,2fcafe31,387ed34,5a8029cb,e93fec3b,eaaeb8ac,8adc9803,f9f3039e,5b73c7cc,cf841eb8,1c15203f,ba192e,9eb39aeb,36f56c29,44b286bb), +S(ebf4611f,cb3a44a9,f9d5b00a,c559dbb5,394840c8,41a06496,bbd2011a,2508cc34,1e183324,9a610584,5d62ef4b,685152e5,c75c7525,c703f81,51bdd87c,6fda0d43), +S(31fc3226,c19aea7b,4845ff2a,ddeca6a9,36505a49,92102cb3,499d66f8,a6e1a3b5,49babd41,b1e8a6c,a728f971,d8d8cb76,47cdb94b,89767a67,fd975ac6,93f144d1), +S(be1e37d9,dadc4b4b,7a5ba74d,fb7eb55c,2b0a4fdd,81564f8d,51038afe,f716e3d2,de6f0c3d,b6efc974,975a7d6d,3c6e9d44,a712879e,4e95c612,164273bc,5de1f4b), +S(f8034e14,2425cdce,31e82b49,cde33ba8,3630d1ae,283b8b47,73960539,c67f1652,a302e3b1,860252a5,e7114568,748746ad,1e02c2e4,280bc913,dd4b4d2f,92a561af), +S(21e709bf,369cdb2d,b7f51b10,f0ff56c1,2c1938d6,18419d00,34e57d94,7b83d5e2,d7e09ab1,2e7d04f5,aab3a75f,8cf75876,ddc3cf0d,cb4b9526,ea7f755a,dfe1e495)}, +{S(638b6618,c1498946,75a1a943,8755a68,30d7dd3c,9d8a9f20,d65a7161,9c8b477f,e4e66035,e947c73a,c34a48b,b43a3762,d1038e6,893dee23,cf658a12,190d2a56), +S(4b6ce93a,acd4954e,cf0febd1,fc9a965e,ae7fbc1e,e24a12d3,a4b86573,62eb255d,8cea4838,1bdf4e5d,79e25ed0,1aab94b3,5f00267b,3ec7eeb6,63833507,583407b3), +S(e2a42110,3e8e2a80,a6451f71,b348434d,7d508023,beeed16a,d87417b8,5c7b7913,5fc15b62,124014e7,fa8f95cf,78ce8415,d46a1f97,d88be55a,76431786,8de3d605), +S(6949956,91582c2c,2e14576f,5ec0dd37,65133237,a4e43369,633edf69,933d1f75,5ca8c2a6,329882f5,2daf48e2,e291c48d,febbbd29,9ccc9ff,3ad54ed,33ccef43), +S(55d836af,2dd4b8a5,7f20eb57,6886790e,a3ccfcf9,2a2940b3,646f263d,685f62cd,7cc1ffe6,37781c72,d3cc26dd,9d4147c2,183c8e0a,95b87742,52ac47ac,19db266), +S(442a3090,46bbf3ef,503a138,b60ddfa0,ea4a5901,ae801003,f3f18ad9,9703a44e,129d9913,eff78c49,16e67c4c,cb658784,fa47da35,92ea1c98,4054b371,a275639b), +S(76981efa,29944c2d,9463fc94,67a92e1f,9403c287,dd595292,4860aee4,b78626ca,c87cb5c9,ce93ff3c,23189404,cabf8e09,996c4cde,e67935d5,874c705d,6a7f95ae), +S(42ad08fc,2a1eafc3,d793f04e,304831e,c1bae89,c7d00b24,7785d870,904bef5c,c3913fd3,6b8c08c2,553b9c48,5b90221e,ecdc8d02,6d558bc2,5fdd6ba3,df78ed63), +S(4d70ffbe,efc6254d,cee74a89,70244bd3,384b3af5,8510ca61,258fcbf8,f0c82575,ba3e19d,b022a75b,c75cbaea,84ff912b,867124d,a20e0d28,a007fb74,9a9d1c7b), +S(4ec8dca8,7079487c,adfd516,da2df139,5477b524,df4aa6d6,4db5e206,cfb14b9f,e88e5bad,c8654d60,fe1f8f6a,73328209,63bb10cd,31aae381,ea1b4d9c,eaf9cb27), +S(2e5a47c9,a47cbbb5,ef701784,34798a6c,48244df9,dab1e5d8,83c7f732,b89c7d79,7c8202dd,cf7fb6ec,471856d5,830d59e6,99c04377,c553d835,f64cb333,cc405c35), +S(3ca98150,bc5f116a,e7034a07,628d698f,67cbb8d3,74869ab1,534464f5,5e8ed24f,fad702ec,c6b738de,5b653f78,f51c98d2,1e4bad57,4db97730,58324d1e,12b89f9), +S(f414495d,9093ad22,11e001f8,b07b38bd,f5430a11,72899bcc,2c553b55,a9d4a225,bc130e93,998db229,6aef128a,5b8e5b9,9cf67eb7,713aa7d9,9fc4c902,af660f4b), +S(44e794c9,5a28ee80,f9b64193,9c626a78,4a851a4f,84f28887,9eaec508,1b60e508,b219e000,1b07a275,f63dfb3b,e977a40a,f505be1e,d3eb8194,b919b9ea,70d7198a), +S(35024622,bc17bec1,9c352280,297ddf7f,41654c08,61c3744b,13c74ed5,6673b98,64aece4c,3ec0b19c,cdbc06b7,4eb15704,50ff689e,6c5bafb7,6ae99396,12f4cca0), +S(45c4f36c,ac4c4738,ab216363,e12b2475,50b8ef09,7a986ce1,60b0462f,f8725a58,fb944806,dee59834,7d256885,3761e3a,9ae666b,9b0ee095,fea33ec7,bbce9a5f), +S(20a0b4f7,cfb58bd8,d09d008d,70e7f807,b4fa61ff,65f2e15,f00bddeb,55df1124,7961d1de,e98ca40f,4d09e5fc,52ae4916,cafdd6e,2bdb9f9d,2776239c,a3480157), +S(fa10af8c,eb2de4c9,3c0c2cb0,95f95911,755b19d9,90f17e33,69930d6,6002fcd3,68a3bfb4,533bb5f0,54fbf91c,b771b08e,e388a61a,9727bb7f,a3a1f67e,60b2eba7), +S(d417d7dd,30ebe9f1,7d52edd6,c82d91f9,25d5987f,a6f53b0e,d769a34f,e557c11e,ea89c810,619e32f2,369258ae,8ad8a456,cc36d87e,b45a42d3,83956039,62e437c8), +S(349b002d,ecee0e4,1788a3c0,cabb9ff7,c17848e2,78ef8905,63924c55,52d59853,47583a2e,7ff61b9,6fa168b5,1191b363,efa3e0a1,ce825a3c,5bb04e5b,e403b4b0), +S(4b8efc8d,7eeb3554,b5128e8d,ce20c29,697f79cb,29f61b4e,a2f7ac28,57910bb,e3cef657,7b5c0d2f,dee52c96,b6353073,b099fc9c,65688969,24cd744b,981c5ff0), +S(f356e8cf,5785b05e,e99a2b4,d202b64,2b1e98c2,57741e60,7241fb9f,d3f5ea2f,9079fd65,59d5a93f,91370d16,20ba487a,a8c6ad3d,e67f2c83,a1c335,fb5398a2), +S(bfb74aa2,15e5ce36,97cb6156,c2666ef7,1b579a50,56ff60ba,d3d5e10a,7eb2d31f,3def8a80,ddc3f407,e30d11fb,232f0e31,191bba1,d51a7eaf,b86d7f97,45d78dce), +S(658748bc,bbc75ba,30c969fa,371fc1d7,76c32a5c,7e632201,264deb36,b296ad2a,c173fe4b,14ead07c,2c6574c,8887500b,53f6c02e,dbd4048b,e69aab41,9267ef9f), +S(f51a5ca6,fd6dde25,447fa46f,c0984d26,66004c02,8d402624,8886d0d4,604f6ad8,fd4290e1,7b2928aa,f2e03b98,97252b82,d481c4c5,ad4edda6,16dc1cd8,e7ee83b2), +S(20ef1ab3,491b8d0d,a1565e2,8dd92dff,efcb88f,e88c6c2f,6b100b30,b58249b6,6814d32,7b5b94c4,12fb770e,2fc4077f,fa9a336c,9e7db2a4,bc7dffa4,286eee0), +S(d98785a,82dfe5de,343bea0,d91cd8c4,93344b86,7fffe1e6,efd7758a,90cdd899,37ad7f7c,5783d262,5204bac3,4405c207,972b7fb4,cccc3585,ee152f0a,48ee16c4), +S(3885e910,18a66e64,2d3f0c76,bca6dc82,a6916cb,1e46a858,7aff5ea2,d9390689,20765590,83ba89c2,14be9178,46e40553,ea195c49,de203c9,d175296e,a4430819), +S(c88cf650,3b50f5eb,7bac15fe,2097ff76,9c57b983,1b5d05c9,fbd8dc58,d4a9a746,b6443b76,64984192,e7056478,e9f372cb,21a0c7c0,cfcb0e84,850443a0,25ff42b6), +S(2831fddb,2ba2d301,2dedd58,a3f47434,3450985e,80e4e4c1,646745cb,1abc69d4,1b04e1b7,db84b6c4,882f264c,7bba91d5,2256dc97,fdd22e58,483dec32,5020a257), +S(5e492bf,c9d19dcb,c3bcb9a8,b7bec84c,23c359de,a78aa0a1,e0522232,df037abc,614fe5b7,cffedd76,35d371b5,2d89baf0,55af687d,e6c12d80,b221d0b3,9d03d0ac), +S(bbc64d06,681957e9,685c9864,c5f9bfda,34b4dd02,6b749399,a12bd8de,87f311e7,3c525096,dd6b7d11,26c6ca50,5064da63,f7f6a203,87594f4f,e4ae0403,fb4d66b6)}, +{S(2b00c7db,16887372,753ab219,17092563,8c603992,f501b07c,9d8442b3,721addf9,8e7c5f66,4c2493ec,77cc74ef,d9221235,f26bd3bd,6f505347,39f0fe19,c41b9fad), +S(56b9a3eb,d9360224,56267f52,21ade9f9,674863ee,4bacb7c9,ef0155ca,b36b336e,2e2b1a4d,f6c150c8,6dcfe9d2,e2836579,f82ac4d4,2f8fa4d5,d814b952,e92da69e), +S(ff52bbc2,83bd15ad,523e6d08,873a8896,9449a1c1,c5ec8570,ed532000,5a92aa3f,dd9c534b,e59d3845,a1943435,1a20513d,1a829424,e65ed8ad,60342b38,6578b21), +S(84f79356,86b0d45a,13a1ce22,7e7c925e,d80be5d9,9fd7e671,270c4c35,7254e9ce,3dfe2058,1e91dc25,12c16951,c667fbe6,83192bf3,3fc0bdec,c760dff6,730f82be), +S(db14da0a,86bcd275,71cb9348,36268bb,85c306c8,9ee1b78b,83c247a1,71c7355d,66ba535e,81e877b4,71b0b75a,6545970d,6e33cbe0,ff011e3f,d653d026,f4fff395), +S(28bfbd9e,44554371,74a4c24a,cc65ef45,5fd4d39e,b466e94,358cef4b,b0eeaa5,5f5ce6de,2925acc9,e503d731,d46601aa,7e668001,669819cf,fa54b3e3,dbb98f32), +S(a7b21a3f,a07b4049,7f9f5087,c763b431,d5f04cd0,e7b7e0dc,f9c6c664,df7c6ac7,daf23f35,b903ecc,af4f50cf,459deac9,85d0d008,3b5afa73,7131a61d,8591bf9c), +S(12fac42a,40935aa,e881894d,245b9691,cd1f6ad0,e0481e1f,444e0ccb,6ee88781,c519e0b9,e3c19fc8,f67c07e4,f357f43d,589ec23c,7714f7a0,4347be96,4ca572fb), +S(5c2e28bc,94f8639e,50133dba,9b6c8a35,348eefdd,2fdbc18f,2abb792,eb8807dd,c546b3c2,5f2809e2,7977a8e2,3a1c3ddf,36229f31,434c90e9,1386ee84,b64e8fdb), +S(e8e73382,fbe8b94e,58bef90b,aeb28305,d27ea48d,9c5f6e08,ef47e4dd,5fad6b78,d3529a2e,86240f06,a63ba03b,ce419c05,24d22622,fab9107d,aaf3016c,6ff7fe3e), +S(26b93629,ebe68d1e,878e94b7,5babd663,6fe1f6f8,659b155a,e10801eb,c2cc51d9,f4630056,b3e532f7,32238911,555c0ffd,f4951c9a,b2f45119,cb12e774,aaa2666), +S(57b3b642,431f793f,24862328,dbd271ae,19d343eb,c3b0ca7c,affe4fcb,319d8d94,1d7ed35a,5abc7e39,1858a9fd,b90f907e,6a065648,c00f94a7,75f06d2b,1cacef1a), +S(c2123794,d98f0311,c1327522,1767236a,6f45cb14,8fcd65d7,e0be8d13,2a650953,d5a382f,fcc2ffba,3917763d,ebe0549d,66f358b,d727c281,288551f8,4ecd193b), +S(16789662,9208b510,7528efd1,36036980,994d6c3e,5b34c69f,ef3b86a4,3db9e8f2,217105f8,39b0ae0e,932b5207,e8e7c190,3ea463c5,40c043aa,e4f8b106,97ccc84b), +S(3a0b8ffc,83a1702e,214adfc3,79bec5a9,753274ef,9e3271ca,8ec5b067,a5f3b6cf,2c3de01b,f27dd574,4496c2a4,75a07e60,71ee60ef,7eaf1c94,c257418b,744d1338), +S(482e5ac2,6477feb7,6c848d58,40173d87,1687c5b7,3b2970ec,b8dd69e9,3393f923,dfb3995a,ca5b54a3,b48e1dc,107023d4,dbd7a918,6adf2af0,61f92160,76e7f78c), +S(3869373d,638a30cb,63177204,bfb194f0,2c6ff503,3cb4ef1f,b146741a,f3b495ed,f2ac9f3a,ca159c7,c2ce9f48,e895c543,d3f19066,74f335b9,efdc4b47,4ccc23c3), +S(98c16ec8,54b34ea2,f08aa4fd,3ce1877d,4a36f2a6,4e673191,17f74e5d,86e57f4e,3448646f,c9aaab0f,4d9ec298,8f7c07ef,448888e7,6318e0ac,552d7cc,b59820a3), +S(1b3a4ebc,8ad1c200,2847e182,de7c9eba,f0f7a408,e2aa172d,484bb9d3,ab897b73,b93decef,69cf2da4,5c3a2373,ac2abd77,311fc1f9,21e7df8,5f5b3504,a5ecbdb4), +S(57b5b2d2,87bec103,e4aa7b96,16129718,64780441,fb5ef847,19f16d,a1c909fe,2c2d983c,d8c37a7d,653716e6,15756121,9e5ad5ab,25664967,67a0fbd8,e8180c71), +S(cd7e277b,ae1498a1,8e7bc00c,2c299a49,69f6862b,bf96e6d9,f5143db8,7b582115,f9548ddf,c27108bb,38f80025,6ffdc25e,28621c17,c370a40e,5009b968,d40660bc), +S(80615f12,82ed7a8f,bdd70890,77c24f18,c03fa395,3cbea7bd,32a26c7c,260102e7,8d54a3a2,83383d6c,a633d17d,e2f4f756,3bcc3826,10cc1012,3f2f192b,e654c2cb), +S(9b16f5dd,c8c8c8d,53786b49,e2d025a6,838f6322,700fe105,7de6d78e,92281a9e,a36aa3c2,f2034285,76f5c570,63bb1bd7,e6e0410,2e1cd2dd,f100a54e,431ca08f), +S(f1d04075,35ffd40f,2a0b59f9,14ecf368,67700c5,b33e15c5,153fa9b1,c724d36c,22a8b48e,4db1d3d1,28cc735f,99db74d9,ba7457cc,67b8fb39,7b38fcbb,153f7c0a), +S(c252ae6b,cb711704,659c37a6,f425b215,1ac8a4c6,63420eba,899127e8,1d8df3b7,8e9a75ab,c5a2cd8c,d44331ea,b07e5d97,a30c6619,8e382261,642c0e10,8f6d46b3), +S(59f6fadb,4a8a3389,999b93d4,cdf1f8f0,4735b397,9fa5397e,64df420b,85876ed5,c6e8baae,fdeb7019,23a68b71,9c88596f,60742a38,db04d7e5,76bd1b8d,1ae25a6b), +S(3c2e03c9,3f610ffd,db519c7,80c201ce,b58ffed8,ee10e21f,d1610e99,33fd08c7,d339d979,38e1c5de,7492e7d2,d64fe34d,ed889d48,54670345,1c51432f,ec6c829), +S(59d16070,f9147ce5,5bac599e,aaace0ef,24c02ea6,85249cc6,ccfbeecb,a4bba83f,8105bf41,47f22f7b,18c73941,3a85ef06,40bf6805,51c68a10,e16be920,193977f), +S(3aca1182,3f31b2b,a12e628b,604b1010,62c45fce,22e15dd0,8b9b5ef9,a53dc02,bdca8ab2,d2dcab6e,3a98e7f8,7e192c19,cae60952,fc6f54bb,d46acb49,60d51c0a), +S(261e9b93,3648c7d8,d5255219,fd0634eb,112e1dd3,fcce0a04,135b2784,e67b5e32,e0eb5ec4,30b1f9ef,2bd10916,b21f4fe1,4cfc80c,2bc179e0,fceb8678,ff933068), +S(75918e0c,a0f03b34,40cd6239,c108bb72,f293a881,a1f2e9a,73c604b8,8c451c39,7f02a925,80e50aa2,5b786d10,422f1d80,2c42cb37,27f09ff1,1f5e0dd9,bf6a6c1c), +S(42025e76,3c05c64c,311a275d,d6f1fb3f,2da2108a,39ed24be,3de83123,b1c1d1e9,dba2eec,7405b67c,a1915b13,45702062,7bfeebb8,6b90dbd4,87849e5a,756921c6)}, +{S(ef2c5fa8,b23285e3,50d7f05d,bd8c96bc,6e662824,5b10e1cb,4b659bc5,ded5836f,1b37679e,1177b653,8975790a,4d5d2abe,3626d636,1d863e0e,1db5881e,8e0c54a8), +S(a1d5a92c,93df3c75,a06f9c2b,a604789d,fd487513,62d957be,68c033e8,3e202fe7,64c1c00a,3964fd5,b35fb52,b423b285,77c8d269,bb1ffd16,325c5e0f,7be08bdb), +S(ef13ec66,d46813ce,68038fcd,541e5e8,bdbc970d,337d7b5b,9099d0e4,3fa4288,7ad7f4f0,c8345229,96341248,b1455ebb,89aaeb6e,1ae9db25,1b86930c,9f779fd9), +S(aea7cf4c,afc1079e,e61396b6,2df9bac3,bf334745,54af4678,8621e337,4c7486c7,c0538605,5911c893,459b98b0,4be449f1,2e9f98cf,ef4cc292,9975d42a,f460d65), +S(8f082b3b,6476b4e9,ffb317e6,1fec0cbe,8e389041,1fdc87d6,8d4d26f5,44c2e6e3,eafc2bd0,d6570a7a,cf8bb5d1,6cdc1020,456473c9,e7fec1b7,fc6217cd,89d0a2a1), +S(e0d6310d,e5e664b3,164faddf,39c93676,4ddd3f0d,f5e007ef,5293ee35,980ae0cc,de093cfa,ca1033bf,47e88723,4978758a,74b93cc5,2cef48a3,daf4dda9,adc79ccb), +S(2518110d,5d064422,5ead0e2a,5ac8b8b6,b1fb7fe1,55e351c5,1d39673d,dab0f6a7,84f0d6e4,b497043a,95b6af9d,e72cd502,a7b6a68d,ecaa01b0,9e0d8ff9,9d8a16c9), +S(6dc820b8,5db42353,c97453eb,d7d768cc,af9732d7,c261bc6f,8399caab,34cf5b93,30b168c0,2509e2f7,2035f60,8be8b89d,577b6e72,540f521,934fe980,7412459c), +S(bddc1c75,5bca9911,3c9ae05d,c14441e,2c707fe5,8a329f8d,feaa36ff,12771376,8c0087ca,b7688dcf,5a3cf1a3,3c27c7b9,cee36007,3aeb9b9f,d7088623,af20f62a), +S(b6e5ef5a,a84c6d2c,a209d50e,8fa8e1d7,93c61ed9,bfbc22d5,2ecf293c,9489ac13,f76e3adc,a89cb983,b6b670f9,5a7e774a,c015de5,1ba56417,40ac1f68,e3df377a), +S(26699dfe,93788eb8,d91cb601,cae628e5,75e8468e,73f6cefe,588755b8,c396071c,e5f9e00f,bcf6f1cc,cd39ab13,41cd06b0,ef2e789a,17d761f6,6a7a83b1,c036791f), +S(72f7e16f,77f0a4f7,92db2cd0,354382af,34282dc0,7b8cb290,a89a5d60,894e8090,54d32ecc,2cd022c6,c03f1379,657450b0,db9f08e9,6e2be5ab,5233dd84,62733cf), +S(f84ae7f8,a03b60,af9cc359,36f0ae78,96935b2c,534f852,8ad159bb,6c0b44e7,68f4dfc6,20a354d9,d6904bae,67792622,337e3180,ab340828,80bf04fd,f47cc23b), +S(5dea33b1,b5207880,6debbcbf,83ca17db,4617488c,ac5c6997,ad4092a9,8a7bff7b,99976fe5,ae88d36f,597e16bc,6dbbd4b4,547f4dcd,7e85786c,d10af30e,1d81bbaa), +S(31be76bd,4f946e41,7de73037,ceaa0dd7,c6eccedd,74399e14,2ae6fb2f,d2b59def,54ad8748,ef129085,dc3172aa,904cc376,e203fa69,38783007,2af33889,52cc6549), +S(b6124d0b,f603a00a,22662897,8dd0da87,fcaca5c4,fb04ebaa,81a7d13b,39f2e307,34ce08c7,4463b06c,afb03c02,583288eb,7bfa6f2d,3eedfed4,91e31781,dcff10da), +S(6aa4bd60,90bee70a,295c451c,c8af72bd,3665680f,545f46c0,bf5af990,aab5f43d,9c2364d8,25406b76,94ec9db,a0ea2f9d,bb36fb2c,5bda62a2,bec941c6,874e68f7), +S(f72faef0,e268a7b0,a9b00a57,3674d846,c1f0dcab,c9a586da,be318b1c,d2874d8b,16b3cfda,65db0f3d,1b5274cd,20b1329e,61ea0404,1f702e71,cd98708e,28c9307), +S(1d26df15,98a6b9a8,7c0a6171,767539e1,86d51d1d,cef130da,1001226f,87872c5c,f227cd82,becf5493,e2fc7635,6a37bb48,3e681a19,ab4d9dc7,92edb114,3a7b072e), +S(28690cb1,db697840,13e9eec4,d9388723,4c28451c,cf9dd51a,746d1274,b13b4610,d9bc39ef,19228981,a1ead1f8,94deb254,162fed5d,cbb58a76,6d361e04,3d8f62ea), +S(4b0b5258,22dbc31b,1966b004,4d39c5de,f2e16d5,1e032045,f9973b1e,fe83ca12,2db33ff4,3631fdc3,b3608b40,7dd494f6,ae730212,9619ae35,f6ea08eb,51aded12), +S(a5b4e205,462ae419,8fffc1e7,393d366f,c5a9eea4,e98c67ee,1684d63f,cc09aa64,d3c11017,de4ad175,17cd076f,cf6c0ce0,4d3108ed,60eabdf0,935499f9,4226078b), +S(d4f1af69,2a3e9fee,1f92d892,b14eef6a,a0ec1f4e,d4d455f3,c70bcb19,52fa9837,115c7ee,73b90adf,f142191b,eca0be01,7d5a651f,93e2e90,5a36646e,21790294), +S(c275c715,9d6e9757,d2adef47,2ee53856,dcf067db,bd4f380e,892c9832,708d46b6,70da1cdd,853a0dc8,a6a9043,3c319371,25590c9,5807284c,ae168f65,62e4465e), +S(d2e38b27,83156e2a,a8e4eac0,149bf2bd,bc2918af,1cfa2a23,d1c7136e,15dca7b,738a0fe,751ecfa3,459e005f,72b7461f,a4b5e1ed,736420d2,22c5428e,2ec1348c), +S(f8f5b3d,b3659174,e0149fc6,fa747c22,9607c434,8f9eab60,900bfe92,b23f9a4d,d89eff33,94a093fb,549fece1,4e11028a,614cdce2,21d5ac26,1bc25f32,dca3919c), +S(5e266403,e49fb860,e6ed0928,45bc0811,a214a0e,dcd6174b,290ecca9,3539d862,ab300acf,5d8b8a14,2fc9e93f,ea995d2c,d7a2bdb8,6a146f65,2b8bd49c,4e8dac1e), +S(8ff869a7,60230ba6,aa5adf91,1ba61702,17cbfdc,5ffa4018,b8a09b9e,4088d634,db5a5aae,bdb946db,80e4c207,22ce38c9,4921bf41,47eea510,70e5aac5,c592f32a), +S(f3d39b65,95bd5ab9,aeedc43f,f49bdb20,73a211f4,5ec2c1b7,72226a97,a31c059b,ea41abf,9322d733,bb5971ac,194da6a0,a6d41c6c,a0d0acaf,a53e17bd,dabcdc68), +S(18ba0c34,10169914,7f7589f9,179b94f9,daed92c9,287f3468,d283bdcc,d71cc637,b3512d25,c199d2a4,c115bd11,eb53d6a1,6ef16c3d,97be6291,5ff76b76,890ba675), +S(2cf3354d,7f96c58f,3c6336a0,6fa30c83,8da767af,48f89fc5,5ced5b40,e0b86cee,403ac306,f6c3ad55,be1ee5bc,29cdd46e,2e3d83ac,71050909,5f117d21,7ef015cf), +S(5d31d140,f754d6c,5943deb7,6aa4d867,cac81abd,9911618b,82327795,da8d085f,c25f99d0,5bc5d583,a3a72b41,4e5eac5f,c14ced01,98247ded,79ba482c,882bec49)}, +{S(e0ad91c6,6ca95326,d440f44,df91c1cd,cd3ec344,e906d0ef,51fd4a48,31ce293d,3559f3c,e349f7b3,cf66c17b,2c3fe7e6,8ba3804e,438c0816,b68ecfe2,30da18d), +S(d8b8c50c,ae9f285f,d6d9282c,373607d8,5fda59dc,71ba0066,148b378b,37440076,ef83dd08,ddc115cc,24948009,f9eb4afe,dcd65c64,b6ef2194,bb4ddd0f,ece180e6), +S(881fbbf1,a9627bd,369abbc2,edda8026,a61b10f,4161e442,530a5e36,447a0290,6a63cb8f,7e5094d3,c8beba5a,2a1d7b54,bc33005c,efdd5a1b,20d51f74,d00c2fcc), +S(36bc0df,fd1441be,1a4efd6a,43ab9d83,243d44bc,a6e108dc,fa9a79fe,23106f0e,eeec58b7,dc37eedb,4432dcff,4de7f88b,2a0e0721,da2c0a72,eadac4dd,71037ed9), +S(7652c155,c2ca8a23,7680f015,a62c7c31,31682752,a99c4329,77ccfb9d,cb58b03e,5339a51b,36ad4548,197d3018,4bde4428,b38ed983,d624bd18,a5f8c4e7,21871c5), +S(904774bb,fb8b0c12,e2b3f91a,e5a2a0c1,a92971f9,86e29fda,9edc609e,e85b222d,ee843f1,8039e251,9c7b23b3,725ca099,114b4f0,26970111,35ded92b,94445e2d), +S(1c7c82cb,fc14b9b2,cdb3c12c,32df33b6,a08e7af9,df62f310,79fa0710,f28f5f95,93471b5a,17c84eea,a45948df,80c0f56,d8684f35,1aa2ce73,ab84b3c,1b8250a4), +S(bb060f5d,971ce062,427a5630,8f114532,40ec54fe,6479d5e7,9ce81444,27f07927,fcbeaa69,8278eff3,d4dad904,836c0233,40a866b2,d8f66774,70d1159e,201501dd), +S(287c5b8b,8dc168ea,197200ea,97c4f63d,db0b620c,7f30d623,7934f856,a558438a,260630e6,ce310eb0,366acd78,bb58f4ef,27fe4836,edc8ff0f,5d5ff987,b659bd20), +S(7d4c5c6a,d6bb0f0a,47b45a35,1264f4e6,a81ee0b1,65a7e665,4b226c95,feb59dbb,e89691f3,ceb4c57f,5aabc1b7,4acd9aef,41531851,b41ec1c6,608f16a2,2243ab5e), +S(ff806f2b,9eaea4f6,47d85077,d8aa5052,9d4b96d2,1e0b31e0,7c86b14b,73b7ab4f,9acc2f77,a994997c,7a2b1aa0,79c0b5d4,c84f6715,e4a50e33,628b871f,8885ef9), +S(3ce795ba,1d91a9bc,b0260654,3450ced8,c94184dc,8a41ac5,e1b84856,e88927de,3492e696,cd1ab2dd,587d4707,ae34fd67,3ab7902c,d0c0972f,ef419795,1ad88a1), +S(299ad528,afa3f36b,c80a757f,f081a8d,c4a6ddc2,d2b57fbe,1e3d361b,ee5a5d8c,9fe823da,74eda2f,266a8e9b,331d511b,623dcd32,ef9ab7a7,f1d1cb4a,7e6fa65c), +S(bc4b0549,16177aa9,b52b29b7,cb91673c,9ffce4c,7d0066b,e4249383,4467e3b9,55bc6436,7db68687,e699cf6c,f2db9dd8,c2b9a438,8202fef5,11acdce0,ab06f969), +S(a8e8b02c,ff5de02a,9e6652cc,6fbe41cf,6e87ae0a,abb14ac5,a178b3d9,e697d0a1,285d4af9,405b03da,c57c993e,4b40df8e,82c6979,f8de57ce,4543b7ef,3381e0a8), +S(e50aa8b6,d7dcc055,4f406959,b056dac5,21a7842c,ffaf09a1,ac24a3d9,8aef5228,46656395,ee84d061,a9f5788a,cb05975d,5ffa5fae,edced564,1f81b5cd,2491c23f), +S(cb516899,98a214c3,c31e4f2,692cd7d,fad6f1aa,eb8afd1f,b29c23ce,429c224b,2292b8a4,5a89eb80,167238ef,2027f975,98a2aea9,a4460c5,3646d088,82403c63), +S(ded04c06,74c6eb16,557b5bed,4b6703d2,cc37c6aa,bae466e,ee7b5665,6693c3c9,4f3ea70f,8e75b02b,76934cc3,645d2af,eee8e9d0,8d100117,40e8a16c,dbf01113), +S(f3d0a253,edb74436,897e6cc6,621c74e1,30457b41,e0690b6f,7b2a203e,8ccf8ac8,89cb07e0,97495bdf,403490fa,d58eefe3,e79ffa33,1deb5cfd,2c548ec0,8771be67), +S(d4c66267,aa73ed55,bd68fee3,2a166a4a,4ec660fc,4cb13e18,fb6ab0fb,19a5f330,7c2efa2e,4509b221,97589483,40b6c74a,8ee2b5b6,5fbb794,7f838c47,ee03e2f0), +S(dbe9a638,f262f9a4,b3a8955f,22293feb,50ef4b32,20df0184,f363a373,d7110981,4c563e83,5e957756,5e6a8996,97510c67,9561972e,5601c1cb,2f2f789a,c1e0b5dc), +S(70c7c07,1b1e6fd0,a97b55cc,5ee34297,166f4d02,417a796b,eadcfd43,96e1b338,b5c49a6e,2ab03e55,f4755f37,e5211d4b,e23339d9,d464fd28,6781bb29,56db23bb), +S(aabc501c,6d52961a,a613fe66,96f0bacf,fad74fcf,8386cbf8,b18704bc,a1392ffc,cb72ba86,70bc3f7c,85a00d3d,76b11596,6cfa0fc7,44b31e01,9129da9,a5b04b77), +S(47f72ec6,e7820788,f0f7814f,aefd6e2e,af5d90f3,f877677d,ae72569f,c6a2e8f5,6709731b,ef2dd880,4696a6,a0661d13,fe579704,5e0a9bc0,e5fdc0af,789c5830), +S(20026251,d9413e42,47a5884c,209b144c,98e36f7d,8ef3f56a,68efd475,8a2ba8c6,9c5531b6,94ba0d24,a943d0c0,94bb623,75c798ca,c9716181,a9d659af,2acb978c), +S(8dfc6293,9b300c9b,fb617d23,6885f652,424b4f12,d04f8bf1,151d1ccf,935e445d,9a519433,18e94107,5472aa9d,6ec3390,59bd3bcb,bbbf6937,c9290e48,9da25f8f), +S(afef3520,3b558495,6fde0eff,5cfab48d,8fb08806,3c1d7cbe,d7e352c2,9d49176f,a764e6e7,bd0c8fa0,8a6f7f30,aa38d7de,fe71773,fb7ea484,68b3fd9a,8adfd650), +S(354c0a98,1628dfff,8be8ede,ed809db4,bc39c686,39a26828,ff28dd47,90801c46,8ff40299,d607036b,acd7c0ab,66a102ab,38f8d3a8,a271e2a5,20b43cbb,687cce6e), +S(da2e7eb1,1a1e66d9,5001ec4,f7b66c1e,d9f7d0ba,ea3bb326,672b9069,5cf4bebb,cbc1c7da,b9bf7e0c,dea9297c,5f45ad0b,9c4fb093,318b55f6,1e4a8951,726c4021), +S(6f780994,d0662667,8fa74156,4232bafb,b3a7f54b,a5b66507,9df32545,c192c3fb,5f11f0f3,af1a763e,4c9fdcb1,1e5e57a5,6dfe0d0f,f27535b4,4343a312,90e375e3), +S(8e28948c,729c1438,5bd09316,31ed3eb8,7acfc5f4,2a9eb4f8,afa50362,33591cec,2c09fa1c,bf0044eb,a78ae81f,bdbd4271,2a89ffdc,f7d476af,881d29fa,2627f250), +S(4011cf05,a85ef14f,1875cf3f,4f78a51,a52a89bd,a8930a4b,8e13802d,b85f319f,35045b10,45c4f71c,c762fa78,5b8d4daf,aa2a1c07,ba37d82d,ee0592ae,ad807810)}, +{S(9089bcb7,1c1559bf,e17f6c0b,91fc098,c63785fa,18a42d69,798b063f,a0930175,de229175,5e4ebf17,1047f79a,37d81b9f,9004a7cf,df747589,7365e174,ae367969), +S(4d1caeb3,41f25459,3b06f715,9e9418df,e29ee076,76c26e6a,51d8add2,5c70a5d1,bf773e4e,4151d17,650aa7ed,1d6a5505,2d622264,75c50f31,3261aea2,cf68dc37), +S(b0760330,517c0d66,2571cfae,830da7fc,a7e0d86c,1ca7f75f,5150f625,db50ad2,d8d10ef3,9c84bc13,32c2cc01,4d4df0fb,45e5c546,1849fb1b,81b7fdd0,7484d35b), +S(3db731e4,273e5b20,2de984c9,74b4112a,d0feebe3,7bb0d2c7,db38c7a,21bd8c67,b425c1d3,46b6a61f,2893a3aa,a243d60f,5563cba2,40018cca,3f80925f,71f4f1b1), +S(3a74a50d,cfbf2ff2,5c99c4d0,1a13a917,9f510c2d,eca1d5a,7ac8fb69,7eb9795,d2b468b6,714681f4,57bc586f,40585c01,e1dc14a1,a42ce887,9ce044d9,ddb92d82), +S(b9139ad5,4f44fed8,4917ad55,c49c23c7,8d62aadc,e83c9ebd,9efde865,cb1eb298,18068856,c80abc3e,2a02a441,bb7a7609,aae8d2d7,8abf4e2e,378fa3d0,a27aa900), +S(bcf5cf94,5887f183,e58a0128,4ed9a4f9,fcf918dd,4e68d70c,5a54eeff,166cb44c,8235f63b,bb06a1a6,d9ad2ae8,47aeb2b3,4838c962,9608943a,93294c6d,e21a3ab9), +S(4b598ce3,a77680c4,c5f66e90,1b76627a,27f35301,9641520f,53ea3894,dcbbd187,357af043,f77cb9fe,c04ce1f4,dd9b610f,9151d15b,3b7383e4,ecc5384a,8ff7c5cd), +S(b588aec9,2dc045e9,a95abd7e,da929837,28b5a7dc,d637001,ce7f0917,1283b16e,e682f53b,5e94fd84,914b7bed,5afc28a,30ae6f53,e12d948b,3c0d88fd,adc5d0e6), +S(eb8f5080,218ac5c3,cd792042,b59e80ed,e3857a75,a81d67e0,7c2221de,d3b7a677,c5f272cc,3734e0f4,6a5cf40,626973ae,1aa76839,1953f211,eb52693d,254a7fc3), +S(87d119ee,65a60dd9,aac3e784,22049cfb,4123d262,ac9e7473,4c9cc418,fb7ce4f0,5185ac,7bcaee8f,f1334eeb,cdf2c39e,83b8b665,1ef9d8f5,48a029c6,464242da), +S(cfd0438b,186d0f5,c64b5f38,a190baf7,35b67512,a439f486,fb79d501,90294683,985edeea,243e9c6b,d9c57cb5,c7372202,7492156f,e10bd2e5,67edd14,8603daf6), +S(52abfb67,5fa8b12f,1b0cf0d,8e85f402,47696662,64c7252f,69562590,839ce4f8,8483ab43,2d4851d7,4f432c0a,8e3863b9,783cff58,3d4c390a,9865d7f7,d1aed67f), +S(52926df,cf12eebd,3008459d,3c91dc1,73532f1d,ce3c5d0a,874ea4c,67331787,18b48fe6,1bd74ac6,4b34f2d0,e7de8920,2c875625,bcad84bd,cb3c81dc,cc86dd87), +S(695e09db,8c4479cf,4c305005,b5737ca0,63f89d02,aced2010,5600d65f,58e26401,32123a91,8bb23fd8,79715cc7,488184b7,53e0eb00,6dbbc95a,ef9d815f,3833c08d), +S(97c35716,e5aac70c,45dcdd45,a5ca0155,5962f09a,cc22c16b,c79ec272,ce1c12d3,93869464,6470f8e3,c0db18b6,2e4378e6,5caa7203,c4d6a079,a10c8182,b8eaec3a), +S(35197cbb,8da9188a,fc60faf9,71cf08fe,73372e15,f857b93b,6afd77e6,bf4db7ed,4e0efeb5,2db601dc,a539c777,14f4aede,c5ff121d,77dbdeee,7f16fb0c,4cfc19af), +S(afb2f842,e0818237,46c294b5,9ae8afd2,279e834f,100f7d1a,58a9551a,98408d49,5bf5ac43,a3609b4f,f058d6dc,6ae09fec,19a19864,6d12096b,6bd3e06d,95d15ae8), +S(a37f6113,882459,b1dc6335,26253a8d,287c9285,b7862721,f9bee74a,d2c4c09b,9ed3252a,303c6d,e01c9985,c5b3edce,1074d478,db56b961,d91fdaf5,1b1d07cd), +S(4579a503,cb12a345,182b28f6,9a3fb98c,4a80579b,2ff592d1,ab18b32d,212098d8,8c61c503,df79dcf2,6083f15b,c3ee1f99,9e1e0960,8bf6af9f,b3175699,cb0e32d5), +S(545031f7,883a2c8e,bd56a405,52719096,4aa1d40d,b22a1730,242f3064,530ce326,ecb024e8,e762b456,f62072e,5f471180,bbc817e7,54e830ee,7757ed7b,df5c9300), +S(b127fb32,bb3e193c,99d232e,d50dcad0,3b45c072,e0d521dd,de72daa9,e20e97b4,b198428,12a344b9,2e8a8d26,f7964c66,82cb3652,66ab3e28,2ba56197,a159f1a), +S(28cb3582,d312cfcc,75ab637d,66c646f7,5157dc74,7a464e9b,933c0820,2326b6cd,a87042b8,510ef9b3,ecf918d,916128e5,f946f43,6f18fd5f,ad62c46c,5882a23c), +S(8a46cb3,27efbeb6,850e3861,c4845ab1,21414f12,9fb27387,4560826d,c9116886,ab09eda1,9156f1f7,194b7b17,fce15268,ba041c96,24765ce,fd964ede,d1f05b3e), +S(b73af914,10ad56f7,d490dc37,1a2584bb,633de0f5,3f00cd0f,6b8a6019,53c7ef16,3dbf4e52,753e5d33,3fd23cc1,c839f278,38eacb3d,5980cba5,bf1be426,b27641a4), +S(b38c1896,427a0108,3f24a917,2a64314c,d9dc1759,60971135,1b2db6f7,d66ab745,d3a71a74,f80d6919,b65629f9,80c7757a,cc49c2aa,78dc67d3,d6f76d06,91a90d85), +S(6f6ac108,aa819a27,6dae862e,276b3ebd,8ed5a3ad,9b0296e0,4f8b65a7,f6a5ac1a,e3048583,7aa2140e,de381363,788d6d95,25a7ee33,9e3a3ed1,2518619b,30d9f71), +S(72f5809c,7c282ab3,4dd81851,33070d85,53999a6f,14fd753f,2ed8deec,ed7adc5b,112bf5fc,8cfd71e1,84ca1967,d05da765,801f12b4,c852768f,60afa7f1,e9576534), +S(4c348833,10f7dd6f,b385ce25,e2d6eef9,8556a59b,5e79a084,ec83425b,37150085,9c4c97e1,be47b073,5209ecf1,5f05cd8a,58ece74c,1b35a92d,96a70287,11d95add), +S(f16e4513,2291b577,ab360b42,c1babcdd,ac61e623,da85819,e9c4c73d,463204b2,5556d7d3,a2d45955,28781d15,16b59aad,941ea356,1b5c88ec,94d09314,555ea64b), +S(3580d3f7,896fb70e,d48d40f8,1b31a72b,51405574,2c2b4369,e3e7dcb,aca4ca22,e38da3af,f409e459,82098305,87aa0eb3,b2339959,75af2e33,501115ce,648360ee), +S(407e63d2,c0cd6d37,84c27734,f7e517fb,4bdf7847,296dc7c,a8714fab,16199828,2dbe5da7,4b29bcc,fe9adabb,69157830,987ac51f,389c6001,2577f298,710025f1)}, +{S(f61f644b,e2414c07,66c6caf7,5d32683d,efafb133,cb4d341d,7eb565e8,9f6e4158,2848548f,15a6e7d7,2b2eefc1,1b76e318,15ebb4b2,1e3bb938,e0c2e9d4,5ad4f7d1), +S(5b891f8,ec902550,429a5ea8,33fc29c0,bfdddf6b,a6f62c19,87a14050,a9689a9e,77901539,1ef92985,6d3e3b35,4e4ba2db,3bad967c,dedf331a,c0bff08e,f25f2e99), +S(d8c5a617,62655ffa,c943ba35,3b595b46,88012282,af068e52,d918bbec,46bec87b,9263db7f,6f74aa,df0dbdaa,7e7ccd76,cb3a498b,44de2bd5,f9b23029,2ebc6009), +S(2e940645,cd189edd,2d6cc2f4,f9b49e4d,305cfe8a,46f2a596,fbb55200,89fa5b21,4c197028,e89ef8a5,b5b6cbb1,3733e90,408877fe,7425d58,1f4bd063,ce286fb2), +S(396c3bd0,9c6af07d,123a8441,c9f79ab3,a783b8f3,fdd69dba,ba61c7ec,f65e3098,534c8657,aeb8cdc6,ea34b372,68f1c70,70881797,46b8e335,477c8525,cd17aa8b), +S(c34e6be,b079f3e8,d1355754,4246d2b7,a82d551b,740b4b59,b9220bbb,768796fe,57806a7,653ff7f9,3d7cb6,b3acf68e,aed049c5,75988fa5,f03b1ab5,1103aee8), +S(5d2d6aa5,252fc9b2,55d89773,e920891e,7021f233,5f7d0ff8,c6bde5eb,b65c5149,1fdbd2c5,6b8bd095,2d16c304,8d9c588b,2a26379a,17f748d,f1345695,1c5959c4), +S(dec812f5,745fcbed,fc36c635,76874bc5,96dde8ef,68a8724c,201b6af3,be7c6e2c,1715328a,f75f9661,d58c667e,5c5514d4,c99dc881,8cfbe702,e0c3c8cf,662e6906), +S(32499061,83487250,f65684b9,9434489d,3a83ec93,61531dfe,48086b2e,b2bd18fa,53217af1,2a25fc6f,45555d93,98fe46df,4247d38d,7b162e34,945f8928,bfe148ba), +S(d3e9381d,83f31116,ee161490,c9b5d1e5,7e086c6c,1552160,2c913315,af033ddb,97ae863d,34271b26,a4d6577a,32028c12,f092a54,8a18ae1b,a83de384,3b8fb84), +S(1347dca6,d097faa5,7c6583c1,c292c6b3,ed87b31e,9f7afe8f,d0d151ee,50ebdeb0,570a9be,e4806ee3,e30696c9,71b5d905,65d09ee6,8b4fa8e2,8acc54c0,7fabb492), +S(691f9995,af2bccbb,f556f624,b28a1da0,67854c15,4f014e92,a56a8cdd,9a43c25c,81babe0,ae44984c,bfdfa958,4dc5c677,881d1b0f,63993075,a3fc462d,e986866a), +S(cbfb62c0,b91cedb2,5a9d4b3,ada43cac,7839dd18,33174711,24688ca5,5f162cb,77c12161,e8199410,b040dd57,4d90c39c,2f1b499e,6b7c17c7,fb21438d,aff4e674), +S(53627516,8de62d6,2c792f64,f87996af,3ed8ec88,653532a8,ad60942e,cae4a339,d8449a0c,c6ae32ff,45a11652,97b3d3a0,57e67c64,42d3bdb1,ea2cbcbc,cf0655cc), +S(2a81679,7505601c,763e6f6d,f7ed5c0c,14ee7fbf,d75b8755,7bd57f3b,e2d3c7c,99f26af2,10540397,b8423da2,c4809942,63734d99,f0d642d8,96b5f216,767b759e), +S(54b2c03b,7a7ea964,220a255b,bb688767,99ff1b83,f0934e4f,fd03c2bb,51490e22,b3cc56a9,ada9240a,a3730828,26733090,ace3d7e3,91200d08,2cbfacfc,bcdb9c08), +S(aac88c8b,7c96e629,6f023e5e,8f260324,9f4e645,bd701705,8f38e9f3,a034eb57,da03ca87,b98ab6fb,e4869756,7c2db04b,7f9948d9,ea65d93f,d222d52f,6d48c552), +S(bfdd8394,fb49f93d,630f6b8d,469da38b,105529d6,70b9a1ab,e3196816,d2a13978,39a97919,4249f78e,c336b00e,475722e8,7ca734d4,3d1e97d4,d2aed074,abfacbe9), +S(5b5dc3d8,66ba3647,d2aab2ac,3338abbe,4d1ca08c,6cc6fb26,4335f40d,4dfb2331,3432ba31,46a0f15a,beca45e4,1ded8729,e6a0a49e,70315745,bfcb3388,4e1b9e64), +S(77057b28,a1d139a1,91e05ad,a8d72f3a,c7bbd198,7647070a,b6a21355,7bc0c73c,46f32321,4519afd2,f830cf7d,567aacc9,47ae6b8f,8c841adf,988e39ad,e7b9757b), +S(f6c8d1da,e28a3d23,2a388998,1b638b23,f381618f,18dc81ed,67bfa696,4cf1626f,2ad8c92d,43378941,8d298dc8,2cbf288e,86d21467,ac73c0e3,383ef3e0,a03142fe), +S(b75b5cc3,77a55310,a3b97067,34f1929,fc0db732,3265e6da,71405f37,729d5a90,be077940,4dc94ea3,3cff505c,e1aef457,bc120359,521eae05,1de1963d,b1948053), +S(a66d54d4,4b4d06ea,f141307e,27e1c225,41274eef,5c0b1743,e6398b22,fbaa4068,51b6b8a8,48e1c27f,107f82cd,d0554643,b9e16611,fa93b789,a2199b3e,3bdce296), +S(56b2f9,ab707dde,3479d0ea,baeb62a7,6cb9bf03,66278eed,559e027e,a1ea6b3b,27c47e9d,646684dd,2a54db0f,c245fcdd,721416f7,22ed568b,736e3e1b,f195b379), +S(a9642a49,83b19c3f,f5f63ea2,9e76afbf,a25dd0c0,221b32b7,6e67373,36e7f5db,8ada3766,9207c6b6,a6b6006b,5240a4d6,cdb8b807,c0c16a56,91289b7d,62b3a051), +S(18eef8d,f9e64c1c,548db40,ad77d92b,11f3ac43,60c63792,5f7d598d,7d8d5155,806db24,eefc3a64,c84da338,937811e1,20c6d0e6,9cde79ee,9957a4fe,c53d0e12), +S(d11359fe,61861a36,8b3809cc,c727320e,42905036,774d0e83,98453ac0,68d404b9,d4182ce7,2500637c,8e14b977,34fcad09,f061838d,57c555fa,420fbd50,9abf6b81), +S(7ea072e8,f60ff273,9cad1d8f,c560f208,b54149a2,5748900b,50830e3f,738b2db2,af09e54b,d44feb44,b39956af,fdca6894,91c7c6fd,f029e71b,e780f8f6,77a48a0f), +S(f53406ab,9fb1317,b038dc28,f0165abc,115b37fa,77d23bc9,e51993a7,8a15ba00,a293f429,f7fb281,9cb60b53,b2e6f07,afb6537a,39a18be,a5ad4cfa,55aea13a), +S(b1674e5f,9f194a16,94fd12d1,4b64ac8,bba69432,241aefd9,9a1c49d,23287635,83cb0060,1f5c33be,9436d946,22c3b3ce,68d20733,ee1e2392,8c3d6c14,a7cde085), +S(22b72e08,66b96344,ee53b898,ea725f7a,b5832c12,7c0881ce,862ea945,5eafee85,b886e8e9,cba29b15,be5c22d6,ada99b02,1098be69,d1c500fe,6fd2ef8b,f1ecae25), +S(9b7151af,698a85d,2246c88e,8ffb14a0,c762c2e2,64ab70b7,e30e2434,9b8370b7,fd9c3d89,46ee9d90,e7fb6d26,796062eb,4cb6c160,76df4834,eecd2748,c8a7bb4b)}, +{S(5ba26c2d,53b04b63,d260c6cf,392786d9,41a1a7c,b88331c1,149cd3b9,9c207f5c,9c7f6303,bd72850e,d4da618,3427e7f3,eee078,6f67cf9,85d483ef,79c2eab7), +S(f7d26944,6d29f81e,39a44a88,49f12184,b9f42eef,16c5d88f,60c96a28,cf0c3e48,e7ec965e,d0a966a7,45087e09,a058421b,852c8a7c,3790a3ef,7abc6ccc,e17c6084), +S(98590b7d,36bd2ef9,37ce788b,22cab951,d921724b,87c3ad83,8263416f,b5a67dc9,b711c21e,5af72a36,5cc1b220,7ed09ebe,be918555,55e9239a,e9b03d75,c0261d5c), +S(92e1cc4e,5f57514e,9ed13535,5f3e2cda,b0b22f8,8f56a972,a657dba4,7263463d,14d296bd,452f2faa,7d6f42e1,550fe35b,3c47eb2e,fe7636c6,2eef90b2,e7822da8), +S(33de9b1b,e153bdd6,efaf9d1a,30aa9b3d,faf26a32,4486b6aa,ecb1f958,f11c4673,7ef29223,4d3a565b,c0f0e295,deffa3c9,a86a6bf1,933a084f,9334b790,51eb0270), +S(f9fad0b7,e1dfd4b2,47cd2cbe,bd863e1,95b3be25,6cf7a707,5d422b9b,f5631ca6,fd5262f9,e6ca0cee,e1c7e531,83d9f3c0,7ac518b,c024681b,56c06a1d,1826f5ef), +S(455ec5ea,f34c02c6,961469ed,27bc7883,c07c9a18,663e22ca,83830a66,569b2b36,4dbf1b57,a7de2fdd,7c0380c2,b38fa5d3,697a5995,8ca0c0f7,6405244d,bff4c9), +S(940fa05,d96fb400,bac8fa39,e696c536,71a490d7,c98b3851,ef76ed35,c62bac19,b6de17b4,1a045978,5755497f,1c2a953f,17554b4,20f2ccaa,9fcfedf3,5afb9b46), +S(16012402,4ded6478,72374af4,6daf9c2d,a9000841,9a7d4672,98b627c2,420981b,7c2607e0,a4b86f7a,d5df7371,60987d21,35d2ce2d,bc422ab9,b643d080,26f84323), +S(caf887e3,339046ff,42c629ff,c954873,2c629ecf,319c44be,6701a9f7,c81bf842,d253a688,3b3d51c5,a914ffb7,46e7ab68,70c2b1ab,5b7e46c1,7a5119e8,4ab6c878), +S(41a5b720,595bfc66,18406547,d59ec09b,4efba0ec,5bbd3191,9e9256ce,f40a7afb,87ee1be5,2233ba8c,82dc06a3,6fd0a1b,4ee8d7d3,ce89cb56,1dc96c19,dad79613), +S(8bdcbe80,fe8533a,174045a8,3cf9d89a,ca438ef0,8f6393cf,6e24d923,edb02586,8d21379f,c053e8dc,c628f0cb,83a7782c,b4e946e3,ca88d467,36232762,fc6f8fdf), +S(409a4482,6b6f0ff6,36178d65,aedd64cd,2d28b39f,3e9cd93d,a0afe712,b75fcd19,25a3bec4,74216dae,d686825b,bee6aac,487a6d07,606e5aed,7c3032df,f4911eba), +S(b7f414a8,4c0af927,64ed5b52,e96dad38,6995771c,2cd90af1,1986bdc3,cbeb61c0,702b0a68,4e93f0a6,26b807d8,8049db6a,3e65001a,d75a476c,e4be230,89574e8e), +S(58b0cdd7,bed4f327,bcecd493,d835c0f0,e45f6fa4,3687d1d2,f19de285,5bcb5c11,21b0a478,2c1d14db,9c67817d,7b23db21,a96e456e,62a85c3f,2a02c76d,78dcad10), +S(c75cbf00,893447ba,5b3f8462,9d6897ff,64be841a,9a6bb714,54adb849,8df03900,15f68903,ae20ae4b,9b3fc7c4,f8135936,c09de15,18317dde,bcf66190,2db79f72), +S(e6258fd4,b63be23f,38361a16,cf3f81cf,f2d7343e,515b2d0c,ea0bfe38,6d4400a9,aedca212,9b73e49b,9757cd7d,a39a1e92,f885b267,a188521b,32089ae7,6d351eb0), +S(7c61b66d,d76f759f,be92708,8b075147,2ba10db2,eee4f0a4,2eac1ad0,d2dac3a6,c2b79de,70372e1a,6c9449af,2612e34a,8e101cc2,81ef378b,97cd77aa,bff004af), +S(29c71194,bbe41f4e,b2f58bf5,799616c3,7b247283,c993bce4,630929d7,55f7c8c4,c0fb083f,d68f63d3,599c2da,9d0c1f03,b6903545,a47581ff,3caecbf4,359e0235), +S(f1cd983,5bd3eb61,f8207495,48da075b,ff4191ff,d5b1521a,a1f4413f,2173a68e,beac8102,13b643a9,4658cdbc,71713894,39b72abc,f8644697,2fe6310b,4ff0233f), +S(94f2137a,ae170855,3af3dd45,8f8fc9d3,c1bf07e4,35a62798,25d5b93a,37380144,e952d6af,b27f9b2b,80ccbe89,59fb8b15,5fe1b2db,f3ffbf14,cf9c1fe9,b8e8209d), +S(f4f0cd2,e28cb8a1,9b469b18,90033912,4a40a39e,67ae1642,a3a677b9,fa1a9a3c,75412f04,5c41770d,73d7cd77,bce0da96,1e6fc69,cfc6cb9,8f691d43,dce1e548), +S(15ba2fd,b652ea98,f2b326ee,e5e1629b,ec8f8e7a,36078d7,cb8a80c8,c943e98a,db416844,cf757376,cfcd5a9a,9a318b51,184f8c89,fcda3d97,e735c120,43d47c35), +S(5754903c,ffa8cb6a,3ffe3488,e484c498,69163b77,7c07183e,8d2da037,78b8da34,508312e,6c2fd008,fac12bd,afdf8e50,1940a81b,d05efd38,5277a85c,ccf125da), +S(3bc76f6b,8abc155a,dbba76a1,9c0fef85,373bb1bc,9775f431,1b3ccb12,9c7fb29c,48036702,aea467ec,daa8b809,97c41c07,9e38c414,f798bdc3,a531b08b,fb4ae303), +S(2992c410,306d3d40,313ef69c,a2e3383,88f592d4,a9c2bd36,ebd9f51e,883aa33,cdecc5df,41cd193a,ecb26700,baa42486,a0506372,d56de3e2,2fa09156,7b525519), +S(baa7d83d,6d70a528,e6392adb,b2af797c,72772b92,ace96a25,90d65c37,b0ff1bc,9943b555,4e44b480,28815d8b,e50189d3,6617e9b6,c8f07393,8309e04c,9978fad7), +S(935488ea,4c88c2e3,cda6c0ab,5b42d519,e7fabe09,fdd3e36a,7c78c9bd,730612fe,705c8f8b,228be0c5,539eae13,1f4f4bdc,2fecf6ce,6cc567c4,dc692af9,7c1d506d), +S(8edeb68d,e63c35e2,5e36bc8,61445a63,8b0637ab,d14557bc,f0b0648b,db43f86a,d20bd0ec,14ef4f35,68954130,6577ef85,baeeeed1,c1004130,80687a5a,94a9e9a3), +S(9a39617a,27c2ff2d,9869acff,b22fad1e,a7d04271,be154547,43234f54,7f21924b,917bf9f3,fe0563a9,8daacf90,dfdcd8eb,e657f023,3fb15711,79bc5ce6,e6f5dd56), +S(41dcb02d,21137ea3,a179b469,199f9ed7,9b831923,68719a4e,5c727ce0,d42e95d,4669d53,82147266,8327cd6b,31c21b80,d3394bf7,fa29a43c,2ed7441,d866f5e1), +S(d4e3e3cc,387e0364,6688a62d,9390d585,a69ff43e,1060811,431dea8,d868355e,3309af2c,b3d7ca6,55334f2e,c53de6aa,debf5d57,1618ecc2,9dc9830f,ec46144a)}, +{S(90edfd0,61871350,b7f1f029,c4114190,b050065b,2030a400,9a8a7a6f,4b92aae8,872d4f07,5f60ae2d,dcec2f12,98a22da2,53d54de4,fde85560,690dde89,1628db56), +S(27e3ce53,b4258f97,a499f408,ecab24f0,60aabae1,dafe992e,5a34952d,5e6e486,d393fad2,9be684f4,7ecec306,332ad969,75b79d29,b5863d98,5f959c4c,b8ffb442), +S(420f1078,27c75c95,d5bc657b,a46cbe2b,415a7d42,ad62cdf1,6c84ee89,22215379,8b257a28,e0b15fcc,ae0b555a,cdadf4a,be93bbb3,a208ee45,77710a9e,d58da7fa), +S(28859abc,b60a95e6,b26c0996,566bf798,60c1a194,2d3342f7,9655f286,32f9d5df,2a770426,5eeca5d8,87840cab,3923d868,aa7b7b18,f9d19941,738ca006,54ccba6b), +S(c33c317b,490e2266,2649a021,e87f6596,3897633c,90be208a,193f1d52,28614059,af850be0,d18708bf,d0e1f523,c1a4fda8,9a6c156a,55f82518,2bd99bb9,b999a358), +S(2333793d,b961d3d6,740fc725,6cf9d833,81b5dc92,85b6d83c,5c343aa8,5baea83b,accc199a,ced3012f,b6db99c4,7a36c30a,f88e7eee,b62c2ed4,1352b488,ba0167bd), +S(4834aa89,caa9c25,a99ee4da,e4a64c15,25a5d74f,9ce573ab,ff44b63f,c3a578aa,fb189539,448a265b,eb87a268,b71a18db,f12fe8ac,e502720,c83ca156,c1cc7a39), +S(432cc05f,c78b0d56,e605391f,e4708bda,a1ff3edc,96a729ca,aad3cb0,300c4d4d,6675d8ee,ece8c078,e1bad373,247ce383,d4c65519,4a6aed20,a7ca5eca,34a89c30), +S(874fda6c,b284ca2d,a216bbda,28249388,88da3968,7f615ab,52c8e61f,b72a1fd,2d7199e2,b0b88f45,18e6eeb1,240b2ffd,a9bfcee4,6f754a4a,3db7959,dfe857e6), +S(7fe21a0f,3ef67d60,1de05f67,2b163285,a5577948,ee78274b,19fc35cf,2d2f6801,62fb2ade,5e2fffe1,28542038,91a6ea73,aabfa35b,1f7fb000,95190adc,de6663f6), +S(cd0540e9,efe497b6,2beb2227,a2da819,a1ac3bed,8eae24c2,6e2991c0,a707dd69,446c3218,7d0c9229,d65dad2,1392e4a1,66445386,4a5c1620,bf768fad,20a45c06), +S(a533c295,74e78024,52218573,66c30001,6159d772,f5bedcff,28d7f7cc,3051457,b61a106e,e0166d54,5e1b945a,f3e4e285,31a34cb8,56a34dd0,cd21184a,9555eeee), +S(5e144f44,ed88845a,c089331c,eb58811e,4c164e02,5d1758ee,51a7a522,c66deb30,ff95cab7,597cf62f,e1aa8df8,a2cd3844,d71ab4dd,4eb02a9e,6175077d,261e2540), +S(97487a40,9562ee2,7620fc2b,c5bd55ac,6509d487,8ab41257,53884b97,7c5a84be,e52a282,1430c540,5f1143d0,62b69faa,16592f02,cb9b8602,d52c9fc3,70769091), +S(906f9ac1,d3db4690,d74771b7,f1940679,b0de7731,a68d7d35,89caae34,c3760eea,6f2be7,2275dd5,1e77a066,b8d3c303,f565cb97,b8fb0dd3,14445d18,876665a6), +S(4c355a31,d17617f3,5d4066c7,a125b2bf,1d6f77e6,27b585ba,2d271a29,a88c81b1,6a686e69,237b75a1,a1ecb86f,b715e858,35aa0686,e2ef10bb,38b762ca,5646e9db), +S(15aac1a8,9b6b7629,57375d4e,aad87c9d,e1fc2617,89e57d29,731fe96c,1380140c,2968c0b2,2c3dd83f,3286d37a,639bcc14,3d89e75f,cac1da56,7e07799a,62af1008), +S(4642f29b,37b87118,65767998,d00b41b9,fca6718d,bfc55785,1c459efc,2ea15037,a1ded31c,be33cc1,425df851,998ddd11,1518ed13,f84756c1,c7cc46cf,3f5e9a72), +S(9554abe,9e092bd2,c4ff46a0,abd0b7c7,fb73d85f,1c01fd96,83146559,306ea727,89e2c07d,db1fe6b0,9872ce91,66ce9ca8,1124986c,c7e48e09,f80aa3cd,70987711), +S(1c0977a,a773c56,2e36dd15,58b95fff,d35b4dea,ac464011,ad7b79cd,26227238,e04ce4c5,b0b165e9,87dfef97,d32094ea,3e86e6dc,33a4c96f,c9470336,34b0db68), +S(71d44171,60361c39,6295e5cf,b1540ef2,1ca046b5,98645a23,e8c9772,ac21be4f,7122d5b,32a654a0,1476a47f,d3317a25,ed51536,4a21253,f4068dc8,14660c55), +S(d906f59b,4d56bc12,f26d60e6,6fc31733,e5450707,89025ea3,8a6193c8,520ddbc7,cd7f414b,c6cc79aa,4c65b943,ff914234,a9d85cf1,9853be59,2a71fe1d,dbb20163), +S(11b7dfb3,17dd5c23,6b8084d4,f3cc157f,c25c0e70,8248b472,240963dd,9a3fbca7,dd2c8caa,2a2d14d7,fbec267c,9fe87ab2,8b1ddd92,dd100449,f75ef1da,97d4e5e), +S(3ef8274a,fca8fbb3,1894d7a2,d1ad59a9,4951b21,328b1e84,ecaa6df9,cc1ef473,2e4f0c04,f5da671d,4a2b641,46ae749,27bc35b5,98a54190,3883469b,3e7874de), +S(a861fc27,f5e6300d,ec0fbf6c,3315d053,98f90b84,2422992,bdfba11b,1c1c7e34,75a7458,5d98bca4,e3517897,afef848,8e524168,a586d8da,18834171,4b51846b), +S(9537019f,57d7869,2a358758,47e885bd,1594a426,4412c595,62eea9ba,4ab34de8,21bfd84e,a66650dd,79cc8c13,7217a351,57b9c046,938f20b7,246362c8,6637d5f4), +S(71c80c38,b1889d4f,507132a1,87af0c91,79994b84,1b816c8a,6d130a,df1b500f,8de1f76c,100e75b5,1572da6,d08c76b2,10cdc447,cf903e0e,2b00e002,5dee0ce2), +S(2fa9ce2f,59865d10,17880d74,d31cd446,5c28ff56,50f29e6b,d74a810,977ef9ec,6c5a2073,55c0dd3a,b994778a,6bd02b87,80ba8e1a,899330ee,cd8781b7,6e15cddc), +S(96ca6bb4,bf74c748,75703386,ae02dc29,13329d9e,a5395892,df1c6f57,4a84fa4a,fcb510b6,dcfe8da5,690f8fc9,4dea8ac0,e42af209,35c33347,b088cc79,52e98b1d), +S(36a066ae,694f2645,25cba884,956ebd46,ae568acf,11664965,63cee00d,a32f2199,5d1e975a,856ebd1a,cb1fe254,101e89ab,ea089e8a,b38bbd0f,1100e914,709fd965), +S(4922879f,800234c9,63f4b572,d236843,4c4da5c8,ff741982,c3d1e341,841d1309,9b259470,24b5f4cb,97c68d18,f7f8dfca,1e57f7de,63208765,2ce15770,98f35494), +S(ee27e2b,acf95f6d,dbb5ebae,bbf181bb,43322a3d,6db87e78,14e57a3d,41b581e0,3d6a18a,daf69ae4,88ecc9d8,7d6b1bf2,c8d65544,3f4b45b4,c5a0ac51,7b1dc3ca)} +#elif (COMB_BLOCKS == 43) && (COMB_TEETH == 6) && (COMB_SPACING == 1) +{S(e3adcb1a,fe947e6e,7cc4f5a2,df78310a,b235e2c3,bcd75eba,1904de80,c8814c50,e0b27ead,c4bbb9d2,37dad580,6e366674,4a9f9c3d,e024f2bd,1edb11d2,fafc0a22), +S(612c2ec6,f0e9c4ec,c2200d23,ddca77eb,d003be35,61e52b1,890bf846,3bb53ea5,9e944d7b,dfc7a952,c1c5ee15,485d7199,dda19551,2d729628,c215a9e0,285f656a), +S(42053dc0,9f90a7f7,86feca60,d68a5c3c,789e44d2,3479aa13,2d1a427c,621373a3,b338f891,f3930ec7,738669bb,3a29ae2d,637be08a,954f2a8c,acb661af,a660bd22), +S(4d227ea1,5194ed57,10f8ea4d,a639be04,fa68ecb4,f3d2d9c9,43ec32f2,80f74051,28a94075,bda4c195,40c20493,b5391df7,166b1264,b957fef9,683cfbec,4c6e6875), +S(8ec4abf4,d4db3b0,2b0712dc,ef54a405,54b6cac9,3f88fa9d,d8cad4c0,9b94eb1e,4e37e159,517346ee,17e948c4,a17912b0,b29c303e,497cfb38,16796752,99aaf9e8), +S(ab186398,117fb83d,db8b9392,cc888fe2,50d2f604,5a0c3f89,92d8a82c,382175c0,79437224,b3b1604c,fae64902,e3030448,51ef17b8,9af02d7c,54a92c34,7fa2abda), +S(2bd09ae7,1e8d85a2,ba550bf2,9c1787a2,3d2c8985,e2ed07bd,1d39e7b9,8ef8135,ddaebb19,195bfd6c,a44ce82f,b7f3c65a,8af935ae,52e2d2fb,33cc231d,c4b16082), +S(e6da6560,c8265e7c,8f62edca,78dc739b,74bd6543,44a939cd,bac0f489,12b920af,147f5ce4,a98377cb,981dfaf0,1a1e4740,238f1c5d,ee69cfff,a54f3aeb,e53980eb), +S(7df5abfa,d6b46a37,30bd5892,69edb6fa,b70a0d31,936c0787,407d5d6,96506263,bc5cbafd,1f5fee67,1aa449ff,bacefc67,cf7c529f,86100d7c,a8160e4c,376c76d4), +S(ad672823,cfe3ac01,50038d30,81a1a109,d8629b4a,a4e26779,373ee0db,44a466d9,c288397c,f91157e6,770c401e,dc84b328,87b22534,d11e11c,c8415a4b,743fef9b), +S(72032cac,3177c280,ceb3076d,7f510405,2413706c,956ecf38,acf410ad,a12473a6,8bbaf50b,95797824,2994e6d0,a4bf6d07,149792bf,f2a74847,1095f845,bb332036), +S(36a1f78c,3bebf8c7,1fae5e29,cf08485d,d9debdae,348a20,ad84ba5d,4308fec9,842f57e2,e900d07b,eefda7e5,9dc40139,c5deefcf,11c07c42,4629c59d,593e01af), +S(5f418454,72e80d51,1c1b8bc2,b6b89224,9119ed43,5b915809,f7b26d01,8427f579,dfc29fdc,f3c65221,a6615262,cebd9a14,acba91ba,cca22ec5,d84303cc,1fe0085e), +S(5577ced2,f6bf41f9,503aa4a7,c0060fae,6d33cda6,e3c8ec55,1eaec315,bb91fedb,858ded64,6c3d6231,87c0967a,84ee5253,2b21c4e5,b329bdbb,76f6a6d4,93cdcb4b), +S(bc74b56a,c94ef36f,2b356bc5,dfd11d2e,7a371087,653ad607,dbfcfeb8,27abc502,d57d74e7,39e758ee,96a422e2,f1fa61f7,4f6308f5,71e6dca6,3b0b0103,e83cf1f3), +S(727ed91f,be4c5086,50a0d365,b28ae4aa,c9434c0,735fce3c,7b3ebb42,f4be911a,8c595547,5e627c22,6bfa855a,22ebbc56,d3d0b331,9120d8e9,13bed868,7d3bf331), +S(6286bb90,71f8887b,c4fbb3f0,a9ecb19e,fcdd2cf1,5e286da7,1bb60c9b,5ff5e644,73731ec5,ea3e537c,c6060ac5,dde716b7,2aef4117,ba747b12,1c26fc9,eddbda74), +S(3905682b,72282a78,2b8d8dba,72cf147a,de0025dc,a21521e1,ea989040,c248852b,5da3bf52,dceaa14a,a3534068,c05bb015,2cf9c722,cc80c56,cf828ace,d96fc390), +S(561a2ccd,ca12b67f,dad28ee2,c3cee78a,cf811766,9e4a2543,c81b1ca6,eb4bd16e,3b386a9d,553c2746,893477f5,17a05e99,bbc8ddf0,896249e3,85e406d6,a57b9ed9), +S(75bdfa06,6a1a42a7,50f283e8,3ec91cc0,a5b68829,6e6aa24a,28a61e33,65f378e5,c73224ec,797d6736,c1a541ab,34523d91,e1ec3754,fe7fed44,474f9cba,29f305e5), +S(e881a840,847aa2e2,2417cd3d,3e798c56,1e630290,5dff6bf7,754d9419,98d401e3,8816d775,f1555452,f624e45,710a240e,90fc5e23,7536d217,cf555349,b5e31bac), +S(1fb527e9,4e9c70e8,657de745,8b81ef9e,e3c2b4e0,128a675b,f7e28980,e18b201e,bab00a09,1145407e,693d5353,7818bd30,49e1f364,757d228,58b8aac5,416e3e78), +S(1c2bd878,b94169da,722a9de0,c4e317ce,a8802aa9,60458301,11a89d1d,9de4270c,95b7d99,bc3df31e,f0dbf17a,a09ef148,71ae6c5d,870ebe75,1f52aaad,a48dfcc5), +S(41f7fa0a,9a59513a,e221e3b8,4b91995f,c9d40eb5,d120a6d8,e663452a,d92099c8,813dbbe,92ec4b62,25d1cc5e,5820ebb7,dbdc2964,d5dd1ab3,deabceb9,5e793d32), +S(e5cbd627,89c6a843,25a24407,89b88dbb,1dc55afb,9e8296e6,bb8af7de,57a50e60,2cf01cea,ae4f4fed,46c4efd7,86ca5e4d,ef5af524,e9393d74,e9dd224c,604b9408), +S(eb3bc68c,623b1f46,ab905412,c7f2d588,fa25abb7,7a7bd782,ba9bb3aa,c05a70ae,df9f46e0,5dc1d126,2f72ef3e,8db01fbc,11915af6,4aee0c51,da1cfa,b4d15ef0), +S(5702fb8a,2602f41f,52699f68,8d4b005a,128762e1,1dfd13fd,22ea751c,cbedb2ef,a77105b3,7af534e6,46f58c3,b02543fd,9e0666c1,58051952,a61f8389,73f5847), +S(66954eca,5434263,4036fc7,fc0fe33,81f5195e,88433bc3,2c5a8a60,341e2859,d8b1b14,40e9f123,f39c8658,f9d64e7d,fe4071f0,ada879ea,42eebad6,4d37f4fc), +S(592152c3,98d6c719,636a03a6,dad64246,a5a6814a,a62c156b,ce5332f,6759b031,8d22d1e2,d93dcccc,889f3b6e,dd5e2098,2f5586d4,bac06842,d689a37b,4b845c12), +S(5699b93f,c6e1bd29,e09a328d,657a607b,4155b61a,6b5fcbed,d7c12df7,c67df8f5,c147ee87,14325497,6b2e534c,e6902748,2a5c33dc,867732a5,8338f05,73368388), +S(c62c910e,502cb615,a27c5851,2b6cc2c9,4f5742f7,6cb3d12e,c993400a,3695d413,e80c2522,898d8a22,2c4dc0b9,8dc9ce88,740fe252,5144656a,c30f978d,dba83c1f), +S(0,0,3b,78ce563f,89a0ed94,14f5aa28,ad0d96d6,795f9c63,3f3979bf,72ae8202,983dc989,aec7f2ff,2ed91bdd,69ce02fc,700ca10,e59ddf3)}, +{S(efbbec14,ff6d7e18,a8015d68,ba3ceb19,d4cbfbb8,a1bbc09c,ce755a23,e9d4b3f4,a76faa08,2b02b8a4,405573c9,5ac067f3,ab936127,24bfc14e,a27f923d,3adf0133), +S(f02f6744,a0ee7b0c,7bf0abb3,c7ec0a5a,3275d109,92be2893,7e9ef649,23fa932d,955f3630,c5621787,13e6d8f,39efee26,d91a0947,8da36db9,4ab4a89f,aaf9019a), +S(1c6f9f0f,d6ecbca1,fbcfbe9d,1f3d2476,dbd3b6ca,ac8e18a5,949b993d,8c0063e5,e3e3770e,33081dc9,5125d69d,c631450e,5494d21b,2ddf48f1,fbc3169f,3cc1eb91), +S(2062725b,739b793d,c9798397,dfc7b1a7,24ebe8f7,5e5654df,536adff1,25970841,22f3e3e5,c0201265,5e6d8e58,b8ba633d,9a9216b5,445a7f78,a2605688,4a5b6092), +S(57ffda66,e0c29448,7a1570f7,e2f5dc58,ecf9b906,5f374046,5bd1734,841785df,22ae8728,a8800436,1264c380,3beddb65,a9dee575,6f0cfa97,c01dc047,3c806def), +S(4b49fa7d,463cbb43,b14928c6,7b3a85a6,8132ad9c,427d3cc3,bba76d1a,7c9a69dc,7e7e3133,3782b30,5c7c3bd6,94e3c306,b3f9829f,86f76f08,d44b1a76,a207f2c5), +S(411a3b18,c9b638fa,38a0e811,ee370f34,5c9476db,61df1843,863d6d7f,4e803ccf,bb306f97,e97e492d,e74afcd0,a771570a,8210b51,9e61df78,4e6e97e0,ac23e109), +S(c8227510,49de1572,37afdf55,d175196d,5d315001,3670b478,a0255a4c,ebe95075,16be5950,a3f12be9,5905fb52,8d5bd93,23eb5908,211d2e8c,26204b32,556c5c45), +S(e46bdb74,8692d0fa,e6fc9f50,6685487,31d61f8a,5717fb88,4e1f7a41,70e4997e,35398e06,48bea42,cc48fa4f,2805efbe,6bead663,c054eb08,2c15ad46,c0611052), +S(d18293cb,d0902dab,e4c014e1,22969601,84aedbbf,a01526a8,6978e144,88ca794f,3a5b423e,32c1d2f4,bf754f42,9da3c9b6,84bb798c,ea73f637,1777ba77,1aae6086), +S(7b9cbbfa,a53923fd,e9f50845,3130101,3b17548a,8097433,79d3a526,d1c90c31,3fd7b71,5b6801cf,30fe22a9,8b7895d8,1b483f6e,9fdefe7e,6c59fec8,fb9786b4), +S(ab6e185c,be9ee393,5ad6278c,167396fa,aa4d936,80524d16,27ca8e93,48fce67c,7154007d,3f96ce60,d09499a5,1262c7bc,3ab5e9aa,929e0594,994a9671,8f912987), +S(56ffb418,8b9c9c13,4a110c03,8df8636a,71141ff9,8448cb79,eb6dece8,a28b65b4,1d728ed5,23ab821,ac0c40e2,b9348e27,191536c6,79a73835,8bd9b3c,b43dcafe), +S(bdba1eff,bf6af786,dca1da26,cc226102,1f95d56f,245298c0,b87a40e1,fa9a0cbc,fa18673b,41f765b8,25d13f2d,7963f1c6,b3308a14,b033fecd,e1d0d597,583440b2), +S(d9a4a7f5,5b3af93b,1c49ffa7,4f8154e8,23aa1477,16b16441,39fbc86b,2d9346ef,19ca90e7,538ac3d8,a28e1aad,5d8b1dcc,756f8a84,240e5769,a0f561d,f53289b), +S(ee5c17b2,74c78b87,9eda9341,256b1506,25582835,60a0bdcc,c8eba320,32d58638,d7d02f4a,b81215b1,7843e3c6,abb63755,c7e05d20,6c61a4f6,bb08d1b0,256409ee), +S(6953ae81,7ec599fa,5f739bef,dc4cd8b,4670eac6,912bd03a,a3fbe91a,5122ba0b,61bca3fe,36245ced,31cae918,fab6d463,50856947,f64a3be,d0eb62d6,f9f16059), +S(3bd721f7,59f7c3a9,93474472,4ffd3e34,503cbe45,fa7fa5ef,40a5a173,b8bebcea,bd7cbfbb,797034c2,d293aa64,1bf175dc,74a44dba,84b8d99b,8182d2be,6512ef2), +S(ab6e36ae,f5b7ff2f,fd2f42f5,8c408b7f,3ac84253,e1d8a43a,55cac222,678dd38e,ff0dc59e,51e504b2,9a0ba824,3ef26eb1,2446f628,78293da2,d924028c,21f57342), +S(bf1a1f6d,7f73b09d,3efbd73,eb9ea2c6,23e17911,9063489b,42fb1303,7b53fce4,236566ae,5371fc97,b5449b9c,2db32175,90e02412,b44539d3,bda7a814,3cd4a634), +S(fa0c6aa3,4c4825de,304cfece,37a20bbb,f72044e3,94cad202,c9e1edc3,b288ed57,df8e64ba,5f5e8381,4b6891b6,14dd4753,fed5f566,956a6dd,95540bdd,25c73995), +S(d2ea634d,ab56961f,52e39ba8,ebc5c150,ba9eeb1c,6178aef9,64fa97d5,e80581c6,2928f71e,a09a35b9,6fc1976c,f6cd3c1c,7d1fcea0,2142eb80,9666917d,c9a0621b), +S(827d6a36,697cb2f1,cf19e27a,ac30c06d,20d818c9,fe869309,6435f1f2,171c9b75,53237d41,3781a1df,d0d977c2,9690d488,b051dc2a,841ba226,c552cc28,12ae7caf), +S(59dafec5,4df05695,e123004d,38d9aa12,6a06c399,e5215245,5392e5e3,f1a47dd6,ff7d173d,ceda39ec,ca8d2c95,ab1658a8,6ad99618,e3fdb7cb,b07b03c5,2f96a86b), +S(5c4f5b9,2acb30ee,8c7ec4b0,ec577f41,a9502af9,a5a384dd,3386f230,3e62a830,8aea5f7,145de3a3,679c86ce,72e8b36,f3d6ac81,bb1d2043,9d719c32,ca2f8b30), +S(38add3d6,209080c8,efb65551,3d9420aa,457f06ac,d3ec84e8,db84e208,a0664ba9,ad95a891,c60f01a1,5fcddf2c,923790e2,d5596334,4d83a21c,dfe5f6bc,4c2b32b3), +S(9038876f,21c3bc14,111d5f6a,4749d07,34e40a53,7d398c68,809355f,764cf1ba,da030216,5e661aff,53367578,4a4d3447,707f14af,cf0d771a,53e8e687,b9dc29e5), +S(b07d3e8,dbbe686e,5e163725,8402cac3,e1e4f29,fdf154f7,bf008c5f,9969da10,c8b668e0,56bf8173,2d9778e2,eaa069d0,cdfbf826,47f615c3,6d0b311a,b2e14922), +S(8bc89c2,f919ed15,8885c356,844d49,890905c7,9b357322,609c4570,6ce6b514,2cec0c32,283233e9,21889013,c4a76d3e,e8d2cfa9,eed8890f,909c0b30,5736aad8), +S(308913a2,7a52d922,2bc77683,8f73f576,a4d04712,2a9b184b,5ec32ad,51b03f6c,b5a4f6a,bc0141a0,6e1cace0,993fc8a2,57ccc015,7d42e0ed,9f54a102,1701afc8), +S(3f0e80e5,74456d8f,8fa64e04,4b2eb72e,a22eb53f,e1efe3a4,43933aca,7f8cb0e3,34992828,d693436e,16f463f7,b7a2fe4c,6afedac5,59a4ac5b,34fd761c,15a0bbe0), +S(d30199d7,4fb5a22d,47b6e054,e2f378ce,dacffcb8,9904a61d,75d0dbd4,7143e65,6afc7262,f51c2a3c,4c292136,167c7f9a,e089f33c,9b127e69,fa4c00df,dbef9176)}, +{S(983e1ca0,5dd64afe,8d39e15e,43c1cf9f,6badf550,12cdea89,5fd85021,b49f173b,18200e81,d75a745,c1ecfe5a,3ead988e,4327693b,7e3c0e04,329b0c80,3d9934ba), +S(4e1200fe,d3e5048f,f6c9fe53,cdff8ef7,5d78e601,4df471fe,369f3d1e,80e46674,a62aca58,4ecf32bd,cc297b38,c1951c71,a66966f,b9ceb2ad,de411da7,d175df94), +S(82f5f27b,83d49042,63e69f48,b676c9a9,2446955,cbc18ec7,fd4346fe,37e0b0a1,e523d039,d0b8ccae,737bfc11,9b83dfd3,d6878403,862618bd,40ddfc89,9a688557), +S(a8c0fd4e,ab1f0e3a,cab37da6,58fbab3d,949ad9a4,31d6461,b2648308,35762d19,950200a9,63c3dc2e,6d2771e2,eff401d1,f9ce037e,75782943,3fd3c560,a169713a), +S(25c1b464,33068900,bff89a4,ee973937,b03c11a,5b33d16c,4f672fd4,bfaa11f9,471f1f8c,df18e73a,e12cae35,43506cf2,c57894a8,f633ad4c,e1c5330f,eae42b43), +S(497e56ce,8793bfec,4dc6f972,dbaf4a72,aa5d8412,3bcac5d4,2aa9baf8,ccfd6723,1d3d028e,b70105b6,eae66785,5dfe7e0b,7c0a6b3a,b069a475,bd913aa9,c29cf426), +S(68a285b0,d30c2dbb,b543e480,f66824b1,69aa339f,7e2282c1,5dc60f50,8e3f2fa6,87529a0e,1d53588d,21064447,99a8fee8,ffc791a7,cacc9e26,f7a7d94b,25e74cdf), +S(721c92ae,931712f6,15f4d7c,498dda23,e1029dbc,944cea16,9442b22e,d755a100,7ef052e6,a0d2646c,a5dff39f,3b2a1019,de43e3b2,5e51913f,d636281d,cee74a85), +S(aae8418f,1b124d79,ad15f773,1bdcea1b,453493ad,4cb0cd6b,ee5c9a8e,34335ba3,c2558bb1,4a7addab,62d1f308,1a9e6fd5,92a06976,3be877d2,af9ae1e8,b510d98c), +S(b6a06052,b492d74,c68640de,8bd3251d,fbaaeb0,ce1eb997,f2127ead,4bd0b81,7bb4269c,4a9ece8b,e8ea2f0f,d663a193,2a571249,2814eb73,4ae1493a,6a97b39a), +S(42fbe048,38761203,11e43178,6af555ed,d7bea551,d4d5aa18,afaa4c05,2c6d0c19,9ba562c0,a4cdc664,87caf55c,291d8246,65c29f32,2a56360e,90138b06,f109d83b), +S(9d6dcb88,b378e7bd,233464e0,25e97bf9,97768e29,6e4aac31,301fa1c8,bfbcc27b,f434ea54,3f7269cb,1ae1279d,4178dd25,bbc337ad,2f0d5141,610dc061,80daa8c0), +S(fa6fa5c8,1e6713d8,90cd6f29,cc8b7d03,c5f8f2d5,88963652,7c199f6e,8f98e060,726194a,2a5da1b5,85eba1a5,5e06ce36,5aebb89d,ba5f7971,db3c1571,c848c5f9), +S(809167d6,85e432c7,372dc111,8573e620,d9ce7e9b,c3ebc15b,ea7e866a,3a8addf4,bf0cb694,f00fd1b4,b62119b3,9dd6c88a,22ef1fed,a94ac0a0,9cf33225,9298b968), +S(99d28ee0,962c1bd2,fa63109d,f5485653,964059df,bd514206,24117eb4,e582ad46,8cbdbb66,4ee209b3,419c0b80,36affa24,85cdfbc6,e6644429,33908490,f6f6353e), +S(559d0617,e0860cd1,87f1c68,e9a9951b,fef7dba,3a67594a,eade6e25,e2df593f,194595af,721e3b26,786fc25a,cf5b2d77,1fe00649,b0cc4938,7168a9ea,1fd2947e), +S(ab9a7228,f0d533a3,4a95af3a,51021b55,bb324229,8d101a66,eb362c97,eac48b02,80a6d111,e451eb09,cbebdd5,a3ce4fdb,42b3665,f8974df8,912221b0,fc7db6af), +S(42c6680d,18b0f528,274c2eb5,422e4731,560ea862,adcc4419,68bb5f3a,5bbfcf16,c8961934,e5bd6e7d,d64d4b1d,f7867c7b,978d182e,48315ae4,3fe2e082,a9455792), +S(e8bc0f9a,c3687bb,69627de1,df71fb34,21e0252a,e33d15da,3039a200,43ec3374,15de9e9e,2ac74839,5116ef76,1267300d,78c2e583,9286e6b6,366c8a6a,540036cf), +S(604ee928,4ea1c8a9,a0a75bf7,be3a5c02,8f52d71,b5fb6340,53401e8d,8f5d3d6,43bc16af,5875b25d,8e2427b3,3913f6e0,bda886a7,52a3b812,f8f191cf,f7bee54b), +S(7f589067,5b771ce,ac754412,a9984352,4f2a4a6b,a5cecae8,5106bb81,f7e4d9dd,a74f2eee,584696c6,88157a3f,fc27085c,6445c7eb,e363c6ed,7a1f5902,63de2024), +S(80aa63b3,1fdd0d2d,ef602bab,dd88a15,71abd052,270988a4,63abe269,fc489fcb,9a145d0f,6dcf0edb,a4873287,a2f221dc,4be613df,f70f7755,f28879a,6e7d9978), +S(ca9793bd,796ae0c1,d778f3,6445bb8b,aa50d859,4be28fe0,ea1e2d16,30972503,7304af4,4c56106e,f0064436,c09b411b,926c4c56,cd82577f,f8c01ab9,9f7c4c6), +S(4cca305c,baf6615e,8cdc8a58,f3a9e52e,97ee20f3,ef080793,ce105a03,a1f1d3d2,637ea84c,9578321b,b5dcc239,7f6206bd,abdfff2a,128d3645,47d474f4,8a8ae493), +S(cb7813b1,a7227a24,cc53b458,1985592a,a9077113,28fb2a05,1d4972a2,3127a913,208b7263,f8f8193b,76dbfb1a,6c4f9264,dd12f63f,e852aa8f,8375fd00,eef83482), +S(d61676be,a11dd1a5,79164cfb,b2488e54,555d7d55,23ddc8a5,454c49e,4a86d8ea,1875b5d5,6db950bc,60b1eeb8,17a94af6,5a19f690,d48aacb0,e483ad52,61995cd9), +S(7142872,6f59c2c8,b398b22f,2ab5c3ca,e803a34c,ab580947,9b7b4d83,1f8e8c0d,3702510e,324c0911,b3154c61,e064ba23,68eff5fe,6f05353a,34980ec1,87ab9ad), +S(72a73d15,9cf7f79b,950971b7,1c66f362,54d13783,c5ef67b8,4da61dcd,4cf432aa,77d711e5,c1793c36,eabf9b86,bf3a692d,234f02db,e4d5854f,5deef926,b9818d2f), +S(ab3b2de,c0a8f23a,a7d3b9d2,88870969,2e45ef47,37a792a5,d65af92b,e58f6347,ac4e4ac9,1bbb57cc,1437e612,e4d4ce37,3d4f0286,5905b621,56826d80,895cb48f), +S(fe5efdb4,32715fed,f9bbb16f,d65ddf6,4ce9bb13,14a491c3,3bfedeba,cb4704ef,e5dc36f5,5fac6974,eaf9d8e4,232a22c3,8aacc6b9,1225a97c,2e695940,ec795c21), +S(5f94851c,a4149e75,e44a0d8,17e81c75,132eb242,c96ae41f,53f30ab9,c8c828a,d9473c47,505e0117,1a0f8682,777d0ca1,7399208a,b03974fb,4014f5bf,c8cbaeaf), +S(5d1bdb4e,a172fa79,fce4cc29,83d8f8d9,fc318b85,f423de0d,edcb6306,9b920471,d7bc7d98,86c861d1,86b4466b,c75dd9a9,8614e166,693a9184,8fccf998,847cb2c)}, +{S(8cf1437b,d87e7faf,550fcbe8,81b0741c,ae0b48e6,e0b3c3d9,9b1b1924,2a925a26,17b40146,c313b1c5,3bdf52e0,efebda45,80d86783,910996fb,8b2d0acf,9bd253a8), +S(fedc65f0,d622743c,53fa6172,e68d983c,2c9b8fbc,58943f48,ad06a852,c98403e1,ca5dcf28,1a2f20d1,5fed06db,89dfd290,8c9d32a,cf40fe6,817e861f,7f168ea9), +S(846c6a48,e771b90,4ae1e8d9,d3daf1ff,d1cb4c88,bbd1de98,454bc817,954654f0,5a4947a5,8a0ab994,3cd0a90,6c1d1f0c,3fb73d2a,49b9c0d1,a9bd35b2,99475dd7), +S(4998795e,a7d80937,e4abee13,6c14585b,40b2dbbb,3fd3c80f,c8c61b45,cd1d59e8,8c817eab,e210398b,59b31660,267c099,baf29e4c,894e09d9,a50894b4,ebbe97f6), +S(76c29921,eb3f3d12,5c11b906,3d1ac276,a205804b,b3e7484b,72ae0483,e4b3c517,48d8a8a5,fe658e1a,4d736bd1,8f07b5ad,28cbb775,d9388e7c,4fecd837,c8eb964e), +S(78de8fb2,b15ff39a,487135a2,636bdcea,57bb3a14,efc329f5,a06bcefa,7ffeaf09,a55c9e98,5e1f529b,ba7ccb6d,3a5c00ce,28cb14f3,e9012d5f,9f66d8cd,5e45113d), +S(71fb3464,b0600c08,7fe70906,2792a676,27830e50,a0bfb473,ec909530,30799282,fe036726,cb928a8a,8affed30,38977377,2a016e7b,1dbde8f3,6db810d7,cd423f36), +S(f1f23de6,bf779cfc,d864dbc7,b46009cd,d2306b1d,cd0de2c3,65f3006e,565d9e21,84f5a011,74ff8e7c,c9a98f52,3f2980eb,4b013695,f6239016,9cc5a1d2,acd8193), +S(f18909a5,a5db0daa,ece22ac7,12ae04ee,53484793,6fd8355f,9ff5ffcc,ab6ca78d,6306f08d,13ce2b0c,b60b3b8a,b0bd5f46,b3ef2a83,7edce51f,2cb5ce41,79f46344), +S(7598d96b,189f476c,bcb1992d,9a38adcf,9d1b6ce9,6c87058e,24584514,a0df4770,7f288be1,b82da02c,a37f655b,d23643ba,bf3d5cff,3b6c2726,9ece7409,ed78bcd6), +S(1e44193e,8223b57d,8fc68641,924cded8,3a04d806,cf9dc18b,7af06010,4e6216eb,45ea3ada,fd726fbe,2b1d6fd1,858ccc2d,57b237bb,bc2965ca,ebcd1b63,53c2f2e1), +S(80954b78,4872286,8fe38891,2d76dfba,d676b4e7,7901e559,dd5983e4,e908f13b,6fe564cd,a0966639,e0237f29,46e92d29,4aee124f,cb33da53,974e8882,b0acf22f), +S(6dd8a9a9,ad7196c1,3c36464a,5cb9fb41,aad8b0cc,423b99fa,a281c5d5,a6ce6ead,79a51469,8767adcf,ed287aa4,914eedc5,8382af71,5485c2aa,c3a77c4,efe2aafe), +S(1895cc13,f99534a1,187a3d65,d1480669,f0d0c0bf,b42b2a9f,1a6392d8,7e1d2c6e,b7905afa,c0eb9b66,51de3583,2cfb9ac7,ae8d2355,1e334d59,32909de9,ed400a0c), +S(f1efcb8a,86f94997,65b38fa5,8edced68,7737b8e9,49dc05f2,190b359d,9ed2c0a9,79b2c874,22de216b,904572b7,a39f320d,f53e392,8dd8e533,a1a28d93,fdd4945e), +S(2944af80,c207d107,ce89fb90,ea6daa2a,c65c1360,503c36c5,ad798333,90432ce4,44b53d27,fd6730f2,33b8c29,f1256136,c637740,86e001a7,60bc1ff0,f8b6211a), +S(938a1dff,117540c8,f6ee7df6,2d3c2cf3,31b38593,131527c3,9804c6d9,874752fb,4683d049,f096bc21,2e0dc20,a8600b8a,a02133d5,d0ae8d6c,b26e4694,ed6f2aa9), +S(b1b3b2c9,54d1fb6e,98fcf939,efc18803,2f693989,81f19c32,f5e55b30,1f59eb16,423a6754,1a29bb01,95adfe15,c1df1c9d,81394e96,2bd1926c,cc789f5b,eef9ec29), +S(52e23f2b,19048d43,b1725695,e3bdfc7a,f4ebd2bf,594f013b,b80d6d0c,ec10632f,258a6236,67090b8a,73881e39,746906f8,eabb6683,4bc3473e,1c6fa8b6,54641cdc), +S(5799a463,cc817bfa,26bcc543,efe0e00b,ca9d2320,1989e854,620fc9b1,ffc14afe,645238d1,8c69338f,9c9395fa,5ef7c9b0,f62b7dc9,c4c6b9e,c545c850,95b6b7ad), +S(1c493b52,3f5a4467,6268220a,58246228,608a603d,f6edb1c9,1a90b060,70b16069,8d311a45,5af92640,e9fe08f0,2981db57,3b22bf4,8fd5e76f,31c175be,23e24fd4), +S(84f5a9c9,cda291c0,71aa9f8d,d7af5a8b,f2ee0dda,fb9139ed,fee08f0f,3f9cec2,df381327,16527be1,d86991a9,bc28966a,c3c6c081,4fc0def8,85e5d160,f59f4458), +S(712c18a0,ae87e7e,87856c8b,ff6e3f6d,996ae157,970e754f,bba80bee,421fcde7,b2788ba,e69d34ba,eb5dfd62,830396df,3b8934a9,551c6070,ae8203c,ccc50ac9), +S(a5104184,ee996a34,7122a460,cd2eba5a,11d04aaa,a47d2ede,25ea13fa,41ee01f4,f4b5f2b3,f7ec9061,7ab5f3cb,763233d0,afc8d4bf,fc535076,5dc5fd41,cc547ffc), +S(79383075,a46a8eb,559ac95e,7dbeb9ee,51b6e906,27e55b9b,922473fd,5f2eb63a,243f56e9,84fd2673,58754a67,2bac56a7,9ae71a5d,68150740,8eaf8c2d,b55ef1a0), +S(2b22635f,b83ab0d4,9b82edfa,a54d6234,8d3bee6f,edbe3315,9470b18a,96f97821,41d9f3a9,52f17182,ccf02725,b58ebd7a,1f37235,1fbb8f2c,15403890,e8b25b82), +S(272fdefe,148ef7e6,957fb8a1,4a07f0ad,b17c27ea,49532547,5114c1f4,76170a0,789b8eb,5846e50b,d489bf66,cebd873f,7cf05619,3674e7d7,147ea691,6a9b8451), +S(2c2da4c0,8a6e73c0,2efd6e7d,13006135,f09990a1,4c0a0eac,1f286108,f4a2a0e0,8011a521,d7fa0ab2,75765bcf,50dba163,9e89c9,300e8a25,31942cc3,fdade63d), +S(19a9e5f,1c4cae30,797a98db,a24051a4,38ea755c,7b062094,a34ed6e8,8a8ff2cf,e199e398,157a50a1,56f9d6d,afed48cf,f3181411,77b792ca,c5881898,24f1b8dd), +S(f7a4be3d,fc6579fb,43c5a960,890893a,f4026165,ed9e3ab2,e6929378,b63968b6,29221093,17dc39ea,de2d6fcf,c735ad2d,668fd047,2eefefa1,b6b225cc,2f3cb3ad), +S(e5380fe8,575f26ad,b7924ae0,d58138d2,68112776,b11bd34b,3eb5e196,33f0e9aa,4680278c,6f784be2,a496ec9c,6db371fe,9046b1a2,b97ce71,3b45bec8,bf7d8a20), +S(4c1b9866,ed9a7e9b,553973c6,c93b02bf,b62fb01,2edfb59d,d2712a5c,af92c541,3e086d2c,df4175f0,804348ac,31a91963,39ad1528,1bc14e52,8d3b0c01,39701c0f)}, +{S(5a13b9b2,5aa6944,1b0b5fb7,f7665dda,95aff48,e3250b4e,34cf8e28,87406c1c,245f250d,78fd66ef,24745e09,f067f16d,d400c387,66d2a1a9,af51e84f,733d0ba2), +S(617b41c6,8534072f,2302290a,4956171e,902634bb,4356bd27,ab83a377,13d8ef6,c867779b,97383817,dfd0971f,64c09c71,7c468a5d,e1bb8ed0,feb98f5a,305d8e6a), +S(ac118ae,ed46b08b,488202f6,96d9469a,e9af3cc7,ddc8eb71,44903a3c,ee43c654,f992fcea,8268ca6b,79f5ce69,c87dcfa8,42ea0345,d7c85a5e,a1b89f1c,9d0217aa), +S(741dc47d,2e0d1424,3f2bd96d,9033d8c2,9008c1e3,66bfb5a1,1434f1cb,3d85310f,c3135d44,e86f574c,266f97d0,f0279dc7,52aee0ab,8e3ed78b,ee0fc646,c133000e), +S(2e973138,f6cea9c0,5adfbb5f,49a7b928,5ae0c15d,120a8b1f,2d0c76ea,1fdcc7e,a05bc93e,68bc82da,7a7c7e38,95a647d8,7f724f20,c5b312b,738c6dee,90de771a), +S(9d938d6a,cf56104b,5522351a,3c424e01,e4d21c33,771ca94c,f55357fc,fe51f91e,881d05fd,4658b08b,edf87396,be3fbb95,ec9f371d,79ff4586,6ddc803b,65ae763f), +S(37a8ed2b,4085961b,84645ad9,8f2c901d,fe9a9a8b,4de8fc89,2cfbca5,c8909835,b1bdacde,94fdc3a8,78cd0eac,f8865d64,77e2cff5,efef834,97b93835,5b7b401a), +S(da1ba954,899cb05,dae6fea2,dc8ddd7c,5ef9e91c,3455838c,a49d2858,ec217d66,14051c3a,12332d70,f8ad8ffa,567765fb,def69640,4291b81e,d3978bf4,51f788a0), +S(92d2ef44,5a10dbc6,73f8c1e6,af093596,13bd1e3,c1b24705,bad2b3de,e8f11b81,adfed916,800d3e94,91a42c59,dd72e3ea,57d47081,b9afe668,f853cec2,c72cbab7), +S(e62208bd,52620df8,91b3ddbf,e6cf0641,6059ce50,be3b00ce,14e7a53,6d1acb07,1fb71455,53b2f4c,431fd86f,c72d51af,5e2edb41,dd3f69a1,9a971371,d9679dc5), +S(191fec47,a48ee268,35ed37ff,6758a80a,532f7011,ab099048,b024efbf,cde1d0ab,47b6389,b3f5534d,a632924d,5b65918d,f65c9c2a,2904ee95,4f24aeb8,c6a02557), +S(60c822fe,a74d52b7,d5203720,b2c2a361,b7628aea,d2a683bd,80655636,bed15714,5d9a9c0,120211b2,e8285b77,8f8d4bc0,b06240d9,22944248,e1cfce73,826bb67d), +S(f602da1c,788ea65b,cc339a38,c353bc08,1c43c2f2,6e05ea6d,ab52648f,890c9101,21468929,89348f8c,67cfdeda,31ef3429,23b5a450,9fbe9a49,f011d42e,57f998e6), +S(756240c0,5274101b,3059d23c,76d9ecdf,33e1312b,7a36af,ea21e6a6,c52cdbb5,ab24e853,900c7ff1,3e4f813d,a2acdd5f,53ce1710,b785ffbd,e74494ab,43e583ee), +S(8e815b45,7adf482e,e30e475a,4949e5ae,c7ff494a,a918f07f,c39441e2,360d112c,a966f04,2dd9edb9,436b0005,7473aa66,dd19b4d2,cbb3bd95,932ba98e,f1a1f406), +S(216d5970,36c661f2,cf6122c0,a136cc33,9660306f,1c190ee5,5f3bf438,e7189261,5bd23797,c6753eee,6fb934bf,dc897ec1,25b31c9b,9e797ef1,56d8cdda,2ec1d128), +S(a30ed06e,ce34d29,a92fdeef,6954b5ed,4065d592,3af09be4,f0ad4a73,e7c24346,f6aea418,6b38c188,b84fb6f4,2b6559be,f52dc13e,b7ddeccb,6e85a76a,8d4efeaa), +S(aa42d20d,8acf7c47,fe40ac15,3fcaf1ac,6c4ecc37,dfa39c39,fe5c7657,c78444d5,bc3becdf,464ce930,e42a05b2,c52d3589,fd45ff37,c7d1767e,f8462811,89634059), +S(7585f8cb,4812e306,de02393c,c06e9871,1953133c,bcb67ec5,c6a79228,69124ff5,c242853d,1a2c1c9,a1cd1b5b,364888fd,28bb23c1,2b0e169,67961b3,e7c8b95b), +S(b096a1aa,fb969483,185ba1fb,a5fa3f3a,d1da87dc,a10344a4,d74ef471,45cc45ce,edbc9490,23801861,44ee39a5,7bdec0a,230df57a,72649e04,c4c99883,a147f0f), +S(7034d8cf,df226df1,6b310628,35dc02c9,f3e3f91a,635ad93c,46be292d,56c0ec2d,f783b6e8,29447cf2,32769a13,7ff33f82,f9fb166a,aec8c3ad,1679c48,c1a913a0), +S(9f88b01b,b936defd,f61156a,b55ca290,cf282a2f,3718b0cc,2d32dd3c,49248b4f,c24ebc35,27052f77,41087cb0,e772ce12,1035042e,603f1301,e19cee0d,30029230), +S(14443190,51f05d23,343367e9,6add133d,fcb63209,2f218847,59ad81ba,c65e7445,745216d2,d11f2556,7e3b224b,6dce478c,bb988b96,a1240093,964e4ba6,f3b15554), +S(54aa2e02,3038fd83,f17a633f,d9ab441f,e039dd0c,57f9368,3da013f1,751c6813,f4d163ac,a9af3e08,c009b44c,b358ebaf,31aacc5e,e0bdb917,d1b4df5,420d2d34), +S(fd44e742,b04ca4df,693e3109,3ec52ad6,1f67264e,100618e5,88d638d6,d96efa41,7ac09cb1,2134a246,b17ce054,b38f3bb7,7d794f9b,2fca3786,a0ba665d,3eb0f14e), +S(f662f214,10cf6e6b,7f79fca8,7ea3925,6760d83,17478419,ff4671f0,2bd2ab6c,be4ad0b7,a56c87a4,8fbc166b,da8473ba,6518385d,bd004b5d,c85126bf,7b9309bb), +S(520e2755,1cd804d2,67f9b4ca,b3986952,612bb099,cbd3f3be,a54f505e,bba4db64,e3c75cd2,c831c539,b095ac18,3bb13a72,ba7cb152,5b9c214c,288509a3,98a9cc3b), +S(4d16fa3,2d74de13,111b3f22,c4133ea5,377921ba,e54af1d,666d6e9f,b01e117d,a63bdf75,78d73f03,75aed657,fbb8675,67230c3f,868f2cf7,b7275ec8,b02ac46f), +S(ab928c61,ad1c2f68,905b9e95,3c2629ad,9bb7c8cf,ad9f5a4b,35b35fad,69a92568,bf39ec2f,6c1ae222,ff383375,6bd83882,c05be6ae,692539a4,5124b972,e72159ee), +S(8731aaa4,93580732,66b96577,7bc24a46,17fb8363,51c5ad8f,c8bc053e,802dd07d,36957f16,1020430f,69a3b1c3,1a6df993,d9ca8e2a,8f487b7f,b2ccd44c,7f528ce9), +S(3514d41e,8b9388e4,33d1155c,c777c398,22ab36c6,3c2aaad7,ce674831,21231d11,7657cdaf,e9fe8147,10bb2ee1,a97c6100,6c7b0ce2,f5086141,ac2904be,1c7a9e3a), +S(9bb8a13,2dcad2f2,c8731a0b,37cbcafd,b3b2dd82,4f23cd3e,7f64eae,9ad1b1f7,6ba44d4d,50111c46,490622d7,b079c17a,f0ab57bf,b8ad2ac,9becf9d7,3c7edfaf)}, +{S(e60e88f1,dc24f079,f835b687,778307af,83446e,71809086,e6dac0db,9f191de4,25a0b86e,ff05c849,d79a176,1a634d82,29d2a759,fbd003c,b6ca4147,85726362), +S(55a5e6cd,c9e11103,749d469,dae84a88,9e744dd5,d9309762,15050a83,fef66fe,31278ace,a971a41,e2f9fb16,8e80ec03,37009cd5,b0a49938,c28c902c,a7c71fd2), +S(5f25326d,e99a7c5a,d81bf2ea,61a9195d,48832bfa,8caa9777,53e483f2,b5a62580,40b69a1b,baa2d0d1,5cb78a3d,3d184c08,5b4c16d2,90751ec9,bf3eb3c1,d3ec2ab5), +S(1a32cc7a,f88976b6,cbc89865,89e685ac,49381a29,1579bd2a,13f9488,c0333d19,4667a3e2,2048f781,11f009ae,5d7b1b97,850a3a5b,86f77880,b128c8c6,a9720acc), +S(1d78e74c,66247be9,352c9797,5fbc1299,743f9c74,68c64d1,f2d8affd,1b098769,37adf553,fa2a11e2,6913ab02,e59c4f2a,48133fe7,d9aa3c24,a76e9af9,48a29d8f), +S(8bb6f83f,6be5c2e2,b2bb265a,9bb3c931,bd5cce6a,48efccdf,daa040da,535dbc86,eb96a982,23278b81,6284fee7,b5b8a121,7350cdba,d56b6078,89602bba,bc003481), +S(a9f19ca8,1d2ebafc,4bb5d881,76bce19a,d2d2564e,185f905b,8f9eeca5,d6b12d6b,ab23a468,3279a9f8,e2e8f880,e0accbba,844bd4e9,4d3e4b43,74db2b55,d998771e), +S(19680305,c887467a,c3bfe44a,dbe65431,7323d8e5,62271e25,1a794b78,618befcc,48e9303a,3d6371f7,cf0a904c,cf16f606,b0007583,87ae0952,c6119521,dde25532), +S(18b3bd03,ed4696c4,7c3f896e,5df7481d,6f19a5ef,53d62ff8,2948f1b2,154175c,85fb04fd,6573a19f,2c136753,a1ca2585,d39dd64e,6e6e3fa5,fba362b4,ae9dad36), +S(38e3bee1,3cc3e18,a57aef97,4ffee58a,a392c311,14ac8baa,1376b56d,f8ac017e,8596c7f9,8abf3e44,4ab5491b,fe659619,f6defb58,f48e2b7b,57842193,cd48fb5c), +S(dba5da08,8cd17c33,3e892bcc,46261694,d2ff3a22,2a26f92c,17c5e1e2,797b235f,ebc15bfc,5729e986,85a19afb,d7f9a219,e60d2784,e9b283cd,3697f782,630fe222), +S(60456426,caea7fc4,48970eea,fab9c632,3e66fcee,50f92630,7b130937,25b85ee8,dd22df89,c5dae339,49459593,1433f2f6,5f719379,68e56f92,a38d1290,17881924), +S(f1ceac82,15670212,279f36e,f0c8ce28,3a192f66,460e4875,d90b2f51,a38f5712,ec11f026,c76c271e,fabd7d55,c8488d99,3298f6ff,c05ad4a1,26be9447,7d878b9e), +S(2c2fb5de,5dea249a,7bf6b196,8bdec8d6,1838da2c,12147045,18d6494,f09e50e,6c0d020a,d6bfd730,5ee73634,e939ac89,ca2b7d4f,dcbe760c,2d14ade2,659a5b8c), +S(2858ea8c,d40ce264,3c9a305,c0e2c758,af5b0b4d,5c57ed21,60cf7ec4,154ffdc2,33586bf,a61a3cde,4f402bea,123c69e2,2410c0e,590a71d8,9a1e8130,85cbb579), +S(2749a250,4e7cefa3,a3647088,6bec22fa,339fec0d,ec63c02,19e6af39,7fdec3e0,d3415104,a9070af8,b61acdf0,77954d37,57fcf742,a006129a,5c0d3529,3aa95407), +S(8edf3ad8,39e661b5,f7f16a85,dce3caf5,d571acf4,d0c6195c,53b618e,5311ac65,fca0efba,35a14d3a,9944367e,db4ac982,7dcb7aa0,12438c5b,aa5627c4,c4a15ed1), +S(dbb92358,8b083294,5d6d3b62,9cced57d,7085d3e2,d0890bde,95d80400,98c22745,42816661,5515429a,aa023737,5fb77804,624546f2,1f0a34ac,1ed4e4ee,dceddccd), +S(aaca9896,6196ce2,e13df3c7,d058a5e5,10566df0,5fefc04e,51f9dd,85a4349d,be389d02,789548e0,aaf67c57,3b91b389,c7e6ed80,ca3e637a,2a147262,80cd5620), +S(104804ab,e621b098,61fc540f,f4d6be9a,750e3cfb,706170db,e34c06ed,e0a431ea,14b700ed,a465915a,eff84ab9,fa568535,f63e4f44,1387ab4b,d841072d,97739071), +S(b2215070,a8ea71f9,b71f1a73,d6ce366,c322b8ac,4d135b3d,ccea68e5,a51f1c0f,9e415cce,3bcc4e62,6f3c8caf,fd632eea,862a046e,bb45e8bc,84fc05a7,a4b87e00), +S(600c6e28,be5ebd28,d83e6c86,bbbd9b0b,aca22006,42234634,6124133f,3348e6f7,822b1816,79e253db,a47ddd76,c0023991,5c0c0206,8f422415,94ac38b8,ff7994fc), +S(f8b9b45f,c6298dc7,13355bf1,3ee33ca9,c4c1aace,c09776e2,56b3746d,ccae0dc,bf4b7f96,1844aa2c,6ed8c8a5,6626386d,174e77fb,98c0c23e,e2b6de90,3f1f79cd), +S(63987b18,67fe5a17,333eef28,5385a0a6,576163e,2c74cd00,ba87b6fc,96a57faa,23ce6655,51d48ca3,c702a5be,87a05d98,b5aa1097,dd5877e8,11e32d76,4873e6cc), +S(2eb06c4f,5ea9ad2b,124a1202,cb13c1ae,aec4394f,4af7c96,d6a9ecba,540ee04d,b96173dc,77b46ef0,6f4141ec,96ce8d1,4adfcfde,f0bd7ea2,479ba6d7,522d037f), +S(5db39904,153002b3,1498bb01,16efd0b5,838e3495,62d9428c,912987f1,3aae5ae,2115b896,479d0d0f,75ffcb54,ff9e3f73,d1356ff1,4b14292c,6bfe8d54,e9e08861), +S(c0f14110,7f324ffc,f3d3e6c,78d5a628,6000d57d,7e85bc7c,fda15f75,79cef3ed,6eb03650,c8142b12,b330b96b,81214a4d,d01b068a,74827611,53d2c52e,e1315ce5), +S(7e3d1510,ed767345,bbb3515b,6f9819bf,33ed9dea,fab35d01,a7284cc2,371b0e66,4c6b3aca,5159023b,d43ec0b2,57e77e87,e5a6b745,178bb017,9960c89,361fd97), +S(f98b5dbc,3e54c227,b002f458,94850ff4,3b15b2d6,1607851c,50d1e4d1,8b20907d,1d2af742,b0b5ec05,bd6c648f,94563361,be03261f,da56f1ca,7caece63,a336d580), +S(188ef3bf,ab103784,37e1859a,7d53e899,6124c395,ca422c05,d6b21b3c,efc76ac1,19036685,fad04566,2ffa04e7,30c671c7,1b299217,c389c78a,cae9fcd4,ad70fb73), +S(b89070ae,96ead4dc,49be16f6,a1a30bc2,41b4e98b,c18d0227,4c9d9d87,dcbf00eb,90db373d,375d2770,b8dd6b1b,3e3b5899,34f274f9,49469598,e480e431,e4f195e1), +S(381c4ad7,a7a97bfd,a61c6031,c118495f,c4ea4bc0,8f6766d6,76bee908,47d297fd,6c950ac4,dc71111b,70c1a058,f66ea133,fbaefcd,246c63ff,6c531ce6,82b6bc6a)}, +{S(704a26e5,19071bb0,24eb2a16,48b66a6e,157b07a5,52fc4258,381f7d02,e8fd9b9e,d169ea55,8650aa3b,ce52c645,278422a3,69326e74,46039381,920f5857,fa3492fa), +S(705063f5,e481735,60afe9dd,5b2beeda,d6e46391,75ad7fb6,f73350df,51edf53c,32290956,61cacec9,472dd014,bda52364,3399d7cd,9ce2bb31,a5b23590,22c6ee5c), +S(972e7585,f8b1725f,4a7d18e7,77939aa6,3600a7b,a07c4d94,5da9511e,889473f5,aae4382a,49b4c97a,bc3edb7d,26ba7bad,16752047,dc99b434,f306c673,2851310b), +S(260530bb,e338f4a9,71930b12,4f18c82d,e33f22d7,32de9375,81e2b0d5,15e59d97,77c66c36,d6b09205,8ade9c0c,a311b60,a705c8c8,73fd2d4,8e6327cb,71eefd4a), +S(15464351,d21d2513,f792ee32,aca3eca7,a52cdaaf,9862172a,e7224a03,804581dd,d9ee19f4,502f1c44,f656ad4e,add6adbb,d8a04f5e,5344b554,894721eb,8e3e2285), +S(4fcc68a3,caf3ff91,dcce9770,11ad5157,6c844132,321791ca,a652593f,6cafcd04,e8db3aea,a35371bf,9700a9bf,b85e90b3,93cc088,9cd655e3,fb18635b,49fb59eb), +S(301c65ad,567952dc,6b39134e,c361030b,3f5203ed,da89784b,225548ec,45c75eee,95e2c0bc,7b4a7cde,8ce3dace,a691bafb,f78fb03f,3170b347,ee807f42,6b947560), +S(96ca5edd,8047ec6f,b5f8c37c,a734533d,13f0e6e7,f55d28,b8b10b5,121f4abe,1a21f1ba,f6a2e336,247f6ee0,88cca9ff,816b0667,3badc241,d9ed00fc,d2070f1f), +S(c94633f5,783c4e68,12143fc4,6e670978,8e8a526,819afea9,404dfa00,df1bd839,874f8760,33dba9,de463f86,b597219a,c1ea37f3,970bdadf,97c96c48,feec4ec5), +S(963146d4,5bdaa05a,b5115ac2,3ee862a0,2305ba9c,75003f4e,ab838f7,e9adcdfa,d75766de,299e5cf3,c8796234,5db9866c,cf011c5c,f108a794,5642a6b9,dd33eb0f), +S(dde8c870,ec4e9890,2a820a7b,c5784034,19ac261e,de5afd0b,82b8c5a0,7c2863df,e7833936,50d4af7,427158e4,6c753ac1,a5143c9b,c09de97b,3b27065,6f622b82), +S(546c6b00,c5e34a8c,4cc7255c,2edea33,d9f77e7a,c67ee629,bbdf1879,4622265e,5ae149da,f65aba8d,e214fa63,be9bbf11,3dd3c220,12d206bd,d56026e7,4a019897), +S(4340c850,d91b63fd,bdaf41bc,f8d8c010,d3f30eb5,79eeefc9,e67c127a,33324071,dd66033e,eb5ae8b3,3c47a940,2482bcdd,4db5c8e,dda3b422,35627434,dc3bad1f), +S(f796431f,679d9cb5,77bce62d,236d1fe9,b5042a83,fdd1cf94,1a2e00c0,5a261d11,718fffe7,68aa2591,d3fb1fd6,1a00537,3b529f9d,f9c27f79,31ad0df9,9aa74859), +S(f3d17ae9,d5b4cf41,27423894,916318bc,adfb5a9a,6c2ca219,1b918e43,eb5ed129,9da6d033,49c64d79,7ad09a33,bf71cf87,8e0ae6a7,9fa7bc3f,1451126,18415960), +S(23899a73,a4b52d27,29ab52a8,370ceef8,4c7684c,cd535f4a,ec360eab,cfa5a787,f1bcde3c,5c4740c7,37b066b3,8a1a88fa,c43357f7,f3fa23a7,b00815a3,85336320), +S(5805914f,5418971b,106305cf,c397dc12,f63a3b2d,8b451e5d,c1b60c2e,3d9e9208,616e2764,67a5f1b6,46279ee9,6e8645f3,76a80192,31e17a5,c92e26ec,1b76e62b), +S(85ffc326,1991848b,5e918c4a,53f291a8,31796b52,d56a5c38,8bebe625,d78cd07e,95fd6f12,7b155e6f,806c089f,3f5abe95,344e9014,e2c72fdb,e720bb8a,93d864a6), +S(6f1a57d0,6566bf81,f4b16329,19f477ef,aab4f829,e29dda4b,27627b96,1cbfe3eb,de1e8359,7ff20c63,3d28b909,caef273a,a57898f1,a797fd91,e00e2e7,da1872f4), +S(3d28eba0,4d0ae2f6,208adc71,cd6af3b0,e208860c,722903ab,e106feb0,af3185e9,cf8bad18,40d3d2b4,abfb5b28,b50702dc,512527d9,5bcd403d,9713ec7b,ef1dda13), +S(46511979,2b845113,1b32663e,baa14c4,20a5408c,1f53afb2,43cd496e,c4b18118,40bd602b,d740096e,842b40fd,8304ee73,842b074e,415d5ac,c5e2243,28b241f9), +S(393a8bb8,7ffe4265,51678524,8ac940c6,4aa70e71,512ebbc2,3485596c,a6d9da5,25773032,d2c1f80b,3954715a,6e4132a1,74b4468e,658f6cc,4d5f5d63,d458980b), +S(aeb37eed,35274696,2b85a21c,86b9fe34,60433606,9ae4ce6e,3a8235a5,e43c48ad,d94165e1,5372330a,7b5507f0,377a966a,541b6fcb,949398c8,dd6d6f52,2411d86d), +S(b0bbb4d3,100ce417,dec58f46,95ed8b30,4306f21f,ee11f899,585fb37e,a9905c59,89141fcc,9344e617,7742e31c,42c565d0,45c7ccb8,6f88df7c,5c36d23e,45e51d75), +S(49694de7,330b4c3,1431d452,f3e9e562,eddfe029,1cce58c,73b69cdc,b89e0f49,4715ea3,b6fdccf8,e224b93a,ffdfd1ac,ad8baf44,c5bce735,e7c9b4ef,3faa2656), +S(9a7720b3,ff0363dd,7263e1ad,83c32526,67b67d3b,72c2c14c,95f0804a,dd20f7a8,815a769c,494824a,a819ea,54b560ed,e1df9bca,d7df2d63,aae69c4,a02f9f20), +S(b89c399f,cdb3aacf,99796fd0,95c17cc9,786d79b4,9a1a255d,5c9ee510,38d3620e,ee3c4936,d4f9d1f9,d2642043,d25b21a1,aa32fa3e,ef44f409,73db47a,96965cdc), +S(add68bac,d7180ac1,4e9bbc5d,1e0c3911,f2202d90,1f9ba649,46b06507,b86ed5e9,fcffc13e,a9be67be,8d090a77,9fd9107b,f62bc785,3f98e97a,c0358b3b,7719944d), +S(9bf62cdc,cdabe928,c1ab44ce,38cd0611,135971ed,81ce6c6f,dfc5eb5b,d9c3996f,885b2381,e0e785d3,cc3f78c7,f9fd54b,ecdd9d9f,c2979e23,f97e9bd2,a4f10d3c), +S(bb223cee,f11450d5,c5e0b75d,20eb44be,9d44dcff,28574117,12fc5875,3b839339,8bb29985,87eb6f5c,c8cb615,285d9e69,71db8e31,8d81fd5d,6318909b,8311a00b), +S(9ed73f09,2263e84c,d022388e,da82361b,445f573d,b646cc62,fa0bf5c5,1d33fd27,49ce7698,144e1115,118a4b0c,bdb98dab,6b57dc1a,4d1bb6cb,a68d4d20,d8e937d7), +S(e747333f,d75d5175,5a0cc9f0,a7287084,65a02c58,7737a7b8,b8fa1b8b,4bb2629a,d5001fe,baf8f3ee,b33bc9fc,7fb3da7e,377c8955,91e56965,607269e4,96b90559)}, +{S(516ea742,3f956765,a15f856,182f1e7c,18d3e548,b9fdca94,ea46024a,1a8fcbc0,cfddd98f,be500604,28beb901,92c01282,aaf9ed93,76f0e26b,e912ac42,a378d542), +S(8ed072cb,13eb90c9,e5c107f6,ba576a87,ac75a431,53025e6a,86addb95,bba7862f,eece8a5a,f28d356b,f1a84c14,2549ae7f,894f7c07,305194f3,18e30e0c,873fb5b0), +S(3e0e488b,1c8acc24,f81bfa1a,f6761afd,b4fa5f5e,6317ba72,bfba2f07,6c2ff593,2c4ec39b,2f37b948,fdbc9e3b,a3fa82c0,dcfde2e2,57830a04,4c178759,ef5bbc8b), +S(f6b3f19f,cd7eac5a,13630ad1,bbf331b9,5608b7a0,ceaa67e2,4a1e830b,5eed9825,a2a64078,19ba0f7e,7a890df9,523c6736,50ad08d5,c2557cd1,53c6ee65,ef493ce5), +S(e2de599a,879285ad,398b1031,8e1a8387,21a5c4f7,1105469e,affc8e37,189548a,dd977e62,3dc05cd6,3155a71d,d87d91d1,d74d6e31,5f73434b,679b605d,9db264df), +S(bc52359,683840a8,59fc2c8e,22d72ec5,da2493a4,bb5073a7,f658517a,de83f867,76a13651,712ff42e,a0c10f09,45c4ce41,2cc8c4f2,ac3ae446,7cb383c8,656d3186), +S(d87e2b08,154e38c0,13847a5a,2f84c276,dc088b6f,c19a9bf3,90a8a433,fa937fda,d91447f,7c9042e4,6f64a9c6,40a5c294,1a6f08f5,d3eed464,b09b2a1,1c402c0c), +S(4359ac5c,5dd70bf1,d4f24f00,1301b9f6,17d9c69b,63350dad,9a8cd192,655ea801,c9e14f94,d8ec39aa,46092657,5d770426,350794a4,b1ef2410,a9b0118c,ac5d55c1), +S(3ab3f503,29e22bf6,8fe9882b,3b4dc989,36dfd840,be6af588,ab6d61de,48094b9e,4a40c435,9f4dd21b,11664095,4b55e6b9,f0308786,eec32fca,6bcdd5d5,8d055ac6), +S(a0f1ac27,d046d987,b9a98bf3,f770205,931fce93,59b75944,6494d221,dc2752b2,bf1bfdc6,47a15997,97b5b6cf,2d8a2a44,e9c36b9a,20b53abe,58ce9e0a,395fab70), +S(a9aa63ed,3b0260d2,b35b030c,7a5511c8,679b6170,b8a4f386,fae0bfa8,92735905,2f654620,4dba9b31,99bd648c,cb1605f7,62f312d1,67123d98,ed66f02e,4d794e90), +S(e51da157,5e566ef3,bad3fa66,e55432e1,29be6c36,32e390c0,f4d76719,bae34b7b,55930b79,2ffc91de,674820b1,eec290d7,74ecd79d,1ca07d6f,5ea2f817,4759984e), +S(8b69a891,b417ea65,7ba52bae,58920eb7,f101bb92,e150dc1b,c961c37e,73cd18b7,5b824edb,f4a68988,39de0d70,ec16ee1c,a01a4692,f29263e1,1069aec8,6b149214), +S(ee5c1186,77462649,6d37fba,e48e797,dc69f31c,d6ad22cc,937c7224,ef7ce8db,13f7987c,f2cc4551,e058d410,3d5c24d5,13c2d602,ddccadae,fddcab82,d14d5310), +S(b961cb45,5de8b5b6,c4c5c2d5,75303c81,35b5d278,503a15d2,371b0551,5b236b,3ed18486,5ca969ba,31c734a,19055129,1cd664be,576925a3,2a142769,4fc40df2), +S(83effa4,c127b5ad,7a0c53df,5be5596b,d4a42987,2eafd8f1,5498a6d2,47b87314,efa99759,c9360b14,7643de2d,64ad07ea,39cfabe0,2bc94e00,dc9b2e70,c2e2c217), +S(f253fc52,4fb0254e,e772f50e,5d6c16d8,48692455,c855d4be,15ea9f9e,9a5411dc,59bd1f8,2cece609,8a63fa1d,48e4166a,d79174ec,5f8216c3,16c48c1f,e5c9a0d7), +S(6b61024e,e6451d97,1446b55,1476c3ec,eb6b19ec,16155acd,317bc2be,11086411,8de5c6e,37b562da,ca5a203e,ea028b76,e6befaff,e54b49d2,6605f169,592242cd), +S(1691a90b,9cf72621,3680a72d,af59ef24,985448ff,5f35372a,ab6e2aef,df8b33e5,83d2032b,6ca761d1,286c1348,31250054,5a230558,cba391e6,f0db9c9f,97c2d618), +S(42a078dd,cf749f25,aec7a1f2,8e976f79,e268c36,a7b5b0cd,6aaee3e0,925746ea,c60f1846,6f025987,e0ea6ca0,3eb98df6,99389753,b57abbf4,f5739509,bfd09d1e), +S(21bfc1a7,16b09543,5142c31e,5038d4ea,4643d9c3,2fd4728d,1374dba8,1ca1f07a,a991d491,2601ca23,8e289e71,e9d743da,4385aed6,c732f808,6dc21406,74540acb), +S(e75223e8,fe247a98,5220cbfe,52151978,c98d1460,746f8de2,8696d235,71f3336b,dbbb8075,ab489582,52472982,c7b0c3bb,d82a0762,36c07c05,44417ff3,883f6f18), +S(7a756a,72fee88c,7a2758a5,3294da85,6b06129c,1978e217,2bc7952c,92b05265,c4ad3a0d,be72fd27,bfa475d0,fbd16a92,5e939362,bc0748c,c39ba9f0,3ad84133), +S(2bc697fa,d947fd62,63bb2841,1a274520,f5d582f6,7f039114,293438fc,9aad7c82,543109b9,82097efc,cb44d854,11fc5230,6c7a219f,2f58b37e,3dd354a8,2ffb28ad), +S(3862db95,1ed8994b,a8cc0178,f6dc97ef,db6e1380,c18719ab,cd24a88c,87039744,af1e8ac9,2b195d3,6fe1b1be,a68e9215,a453e638,67e65d88,64a8baf3,ff5c1267), +S(7b648cfa,40ce7274,59a6fae2,2836ea1d,b18ada4,9b18a61d,748127f7,7ceee771,f2a30c56,42887135,30124a69,da2c0355,8688bac3,dae6d95f,a252855,a85a9b4f), +S(f803d7c6,1820f980,ebe0b297,87aa688c,ddadefca,229b99b3,a6bde5e9,922f94d2,a5f8b450,34dc7de1,461dfb74,e7ed9c49,80407bf0,4b0d9159,af703a9e,1e0f9c61), +S(2247f630,9be2f3aa,e30c5907,c29095d4,b9198d25,1a17bb34,7cf5cb35,a2ecb1f1,82685964,20d87b07,1c5a4044,b79b069f,7fa6ecf2,cfc0f839,b2161475,5728c2f1), +S(1d770ace,ceb2183,fea7c924,a8fba197,579df37a,908992be,d42c8e80,8bd98ee1,d87077fa,b910a21,8769cfc7,49aad579,c809e35b,f1c2a813,6047e85,e2c6fc65), +S(5d134e5c,5da47f7b,a495f216,b4994d90,4a79057a,3d0076be,34f09013,99f1f366,fc4e10b2,c1f7bafb,d241d5b5,1c57d48c,30fd29e9,df5774c6,1d4f2c15,3b66ed03), +S(a49ed10e,aaab9323,3a5f485d,4bd18c06,28ab2629,f0b8c3db,4d05956d,6c953fa9,338d476b,99f0ac67,1fcb893f,5f202204,a5178acb,6971e7e4,984d42dc,b904afbd), +S(4d000b62,1adb87e1,c53261af,9db2e179,141ecae0,b331a187,aa4040a,ee752b08,95f2a470,e71f2daa,34927daa,7d268d33,34820a0e,e638d6c5,c18d7adf,b7cfcf45)}, +{S(44d42980,eb92b3e3,b16816f5,56858355,e031b88c,99117385,def6599e,f274e56f,6e3de5ba,4f693fdc,747caacd,b2cf0107,f29fa7c,9c6a1a09,a527cd16,4c2c1484), +S(9812d508,d6da303,6f08fa7b,54cae319,232f925d,6af91d71,fe6c2fb3,bc86be5,735081a0,35fc17f6,7547b9b8,f0f91ac7,f0ddb965,19f6f398,dea745a9,81441e2c), +S(5a022ba,a90ddc87,42246783,4f692ecf,dd2c2dcf,b054308f,4afeb17a,7ff6ddcf,6fc2a9a5,4c7a130d,fd26ca48,82406fb9,f67db0ab,7e6a6d95,1675fef,2e2d4256), +S(c181ffeb,a8ea7d69,c524cd42,18af3030,1cac8e97,69eaf6f6,ba73027d,30fb7bd6,e88959e5,b07b7d3e,693756a,f94590bf,997763b,afa7d850,a80dd9fb,88e6e904), +S(e29375b8,21c056c,30954b81,4f9ce795,c1493dfb,ebf06f6f,f32c92c8,c74839f1,a9040ad0,95c9d45b,1527c624,bac86841,a1f28b7,ccf8dd37,b7e950b4,858e6e18), +S(69445948,ebec5ae3,9fcb505d,7efb7902,6bc1e8fd,5d3024ac,2b772439,72142d80,5b6c2694,abac3938,db899396,62635c21,e64fe2aa,40d18678,9c246e9,fe3f4be6), +S(a86f3aad,85d0bbb3,8270956f,58c2fd65,f5425428,27d7a658,da1b111f,64c02c36,dec740b0,ee35208c,dbec5b7f,69bb94f0,7fccd075,7868a37,6ecec7b6,dcbe20e0), +S(ba2bf65f,aac92da5,6c252b50,8dd74e3e,99ace1bc,42b9d2db,9d0ead3d,b6820306,37bcd01a,75027b42,eb0d7b85,564bedf9,67153930,6fc97106,ab6623e9,90b031ba), +S(78419e61,4e8b5eb9,d09e0c09,79ce4eaa,26271696,fcc68269,4cddf1d9,6a4c7fa,a32dbb3b,46f9b6b4,9adf4dde,f1986af9,72662a6,2ed6b6a2,f8b920b6,82b32363), +S(71163271,204207c8,a84b5993,88beb505,640898ab,b24c4c10,42195dd8,15d77985,aab43609,9370f246,7035ddc2,e71d73f3,c0f1aa13,148303bd,840459da,ae307e8d), +S(473f52a1,fb7c3920,f09ba6e0,a3c891c3,3f4a13cd,9dbf51f0,f3d39ef2,d6bc07d0,b2c403d2,4aef71eb,1b834df2,8bc08b67,5130897f,a6d9855a,eb21ccf2,780444cc), +S(581e93b2,99b8c50e,e6338c0f,f426502a,d8699563,f17935dd,abe08a73,6932b71f,46e7c7c5,1e076fd8,9b8aa98c,f0b3933b,8ca82cc4,d21783a4,d74ae1b6,ca9896e6), +S(e65d9e24,e7340122,875a9d86,d6071a48,691ed5e5,a94b315c,76f169f7,f3d69c48,73575103,a70b7a59,90d9b880,8698b651,271c8c0c,ac93122a,66873bf1,fa3c6fab), +S(cceab216,41d0597,f9c7ab64,7f99154c,b22d4827,70395d6f,ddd6db5a,dc752825,4084c57d,5aafc328,e7a250d0,a7c3c0a9,627ddd70,c77c2be7,e5a1af34,359b9b86), +S(4222ee66,5baff421,17f47df5,c1c1df5a,dbafb790,d5c75bb7,2646cf85,7ae85923,43088d6c,a029903f,f5a789f8,16730345,5a5cd0af,cab57e15,12781396,fcc9b6da), +S(391c5d0b,17a8c11,3440cd30,83434841,969b0833,71758b30,27e38a25,e778da6a,69f3d295,be55f859,4bbb2fb4,116de5d0,b24b5a80,ed62c1e2,8fca9b8,3f6d7439), +S(803b7149,f87e86c0,13599898,b0c9050c,d4a6e030,e07e8d7c,a49c46a3,8a6ea6a1,6b367fcc,6d5916e,72f670a6,5ada9c39,54800e90,a8830fad,c9ea17c0,494cd9aa), +S(f7aa1c64,f8f92f20,1319f316,353d89bb,eaa4d65a,e148b01f,ab66aff6,c9deb179,e9b407d9,4c2b385a,74f22eba,93dc35e9,bebca7d5,17401b7b,576b7d2b,e13ff0c0), +S(f1c34d52,2b7493ec,cefd49da,99732e00,85ace2c9,fd14e9b0,69b67dcd,5acd5e23,29460fc7,dd77494e,a5a7764c,7ca6db5d,5d7a5e3f,65e865b9,e5f85d58,e77713e9), +S(db19a1f6,38ef7034,5340e3df,8d384944,7500640d,cdbc3be4,df3b191c,edb9db87,baac873,a76e0b91,c4847770,9dbe88e9,6195e9c4,ac4d7749,71ca204d,4a5e748b), +S(4ad12e00,f384c7f6,ea669c71,3649da6,55e0abec,67551a58,224b9f9d,de6bdaf9,2e0314a,8e3f32da,33a22ecf,ccac4965,1f1f6f5,20baeddf,39a02bd8,423cd40c), +S(c9130b88,cd451d4f,6eafffc8,357ba391,ae920c27,69e7c48b,49881070,fd088ad5,aac7c2f,4f2f8b90,bea9267,897e0079,7d6515e1,937fa4fb,1043111,6b5e1de), +S(88260ca,df81b391,be79bde7,b54f8a98,428aeacf,970cd843,d683e6e9,50686db9,3b9b187a,b998a22b,56b2933c,fcd09333,9c23889d,1180e365,10dc086,9869cf2c), +S(3984fce2,ab73c70f,a5538206,c2a61e60,2f160b1d,2eb61980,fe174cbe,fe464dac,b7e65c1a,46b50c72,621e3fc8,4f4c7cf3,6860567f,abf00743,5fd1b13f,7400326a), +S(e6b48495,c8277598,23b73f35,762c55fd,8cd20420,fe5be6ad,f27f12b0,68bdd63c,ccbb7124,3b0300fd,993dc9d3,4b55534a,12515243,e07ab78a,8d8fd528,46e5a69b), +S(6af5144f,342f492f,3f506ee7,fc515d3d,d3c93d02,27ba841d,74bc6548,97d4830e,b195d9e0,8113eeaf,fab92a2,81ddeaa0,95356053,a51cf84a,b5d60fec,5368f98), +S(14439b7f,e40ca407,374da12e,217edd9a,86c84397,e2fcf6fc,965023,ba984a1f,112ad656,47c47c30,f19ae62,e0c06b35,effd49bf,d5e604d,6d621471,9f088fee), +S(d4a7e4b3,863fece9,660baefc,ee57d09f,6f60cd25,f4aa178c,cb6f8a17,5fda9d4f,4985a973,ab0e8627,f6de7ef4,470de4c7,1adecaf9,f3766197,a86f4e40,14ea474c), +S(facc2a9b,9d3ad0e8,9fa479e0,ba777a0c,90a0c229,59d4b719,a9304df5,f1e96ff0,6e12c914,70c78733,3e5a65b9,8c01d342,827810aa,be3e4e33,cba0b7bf,eb283b91), +S(3d1b3f54,2809a7d7,79ca2416,a7b7d007,4a728599,e4f30cc9,14bbbba8,3daa091f,dccd0d01,e56c7e6b,90829ec1,f0fc733c,8f1cbcb8,79916982,3b466448,cc21674e), +S(a8c1ec56,3cf9596,d761e41a,bd6bc960,562eeaf5,b54eb83e,3d7e7259,f69671d5,a03c9fae,e160ba53,8aaf38cd,96ebe3a6,db59a04c,ce7074e7,dc3757f1,ccc244e9), +S(219b4f9c,ef6c6000,7659c79c,45b0533b,3cc9d916,ce29dbff,133b40ca,a2e96db8,db2639fa,26a61015,a5bbe7f,3fc8d591,c6b0753a,c16fa89a,d820fe57,72c49068)}, +{S(b445babc,55be50ee,bedb8c27,dfc6c37b,492649ef,8a65de02,111b9f74,29b8c3af,6f74c5b9,f9a022b1,8d3a706c,5c608b31,9f7ce25d,8424d893,4cbd2f90,84b78bcb), +S(dbed76fb,7e46e1d4,1b507edd,8994fefc,f94bd651,a9720d9f,8d62dc3e,9f329104,c047fc1a,41689ba6,9855f063,c563bfe8,49bd8b5d,37b3836b,d8bc57ca,fd02ef64), +S(844426e0,860ff2db,f012ed29,ad2919d6,f46eb102,68073862,c1792e99,f1b2b33c,243512c9,c6ca739f,fb181482,a901ecc6,a41893f1,371d6b12,31d5427b,fb486394), +S(1df697b5,9a2f9c91,b2c5d4a7,8035ea2a,351dc000,4e1c3bd5,5973020c,24836aa1,e89f949c,f6af652e,d7e79758,74a994ff,46475df5,4f7b17f2,a5c29cd9,7f722831), +S(cf4ffa86,87d9a39,7b4727ba,a033cd02,7d8a5377,46903db3,34c35f1d,855999a1,d1316b65,e027ed02,b4be11bc,4c21c1a8,585bb247,45cdfa67,5fb9cccc,faf0c546), +S(e3eed1d6,1813e3ec,d1b9fcfe,3e8bd700,bf3412ff,78a0a9b9,724d4dde,ddfd98b,dcb09803,b70d4c34,ee2bd7ae,6444724e,9ab27c20,5c3c736b,172af37f,cc673105), +S(3a202c1d,94a94eef,18fa396e,5cb8a867,8c3ae45a,e4ee64b0,822d207e,6c814fe7,147992e5,ab565bc2,ad1b1355,60f37dc6,b5cbee74,fef8e5ca,4e4f418f,811a0482), +S(6ce8f558,a853dacf,205db4a5,80c4cbab,8ef477a6,47bca6cc,9e676cb6,5f3f696a,e88e3934,b2857ec,6edb911f,acd132fa,f0078971,2805aa59,9afb3d80,942dc23c), +S(7fef9aa5,b2df37ac,99ca488a,ba598b4d,eb222149,55e1cb4d,c3ef1e7e,7bd38945,d4b7cb4a,8f9edfd2,3a0efd1,9882baf,98312b6f,7b5775ca,65e9dbf1,f2c32870), +S(6ec1ce91,d1eff7ed,9beba2b8,2f4a526f,736e717d,6442dd29,b55ae2e5,3371e0a2,28240ee,12e2b1ed,b40698e,ba6f087a,145eb772,caece880,b3e94b97,700dbd58), +S(645b9fba,2cb739ee,9b148b29,8fbe9884,f284893d,968c21d9,50696d2f,efbbf0bd,b06977a1,2d19836f,add50b7,b73399bc,698729fb,fd182026,d918a267,eab4b7c6), +S(7b930561,3a4a7cc5,ce1e7f5f,29314e1b,40bc8b93,40604f81,76578c18,69abf6c5,55a7e3e3,3f19805e,b5056d15,deaaa4f7,aea07a46,f9dc6a09,6ce15392,e146fb3c), +S(bbcc74ca,3697ef46,e7415ec6,b31a0808,1e6ade01,c7e2264c,f9d4d94d,d849ccaf,27bf64e,e1005f13,989639a0,8772c42c,b4249ba6,9d90cae,3f542ee1,78929f26), +S(4a45fd82,af96af67,9e640bbf,561cb385,2585a8e6,1b57df7a,e028ed33,a017c680,4ba76ea1,19a0267a,f019b3b9,89cde9ce,7b1c0b6e,da3c773d,ca31e44,61e048ed), +S(c3efb1ce,ddc6a749,a5db9daf,48032a6f,3f1a848b,aef9e44c,ebd76127,a9c90d0e,3de258cf,e593b489,8f92e8ac,50be894c,3636019b,a9f31f70,28468eac,687b8f89), +S(ec71a2a4,6f24acb2,8fda6bbd,ab9326e9,6590a96f,b9b9a4ef,405949a5,e3d2858d,31a91fa1,71207da3,1b0acc25,cace1e7c,5126ca2b,4c8d9733,4c50a7f5,29bc61d2), +S(65dc268e,cfd191fa,f07421f0,dcb16701,f979ad24,81ac5ddb,1f77d3ab,41a773e0,f8c9ac90,255d6460,15ddd1d3,57b92522,53bb55c7,e2f5d843,d7d9a025,2766d2c0), +S(62152eaf,df564900,4379891,4b53ddd7,3b91fb60,f16f2d18,941caa96,18d8ffd3,3a185ef0,a8d8a35d,112f678a,6a04a654,df565a8f,87e99abd,95fb4977,1b278ce1), +S(f68e6fcd,b2c49661,ae59bff1,f24e97e6,fffe7cfd,f185d0b8,133d58e3,bec1c89b,223dee27,5e9cc518,af12be21,ee7ef3a9,ab39c7d4,4f950fdd,9ce5c78e,b50514a2), +S(5d02e9c4,108860e8,2b1ae04a,4afbe1e2,9e0a8444,89876776,7e5b60d9,3fe5c753,25fdcc35,5f1970c1,43dae96c,a1ef0a7c,f95853e4,102548f3,d869d3d5,8bcf962d), +S(f6217e4d,4e6d06d1,27668a01,8225f88f,a1e0fcd8,e8654fd,ab26c8a5,4c6d4751,65a6acbc,19bb2835,13eea5d2,5fae521d,aeed63ca,50f9aed8,edb74dd9,c43d066b), +S(c18bb768,bae77077,35b4d3d0,e82cac24,fe3d7ee8,dcba20b6,a320ba6b,4695a406,b7a7ded3,a589153f,8ee504cf,fb5b45eb,b2d8e121,40f2f475,186153df,1fcf84d6), +S(36fc443c,1350b40b,881e41c4,d3c15952,31f8da9f,cdcac4be,f1d0c5da,ceb9844b,9843bb7b,fd0ebca1,762785cd,55669233,16c36aa2,d2c37b3f,2b196f78,bfa5830a), +S(ba7b8c09,d5293e6b,a2548e6f,ff3c939b,80d2ac54,34903039,dfb8b661,29e19cfc,54fe2a,9353fc1d,a0d34e07,b6d34d1f,f3a1f67d,f4aafa7e,57919142,95c2a5e3), +S(50a8ddf1,17a91c92,37a48fe8,f1a00e72,a5dff682,7398a4c5,d2f78b4d,d49ee339,f91d9b20,da28e51b,99fa102f,13f5e451,ab22e139,80052384,6b9c66bf,b7da1578), +S(642ece53,832d1859,c6543147,56b618f9,520a5888,2549277f,6b27f16,e08e3d1f,d9963beb,2c6da204,339a49c5,f253498c,48cc3e99,b715ea8f,a5eb00cb,1d6cffbb), +S(a68c0d3c,13d764d0,7b513390,5842c9,a7171e4f,755a9737,609db06e,1a44e5e0,a2c3fdd7,b7938a87,86f3756d,dbc66b29,72469e79,839a1448,b367db5a,2bc52c15), +S(5b33d730,288fde53,b123fdee,177758b1,ec113adf,74e79eac,513eadd4,cef377ac,1bbc10e,9d45cb00,db58fceb,bc4bcf4,a0e2bcd2,a7d3ec12,7d87beb7,a134a20b), +S(aa6dc4d3,ce531af3,e68590fc,acbe7816,c8293af0,d77914a3,c7119e23,e50ce56e,14386670,5dbe1ad6,91e09123,a19a199c,3ee67b25,708ef57,4620c5ca,821224f6), +S(180a4ece,d74ceaab,e0f7db3b,b038034e,5e659c61,3c66a534,8d962d14,efa32402,b675b2a8,b845281d,524403d0,db01417a,59fd3a6c,80232e74,cdfc87f1,3b76b0e1), +S(3a55690d,abb5e00d,c2d0d8a4,96d16c44,76ee767c,a9d0d1d3,694c856e,e5b7ad0d,3c1d71e6,8a5f9a84,4de0453,6810660c,fe353475,353cede7,2936786e,4d173828), +S(33b35baa,195e729d,c350f319,996950df,3bc15b8d,3d0389e7,77d2808b,f13f0351,5a75fe7a,9bf54078,6b9bfc9,db72ad43,559a9f10,4377648f,d43afc32,34728817)}, +{S(52f79560,fdfadd45,6165a204,6bf61bbb,726cd726,3a3ed2d2,45f07631,5b0b6ae8,e6c46e55,5b4a0410,bf38965e,5a7ba381,fd259482,2280482f,877a7ec5,84d14012), +S(29eeb07c,7b27f82a,1b031881,11d324a9,4df77713,a8cadb36,2ce4012f,52cafb19,b7538574,28faf258,f240d4a9,f464797c,dffd0a68,f9f978fc,476f9bf0,1a0a2df5), +S(2191ebbd,a95c29f8,e7062f21,a70cb368,ac67ed59,dc44b167,66e52120,cfe8e742,2812f1fe,557496f8,f21b1f11,2df7bd19,db6aad90,59494ad4,eaed4d77,49f66a4c), +S(3c29d849,e25364d7,576779ec,78755ff1,8aa64e2a,65140a2,bbcf22e3,da33a4f3,3658d9ff,e2e283c,f8973cc0,ede5af6b,69ac4970,3c6b1370,f6a2ba4a,78a28a97), +S(37230e16,e11db299,f54ca0f9,f5423ac6,5f05840a,e166175a,ff0732be,c72ba88d,2a26ac2c,e8f9ebdd,20f1f5f0,f628d3d,d0e02745,6132cbf8,78b614b4,51db28f2), +S(8fbb3be7,98e16bfd,b738a512,ceeea92c,1be8eeb8,5374702b,e927c614,ab1f1baa,8280f387,64a48061,26392be0,c95f0c58,3607343f,d0b24b98,afe3605b,8f7e79f4), +S(fb639ee6,29dd1f03,8e12330c,bf40ec7e,129d7da7,655c1c21,86452fe4,9589c89e,171adbae,2efe213c,8d01e273,ed9c5d47,c4e85503,de3849b4,d909823a,bb1da898), +S(2399064b,876b7584,8c977bf8,e35d6b32,2e45d1a0,c4243fe1,2a31a581,d1d5d826,79c1ef29,c1af9497,f3b3db13,17432d42,86fa014e,17e5d780,a0d39df,b61369c1), +S(dd5663da,63acee49,eb7fde29,6ac1215a,772512ee,6a080f3b,1266c7ef,51da5dd2,d19c7348,3754112e,9cb3a4ce,8986f748,3eba26ab,c415abdc,5effc956,27efb7dc), +S(30862c58,43b161ba,c127bea6,7b23d3cc,46b6c42f,8faaa281,6ae47092,8ae47993,44ea1101,26a7c448,dfed4995,46a0fc8a,3658e540,d7d0c2b4,18f8cba0,accf9537), +S(df7ebbdd,4e416e4d,6b1e67aa,34915da2,cc15bf8f,f6d79ebf,273b63a8,32d6610a,d05fddd7,e9618753,21f473b1,bfb5ff48,65b3c4f7,5cf4ae26,549989a9,e13056d8), +S(13adba8d,2485bda5,1ac7994b,c45a7e4a,1b21aa9e,8188e631,59b217a,29d4237c,6256a795,3f24b25a,c1f59384,aac3eabb,4458e504,af3b99c1,99ae614f,8def4ff4), +S(c160f7ac,9a453a1f,8811d031,9849be43,22d8bbe4,89cad7a9,cb815927,d4b54720,7958b41c,751ef3a1,fb985ea9,c7cc85f6,c16282a4,c374fed,5999d8d6,3227b720), +S(c66af931,82a7a9d6,588e9c7b,3eda3b49,40fdcb99,346aa55e,e6549d4f,f9382228,ffe4d0df,43f00af4,fe885b10,92ae38fb,97d21a8d,26aa5f69,9751d52c,a9ccea4b), +S(d3a4f4d7,d208b43e,c4c2fd00,798d882d,922f302d,a199b707,76a70f36,5ff404aa,8df220d9,63faa827,1c4ee360,67a536ab,25813239,82252483,311616d0,1458e1b), +S(47bdd428,d57ed451,cd8754ea,817c5f5f,9658274c,ef6757b8,70527b4e,96f372f9,fbcf0ee,9fb14de6,3c288dbd,b1888fcf,72f0265d,3fe2209e,12c85841,2c375b53), +S(6e6deb95,7f2eea30,5d625288,3cb311c7,f0365a42,480fb807,36315c4c,62495438,ba0fdd63,9b8678f2,ab0fe3e9,a16512e,ffd9ec23,e691cd4f,86146969,534978aa), +S(dcd2775,7cd691e8,28e21987,d6eb6b54,e8def24d,27238cd5,dfb36a3d,d0f05caf,40bf37e7,bd776a62,ab420209,c71df7df,74d185c,f0d6b038,dea9c8e0,c1dad163), +S(eda569f9,9bccdc21,580da94f,92d89312,cef87d13,f08d8ad5,f1574e12,30a64ce6,4e1da1ac,dd274e3,f9d7def7,746f0652,678e549,ad5476d1,410adbbf,aa3c1e42), +S(5d3d4a29,734fb7ad,2846ae12,4c803364,ea3d57bf,e8d77d9e,6a3b3f8c,9cff26b6,d3e598a7,1a469323,a357df08,319dcd1a,d7337a32,c9894b80,6a30c575,b19756b0), +S(10161fa4,61e87595,f269da7a,ae3ccf01,40e910fa,891276c2,df1bd91a,95e4d046,b36eb5f4,b8291a01,18691f1e,50235d8b,f66e14a7,f0641dd6,18ad7ddd,ea150196), +S(7ba1b276,3df207f3,cfd1d58d,5190eb91,99cf82f4,9d2d0927,f5f260f7,2ea0f178,cb9fcac,4be96ef5,3134f513,5509c178,99af24c6,4eabd650,afc599d8,3927969d), +S(4bd6edd3,aaa1802a,b0f46e05,418ada37,e75728e8,6ea4b293,6619c92f,57674dc3,c9e962d3,de71eafc,7fc9a329,3bfd721f,305e876e,a2a4755a,f9567dca,21aa3c0b), +S(95fa0b32,40b24ba,29a484d7,f8f022eb,b3f30349,9d8abc1,9a69b690,3e885b68,dfe6b88e,56d7b923,dcf8bac6,2241d663,3ac2ae55,c3a01fcb,9f966d62,8f3acadd), +S(d0fd4d10,18c37114,2d5f8a86,617c250e,b6c3d5,210ca465,6ec84e87,d0ae42b3,4e3bf443,290404a9,3af38e72,a54fa06c,3b2d6a81,161fc8de,554edd9b,f3399587), +S(992e1183,d4e7afde,166c45e1,37c71c88,d4039709,4262163,b4ae38e,538293f1,c29534fb,55e47a08,ecee311c,8f0ba4c0,39096edf,b2d7ed63,21a2810,32e85900), +S(9c124ecd,4e6ce167,f60dcf38,25976f33,64cc30ff,61f7dde,966f8c23,4c13a4d9,7ad73bdb,e0afe3c2,c89d9135,d445ba4c,796066eb,1909349,9e6ec14a,f74f664c), +S(b09cdc9b,d102f89f,bcca0ed5,888519b,7c5c02b1,64ccbfa0,3d0fe42,b1b113e4,f409865f,6ab4371d,f52790eb,88df67d,84b3b74,f17edbc1,29b802cb,d5e49a59), +S(6b4f628e,beb6d619,1d616e87,3233ae37,ca4cc3f2,ac881e59,9c2c8e3d,295ccdc0,1140b988,60f4ac7b,659eb012,6fdfb796,c0baa652,2202cce0,bf54b3a4,865f171b), +S(a728c830,10169439,3af3f780,b1ceae3a,6ca08ea,4bdc7554,2ae84564,f542c28b,7b68fde9,8c97db32,eb3cdbd7,15816e51,9aa58458,259dc74f,5d722dc,f48f1933), +S(21ce4401,4ce959de,f16b3912,e88ff48b,d44ef79f,5fed2d35,bdd2dc78,de8f7605,cdc598fd,c5d30508,a2690299,e0e25b91,b1ccb69,97b99fd3,eca1baed,76aae6d0), +S(89912259,11b9132d,28f5c6bc,763ceab7,d18c3706,e8bd1d7,ed44db75,60788c1e,2574b267,83365364,d84789ca,a64ec905,c969637b,21061ee,9ca3bddc,7170ed3e)}, +{S(5914f66e,28c1a0a3,47f461d8,1d7f2c55,845e35eb,3dc39945,584b5efa,8d71a215,cd2ac885,3f681e4d,884e308e,ed3ca185,b47e2d63,3fdfff6e,efb6dc67,4d7de056), +S(519834c0,d16c807a,7867b8fe,c99dc93c,3b9ed218,87a9ca17,9343729d,3ba9e294,b867d57e,fe2dd7c7,8586303,152f02fd,f67b5648,78a7727a,190d304e,64f97203), +S(959eda70,cbabcb05,fa8fae96,7227b6be,876db942,ae38bfea,a9c3d359,977e1c52,86373396,9338053b,b00d206c,5d67abd,f95d35e6,992ad69d,8d8a3322,7370fdc), +S(a40279c8,48dc042b,a3ee929c,2910e326,eded6051,9d9eb1a4,98fdd7e1,fc88a6bd,f2c962a9,f2950d2c,acbfcf29,35bad39e,2709c0e7,36378968,fa04d957,1dadc4ee), +S(650b8181,edcfe46c,eea03ec9,f8ee5af2,c288e618,7d634961,6c95554e,25957334,ce140ddc,c2e2b07,a57e5627,62da3eb5,ca1acba5,463e97,fff7eae3,55b954c0), +S(eb04688d,5f4c8d2e,4ccd509a,3d003b30,8c5539b2,dd160a45,cbe71efe,36fd9005,37d80690,2062bde0,b96fc8ba,7a7f751f,9461f774,a1d6f3e8,8999c676,a2ae76b), +S(f79206b6,7813cd64,9f946313,3bac4aca,3762975e,954e0ef5,a876b78e,4b5a5d24,6033d4ee,936e956a,af117dca,6086eb1f,6466ab18,d503503d,4b011315,365242d8), +S(539c99d7,728cf662,13e024c0,9f1226f5,ca5d09cf,67bac12d,47814b2b,b1e7d611,87efd14e,e58fbff,5491bf85,aafd48ae,6680f37,e0d928f0,13fb6cec,6f417f76), +S(2308281d,e761f602,66fb8228,45eec88b,e32f8fdd,4a06b8b9,3dfad9c3,75d64a8e,933f4071,e4f2a9ae,95f4a299,f4267098,94b661de,c96443c5,f03f6cb,f3be87ed), +S(a93d05ae,fa31c0c1,54c02f68,9184c1ff,344c670b,e13eb304,2de517f2,1f6124ed,b7549c5,4651fa60,61f4103e,27d316a5,db531e3e,d7396a46,e360341e,f53ed274), +S(35717dcb,4feada90,b039aa79,10cf064a,c8c998b5,fcbb037c,22bf9e92,eba560d8,b6ff9371,d98bf532,f82d7fdb,24fffa69,2afeb0e6,59ba30da,602b3399,2bbe5a5), +S(941d37ef,1671d5f5,675be9d0,d5cb1f0a,ab6dffdd,2bd342c5,c5b62be9,88d5a0aa,4834d5ee,a8f9ae8e,ba5cc8b,2fb52260,33e35767,d55b6aa6,d204e0e1,a38b42ed), +S(c22cecb,aff78c61,f6e34c9d,9367c4f4,1acc9c35,29e9d894,7989a874,1d70bccf,38a37fb0,5fd9036e,762e2f0c,fef8fcbd,c04a92a5,4cb72ee2,ba08213c,4b58f1e1), +S(7863ac2f,1704fd,5015f0ed,30edf5d4,33c5ea2c,e150833b,a15c1db8,a5e4d2f4,7468fa15,eeab5653,c9f982b4,ad9e4c99,2f44083f,a7a93e9a,25ff70e5,b8742b4d), +S(f702cfa6,f0cfd275,a2c7af50,b53d0c94,bb965063,c433f4f2,cfd13d99,800da48d,3da4a4e1,bc5f2c6d,2f8daec4,599a9704,7c1b930a,b37d6b2c,f8a586cd,ef7dce1), +S(c3a1da3c,6e6b8f2c,2a8eb81a,1875f2b9,1e9cd286,414862d6,57626b47,a413d7dd,983d0892,5983d42e,bdbce2d8,df116bc2,f5cf8c87,aeb833da,e5e7e9ca,f9699798), +S(df0a4106,d61fc3c6,b2a14ecf,ebea3dcf,7e38069b,8faac576,a0b8a1b,7c8e7b5e,dd97a06b,840d64db,1798cee4,9334b033,e8d3f4a,79da565d,c6130da,f0bea75b), +S(ee9901fd,9312a21c,879d4e1b,24d5a299,b8200a15,6e65e147,4a2055c8,a2363423,1bb2933c,8b10f8e8,ab93ecee,16f861ff,a86781ea,59b891b7,740fdc2d,f6c206d), +S(52890b99,c8dc48c4,b6b1e4ae,5b823fca,ad9495b9,8217fa4a,b4f8e960,77cdaf9,6ca2ba73,72606e82,9c3395fb,dd2e4b74,8c771231,e86fade,5e2d728f,e5e7391e), +S(a372b545,bf56b58,b7c4628d,aca9bc14,e8bc634d,d79d139d,8eb7a2d4,13465c3e,afde23df,fad41c68,df94abdf,90a642b,31d62f84,c6254c4b,4cad2934,376372f2), +S(89d02f41,f88b1f7c,90b01078,d7599a70,a1eb9c23,1059e856,4237b0a3,2c18010a,7e8e810b,b063d75b,c224f41,a842972d,6fe065c2,aa6b16e5,7bf224fe,e44b2275), +S(7ef367d7,23fedacf,86425861,f67c5ba2,2deaf04,69e31988,7a3a3a12,2f39576a,4b81e743,e00bfbc,1d98cbc2,5c98c516,55e574,fc7fa1f5,86f15d9b,1b5b7ac1), +S(2eec37a1,5fdd1caf,b4c0855f,e86c5534,1a78cdc,b3944798,311b1cf4,7df768ac,1c18cf5c,1a98fe9,70d1e635,ab133668,4e0d964b,4df0b16d,7c51ea01,c9a63), +S(72208b8c,fd9840d,76dfa6e0,f36cf57e,502f285b,422f0ba1,9b119500,6b2ddd11,fa09196e,a89ce6a,888415ec,a8eb92f4,149bb39a,50174a85,8a29bf63,65b4e577), +S(9f46479a,69411d57,c3c7ea6a,dfa833f9,1fb2109a,fd30c790,2ce323ae,4b14be0c,6cd6d7e0,8494cb95,9e67c258,1be426f6,4eee4514,83e9a9a1,278b073d,758487c3), +S(a9aaf56b,5016db58,5b8116dd,cbad1169,4b16de8d,9db5ea5a,279ccf4d,91b1d7a,218fed41,389a4abc,44fb2a83,7016eb50,99c40e86,bb419265,7f57714e,194a5900), +S(5f950f20,b610c06b,76949dab,52fc6149,97d254be,a1330a0,493f1ea2,1d608864,d9098481,823b3ff9,d1c0b7d0,bce90856,186b45ec,6f20da26,9b158283,8a4c96df), +S(ed621f77,98add722,b0dc5e52,9c6fec6b,dff60827,b0b12c85,18d798dc,761f1075,a8973e79,a9caf1fc,e3165145,df08b7db,6b7187a5,28b12712,6c62bb5d,4f0c46d7), +S(15b8390d,652d7338,e18ee091,97e0e176,74f8c4ba,fa2e7b85,8f5badc9,9c89240f,87930df3,710172f7,c5422833,385a6066,4cfc9854,a3e5ccca,d1d06106,1cd90be5), +S(ac2acb9b,21999a70,540708ab,68338266,aef650ee,d81c5b30,da1e87d8,a8a923b7,897bbd7a,ee3e8db2,e36505f2,ec2614c,9f4f2f40,ed2d85b0,5d23edb4,2832db89), +S(17c072d5,6bdd1382,a782481b,8aa4d223,2db79438,5870bcad,c3063330,a5cd5379,26fe420b,d7c25f9b,1883edb8,50e2fcb0,76a65389,d9a452f2,8351fad,4ef72f0a), +S(8d262002,50cebdae,120ef31b,4c80cd5,d4cddc8,eadbcf29,fc696d32,c0ade462,1412c44b,8ea40bc8,2ce090d2,3c11c945,e2b504b1,8d9874c5,271f5745,f0d9b523)}, +{S(ad9144f1,bdcc3673,26d51685,a047ea9c,3c4feb3c,da4b9b83,80e1ada6,300ba487,68003744,ab5b2c8a,cca5bcfd,e1c4262e,88ffbc0f,b0ad4206,2d57dcf8,62c93c47), +S(f3b90a0d,7a8cbf1d,9b994b19,7ce215f9,b8ed861d,d526228,59fe1811,68727bab,95f48e8b,c05a7bf1,e47fdc86,87513ae,5a56472a,44f384f6,1153a954,2db68b81), +S(24af6d7a,99122466,45b07a1d,29b4bb1,a68b5b0e,f9422065,b5bb0050,61d43cdb,f9dc7725,f628cc4e,d4e5554e,f0166b22,566d59e0,4d55c28,a4d0e975,8306c31a), +S(f704aa4c,2bf19c9b,128311c7,1bab5f8a,f2a3865b,728f4838,b8ccc7d7,82574cdf,ae7c46ce,c44d54a7,2e3f758a,e855710,dee6b189,1223d120,9e059620,38d12453), +S(f701adf5,a1bd988d,d7e1fadd,9903c453,e6798760,252579c8,b90cdce2,a046d9a7,db39a987,48aa20d0,5d8b8538,fc4b7d77,95e2810b,160198c7,ad98305,96407c31), +S(bfe36081,c492ed7e,3b91059d,bb1af376,47dca509,69be6665,50f94903,d948ca7c,a1fc9468,2c3dc954,764ee858,822b8c1a,5d0184e0,93f12bbe,21e9931,18911f03), +S(e707057a,297a3d7d,904a615d,ac1b8e81,78f52481,32fa166e,afb621e3,af3f4f34,9161a930,bfd583c0,bfd3b121,acf574a3,6eb534ab,5198aa84,ef38253d,9ca19bc1), +S(27a6c7a7,970a9e3a,7cd42b6b,4478be62,31f53ff8,481791c,4394e78a,968fdddb,e4bf1b16,6bd56269,9e2c341b,b1a51c8a,c2ac7d28,807899e1,3ab1f726,90f44108), +S(e65f799a,8fb3b6c,ad088351,614db5c3,d64660ef,8c977ec1,2bbe58fa,a53314d6,5897f680,253a948e,fc260fa2,8ac39377,4e6a445d,d2bde00e,4e01ff03,b4398e2), +S(8406a84c,e9e63204,761dd406,9651f20d,6fc3efe3,f98951d0,d0a2db9b,cf86e0a4,ef81aeb3,eac17e5,676f4455,b4372ccc,e405b786,f11a871b,d781e54c,6307d1f2), +S(c012cad9,4742fd49,8daaedfe,5b847f34,7a45c792,53c8a645,2192e905,e256c7a1,c4866f98,48f31660,8a81da9f,da112a71,34232f9c,75e388,7ff987b6,8404cd42), +S(73795313,e9de1efe,3d91ae5,15c620c4,4f9c6bb3,a21e3097,c8794710,b2032683,548ce754,93817f22,cb96c674,5d67708d,c7b9b133,c71cba5f,fede1316,c55245f7), +S(352b89f4,78a47e86,b5575fbe,ee1373bc,e93ca316,1f594564,9efaf048,a60bfebe,d784e6cd,88d7862a,d82747d9,b23340cd,b50235c7,65f30be2,ab5d313b,edb0624d), +S(8a0b3d0a,80d41abc,4b8a028c,6c523923,7b040445,525dc345,d2d8a319,c4708316,7b7a427a,f0e1f902,dd1b9bb4,65b6b376,ee68b9a3,f495cffa,c52fcb9c,705443e9), +S(b4bf6756,61462829,53f9a44a,ee3b5427,2485b45,951013a2,8d59346d,62f65894,85d0c26d,2987dbd9,e26c9673,71ca86af,3b8cfb4f,cbf97404,c99ef900,5379a1c6), +S(bff69744,3ac23a6e,574bd1ac,d0fea305,2f05ea65,14814f1c,65e86e9d,5b46a2a5,36961462,5b998565,9324f5f,c8714d9d,57ff314b,5d5c2cc6,99a4ab39,69add4f4), +S(ecb09f5d,122adf91,e68e98ea,d39e5790,27e7c4ca,405bcaf2,e086d4a3,e68242ed,aa214cca,8a601fa0,a92633cd,a353ca02,7a7dee71,cf335af8,fc75de56,a3405f60), +S(310d957f,10fb34ef,ca3a2a0b,35c901f5,35c0862c,68310134,10982d7d,e74af8ae,289cda3f,29a489a8,86121f4b,4e75a90d,2bc4ff20,e95aa103,4044ea80,cff56378), +S(3a5f1ad7,c59ee6cf,e090f210,7040b419,4ca15fa7,dc8e9f69,20825fc4,e012ac2e,8ac8986b,48d7bd1f,5ae99535,2505b0ad,78f855e,d8411b03,15725571,dc99c920), +S(725f136d,1b426894,c24f8782,43fdc1d3,79636a23,d682f389,dbaf71de,d4672067,db0ffaac,ec5ffadd,f32396be,3f01fe2f,45bb0cbe,eb0d98bc,2390f3ca,c3dfec84), +S(b28e523e,6fc68192,445180d9,5da3e411,2fe0db1a,5b3bd5e8,e00a1090,39c69d53,7c172a4b,31339fb3,47db74a6,beedf59d,c24e6aea,c71e2a0c,434714b4,d61a2f70), +S(b808db0c,e34b5607,8166b308,1dd4b2ca,cf9d2d51,3079648f,fc3c617b,8e45ba09,d69c4ab2,fc7e490f,6887f2c2,49e0b71a,746e3e2b,97a7415f,34475bd6,f6dee79), +S(5e0b091f,3144d7bd,c7e40dbc,98c716cf,d7e64eda,ee9c1fa4,6838bcd9,e0c6878f,1586cf7c,da66b005,8b2d0d49,f588d444,65eecf42,1d94c004,a078dbd,47e0bd20), +S(1c3e88b3,ba46410d,8e08f9fd,5db8b53f,8dff33c6,4f5314f5,e005442d,10cef1f8,ba365020,5f85aa9f,71a42c0,392345b7,4a17a5ab,9ff91109,4d81252c,d8c8f72f), +S(b4926018,fb0e9c,e80c5614,37c3f22c,cc223412,384321e3,6f408e4c,ec0d81ac,55544f6e,cea3575d,e81649b8,4950f225,8a94e78f,13325ffb,16debe1a,8387173d), +S(f4bfac1c,b0834e1a,e332b7b7,1ab84500,b1c8460d,c8c2efad,6a5efbb8,ae78cd1d,5faab691,59ce9d3f,6bdb1818,676684b1,cc2309af,1401b5d5,137e1c61,5fbe287), +S(220ed3d1,fe028d87,b96e8ad9,37ede03e,ed8f262,ce877c0a,42718ab9,cb2ddfb6,5ee2d60d,f96a1b8b,e11c9139,7abf9b4f,a0671966,34bf37a2,8d26864,31933fb6), +S(dca5fad2,d045526,b6a4c309,de1d95b5,23f9a7db,e669b558,edd75ca9,40c85878,f350337e,877c9c61,98fc912b,5d53876c,78ea94cb,bbf3744b,62a52fa5,f5ae4399), +S(486ba509,3272eb1d,16ece443,861eae7b,2d8604f3,37014bc5,11267485,9872642,688d4585,9fa732c4,f582d65c,45930567,8c27dc6e,5525d47c,3908daff,f0a534fe), +S(96bc1bd3,b4840354,14aa92eb,6db81f5,403e2858,c0552d5a,6b21d33e,c468f31a,83027873,f4066b5e,ba6f413d,6a7d4d18,d57f4a62,25cc9289,b514f153,91ede3b9), +S(9f131ffa,b53e20b4,e9cd9e33,793f4614,922c03df,7d11222c,7fffec33,42fddec6,c4deffeb,3f4cd90b,102cb6b,3f713728,2c5cdcab,bc6e7153,91ea890d,76207bdd), +S(c15c8c23,d90c8e35,c1a214dd,e2d4383c,735ae45,bef61f10,aa1a1c25,5984cf74,d456ab27,d7adddca,372390ba,1da02845,b84088d2,af4fea5d,3b5b7326,c6334c2f)}, +{S(e24b71ae,8fdea24b,2d42a2c6,5cb022a8,2aa9e03a,3067a889,e778caf8,34903fa,f87d5757,cae83263,1233b840,296d6066,52cd1ddc,e8334629,25c992db,7e0ee14a), +S(886a7626,6203c559,807acbf6,7e1631ae,1f6bcacf,3fde277b,ddcd795b,292c38f6,b1f590a1,52d3ecc3,2b699c23,a89b2601,de78be2d,fa11b20a,1ef1235d,93ed9e99), +S(3079f709,3d5270f2,95fee75e,a6c5cd3a,5638ee37,aef535b6,523604d2,eed0d57e,492dd2cf,d76705d7,42187f38,f38982d1,85efa30a,fd1639cb,984a8772,3e912a91), +S(7773469e,c557e3e9,4097bd55,33a87583,a79e3eb4,2e421cd6,592363c2,76641966,f827b0dd,46f4b5fb,4a656731,d827cf21,df1ec610,f36dc2d1,215f33fa,20a08020), +S(ebeec367,eb032a6f,7c421ae6,f8fb56f9,3fcdaa68,f6741e46,1992d019,7567336d,6e78af43,e10c742c,35467149,3323f8c4,a6cff91e,7b1f1c2c,65b21fa1,e63f3a6f), +S(b41658a,3683b512,c751d817,f5d92f8e,5d158632,1f2eb836,b446aebf,d276030,9396ba60,ca61b35e,4e52e879,a457ce5b,fee9121a,b2673c19,15e78236,483e069a), +S(2e2ed965,a926700a,1428af7b,68b7dbf7,61d1bf53,6eb9f75e,d56afa0b,63852cd6,8d77656e,d5f11224,3a94e462,3dcfbbdc,61749930,dfcca6cd,c4303cc4,617e9133), +S(4b54bd22,e5604384,9ff2268e,88c695d6,4766e0c8,4f598f5b,634e1dac,d03063ba,176c68e4,a1f25683,37c14fee,dcf9a64b,17cba4f7,283428c,1514990c,98d29d71), +S(b6cf7c38,2d4c63cf,78557116,55b5de99,1fd32da6,8b8d2dd4,cfcd6f5c,59c45251,c4c190ac,2870142f,2a13d7bd,5d6768b8,fb5ccdfa,b99d0e3f,6bda805f,7741ff52), +S(857b6db4,79177eca,82a6c801,bd763647,c1a49021,e5b4f405,ad02e6ec,7ccc3629,586cde8e,cbf7907f,704a6610,f7a8a910,16599e9a,93bc6a6b,1b70d59e,39c0db4b), +S(a18a23b7,6643d92a,9e1bd2c7,7bfee61d,c5171b33,12f64d7f,821fbe05,6a771ee2,321f460b,b9525303,c159fe3a,6762dd97,60432307,919a2f1d,6120c946,47cd8568), +S(19b91028,cc2e5434,b162cee8,c77351d9,d38d9eb6,8ff9b09b,f26cb25f,4b88510e,cbcf2e52,3335ee5c,56ee2a06,7c565627,a5c60f16,808ea8e9,94250c15,e427c883), +S(657e2f30,b1e0241,82c0e57d,996cccf4,7bdf8eec,5a4da875,1638b3f4,9bcdbd2e,8e0a3117,12da36b2,2d0cd048,a9a99b26,5faadec2,14162083,5210f1bc,bb79fe3), +S(576879e4,f4a8e697,45014bee,36ba4267,cf72038a,f5997d38,cf512f08,f0ccf6b0,3f313f,388c011c,18ba0938,51b0e7e,84627277,2e9da999,b839b58,92ede5c0), +S(ed72d681,6516c2f2,7a9e97c7,1a7c99f2,faeb8e31,a5f29260,faa0bbf8,6475117f,331fb25b,e71c24fe,f4d2133b,f1591f3f,e5f8830b,15615134,36fc47fc,522ad4b), +S(e4ed422d,9152f00b,96bce64b,bc3ddaee,6089e1a4,1ffbb58a,109c688e,ba44699f,6dae6420,2dc6cec2,e4a49203,6b16c9f5,9c517436,bf3b9d9b,7e8f458f,7fcba8e9), +S(fc3b8afc,fe39404c,29622db5,b06c989a,8d7a0c4d,85018796,d006bd5e,43dec087,7b77feef,2211c1a5,724af5e9,a841e09c,d7940bc5,43d70c7e,51676689,7682ef15), +S(9c2421ee,e2e7e66b,decbd152,a8839f1e,4cf03808,649399bd,ba55cfbd,9dda6360,8d9477c1,c66a532b,967895ae,66c7585e,608e9653,4f870bd2,c97d7398,74a84700), +S(22040517,334bb5cd,2252d1b9,8a9da91f,a0bd32b5,562c8218,4d991e01,d94e8f13,167d3dd5,738a467e,f8e03064,d6482c2d,64503892,b4f5b9d3,c4b04684,fe2f15c0), +S(b648a617,3c728243,f3c0c7ec,2aadcb13,dfab92fd,77da9aca,1602d47a,80022dd4,7199a3cf,89c596e0,d607d05e,de95c8db,ad763ac0,76fa7ee8,ba7ae6e1,4c14308a), +S(a7d7ab3,6722b9d7,940b2a15,c94bb9fb,41a139d4,26215286,bfff84ec,57386dae,25ea853a,c3e772b6,f400d850,a7cf5760,ed568add,a145ea75,6f20b77a,c32d9f28), +S(9787a21d,ea3dab74,366214b4,933a702c,7a07c4ab,696eddb7,3a84cb5f,80f2ba41,8663b959,2214a018,e373e360,a9e035be,f68d9e01,f6fff1ab,f8ad9b8d,3f6f324), +S(1d2ebbd0,65bd4f50,8dd697db,9c8bafff,b548edef,856fa4e,39f893cd,349ff205,85d0716b,109ab208,a96367e3,bd0a2314,ad2c8586,169096ef,9521d780,61df01a4), +S(d0a506ce,14e88414,46c08a61,98ea0aaf,75b9dfc2,c4d2cc58,1238a597,154981b4,dc8c863c,7c4611a1,85744975,34c8c02d,7cb7504b,dffa91f5,96765a25,98d1f506), +S(b6c4d103,a57d0af,27e93627,f55a34b7,75b2ef48,47d7612a,5fac0748,b41afee9,dc9440a1,596cbfd9,ff87fade,8b426091,4799dad1,ce0f7b60,d032e94b,bbaf53f9), +S(5b5d965c,f2f37462,86f088e8,b58887ab,2182f874,484686dd,43a245e3,dcbc55c7,6718ba28,cf43ba30,eeba6e49,a7234ec8,7f01762,e915ff12,41fb461b,6d87a875), +S(bc85aec9,55e6e99a,c5fa7738,c7972354,57b3935b,bb69e8e1,ddc69d01,d34a47f5,59dd49e8,cb3100a0,9c48ceaa,20cbde82,5072e13a,7af0a44e,601044a,361dd971), +S(66b7ffeb,a34d8cbc,e00b4d1b,a0558741,5123d8b2,89ebdba0,47587d66,b260bc99,43bafb96,c88a5917,c6333dd9,b4a546b5,1c37ab48,3f3873a3,6932ab97,efd79712), +S(3cf9208a,b230b73d,68470411,bf3d4899,e0f19675,f829e32f,cd148d,3c07d7c8,21fc39b3,ea5079a2,ae131935,9a3e98df,62b97b37,2a473a63,f3b56e24,25b30e27), +S(66e3fcef,b7b24cf7,af0f8de2,8e53c2df,2bd1dfb2,c0289b10,31239da0,948e129e,df4074b0,488f3f09,a674a40c,b3207f34,a0282661,2e5ac4ae,8d443c9e,d1184045), +S(28df781d,4ec05680,590f4658,713c8a91,fef23763,87ddb6dd,674a35c8,b0e74459,eb66159,95ecf0e8,34f24e87,6f0dd86b,5c86a45a,fe5190f5,721f833e,10a196c0), +S(85d8da47,48ad1a73,dec8409b,e84f1a13,16e65c51,96aad27e,766746f,3d477c2d,a76b74ac,99a3996f,a794ac9a,ce103843,6b4f5fdf,cc3b2a59,df867e8f,382e1ebf)}, +{S(39ca1e6b,9fd848fb,ac24c444,5a9f398b,8639fa6f,c0c2f2b0,8058d84e,6c0caf1a,8797227c,f956ba7e,5228a452,91cdd51f,8958ab7f,43f6c8b5,e06176b0,dc9048e4), +S(4c87e538,c9eac9ba,d5a2a81e,43a6f1e5,f8403c01,68ad5020,4adef77d,5e3aecde,6ee8b74d,dd0b9bb7,c8b7ed7a,728dd99d,a9fab941,f0132d0e,998e65b9,ffbcb9a), +S(1226617,9f5dabe4,6d963b7,e96247e1,e29f2440,f831c8be,578d628a,78561987,2d3552bf,ddb5ec6e,a7758830,9badce7b,41d71926,857962d3,c3bb28cd,5d68ce7f), +S(866c0a90,893b6b3d,807a96fe,3c67b928,67c1d95,e05146fb,40038476,26981201,8d8f3188,da86e510,b7a7642a,97778201,3926dae6,4ce80663,335bc448,d204413d), +S(8eeb2e94,9a66824,26a6f474,9e7578d3,1b356aa8,d1b42049,5fb83e5f,5d08f723,e439d710,c45063c6,d23aad9e,ac0cae8e,36552ab,ca6f2c02,6eeb03ff,6162a052), +S(ffc93fcd,85fd9502,78369b3d,291f1ffd,5da44964,888d5eba,3c3f60c,95082bfa,9aa66635,a4b0defc,b2514e97,515aa0ec,3f65ce8,6f6962f7,72eaca41,d5ea7983), +S(605ccd66,4f18c83d,edf36f62,e5089f14,4ed23f4,f88635fa,ab161567,fd20c8d5,cfccf020,363a805c,1d614aa5,b9a912ec,99cfea61,5c088789,275ef531,dddf2418), +S(d1e4f37e,7d3902aa,dfdd7254,fc727a44,98eb9303,a12fe71b,4d193be4,8dba6913,bdd29d53,4881cbc6,c2e301fb,7d757bc9,9224f12f,4296e834,9badb88f,84fcc289), +S(f30b6d53,f330e6b6,b23d21df,7b4350a0,c42ad202,4a92751a,5dfed94c,47bbe60f,b5ca6c03,b31d06cb,183b0b18,4432a06d,8143d511,8af4bc01,c364f024,b46e0c38), +S(540944cd,42101851,c2cdb0ad,61264e18,cbf948cf,2090df68,54482628,74271ecf,cd16820b,4ccf9131,476b8778,ba3e83,f5970507,7110686c,653be572,2e99db3f), +S(846e5478,5d9cad5b,5109c7e4,6fd62b04,f686c723,1fc3c0af,66bea20a,d9d60dd0,4b1a28c1,78bd097f,aeee951f,fd4f46a9,4658a76c,268ee7b7,9aea4bcd,e75fc8ff), +S(16e732f4,43b4c616,24a495d5,4497a23c,c95612d0,58df9f81,11d1340c,4b2b8b5f,61ee476f,30ac2be7,e3ff09f3,ebf0b3e,2d76177a,30573465,101f4cc4,ec0585be), +S(4f30ef37,2c730ba,a6a40ff1,94b6b58f,436111d6,848b4e60,10be9b9f,abef17b7,b579a133,7f3247f2,8c6afc05,644778f2,3668e73a,a7c6d14b,649bf948,ef126142), +S(595a0d2f,1668c0b4,9ba0994f,3b681c42,6e3a67be,e957bf52,47acd9c4,7cb7d009,fb10684b,3ef1b0ee,37684ba7,53858b3,3586b837,aba6d82a,958eb947,2eca319e), +S(85dfb59e,d7ef6e0e,355e0ce1,304fe5dc,8bc6a3ad,74de3352,2089f224,8894e0c4,7a9b9ad1,10099903,d0d84a33,6838d422,5f98abde,32d82ab1,a383969c,1fb98bb2), +S(c8e13980,cf58416d,8719bc94,96e21774,c29f2e1c,5a36e760,2ce7783e,2c810fd5,5bdcded7,bb484d46,48bc40e3,ee6a3761,cf995e36,2af21f0,10048a91,6fbd4717), +S(80b98fb8,e48f44e,db69fd8b,18eec95,2404fb59,45c8a35c,bf3616e8,c746aecd,d44010a7,20622d14,6af5319e,155fe4ff,591bb829,f5086c7b,1fc1ed6a,32ccbaa5), +S(17629b1,cf015e58,eccdc7a,de049215,fca806e7,805e0e35,951df2ed,5cb87d38,afd56698,44f6aefb,528dcea4,29438e0c,d10c4b21,23f02444,a950834,97a61f17), +S(592677f8,695479dc,b215af2d,bbc90621,e7f3cba8,650563fe,1b2a8765,6c44107b,3741e4e1,b39b0e2a,58373166,854a1d31,ed062a25,c4e3e1fe,bc82e941,eeaaf50d), +S(98d5f85a,a93c9d87,e34e3bb3,597d9380,f0a7e5c5,b03ec219,4025c89e,42126453,dbe42a83,66753aec,61f7f01d,e5dfde1e,b4b989cf,95bd36bc,a66ddc0e,ffeea196), +S(9187b546,70d2b9a6,b711c88d,353bee60,72a1f5d9,ce75288d,4e6c9111,80dd4126,80e73529,d211ea24,d4bccff2,b9de3e31,c6307ee2,3cd9267e,b2d372ef,78f8d2c0), +S(e38c81ad,8ddfd8ca,4e01f380,78eafecb,f8edba6,8e33e565,309a3ad9,f0abe0eb,9f0ace1,f05f0a85,a1488644,88cce81a,2cf55eb3,a91fc10a,e6b82f47,60dbe618), +S(7ee9955f,99e218e7,dadfed94,dad7054e,3e0b97ba,932338db,69ed056b,6f8adf55,5244e198,524a105e,2b5de11,81d7bfe9,ad56aa0,128a3d87,8cbcc5c0,25b41ca), +S(eb9e5ae8,cdf64b28,76349aab,c3f75c9c,9d95a335,3214d0cd,d43123c,265b08d,858611ee,f67a32b9,7b8a9090,6639e998,a05d9bbf,8ccb7c1b,9e5eb711,4216b877), +S(2aa74ebd,7e8b6b2d,952effaf,e5545eb9,e99b9678,a2515698,975247ac,c83ff081,1ec12cbe,6877aafc,f353f641,1a5edf9f,e4bcc09f,31422df,d076932d,8f0defbf), +S(1b7b8fee,a3ed4af1,cf9b07fe,b435ef76,1d081b1d,f1007697,f78fe5d9,89076aec,b4aa0d8a,efbc71d9,d338e998,197054f0,20c5a2df,7a9504b1,ca7cb603,6641f85d), +S(3f293b75,9f152a4c,b92e319d,e5d02b82,f5dcfbc,2ee7a53d,fdf7ef6c,e2595c32,b67babb8,d1d1963,fd742c22,5ad5bbe4,27e57d6e,b9e17bbb,f91d2c1e,a455c1d0), +S(3eb9968a,c9b01fd0,882ec65a,8f9f5a5a,b0fbec2d,e2dcbf88,cc9a70b7,887ca59a,1a4de130,4a46fcc7,6719c254,dad5e88e,9d6a0839,9a9a28ac,7f171aa5,9624ee2d), +S(a559381a,f41b944f,e2bab9d9,62ec7c53,efb25ce4,1ff1a456,54a99f46,d97ce20c,ebc6f66f,75ad7322,4c1319c6,4268c997,4142,11ca65b4,58c5f79a,be0ba0cd), +S(a8bc942f,c60ff2e1,140f9a97,3d7e0b8b,77698254,57098005,f9186e97,9e430593,2a82070f,25480267,c4fca773,3173b354,fcd5cc1b,ae497af8,58b7d451,8f048c73), +S(2f456ca2,c4f8806b,ce4caf12,32446b07,3405dcab,7b3cdcc0,247dd079,adc7a626,7308e58,5b9bafab,b2dee049,9bbf60ac,fdb37242,3e915156,15314ffe,5ad866fd), +S(b56f4e9f,9e4fd1fc,7d8edde0,98f935f8,4c750d70,5f0c132b,d8c465b6,6a540f17,cd171acb,d63357a9,2c23ee52,fa7d2e2,de2bd69c,343357ab,b95d0350,fdffec02)}, +{S(ec474055,43c52e68,5c9e6c75,97616fbe,edb70df4,fe3c375d,d7d24729,2b120851,22c1c1a7,30066375,5ef8c2fc,86452667,90347223,f11a32d7,9f1c0169,a467530c), +S(3f50e502,c45fd922,94fcc46c,b3118a86,43af00d1,634bd694,dfc0eeb8,be2dd4d5,7cb992e0,f29fbc5f,2887161e,6d1e266d,f11fb723,3b6c020f,26eee393,fe96b526), +S(443007f2,43c3f6f9,76914031,c41e0d49,61337340,9bd4a681,f20e4c79,934fc2de,df67adec,c9ce5f6a,e6c8312,699e0353,68ee87e3,1e96790f,f0bd3408,94af74e2), +S(1e15b9e9,c28f77df,75837a0,cc9504ab,a3a49aef,26a88d99,543fa7d2,a875620b,2a081093,6afbc025,3808ba31,f5597287,e32898ac,77fd0021,9e6fc298,26b0370c), +S(cfff0258,ff6c0d97,99823447,775b75b9,1881e06e,bbd72ba4,28f8248c,5cf2144e,61e63569,5c4a8fb4,f68f974,219bbf4e,e0c277dd,4b74b843,88f99041,f97809e8), +S(2824f4b,f72f9229,2aa04058,7a0c5395,4c87e7dd,bc5dd199,af6918e,6db62f1e,16ab1473,3bf8382c,521af6fd,27f8b2b3,b421dbdd,bcf06c62,3bcd86b6,4bf33274), +S(5dc7571e,27d6b955,6c789b4a,80d49fd3,17416fa4,e04a7eb2,3cdbb88c,9c253a44,b7261e2e,39327d68,a5456abc,9d4600c7,fb6d6e51,a732c7f6,c64cbd0d,56de4a17), +S(e93f3aaa,5d9edc53,6029d332,9ac0bffe,af27d4dd,40f550e5,3df879a2,a5c1d993,25b442d7,f2e2e03e,c7f1588,16a1af43,b5d2870f,e0cdf429,babb19e8,951c0982), +S(8f91f5a5,7aa40d62,ba407d8,6ea5678b,65c84ea8,f241e2aa,dd6df242,52635a86,e9333d7b,d6c319be,3ff4f5b6,f286a8eb,27d5a1bd,29646cdf,77441c40,f716a6f0), +S(77d398e0,228add30,e9e120ea,b16436be,30c254ae,65016672,8bea1198,de1fb17f,749a20c8,ad6f4312,fb6e6fa,c390a4a8,209704be,3355362f,31db9b45,f3876963), +S(96976a85,b6dfc4b6,13dde357,c21c3518,a5f55c7b,a2d22976,592d7632,3b5a8546,96dc660f,8ef3b0b6,adbe77b5,69024fb5,dd713566,617cfc51,c8013f2,5b424e9a), +S(49093c4d,26194278,623c2ff9,6c8e2f11,f9edf3b,13c33099,57b57f1,9db451c6,5d53ff56,50b82edc,9dee9f43,ed6db93b,f6a26233,2dbcd699,130aa9ce,5130384f), +S(49187f03,d5f5f628,b9210b88,8ac4f1b5,2f754015,541e9f38,162e969d,6a99f4f8,276aacaf,d38d0bbb,416bcd0b,8ea590d9,7735a3f2,8de72aaa,76bed0d,6644bd80), +S(7d64e446,65c03917,87fe0b14,16ab1048,3a6025af,b20e8c19,3bbba444,2864c587,2c0da181,6507f8b6,4c9e5684,a4d53d98,d6b88215,772def9f,fa5a7a1b,f2b2ccee), +S(2223484b,9ee12b26,2a21a18d,2682ab01,c291ee1c,fe3b4b9e,2e93fb67,aa08535d,4cd26418,bf0d62fd,b266a768,5f7aaffe,d7bc95e1,be41c6bc,7a0c9076,1ace3974), +S(aac92330,7d6a55d8,552ce6f3,9c531d5e,afdd5313,f801242c,21df07b3,a656c618,93d9be6c,590901a9,1413cc23,94cb426e,e6a61593,93511c,e67e1ffe,68b8f3c4), +S(6ec1a0c7,fe40c40a,f3515ff6,60f0b53b,8fb6be3d,d912f8b2,c7a473d2,3e49d201,b10f000c,191e9423,60fe6b5b,2b6b7b85,73c0c2ee,384dedd6,e3dc04a9,7834f93b), +S(bd982a5d,a4d0291c,38568fae,ebc76df3,f2b0e5b9,1cd0d3b6,d2f32077,6c35c43,48566068,d5142f6a,90b13105,e7841d32,38d869d4,fcc7319,3e3cc9ea,76739c5b), +S(25d54513,b9084ddc,a3f20e18,94382290,115ad5f2,dc72c267,ba845b3c,6ade39f9,e908508,7fc5efab,a6f62c41,ea8fe856,226c8e2f,95dc31fd,2b49a7c3,6aa53b39), +S(29ab6cd5,add595d0,cb64ead9,c3d275a6,ce383f15,9340faf5,118ec2d2,9bb9a62d,54584613,dc27c249,d5d1210e,9e121aa4,7d606fad,1c4621e1,67f67b90,d8f3434c), +S(4cfd960,86f86d5,bd805667,55979c32,d5419dbc,946d63a3,40dcc6f,6d6dcd48,f032b7b5,9d85d0a9,fdc290bd,a1fc703,55b5404c,f70d45c,d15fa9e1,33ee9319), +S(9c786066,b6642e11,139aa303,800314b0,6afd4d97,e8314a1,de9d7002,5b7bbbf4,463a2ded,e2185c8d,944f29f0,140f6b66,9ad6e3aa,8ab6e292,a2af551e,685e58ca), +S(4e98485,f15c506d,6cd29d7c,3f9a59ea,4bfab065,78d86b63,f25e74e3,e7aea96,2baf3fb1,c26f2b0b,1a0725b1,5d1ceeaa,7ccece9,a1dd8f2,7f80d825,d8cf1d71), +S(8412c389,bc88e9bc,b157d835,85af0dfd,48689532,e38044b9,117b8acd,ce3b62cb,17eaa404,ffc1f62a,38f7ce99,6216b1f,40bb62e9,6d1f7a5,8bca370,c0d30b44), +S(31b9b8dd,7d37b38e,892e94c7,a5e817c8,ffaa1c1c,f56979ff,7f25815b,758b6d09,cdb680a,ae795ef1,f94e7e87,50ad9077,7a55eec6,c6f0795a,ef951e3c,ab45d186), +S(2be45d05,e89c58b1,8212890b,b6eaf935,6f03e37a,fd957291,4ab71a97,7af8350d,c3b05f04,c9f7a1db,b6689fe0,6ecf7a80,3ecaa147,8d09a1ec,9a7d71dd,a75406da), +S(5185cfa5,fe6302c,b5573594,61f375dd,c483a66b,c615b5f9,30abbd4a,5c7ae0c,83cc447e,53c91e07,6f44d265,389bef06,549b8d78,9776000b,5c35ce36,5fcff98d), +S(cd42328d,e4a16323,c51ef888,b7e67ba,f9ee1c53,82161b90,65e1db15,bddcffd9,caed06b1,7e86b470,b665de93,74725fdc,94792c57,5509ebfd,f012133e,122302f3), +S(7a1ffea,8fe5114b,8a638306,3b7811c3,25a40c19,42451557,679e75e2,b304ab91,1ef3fbde,4f0283ab,96efbc83,bcbb5a6a,d781a215,e6ff6262,ca50b9c3,986816db), +S(cf0bdf47,a3f15b24,5c7136c2,3a3e38f2,661fa8a9,4df29fbd,8b41ef22,c291dc6e,c73d1fe3,919e0aee,5b3adc4b,1a86e709,4b039302,d44a0d56,638c3eba,24857a99), +S(3a571630,935c1f02,d6fd8744,2c082060,cd5e792a,1c6f92bd,c4eed01,686df50d,7a1ec78c,4a660cd0,ae90c00d,1a8f5f22,1f5507e1,4487e5ee,2dea74d6,17a69494), +S(1c5e5481,32b49a7f,66ae9fed,8323480e,d1ab974,622e7cf0,8993895e,ec87fac,b00309f0,7c80b970,d446a605,e2b3d52c,5c215314,d901cdb3,aaa284c1,a03d2740)}, +{S(2b081f0,268d6ff4,1090561d,79144bb9,554b1f3f,1f0f2cfb,c9344e2,b692157a,597920fb,c528543c,26499af1,8b5e7d7b,5ebf5ada,5df4a46c,edef52f2,1e2fda5e), +S(2ce45dc7,d84d3143,884d6696,73738e55,e30f6045,8bac95cc,c30e86f8,71779827,deb79108,80a1b675,a628fb09,725c9307,d1629b07,8027f566,29f8560c,2ea80458), +S(9dfa0cb6,2a63244a,35ce3a0c,f102e7c7,93a4530e,21c6c03f,15a4fb91,e116c480,b01c1aff,902f0831,bc8cd268,663f0ce3,6d8e22be,86026460,a8950636,ce44626b), +S(61a32d1d,cbd7e887,def51ffc,9c1dfd55,d06d72f6,a73ee2df,f83cfa0f,52d47bb4,69a3b17c,fa91e3d6,faf28d83,2695aa66,c87b14ee,7b2d987c,80242fc,ce2cc42e), +S(8cbbac63,5414c0ac,b6d7f659,5c6eca39,886c3ceb,82549f72,d07a4019,e3076eb8,c838dc49,fd5af1b5,e503a430,71901bcc,90e1ea38,9f735e31,236491ec,43e7b621), +S(d3f77c5f,663c6efa,670b46bf,dfa96af4,fc4720d8,e1df6e8c,1ffc5696,f37cb55,aeea0c3e,50eee6a9,16462a13,90ce5d47,c060efff,1fd3108,1db77513,34300332), +S(6f774118,4a0210a0,79695d20,f93f861b,658137c,3a072076,7d80e5fb,8b1ebdff,c12aecc9,b55bff04,bd6b6e73,870deadc,666973b8,ec498bfd,bcc4c33d,23f5d674), +S(fecfabd4,897a948e,5fab7200,969f9955,9eb1c9dd,2a31325f,34dc4f80,13da72c9,ba70c9bc,c8048aee,6fdaf5f1,8ef638ba,ce739c0c,76ec4c13,fd4dd6c1,1663d02d), +S(d1a1a1d4,24fb5ab1,3e985c86,9bd7c02f,f81b4633,dcd22e96,c3f33489,2e80d543,cd5b79ae,af62769f,dce99530,8b921b5e,39a60fd6,f989dd7e,1d0d7219,e9ee8865), +S(7099682a,c3c083a8,80467746,fb924d4a,56f23d16,a3b57f10,1a824b9e,653d45,6a9c296b,cdd72c93,df840003,24ce78b9,1f9df6b2,bfa33922,ef32733,fe49cb31), +S(1035866a,4e9ff0fe,6b0066c6,3f0a2392,c0b8cd61,36e13ada,21f6dae9,f22c39eb,6390f9ae,ec1989de,2146cd00,a5eee99e,76ea4536,423e9bf2,c778ff29,85538fa8), +S(e18351cf,163e4df7,d31851c0,409b5705,a5ffd472,dbda5dd3,bf05e66b,fae50fec,264c1d26,41f185e2,72b908d4,77222484,c651e8e1,9a9e1fb0,1ec5ed4a,8a4b6c08), +S(dfbee778,ae4bc89,24f32c18,bc0a740f,d01922b1,28e1a595,283bfb4a,fd8f2f76,d11f9b3c,25ae3619,99ec2c9c,2f1a5903,d80eae59,e096c5d,c5e37201,81756acb), +S(842cdb54,414fa977,58ae3fb1,9316ef32,af9c4f0d,649f0abd,cb94267a,124b59fe,a016f899,288f4caf,dcc6edcc,3cbcb561,fdb4047a,f789e1a8,51ad21b3,be62f5c8), +S(3deb5d22,a81540ef,cff29ac5,585a056a,204e4d67,2fb858f3,5c23e939,790c744f,20d73911,5b24b1a0,a4b31302,73321dc5,d8b74398,d6516439,4e1423f8,b4022d6f), +S(3108e61a,1e0f079,f76e3ab0,d69cf068,779674e6,49768aab,718a09b0,640251bc,245a9f2d,141f390c,f1a17bcc,a06c5a66,5cf3a87c,1096f5e9,b04c4fd6,737d9a56), +S(63b9eaa,ce6b32cb,e4cf4a69,6599f8fb,3797bff5,9103ba0,c1351e78,b16cb0fa,938ac414,ef911df6,bda32b5f,1f69cd7a,87a25d82,177763de,568ca95,e846fa5a), +S(f37a5a41,cc96a04c,c882c27e,e362d054,7d6267f1,c91c5403,2daa5c12,1700abda,108bd6ad,27aa72de,48406693,758a74df,53a3ff98,d490e303,54c45ffa,c64638bc), +S(52afb7fd,6a16dc6b,98f9d7d9,555068d2,c2317035,b7492e8a,fbf28aea,3b1fcaf3,548d8ca1,2cf7a11a,b0100455,c7240290,6cb2e92b,101d1e2e,32ab263a,3f3de413), +S(f644fce7,874e9154,8f3fb284,b7d1ba17,fad6eb6e,c581f57d,5aa11804,86de9889,b2acbd8f,5bed4270,ec131ea,1891c99d,ddb46648,60acaf39,d68d2a54,a58b92bc), +S(863cdfdc,66065a4,50c2b7c3,1d694c58,e63ccc09,fccfacdb,4fdf0b1a,b150e937,14d168dc,c84d859b,55a3d5af,9d17ce4e,83bd90ed,55e099f2,50932dad,b5d2693a), +S(9f5569e0,50a26288,5d91f82e,9cacdf9e,f4487676,730f4da1,46ce8769,3d8807ba,cba008af,547e01f,6a9c6c45,8f9d71e1,8ad062c4,4b305b52,3f3a6655,3979a2b9), +S(a0f14b6b,99f0bd74,cf9864bb,17b1c43d,51ade513,6cd72a15,89312dee,706d50c1,e2bd2d82,c549b4da,cebfb888,c1a7c5d2,f0757fe8,53e07fb4,747eb7a1,542137cc), +S(9e7bd727,fbab45a9,db36d17d,5e5437eb,f028a10b,392ea470,d5cff0d3,2e9bb0fc,fb52eb32,e43133db,28125280,e3cc55a6,76877c58,b4051f70,9c031f84,24f12d9f), +S(7d8b1a30,4c0c8931,2d5d712d,ab396efc,7a117483,7f62bb38,62a81a3,660b1068,472a2dbf,ee99c398,94d14c1e,ce87cf17,c8aee10a,4720357c,c5ce79a6,19aafe2b), +S(d5eb073c,a5afa126,70602de8,417fe50d,bd8f0768,d615ef2f,565e421b,4e7842f9,52571e4c,e4f0c424,fd288f3e,8b6c54b7,7481c3a,43230fc7,4c6f48b,d4041089), +S(3c41cd8a,77728b07,ea592254,5ac45462,2c7927fb,6a7aeefd,61635cc4,217acc90,eab0f00e,84099fcc,c2f4d339,77ff7d68,4c035b3f,34c6c4e6,aa812c9f,43af366c), +S(1eeeca5e,cadfae31,188218ae,7beda45,57f85c25,5c99dd64,1d00d8ce,2e6f7809,d7e5c2ff,4ddf421f,cf09b655,113b8cf1,a4c25e90,d02b871,91dbac55,d6606ef1), +S(54c13737,454414e1,76bfaf1e,b4402bf8,678daab1,555412d0,c6d3fd44,653510ae,753f6a,f382d0be,f1dab47c,1b9368f9,57d586c4,acef0d19,dc241ce,f008ea3a), +S(4d608c37,1fd6f635,9ffc57c1,9f1aa5b3,5b0f5702,55851cec,34278d2f,465fc8f4,12d1592d,c2cbccc3,7e5c9fae,4b864e9a,ca6967e,9d4852e,9adc9e31,1000670f), +S(71157d64,8c0a1a33,19b713af,f806cf9b,c91a446e,2ba48ca2,fdd1ed4e,8c43da59,c2ac2aeb,a298fcfa,c0d5eefc,6eae54ec,330f5c0,5b34952a,9821ded3,9b72d383), +S(327f876c,93652555,fa80a054,968b4712,930dc930,12ee6b8d,c10263ed,3b89a762,4d2bfb15,4cadbfd9,4f6696da,a1e66846,8aacaf8f,1428201,636026a5,46dfc92e)}, +{S(4d3b98d0,b5926a8b,3e5622d6,10b30e88,caa6e7ba,eb10bc3c,38aec3c9,c1267578,e84056d8,4726291d,e6880a2f,2d3b0b01,371dfa27,5b8c9cff,4805d18e,a5bdc788), +S(6e463689,111d1a5d,d10b09e1,5d0f438b,1cebdb67,7a6cd230,bf6349c3,70667db9,de10eb3f,5d2f4320,7265952f,b33fc23f,154972fd,d3394cc0,21b66276,1b51db3), +S(48235e7b,76c94c32,b0d21bf1,7fc215ed,df036366,a9ef494,19723485,78db8943,4f5ac8ce,36c77403,b2fa83ba,1fd0e88a,3da4c8cd,3c10ddb,aafe2d0,5da40a2d), +S(668af7c1,4063dfba,1a4187f3,f69cb457,cae4edbf,a3bf9669,4080b6de,bc3e2f0e,ec95f37c,7bac26a0,df23275a,283828a8,5a102d8,f33eef1e,87cb56c1,850740cf), +S(d4426fcd,cbdfd904,725fb501,656b9f2e,2a9f9ee3,c6522064,f078165f,61c31d97,e73f2a38,c56838a7,174ee704,948d28fa,5b5fdc34,7774df9f,72f27834,a85eb4d), +S(d0f49ec3,42076b68,4cd91172,f15584fc,ea38aaf0,a3201063,f854ff1d,f68d4600,28d95ef2,82dd7d6d,72be7854,e8858b1d,a142002b,ad7b7b4d,bd1e582e,94341e16), +S(8a36f3c3,50bc0f1a,1b1687ed,4ff83a68,1578d74c,c28fa875,f6969e52,4887bbb1,15ab9e05,c3ff823d,ba090e21,1033c34c,fa713d39,feec4346,88e3ecba,4b431e10), +S(4d1ef23b,b316e821,7d2cc409,a1baa273,cc06f79,8fdd4d16,5d5b6805,3718e238,fc37e62b,db18154a,2add98b0,ec221e8b,bd1a2096,ac2dd1fb,cf8e2e64,821301fe), +S(eec1f8e5,76e87803,bac48bb4,65ed923a,a68b2965,64365d45,bd1c24c4,cf7041b0,2c6985e4,7cccbc38,3b85be66,ab34a166,c98a8000,aad08f73,616e4d2,2a15a009), +S(9fbc20e4,de372a38,90443786,bd7cfc40,c6195b29,4cf51874,6ccd9ecb,cee223e9,f734bfc8,a6973209,903edaf8,52f63bca,b23fc1a4,879906b9,1c5df169,9d24683a), +S(7984c8ec,a2b02dd4,e8b9c69c,6f803418,48f108fc,b63d7038,de58e567,e64a894,49adeb11,13c705a0,9eb01e50,dea5be48,86e5d424,689282ba,6d64f745,74f45e8c), +S(29a7400b,16f5712a,2324becc,29fc4b98,57fbb926,f8741dcb,324c26d9,6cd178a3,90770be5,5c0a94a8,16bcfa38,aeab11aa,5ec3b7d9,eb4e7d29,1bee1c02,69e87267), +S(8299d2fc,84770bff,a4e630b9,8f2e6744,99b1c7f5,719e907a,d70515f5,140a00c0,c790968f,a3c3d4ee,3e25a1ee,8e1d4923,3c22f034,ba7c172,b5d7d91c,99eabfa8), +S(5cfbd498,5b608db3,5d1a2872,b9cd03fd,d775e498,4629f41,61a2bde4,fb2582f1,8288fa89,81056333,acd1720b,bde757b4,e83d0a49,9c5f2220,521a0bc8,dbe827f8), +S(281f1fb8,e144e39d,9ec2104a,96bf0f1d,494eaff3,57fe084,63825228,ecd286e1,ae40e075,d19ee5f1,1dd7e22b,f1c277ed,9a02abe9,975609c,a7c811f9,7c54e493), +S(51698bc6,73d3289d,6b4882b0,cab14e67,97d31221,e5bc6e53,af061aa1,9f546daf,7b850099,fe977f6c,f50abe00,bb3a0b68,90f47c45,24e9ae02,94304b6b,20bd986c), +S(db701e92,9b696c86,d7fb459c,97af90df,ef847bf5,1d235337,2a2a4792,5fa8ae53,edc7e98f,1a108bc4,8fdbe65c,2904058f,7da5e188,e71d194c,4e9dbfe6,8a55d18), +S(c900f57f,e9a31d4c,9715a822,5a906e90,22d81c12,714006d5,81be0c7b,aeb5a490,8493eb00,90517d9c,b70a4bc,39043ffb,e0863475,17cde2,a9bd0d95,f616bb66), +S(d74e842a,fe2da0df,df6342bb,582fc223,717e0641,f1ce0e14,584c5c63,f379ad72,cefdbd7b,b4ecbdaf,409a0fa3,9a0a305,b1bd986,4913f977,bec6c47d,5d525c10), +S(b00a5f4,f033d126,64366147,a1bbb9b6,ea60a38b,863c5f3a,e323e8e5,1aee200c,11e9f1f7,b7701a4c,26a881ce,30fac1e0,92e157d7,b9c2e4ce,cffeb38a,172ead87), +S(5772b134,68bf9f09,d26074c5,16dd7472,d3a83624,92306cc5,c7544ec0,d73de280,2e2a7931,aefe2a31,6dbad1c,e7f9d42b,7f38197f,43024f16,9e27fbc,7af31d0b), +S(8bf8af02,ccdafb15,598f6725,5f172fb4,ba8960e0,6c81ffa5,b4c1c313,6f95f29b,96041af,1efd128,ef133e5e,b0aa3d9a,6ac3a651,92598b09,ed649847,385a9b2c), +S(292889a2,d8329139,3410385f,cf5bf489,7e1ee23c,e0e3b5ed,82ceb340,d89f87a5,41099fb2,bcec7e07,d4d4ad14,3cf605d1,b0a32487,1736063b,e49b06f6,d648aa69), +S(ad227b2b,737dfd02,665c15d5,9b28c7e8,76413dfa,25c9068b,90efa79,ce83142b,82f1eef1,7e2f6b86,87137302,741f8486,26fad679,9c6a22fb,3a49e341,c7e51e9a), +S(b4245dc5,5df02839,4cff2610,4a4255ef,89f3e708,21541c3a,4631ee4c,145bf85,5a40f72b,7a67540b,6858e5e,b15005c1,3fee862f,3cc54a52,7643204f,d0b8be2f), +S(15aaef61,568537a4,695c1990,c05ecb9,2c605232,f705c3e3,729720de,7e9c2400,e6efd1fb,b74e9e43,ec1244e0,bb4cff2,2a5ede8c,848a4f5f,5eec6f8c,77b6f5af), +S(ade2e63d,4a828328,b4c53763,30790331,734d7f90,37c1a584,59570c8,f31e72d1,c42898ab,3633dc7b,f3a454f9,d5475c4e,fcf1f786,d1f609fa,23616f26,b23a1a97), +S(d8a9043d,297681ea,c5ed63a5,de306500,6b66e4fb,167aa5ec,c76a8e2e,df426e7a,cd3de058,a0a93d7d,7122d777,1446b2b4,d4cf53a7,1759fea3,78adcf03,5093f4f6), +S(30651cb,592d282b,5348f192,5be3f04d,da5033bc,39e2fc7b,1e61500d,9769b57c,dadf77cc,44853f67,53b1dbdc,17a97d3c,e6d5b2e7,8c6087fa,800c5af9,ccdc54c), +S(aa21c60d,6f7d6253,9d42bafe,95c58f30,33c0396c,fa0ceef9,6d2f91ed,d6569044,4d519779,3b19515,92e2d952,2be520b1,11a5453e,ec6d7ccb,3e6db3bd,3d0c84c9), +S(5335cea5,e99eeb23,765b3444,d9bc7be6,1da67d6,91bcc42f,d43ae543,e9c22bc,c4072fdf,8963addb,5f980f7f,f314795,373cf3dc,935e0e64,c3d3d98c,342530cf), +S(708a530e,9e52c73b,ee87c9d8,8161c810,5d5762,2c29ae69,1cf999a8,3a1187a5,6477b7ee,1e065768,569a923,4492c7d7,c13258c3,92cac175,a75b0e63,b8c2426f)}, +{S(3fbd5a4d,ebbeff54,8c2271e5,33dbaed3,fb8ccc23,e3fa2579,4c8f7fd4,47ae186e,fdee4625,45bf75f5,5c29a724,6496d970,4616c54,ba01d0ba,feb9155b,cafdb555), +S(c1483ec1,78ba8414,c371b57c,49c687fa,69669e2,e3e1067,cc6d2a93,b1a9d24e,edf94395,962adfed,c2ebb3bb,29346136,e4dc870c,5c76299e,3b07da35,6bb26bed), +S(26df4b09,693a3905,2cb7a1be,5bc2cc97,222b70e3,3d297a54,43741228,beb77017,a3d6b908,cc6d5f80,aecda93,99e17a8,ce33c423,f00cfc4,dea8354,af502760), +S(b6c265d5,90475506,e15b2388,b894718b,be67aee5,ba40ceca,51876946,e336d903,b451d3f1,2c666c85,bf9486cb,296c39f9,49f9f98e,96d50a19,80f86f85,a1efb999), +S(da6cf69c,feec7b1f,c848639a,7e27932a,f49cd695,a2e56a50,693fa862,6e257c66,4506f44e,e6e0d822,7e67dc4a,9f8e2ec2,d3ec0c3a,c2a70c7d,d25fa9c,34cbe3ae), +S(d57648db,adf18b77,db185ffe,3f86f859,6adeec05,ffb86215,4b894a0,75776eac,a3f2fec7,7186d81e,4228cb1f,691e00e4,82a125a5,bbe9e6ec,45a53604,4932491e), +S(4de6cc4,d64d52c8,49c0e8d2,45409ba0,88248399,1916df3c,238be4de,ee2504d2,b389e7f1,ca72e9e,1cec2ed7,70f21441,590f0bab,1b963f1c,411f9bff,d3df03f0), +S(15f1bb11,78b01439,f26412,1d36a44d,b8333fbc,eabeb471,da2e6c1,1b8b3ee3,bf137117,35e10854,95acf3ad,97fe510b,33d6628f,e67d0067,499169e6,6c12274c), +S(badc76d5,481e77,9df71d6e,223c6965,9e9ecba5,8415a95b,eb7118cc,b1f931a4,475e47ee,115d258,3f0607f1,7542ccde,626e6d57,6ea884f9,61b41354,aef37247), +S(13015ae5,d770f4a9,75825bae,a6cbbece,78536dcb,78d7116e,d304aaca,199add2b,f5e28585,7a99ff0d,a4fd15e,8ac650a,98421629,aa102bca,25df3930,7e5cfcbb), +S(7734d2ac,707b9b53,afbd2a64,50c9b609,1905c391,958d7215,f92353ee,fd3c7be5,751d38f,ef48bfea,8fa5de06,8188a658,ae6c9c75,a359a4ea,efaac5e0,b5e859aa), +S(91814384,7fe2ed34,e9cc9c61,3fc2c67f,2b76a208,561d0e06,271b812f,6c678856,9a97f6e0,9888e076,93c9ebec,b8773485,c3c5d208,c793a77c,6984fb09,cdfd67b2), +S(98c516fa,2a2c8073,70ca9d7c,b4187108,ea345652,c8f814b8,b4a9405f,b48c2469,7b3446f3,2e8c4764,a8eb0846,4be3bc6d,f42b8d14,b7da65a2,ac96a018,d0831c7a), +S(5691d1e3,713302c7,48bf633,189ce032,10832e4a,9af1dbc2,abc3e99b,cb4faa01,d802e21a,fab84c54,5d665ed3,54130d9d,f7f18283,30b3a1fe,e30c2298,8b71654b), +S(1f8cb624,6440b640,aadba62d,c02f4ce7,a0ba9be7,d535987,64072fed,95c0d1a1,647a9dea,abf8247e,f46b60c6,53cdcd5e,cff0d1c6,88b7519b,a778f9ff,c894e1f6), +S(1489af53,94878f07,5cfb2e20,931fa3a4,e585d494,78818e4,f47f05e1,2be54d14,cd5bd721,4e535822,43270bc2,dc692ba4,c57e494c,eba92d4c,dd2e13c8,e24d8550), +S(66159248,2b2229d,ea70ff76,d2a5e70f,ad1905c0,9211e3d6,2d1d652f,ccd709a7,8f5ab85,57948aec,67e7b538,fa9c704b,ae939c22,4041e6e1,65f6045b,a6fd0fdf), +S(bc894efc,d0fb7497,ba70d654,961aa79b,6ac5a795,95537c80,82c525c,2c44c3a1,d5254292,ef0fb6fc,db587393,3b17adfd,87d13320,858ff783,75e356fb,b0d3415e), +S(f117d7f6,85457601,9b559bf5,f5bc150c,13363e7b,72123435,b441d98b,d169dd27,a8f4a23e,dd0d8f2f,8950c124,1abac43e,e629b0e1,8505c3bf,780ea378,20c8623f), +S(2a8d99c2,65a66a51,56b60556,775c61bc,b2a81a62,34896a31,16238c2a,b7716ec3,5e842306,efe11f66,5a049c0b,fe3ac74d,d72c5033,6dbd04bf,2a77b0d2,4d7ea651), +S(ea747597,1a6b6d94,2e368bcd,9979876e,afa4622d,313d819d,5e8291c8,2da95830,41d4a478,e0950bb9,e6595bef,3c197e5,d0f77ae,6340ca8f,2947fec4,70465193), +S(114150c3,fe8853ed,9f3e26f7,bc9f3d6f,aa50ba0e,6ae2d8ff,97924b04,dd9678b4,5530c22f,4ac30716,2b272015,460426ba,9602256c,ab735174,1a2fbbfd,cd71d134), +S(65d96017,c91a746a,656eb595,d39dc9bb,3476dc0b,1a1036f2,df7a4ea8,1846631,de46bfad,6999b108,1f358edd,7809919e,4de768f1,fb21dc09,4b248bbd,56b3dc76), +S(f2aec214,61c040c0,ebd18204,bc277312,732b452,266bfd55,aa071853,e458bea7,52a1b71a,eefe2c48,5ae2918,e236f1d2,1622d37,13b4bc04,36124567,d48cc453), +S(370ef89d,c39e637e,8bf6be31,63a4f76,7cebb202,c868647e,db18f991,977681de,e6d402ba,9769363a,b963729,822bd6aa,9794592f,36e54461,579ae53d,4c8bc4cd), +S(8db6356c,4f31f46f,961e4342,a1ff50a1,8240629c,a0decc36,e1bb24af,f6742e57,8ee033bb,96958466,15626ad6,736e9025,fb76320b,c2d0ceb8,ce3400cd,743f934f), +S(14a1a08,502510e7,1060f291,1316ee01,b1fc2bd3,c88eaa1b,656cba0e,8e3515e4,5a4dc536,b62c349b,c9bfc6d7,fb677231,1368655e,fcb9c89e,572aa58d,a57f08c6), +S(d530fc7c,4d5b4fd1,5f44ba0,c0f08f24,889b278a,93ee30ab,935fc112,5e244a58,39c0ea88,5984c2d1,d5119a28,7cd842ca,d3cb54c8,ab6aa222,c01e7152,98aad10f), +S(50f3c13c,a474f604,ca992658,bca68207,76acff7d,d507d63a,b5e18b28,5c5be81,685e151c,7d8fddee,6c9d8513,dbf167e2,c32dd70f,b6932397,38eb63fb,3e4f7afe), +S(c0a72dda,13174682,726ede1f,7ecbaa68,b4b137f6,d44298d3,4e17b7fc,10e19d4a,1e45ff3e,4a4239ba,4a897489,a265a60d,9a91f3f2,83fe2e75,9e770156,c9ebb3ca), +S(7121e14e,7e2a2c57,76b5702e,c83a845c,28785c79,9099a007,54b50fca,b4d9279c,e6b3ff5,ce62fa35,adf45e69,2ccafb91,b805d7cc,b6eff2e1,38dfd680,d0684401), +S(c0c01f34,ae41b8cf,e466b4c9,c6a5d5f6,14f570d6,fcbef768,a81a6c8f,5ff4adb,f47b0a41,1bca80a3,836c85f4,bf8a4731,3243bc2e,8f2ea47a,3b1008b,53caebca)}, +{S(4f20ce51,84fb2949,443286cd,8ea201eb,15248749,6e15aab6,f3ea2597,d4cbf47c,bf37770,62691c5a,d6c6cb8d,c30fd3b1,73578a3,bcac43c2,c8404b6e,c085c97c), +S(17ceec36,7fad4365,520599d7,62c66c12,5abeff81,ce7242dc,bde4e799,402759c0,91e024e1,e2147fe9,73091001,984dd3c0,9f887257,73bbbedf,47f00c7b,c5c9f626), +S(dcffc4a,5557f2a6,ac7a3527,5a8228ec,325ea0bd,d9bf52c3,8a78217,6bd716,87658163,dcfc39e2,ad08a499,898a1505,988d9b86,72b6d1e9,64e6845b,cb41129e), +S(625fff43,45337aa2,1efa0884,73a6662e,d5340470,a79576a4,362e30dc,bcf762d4,92ad0a66,d0bea2a6,d7eedfe0,e33295b9,3a656e45,9220026a,5ff3be8f,83184187), +S(410b96fe,7db23faa,7d123e97,c1a82a9,7b24a26a,80143e50,dcc6d9a9,1a6e81d2,ca0da356,dce88799,5f8cc790,64d197aa,6532dcf1,20fe93c3,7e2ff4e2,f14394a7), +S(8136e51d,ca68170b,136d40fe,76980b4d,d4f435fd,e38f3017,99de734c,b2491551,823dd1ed,de1d326,676649a3,9d5ba083,7c48e180,ecd0a648,eaffe7c8,2894e819), +S(64a67d9a,a7a31390,3ed9e348,e7300917,6c1d52d0,be63f54b,aa3ee8f3,f1227a52,ef770581,df4aa013,6d191e99,cde7f42,a14fdfbb,11e1b709,bb540100,1dcda1ed), +S(5fcf0465,a905aa8a,a1da5073,d524e8a3,30af663e,f4307359,c03a4c6c,c423dd9a,58641e67,fa821fc1,2307a66e,fe0129e6,4ace7c36,c3f5395c,db87667e,5e742a42), +S(aae6747f,ac3d8c9a,148009ea,c2d25574,39a8b546,455fb3a4,5016891a,f9372dbc,66084f19,b1d97f2c,22e182c,d5450d43,d56636e4,92651cf6,22772a7c,5b46d9), +S(377dc2c8,13e36bb4,642d1e02,cafce754,2ac6d9fd,c2212edb,5432674f,38e242c7,8395dc2a,39d3b1cd,ae9d7d37,d0c4597a,11f931d8,75c8bcf5,8eab03d3,674d5841), +S(35c598c0,7ac5dc3,7afe6895,29d815e9,406e2608,292ffa0e,7b24df65,3278d8ce,e793aaf1,45f538f6,c133309e,53cb5343,dc1dcc74,985c57f,27361c6,aae23e7b), +S(e9666336,6bb286d6,c86f425a,2d5658cc,1d733223,9ec2e9de,c8ab7295,4b329845,908dc533,b6098e9e,9b737e4,b96e7345,e635f591,60bb3df2,75e165bd,d1cc5998), +S(46fab0d4,7fc6586a,31cf861d,ff5e0bb8,cc12b60a,53103007,c8974ab8,204af703,845ab7de,7654fb36,618dbfb1,287534a9,2d43db6f,2a2cdfe4,5365b4b1,893fbe9d), +S(4d80486f,fe748d1e,f88aabff,76bb82c6,a45db736,76ee0ff7,d77cdffa,2c69d07c,2a52044b,d4fc6a59,fd16dabb,df35bb6,8057ad4c,292e87b5,528a3847,c8784638), +S(2c1d108b,f4945c0e,df62cc15,6bf0830f,7a45ca,1baa636e,9f759bb8,bf078a55,81e34495,d269afbc,1be39ce7,5417ebf7,d45decb6,eaddb635,4480a7f7,8d7dd34d), +S(320a08af,eac009eb,7f254b8d,395d836f,ca6ea527,4e2f309d,dfb7f120,2f1b3cdb,75269a2,41199c0e,5f1cd9e2,d102a294,2324a3ea,cfae231f,99ccc5f3,e0af00c2), +S(8b893fcb,9a524af2,6de5aa38,8ac3dc,2159817c,7062e5c9,d5c9e7f7,dd889ad8,cec6a5ba,481f7e3,88c1cab,c11505f2,39afa143,68977ed6,52ea2d6a,19d2cbfd), +S(ea89b95b,36cd5203,22c8e5af,7461f9e1,a054f23d,2720469,fa74cd67,3a52aab5,5325d16c,4b866865,2437b6b8,598b31c4,59e6101,2cc1b147,e0473527,5935ada5), +S(cdfea79a,8c16ce78,75a9fa1c,5b7647fb,ad641ffc,5b73fb31,d9354a1c,3c1cabfc,184c309b,b0f52999,2a3f6b93,77b9e6a7,6da6b943,d8031408,b71223cf,b3ba9100), +S(3daaaf0f,785a6397,c652331,630931ee,a975c522,35899736,1b7e5fcb,409880fa,952efec1,ebd4c107,b26a98f3,c6683903,a498c840,ff4a36c7,ade569e4,c899919b), +S(7cea5226,a56d21cd,45bfdbb0,7fea6670,40247c70,ef43da28,d1f8bbf0,6e4ef2a6,b03edff9,6a5f32c5,6f8f63f6,ba9feb68,f43cca62,391ea587,81396c7,5d963b67), +S(1f5f4c27,847ba921,c63cef52,8b57fef5,5bdb5344,ea67a23,c173828d,c59199e1,d37f6918,e0b774ad,317dbcac,75c82188,c8a421f0,ff5756bd,853a05b0,c95ef089), +S(36cd4da9,2a77613b,6417deac,1d9a0dad,1bf0e506,de26b529,7fffbd03,4a4663f3,ec1dd8f6,6226bf5f,fedb071f,7027f9d8,d931e6af,e378396c,d0d296eb,a63737e3), +S(9835c156,1be21ce5,db788f1,3c0aea13,fde6861e,97cb2cc7,a67fbd37,17eefadc,7fad454b,7372d969,a6e754ef,c73415d7,fcd4d589,c8e255c5,1adf5a9a,82228f42), +S(5e218414,d9c9f0ad,35ded20e,76a484a1,d41b3894,ba9d3be4,bcb4546b,371d0e4d,76966ecf,9c8f1c9a,452cf971,10ca6555,2ca59d31,21092e93,333bbd61,6eb9cfcb), +S(b105f4f4,40e7ea66,e3272da9,d6b2b76e,d00e96a5,6f95224,34ca0df1,5340c585,9e8fea7f,35bc9eec,f82ae118,bcb6dc33,acae587b,f37b149,1f8312e2,4ffc86d8), +S(81d5713e,a732b4d,98d085a9,75cac9b5,3fa65171,e5cf49f4,684a7856,7c24fea9,32480cf7,a0bc0c50,a4de8200,9343b524,4a0f2aa8,ce67b11f,4a5482cc,6fa00bf2), +S(d47b4f1,88f5e7ed,a9eab2e5,8ad2c140,c6278d63,517bfaca,8cfb64aa,cfbcc7ec,524f6580,9d3ee034,afb1e64b,1a0f8ae1,1e464915,3722e345,bfda9671,1b94a5), +S(16e85ad8,6a953564,39b97957,7bedd0e9,6e2eed72,76ba269a,626fbd58,447996c0,8bf74f51,4bdbb6c1,4de81a3,1ff12aa5,de49bd52,63a962ab,b777439a,47eadee7), +S(c299c6b0,6e6c78ae,852bd55c,dea35f99,d264cb5a,e836b77d,ab209ac9,c05201e1,a558c66d,c9ee7fa4,c777b0db,288b328,428b230a,7c53d516,522ccec4,af0ae08c), +S(63c4624,35ef974b,393b05b3,7d1c89d7,b0d8958,ebd541d7,584e2bbc,7235c795,1d806446,ecfc7bfb,bce099f2,6ce37a49,61b53453,5b65642,c0cd23f5,a4eef9d7), +S(6d36d105,ed8cc5ce,53f2cb69,8ab620f9,469a3e5c,b25bf6e6,d413f414,c5af726a,1b45a3cb,1c889961,8d273993,6a3affd6,233a66c9,4bef75ca,3a8fb6e4,ec05ffb2)}, +{S(abdd85c7,a2f8bc31,343382d4,e405978,3874c8d0,1405ef14,85047cf7,f0f71d50,d5a03157,798fe828,a03ab63e,84bb007,b53a5315,1db7af14,e4ab612a,736232d4), +S(31297c6c,f567267b,3c8d65a9,72afc752,e8525eb3,de2958aa,76f72e14,5ad903d7,f4735877,a6c6d89b,d1beb50b,edd1235b,5f5e5d0a,878e4610,e7d756c5,34813389), +S(64706e69,11a7d0a1,2e587c86,91117a27,cbfa64ad,1d5617fc,81e55b8f,64e0da86,59d9af3a,419957d2,b3de7570,15fd8531,a5d07430,5cfd7444,5e7e70b3,57e62772), +S(a4988ed2,89d8397c,f1b897d3,b81d80fa,92658ce,2b935f4e,e2e3f0f9,b193af51,813fb8,73270570,50f23c3,f8082bcb,563ee366,1f6b2af3,f631f5f,916c8478), +S(3c2769bf,af401993,595a01d9,9c72a6f2,699591fe,4b869077,8c6b5ee0,f172a866,f3e0d8b6,cff168c,95873f44,871d27b,df1e79a2,d9e0bd4f,6f90f682,538c1f24), +S(49d93e09,df655edd,19548fbe,affce201,4c6822a7,e196eb98,b9ddfad7,3cb70125,26e6957f,84ced17b,c64f710f,b37656d,31ba088a,98350337,8f7323cf,c57f0eee), +S(53c06842,49997cb2,6e5b4cc,5f166fe7,db0ec0bd,52639a27,d8fedea7,214a78bb,8a8dd3f1,b3081dd4,948255ed,dd178089,a0fa7342,1ea616a5,1f639057,34a489c6), +S(7a8e7d18,3f2aa640,d0e2ea02,4cdca5fa,1767d9f,9ae38805,5d38e8e4,a81d33b7,c2fb92e3,5556fd14,4a894be2,3d97c6d4,30872ccb,25e239c0,d959a24f,aaa77397), +S(a5221a2d,29cf3ef2,f066897e,4ee74ac2,95b34cd7,54390814,297537ae,abdf603f,ec0ff395,8c3a1d1b,5a379417,5a61cd97,782c9683,aa2c7c07,5d147db0,2b134278), +S(3f49da9c,1d62eccc,afc4b88c,814e44dc,8440341d,f347de1,fb60126d,59578dbd,c3cf8e96,2fa9478a,f1be08dc,961734ca,5021a65d,b1b45f80,78fa8e8f,d2813a79), +S(47b16636,f5a64b07,534be14d,6ae37af1,9da79b42,666b201d,d0afda9a,2daeb6b6,f1218111,31ebd87e,e1fd7c9b,d24a0a11,a12e842c,6c00f445,6a342309,9b171f12), +S(a7b5a8ea,1f23ff1e,c1768eaa,2fef0d66,b75744c6,dc925d3f,9068beff,d69b32f4,fe01a23c,b0e5acac,e60058a2,889f9434,9ffce6c,b24f4a3a,662e0079,99bcb690), +S(3e14e2c,e7044716,d42e9b6e,54cb0500,a1e4374e,18917336,e3205e31,4a878b47,18af982d,2c78ac23,818644f1,ec657da8,ad66bdb,3d5a9b84,3f8bb988,4ef8dc3f), +S(71393e6,746d3072,830299c6,c1244303,750742be,361c5f08,6eb314a4,76f1736a,dc30a7ea,9b644339,ce8f1fe4,eeeba07,5bb08934,8135e819,cb061559,aa14e42f), +S(37721b73,e6861f15,7993696d,aded49d3,78994f3d,e2b573a7,defc907e,d6f301f2,ee0e1755,d8efb25a,5cf4d783,ec847425,746fa442,d460cead,56e73a69,42561de1), +S(7803c663,509fc9cc,55b372e1,dc0fa76f,149a0ca6,3db4516c,4abc0ad7,5961e4ac,356c72f7,794a70e4,db3463be,eaa847cb,256c58cd,b6a7d862,fde4feef,d896a46f), +S(32976d3d,a3d033cd,c073b0f,c7d2f445,25646893,fbded1c8,1a0a1761,a8703206,5e6b7900,a069ce4c,65cd84cd,f290f092,2b936bda,af6ea40d,9c36a321,a7c9dcfc), +S(c52c7b18,b5fae5fd,a4e3597f,39c96b8c,6d6c856a,80f1210d,a1ebfc15,34850763,b87e50f6,20b66865,307d0747,a02ba22a,b310712b,cb0bab6b,963c589c,c5a208b1), +S(7de59c8c,3922fd51,68f4151e,cb783775,cd0bc0b,1185ecd3,6ee075e1,14e66cf7,688e2cad,e4d49da7,fe691497,412c9372,c67288e8,ca4b64de,308eabeb,723fda15), +S(ac49d6f3,32cda691,c345f099,667ace08,f6496126,830c39ed,877223a8,cedc8be7,267e6a52,5ddae4f6,7e05f0e8,52b9dfe,5101c491,64d791c9,82249937,c3a7b031), +S(5a92401b,698cc394,c9b714c8,bdcd92d1,20fa72e9,b1311839,1c383024,f469ed22,e29f2926,84c255a9,a739ef0e,5d13cc55,987f5b3a,5c6ed623,29431033,70edb4a2), +S(3609dfba,51616095,ab060e77,d6779025,6456eddb,f4b651c6,442cd673,f893878b,f85fa9b9,442050d8,ad9d9314,9ede8698,91dfc99e,c05a2a48,5854cbeb,55a6c380), +S(332bb85e,92c90a15,3bf602f,45dc33ab,3dea5ef8,7034af81,944113a7,4edc94d9,59b6c879,5f2a824,96d631b5,ceff8708,507db41a,375c7257,7533d8f1,461fbaf1), +S(16e9e054,916b894e,730d7126,27b1bc81,e7689efc,23cfeacb,a423362,df49d87f,303d0428,b701f1e5,fe8ae460,e54adeb2,d4b5aa93,a9c7d7ec,7b903cdb,20e440f3), +S(4e62ab89,1d4c4cf0,2c44915a,4e2fd522,88d75aa8,e22b7463,30dbfbca,97ed9515,a7c21be3,3b5cd522,4de0bd25,faa9c2de,5d6b2f50,b50a6901,b7167b3,c4def4fc), +S(649eedbd,5612c429,2aedbacc,b846e759,4a2b5870,f21452f3,1ac9e697,fc055db9,ca694303,ee206a4a,acfc4cb3,1aa9f117,8fcbe37f,d6bd11a4,669289cc,7c37b0a), +S(e858f72a,5fe2314,951ca096,8ba59760,e3d2a667,e76dcae8,c3ae2d7a,4721afbc,f1c7131d,3e2d0468,ebb89bce,700e0eca,ae83afee,75620938,60e1fc70,cfc7810a), +S(cd351498,29ccb1e6,9b18e35a,72a24b30,e074793d,aab4028b,1c5eefe2,b7b3163d,6bbd52b2,93b43cb3,a19f6291,69ba5b2a,59785099,16842093,1e58dc1,a040c57b), +S(19ffe344,69ba3e43,7d901863,3be7c298,ad8b65a0,49c30dc1,bae30ca5,97ab38fb,c33ca345,efeec662,96802e95,69f0f34d,12ceb64f,30fc704b,b77261f0,ce5c98eb), +S(8a2f772a,a38a5b55,a7081d0a,61bc27d5,89f9832b,1326a230,d81b9f58,4d634293,a4707a0e,a7bf528c,ac62e361,6f09287c,182aa3b6,6862430,dcfef3c2,69d1567), +S(e583bee3,1dbc8f0e,572eb18f,366f88e9,3a7a0484,b4299b9d,335f7836,a222636,8a4fae1b,be122228,be9d8afe,be223c53,dac161ae,ca77ff4f,e14d9c78,894fdfec), +S(8b6e862a,35566848,50b6d4f4,39a25950,47abf695,c08b6414,f95a1335,8dd553fd,15a1f76e,f12ee34b,f2ef43d2,b14605e,db53c3a5,e7cc7c2f,27fc252b,c1641642)}, +{S(1c185b5d,e988ae93,eebe0aa4,a98396aa,fff2671d,8246ce2a,4394db96,7a541ad4,dddf4244,3532024f,d225f86d,133b8156,3ea8c92b,f0ddc354,88e6a04a,d41da5fc), +S(addee173,b29de510,58dc107a,47fad47e,c48bf332,2f7c138d,51060322,571faacd,3890624e,c6920ca8,6a9aadb9,90a15156,799dd771,901823e4,9f3bfcb6,8bf05d5c), +S(9e20bbed,ccdd5c05,d683b2ef,852760b8,e246e5d9,6a8900ea,999ac8bf,5e8f12e3,9f28e5a,b4257f6b,b826d076,ffff259e,1caeda5b,7d34f658,ddfa0401,7cd4768e), +S(dc825d1,5f707c17,46920014,9d7be56,acf2d1d3,c444fa27,cefe5019,6f5b317f,226d4960,2f349d4e,9cd10a57,6bf01681,e4981cb6,4235d347,72a1e5ce,7694a20c), +S(812e2cda,3f473919,1f2ac087,7d70d0e0,2ca0551f,10c96d95,51ba4199,22780f90,c8d05855,6b6364bc,d9aff119,5b9ef26b,85cffa72,1e880b83,eed73cbd,d23b91e1), +S(aebb0870,76f5918e,68194fce,42d0b925,cfd2a506,359af62,146c8ceb,8502231a,c1c19605,e0456cb1,3e57229b,45c83ff7,c3695a2a,31908bc0,31b08140,9c2040fb), +S(af7332f3,3ec274c8,d34f47ac,fcbacf8f,7980cca5,7220012b,8fd5ff94,cbf3d8b,d439f1a2,89799dc8,92b7e53d,a84a9e82,7bf7bdb,7240c34a,caef59a,777188a8), +S(baf71cf,7851a758,12d7e09b,192741f2,1b5d2a36,6e31892e,e54c282c,81163a6b,1ef3bf2c,a81acdfe,17cd6b45,266241a0,22caf299,ed4d87cd,68d3d4d4,526b4d38), +S(615991c5,d250cebf,8c7bd1b2,969213f0,403c7da1,a3ba913,44fd0490,88c2474d,4f014177,12142cca,163f29a1,f5790004,32726712,93c2e87e,f46d2138,c14040b6), +S(b1574b39,26ff27c7,b2dace6,6108b93f,3fc75d48,478567cc,66bba29e,750c0c86,2759967d,8d05be25,3f88a66f,830dfb83,5139e32d,6f42cf3a,43b199ce,ab85b55c), +S(5fe92a7f,d1c407fc,967dbb19,e9fd4d,8361aefc,a3d5a9a4,2f8237a3,458e5e90,9b89ce35,57d469b6,9b9034d6,cee93609,c291d023,d1d9349a,d9bcf47a,aed8b2a9), +S(d65b0a5c,41b2dc6b,e5aa87e4,adfef952,621f9d99,550e424d,176ee180,65f666e,a76fad91,3b80b0cc,3d3ceac3,9a465cb9,4d8c79de,92adf9cd,7a4efae7,c85c30a4), +S(61d7de65,fe34ec4c,f82f67b1,75887263,11683263,145cbeae,18ed192d,14ced48d,effac049,d7e5412c,5052160a,6d1b2230,7157669b,856af0e,e3e46a25,2d2ee19), +S(9a77de66,5165a9be,3dd2758c,39aa7a14,1f052358,fbac634,5ea701c8,c93bc4a9,1044e428,bb381024,70108d56,b8b3e3bc,7512300c,5a6ae44b,93b2098f,a13fc023), +S(4ccb2426,b6eed0f9,651f80d5,72b23e78,d84d6928,57648077,3663216a,bc8a418f,1840c,bf5ccdd7,19f7fa8a,33e7151,aa351d,2f620972,6ec67d1f,fdada8c6), +S(53f96bb7,86516e0f,2ac7611a,1aac61d3,cfbca76a,9609fe,e4cae036,52f68271,97e3acbc,468b777b,bd1c8263,5332dcc4,b08b9fb1,9608fb35,cd51e49b,f09d9087), +S(395253a1,b6a349a6,dfdb0d6e,65695572,2a597411,fdea9294,6e48d107,596d8ac8,c57110d4,dd0d35a7,663fb3aa,e15d8c4,dce5cb67,d3173d91,a6ff7ea2,1bd28107), +S(d7becbeb,c47d0de0,899ffdff,8620124d,b29c8e5a,fd71a0ed,76e0df76,bd4e26e6,d8b52fa3,e16e7f19,e925e769,3b5a731e,18f3163b,1ad4db34,7f878381,da75fc15), +S(fa3afae0,4f8c1fa2,778446af,88e29150,256b0413,d9bfeb44,45288e41,29be15a5,9dc76b39,574453ab,2d46cf23,ce8cdb06,cbe7df15,d03fd390,4470a86a,822028df), +S(da56da00,dfdd788f,90a12219,db03cac1,403efef3,ae706031,e153aa16,b3a52eb3,1012ca8e,ae20efdf,41c77128,93fce97,fc66b187,caec55db,7aaa81ef,cc12838f), +S(f07866f0,cca3474c,40e7fa59,26df41c0,e46fbfce,faab92e8,9ccd1170,3ccf79bf,37ed66d5,5e891f4,e644fa04,182f34b6,1f1aedbc,d2a71aac,dd1523bf,f579dace), +S(853f72d1,edc4d953,348528b8,3656894d,67032333,28a16801,64a84511,15c5e968,197737d0,de83e73b,247d861,510ac76c,3ca214d8,ebbb958a,74ce1c31,5e715e87), +S(7c7eae74,dce7ef76,9ef0ce86,cf6ac861,ffc3d4a9,6313f379,fb2c0325,daa91aba,131e1689,fb017e15,e869d858,2dcfc4f9,153d1e8d,246fd613,b3922302,5b5c3767), +S(56028652,bce9dc6c,c8b4ad5c,f9f222c3,412e5bb7,8d556225,2c06c2e4,25a6e31a,2aa8e093,d8653f6,2153972c,e54806ba,666d49ba,3787934a,a37bd65e,79374ac0), +S(2eb98b01,550a00dc,59d280b0,71e472b5,a65eea89,298fe4b0,9f6f0e07,9315ad7b,74e22fc5,3daecdee,6a0b50be,e17f1d7d,d9481e77,28778957,274c8d29,a0d89fdc), +S(7268b61b,f65d73aa,37766a99,9960d998,18aa4ef2,ae8a97b1,db8476fb,32f891a4,824e99db,3157b706,38573513,618f6901,ce1fcff8,f25019d7,c5c45bb2,f3bb4d47), +S(cdea8771,4a764e3f,a94e7356,879b7d9e,da7c5b6f,28c172a6,1c0ab012,9b9ddd7b,daf49b12,34ce20aa,263b4349,f9f88cc5,1334db26,59b7c587,212f407f,cbb2644b), +S(38831af3,193c8860,690a9d74,cc0079c0,9e3ae0fa,ebe0da02,67ad6e23,99059d19,be188500,5193f11f,e34e70a7,e470cedc,902bee92,e7041403,c2f1ae53,7a8bb077), +S(df3acf55,bc6d97ce,34ebeb46,34fe1010,ed3d6d6,383c11a7,53a93123,e9c8381f,94c22735,ae6f858a,59f663e2,12532e14,4efe6a81,981c7619,e5002968,dcb81df5), +S(a8b08b86,4946ac6d,a101eb85,ee7bdf55,24282ca1,a9956e4a,eeb1afe9,87a43ddc,80ff0174,375c95fe,cea6e00,20f17123,5cda4bba,d4ef893c,78ffe37c,205d5577), +S(fd9941ce,e1c26864,248f7035,352787d1,aba9e93e,f5edd333,d08c89b8,4bb9dc8f,85be138a,42bf190b,921681fa,8777a619,878d4d02,11016c72,8bc151ab,1a687b5a), +S(7e2cd40e,f8c94077,f44b1d15,48425e3d,7e125be6,46707bad,2818b0ed,a7dc0151,6fa48af7,d523054c,7d59e574,cde106a2,776411bf,5111f7d3,65c43ac5,df8ddd68)}, +{S(282c5bc7,5b9c3f76,73e244af,29f22b80,c171bcac,d7e39b4f,ac7ba6cc,656d9010,e8db2eb0,a56699f1,73d5b5f7,99d39e14,dde34648,f159ad0d,c1c7767a,19ae72aa), +S(d5a3eb7,cad9c548,839ceb7f,67145e0e,96c60d8d,68415f76,73b73700,5ce3a8b,34ae4e12,355d1df1,25149efb,1a9050fd,490e251c,4404fb37,31b6dcc9,e233b9f1), +S(68718b29,86197989,3c5f7b1b,48abc254,13bd23c8,96c8828,7000ebe6,6db742a2,bef9d2a1,bb596fdb,3caeef3b,4d950568,8a94b436,4fd85f37,30b20de,b9e9a4fe), +S(a5ed1709,7932011f,9a597511,a526e61d,f22d0bd8,ae3e15ce,655820e6,b1ff1238,dd6dc7d0,81e70b57,4f235c10,c7c3dbed,a57743c1,15e6fe01,a20ac751,34cdace), +S(ec37904d,9662a487,1a471d9f,778bdef3,430df9e2,26fc42e4,7fc4bf5f,80e3a9c4,8413f2f,1ed55d8b,8448e336,ac9d1418,c48846e2,acb43509,f1a3d935,8cd18ed6), +S(b09f9c76,1cbbb685,f695328,61c459a4,d2b16989,3cbbad2f,dd49c87,1d860db4,dbbf9049,31b18454,21c41f2d,2185e3d6,c8f55dad,f1514ab0,655c856e,3391278e), +S(ed1a335,48864e9d,b41abcad,3344f4e7,ebe57841,9371095a,6b95fe4e,ae59edd7,d1146be9,83adc77d,bd9c107f,3092a9c2,9c271248,d78ce913,7831127c,c403f44c), +S(d39507d2,6ba377f5,c7116aca,78df331d,a795cdfb,54e5c912,8558c0e,997b74f3,fa7971d4,32cb5a44,589dc705,de28ad0,382206f1,6e11229f,86ff82a,efef3131), +S(641dc311,baa77b14,35f408e1,528445df,53c5ac5c,32803a3d,84e8fb66,60d71d,2b355a47,76980bfc,8a4e0ac6,a3bd7b02,a6b20ffb,f8650b16,89010456,6953e49c), +S(c3dd73bc,cfb744bc,57bc95f9,3c260df7,7f3b7e74,9e4a5237,f3865f8f,f0c89489,15d58dfb,83654754,80e53bb2,a1ba430a,ce213c38,ea71c7b7,51b4143a,fe2bd124), +S(3f883fa2,e834df1a,6e9b5c46,b663880e,9a0b42f1,891b92c,eb30600d,5641813e,7acff194,a5fb76e5,bd3d8fd4,2c7f07a8,3a991ba6,7f0e4edd,c55e1d8d,3025d590), +S(70c8d4f5,21d808e7,221bd5c6,31f171a9,5e7aa358,4477068c,2549c59e,228688bf,52badf20,6106d5a8,d7bff921,580eb5f5,3a53aeff,e0369f9a,1bcb282d,7b4cc26c), +S(ae08db34,874d39ff,bfb9c92c,5e4253ca,7ed508fd,d12841e9,63600461,b2b3a0e1,dc0504ef,d209be71,381eefd2,91508120,fb6ec1e,df62d24a,cb1d77a9,4eebf1be), +S(627027ad,4aa88477,c6240517,87a25b88,7d5b98f,b968221e,8e45d584,3db6e0bc,34b553a7,c6ac7004,69367afd,17c5eaf8,7605ca18,6a57667b,650fd8c7,18ab76aa), +S(573ef2ae,72ae8fd5,eeb0b720,f8967b44,f7d9d96d,c8a4825c,23a3dbed,fd2bb442,264f508e,efe5e0a2,55e55a54,bbf739b5,757d0a15,994ea9b8,4e139738,7c484786), +S(28907848,cf84eec6,773a384,ce5f4a5a,24c8afc8,606488a2,ccdeff25,6f896dab,ea87d4f,41df8727,2fe84537,d11126d5,62618bee,a51008ca,895a8375,4f05ec5e), +S(163db4c4,536114f0,75521627,c61f62d9,14214d64,ac9e66b0,d85b9991,62c54c5b,7ffc24e1,11c0c845,1c574e9b,e4b56610,696d3667,a6e6abbe,9d1a5ea9,4122aa1f), +S(2ec11f2b,71ffc28c,fb5e779e,7739098e,c969bc78,3cca5a22,77d2bf53,e6574d1c,c5e9fdf2,89a3090d,e24d13a1,bc8377d9,de0bcf4,63482ebd,9620cbdf,8b238fb0), +S(30549ae0,9a46820f,f49423b8,9c6fdd48,703132fd,ac166dc9,90609a32,49039f0a,b8c94b4b,36d39247,732976e,fc16d500,ccdc07f0,d7b97db5,7a1d9fbf,d8cb5d2), +S(98685f94,a043399c,89e74674,240322ac,5a595bf5,41aaa44e,d781781a,10fe9225,4506b1ef,7561b811,53f44e8f,325f9222,e999013,30523885,d8c59864,db13a3ef), +S(9acba196,3014ea9,1baba28c,e273c6e5,b9a2e1a0,98216c3b,194a0b56,dbda7db6,f0a3358e,eec737af,2e313262,b29ddf6,2adb9e97,9f56def2,65102272,6b976290), +S(e81e91a1,7aeec75c,19df0ef7,fd07ce2b,e477c031,179e3f99,4ca13857,e2b5ff93,65236424,aaa8b6cb,fdb2fb20,46ae3c3d,839d97ed,217edc6c,c774f889,d2ce8b45), +S(61e60aeb,821c3f80,b53ca78,2c3b4d21,960eb0d2,c90202f0,a5fba651,1725ddba,b029275f,690d10bc,b52e8bb2,acceb071,f07834fe,64175088,a97e26f9,8ff34432), +S(a931c410,8fcb4346,6802dd4a,8ec2cf62,cf4c5558,8129299c,b3a87e95,6fba2a34,c21a8dd1,43d4a639,339fec49,f56d717c,658a55af,ad72da1,c754fb9a,117cf6e7), +S(fb5c106f,da32fcfe,ffe9b5a2,7ac8cfd8,d9a73da1,5fa6340f,e09d187a,7a83cb88,a3f4c60f,90003375,11c39100,ba4c4721,c6c138c1,cbae09dc,46d1a1d2,5baa95fb), +S(dc25e18a,18f0035c,2a05e80d,d6b38830,7fb3b176,a66ae451,8c5640db,7540dd24,3ba83beb,3e6b29c2,97a0ead6,148f9b93,711556e2,e5fd513e,ee649228,c62d8f3c), +S(ecf7b689,ca03b840,739283e9,c3003a01,65ea3f,3bd17e06,9260c0e9,ad403273,5e0dbad6,47997fca,c0d7ba2a,170a7954,67036ae8,e61dc532,b5fe184a,deb8a7ea), +S(263e593b,10c982d5,1bf89ec9,71f6a3f4,60e53bf4,cb2f6af3,2381214b,2e981bbc,e255bc11,11470eb8,894ead67,c618d7ca,a6b76ae1,a230ef05,3830d028,4a7faf37), +S(f79781e7,a4137ac4,7a9a9d00,9d239b37,6cd0fa3c,b9f5de46,8cba5a11,ffcdd69,d10ba78,896e086d,5e25444,165e79d9,7b3d485,1a448e03,26d8906b,2f27745b), +S(a4d28024,11f577c1,c5d08fbc,457a46bd,428f4d2a,b29475ea,ef622876,593e49f0,e4855491,ac0342b1,dc804bc2,7ae23877,82eeaf22,52874a00,4d4e0d66,b07b434f), +S(87195a80,dc83be4e,cfc9d4b8,29725cbe,11101c26,13c98f2,641753af,1ee840f8,f9fce233,66931c51,4ea09224,b565dec7,22763d8f,6f572057,fdd7d96e,9811289a), +S(210a917a,d9df2779,6746ff30,1ad9ccc8,78f61a5f,1ff4082b,5364dacd,57b4a278,98f1e4ab,af4a1a84,85c6417e,7298c82,c87619e5,500df403,80d8ec01,f384d9fe)}, +{S(6c16768c,433a000b,adc47b10,ba4e132c,f5480e65,ae83d1a6,8aec34d2,c00c76dd,ca1a47dd,66c2d74a,ddb69283,2ea289a6,ae679669,edd80bdd,4ffdab2a,defbb542), +S(f757e860,ed04db61,594bd647,5ae81b7e,d6d2fa58,80cad10a,7756fa26,810b8543,f2aad599,4e491e02,9b1ae256,2c90912a,1c9aa6cd,dfc2331d,a0069a79,861208a), +S(d9f269d2,9aa777c6,9989d706,91403dfd,9025b491,ba03ddf2,dab8c9,af7dc764,1b39b85c,cb4749fb,7f47086a,ce63924f,3ebb4213,af5dfc95,fda796e6,c6b0b8b0), +S(d05e14f6,fe6ca50,a23e9339,e449f771,98e842d4,80a72d5f,8f5e4c06,43547cb9,869e3bea,6b19e0f2,de83fa8a,e932086d,d66e838b,637ea603,5f0fa081,5912c8f1), +S(9f723d81,1818046f,b7512abb,faeb46d3,52d8da9b,3abe819f,3861f9c9,963c583b,37df0657,3f2bb428,6c8b3efe,f6941e2c,4e48d90b,931cd0a5,78a4b52c,6581ee7a), +S(e65f0b42,54ad9df9,681c0db,3428ccaa,11194df3,9e837aab,4564e1fa,254e6f97,43e59d10,54aa35b5,80373e08,cfc02aaa,4f581406,58341e67,7e50977e,5bd893dc), +S(605d61db,589fd91,78a65cb5,99697001,73afca81,23f663ac,5fffd0b9,8f5e7a64,a976a9d,a47745f,447ad4dd,7eb63875,c228b979,a7dda50a,d994df7b,545d0ede), +S(43298aaa,faf20e9d,c2240256,493ef19f,5630db6b,f6376e4a,356bd034,98f1be7e,737551c3,653af1cb,4f8c1e8a,347f50ca,142c03e0,29007f29,c76bb763,b52ed053), +S(8afba782,d6373f0c,54734f1b,4b854e63,bf2a3b4f,23f57a3e,6c2eae86,25c691c6,da3054aa,228b9757,b7321da0,64516249,652fd814,15017584,2c7683ce,1a3638a2), +S(3156d359,e01d64fa,9c8fd8b2,c47c3492,82dd459a,fe89d94f,35906da2,c6d0208,85a23f48,f0a7448f,c57ee545,3978e2cb,6f2bbe54,864477d8,a63775f7,7ff7289f), +S(88e1a44b,1e206eab,49fe97af,30be5e47,25e1011f,312a5222,e9e80819,b3f26357,63dfe52e,10317c4e,227b2a5a,d61b713e,2d93aba7,f0a51e0,b5621191,40c58ded), +S(d10de96b,f2e4a6f8,78e0f37e,15569f3c,b9717a38,7fb98928,6d65d171,4b81b301,2c0a46c9,6a2e3884,e7f3b146,acc170d2,6d12b959,4b75a901,dd535016,f0355ae2), +S(eb36b865,812ae4bd,7893e50,5aef6f14,bfc90c1b,42e75ea5,91615aa,a2101784,1523537b,790b2a61,fb6696d0,a622ff31,efea1255,e1dceb86,763985e2,6c5ca8df), +S(d54be697,e41396c6,3d63f96f,bde9bba2,36ab1649,3c156159,3df81d69,c906fe60,89de1769,433b5678,1f7a2206,ca98258,20d0c7dd,a6d5b672,f77029c2,6bb59f33), +S(d5aa72fc,9063c2f8,bd0fec97,da30dcd2,a5b36aee,7894463a,f7042795,1998c979,ed90095d,bf2d3a67,2d2f1a0f,9737c4d,e8f3e773,c04b77d3,a2345dda,ab662199), +S(ee8cd53e,8ab64281,b5cad323,f03fd06d,7aa166eb,df9185b4,8d0eb0e6,1bd0bc61,4781263d,fc518e4,809e5ea7,7f9df238,1ee7b6ee,ab25c1d9,5cbf3fce,72fdd615), +S(ddc5e95e,2a46736d,9bbeee74,74364bf9,e1d2724f,c43522c,cffa05a8,7d078be9,60908fb,809ae964,98a26cd9,67532df2,409491aa,73c46803,eb58861,7ad86745), +S(ae503a2b,b6250ff6,6ee615d8,41cae4e,751160fe,aef7f33b,dd1feaad,ab236b58,6e53d2a8,8f09f78f,96d49a6,2f98773b,a282b575,ab6e24f8,4d604c3c,8583a66c), +S(8a502d08,bb3cc1da,438c5780,e2120c50,12c1a972,8aaab6bc,5d908b6e,2a83dbdb,fa02e62b,85d7de78,8cf11d9e,ab406523,bba1f912,53006a89,f3a491cc,dd99575c), +S(b52891bf,5acb0019,a8d10b94,87fa47c4,22f83a00,ef539e91,44bd9f7a,d5075716,ae58653a,b167a9e4,b71eecd7,4f4a8786,19c19026,29c0018d,9f082e7d,5920b2f), +S(176170af,b40a3e79,8a88b98f,fb6c578c,d1ab56b5,b7f4142e,b2d84a59,1b009f97,6e1d5682,36176d58,ce5fcac6,4d4d2885,5db107dd,5215c71f,b4076aaf,d31c5d24), +S(27359f7e,8d3e3dcd,ea35f603,d8fb15c0,bd63c08c,3ae4d2fe,8cb6434a,ae2e716d,a0d64207,8fba00dd,4683d597,27f3c67f,3c25075d,802a4ea8,eb08c20b,47a941f9), +S(1e9d955a,2f68478,5227e866,491990a5,62c802ed,1b106bb5,42d02d29,93542067,fbf5f466,57707b3,3f116a23,fe5991a8,90a9583f,fd063943,37a19aa7,e125ccab), +S(b5c4c10b,1b0e0813,37deef6f,c089d2e1,ee14da2d,cbb48e6,74b7dbd4,429e22eb,fdac245,b109947,8f6a53a2,8a1ec4fe,da43b4a9,2ef49e25,8f9296c2,88c48378), +S(bd2f651c,ff6e614b,1d6535cf,c3a2c5d2,da5307b0,1cbd3f48,655623c2,55503916,3715b0bd,bcf29d97,63d7fb35,f9c5b54c,769a863,3517a2d6,8dde74e4,c4277779), +S(c4c2a8e8,f1e257a8,fcd0b11b,30635c5e,782fedcf,f99b0b95,828e1369,3ee0af73,3a08abb4,777a066b,49ec4c01,aa5b0868,f100a473,e555def1,7c5a9d84,b1fd9ae), +S(4aa77ce,15dd97ff,47c1125a,77bcf0e9,d302b79a,e8a919c6,a875e5ed,eab8c2ec,31a09dc4,89a90240,334836f6,302d7e81,57f19762,a9b5f727,6c276e63,560a9d10), +S(3731162e,66a8d2d8,ff4df3e,95950103,f5a03f9a,86bf37e5,605746,cf4be846,e19d7835,10af5daf,724be4b1,932dfac6,23899ccf,7e3e58ab,5bf3265c,667cbf28), +S(6e2114ed,297ba44f,c3926603,bc03a87c,af3e9f2c,8bd84e64,afcd9846,bd9c8f0a,faa6e5f3,3d90f91d,82592af0,7f3a26e2,f6f4138a,2f06a6a1,4286eb71,2e95cf94), +S(50d775b5,f72d186b,266a14e5,254cb5aa,49fd8633,81c36b09,842632d7,ff004130,cbfe11c4,f0b15aa8,3ae8dbcb,9feff9c0,d68a26ba,11095b3c,ba94739a,2091bbc2), +S(8f3ccf31,f8b74b9b,624a5d1b,7cb1096e,202fe5e7,233777aa,859864d3,775732c0,980e32c1,d2c61ace,7610b926,6831ac27,56f19788,ab7a77da,18c421a0,9a46bad4), +S(24cfc017,6da2b46f,a8bb5bf9,636be1ef,fd7e297f,29122fb3,e84c9ab0,c18ada5f,14007044,f8639e59,67978eb2,a21256d8,126a635e,5b07eb0d,97059ec5,6875a3c4)}, +{S(6efcde8b,e99d9ee8,ee0d6b8f,a76584bd,5deb67b1,415e729b,48f3d41a,f1cc1386,4ddcef4a,a6ad5be2,d1e83449,9eca4a8c,73219f80,464a4a9e,ebb7f3f1,b70c9fd2), +S(24fdd052,a1e535e2,4eb79ffd,f03093f8,5778241a,b845b548,31b9a82,730ee3e,c6ff8ebc,7edfd9df,9b7410a,7f54c93d,ff0c682b,152bf4db,1b79c0a6,9889797d), +S(aaaf86ed,31dbf395,687c959,6c445b6c,dcd1fe7e,ba2aa13d,1bf41867,dc87b30b,582b9683,729be5c,85fa83e,2ba2abac,e3037262,2a24aa35,c7753312,1de2fb93), +S(23930d0d,2400db1d,56525bb4,67172fe5,e930bf86,21124fa4,6c5a421e,10b059ea,5e11f202,beca3d5e,dc9b282c,2e86d5d9,30f8f5d,27a5c4d,d2cd6dde,6d1497ef), +S(76ad10d0,bc92ad8f,55b665a1,8ee84e01,2e92dcc9,37e0c604,59bd6fd4,ded2d9d2,d4ca7386,ce0c4c5,fd37da9b,eb8fb040,97d98891,35a5ecc0,320dfffc,95ed3c10), +S(10b324b,e959f0c8,c8a82142,4a8f87c1,fdeb7f88,258e1021,c9cfaa66,b131f3a4,590e672a,daa8d547,161f635f,153fa12,b3500694,677af3f8,90dd4ca6,9620bb56), +S(afdb2acb,ebfdc11b,3577177c,d8bcde00,65151495,79c6ad2b,f7386275,a9314317,87d7786f,5ba775c0,ea47b141,cd0d4274,c7e58634,b64e4c58,f7f0c595,5a307250), +S(574cddbd,59b34df5,30f5dc4,61884ebd,1c867ed5,6cb60832,4a11b1f5,29ebf733,1bfea852,34256807,1fdb4f5c,485caa73,7136e3c3,b4b8a39a,389d7dc8,724f16fa), +S(97ffea2b,5de34e1d,495ce082,d0097b72,e7daddb8,1cb622c,2c14e814,bb0ae278,45fd3d2a,9d1e6530,61b4a356,65aa9e70,43766950,622e1c25,2baab265,6d4ed95f), +S(de627f6a,a7b56d85,535c398,80d0276b,b910ce4a,6066435b,512e5e0,21ef55ef,753033a6,ef89f053,c0e662c8,1557e6cc,d8b4c8d4,5204f5d,e1c8c742,72b96277), +S(b126c35a,d7993bd0,164867c,58c88421,d2cddb6f,d16a5966,7d9683bb,1b428eb5,a9ed1bb9,e9eacf9e,e712bcda,be629143,ad0e7652,82cbfab8,e586cb07,131e5b1d), +S(847b90cb,8837f488,ef027a05,71b2be6c,620cf86f,ead235ad,e76e3408,d0dd1073,9a2667be,6ce36e7b,d76117a9,fdb8f1b8,7c7cb45e,1a03f53e,7b32bc63,6f274b4e), +S(8ea21457,6f1bc2c8,fbee9065,c2cf5c3e,7a3b9fe5,403fb980,96040c2e,c6fe1488,dd75b454,acef4d3b,1b355a63,f0cd17a6,66aa9e65,f1262629,f0c7d1e0,33571b58), +S(9e11bb60,ba4b2d5d,fe53bb9c,598edb16,f3926bea,1cc90eb4,3e05ca34,e83f1896,263d7ea,50d83b8,791fc911,a4f73cac,4d42a09a,85f5ae68,86cb268a,fd562dd0), +S(f741856e,f353a7c7,17db9a13,4ab4aaf9,13c1f7da,cef08bfd,6f81dce5,b1130e20,ee63dd2f,48e15f68,d1acbf49,705fe010,231e26b5,14146c47,1a689960,d568eca4), +S(671ef05a,410b41d9,3b092b04,e523468d,44837d2d,26dba670,27400715,eeefa2b5,686d318b,b49eccbf,40dc18af,f1938fa9,b16d4d2c,c19dd2ac,47c7830f,89b8d55c), +S(59ea10a1,e5bffd6,a34593f4,b986e37b,5294ddbc,60d92906,52c6e9d5,75f88c55,c0a2eb5,6d04ab99,abb5b76f,7b2b55c9,c09d44f3,3785e3d4,64554c3e,dc7a334c), +S(37f2c7c5,69c6fd15,9b721d8b,8d40138e,a8873b6b,452af0a7,89a50551,e9703c1e,d114109f,f9e6d7c0,c51a542f,b2e3ef5b,74654bef,5eb84aef,c87f5096,2a30c078), +S(1d280637,9d77e509,126a440e,b1e56f1a,8723728e,97c92420,5ed13081,98c868b9,85003989,93a4a600,dfd0f092,b13a1186,c1c52dd8,8fc8eace,9bd4f1c1,b47741d8), +S(39aed6e6,a123061c,228d3d1f,857e0c9b,29b70cdc,549b4ea1,9fb6802a,8d8beacf,6bf86967,98e3dbf6,75865a1a,b86d5bbb,10f16e8,4f9104a0,87602c,e6946aec), +S(aa770804,4a996b1d,5bda074c,941b30c1,d1474da6,47d7c4ed,248d3a9f,c3c3c525,10ba5652,b20482f,fc2434ce,ac185d8d,af6cc6e3,61e77d3f,258abc0b,55610879), +S(7626a96,9f9ef188,3ea82737,83e5571e,4054fb73,6190977a,299c2a05,d29f60c7,172d4618,e5f88055,ebfcdf9f,55267ee5,cdf18396,1d5a2a22,55b87ba3,c7d7d2b9), +S(1a550684,d1195da7,c4b09349,f149eae2,5a1ef23,c9a81109,115d93e4,c98cdbda,c31d7dc1,b7efd019,c491010e,30f90ed8,7503c4bb,1b37fbce,3dae199,6609e3b1), +S(8d2306d2,dd8c753f,2b093e62,86fc282,ba3e1dbd,7b4ba101,83d1070e,d2d06e67,97dd14c2,d2c1d147,486a3dfc,d608ba28,d63fc03,251a106c,9811b088,978e3a5e), +S(f31a69ab,97039589,940851f3,cdc98bc5,d400ff93,63794f81,4d88215,4f00db99,56e510be,7f41b009,89792401,13641590,40f5f305,f27fe1e2,db1cd7ae,887ff5e2), +S(ce96b3e9,6eb94b7c,8bdc7b57,efd2186f,62e23e72,f11337ab,be7405d3,43b4d762,cc0dc898,33e7a632,d0fed52d,487f2c60,96c69664,f698a71c,3f7f8a29,4f181add), +S(bed97e25,7d31b5fd,36b41227,462d9122,706da670,d432ceff,5d37d83e,fefda56c,c0cfe30a,2c3b3074,1af492b6,e3797c4f,3b00593c,6806e2e2,f2cff401,6e877ff6), +S(923bc6c9,960f6e4d,ca2a7070,6d160e19,83a16b6c,8535783f,12c5ac69,4aad226a,c47f08b,6b2056d2,8e9f119,9ec6d5ce,b48801b8,7ee56280,d6a48352,b2b42b1), +S(b3cb28fb,7465cdda,85823dcf,819400b,357bce11,23d9229a,eddb8262,53b246c3,cf035ed0,b624dd68,8a31eb5f,3b28e83e,c0bf9453,649dfe4f,44078eac,9345f2a6), +S(c69aa2b9,ab3c5e45,8713a912,e7f95bb,4e5498a6,d4090323,5cfed1c9,c2a60709,2e95e198,85637d55,744e32a7,98c02c7e,b29f3bf5,7cf7c870,7cafdf41,f6710f0c), +S(45996af,5795ea6e,43e0fd29,671e119b,8b8d6ad2,4eac90ec,d27d5db1,b4fb6a39,2c0651f3,1c7d93cc,98d79d7d,f21110fc,8c1dd74b,f1ffefac,a3d52484,f8da40cd), +S(264559d8,7829256b,ed116900,d82d0c37,9f0e4d12,53c68e6f,cf2d41ae,7cddab8b,861a42e6,d92caed3,108439c8,fcbf8d28,8579ce50,c6350e19,3609b4b9,ffe217bc)}, +{S(ac13e0db,846df259,fc38d6,3b0248ec,9fcfa8d4,bcee368b,1f4a66c6,d41f9163,6721b0df,2ed06fda,9b485cc2,aa56f1f3,3a913e99,f6809577,95280451,9ddc96ec), +S(b6b7227f,228da269,a0e5640b,8a2cfa34,555ccdec,2243dd0d,4b2da0a9,b4cb5e4,6afe41f9,dc129d28,4786bb76,17786c8d,42597435,240f998a,f970620,90d32059), +S(460672e4,4f2768b9,842a98a5,ca8b90df,7d9f52bc,3fa2665c,4272d7ad,5f48b992,6d7f8b36,13b38fa5,80ed1d4a,21d196bf,be491b46,49c96da8,342441d3,f4af4ca2), +S(1d3d4ab8,b7c06136,8dfd612a,25f04016,2bd3f6cd,cd9cf58d,c11647a0,d28b629f,434dca08,17bbf964,eb0a316c,b2b0df20,eb2e965d,c4d8d795,1d4a6e66,5ed23d38), +S(9c5d6342,303bc7c,73763cb9,2e3d7069,7d913f6c,1a6e2f47,39470da3,22b7c1b,825c1a54,395b9b41,ccc2e3b5,3fe1092,f04c382f,b2ee3a29,fd59e255,5f22fc15), +S(5c751285,a4b55535,fe24fe27,568868f3,afb43cf,aad1d2b1,c6367daa,ac9493b2,e2388ab4,414c4e4f,e34a4c78,c869dd93,7094ce2d,4f4666a8,2eef8047,3b681fb6), +S(8c1592f3,8d73e277,d3c18d4,ee3eabce,32e86f92,2b27c2f0,1f50509e,74dbc211,399c9507,43cd9e7b,200c255b,bd25670e,cc111462,2d5dfacf,9dbebdb,53ee59ab), +S(85320e36,5f40235e,621171d5,c8008845,890f521b,d7e2cccb,88c7fb7f,a08200c,96bbe8ec,74b5f1b1,2a6ecbee,2aea6f0c,b6d0657,aac3556c,ddc4e46f,17cd31f1), +S(5fc21f20,13403705,687b8ad3,387a725a,f2e6300e,13d28403,569d4cb6,5dda7f34,bb709fbf,be95aeef,c00846b6,a4645b72,dbb4e1ed,866edb57,7bc5d9a8,2b774b0b), +S(fa40e658,588f8a5e,29d380e9,c1a6482c,888f53e5,e331f8ed,9b1273a,56d094e5,5486cff5,3b7baaaa,de8a51a6,1d1a9255,95ecbea3,39955c0e,172de4c3,4762eca1), +S(9f87d04c,5fcc48f,375c40af,3197c28f,c62cf3c5,10fcdbde,5aec79a7,4e6a6bc0,9a6cc172,23a770c7,a03b5333,6922170d,e9409f3b,9846b9f4,41832ae1,f70f5c57), +S(bb66dd5b,2f88786e,736b50,e536a0f0,3d59b86,511e95ca,1bab2cb8,875bb187,f8215527,c76a5af,e5e76a33,eb2622d,5f822ad1,d284c68b,c840f65d,4f731c63), +S(74d223e4,bce2d6b9,b2fa9482,46327e04,18eda6c,cfdd76c7,cda8be62,3f6dd3a9,b7276bb3,817c0e72,e1ab002d,50531065,e1c4ca30,9c6d6f18,bb5796ee,457b4270), +S(80298b62,eb4d3ff2,e10607dd,dbcacda4,3bb30e57,f3c8c7e7,6f9f3968,bf391316,fc72362b,48c8b606,4e428e6d,1ef2ac87,931caf75,e936a33c,228a5caa,c460c5f0), +S(8519f27d,9560acdc,509fddee,9b4a4a7a,8b13496f,14760a08,22609f3b,2ae07963,193aa9db,b98293f8,e70d7253,51d3893,a9f5fc73,6f3c8e65,28a2dfd6,5dedc220), +S(49d734f9,c8eff915,fd66757b,d6484bc9,548f20a,d8c05959,f651eb36,e45cb88,4c594f79,7651b49e,929932a4,59e3bf21,3e74c0b8,acb20907,697a25a7,ed21057b), +S(6a528c6d,19b1e28d,b4d9ec9e,19c4f7be,184ef845,1f41b322,e5932f05,575bcc4a,7350b90b,c22ab41f,40c13a80,18749e8c,275d3e5e,5d687df0,ddd47133,c092eadc), +S(6f3df40f,5647143f,cb93b23,4795d9a7,708db6b8,2e2df53c,f214de4b,61eebaa9,dee10664,54b625ba,34ce4b54,f7285714,7874b5d0,6b38b1dc,37b7471f,9208dcbe), +S(5abfd7eb,c4c5dc14,cbf0e335,f2e87e7a,7db96a2c,b78000aa,64fa8aca,517ee1e5,d65a98d4,20d872e4,4c43997,55cca5c0,bb94ccc0,b25e30fe,8b5a4fcc,7006364f), +S(1bf3714b,da04d769,782e37cb,c4a4b347,f9fc769d,a18e4940,d19a205a,bdd22a23,d0852b21,33b04274,183f4de4,9a20769e,4a08ea16,ca8782bd,84a4da7c,64c928a2), +S(773ab884,a4e90454,ea467caf,f18c3b64,e316468c,b5789fa6,4958f73e,ec3204f1,62213b85,b4838d8a,fa3a14f9,32db7d79,dec538c7,d872d9d2,be1640a2,4e367caa), +S(33a283d9,9b7564ed,6ed10d88,ba26ba,fbf3a375,e00e10d1,577fce27,2c204324,bf84dac3,40736625,cf0e6be6,98072c6c,5fb8bf9d,2850be84,ded3f652,569370d2), +S(62bdb467,596ffefa,22b735fd,d3dfd959,d4a6e187,a19d4c1f,4d647b4e,db380c3b,210a8e93,d1a184d0,a3548be7,6283d180,8e4f32d9,52834c,515953f0,4ecf9acf), +S(ef16d3a3,233f03da,5864801a,c246756b,d1356137,971bc164,b5512067,b369dad2,480e3d32,7f1df8b0,646c3b58,a51126a3,e91522de,ab77d6d2,f2bedadf,1219b877), +S(a6834869,c006d044,a9dcfb9,8a5a14df,86469fd1,fd0cba06,a4e8ec1e,1fba89d6,c1a3e0ff,7abeb1e,8cac11a6,8c1b4c1c,f663e615,9f508c35,f4747f50,84b247e9), +S(203d13c6,53a3c36e,55a836de,b38c7443,681d7b7,c681d71a,38fb0fde,986ce9c3,5d7dba97,573ffd85,b3fd4417,f09192e1,92461c4c,125a9947,ced9c737,ecac65b2), +S(c48819,b8f32966,bd50f162,30f5c0a1,45cb3570,d9c4b104,4c306696,2f4d6667,feb08ff9,1f543c1,35b6e0f0,b21d7624,91ac096a,181bf093,fcf8f4b7,bf6559a2), +S(31441031,ceabfbf8,59bcdd8b,6e177f91,df7bfe08,f9015172,1ead3acd,ab64acff,e36315bf,6f087118,32894704,8d2fd259,6b8beae2,e1917341,d690a1f,786db5f9), +S(e3e4750a,310c48,38920654,b6afa032,79589d52,74e48139,6e22d9cd,3c05fbdd,f05868fe,5452da6f,fadcafb6,69e5edfb,4b9a7840,3a305004,345ddce1,eaca43ac), +S(3659ba70,60d8200c,9512facb,5c730111,4cdc2b9b,aa5bde14,8ad9bf9d,d8f8fb8c,b1185617,f91fe5e8,ec68da07,138b6780,e1ebd12b,1bb44eca,8a1b9472,8337585e), +S(1a46b7e9,fe99a4ea,492fbc90,3281b924,6831fe59,9360af53,bde4ce8b,43ed5996,97c317e1,5c0e23a8,f1c11f7b,5f9c140a,af786b56,10ad8ba3,d11b12ed,17379f81), +S(f16a409c,677a40be,402f8efb,3752373c,aced053c,6f702b82,8bda222c,a412b6fd,d5becee8,ebacd866,285958a5,8b1cf1b1,e9abf9a6,db61435b,d9725187,135fa955)}, +{S(32c932eb,6fa35974,90a408a6,ce962d7a,ef2bd22,72cdaa,cb80f798,9836abc3,3e145848,c2f8197e,f0264d7c,370d1784,7d21a09c,77fd9f7a,73245ce7,2ce5f3f6), +S(49d837bb,63890b4e,8a4a63ea,6d88599a,c9961c20,80dcc955,aca6a101,bc935f16,358a7f6d,b540ac03,78d83bc,304cabf1,84c7580c,46c258ec,58f22254,e3e03aa), +S(23516ddd,40dab9d8,63dcad6c,cd325503,b783379,d870ace0,9a0b238c,d7b6b2bf,b1fb8268,a7814efc,54f3d637,88956b67,a3997a31,10a738a4,94786d95,a5fa1c59), +S(6b4e215e,df56e6ce,6378fa98,5d604f68,e3561275,788283d6,c40cb249,6d16310e,cdf9537e,e6f4304,dbcb9df,f8b97a71,a12f014e,29867e5,6b09b388,78c9ce8d), +S(f4f30433,c933dddb,949ad868,cc0d52e5,247149a,7ec98f12,3e7f63b4,acf6b7b9,949123eb,9fb848fc,d7b94401,a64b21a3,53fde44c,d93dae3e,b7a2d3d4,78055af2), +S(dc3523f4,cd24be1b,30787dd7,5140fff,b66e4487,55e9a3c9,6124fe59,c07faa28,47b945d7,6d37b855,8ede59fe,e297a8e7,81d3ea96,f0a81588,b68db767,9b9641f5), +S(b92cace4,e31dc724,3b3530b1,f90de1c3,47cc39e5,5b247455,a1296912,4e3c2a09,78f89163,c735cb13,b1d8fe7e,547027f,68d8f864,a1f093b,22c0d9cb,95fe28c2), +S(8f7ed1f1,77238a68,bbe32e4d,ae6d67fd,be07c9a2,9fc6b940,6ef81a77,65a8fb75,98e627d8,d32095bd,5913daa5,920c5c60,334691be,537b08d6,da5b8c19,7bf81c8f), +S(47fa27ac,e035176f,34c59581,8d3dca2c,a2b40e53,29756c55,7cf81f75,4f99316a,ddee5921,f381ce26,3634a34d,1b4f9513,4d9f0e50,5e96bb79,b87d98b5,282aee7c), +S(7584cb68,60ae81f2,e0df701c,97d7aa29,8132cb96,fee4ad59,15424bec,2e280dcd,4b76458b,e3926b5b,bf59ad77,da4a96c9,1f9147bd,88a234c0,74b0e09c,a6993228), +S(2cd4c11e,70d432ff,38550aca,481667f4,d09ad11f,9aed62d4,968492d7,5de28dae,82514708,3e5bf46,341177e8,9ad2cfb3,a215578c,52f9436,d3952432,e9acd430), +S(2b524c99,2b18a6e0,30863716,362d236d,e385a10c,3679eec,2774edb7,a1a89be9,1abb3b28,3477769a,5c7b4580,93efb22e,f2e61296,da90d4d3,1d6b2ff9,1766f89d), +S(d642c258,9d0e47ef,f5b2b60d,9321db58,727315ad,522daf58,3bdf35d3,336f1081,1019505a,994030be,484e5340,abea0b7a,51276c99,29cd1f1b,9d19798d,aaacf3d9), +S(3e5e09b,451bcf5d,549f1d66,b96da0ea,25e63270,dae59606,bfc3165b,f89f29fd,2ce591f5,32d57be6,4fc48aa4,ba40231d,9c104615,b76ed6bf,11957694,16d2f0e9), +S(4756965b,82fc23bf,64041d23,a23cba32,cb71d3e7,ef3e6c03,51b20f3f,dec049b6,75f3a293,eae07f4,362c47e9,44a78561,323244ac,bcecef0c,6ba2f5fe,d1933679), +S(f296e9c1,41694ce2,c197ba85,bb9f172,54fc0bc7,f89347,a0e92b8,58491a39,73c7fbdd,91c88ce2,bbcadaae,df8880f6,aff07e8d,3a1ce05,a468e3c2,3008d98d), +S(b437d387,ddae39cf,e26edc85,b0e600bc,2a199b6d,b521f9c9,88d921dd,7e6fc761,ce2111f4,d937905e,2af7f2dc,559f9eb8,bef286dd,909a5965,53c7f61c,f51aed18), +S(bacd4a38,f3e1b7b1,b601fa5a,2a579e87,459fd189,a607314,5a0dcfb6,1ad3c21b,8be8d6b3,9553648f,2a94754f,4c6c14,c4917296,aa9987f0,deeb7e66,d81c3777), +S(d8164748,8ac6bca,945fce70,e8f6a256,90512c8c,dd4c8fbf,b553c131,96f7f607,16b75474,65a80a67,86b5246f,e086d32c,4db03b83,58271938,41877c38,2b5bebed), +S(9c2b0749,cef57b4e,36b31328,e01503dd,ddbd2834,5cd86ca2,5224b967,1b7897d5,f020f978,4eed44cf,cc4aa33f,b2eb4b71,f24b5f3a,a8dc1d72,569bdefb,5f6276fc), +S(ea277814,9f0ab428,63b05bb1,c113ea7b,91afb815,e8f0791,12c11573,eb044e4d,8199dc4f,4e72b691,1c562ded,1220aec3,ab967029,139d30ac,58c753d2,f4548030), +S(4be6fcf8,40673659,5a9e4f2e,877ad7bf,28e25177,63d74238,6e43e6da,1c1c43fd,eb5456f3,d1c40592,2eec37ab,3e0d08da,b7cd257d,9babab02,44e5b2d6,a827a7cb), +S(3f1e9ab5,160733e2,9e7aeb6a,378d169f,9be5c266,a6462e2d,e736be07,f88c1da1,907fa0b9,814da057,9bb11309,aab51902,a0699aad,9422e1f,b8f1a8c4,aa9d4399), +S(eb730dbb,1ba9b2f,50453837,35ec6da2,ac4b5019,86cf03f0,3f5061e2,a28285f9,41dc3a0f,f42fb1b5,d3b464a5,6e305fe5,c60c4561,d6e5a6a7,8cba87ce,15c392fa), +S(aeac891d,f7032059,54d0bab7,41927702,1a595a4c,37bfc34c,5d315876,3e85f3ce,168f8260,1331b5c5,edf941d9,9f1cfe0b,72fd2a1c,3e4bbc2c,c62d47e6,6399105d), +S(667e04e6,daca6315,4888ac26,a268876a,f4b754fb,87687ca7,3c4cff77,d6dac204,1826a26a,cdca828,8e2ac81b,855a4d40,86f3009b,162fba82,83cb1d17,b9f7aa4c), +S(240ec754,24e46326,8e2e4ce0,240f335c,78c46150,1e18cedc,b32e3c51,77ade3e5,be09c744,cf6e9c6a,75976c03,530329af,5e11e5ed,3fb13e8c,af40bc5f,95872645), +S(7b83e4b7,70e7a442,3efbb501,c23881c5,2bbde4b9,d5aacc38,7071decf,79690025,d242ed74,441d1ae6,61b97c83,70be2f52,dcbc2831,1e8707e0,1b44c827,420dcd45), +S(63589c41,fa8975f4,c8738f57,579cc0d8,447218c,69da1a34,ee06af0c,215f6c27,c34f2ede,7589760b,80dbae48,94a3c13c,7351bf5c,33a35351,9988ba67,c2a56d48), +S(db092b0f,4638ee45,190473c7,cb60cfec,45c94d96,99aaf289,82d28af,16ba1c66,8a96ecdf,29ad2fd6,3a85a7fc,b73ab6d7,719bbd6b,98d052b3,3a0cd91,ab924f46), +S(11c4dd8d,3eddc0cd,9a832dd2,dc91c8bd,491fdb51,f5da21c5,732dfb7a,362b8df9,ba4c2789,740b53d5,51bc9fbc,776f049b,e848182d,9d13abb7,e7cd860,96911eff), +S(a65a3a01,df3b5ef2,e620d431,49fbe1,4d71457f,19d1ed35,aea39d57,89303fdd,86715f6b,f300a390,470bc272,6f12d389,7979e2fd,b0512c35,252bb571,fd19752c)}, +{S(d8558716,b7033a9b,29afb346,fd71663a,79b6e86,2719bf12,6e532dc3,f581b7d,a790d460,1e5b2630,1ad6ec43,62f79120,d75449d,8a500e2e,6f17c021,8037a405), +S(842c01b3,54353026,c43dedc7,8829ead1,db35b63d,8c4d0d36,8cd7b661,2eb5e11,f173cab1,a37ee0d0,68e097af,17bf859c,13bb4823,255abddb,f0dbeffc,573e06e7), +S(acac5cae,414c3556,38e293fa,e7cda051,18924e9d,abb81bdd,29123768,c7f21443,5d17b909,5b997254,5f56770c,dcb8af40,e37e1a8b,6e01a989,34ec22fb,f7d04537), +S(c8e73810,c024c6eb,d5398bda,3784261e,542279e5,3438d49e,83b2639f,80889aea,7a2183e7,be4f81,b0337993,935657c4,c55d20df,729d2e8d,b25af238,f3d85f4b), +S(f78c5f53,5e7ccb53,555a6f2c,b1de1c5f,da379360,f6a7fc52,eaf86ecb,dbb3bf90,cf2d33f5,eab2ee1d,5a32eea3,18f9927b,cc982fed,cc9add2e,2461ba14,9def0292), +S(4cd40c43,bdb8a042,2babc95d,eb00a405,59519074,5906a8b7,b5ea00da,b7f995f5,a0bd1c74,79125d2f,5baec520,21fb7c62,415817f7,2afb80,b2315dda,40cf4c4b), +S(647c5950,f8a7fe9,e6945b3d,6da91932,b486a4fb,ed903836,9fbc20f9,a849ac08,d331cf32,d72e148,b47af547,6794a33d,55f49ffb,be47db02,7d2de73c,542bbbc5), +S(97664e78,980a49f0,8269ff19,649e86cd,7da88a76,eb1441d8,a5f3fd2a,6ea335d2,b2898268,9a8cd91b,b1b16be8,ee46b4bc,252f7016,f72432c0,431f1264,8d7450a7), +S(523f68b,b39c2ded,81d22a4e,575483ee,d8748c9f,52c06081,391c27d7,7afe3805,5c331672,4464dc47,cc9cfe32,864b6095,ee8bd6a8,42c1af98,b3e33183,a46e2471), +S(cad866de,5cbf4938,989b835d,5aed958,cd7c316b,980b7c76,2109d688,d7ef5b25,3ae79c30,e77d6d4e,fe404b8f,324179c2,f677f434,8a1c4367,2a0fb5eb,b706607a), +S(ba065cef,b47170a,d6796033,d157fd1c,f22052d0,7b7f9992,6cd58e03,316f95a5,26177c08,bc535702,7f5d03a4,9d982637,d74a6b20,696be76e,742243be,b9ecddca), +S(27ca8178,be756f12,22cebe6c,d05310d8,5a6c4f59,eec71613,7777b625,e6d44c97,de547a17,ddee9fc5,1fecee01,45f9cda1,b65f097,5d1b9544,aa2317f5,102537cb), +S(bfab1d94,d04f4909,dee00998,78f77cc7,d9de94a7,96b5b770,5f3c759d,2ae97ec1,6ec39a8d,9e900a79,b8b88098,d1e5d79d,b75ef91,e442cb2f,27ea531a,2db21bb9), +S(b48a4f25,9d82242,59f08a08,29b05ac8,ae6b97b5,56cccb84,20a479f5,df92701e,beef137f,9f9acdc,8d31a780,2290fe79,9d9470a7,3c8a01a,35abcbee,9730d17a), +S(e3f5d307,ed2f2f13,d23ae5b5,9dd567f0,8161996,776d506f,b53e14f2,70a52370,40ecc697,7da3771f,32a66438,cf70ea9e,550194be,1af85a08,c8a4515d,32365803), +S(818b0462,d5a815b1,57216ab2,4d795886,17cc99bb,7a7abd91,655cacb7,ba99335e,c6ad05a6,7d2a391,a15b6600,7716e02c,9fe40db2,f82283ef,c9c0a7d5,ebe854f4), +S(7e3c52ed,23220b73,ba47613a,bf39a9fb,b3a6bb6e,22c972a9,3ef21a61,50cdf830,b3e4a95b,875719b3,bec1b113,9e29670d,4ba8f39a,2fb76700,f69961fc,bd01fa2c), +S(594e4129,9c1a117e,ce8564bf,ba88ce04,297f2e14,7ecda07c,5f12913c,14d9a5cc,60bd54c8,7395fee2,7fedccfb,ca9524a9,b5750b2d,d712621d,e73e0692,46c2e347), +S(3686bf4c,f387e340,6fc314e,f02c637,ee6f5062,ee9bb567,235b00e6,4d516648,915e5904,b106e057,a0db43,151ac9f8,4871e843,126d5285,337dc3b4,52c67165), +S(338dbd1f,42480753,516d3cb2,c535492b,72849870,a7828b48,643dc143,b966ea61,e51f11ec,86104334,9e9dae17,78116032,949c66c5,3c4d441d,3c88cf4,c7ad61c9), +S(56f935ae,f58bb403,7649198d,1a5da704,26fd944e,c5694c18,38c94287,2130215e,a9c48fd0,3b059474,e528016f,9c998e02,cac7c40b,8c859852,b58b9082,b638222b), +S(1faadcd3,da472591,cc723754,82546c81,c4f53c14,d0d8dc5e,ab95a58f,379e6899,5bdcc45f,42d0ba3f,783a0806,a5d08c74,a1b1b9f5,a559248a,8681b153,74e74958), +S(532d8cd8,fdf838c7,70b87ca1,4703a884,116dd928,74acc660,6ddddd61,8eb053e8,67a31325,853db4d,3e5877b1,c76e7e39,468d2d77,37cb8a6d,af4f16b8,17cd8ad8), +S(8a8cbfd6,d45e5740,aa9f0a21,f40e3671,ef897fe,bf2bf753,ee2d2f75,844ab648,d00eed6,efefa26,46c36895,3a54045d,96da4cce,8ffc554b,9bc989ac,2f62acaf), +S(38ae095a,3c705343,38e542ff,6789902b,cc1b0b5,7763cc43,2f50cd9a,d26d0f1f,100de239,87026f09,e483839c,fe9e1f10,11bcfafa,662a9331,95a8e4ec,e4fc804c), +S(82d9e5a8,385de1f4,fa541796,a00533d9,a3aa4656,74583d07,c4b3c344,b6ff8cb6,70bf2bd3,5765165b,a466171e,f26439e8,f790e178,f67ef5,d2e15e98,435b4261), +S(1843988b,42ddec86,dcc6c9ab,36b381ad,a0ca745e,aba36bf0,237e2830,579aaafb,f1bdc95c,d76337e,cb3cfd65,d9c30b7a,e7c7d667,65c9db5a,6130edf5,e240cec4), +S(a32f7415,9c2743c7,2ef192bf,4a68e838,97a86a0a,3997d1ce,fda3c581,b4fbe683,8862903b,db791be1,dbab5031,ca57f161,b6449bcc,db061438,f45e610d,50ff3bef), +S(b09dcc04,d9c30c35,2bd63880,a766da1,f6314287,dc201bbf,9605516,3db2a09,7580cf9b,7e30dbf2,8f72e9c,a5152ff1,956ae42b,3e952b18,512824c4,7f4e5b9c), +S(ca07cbfb,b24ad1a5,edd9a12a,8ac54157,6f3f2ba1,4b878d82,ab7dc996,bd7e2c95,5123ceef,cd20f120,b575dd98,43ef9936,c53cf90c,c481f340,fa166452,72af1c8d), +S(f8058324,c6b9c2e7,e62147e9,a41ad78d,60e3ecf4,17524c05,80832add,f11349e2,6a39f1a5,f577a932,3217e559,f15eeddc,af6b674a,9d921772,a053b960,a4dfd633), +S(2e3c0532,6255d80f,a42fc69,d5c92aa4,cd326a5,3e8535f0,435efb7b,694a09ec,ffe0076e,9a93904a,42251dbf,47d03e54,1fb75ac3,8f8499ae,dacb797d,7738c9b1)}, +{S(7bd8469f,80f009fa,b4960cdc,bbfbd4ad,d8e37bb,a4b2a34e,d5c95d17,7a94c207,f3062154,c3bcc160,b2aee99,aac98446,516a277d,85b37fe9,34be9359,4af905c6), +S(139b7c10,ce844844,f5d0a9db,bd7e1679,17b37e93,9bb6fd2b,4f19643,f22a6af1,32d4e929,27f5951b,ffa4ddde,4b091ec8,531a6f23,f1772c9d,ada292db,2b88c1da), +S(f49cdd14,14b38e5a,2dd34bff,3d01e1cf,ddefb954,2a641edb,df698d83,774ee70,5c10a6d9,200253e4,a932a42d,2e770f18,69d0336f,3c44f480,ce4a3305,83050c31), +S(ee145304,4771c862,745f03b,4776ade3,104ea0cf,eda8710a,5fa108eb,1e946826,b91f14,b6127808,f1175b72,2c09e02c,66eae622,109f4156,261d65ff,506b88bd), +S(c9ebbdda,867f333d,39142483,2e4150a8,c98090ec,d8ba9c09,3673330a,8777d790,c46d72c6,6028477c,e4754960,d40bd10b,b2defc1a,17dbf018,538b71b2,d208372b), +S(707bf0e3,9f2c8c6c,73a5d0d3,3edb32e3,46e73ac5,dbeef6c,60fb5ebe,b95ece24,adc6edbe,151bcb7c,2ed5fab,1cb9b2de,3ba2f3c5,ca762082,902582cd,e9e27f54), +S(4a002722,9fda7d33,320fc533,27b6c9cb,88a09c2d,e95aad01,65f68f45,1c82e2a9,233416cf,1cc1ee38,90816a09,17c5fd0d,da0bb8f5,d33c709f,6f1b07b9,916282e0), +S(8efefe27,b45a4cc0,3088b6e2,2a0baeb0,3e772763,58af3217,f39c7222,1e20b59a,b9f3fcdf,65771acf,cc7b7486,9b10bc3f,b0e8fb2,960cad82,24ea2430,fdad1634), +S(7bd3815d,6779f321,195047a5,b1772b19,ab29a99f,cc082e93,c442e927,b1ddb235,eeeb4bb7,480f3dd0,92e627a,a042533d,a9eb598a,6cd1ed9,2d75aa89,a592ae8f), +S(883f939b,6bc9169a,3860d36,9894c4b5,2863b5d8,d0348c4c,62368a94,737fc3cb,96e37629,c05b7231,8800ad96,8e922f7e,5b8a2c39,62a25210,9b3e4949,4b24934f), +S(4ad8cfb8,e8ba3265,4d32a656,76822176,95c40b92,e97c6d3b,af26449e,149f4b3c,491d3eda,89930ffe,e401b994,54919947,7ef33a8d,6cfdfb9,eb28295a,c5ce94fa), +S(ff15cd1a,4b185632,c6f11ee7,19319bd3,abce5167,65539608,b1ee3a4e,1671369,24df322b,ab157296,40aeb039,c00ab8,91c96833,4142f87a,1e00d105,b08c63a2), +S(3fc8e63e,995fda97,1d09d96d,4c84e18c,3e0f4d6a,9f8bca41,20c7c832,c4e9d49b,e17b239d,8e6f7fe7,3c4e46d,3aef9040,6bd631f2,da1677c8,db698484,85922ae0), +S(d88b3d3,6bfe995e,45812e9f,63e8b6e7,d5a87562,1c4a23b7,ab46f6ad,2f7d1e81,63079694,7c97b00e,311bfdb6,198c2c4e,eda57d09,b17fd74f,7140b40e,d2842d06), +S(da6971d1,4c0e9c37,e5b1379b,9cedd83e,218ba47,95e4af56,7956922,c64750cc,a14a0bd1,ebd0727a,258c1246,3aaff478,fcb490f0,53d08a40,44cedc97,61be43fa), +S(d098ccf,e2fee442,74377e1c,57d0b924,45f0954f,7af643d8,b7ed5d9e,956fba23,85c99754,17df24ef,2786621b,c0be5069,a9c59da1,61e14759,ee26b524,e9587d18), +S(633f9b18,9dd98f3d,8c4de,528f7170,1c9d5972,cabe3219,cc4e5f0e,e7e094e0,3d69c877,28c859e5,d9e8ea27,3c04ec98,ca084df5,d7c9cb34,9fa537ad,f7da0b5e), +S(2e14be9,af0dda46,8d59df19,9ac9edb0,c875f829,5715cdda,5ba3bed5,d54fcab2,a04688b,64c5d34c,752396d7,f864a9e1,59eea9aa,db8c93c1,5b4d7cd2,539bfa0), +S(adc92567,7678b197,1e45ed31,38a991dd,a4cd3586,a1ce1498,3ea30be0,642a2dbf,70f2c69b,7e47aa55,cab6ab22,e6482571,e8e1ea52,a52df934,d5ab99d9,acce2770), +S(ab89aaff,b04be186,183e8076,46c64111,476c552d,10df84ba,10a1efdb,32c01162,fccc1e20,17ac63a4,b9f78ca5,af245a74,4174c952,cfe29491,11ce1d71,e4be8f87), +S(1195576c,ca3a49b9,4db3f827,1ff2308e,66b66739,a30d73cd,e8acda4,a382002c,6a2be3a1,c6ae9f0d,b314a7d4,728977f2,17e7c7d0,199868fb,c7f79d31,6cd7d32), +S(8a15bed9,bfa215f5,42c62c89,da0adb8,c68cbc33,d9c879d7,a2f2803,b7068556,ef437bc1,1786cd73,6dc321d0,a3360517,3e7572f5,bce04b7a,3c8cdb85,cb56e697), +S(b4521d6d,f9b20080,4d3799ca,4cdc87bc,ea970d60,a3005071,e910210f,5654da88,c4ddf348,2a23e98f,b86ab9e8,4decc6b6,ad18d879,e96435d7,4b944d8c,f7cc1587), +S(4074523e,b75634f7,6442c3bf,ed9a52d4,5f6636f0,77a10e84,5e6ed950,b673a9ea,d8889a02,ec95b511,aa74db1a,10c91547,45b89b57,981011a0,9d4ce57b,e4e1f032), +S(b2e71794,e6ac98d1,ce532974,df79215e,bed8c668,561dc391,505e9e26,8444a858,94d8ff19,b8a74599,fbe5f471,e7f3e1ff,e0238cc9,2504f99a,9c4f5fbc,2e482854), +S(2e672209,8a6b4ca3,905a8910,6d23daf5,aeee63e4,34e7bade,70395df0,e5a1af87,708e9fd2,a3c0a3b1,b0e03f96,c3d477d2,abf6dc0c,bb8a7181,ca4b18db,ed12e3f7), +S(7ec0fbda,63fe7404,438e36,d567d9b0,bdf18b09,d929329b,24a8bc91,816fd433,f80ab84a,99d214fa,5d288e3b,c2b5560f,a1791412,9c3d16ff,cabed23,736e4f85), +S(f166252a,34572146,8bf3a3d7,bdd2c67c,b0d36b02,d7a70033,add26f97,128b1637,134eea4a,42b482c7,ad625407,bb89a615,656e3a2d,232f4bbb,a33660b2,403d6f63), +S(7af860e0,27d3b1df,aa0244e2,51f9459e,488afbce,6a3aa610,e5e223b7,81ba2d93,6ad22116,415c668,7dd3f4f7,b5a00599,bd35705,951e1093,3f85f815,4d0c8af7), +S(e4ad03b7,e01c5d04,7030fe59,6e7e7960,77d9847a,e604d2c1,d801a5eb,e21c0731,c7757ea8,f57af58f,b64f3eb9,c7762bc9,544f28d,a80d760f,c46b0c9,589019e8), +S(ffb2f941,f27aa8ad,6a59ed01,24e83bb,d49f2588,a5602389,15329f6d,f77220dc,6812c00,7dd44185,fc3f0687,6f7a62d0,d31adc40,c0a1a060,c67df13b,e4cd4873), +S(42ca15ab,9f245041,ce991e19,3d696f4f,4c277df9,8cad603,8ad0772c,2da6e03,972d10d9,37e3a836,9b831b2e,347ff11,29917a59,7ef94158,7c977604,73cb849c)}, +{S(576abbcb,8b768480,882aefc,81380709,831625a4,b9de63a7,b9c3390b,9cb4c7fe,b49453e4,6e17bbae,2f1f8f9b,91c3ed04,80d5f194,33917cbb,d28b878,bc6e6c4e), +S(f9d8a157,c151181,3e085c1d,ef2958fb,df2a17b2,6b330a0b,2d512c87,69e5c14,7eacca29,26aa402f,f8b78d57,f5e02add,91087da9,d607bb41,b56a40f8,f7b19b78), +S(d31dff73,7d2d3422,7fe39dee,b2eb4bcf,dc84bd39,d6cfc4ea,ff09812,23400a80,4af55e8a,fe8e8ab1,2e2c4463,d41824df,7b53e44d,efd946ad,b6128214,4244055d), +S(9ff2bce8,a9fe6c7e,e68a8292,f0d2f4c4,8d963c47,63018a55,89a2c130,667bc861,eb138923,94aadfc9,6eca7c5,78c0fcc,bb31a40f,98d02e93,a140abd3,cdf041b3), +S(1397cd8b,aed3c601,b6eee616,243a61dc,fead22fa,da50db4c,1f9e2776,6e5bc9da,534a8e23,59316503,cae233f0,3b6ef0bf,1c7e0105,119d1a49,ee688f04,40695c66), +S(4ee38986,511024ab,5385f710,42bc3778,7cbedd0a,ad13ba24,b77f42c8,2ae935d6,cf87468,24a38404,f313965,a64c927e,4ba0b7e0,140f6b36,47e2049e,35a74e4f), +S(7614cd7f,9b5f1455,74d0d38a,370f69ca,f3050297,10af5242,e5ccf19b,187dd189,b946eded,e4b72db1,6dad876e,396e836a,875d7c9a,28a9c739,f665c741,29ab7648), +S(67fd2372,5bfb445e,5254bc42,f7dbc1a1,65bd4017,cd1019b0,8a3f96cb,7b3c7cec,b556e950,a144febd,a81dd3f2,f729ecb,fe43fc78,8658bb7d,2b9735d7,b06a920a), +S(57572b1f,1f17070e,e9b30b6b,c7168cb2,4741ec5a,b3496b1a,c06ec0f2,5f910fce,8cfe2940,3dc97084,7ab28da7,167e78fe,f2310c83,ca476a97,91ca35a9,610bc560), +S(1f111332,1e31a294,cab4df73,5a0ef333,e753c2f,7c83705c,9a5bf27,1321c4f8,8fed26de,202c92dc,5b51b13b,6e9bae41,3c7c88d7,b858dd72,a11f073b,e2945f9b), +S(23c9e313,b04eebff,15fb0625,43de6975,d19decf6,6416f4d1,855083bb,d738f882,90673370,f380ca49,e876d5f4,b6649de0,24f4454,29cf9d91,96f4f196,8a49ed99), +S(b9251407,6ef7f01e,379aafe8,8f22c156,65a85ead,f671d8c9,89602c5f,804725e7,b3a9409f,7bf973b4,aebe08e1,5ac65562,56983f89,23415e0d,eeda4f4a,c0d7c5f2), +S(1bf9deee,948b3fe1,b4345800,51c67266,8fdb7af2,99275a83,706f9716,7e38e38a,688fc563,771b7d27,f9c09953,c40cf009,a55d7329,5fae0b7d,8fc37710,729a3911), +S(34e20de5,9d00dd45,19a70b3f,2994fc4,588ca9b2,beaf6afe,4a1daae2,10692f33,7804aff0,a43f1ba0,438c05ff,8d013e3b,e5180bb7,3a969825,fc97ef52,6da1b6a8), +S(80fc119e,85e88b0c,8c84d23f,9e44e96,1c7722d8,51d4c9bf,f1824fb3,365823ef,efee941a,a60743a,28b6ffd,39762f9e,437d2b00,206e718,7fc423bf,4eff0caa), +S(89ab0f45,e3860393,f24b1845,7578fe79,b812926a,6bff3788,c8baf283,89fdbf0e,57d4fc21,42bf446f,8e4d9331,659e7673,90391fe6,62e77ee7,f7a4886c,8f440c8d), +S(1f092931,664bb98b,79d8fb4c,efb287a0,f72641fb,1cebe711,820c92e0,42f26437,59f63ca0,b8e2e959,a97b1c1d,1cfa4c02,380dc42f,db7cb5b0,995ceba1,d7e45d94), +S(95ac9f36,f447928f,344eb4e1,9ea806,717600e5,148ad222,fdd52a83,86bc3537,cdef5355,e928b1e8,225b5a53,bb976822,6fb50d1f,6c6cde20,758d5ab0,e9f28543), +S(a9ce5ddd,9941ea69,1343ea71,c85fcd73,6269826d,6eda5008,44cdd1b9,4a66044d,29504563,1fcb7590,27d904c5,4ffc325,2ce3c8a2,169f4649,907db751,2ef3ce43), +S(2edf81,45c4bcf9,62425707,ccb36a3e,7fa1fadb,4062d14d,f78771eb,f3ec15d9,dcfc961c,547548f2,73206d9e,aa0d829,a235f66c,5afbba92,68fdf9e6,abc8260b), +S(fcf5b985,c935e207,92907b93,e9976ceb,ed320a14,3cf286ad,b38540ad,b4077dee,8a0e0b4d,1ab114b1,caf7d0d,f749f219,b75acea5,6a71b3f6,aa18557b,1da85262), +S(2bd4391f,42b70803,2baf4816,54569f48,95f1434e,be6f146d,41447f45,f14581b3,dbc9937a,61f43af7,42635810,5cdfa02c,49a5186,ce67bbbd,7ced2842,19a37506), +S(eb00deae,6cf69ccb,abe6b93e,e5493e05,d22e53c1,b069a6c,4660330a,4e3bc069,18002f2f,61b08dbb,60c784b8,4c6d71d4,6b004e6a,3089a0d5,f853d659,83242d9b), +S(c7c62a5f,ce15326f,25b2fc5b,697cc7f7,26d231e9,e7e9f15f,5998b8b0,10605524,8ad4b370,ea0506f6,f25eb16a,78f87ef2,f408cd17,fa4ec63d,4ee21448,1d5286b7), +S(aa1c2baf,632673de,6f6704aa,5a76c077,be0c24b5,223de654,88d1386f,15a1a002,de4648e4,fda7db79,41efc5e8,6fec516b,c6aef164,62d6dc08,fe93ebc7,a85261f5), +S(11871161,13c3c670,e7f5366,edd22282,1f76ec98,d1a3500d,f0e483d1,e53f2666,d0042c9e,8dc1d72c,f53836f3,2c76b5b6,52fd5ec1,9e8fde42,aed1a7e0,9d242745), +S(e232a92c,9ffdabcf,24422182,34078534,6b6b79f5,983ddd57,2580c3df,e4ee4118,6c1144c7,471342d8,7a784fe1,587ef576,483f8980,bbab12f9,35aa0d84,83c1d76d), +S(1ab6237,3998ded,e50aec45,8043f830,8a7b4564,2dd3c9bb,4804f98e,a7c2e0c9,5528e158,6a23aec9,81f04b51,b90576a9,a9e7feb5,53200e51,e604898f,e55996f3), +S(3bc24bc9,cbc58de3,46644de9,b17ffa7,39a0f7d8,83eb9f52,af19eaf4,d8d52891,f71cf5b,7587c275,8014127b,f404b70b,b257bad7,f5b78d2e,c792e1d6,b2fa4493), +S(a2bf9afe,e6eec182,ef5866a,b4bdfe2e,9d045323,343aa422,8c1a13ae,fee515dd,a5ee438e,3aa35484,c5f5a1d5,43fa15d7,ff0d1c55,6571678b,a3c5694e,f93cfa1d), +S(a0b2b4f,ed0ddd23,8812806c,fccdfa9,7fb3b42a,748721ae,6477dc9b,18953133,325ee7d3,4a540d0,fc3e3935,79ba7372,905c7b17,4f12b456,b43db5c7,cb50ec66), +S(e7b9796b,5ca006d1,632f482d,7f0fe393,2cf16a5a,e104eea7,a7ea1c25,1073e879,ed476773,e6e961d0,20bdefd5,8c833e35,634a40da,1256750c,c718ef75,45575e97)}, +{S(a8565dfb,75f8eea8,ca9ca6e7,c7d18a5,bf3e437,5d1f4e87,68d5f51a,57199ac5,daa7d7c6,cb86b215,a682141f,2308d9b,4c204196,eb779f32,fcddf0a2,da194921), +S(974619cb,86016199,20f507ee,62d10295,44abdd66,456952a0,54e945bd,7890250f,6c8d8bc8,21da8234,1ffd0cf0,548be1dc,a1bb7e1f,47354dc8,3e5d96c8,2c9676f3), +S(24bbdc24,1396b6e1,75f23a6,4bfb41fe,f8329b80,d306586a,ecb69e41,2a2014b8,aa6448ec,f00a0710,27b46f09,d696642b,9274ce3a,11a3e986,e84536e3,7fd7b2f8), +S(eed9a6b4,68004486,e3bd388d,591d3b65,2f35a3f1,9401e5de,81a86f5e,b7cd972c,c81f9aaa,d7300671,b3dbdd73,a095c79a,d73ffbd5,9f845eed,9fe3a57f,a41e9468), +S(5260e0f6,fdc6858a,8d519d3f,6c71929e,36979b65,431a6f3a,a7507797,e54654e2,5af860e5,fbcf9676,bb00c329,d3e2e058,efc860e5,cb9006ad,224caa32,9fd49f07), +S(11e53f67,d844c511,b8118f28,de6ed9b8,66b70bf,214d4d1,ed79adfc,18f7d6bb,20dd984d,7b9eb626,77e411da,2e823045,685a4bc5,2a3f4e5a,3aedea95,1060b330), +S(98c9f3f6,81e220e6,d4bba711,fa8b212a,dcc21bc4,8219b813,eabdfac5,70e6fffe,bd0890be,d9cf4ec9,44f6abb1,56250329,a37d2cc4,64c931ba,8606c2ce,55127aa2), +S(f644f4f0,43d7713,ba4380d8,26ad0f3f,44106352,142fef13,7c6e05ce,5e9f1571,3192280b,f3971223,c00ed336,94779866,536020b6,79ba8cb5,c4f9c515,69d2f97d), +S(334ab869,32c4097c,8d8d8a23,d529b079,6a759d47,a907b047,548e735,5b3b766b,18f11736,d54c9d00,89149b07,35f5a9de,b15d9c,cde4ee06,155a4f3f,de98a7bb), +S(983542dc,61b43ee5,c4a7f36f,22da008e,832d4eac,6791d838,1a095d0e,6d8a14b5,cd225f2c,334d1ba9,94b0a681,d6be7696,16bfb2a2,426e9939,d2238cd4,43bebd02), +S(dbbac008,1b678270,4a0fcef0,73683822,a3d4107,d7f1a71b,41497da2,9cc942a0,cd25ef66,36f21a8b,532371ae,b91b67a,deea5797,983dc36f,54aed202,d9845515), +S(477949e6,9ed28a74,879bc8cc,660696cb,115e6392,5a63817b,60e5187f,1f77f3be,dd8ca490,fb8e3bc1,44f5fe9f,aa41ce73,56a1dce1,cc8e11c3,ca5725e,d1b764ae), +S(7616b9e8,b451d4e2,e4826586,9bfad6c8,ddbf5fd2,2342c6c8,42d6bbe0,398f94a2,4e3bb1a9,76efd345,3c4474ad,e6a494f6,4f97c6dc,c98cf68,72bca24b,dd9e946f), +S(b87fb86f,6ec4ad7d,5bec3bee,e8d68618,c8e4906d,1c584368,ec819f2f,871ca8c3,c64723c0,aa587911,4dda9c75,493f739b,e8c2221b,b2e75ee5,b25def54,a1d40c2f), +S(56ea4572,61a6ccfb,46fced99,1258b31e,8573a488,aa53b7ad,65333452,b06d41c4,d8529601,4145e12e,a72ae4d1,5ae6e5f6,9cc88ba1,4d79467a,3df3bfef,33d84290), +S(e4c6540a,19682e0d,e1f1258a,103037a0,af4df5ad,f27cbb7c,9e3ce67d,e23e13d8,a31e1b08,4bdb5728,36e53d93,1de035,c90b1efe,b5343b23,cac0e7a2,bf5b3868), +S(1902cf3b,90fae93,1855d758,24995b03,e1604861,199853c6,ece84903,c8bd67de,3b3d41e3,a2dd4c28,16d492c3,e6c53c83,e5203c7c,a8100d41,24cbdcd0,e12fe222), +S(6519f4d3,b5d731fe,eada6806,727623a4,daf924d9,b6337a51,56096ec4,16ab42d4,62e2c1ea,afa990bd,6dd91675,e3b2d1e2,acb2fee8,e56ec30b,eb25bdce,2d3ad30e), +S(e1128682,519b965e,a933f197,eb0997a0,16114459,4c0915cc,9c55ea4,a30c1ad1,cb1370ba,f8707c78,84817ee2,8227da3b,7b7c97c8,266af491,e0d52bc4,ea0f9614), +S(4366960c,6ff595d4,143d4cd4,f0f0df2d,3bf864d5,73790abc,23419c7d,6ed9201b,623faab8,2caebb5a,b4c42bf6,b2a686cd,4640cde1,a95a65a1,f8d32836,9e5ee0cb), +S(5acdf691,3c1e283,c1220355,6efd99c5,d347ef69,bda1d040,44cbf0d1,ae41b16a,1bca567a,71698c35,e35e031c,e8a98dd,e34270d1,4e2e2439,9276a7c3,6a1f35df), +S(807ecc04,81aae374,1efec46c,8c6c194b,faa0607c,cf5b7cda,fc270fb5,f5b416bd,cc60be6a,6736dd94,848fbb05,375f6459,d556866d,165a2c16,41984411,dda33fc3), +S(29c470bd,97737284,765adcaa,68a98af7,5e6c275f,fa4fcd5d,6c71d428,bd3bfd79,b19ab40f,33c15201,41fed31f,681f176,4a464373,23283677,a40b4018,99a6eec0), +S(41a6d6f9,40bb8abd,9e8748,dcfd23f0,5333eafc,4ce311a3,161440a6,619efabb,b2a3702e,900788cd,bf35204,27e0facd,b090804,62f65418,89a3c34f,ae2cc008), +S(d5f5096d,776ffdb,f694b9c5,c9a9ae0,ab5897ff,c5ca3320,82cb2a2b,8afcfe89,6461e24e,28560d11,336244da,2038e13,c69ed5,a7a435a6,d07a1d72,be43daa0), +S(f65a00d9,5707ce6c,6bd55e8b,4b0ef381,1eca65b2,9845433,d7b307e,518ea724,7ae079e,9aecabf0,4ec5210a,b85328f7,e60c8ff7,3deb037b,c8e6e1d3,34774734), +S(346cff42,23c9ed2d,a1082d46,eeaff341,f7866e72,d95561b9,678def2d,9f7cd187,f97f85d8,92002750,11efcc9e,f8ff58e4,894f105f,b94e7390,7e185806,575698b3), +S(d0e3cdff,a47417f3,86f64a2,4029e3fd,9bc7a464,6e839bf9,232a0d50,349ecaac,5bdbecfa,2a2b35d3,ce2e9837,222535c1,57ec5bda,5fd70186,1920803d,a279989e), +S(f6bbbd77,b8dba8fd,704a3f02,1bc418c0,f8524c49,ccfcd14d,fcbf7f04,c9a18d,38184001,f39b257b,6755a132,86bdfd92,1a8ff771,fdd5530d,48eb8227,ea70be1), +S(6717bbd0,f019990a,c01a2996,e34f0912,9bf60a3a,71d8124e,fd86c777,9cfad879,9581f790,a16825d8,f44f316f,db3f0bde,108643cc,b390bdc0,75f3dccb,6520029f), +S(417c765,ca91a120,2b07459e,3713d5e1,bbcdfa82,bbc26cc9,279fa2d2,59251fa2,8d281a2a,ed38a80a,cb697989,9839d7c5,265b4e78,8a9e1176,66cfb6fc,4143a935), +S(e2f349b0,f89c69bd,3c8cf2a4,10730dc5,8e0beed4,7048c58c,15f9ffc2,508d2cc2,e014d0d7,f07d8dc8,7e79f513,89fdea45,bdcbb417,1f63424c,81cb8426,1f2b3be0)}, +{S(aceb57c9,187a5202,118c4dbe,573906e1,646b0325,781c1352,574ed15,e02b87b,68ece7f4,4037ff05,d4b89120,d90f08c6,f0499fee,d4e9e02a,a2e68bcc,2d7b70a), +S(365e555e,de9130af,99f996b2,106229c,c36c1ea5,8b065cb5,38af3a5d,2cec1145,81fc523c,b4b97bd3,cccce1e1,d1980769,fbc25a9f,a403adba,8e7e8074,13c87f9c), +S(d0a3812c,b9244d7b,c1f5b652,adbb0df,22d15d41,b1724071,fd297d00,bc8cbb01,f8d7650e,fda2be30,24ded196,eb3baf7f,351d2013,2479640,16ee4c6,b469951), +S(8f4ce1e2,a51c0ebf,f5e34cb1,c6aedd87,85e415dc,e7307119,143bbe9a,3e7fc632,617009a,ee7d4d81,1ba2bf14,d1647911,bf1a3bbe,cba8dfda,9030ead3,803fc217), +S(ea23d837,54cb2e9f,9b884ef,f4d1a708,bc1826c6,59fea53b,f52c51b4,9fe0e21b,7e8c691b,cfc3b7e,56a7699c,4f56a11a,fca5710d,963d602b,b102e1c5,b36dc3f7), +S(e3c970b2,c764c9f4,ad8bdc15,cf995690,807f5d09,4a849787,9d278d18,eed6ceea,aad8c7d7,13ce5439,b9125d9e,c14b5d8a,1c694cfc,f84e6922,b7e58df1,4ab8a34), +S(8ade30a,94b236b9,9597be14,bd421130,b6843895,a85f3613,efcfa0ce,9781a96e,78e4bf57,974cfc0f,c310330e,6aa47de8,2b0f5009,5a703fa,50093d5b,a8e8f0ef), +S(fa5f1cd3,4427d71a,de7e79b2,b0a17ba9,66d05324,1f9996e,be8143c1,9186d24a,3481bd18,2319ddf8,f344e4b0,196b3ddb,10deef4,d8d75c0e,49fc5fe4,cbd6e1fc), +S(8b88b79e,8cd28dc8,58e3f1a6,155146b9,af1e3697,d57b7435,c649f6c3,bf8574ca,e736106c,8ffb9bf4,d83d79f2,4faf8fe2,ba5dc258,e4ae1b1b,b58a1a7e,4922c95b), +S(12078a5,5c46d721,96a148d2,fdf6505b,d059e423,c5d5295e,facc2b82,aec51f5d,66a4332d,cd265085,add9a141,2fae2562,17441d7,dd9596ad,46309a0d,bfb4e55e), +S(841523ef,29f5bffa,b31a526d,bf74b16b,fac3a3aa,391f7404,6675cba8,7808c171,7a3fc3f5,bac300b5,7ef843df,e334c995,cf66de11,2283fdfc,767cb57e,e7e7329c), +S(c8831ece,f4545c2b,387378b4,f88173d3,f1cc7db9,d064774d,60394f0a,ecaf5af6,f32f1a48,bb802757,34e66cbe,58a3ed3f,adf28dd9,374a42a,a824a095,6701322a), +S(30001ff3,7b1b1691,9a135a31,287e3a3d,383ef3ca,94748e33,a52c146,586dc4b9,9d71b25d,6fc35db7,26b58d1f,642dabb,46dfa64d,e0ec2a12,c53c414a,9dd2574b), +S(a17d3621,74d3c789,c4e00888,fd4b0f4e,ea3929cf,afea9e9f,7439901e,d6b0fe44,2bcf09ef,2d374194,510fc057,dc973fe1,bb687428,91e9056d,a5b4df7a,de79bf), +S(4725e2cb,19f95359,2da72565,d8405e09,92a64299,9ad74ed5,b41f5d24,44cb6b0f,be23fa82,7aec3121,7b90028d,b61d1092,764b2824,9f3fa0ef,91929db9,b2e0246b), +S(67c560dd,74c276c4,df3efbe3,b95dca4e,a56c4563,cc7ae225,ebea90e0,f5e212fa,2c9e3120,d52ef31d,7e9e36d6,eafbcdbf,ed8a28c6,7edefb94,1df7f38b,cb05c160), +S(8468da98,7b33b79b,e08da5fd,57cee298,ef86f624,3bb975da,2f4261e8,f7531d92,455d8a8e,b4f45693,2e8b6f77,ddefe070,591dd37f,d6ad3a27,5774055b,8a63e650), +S(3416d4bb,78de7570,b1e9e912,83a3e8fc,be6524d7,4463dee6,82e84e52,72c0953c,94e55458,2c17fffd,321364c9,16658093,986b56,f88b4818,129e19c8,ce685dcc), +S(5c66928c,a39a6e22,672c1dba,8bb6331b,41a7f43c,a72276a6,afd3e209,6416a9c5,181cdfc4,15e7d6a3,c24be94b,7fe328cc,ab624c0d,dfabb1b8,f9a73b56,cdfe1b28), +S(971f7a13,210680a3,ff6a12ad,17481a63,ef624d0c,e4121166,7e63aaf7,9cafce,5de2fd1b,3149e321,2980c7d,88a49018,26f83f18,7438061e,9bdb8d33,6a4b08f6), +S(650277a7,9ae7682d,c5f3526b,8411342e,b48277a4,9876caa7,61ec6815,9a1f13c3,a903255,fcf09808,cd97d92a,26dbd2e4,7a29571f,ae91107a,7cb6f0cc,3aea1985), +S(76a79cc9,7fb80ab3,e8d31e5a,d11f5ce4,74696d23,f1ee7aab,3928848b,556f483e,1779bc5d,c763d1ef,7611b402,4583f07d,c7dc9c96,7afcf83f,e6b6ee42,da75972e), +S(6e0b4015,474fe250,d372400f,13efa0b,70c4e8df,816c0e8b,8d27a7,a8168d54,f01dafc8,8178dcf7,15f8fcc2,e7163137,9e1dd4cb,6c88cfbd,e9a051f,ad204c3f), +S(ee5dd472,b5efeba9,d0e354dc,21228d22,40a69088,842d00dd,6b6358e4,309d1f5b,bce93ac,3fd4a098,9e74448f,5832643a,a2a172f2,eff1e2c6,c61ea99,cc6e7cdc), +S(df99a925,ef2e9f9e,57208fe6,5373ff94,876b1448,368dd453,436c59d0,f2a857e2,88dcfe81,4397f990,56f92a27,143c902a,2a6a66f7,f7e9652e,e0b16f13,33252a1e), +S(9186f095,43dc64db,ad582561,cab96a38,89be54ad,e1cdb27d,674af836,22b5d284,71ae31d5,a73b29f,54af1aa3,2d8e541b,14f7cebc,9279ac26,c846d466,aa975e20), +S(645da454,63357bfb,61b5b932,1897a73b,87af6077,81487bc8,af1a66ba,49bc5e37,4b925aab,aa7bbc19,5963025e,f1896cb5,b6463242,cd8a35f3,b1b404b0,7faf8e94), +S(5cd9a6c4,e9d372db,90a65f11,1f1a1b5,f28bc3b8,3d05f599,39979c91,5277eab1,c147420f,7dfc4ef4,d7d1f08c,1c523771,86a8d7a7,10cd7017,82b97c55,63287aa8), +S(4fd699b1,2c720ccd,7b977e5b,dc622671,18ac3028,bd635b26,fce648cf,335cacbb,3936f10c,aee5f51,26b86240,3249e1d3,5566714d,17ddc19e,cc4d1056,71e523f6), +S(b3fa0545,83510d6b,91226711,4bac7f4,ba4ae5fb,baad7230,3003efcc,4c3c18e1,57a3db8a,6cbf0a94,845e7d67,f9b01902,55aa5b66,ef31abd,34ee0410,ed55d0e0), +S(fd73c052,b194c6c6,dd46aca9,d640981a,ec796009,17a565eb,e77fd534,649a2115,9df8973e,37e877bb,fdf5454f,d9082926,fb09fea9,d162bde0,fb635483,59458f55), +S(2982dbbc,5f366c9f,78e29ebb,ecb1bb22,3deb5c4e,e638b458,3bd3a9af,3149f8ef,59e4a416,5099ddf5,4605acc6,384a4362,f6a2466b,ed1c127b,a918d94e,e93859e7)}, +{S(8aff982a,fbe09f67,6d6e0f49,e2b68f88,8f20dd2e,6387b420,8157ab24,d19027ed,f2350ea9,d00fd861,41259f03,b51b5326,6ce05a34,74508bd4,31ca74e1,366eaf92), +S(27ff285b,1e14961d,a042bd31,56aa44af,5e73717d,fa413a47,b300f358,e1960dd0,8b578851,264a8fea,2e29bbcb,cb9c90e4,93e8c731,983f4bba,65381e88,bc83a8a7), +S(fc6acf61,4a214859,1418ab5e,e0f0274a,309a8248,2cf01f73,db8a9790,825486df,190b9c0d,46953d99,c9de2bdc,bcc15d23,ee90485c,c4c152d8,e28322e5,4c927d54), +S(743bcc6,ac86b0be,a25cce81,1fdcfc13,73f23926,e3116fc8,9415b8c0,4c1983ac,f3df10fd,4afbd3b2,dc0678c9,102150e6,3d005680,6a5e45fe,c95ea495,9f2b8555), +S(bb165428,2c13362b,b1e017e6,6402613e,f82bbe22,9429f29c,6a1a522e,4956d67c,ec542c4f,7fbf3c6c,32e71aaa,86e3e4e7,e52b0d43,98589e15,1f17417a,40b31b07), +S(b3f74ed2,5a7fd474,5820a2f6,221349aa,e41af762,25c2b706,160a463d,1d59e7bc,a9af9d2d,89dcdfe0,21ca46e8,5f09bdb5,197c8f23,bc56d705,851974da,1608dad2), +S(20c0914e,f88902a8,6af0ff68,a08f96ea,25f15ea6,b1128900,120028a1,1049a77a,339567f2,71a1f1c7,16eb1d56,2f009537,68ff4cd3,9a81c6d9,6359d2f5,5d04db9c), +S(a3555aea,2e96f05,d25a145e,4ad0d2f7,fb453974,8c4a3097,a703c0f5,404a0e7a,ee236b76,8fa04380,b0448beb,d2589665,e43299ee,b9fc78fe,5a64db69,ac92b7df), +S(37191a66,1d2a7bd,c96a0767,ce47d97d,7acfb8c0,ce251e9a,1421e2d6,29230c2b,57093393,4783afd7,2df6524e,871c8e67,ff2f48c9,c73e2054,fb219cf,d3c2a68c), +S(1a2f5b6c,5fbe300,8b01407a,b0b28c3d,c823cca9,b4c71a1e,4fc814f1,e186e062,b2f1c632,a9d92a4c,82d31a55,f4fd50bd,d53ee99a,2e1452a4,e43e5ac4,b8cbb7c6), +S(2976575c,c5e70e47,cd9c10e1,32a593dd,12b65215,38613cb7,22390022,73fb41d0,c3f0b08d,a2a3a046,d87dcb13,38c35824,1a8b9959,e2567543,852dcf73,c4f5cba2), +S(bca28e75,5cd6ab74,85884b30,ef399f,44188695,fe9c4143,6016bdec,25d502f7,b67538d4,a571e935,cbefe237,c5a01f77,4ade337c,fec9f95f,3e9cf042,f0dbab6c), +S(3dfe1718,beafee83,b858048d,25d46ee6,7741d3bc,bec1e52d,3ce308cf,738b715,8499a8b3,a0c7c599,f62f056a,a8364494,ec6e0198,2c47bbf8,7e2df591,de0ff537), +S(bde6252e,a9e4823f,36bd1737,ce188fae,be4a271,9984c9e6,76f9f4ff,d070c1c1,2e5db82d,e02a1fe1,39d903,7e7adeef,12d40366,de0eb164,c04b2ef4,b1e849b6), +S(2c74b766,eebac93c,479fc0bd,78a3805,de50be2d,a6ad70c6,9048e43e,c91343af,ab7a929d,588ff993,55094f83,6e7b3b58,c6381bfb,b284f9bf,7dc44cc2,67cc741c), +S(f0e084a7,af9abfaf,b6ebf3c5,b526d545,b8b1cf5e,8e09a06c,3670aa37,6af83a3d,6bb279db,abdb2b2d,fcc97510,2b075dfe,b42d9e6a,5a8af760,f4b63788,c315f8dc), +S(715aa28f,4e52fc26,a2f4b9f,391894b0,6adc3b69,b508827b,4732396f,5eb7edb5,c5d0d68b,3a8c6532,2f6303ab,99b6c48a,88572c4c,56c780d1,d51d2441,86ba110c), +S(8f980e69,3511ec3,cca89b2c,362835bd,24d9c8a6,97deff86,5540f7c2,b0bacf8b,2d5e8470,f2041ca6,f158ac83,e92a2345,4059492f,af27ada2,92bbe51a,d67ee5aa), +S(6823a4e9,d80838b2,750dada3,cc31f59f,3cc9d6c8,3f33aa5,38d949aa,c4d6d657,e087127a,3ddc19cb,e4088a2a,6df61863,e8e81cf5,c5cea4a8,8cd2ab51,bfbcba8d), +S(8c9af14b,11add28a,818f85f3,276d1d7a,1e3478f4,23e74b72,caaf2440,24558538,a7c17174,da1eed2,7eeb7b6,c1d93e4e,9e4515c5,3cd888d5,e4527cdb,94a64fb1), +S(5fadb7c4,74b13592,a1a27f76,b7c2011a,102b66a0,c6ffbc02,a7306e1b,a9ccf49c,7bf61c4f,134f8b4,7a5f90a1,938918a1,4d151f2c,7f1c4bea,cb8c4773,cf11609d), +S(79a21b82,9325fbe5,c01ac979,8b89cc47,379eac4b,682fd747,47e0c04b,879b404d,abfa4d5c,7ff916c4,9f489c12,5235bd9d,a0395b6b,84d6699f,c96f9c0a,5a4cab2b), +S(b213d11d,e4b5601a,5f10827e,d39a7825,adc36bc0,1130a055,cf8b3e8e,fc96d10b,27c0e5b7,a739fcd0,5eb73321,3fd1bbb7,873de0a1,2b92cbc,21de57c6,2bc812b1), +S(299ef8e,e131f523,72949d7e,fc2f0f7f,9965e69b,56725b55,4d513435,ac8b0b3e,8ba93fa0,2a4d97b3,54d47c10,d5d791c5,f724b68,4f501eda,1931e563,2c6faf06), +S(5143ab76,43a21de7,7ffd0f3b,c4746fb0,589be22d,9d9ca2fb,89403a39,86d1cd37,20991000,a7c01e4b,26d9236a,45568bbd,91c968d6,c87dbe05,15063af,d8db5a03), +S(738ce787,49783066,923ceec9,a841d60b,56855e09,93e67cb9,9d52a0ca,7a64b5b2,aba44aa,272945fc,5eee0330,976b659a,a6455dde,feb5c894,cd274414,71610384), +S(6bb9bbe0,4c3dbaf,6c60adcf,5ec5fa59,29cdb04b,14633c10,5dfca2c,183e1d97,b7dac59b,5c35c3cc,15521da5,89c0d333,9dac05c6,614acaf1,d8b9e834,8e02c3c9), +S(f325eeb8,49a32b2a,fb19491d,8c3c112f,a7ca3443,438c8c19,99bdf791,6981472a,169df94,a26f26b1,e5aaf810,7a148faa,17742c3,10cac320,6daa69,f8aad67b), +S(d279bc0c,f7f58a85,b5abbe25,936d5088,4d8ae8a4,b415ea30,2c0f1133,de98603c,1e69875e,2e38f9af,222e03b1,6c833bd1,12bc10f8,1724da7e,bc780e6f,5228fd17), +S(224d079c,750eb1b4,2d70aa25,5fa0c3fd,c2d07c1d,ae4d6cb1,17c1e61c,5ec1c6b3,e54dc4fa,b0e05362,60d27fa7,ba53c37c,a37ce30e,617365dd,1c58a59d,2c93ed00), +S(f4741ca2,b3de5414,49426531,d546272d,ab8fc55d,8f65eb3d,5ea780a,d25cb53b,3b7290bf,dda0d0f,e3704f27,d8537063,f2fe9571,4a0791a3,e1a25865,96a5b0b1), +S(e931258e,8eb5559c,6d697272,8a704c17,b775a26,5b4527d4,a4d4d742,bbfd71fa,4e1ccc9,b3c0211f,17a14be9,636ab4bf,4c6b931e,44a1ca0c,c2642f2b,e8b2c928)}, +{S(fa01dd32,fada2843,c51845e6,3cdc1b76,79dee47b,d2f4b767,5133aa5e,62029057,6ea6596a,b0ea0201,b6c8bbbc,e9d07fd0,8040e1fa,198c8767,67ab6055,34a33), +S(97ec9d33,a9d88115,471619b5,3fc58a08,e6997662,7a28afc0,b75b2f49,55eba300,92ad1d6a,f8a0a100,27d9ba90,4f7fea6a,571f3c32,53393a7c,79abb0cf,9a558390), +S(ef364ba7,626d72a6,87bc9776,3f2c0833,50640bec,6ff4d80,9dabcf2,9ea9145c,7f8d7c48,1bd80ff4,8eccfa9d,2de5eeb9,800cb98,c02da539,3b3d6c83,8fe4a2ff), +S(45961303,a778b47a,89109231,3242304,30a17859,7d940e9f,fc2f25bd,1be61c00,5fa356b6,daad2b1d,7bb19cce,b9148d31,58d2651a,b4b436c0,b99193f6,61cb037d), +S(8aa677f4,d73c0725,e2163e5d,ed3dc312,7ad5ee29,f9bad8b8,5ab8f50d,ec6d77e9,1fcb9da0,d3fb9bc3,3a45bcdc,50aa2ba1,16c2b05e,836b539c,863163c7,2436c334), +S(8c6b2873,33082bf5,a3597a26,7cc14696,2b689f20,59caf1d9,35972c98,9b14c86b,aa86d282,a1107f8e,21307e0,2ad1420a,a4061fea,3e3dd6f5,9b5d6900,6bf4827c), +S(46c963f0,3bdbf433,cbd60858,5a4d659e,9815c286,9f684eaa,cd879d66,ceed05ed,be2a8d60,636c5b80,e443b13a,9e21c91e,90a9e781,1c35101a,dfd61a49,88193e86), +S(cdbe43bc,582f3936,314a88f9,fa21b29d,f4b5acf5,96cdac3,4667e9c4,b02b926b,8f2a5b62,4f20b20d,cce97348,d73d5653,8651dd41,dfedd476,8792fa61,1bac16fa), +S(6f9c5a84,1ffededc,ec45dc63,7ad15aea,207116aa,a3036ea,ddfb0656,1dfd074d,ddf1c22f,9168232d,cf9c36a5,dfb7835e,62d28405,bd32ec15,5e3ddb3e,df834088), +S(42000663,3223b99,e15a2a65,bd95b229,820abee9,5ba5be39,6f8879b7,3f421e7b,9f3f3d66,40de91bf,c6872619,87487226,57e60a4,3ac633cc,48f684c0,cf42696b), +S(f02335b9,9cb524b7,45fa9167,41da4259,f70279d8,efe851ab,f5b0b8a5,32a087ff,e1bc6767,ba068b22,cb7389e1,36805da5,c30ca62a,e59b92f5,48e4dd1d,5327cfbc), +S(5bbda2dc,cf8154e8,28ed49b1,2fdabc3e,eb8c3f9,d0da5878,77611ff4,49d72e7c,312377c3,6277addb,d5b044e,fe136626,d5f7e7e7,a73cfc4b,9751e8ec,e4f77084), +S(5cd5cb83,ba2f225d,1ef4faf6,22e226e1,eaa85a5e,99721d3,82aae23a,f9dff565,254f58ba,9c49244a,4178a067,b0e4bf6f,dd7f3e15,65e21637,bc41f9f3,55045908), +S(3b20ebc6,b453aa16,e5b61381,1d81ca1,f87dce6d,b54ba85b,d8578ee3,23bff228,8c9d3054,56627a,7313505b,4aa5140d,9fc40d83,bcc298a6,43842f04,70a335f4), +S(cd531999,cf33db75,df4430c6,bbcf32d0,642be18,5736d79b,f2947989,e52c8da8,c7e99c34,2a5c1112,400edc69,f58246e3,d3cebbef,2c43ff47,7520b027,e2aa7d78), +S(40b3856b,273bd2a5,145b70f,d16a2972,e488b33a,f3719143,db7bc567,26ff23c4,d8bf895f,71d96e6e,20d523dd,1256bd56,44e11442,c4757d74,f116ae44,69dc9b21), +S(1a0cf029,2d7cce75,32b74bae,acec6864,9e682788,3cef4bbd,c8b24fdb,53e885a5,32c87d92,6f969f69,7989837d,d8ec8ef1,c284d9db,2a86ecd3,5bbb6772,dea06692), +S(7fd5d251,93dd6c17,8d0be92c,342f94a3,c92c061,27998f4d,54f7dfb6,1326fefa,ea7d0755,e0a804bb,8b7ac8f2,dbe1dd7f,9ccd36ca,2fa94365,631ae455,5d080075), +S(51820145,6c07fa3e,70d7b24a,7754b11,e42828e9,c1b96b0f,fd79bead,2f44050e,126f5526,1a55b724,7d08c868,366d697f,a6898c66,d14094f3,44b0a6b3,613d043c), +S(86f2c87d,46038770,3be5ddc6,c2ba1ccc,7dfdd56c,a9986663,882f85da,345886da,ed34fc59,4b66f7e,f06f54de,84f3c7f6,ea1d877b,bbfc4185,3df800f2,fa805027), +S(7f7d8a69,5b86ca13,d6a0ba07,99e60cbe,f5c4e1f4,c74a62bb,93d94d4f,8c1f296e,44a14061,b2c741c4,6a52639e,9bf08776,5db5d496,92bb6d1b,e97f9ced,a89953e7), +S(ec61e956,83714c55,1b72ed5f,c5b09663,6dbdea9a,64d13ef8,c9cf0c55,89da5ae4,39a6e38f,9f7927cf,ffcd0847,df91e856,4188bf58,276bb4df,3721335a,5357c77a), +S(e5906c85,4a75bee9,322d70be,a5d31c76,31a59389,2f479bf,8dc11bef,9ad5101c,125b3a58,8c6c1c5f,288402f4,3ce74ec5,fe9c2dd3,3f3605df,9ab41210,32641524), +S(6c9faca8,b1b435b9,213fde17,ce967f05,46e6f27a,cf0e131,8496bcfd,d856b092,a04ac67d,4bb07624,6b59df97,2fbe2c1f,bb04be99,e269d33f,ccc81f76,3f567577), +S(61031a0c,730cf279,d929b4f,5608f16e,6b1b1440,c04e5a9,fa300ff8,27303def,acc4d732,afb4730e,39a10c0f,5ae2cee9,5099be03,bf5612ac,391900fd,b51238c2), +S(e58fa07f,ebc3aa4c,61ff4fe3,bfc8d04d,48a1e3c9,935317e1,83d537f9,7f35826b,d2402844,7e63c3e0,be630190,8139a75e,2e1a2b22,b05ce52b,e453ccf7,7c35f1fa), +S(4d4d2982,b45a339,1720af,cf6b92df,2c201d38,5b9b6c3a,8fc53b4f,fd3bfdd1,d72650fb,d130482d,116524fa,e2b3dd71,c68b4bbd,54fc55a8,f9824578,cff67503), +S(9adeb6f9,6ffcbb56,f171919c,a8a64c70,9b8ae835,828bd573,b7a1bbc1,3efb0360,6d920a2e,d2e3f41b,4820d838,ca342b66,9af35a7f,7b6d09fd,b1ba4298,9abe027c), +S(64ba9514,d8680f6c,dd66895d,9c5ad45f,6e29,33506f8e,d7be9770,822aa9b8,7ed8c0dd,59bce424,481f88d7,3e641b61,a010e490,97cf84ca,16c2e045,49e9c6ca), +S(9e4ac64d,9ca58a04,46ca18bf,c1700f2c,16937ef9,c82e8b55,9ccbd751,2a0c0222,315ba2e2,601b18b2,cf7f1720,9c4cff2f,e39dfcf0,c2546fb1,e930898b,5b023274), +S(f13a99e5,8dc72fcb,c62a492,d2850704,621ddf48,f1f433e6,9a9814c4,17d4b84a,cc3d3732,f0f4166a,55946e32,e1c01f91,491c82b8,ef0d269d,7a66f039,ac02dfae), +S(fd6451fb,84cfb18d,3ef0acf8,56c4ef4d,553c562,f7ae4d2a,303f2ea3,3e8f62bb,18ba314d,4e78ea87,490185a3,e43cbb33,5d54b6d,2dff17c0,2f526f78,ecd3f31e)}, +{S(f1a749e,6cab100e,2aeef8ee,6a654551,c0ff906e,e7d11d77,f390955e,9d29d783,a60f7295,3c8c3bf7,f1dc1358,e39baf76,3dba22a0,1ce7917e,aeabd996,e21e845b), +S(e8c45020,4c9d9ad,f7878aa4,184a1576,d4c65d5a,c1c4d494,ff427e86,8b42ec1e,aabff02d,8a715c2c,34414b27,808882c3,f656389c,71c26d6b,d7ac8013,83f4c57c), +S(c1febd79,1784fea9,bf378237,a05522de,1081df6c,27d22ea2,aad805dc,7c2f1c4c,c38782e9,fcc1004e,aa677f79,536aa069,7dd9002d,ac16936a,1f0b8736,8734174e), +S(91925564,4d9bdf2d,4522825b,5758b3f0,4d32da73,3a4e772,bfe3eb2c,9909f4ef,2568e18c,1a0448ab,d038ae62,a652d152,4bdec1c1,a0293695,9772bb65,d78450af), +S(25bb4202,9880c39,f5bde432,c1fa357c,7f4867f,6fee48b9,24ecc824,5e1a5253,5d43db2,64c23715,b4b0eeae,63127cf6,9b4bc79e,f96ea8cc,d17cb53c,c3ac0fc5), +S(2597e080,e772d36f,df500782,5f92f797,c61c72c7,8d801dd1,3deb1bfb,9e91b12a,fd5918b8,938ded17,a458d0ae,559c552f,bd45feb2,5b4f59a8,f5b735cb,bdab92c1), +S(70231b28,f578dc12,9f8ac54d,fd4e3577,73d0fcbf,65be0dcd,51132882,5a36e7e1,d12aaf89,4dff3e42,405a4140,58524e30,b7c6c4a1,83763268,6852acff,83d2b7cb), +S(f8ddfd5e,5f3b46a1,ab363169,12b74c97,b0bd654d,87824040,bf6d2cad,b4fcbf95,931fc58f,5b429636,5e080d5a,8fb35ba0,f92104d3,891d6584,8d24c0f7,fc95bda3), +S(a033f432,670a382c,57e2408d,3bdcd2a6,6758e63d,77574598,6b123e4,d927bf10,83b52f69,d79e7445,b6e33545,c23f16fd,52691151,96ee60d6,2ecf6de5,b2961a0c), +S(8e77f9ed,9a643f3c,bf197b09,80f92860,f37d8b83,93633230,6c902c38,3bb7f96d,71b4da9f,f736f9f1,f8c3c099,c34c1bc4,30bb5d26,3c861e2c,726fe891,cdf7d1ce), +S(f34153e2,29934c71,5d895102,778425f5,e92f4ee5,b96d1333,df207e62,6761b328,954584f1,64c8f35f,2c4e0188,76186ceb,3e91523a,5e8ac03,d5998253,49b7b8ac), +S(e133aa94,c0252f05,379b5bd7,75ba3f1f,92de2876,68613613,28946904,11b3ed52,40363801,613423b7,cc6c0cc5,af3641f4,dc2a7ac4,48b178ae,d1393605,103bd6dc), +S(28119c6f,a57d02ac,856edb00,f594c7be,22772b0d,700ad14,713affe5,7e385b5c,969b6cb2,8ef483a0,db4a96bb,92e2d332,6e6d86a1,73bc3d5,831bcbf2,5efc437d), +S(8c728d65,8b78d96,44003708,dadb48b,65dcf6f,6d9412c0,e31cce3d,b5384d00,bb3cf660,9908467d,285f1c7f,40f4f18,ca618093,92633beb,b4ce30c4,72680662), +S(477321b6,1fd5b4ef,3acd1e8d,8432ef5d,e70576ee,6b8490e6,839f1985,dec96490,88008466,2244e3f9,7d2ded5d,2193c70e,2d72c67b,9b7cd70e,9f14cb05,70306bee), +S(ebedd345,ccdd0e04,4bd3d4d7,e1f1cb6b,ec06ad10,5ec2cec8,821580f5,d08a63d4,4278bfb0,88e4ff81,a3fe15bb,e01be36,40450f85,885da0ae,e15c6b9f,e78ad14a), +S(f4795df9,41b315e2,24a98dac,d9149ff2,8b9a7bf,e758a1f3,5cb6336e,8e1f9814,6982bc20,285c27d8,12c5c648,d0635c7,fdab85e6,fc6905d8,65da387e,596da791), +S(65a5964e,ea76e30c,74c472bd,3ddd5169,11dcfb3e,1f2d7ff2,9661e254,4a38ea30,a7c394af,80ebbd32,e442271f,b061bb42,a7b1758f,44d7d952,89152fa2,a88fe3f9), +S(f3d10725,da6b6c76,6da6fb5b,969ba7c6,3e33b4f2,d062a446,4ffb20bc,dea2d376,4d65ff69,64518942,bc3142a6,2148137,7bb609dd,6545bc26,9678ea19,62812ddb), +S(f5fe0f35,cde00589,301584a2,f4f5b1e9,3977082e,9c9bd50d,7c2c672b,ef05cc9f,1b49ac82,486e6344,dea32ca3,c96cd5c1,446ac2fb,2a658a42,50425f32,e8d72e94), +S(fce17cd4,d9519a53,f0a100f,ca54d1f9,fa87eded,98a12654,769c95be,151e33c3,40d342ef,83a4d715,bd13df0,f21197c6,e189681b,efa0d925,248733f,5ee07b8), +S(fd5d90d4,a97c1d1c,4fe18a10,6808f46,f6ea4422,c4408860,c2256b66,618af8e0,7ffc76c3,539bdec8,f59a9a7b,b36fd534,99306cf3,2dd1fe43,a2db5b59,af2f7e3b), +S(1c71f824,1b147abd,9e3c1ca3,fad5146b,e531dae7,c9c0d586,4f2d8bd8,7a6457aa,23e7e758,2cfc92dd,e498c0af,b942182a,92e02bb0,7e95bc1b,763d8030,9ddc9137), +S(dfb018bd,9bc352,f36889b8,2a46512,8850a158,872554cb,3a3dad28,a0496f20,2daa780b,d615d778,3de8f5e8,25cbd934,5c021df1,9ef80a6d,39ff87db,67a1e5ca), +S(bbd320ee,dacc1282,d3fd2109,c26f6bcd,46205ec1,d96b806,dca35dc1,4baa823d,ae7beed,3b5f72bc,ba66c794,89c05666,efa85966,14bacc45,9a99d882,8edbdbfe), +S(c9cd8f21,a068f78b,ce5129c0,9084be52,e48d688b,f474e690,b7720360,e362dfce,a10b9fe2,78c7814e,37851b5a,36aa4246,54c6279e,89df8fc2,ed189ad8,11518f22), +S(ddcf39db,aba52181,72c36a53,50883245,39ccddd8,46ec4258,e72dcd71,40041491,85cadc4a,a569265d,412c8fa9,4872bce1,51a750f7,b43385e2,2db405e3,54428a5b), +S(391562c3,f19436b1,a6e41d06,7435fbe8,27de66b5,555540c5,3ca7a0cc,c7876457,c3a5d917,5b56f67c,66ff269f,72c0a1ac,74503106,9059aaad,f3e66dad,45a80ee0), +S(63d4b224,7b2d441d,680a0437,604533cf,1dc48c9,bdcb9e10,e0249960,f966b2d4,e25cb896,ba165d4,46f73344,61e6856d,4c186736,402dc6a0,d866f97e,bd5cdfff), +S(5fe057df,5d2508c7,611dc21d,412739fe,3e7cf9e9,670812df,cbb00255,4d44cb22,33b88e83,9f22a7bd,17c149bb,65bd4a49,29b2a29e,b975776c,e82189de,80c7d45c), +S(5ac83bf,498f7eb0,79507ac,d5fbc587,f758afa9,b6a1ee51,4c857f8d,608a7b1f,1c866393,8a91904,f0530bdd,ba15390a,4c10fc4c,ef8a2f07,d799c89f,69a33097), +S(b0f9e4b9,b29790b6,33bcc04f,d860cb0f,823d8d1a,4cc1a1c1,413c1606,cc9a8e2c,b617d40e,7bc52192,be344f46,f9021c0f,ccaf33fd,3e8e3118,93df993a,20c2ee7b)}, +{S(eccf169c,9514a854,8f7e1131,a7438469,4df7dc2,fab96462,20e5799d,6d3f672d,452e53a2,aaf17617,37055bb7,24b64f4a,8fef29ed,f8571ff9,a3a6d2c4,6acdb91e), +S(a77bcddd,a0fecd39,a99c6387,57bda1bf,30257248,6a3fa08a,e2d6ff17,e6e4b6ea,debf4c03,b4bb5c7a,8a386a7b,1e459426,6c78eec6,55f01cd9,f137ff18,c5fbdb1d), +S(a77b91ec,6db6a66e,a48de424,65079a2e,ce220fba,da221601,840546ec,2295c2a2,3c721fea,81f5fe05,163562a9,849bdb15,90bc818e,86674ea2,57fe8d0f,4050086c), +S(99a28a1a,3bf2af79,ef2bf134,d31880a,71c2aad3,824fb7df,23fc4fb7,d54b2910,620e2918,df14e3c5,dbfceada,1905941d,32d77592,89ec607a,f9851a6c,5592803d), +S(7eb52616,71402db8,905c7097,2af96b72,2bd77d,f124bbcc,5418f217,f6d8c7be,ce1e663c,8276bf42,99919592,11feb13b,66aefa37,5d6dca15,8b7b66a3,ffc6d7ec), +S(c88b1815,f183e6ea,3ce8469f,ada5b88b,805288d6,828473ba,368d52f,2145e7a4,55e78f2d,3784952e,cb47f6b0,113eb471,8cc58225,85f9d1e,2198dc60,af3f90c9), +S(dd893c5e,a2e4e70a,fcc161ac,47232d3b,77f16c95,54c98770,9a7a6f64,c0cf7ab1,a1a58b41,c7d4d0c5,6d6c908b,32d97467,b8b6ed20,73e6a677,54935665,6a92a480), +S(591b8422,eddbfaf9,d2c27c28,dd84dd30,712a15a0,deb752dd,dee682cc,34722ea7,877b0c99,6a248082,fd442509,b0ce4cc1,b181d4f8,8ff755dd,5f0dba66,ebf95d1f), +S(75f9e3a1,ffdd902,be5d1d2b,3ed18b37,62e42e95,8b024ce8,f892ee13,ab35c674,57fabc84,7c68cfdf,272effee,e7a6ee2c,5fecdeb4,8e4877c,ccf2a8de,2e2264cc), +S(c8a53d5,e1895cdf,db61c1a2,395a866b,ad803773,23ea43ca,775408f7,a4141cc6,ddeff9c9,97a11e4d,d0afab30,f63229f8,1b52ac,c25749ae,2749ddb4,2b201196), +S(8827d23,668f3006,b966cb19,698a066d,aea556b7,4108739d,d6414d8,e8dd78c9,3d009ac7,2baabb53,2e3658e1,8941d4b1,efe512b8,fd7696d5,14b12216,215f10e0), +S(dde6b713,5cf165c6,53c7f5db,542501bc,b0a41e3c,c6779aa6,194ac1d1,8a830b01,25c04b4a,937e16b6,e72616e2,d64a413b,6a7c29ac,71dfcbf6,826261dc,2507c16), +S(8cf6210c,5426b3a5,ed594699,da6cb8b9,8069a3d7,b926cae9,fedb2e96,25d20010,78017fc1,7915e3c8,62557896,acd002fc,7263bd7f,aed38fca,d63ccaa3,57391f30), +S(35772904,91661db6,340e7d1c,a98db8bc,2f50f557,283ccf11,8e446f71,925ade9b,fd8a4a56,b82dff95,a59e29ea,bd5d8e8b,a876bf95,4abf0537,60832d1b,d7edc31c), +S(60e4201c,4dbd9c99,c5eda030,f041f51d,f648f77b,13ec2072,4d89b6be,f249d793,ebd96057,d60b7cae,71349c51,1a3ca99e,847419ff,cdcaa0c8,54d75d40,8263d81b), +S(f39d686,b17ad518,3a7d300f,1bfd015c,57541f08,a96b5943,43d2ef82,bf20bb6e,f1298c9c,633a958a,a0d12b87,8c95836d,f9f93b5f,5e3a6bbd,93a75ba1,1b96d4d0), +S(37ea7dc7,2a3a0b4e,72412814,bc1e1233,17ea3e1c,c4ede35f,cab5d31c,93cc330b,aebaca93,8b14b315,708360e,5662e6a1,af25069b,cc07f581,225dd131,c656c607), +S(ff1f61ed,ba3cfc6f,2fdf3043,37205bab,301c965b,501e4f2f,fcacde00,dd127b25,fb1edca5,90e00f87,eeb56ef9,94e9bb12,b64ad1ea,f5ef0afe,6f0125b4,e100a483), +S(3376e0a5,b93f15b6,c46b92ea,e313ea2d,c5d0b961,a2623487,8919cf5e,25e9ae38,a4cfc1be,fd24647a,20ae014b,2041ab3f,6cb7585d,48a607f8,299e0c10,96bcfdf1), +S(be575f99,842187b,30bcb312,987ea218,3d613442,8878804,b5e7d920,12e58d9c,154e02b0,b573c81b,d2079a4f,4a6efe5f,5f37502b,33225064,4eb38b2c,3f0a1767), +S(5a215836,f1f2997d,9b09d4d0,6473c55c,46cd3006,70d85d6f,6b5531aa,c8da043f,ef5fba1e,b6e1deaf,bd83e480,fcd4984d,cf60f91f,4799e8b4,3f4edd15,f94b6d33), +S(d73fee2,16a503e3,a7d6b0a2,675adb1d,197c3fae,4d43835c,b6b043f5,d44909f5,6f2cc9ee,fbc36b4d,a5b3e704,c13daee9,cb81ce9d,470f1290,8b32f047,ae231053), +S(26fda2e4,d07ec613,ded58e14,ee84e421,ea58e5b9,5beed698,d847f6a6,db185f6,683c0002,bcd6d8b7,1d06e592,db4b961d,f2518fbb,47cb4ad9,96020d84,ed8a5909), +S(cd3d4e87,e433f2b5,5dc55c6,a3f280fc,57f899e1,f8f0777f,32705f3,eb24551c,2315d85b,7521e4e3,8e69f29b,a49a3203,abc7f280,ad49365a,4c78f21c,3ee12542), +S(652476ac,2c9b871c,e108fa13,6a739766,879a76ec,60d787ac,a1b7447a,67f8afd8,b66bf6db,cd3a1393,f70ac7b6,d53069d2,5f084dd7,f05c97a8,76f7f646,c7b67fa8), +S(61ab4f97,61c96446,ea7a75de,7ed36224,7b5ce8b9,e7b442c3,432f9fa0,ec74355e,f391652b,17a910f,6d476c29,89e854f7,d31a5f31,fead5fbd,5013ea56,e44985db), +S(36e4bb36,e62f78a6,a6155351,36a73637,13fe8be8,1c8c3460,a94bb642,4f7c80de,12b38983,c10079f9,b0016df7,fba0685d,5eb87518,234c65c0,7dff006,dbb6a563), +S(f5e4cb89,101e90d4,b2f50097,aa0b22fa,df076932,f4045e9b,7a9ce8d6,ba178780,c12ec4ae,56db7971,3a1bb0f,2559e3a1,de3f8200,650c809,74101940,181eb52b), +S(1138ad12,333790f9,20e979f6,a6471274,2a9bb567,2356e3c,80ffff89,a9de533,4caada48,a78ae26b,790f23c1,606a5820,98642f4,bab5bfff,95748f6a,2ccd6bc), +S(e0346d21,121ff741,fe4eaa23,938a4347,a71df442,9e55359e,aa20d691,c9f40840,c1197c8e,c36676a9,28a92b56,811845d5,d9632c65,9142cc12,3c65e54f,c282dbd), +S(d42011d6,1061388,fec6b7f,3f332b20,24ab318f,2a9ba7ed,23731207,3e32478e,451a2b16,5c82b1f3,e4d2a0a0,bb407b84,904db4d0,caaf733c,e31fa97d,2fb1735b), +S(63964eee,619074e0,780140fe,2e90836,e72328d2,448386d4,59c5be23,187f5048,c49304c5,947630be,5c60064e,3cb40436,c2a7f46c,b221937b,c7c5d7b1,76cf5e37)}, +{S(8f741868,43906722,ab9f5c6e,c796573b,622fa2ae,6d985bfe,ea4d51a1,8f141792,61ecd858,d6992c4a,bdc22472,fb8fd242,929dc5b5,36ea8e35,d1c8c513,bcb9e31e), +S(f2dd67e5,6f75c397,76b29366,149ba4ff,69385651,53afb385,3853acb7,9fc2bd59,3a24641c,d48ca39f,fe992bf1,50291604,79066af4,a0cf364c,9e52a9f,9b51eb66), +S(9386aa5e,c3452728,a8f65141,e2f43a14,c250173,9349c96d,e1968a4e,48cd30,a3a38a85,4f68048,d8f81002,3eef9966,780262cb,aacbe859,a8fc66fc,27c37f32), +S(6c9901ea,920c0f4c,ce51fde7,ab283f98,eebc30dd,c76a3219,1df4c4c9,db467aac,6773f8ae,e601201a,84dd4485,fa560e22,81d5eabb,25a3b3d8,525f4a56,65f79d05), +S(ed1eafec,876154e0,58597caa,8250b0ef,7262ff70,b719ec9b,63c0b2ff,9d167fe3,73505073,2b563f93,89078cc3,93ff9837,227ab8a6,c7d789c,6d2bc835,2018f77b), +S(515806b5,13d4d4bf,83533b56,3b39bf9c,4e808426,f2e4cf16,562e759,cf2d56ab,83c2fb,673a08a6,b8a86b1f,e1ba23d9,3347903a,d6855059,130d8d39,737ddead), +S(30a726d4,d8db1cfa,d59331a0,8f4b5376,36848547,914dcd75,37a80e40,109b8e35,8f628b92,6a11ddc0,dfb1cebb,934aeaa4,3840d442,a61145d1,803f771f,7bf65d7d), +S(116867a8,d72fb00e,80a6f267,e8163770,34affeff,36d667cd,38219f0a,e3c9038d,270f15be,b2a3d50a,4088720a,e9a2c3dd,df00817e,31e1a5b1,d850fe23,dfe51657), +S(abea2899,e4575c6a,201c96fb,a60a24ee,1f1fe0c9,b718b54d,18981938,4f33a1f4,d43d54e3,9e8d433a,ce66ad94,e52662fa,8013e778,f8bc2e3f,31938a6d,5681c660), +S(1fa796d,9f658aa8,6ccd0fb4,6a735651,102e3181,302e371b,8c965dd4,5f078b30,69815d18,43c3b4d9,f7fa4af7,3d2e5dda,390e5372,28608912,79826a53,a437031b), +S(f5022faa,c8caa29f,304ab6c3,d00931c5,e09085e2,73beab04,c1d18f87,1c0fde73,c6abd143,73213fe8,ffa5ec64,8a22dddd,fdf2cb25,e32afd58,4f92dca7,838e8249), +S(8190b10b,97bc72b9,301b1dc,cc60e69e,460e389e,ce7d5d11,4e2284de,853ea02f,f1ffb850,dbff0f06,561b75f6,5d2ae823,cb13881f,d1150eff,274db4cf,112d2253), +S(ea230fbe,c58d7e2f,1a3cea60,f9018562,d2fefb49,8efa312f,4beafcd3,139da094,6045d69d,b27bee6f,3357180c,e92d3866,b480faf4,2debc033,cfa118fb,b89c3bd2), +S(333d063,ccef6aa1,f78c81b3,4a84975c,82bc2cc2,bb897608,f0bed49d,cd08829,90ad105e,f72b7e4f,a927240d,9c69729b,a0aae3a2,3a45342,3be2c385,488840a1), +S(4d95cb48,58d808a3,be82f42c,da4f64a8,c64ae176,3b50257f,2e4ae655,fcc4802,5f6efffc,99bdde54,6d8ffde5,e9a551d0,121a39c3,86db540d,1caf74b4,894c5559), +S(b87b5eca,6e0111bc,5b756816,fa82acf9,77f81376,af796cdd,1e8fcb09,4d363d1,442fa845,9c2a7799,2c09015a,db80f26a,28428851,62432660,56026009,5f2f9d8), +S(34baf43a,a82cce1b,19945590,ef3cb582,2ab03142,6538ea5f,74571582,ee14cf00,9a76705b,c0141e29,75d11543,215377b5,3c051c31,156697cb,e8f56721,da386e2b), +S(f07c5d98,a2579c17,53b3fb58,22a139a1,53e7deeb,ae9304b,114bb188,d61cdd0a,ec18ce0c,1e51b8bc,e12f3d85,23739f8,bc25708f,32deb81d,a780cc4a,1010692d), +S(9a146c80,5ee261ad,3e708885,aa41041a,53bd3758,b3d1ab7a,1a44aa7e,29acca7,fc553e71,4ad8a192,90f94ed7,7c171f9d,9ad9a047,6791f045,4a3ab7d3,f8834f02), +S(c8088409,650feb74,9f9fe21,61772279,128db1d7,58610a9a,8b9fc4b,ef9683b7,692a6be3,132a08d3,82295ee7,1c469465,ae7d63d6,c20c7357,36935003,28799639), +S(53bdc8b2,3edd83b6,b149b79,c88130c6,b207f999,e7045285,7e828f81,b325b9d8,a9a039d1,79486167,8fda727b,1706e9ec,7ec3eba3,26e6a4a7,e27db3f0,8a6ee238), +S(fd08fb47,4af98207,3d8b4ef6,d39012f4,78225f1a,bde3c841,6fe3881b,4fd276c6,d38b53a9,100da1fd,1d2a987e,6907370e,7bca492e,98a22e5d,74a10c9b,93a197e1), +S(5c42ad93,2306363e,a0edf86d,31d14b04,c3f7bc09,c9fe1326,d1ad085d,c84fb7ca,1bdbf812,e9ad6486,ff572d4e,de5be4c9,59de7be3,f21e0dd8,76534091,f13ca3d3), +S(66257876,115e7eef,fc0e6132,9f177d3a,437c81c4,1150f86b,45904f86,30bae971,df830e1e,33aeded,721a0a6a,62a3a402,1d2b7ab7,438b7b3c,d834d67,3a857aed), +S(4feea8d8,2cc6601,c847deff,35581c1d,bf1f4070,402bb948,ce9a41ee,16661627,c09a7686,ad6bcec4,ea9ab0f7,8316adc0,7c7a2899,9332cee7,5d70c50d,249a0007), +S(2d3bb180,73f5345e,cff0c901,9a6f2fb4,e0a237a3,9315fc11,fd53c7d5,aec43670,58a9459c,2710ac75,ff2510ce,4c9c5fb8,b4f739c9,c6611494,daf896db,e43b080), +S(bd539f5f,47b25116,7159153,f402e0af,8650c17a,de7c5dde,2d9d9cc2,d0a3103d,407cab4f,ca581f10,eb386e20,9158541b,8649951e,b2f5e454,2a7032b6,53f0caa), +S(c7a72935,87ba5114,744c3d0,9030be19,9ccea57c,7f80be87,bfb5b79a,8f8e200,7c2a98f8,b4526422,b211bea0,875a81f1,d379012,486db005,e31b9682,404e14a3), +S(cdf20316,f4b63ca4,c472e1cd,b3a938be,291d98b9,3ad8f3f2,4f3e1a4d,f1a6cc80,ab993e8a,68988d4d,2749760f,241399c8,136ee9d2,3d4ae7d1,e6d26df4,6056587b), +S(1d341e6,2eca1f48,165bb2f3,86207da1,f2c7fc86,dff7a75,cb63976e,f21bb074,923b53ed,fe2f5bb5,56aa7cae,2a08ff86,160e3344,c4adc09a,e7aeadfd,f31e2b9c), +S(8704f69d,9d335975,f0e3bb83,5aa3024a,60103d89,e5578253,fbb3d537,1983ce4e,94f4adfa,31dbd13d,95c738b2,8a569453,cba45efd,1cfd20b6,78f6a724,e9a8d025), +S(7175407f,1b58f010,d4cda4c6,2511e59d,b7edcf28,f5476d99,5cf39944,b26b64f1,bc4baabc,bb1c2aaf,c92cbfe,ecb33791,4fe01748,8bb8e2d5,bd918104,4dbdc75a)}, +{S(a16a4734,9afd167f,d5e79d24,9784d87,5121fa24,2c3a54a,88f9b176,72669aa1,4df3fb81,7021efdc,e5296735,3a177b5c,51cc7762,4755ba28,1084db5c,4809e02c), +S(91d1abe3,8d3f9671,54337e03,d27fa6f8,c3007f32,323d15c8,31306b3a,30900328,b1b8c71d,b388009b,98000f9f,291b66e3,f890d42c,a5812f34,5c070f6,e73b89f6), +S(61b64b1c,f2a0e720,e9bb4853,537b9f38,66baff87,388df7f9,f14c06c7,12080b96,44444011,b6ddadc5,7ee00eed,b6af3772,e4116711,c3853f13,7f9c7b00,2bf2a1dc), +S(3b96b2ee,d9cf1ed6,3aaed8e9,aca3a464,d6a6fbf5,e6fd48f0,5aacc318,dfdbc87,51c41c26,506cac9e,bd0c5dbc,8ce8788a,3469e42d,de794707,9e0cd0d9,826e9c58), +S(7bbd147f,77b293ac,ff797b9,a52778de,5874b754,c08df397,72ed8ef7,53242efc,3e843df6,75abef2b,e4d32c83,205322cb,f53bde0,2563eb8e,b5dfbe6f,27d4cada), +S(becb7fc5,de84f994,9f97e55d,bdb6981e,f38c0c45,1e0e454,519c9411,5bae3d7,754145ec,ee6f9c7c,f91963fb,5b0a683a,ef24313f,1125570c,c9b9c7d2,afab99a8), +S(87936626,aa88346d,6d4330d9,3a188ed6,992bdbb8,387b395e,d21dab93,63d833eb,a28c868a,18dbe0e7,12ca5237,53f6a50b,9313e687,85f3b31f,ec778fac,87aa9327), +S(e79d4b2d,e33de1e2,e7eeeb44,d197aec1,f5883ad6,1394dd79,de274ef9,76e3b022,9c73ade7,7c661527,ec2ec6cd,b370c130,380bdd9a,4bcb668a,86e8259a,ca85f293), +S(863f0d65,34de1222,237a07bd,ebb066b5,2c1cdd83,d7a6d3df,278e57c8,bb59b8c7,c546940b,99d04ae2,5cf7c881,28a985cc,9b6223a6,ffc06fe9,8a3e0f68,439b9db6), +S(71e9b0d1,3972d9e0,2225bbda,5a1024e9,c373eeb,f6514eb1,c113ef88,dffdc3a,4436c52e,c58a34c,562638c7,8d76e3fa,29e3586d,fa667577,2fe0b932,c4a1ade2), +S(ef4a500d,c9369125,78fcfcbe,3c313bbf,f0323caa,75750b6b,a317e1e3,dd8054e3,e807e9cf,7911c919,fef82e40,a3ae1b9b,ed8ded38,e74126ed,863199de,c031f2a1), +S(806dd4e0,fbf72904,c7b0080b,4e7526bc,c71fc52d,f143da80,e571041,dd964915,2f4e2e67,3348c32d,6bcc0741,2e76f4fe,944f96bb,d73382c8,c6880cf6,629eac8a), +S(9ea889e8,acf0441d,6e299687,c532ea8f,8b9453ed,5fea0d47,f735056b,1eb3bfa1,e43f79a8,4d302f3c,88698896,5fa7b8f1,a92c620,dfcb3462,c4befe3f,4afbff5e), +S(9a990a22,1d27d8f3,40e79489,58cff3ca,2720dd3d,ac71688d,9c3c9e2f,afeee215,4957ac76,db370918,7992b0b,63370656,7e0f4a0a,9e5f1d9a,be8f7d5e,8a950eef), +S(d3291003,98ad3d92,1d6cbc6e,b37ac3f3,9360cea6,23edd794,64d34a51,fa7adc60,657c110,5bd8df6b,fe52addb,2fdfc41b,810a1ff7,8662021c,7c220b0d,b3509d14), +S(65eac576,e149d97,3cbd772c,60570870,e437e92c,2e5138ac,9c0534df,b7a45582,ebecb6a,edb87cc1,417e066e,fef8e52e,c61eb00c,dfd98205,91d63c08,9dfd5347), +S(b6976b99,c2515be2,2bc901fd,8671255b,f8fd76ca,1f3474cd,5eebe39e,98f6f14f,84ab17d,da67b61c,fd01881e,b1087e69,845aecc9,ce1535fe,1c7245fa,8df98181), +S(c7f5967f,f9910e10,54c93e1e,d0290102,9bf31787,15f53758,f5c53cd3,c79a52bf,bfb01210,5c1ec69c,847ceffc,d1105ac0,528129fe,3b4d3086,2b6e9562,836f5eb2), +S(ffa0da7a,e8984e4,d02a0fe3,acfb4e81,2a63d6b1,682dcd78,fd2635bf,88cfdf1d,49459ee5,3fad1097,2da786fe,45a2d201,e4a52260,7779b1d4,23defafe,29e70098), +S(5a53d683,3bc1740f,d02f278b,2ac15a87,f137f2,c798f157,725a4aac,63f1798d,ac5e7ec5,86d5960f,e25f9e25,7cf9ee05,110d9595,e440d032,c416d444,6242d10), +S(70f67487,9b030a4d,9ccc0bf2,90d5b78,c455f8bd,a1fa2b52,efaf0200,6b70a6cb,10f5b1c5,dc46c0c0,68757804,93805aa7,5a259dbd,95b4bd14,d031daef,a81bf7bb), +S(a4baf0d7,d3a53c29,e78ff81a,52d634a,e009391b,30a9aa91,df8f7bb6,13e3c16,c9f9d001,7f388f09,b6802c45,e1fa036e,99443467,c3847937,8b384a9,dada35cc), +S(351b8e4a,dd336c28,5d140c57,9f2b089d,3c656a05,b1ed6,4cdbaf7e,e5bc671b,b996e61c,cb14553c,b7b79803,c82332b6,704ce97,fb4e19a5,1f70b13d,f8e2732f), +S(d248350,92898c0,5dbb4465,18695efa,e59ac007,d58b5df5,bb3b7038,82f18e61,23455e7f,5104051a,44600be5,2e242a90,95213d25,b4fd65a7,62c3f9fc,9234c2a5), +S(d3fc6d75,10cb0b20,77b52b00,93e84d47,54dd1a28,4f3928f2,a9e3cc02,f1869588,26e86b02,c16171d4,4238aecf,666146f4,9386e0eb,52dfed87,7ac0b409,51ced10b), +S(1c611335,3d115906,182b0e4a,7eb3d39f,552c49f0,c5928aa1,15ae00dd,c23a3b70,1c3e3c4e,ed65ce47,ea82a33f,df8fa6b5,532977d9,53aed38a,f0f4dab3,98477c6b), +S(6487c5c6,abb6e673,821c4b0,2c485f83,3e149af1,83b3f025,71a81fbe,660e98e3,63c4f6b4,7eb37ed6,7668b41,1e83d9c8,9ea323f3,2d9e8918,20b65276,a8a7b7d6), +S(1b0baf63,6daaf2c4,28a62bce,bdd41de2,a4d7cf69,93f0b931,222a40cb,9f5f9a2f,af9a62cd,f91e2c6b,47f308af,e2de8f16,def4972f,24bf4c5b,2b1f92ac,f63a21d2), +S(95bbd974,78e1b8a4,1622e460,8aa82fe9,e77d43e7,492a0d21,1146d987,f9b8f255,412bc52e,d61c3880,210d3df7,f0d2f27,d458d51,388803e,fef1c016,d7c9e7f6), +S(a3466715,5b6ea598,2d3945fb,743a1510,c671b96f,a3494a57,e0349010,55ae087,de35a05a,1a943a42,7210165e,55d5cfae,3ac15490,dc6b0f43,34c0c99b,dd778608), +S(2ed76c11,52ac3600,7aa17c85,a5f902f1,7c845a05,a4e0aaa0,7b05e836,cbcad59,9c60b2bf,bc47a0dd,d3259151,37e89812,a08d39fe,cf5806be,eb538575,3b159531), +S(20e6e2e7,96946bb6,30c7071e,f1b92ea3,d53d280e,e450111,5f5da36f,840dd273,2c528501,b0eaa61b,b5f45e52,6878b9aa,7ee13686,c25796c3,3f8302e9,44b9469c)}, +{S(f040a2fa,b839c753,4e216425,6c2e8dd8,57c52dac,e75cab3d,512a7b1d,562075d2,9e211cf4,bab24e0e,f745e2a0,9b59565b,be7b2449,8123f6b2,ba383b25,29554b36), +S(c66813b,904831cc,12f89e3f,bde93eb3,11ade6dd,f6cfdf72,21cc61a2,ff46bf26,3b60c8c9,9da35a58,7b9650af,f85ca785,ece41146,e7ed8d6d,ef8d26d1,f3d055ce), +S(cd38ece8,7c7a9cbb,e23b58ef,59925633,734de285,f93b3ac4,eb01e03a,adab904b,a5f48fcd,afe414f4,1a44917a,5dcb80b9,30373af9,70e9f22d,c1af80f,a8b06320), +S(72d6f7db,199564a2,6e823a49,eb0171cb,ebb76a2a,add56c7c,6d3102a,9c3ee18c,bd2039ec,c390839f,e2d4451c,9437fef6,3e98dc62,3ab0eea4,c56376f2,e270f626), +S(2ea6c313,1e101867,2454e15c,d34d5fad,13829d5,4ca86062,f074e512,a274167e,67e3d34a,56f12e1b,43687f51,c2d56395,14355d7d,9cc52726,22f62ab8,91c8d5de), +S(d66bdd78,8b20da57,b2485804,a2f6e2ef,78c7ca87,ae1c5c66,fc533533,5b624162,1a8688a1,300e6d39,e130037d,3f074ccc,57addd1b,88977e64,2ab296ac,d6e054c9), +S(6d6458d5,d1683d85,8f9e40,15e5a94a,73868bda,54f6139c,446b5283,6d211542,e44c7ca8,33761e13,ca5458ff,dc682f22,3819411c,a3c5feb6,24f06412,471b9f5a), +S(49f8063,b3d98f6,f159f2e6,65b0e07,8ef8c7df,44da06c3,55b592ac,13402b9d,b0b2d838,4b24ab11,de895013,e897e825,45c3e8dd,6cdb0990,555cd871,5841f8cd), +S(8b2fb6bd,e60449da,2684f8e3,6267fff7,254051ac,faea37cb,102c9bfa,91abb2ca,c82cb9ab,c33c1817,10d3fb19,60f2850b,5072eb47,404266f7,c7964fb,f98027d3), +S(cf90331d,73644476,47c8f86e,eaa6e67b,f3fb4b3c,4c895b82,30ab2f38,80df1e42,9c493d94,3471efd5,ea90f723,db576a35,8cd1ee6,1a119b56,6c65b16,112eb2b4), +S(e70667cd,8d2759e,43f99417,ecc505a7,953d80dd,e7ce2cba,3c8c948b,d43a912a,92a534b3,51449a66,82395a3,b75877ae,851923a2,e791acc3,7293d728,777a2247), +S(4cc07d11,4a715e9f,4b4d0811,f0337c7e,f4bdff74,2fb008d2,1ce8a9ea,50520d47,478b279,613d92d3,dd24ae31,2658eda8,28a7d628,f0346e04,5d5d9dff,7178f093), +S(2a1cee60,4cdd3b2c,1f859bfa,af63d7e3,9aaad910,92c2a38f,a9362798,9753c30d,325c248e,d409e8f3,b96dccab,6fdb62a6,83b7eaf3,36d2864e,b821663d,ed31a6f5), +S(7c18d0bb,9a01969d,302616cb,bad8722e,d00103fa,9985a50b,765f0e2b,9a2ea14c,f6365a6c,b06e4749,c48c212c,63fff571,8f46e0cf,6fdc8c42,34d4db64,ceb72080), +S(a706754,65cde407,e853e882,8fb7a2fe,98638d7e,64b8df0f,b0a7a0b4,e629d0ee,fd694b2c,1354a5e9,415926d0,1590eaac,dbd1b36b,5ecc46b5,72467c3f,e2cc5393), +S(7ff57a63,36ec73da,cc1dc527,928cc6ff,4ec063b1,56b36292,23b8bbb0,a8ba2c7d,4d6dfc43,da0fe33a,1e75dbf5,5e5d669e,be6471d,eb8a4102,6db1a41e,9d5da637), +S(d4b1f7bc,87558c27,7e0fdf91,22bfe488,b3182555,599dd384,5cc039b5,93218e9f,992f79dd,c8f46682,5c44a54d,626b352f,7f59139b,d545f78b,44bd0b10,55c3c1fa), +S(897773f,a9de63a7,46ebf58e,248d0c21,10f90230,a792f0b6,ea5a25a0,9d1940d2,b7c7dd27,d561dde6,ca7588b,8e3a09c7,16297ba3,9d501744,f9639a25,b16b4f64), +S(2f9cb312,b071a600,e5d24cfc,79b0fdbb,f6da1527,10ec395d,53078453,1a3b07e7,49260f95,757b9b66,feeb5c20,16aa051,b444bfc8,836fd8a2,ab913e98,731fa97e), +S(5c53b27c,4c0ae241,8569c806,8dd43a5c,6fa23ac6,74d001b4,eee6a748,d86c9e6d,4e0e720a,f430972f,b0ab89b8,79a56eb4,f0af5161,cae83ca1,964a8099,f9d497c1), +S(2671ef50,5a321387,9560f0d9,e8588707,1c2b87b5,d06bb9d,dec3d179,6275b098,750ea18b,dbdcbd58,be994eb5,cb3539f5,8c3dc630,7d50bbf1,f69050d6,235826be), +S(59baa5ce,9d6e707b,b0738f4f,d37c9890,801ed796,a82afb2a,ecd2c5ba,195be65b,e6b66356,20a8a106,b58dc202,10cccdd1,e0e8c579,c92f3fbf,8b335765,b30d8291), +S(bb422d0,88abedca,e4686479,295aa1a1,77d7e68b,293bcd31,4097ddc1,af764b90,a96d33f6,46d4861d,a471f853,e0c6ae32,b1eea619,a7441504,a773f5e6,fc548805), +S(8d7df8a5,f08ba2b0,923662fc,e594f111,5295cf6e,c5aec9ca,df0f7236,fe51b362,26452215,7d8572d0,f057ec9,6f572f11,ebad3fd0,56032240,26b54df2,991f9046), +S(9e2b1637,352d8988,1e76fdec,c2dc8533,6a71b18b,3c98e59d,397602f5,8b9087d7,b997404f,1c0b1e64,90cff078,fdc47c42,aedf245a,e69d844c,18a146fa,6d8c3d13), +S(972c7bc4,6362bca6,b58f1d0b,87c0b8dc,fe91a217,7f0cd7af,404f6f06,47e09358,cfda778,a59d944b,4ec08bcb,3aabd70a,cd6f29c5,204c9161,fe2e5bd5,71d03f6c), +S(f7dd32ed,89ceaace,52e7f26b,202ea6a5,c7e8ff42,6c7ebc16,12106f7c,6fe51a54,7349c17d,d8ea6ad1,cb346e3d,26989950,3de00c11,4205b3b5,50d27ff7,67efe75d), +S(c9f96f88,3e34aed,97351928,fa77b07a,f4b01bb4,e4515f0,59745ee5,decc9fbc,6fd62453,dd6c9dab,10fb7d79,c15b4822,178eba31,258800e4,519e627e,91ef20c9), +S(9c28cc93,809b35b3,96a4c9cd,d6976391,17402ffb,5588cd76,7c41a92f,e971a9a,ca3b2634,28513516,86a661c4,747aece4,c8130d93,ff4108a6,3365e725,2bbb80ce), +S(263a3fca,437c4dbf,48ca36e6,aa892d61,abf58f6a,d3c82b1f,fe945dc,c45a15f8,604c5bec,69e0f1a7,3e8f8a80,4f762cda,96ba2198,35268887,910c8df0,e83d3044), +S(7fe42dfb,b3466ed4,d7cb8242,5e66b5e1,14a70516,b118911f,9170656a,3dbb04fa,d11385f4,b0a3a0bc,cf09374f,868cb30f,55175d77,2d3e463a,a298b6ed,1e6f6fa6), +S(53f2432b,a8171714,3fa9df3d,ff41ced2,4a29b314,bc5a8c96,f5f6400a,d7c0979,42ad1004,3e0f8648,332b1c1f,6ee4f821,b42a5b0a,361747ba,60816f2,ac84c58d)}, +{S(b8b52efd,bc367a5c,a1534bb2,f339a048,50fc4941,1668780,dcdb8b51,2daa7526,306a2236,856070ea,1e0fd846,cd571889,e20968cf,cd490bc9,facfc4e5,a5970b2a), +S(27e226b6,ed59c89,5bd20232,bc677c35,495d9601,5f37493f,5075718c,2017e42c,a130a5c8,54ed8ab3,ed657e0f,ee4a04cc,1b59a291,6e96465a,74b36144,7cc621f0), +S(1733f1c0,da38fa79,a7b37988,1822ef51,2392d8cb,59d1ad1e,afaf535a,e151fb64,a93ddb00,af779565,eeb230af,815f9434,958ad39b,387d9069,a03cfcb,8563a920), +S(e3f4b777,d06c8839,c63dfb41,73281787,72debac0,ed45b991,724c19bd,85ab3c58,2d6a84ea,745decd9,e6444b7a,dbb59fa3,21957b7c,3f8141e6,fd633d3f,7539dcdb), +S(a2b42fb8,9ac10df9,ebe804b6,c105e855,25cb05eb,7407d383,3031e216,64491ff5,d0973dbd,346a87b4,f4ddfddd,12be3131,e6c6a397,8e17be2c,bda23683,62f80765), +S(66d441a2,6b28378b,cf23d33b,ffac1163,7c23bbb7,7ad352e7,ff5cc09f,41bf6e91,982aa46e,5fa0b19a,28ecfdee,539c0ec,b5f06e2a,217f7687,6c3cbf1d,e92a6068), +S(3721fccc,20338f8a,779aceb8,eae3fc7f,bb0e4040,1de2c8e5,27941ad7,f789d0f7,d9516c54,8f457b6e,d44f6bbb,23f36c7c,e6fdc548,60e5042a,b3dd4f67,ad5ae3ea), +S(959e980,4618bed2,73b5cc48,5565df27,b8e09c9,a128a9e5,ea92e347,66e02015,cee3a227,1bddee01,3582d65d,c3e26c8a,f80a4601,abcff432,b1737127,91ca15a4), +S(f2e81d16,c19466a6,1b56931,935d03e2,aad6b8d0,7f193d97,bacdc29e,13cdcf38,afb8e973,8d563dc4,1e7688f6,c6b43b71,f366b576,9479f093,88fd09e5,faa1063f), +S(98305a48,800f92e0,bd815192,7b8658fc,60a97c64,c9f97383,68812614,3563910e,d32db8e2,6699b969,5b644c08,39f2399,f8ef45ad,a0d857c5,2d0c7c3f,96a62993), +S(8dbd4fba,113c50ba,ff3f251c,96aba9c0,440d8e69,8a1e4ec1,84fba97a,e497c443,f642b1d9,b012eef2,40c6ad38,fe441d11,cfb42ec2,a3c15540,45e64c76,c15be491), +S(deea5bb6,c7eac0a2,93e90817,836a3e55,2a7f1354,395296c8,97964c2a,4527a727,4cbe143c,c9fde617,c6142335,4323b9d8,bba13dd7,fbd46db5,cbf4ce2a,11c9c00), +S(349f46a5,8621034,9f207a07,4558787d,336cb0cf,a56c1e67,8dd3b04a,4d717f4b,a6479d8,f7f017a6,32c369c0,8679fecd,985b3c16,ff444ba0,3fe43575,8b96455a), +S(a6d818c9,dc182fd7,81343bc,b737811f,611c8499,e44a6cdb,33a36beb,7e44b545,1a8ee36e,d6e9b191,b9cbf840,3924e6b8,ac3c3f8a,cbc9a0b5,ff965d6c,734d741d), +S(f9cad333,7b82ea41,b00f3ef1,bba37b8b,fcb24e8a,175fe380,8e399b67,d21837e7,cb206854,4e7f2cda,28c035f1,b8b50009,319797da,bb498b99,d31e24e2,4fa27ca9), +S(25042b59,f9b29a9c,83d04515,c78f1c25,5b72f97f,7b387113,e88c36b9,9da3ebdc,d966ba9e,a7eb9734,e1481cb7,2df63252,7492e1c4,43f1fc9,c0efe0af,442b5a13), +S(e19c4319,b5c9a01e,b588c629,8a7c6b76,1b80bf4b,e39424e0,666ddc45,fd57e0f6,1b0a2c30,4a1bb1b1,9dd0b50d,29df625,bf958a73,46cc6b1d,81a213a3,b6636285), +S(59c26fc1,6d151c0c,7da0edf6,c474463c,587c45cb,7e407589,d15aad89,de223fa0,f7b227b5,4855c1c4,1e576431,8a7106eb,ea214686,ef815b42,db8c18ae,d5c940a5), +S(d967d546,e07ac1c2,31fd50df,a1d25a51,60594d88,3e816f6a,bd62c15c,446aeff6,8eee6c03,6e22a014,5d9cf3af,9b44e005,cd1d36ce,d7c420f5,e2db918b,e4fbf83a), +S(424b149d,9104254e,3f5772b3,7d973cf2,a46bd110,89d8f850,7666f04d,382c972b,7272ad07,54c18fbd,66e2abb3,952c526,d8113d5b,166283a3,9ac8ecb6,2b7a3e46), +S(40b4b2ac,bd299270,e64bc470,8607c586,3bb50913,45e573f3,a5e2461b,47dbc053,d094311e,fd81bb1f,4622d17e,68044107,a2a8ed54,3cd5ff8c,b531b28b,9b8ec99e), +S(79e79ded,6bc0d851,fa769b5e,8d65857c,f3c1c18e,6c990cb6,116fc45b,63e9f924,4fa89e89,ae4214fc,ba2aecdb,41984788,8154eaa6,bcbbe29f,f04a6262,7299f469), +S(a11ad5ea,59c644b2,8dd7402a,5f96a970,68d96e2e,eb77d59a,fe0c2fc,cc6b252f,38e379d5,150109df,36ed7ad3,a2daa41b,4fb9c731,718cf5e3,8f8f8cf7,d1f3d770), +S(b3002b00,ec5be154,cd8e5226,4b97f5c9,f444b305,8f59c4c,bcda5edf,9d10dc88,f7e9ae65,6ad2c823,8e8e0436,e007d821,b17d9405,984eccc4,617e3977,2f25d636), +S(8d1267b1,94da1334,fd20cb8f,77fa01cf,9e9ced90,43107e41,d1ec4057,eb6115a2,a7ba1b9e,2c6f0f19,5ff1f50a,7a8da22f,da3003fa,44b818b9,953b44d3,e6d6a0df), +S(dde6a3a0,87ef41db,2359e4e7,ca7cb064,424301e7,c5cbb5bc,4b6e504a,f3af4837,24175b1c,b4b39b7e,23718e26,be4a22bb,8bf54302,1f156234,e7f18010,d538aeb), +S(79efa584,2fb89f4e,85f556e,c4be170d,5c1ef88a,3f3f75cf,6b20fc1a,96984ad,b0704aaf,e4d8f30f,4f29fa85,6d55da13,91f5f3ce,36cdef6f,25133999,cc8541a), +S(3aa09dc0,5546977f,7369fa0a,7b60c94b,eab86a1,10d85af7,7b826475,7d67eaf5,343b4cf3,aa6c5ebc,ed041d7f,2381be57,f7fd32d0,29a2f42,a7c8821,4f425d8), +S(53fe8af9,8f9419fb,1445bb6a,94750d46,46be9f37,b7155763,88b11064,df2e6ffa,6cd77e81,84aeab9d,e9bf3093,bb9b21a3,a04a0719,fc428f3d,d5e14c8c,9b16cd7a), +S(fc395dc4,a5114dc8,bcb0f7f0,3a4d3e9,38a87a3d,78d33864,d1dc4cba,9e41e20e,c7991f6e,f72f82f6,b3147e56,74224929,fddeb8a5,97a1b1d4,8852733c,1830b941), +S(b1d25d51,b4558f5f,d0ccb868,3af9a9cf,62a169c6,91627fa5,92d80b18,36695f94,8f92258d,fcf16f4e,8415f53,e65457e8,9f090e72,5479c123,5a481464,a11cd4f9), +S(b866d6b1,42df940f,2cf28b54,c92f0c12,94e0b6a2,2a91f2ef,44bcd88c,4384480d,e6eb4f4c,bd95148f,765d8728,15652853,db1add7f,b4e27929,f19a64b7,f3b34c87)}, +{S(d4aaf32e,dd897f48,5ab16466,76d747cd,fec5b7a0,a05c917b,60c07311,45d16f89,4857e649,beff4089,2470f700,cadb73ae,d4866a84,c3f0b975,6fd8570e,df9d29d8), +S(4ebe5b8a,f3b1583c,9f41bd98,afaba549,f45c381e,c93ec9d1,4a543d87,9cefbaf3,63ed1d17,9b215f34,f1f580be,4b3f671f,2fa14689,74cd03d1,19fadae3,c92935ff), +S(20df6160,556dd3c5,a26620a8,70ff5323,cbbab94,be3e3bdd,ad8b936c,554f28f1,7168e7ab,cdbafad,26fbb5be,a09dadde,ed36c20f,c8deafaf,75a480b5,f980e981), +S(86c663f2,cc6f7ee2,50be25fd,fb35fd8e,5873481b,c477bf5b,c0f1bc1e,3f1320f,c13c5795,cce0ad92,e31240da,90a823d0,d2352314,f2852e67,cb62e0c2,8570994a), +S(3fd8085e,57f6870,b25e41d9,7df00126,150f6022,a7ede22f,d27da581,d234ccaa,c6657746,98d6ac03,ed1ea2d7,bd3f70be,86351c5d,407a4d7c,227fd7d0,c330ef04), +S(1510fcf0,b0fb5a23,c15e041,2a7f6d89,9fac4244,8ce316bf,d88fb58b,10e23118,1879dc07,b34d0a62,f0b9517f,3629ae0f,e8aa6d30,5a783f37,69bdf65,3b40408e), +S(67e9982b,c40f427,98df055c,2d8bdcc0,2ea97bad,68d34024,85498e27,d99e19e4,4f087caa,efc5fd7f,b099c134,a273635c,d1d5ace3,26e3103f,9b2fe22c,e95f288e), +S(e8eeab21,6c3395d6,d16338ea,de4108da,1c25e471,67fb13d5,99e8daaf,93e7345f,7fd2ba87,7c7266a5,65a31548,99950ea1,e5e3d73f,612addea,318ad5bc,a965228d), +S(ab20c7c8,9dd74c20,447bc762,e374c548,e7a8ac31,eec11123,1a040cd1,36e9a546,facacfb2,52eb9532,9106a26a,60128a0f,ae1d7e5c,fd39483c,aeb54dd9,231b55ee), +S(a9004211,b7cf5494,1c530a0e,d658fb6e,3b5d2ee1,37b7d7de,45fef6b5,efddbf0f,58cbaf67,5cc5a131,54eef7a1,462b5d1c,408d5d56,3553ca55,45388d77,c6391d4f), +S(8db64274,422ae0f5,6474b83a,89912fa,e3a39b6c,b3fb8370,308a572e,b6b3c020,9b71a72d,431fd44,aa8632ee,23bc678,61d96edd,b7ec72ab,4b1679b8,a4ba73e4), +S(301b330,c478189d,dce4314f,380cb2d8,38bbd416,5dfad8c4,90f2443f,2a56148b,737da0,1c05cf73,db36a1a4,5005f562,1327167f,d3b60ece,3da3705d,131903fe), +S(b9cbc7a3,4a1cbdd1,300e789d,b7ffec1c,dfe1f738,fbe1fe19,67dd7c14,92ee3ba7,5a816a0,9d08c4be,2b8d062f,200fde4c,534fbdbf,854c7e53,64532c08,60c97c01), +S(6a15e51,6f9f0a7c,25f2eac7,649285ea,d86a1e01,5a386dc,c7f94ba8,4782b45b,63eafaf4,660642ef,988aeee7,642e7c4b,71124a1c,2ca2f5c3,d4f2eec9,ea72d70e), +S(f4c696f3,34c56e08,2ab2e627,4d450f34,fa7fbce,29f3e14d,332bcadf,87d5fe0d,6ee44edf,f574d9a8,363f98b6,b863a648,27d3020,1e652935,be12041c,1bbcc7c3), +S(d2f3d5ad,237ba177,ed312bbb,1d02fb2a,e4bda20f,41f5c217,8b70dd9a,c26ee9b0,cc5912d4,2ea1af01,aa914b98,8c42cef8,46a5a059,664c8545,fc00b662,e0327920), +S(5588b0a4,757beb33,e668af5f,adf87fb3,2aed8e16,e6ceabf1,1576ae17,c6a2b843,70d8961b,ac203e89,c437b88b,ce331309,c4f7eca8,d614299c,74aef9b2,17c741de), +S(f993cd07,f6eb75ad,d41426d5,cc653886,18dde1f0,88aaf3cd,b2631eea,158373e0,1e74f804,5f60349e,a85b90e1,206f0ea4,b0cd3740,861186be,648063e8,58c2b395), +S(2cd04170,78291a50,750218b9,44a11a64,1cb75e7d,cd5cc4f9,64f53c8d,a1ef08f4,1f54a70f,f66ce343,c7ed3001,78d7b99e,49129e23,90b5a026,7ba25af5,3467b6d3), +S(52fc09a1,d4f0cc2e,c7ba6cba,1b30e1f0,b9e37f31,3bf59c33,60fc02e3,3b0c15e8,9bd14bcd,a7c7b6ab,dd7e17dd,ab81a1cf,846be336,a76858a1,8e8a0194,776f0a80), +S(90d29aba,764a9b49,1e2878c2,9b964bf6,e510af,3dd5aeb9,3fe29e13,b8f03b23,396b1f6d,e9b8fd1f,463ca064,11b09823,26cb6ab7,4bbbcaef,43031497,f149a620), +S(ce1d6e8e,ddd063f4,316cb006,b4a4213d,9e0952c8,43e6e1e7,570a35e,aad7fa53,a1abcd7,e2c23ad0,895c5aa8,82a805cd,1d7d434c,72f0c528,2ceec0b7,a7016f7c), +S(4df6e1d3,93a4be66,6fd88c75,e1e686a1,e2cb1844,f5f1303e,f7b0a751,99b42bf5,262d8b9,f7e202a3,78a51928,91ee3fc9,f269ef5d,e14dd0ff,f1fec9f4,4cdb9058), +S(f71b9bfa,bcc353a4,11a055eb,a7d6f48f,47c4e437,96382bcc,d5b882cd,a9059638,bfc1c3f8,fea7df8b,d1cd088c,b1f02e47,377d6656,9b3bd8a2,8b457ba5,e6453468), +S(ad5e9212,d3ef76d,8319fd98,72ee753f,ec99fab0,6244f4e2,a9567068,a635eb53,65fb538f,cb570092,7b0f775a,73ffb0c1,4e6c2274,e253f3a6,2dba9caa,27a3e5e4), +S(81a7dfa0,7659fdbd,57e1c8ae,20c14a80,ee8bfc51,46caa8db,b077b653,23bad4a,ac9d2438,3ef0d99f,26744be4,77e69d51,49d44ab9,84801bb,759d3a5b,7fed1e2e), +S(3bf8c1d0,a613316b,e90eab62,6788c8c3,b1641d65,d0e50245,9e5b19c1,ab1eb617,e1edb59a,8594d73,669e6f93,ca10e210,1254946b,8c9e8eac,3fa84a49,e4e2944f), +S(30f9283a,767c551c,e9fe87d9,5730eff6,fc302a4a,1810e4de,11ba62af,fa17eaae,1f383ac5,e714240d,67980617,d96b0c05,76008599,f8e3fa04,d57454e9,927e729b), +S(1c5d4ac6,91d37d0c,9db5e071,c809a59e,99056263,fbd83028,ee9530e9,c2b3f3c9,b98c7be9,7a2fb196,3d3d4a75,4f7fecce,2fbeb8fd,cf23c229,73b6875,86bd276a), +S(3dfe48e5,2f055be1,1db79fa4,501b44d8,f5ae8447,c5a1293a,a79f683f,1e1e9bf,2d7e8303,b988fc17,18c9b64c,1c03373d,27fd0c32,13c26e6c,b684ca94,49f79d5e), +S(adc4251b,c3ef6d5a,a4d6eb22,46ab2787,bc835b65,1d17ceae,489f181d,57d37248,4f0c489d,1c3a1814,a2f9c1c9,d6fe908f,4623aa44,ebaf4143,79fb8352,15234014), +S(edfe16b2,db401803,11f98920,7a2fef7,d05b2a3b,b676899f,9c6e2192,d38f93e0,1196fd0e,35a24c9,6b28b055,b4fa2f2d,a4c2aeff,3b91dd81,c2fe86c1,1d6bf682)}, +{S(b4b57b34,6e1b41b,7394e655,e059cc93,44c5d83e,f0ef17db,2789db5d,13777b78,6fa187a7,4d983b7e,cea6a268,61039430,63e599e7,cba73144,fe3eb23,677c6265), +S(9937238,7300054a,1a8713b7,6942f003,99818b28,6c6fba5d,ca60b9da,1aa7767,6c003e1,848ce30a,65601eb,e7b76acf,b2e122b6,882d7439,f463c042,ef1b31a), +S(ebd177f8,b5757665,58851c7f,a7ada38b,e3596080,f2679181,f994efd3,82714784,d0fe8eb0,97c852f7,b284d5f,bd81f77f,79c35af7,cc30338f,4e63211e,9e20a244), +S(367ef258,b279f923,a18215b7,67d396e4,c6bc874d,2be6b369,b01afffa,2e041741,bd961242,2452eddb,33831dcf,fb3a0273,30ef141f,6db77d91,5bec2ecb,553b6e6c), +S(d89f40c4,f752cff4,5bae5762,37f5096e,f27d46d0,d934d4de,c3011a28,59464e8e,9d32661e,e2319d6,f6427ea,a3014b5,cf98306c,666c4a9e,970dba2e,65e04886), +S(ef6ff862,1d84c5d5,22e490f4,db21181f,a17bafea,3e097868,4f1f0215,759772b9,ae006f11,aa85db2d,3624cf51,ae319ad2,8b4970e7,eac03301,1eb15db8,dc59d62b), +S(8b0a1b1b,d476bbfb,6da1d071,68d3a988,3b49802f,8ffa04a3,bbba1313,17c67a00,d8c74ae5,65c38597,8d9fda2e,dff6b932,1512e40b,ec5b62e2,59d4d81c,9b657b55), +S(9aa9250f,12ffde38,21384434,849d7eb7,bcafbae5,9a3b861f,68a3addb,d75d3715,19b4b1a8,8d8bfeee,38b54564,30d5f73e,ed0365fe,49092d4a,2f52fa12,b65e3ac7), +S(aaccc00f,55e96f0c,e66d9b43,12f9abd2,6772d8b4,30a6c62,edd2aab4,97acbc22,5af203cf,97d11147,82374056,f012f5f9,2825476a,820dce2e,6e1c4b33,cef5337c), +S(43c34546,2836b544,ddd6e432,6aa19b4a,9de7fdfb,86f43cae,ce98ce7c,32b1ccaf,dd518249,f1fbc1c7,1f905860,17a6f60b,15be97d4,18c66d42,f4f9adcd,d722c096), +S(9a38eb25,935441ab,8983097a,d58c821f,d784f091,5f85dc26,3f0c020b,b80c39a0,d8e6dc57,41e4ba5c,576179e8,9a6dcb4a,bd7178c6,13a1100b,e2bd731b,f3e819e2), +S(6b10527,204a4f7c,e8afcacc,fe771634,376f18da,f12774e,50f23a90,9efe0223,b443a451,529b4208,c8c98904,f5eb2ee,2e2ede2d,80ca50c5,aa29b95a,714181a), +S(1a88fecc,71d7550a,abf7faf0,8e884e95,835f6dc8,1815d2d7,7dab66ea,b238d6b2,82cf6711,1dd38ff,d0daebbc,ea2c064b,17b6b21d,34804f93,4a037936,9edec692), +S(a6b1751,f30507fe,5927b6d4,a92ebbbd,77358c02,9b750d05,a56e4d41,efb99144,ccf7c048,a2a0983d,fdcccfd,a071b80,e8035866,c479ea3a,3bbe7c80,12dfd618), +S(e186601e,8b545292,f23ae7fa,4cadc80f,1fcaa1a3,430ddec6,cfd2af47,c835cdf9,fd471f16,7c3683c9,2e5fc0c2,89b646a5,c8ebda6d,5b6da213,d862c3f6,2c292e9c), +S(91b3935,d8ce2b80,c179ee0b,87850140,4c418c7f,7cf94e4a,64b9fc9c,e396a093,45a5043b,8184546c,9083982f,550807d7,d61fe677,ce73ef21,9b3aa573,97c4eca1), +S(3fbe61fd,2a387654,dfc428e7,dac09e91,5e1ae7d6,d3794288,743f2535,20858ef5,206fd9a0,e3265118,e0a6475c,4df87e43,cc7c8898,59d8aa08,23b6dfff,b68b34d7), +S(31a35020,697d9d52,55476289,ce4fcbdc,4e1e0690,c2c36d1b,a4f4640f,e4c5ba18,91f660f9,159d463a,857f08ad,fc3c5ddd,804507c5,92f73de4,2ee44555,da538553), +S(7dc6b83a,10f26e71,e12c0bd,7ebcccc6,61b4394a,68f576fe,bfca1c23,256e8aa2,b4796977,bd386b98,f3e2fa8e,798b6548,fae52a80,40bb12ea,7e6ad675,64fc8736), +S(67a9c3ff,9c7b99b2,5318ff9e,2b85ee23,ec244655,8042ea8b,d880e23e,7d3ce221,a7bcbbbb,895ca7b1,847a43fa,98809ce4,98016123,bbb3c099,7d34debd,cb023f8d), +S(36602997,eba2c6c5,aab4cb65,8d4efd46,65ab3965,f643ff66,831646dc,f6443bf3,c82d0e80,ef775f9c,7ec7862a,e3158556,a57038d,e6850dd1,e349629c,2546239), +S(9eb9244b,299bfd76,f63bb140,ae2f42a1,4af1e072,83f8259f,6478ac03,d411df24,e43f91da,13c2ba21,a9d17d2f,7a8a629d,9051346,93a6552a,538d590,9d2bdd38), +S(ba4450fa,27d57993,3d949a1a,66013906,7d1a9716,6794993d,e45d9426,b4bfc5ed,8e3f3b9b,d8cb8210,7a5ae2af,92b96259,b73633f,6528ac04,20c3e101,6bb6d8a8), +S(e6d5335f,b67abd36,2712c7fe,575ee769,53d488b,236e8589,5664fb04,7f385248,9e255154,e070a5bb,e98e97f6,281fb999,a75e68ea,7681fdf6,fea093bd,919aa5a4), +S(63c099a9,300a331a,3bc4348a,a373e514,c84a810e,1ea8a8d1,4ac8d7cb,818eb534,ed7d4029,3cc4a086,b1d40c24,6086109,a02dbcb5,a864777,27939024,6fd6bf91), +S(7088617f,66cd93f,8130eaeb,874c3f77,3bcb0daa,78923b70,a65512a2,992554dc,5a3ff995,3c712066,291ac4a2,dfc2573e,1d0aed56,75ef526b,b15f61b0,d20f8156), +S(cc354aaf,746d756b,9387730f,2f12b999,4fcd815c,6d25cdab,2e1185aa,4aa639b3,fb1dead9,4fd76859,1aac8d79,5c337924,dc155fbe,5cd5c953,4d55ee31,f6d284a6), +S(e7e47c3a,e2bf4307,7f33ec3d,ac1ae2a7,5c669e61,e248f588,590cfe07,3e2186e0,46e9c4d5,4429fdcf,5efb375e,18f46cc8,3fa7a403,6013777f,e450e228,aebd4cd0), +S(c6ed5e63,28ec31b1,37041108,42d4ac23,fbb883bb,349d88db,1d747cf7,325fe9cc,21b8bfa4,b62807cf,d6cd11ed,a38084d5,7bb068d4,9f0dd30e,f3f431e2,b57022e4), +S(331924c7,50b3417e,48e279ff,6ed7f3dc,ba2e121e,9f69f8fb,e64093b6,c38a8cc6,357086be,e4cc0fe7,d45a49fe,41d004ce,80466165,316164ab,3b171f03,b9a7841f), +S(b4319cc9,f3e0d3b,313626ae,5385796b,c49b300c,88ba4553,dec0aa4a,77829372,b8f82bb6,6590afd4,48501f,63de3a5d,8f84edea,35c1ee44,88d6333e,f522a808), +S(da433d5e,11ceccc0,abc5c762,6ce7bab4,2e89b221,f785c409,282de545,f3fceb19,1b67242c,de57efcf,e214423b,506a1ade,718803d2,6dd84d88,97b18ede,590a2fcb)}, +{S(ebae7464,ece277b8,309d056c,cf3775e2,11a77aa,81c316a4,b6b7b953,6f90f539,62a4d6a2,95fdd811,f2051715,322f17e5,1753c9d0,835ef9a0,3e8dc9f5,c69bda31), +S(5b20700c,1af63394,a3e4cadb,b0ea682e,19cf495a,b908418a,d41f4c6c,ea4477f0,8435d15e,34b03a22,ca89c73d,326c2f88,142d2e23,8964ef6d,99287125,79738f78), +S(b2f25f91,138b974b,561328c0,92f50fdf,8a694004,fd4879d0,12a4a6cc,c8059d1d,d9ec0b2d,b8e81b2,f6feaf55,9776ff78,cda3401b,47826de0,ca06e579,9d866c09), +S(64e79790,7783d6fb,321eb785,acdeb2ff,4628270,fec3342c,527c8db0,a34c516e,c0c4da5d,abf3da9c,a8613f82,ca28e84,a1a18376,c9967c08,aaf70bea,7a2f34c2), +S(a50cae84,a08f4f32,4984853a,d4c6bdaf,77eaa788,9cb8fe95,72fd56e,9078ee73,120ecbf,76e47b38,503067c8,36853003,60ed261a,40fdf440,161ef2cd,19786b93), +S(76ff3ac8,80a451a9,6741fc70,82bc4c82,7bd51c08,95eea8c8,b422b8a9,96ba4794,25555d71,d4313a60,b189a154,58e0a40,c643c204,277334e,966e2abd,3a23f6c3), +S(307e5caa,8b708760,3d9f845b,b78f4f10,72c49c10,9747f91d,192f8d6e,70c0f4be,f5992f76,37167e1d,55cd31a6,1cdb4756,85eb1503,34fb6009,e0240a18,fa8302b8), +S(d8e62e47,b28fd165,4d420137,884dcf21,c10cb159,d9885843,da34b0d9,d09b2758,675c75b4,b903ad28,2055a71b,2c470e2b,1dce69bf,ecf160cf,3a027de2,55b723a9), +S(ec5639c7,73dac23d,3008dabf,732dc005,3154703d,26ee3bbc,7689286e,4a73e39f,aaa5ea4a,2cf5c23d,57cdd0d8,8accbbf9,9fd2c213,97bb45f8,83547876,3aab1248), +S(3d928ee3,2065557a,27722f08,5202f48f,40917ed6,c7ac1963,2a122226,8b0cb9df,ece112a4,e7a05ad6,17c2fd83,76f89102,9eb94eb0,930fb23c,a342d7f1,f021a0c7), +S(616228a5,cc6c3a92,cd694cec,4b2b8574,5dfffa90,b2a36d8f,32eaa6cc,2530de51,50d8d140,4d506a78,700f8e82,967b36a5,1b4de644,a8e22271,d509c8d2,4adf3148), +S(6f85f308,e847b145,c13a07be,bebdd4ba,6c138939,6afd8670,733f44a8,969406d0,864bcde1,be36c9c7,b7e04ef8,cd2366e2,b3c22902,5ee7efce,d005ef5b,ff7dae2b), +S(f3d1ecc3,53a82621,1bd78f0f,aa029076,c6ca779,9bdc54b2,128fa3d2,aec00c6d,75aa0cf9,fd0b7bed,19183e34,58142f66,c94a5aa9,3915435e,ae51c1fe,96625ccd), +S(a5918de3,f18cd8d1,2a234f9f,3a19fcaa,2d83671d,ad566f16,8aea2b1f,b9de41b0,c515dda6,43c0f6c8,d8fea16,5d595917,16b7f521,43d3b941,f28585ed,8a49c06c), +S(3c49e2ef,1d2d3464,81e05fa0,33366609,1615ebcf,535f68,be257f35,7bd91592,57901e0a,c8af3a31,aa404987,72c903fd,175c9b00,5c7458ee,ed667f11,57754132), +S(6c45ff2,c0c30320,83c343e6,dc80b4f7,bb64502a,52f412ff,ada521d4,a544a9f0,e9936037,f1e641eb,1cd6f801,a25271d3,cffe67d,c9bd7162,babf9855,9628a9a8), +S(66df5d95,acdf4260,ee0e465c,e3916d79,395df522,aa086aeb,6c283bb7,18296d46,cb1f3deb,8aea0337,625f46dd,903416d1,5647be91,1633c4c0,cf0e629a,413476fc), +S(428bbba5,ef351762,9eee4059,a3339213,40c7fee2,5ccb051c,88d75e53,ba618858,ef18809c,28227ccc,115876df,b3f378cd,374c0670,2c658501,7990e767,922c3999), +S(e8993820,d782657,ed8badc2,d515e360,df336730,860ef49e,65ca58dd,1a385815,feb41189,16c7e8f6,53c7f5a6,5fd7b6be,7a029814,149c4645,847073be,770959de), +S(2b77e42a,63502244,d6c7d1be,54b7857,9e2742d2,7143d689,fa3f70a3,5986ccf1,721e9da8,bee88ad4,2155dc9a,28be505,86648378,1d6af5b1,382cd47d,771e6428), +S(acffce3a,ed6beea3,2ad71633,21e1ca53,6f69ce76,fb5cd394,9d9dcc14,bbcee96,5384c97d,eac946c0,afc85b54,f3a56b79,fe263bff,63e1894c,6d52ef1b,9b456602), +S(e13d8d4b,25bece8d,90a008e4,c004824e,223b06b,7cf65ebd,1215e910,2e67b639,3e92b1f,14cbee57,9640b377,6ed5938f,9aee0e11,b139a678,3f207cf4,6dd7e20b), +S(d8f356d9,d2498eaa,b3fa12a,cb64562b,dff3e270,c7809a31,25a9ae65,9cb1f3c5,a5403cda,2d499a7c,7402b57c,c9f99e3,64f5085a,91fd8cfd,8a67c7a8,dbce04fb), +S(350062b5,22fb5d0a,8c79a5db,29e92216,79b9fbc6,3e1f95ca,e7d087f3,fedffc49,74cacf57,5e79c85b,d7e77a40,796e8750,a3ca57f2,a47cce8f,3d2de02d,b014df0b), +S(c159e630,9ab23135,58ebfb6b,22edaf93,eac8e16,77cd9f3b,1cd9492,20bf8e54,99244263,53f32608,831c6d74,da51d61,c344defe,f4c1e401,6a3db44b,4c57f4ae), +S(9e568b70,36a2daa2,fe7a3a52,49c56eb8,3fe4afa2,decebd60,c6c3245f,17bc6a13,b6643644,274eab9f,5e83c598,14978681,17c5a078,765156ae,3cb65fd3,830e06ae), +S(9bee7471,6b6c1ff5,62c1bc36,57a65de3,99a91d72,115703f4,4c3819a1,87828478,bb23a3da,ed34028a,7d39a7ed,fe2e23b,73e085a2,d6c2e51a,ef2a2076,a7c902ad), +S(c430c044,91228a7a,ea835698,ecf0f552,9aeef469,a36305cb,52902ccd,1c897473,40d0ee56,61cca82,80d11da,bffe97c4,f10c93aa,5e07224c,154b666e,bcd58c74), +S(2be073f6,b294a01b,eda0b0db,6832e4bc,23ef3889,7a859853,5ee726ef,ae0f15b1,6153f846,349c2a98,26008065,8be2a7d8,311a5e70,cc310ff8,7935a901,8d575813), +S(2934de46,a6d921f8,720567e6,b46e6362,36a7ed53,483b13ed,20958452,3225accd,5979698,26927cd7,abfe4c57,c53fc72a,48b71679,174c749d,aecdb057,e6a2d961), +S(4e9991b,92fa8c4e,4e8efe45,66966073,319e80d3,a54d4b7a,b61cfcc4,7ddaa5d5,9d03ea22,21d4d80e,261952e2,73f6a8cf,c31f6091,e5aa0a8f,2281ffbf,1345df9e), +S(ff3d6136,ffac5b0c,bfc6c5c0,c30dc01a,7ea3d56c,20bd3103,b178e3d3,ae180068,eccdc641,7b1bfff1,bf2fc8d3,2269523e,ab89890d,bffe0a19,8f594490,e7739bb8)} +#else +# error Configuration mismatch, invalid COMB_* parameters. Try deleting precomputed_ecmult_gen.c before the build. +#endif +}; +#undef S diff --git a/external/secp256k1/src/precomputed_ecmult_gen.h b/external/secp256k1/src/precomputed_ecmult_gen.h new file mode 100644 index 00000000000..283738a5ce1 --- /dev/null +++ b/external/secp256k1/src/precomputed_ecmult_gen.h @@ -0,0 +1,26 @@ +/********************************************************************************* + * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *********************************************************************************/ + +#ifndef SECP256K1_PRECOMPUTED_ECMULT_GEN_H +#define SECP256K1_PRECOMPUTED_ECMULT_GEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "group.h" +#include "ecmult_gen.h" +#ifdef EXHAUSTIVE_TEST_ORDER +static secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; +#else +extern const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; +#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_PRECOMPUTED_ECMULT_GEN_H */ diff --git a/external/secp256k1/src/scalar.h b/external/secp256k1/src/scalar.h new file mode 100644 index 00000000000..70f49b1cf20 --- /dev/null +++ b/external/secp256k1/src/scalar.h @@ -0,0 +1,105 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_H +#define SECP256K1_SCALAR_H + +#include "util.h" + +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low.h" +#elif defined(SECP256K1_WIDEMUL_INT128) +#include "scalar_4x64.h" +#elif defined(SECP256K1_WIDEMUL_INT64) +#include "scalar_8x32.h" +#else +#error "Please select wide multiplication implementation" +#endif + +/** Clear a scalar to prevent the leak of sensitive data. */ +static void secp256k1_scalar_clear(secp256k1_scalar *r); + +/** Access bits (1 < count <= 32) from a scalar. All requested bits must belong to the same 32-bit limb. */ +static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count); + +/** Access bits (1 < count <= 32) from a scalar. offset + count must be < 256. Not constant time in offset and count. */ +static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); + +/** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`. + * In: bin: pointer to a 32-byte array. + * Out: r: scalar to be set. + * overflow: non-zero if the scalar was bigger or equal to `n` before reduction, zero otherwise (can be NULL). + */ +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow); + +/** Set a scalar from a big endian byte array and returns 1 if it is a valid + * seckey and 0 otherwise. */ +static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin); + +/** Set a scalar to an unsigned integer. */ +static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v); + +/** Convert a scalar to a byte array. */ +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a); + +/** Add two scalars together (modulo the group order). Returns whether it overflowed. */ +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); + +/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag); + +/** Multiply two scalars (modulo the group order). */ +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); + +/** Compute the inverse of a scalar (modulo the group order). */ +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a); + +/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a); + +/** Compute the complement of a scalar (modulo the group order). */ +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a); + +/** Multiply a scalar with the multiplicative inverse of 2. */ +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a); + +/** Check whether a scalar equals zero. */ +static int secp256k1_scalar_is_zero(const secp256k1_scalar *a); + +/** Check whether a scalar equals one. */ +static int secp256k1_scalar_is_one(const secp256k1_scalar *a); + +/** Check whether a scalar, considered as an nonnegative integer, is even. */ +static int secp256k1_scalar_is_even(const secp256k1_scalar *a); + +/** Check whether a scalar is higher than the group order divided by 2. */ +static int secp256k1_scalar_is_high(const secp256k1_scalar *a); + +/** Conditionally negate a number, in constant time. + * Returns -1 if the number was negated, 1 otherwise */ +static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag); + +/** Compare two scalars. */ +static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b); + +/** Find r1 and r2 such that r1+r2*2^128 = k. */ +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k); +/** Find r1 and r2 such that r1+r2*lambda = k, where r1 and r2 or their + * negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). It is + * required that r1, r2, and k all point to different objects. */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k); + +/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ +static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag); + +/** Check invariants on a scalar (no-op unless VERIFY is enabled). */ +static void secp256k1_scalar_verify(const secp256k1_scalar *r); +#define SECP256K1_SCALAR_VERIFY(r) secp256k1_scalar_verify(r) + +#endif /* SECP256K1_SCALAR_H */ diff --git a/external/secp256k1/src/scalar_4x64.h b/external/secp256k1/src/scalar_4x64.h new file mode 100644 index 00000000000..700964291ee --- /dev/null +++ b/external/secp256k1/src/scalar_4x64.h @@ -0,0 +1,19 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint64_t d[4]; +} secp256k1_scalar; + +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/external/secp256k1/src/scalar_4x64_impl.h b/external/secp256k1/src/scalar_4x64_impl.h new file mode 100644 index 00000000000..807b9b70ab1 --- /dev/null +++ b/external/secp256k1/src/scalar_4x64_impl.h @@ -0,0 +1,1000 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "checkmem.h" +#include "int128.h" +#include "modinv64_impl.h" +#include "util.h" + +/* Limbs of the secp256k1 order. */ +#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) +#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) +#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL) +#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) + +/* Limbs of 2^256 minus the secp256k1 order. */ +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (1) + +/* Limbs of half the secp256k1 order. */ +#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL) +#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL) +#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) +#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) + +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); + VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); + + return (a->d[offset >> 6] >> (offset & 0x3F)) & (0xFFFFFFFF >> (32 - count)); +} + +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); + VERIFY_CHECK(offset + count <= 256); + + if ((offset + count - 1) >> 6 == offset >> 6) { + return secp256k1_scalar_get_bits_limb32(a, offset, count); + } else { + VERIFY_CHECK((offset >> 6) + 1 < 4); + return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & (0xFFFFFFFF >> (32 - count)); + } +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ + no |= (a->d[2] < SECP256K1_N_2); + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1); + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { + secp256k1_uint128 t; + VERIFY_CHECK(overflow <= 1); + + secp256k1_u128_from_u64(&t, r->d[0]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_0); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[1]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_1); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_2); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[3]); + r->d[3] = secp256k1_u128_to_u64(&t); + + SECP256K1_SCALAR_VERIFY(r); + return overflow; +} + +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + int overflow; + secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + secp256k1_u128_from_u64(&t, a->d[0]); + secp256k1_u128_accum_u64(&t, b->d[0]); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[1]); + secp256k1_u128_accum_u64(&t, b->d[1]); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[2]); + secp256k1_u128_accum_u64(&t, b->d[2]); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[3]); + secp256k1_u128_accum_u64(&t, b->d[3]); + r->d[3] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + overflow = secp256k1_u128_to_u64(&t) + secp256k1_scalar_check_overflow(r); + VERIFY_CHECK(overflow == 0 || overflow == 1); + secp256k1_scalar_reduce(r, overflow); + + SECP256K1_SCALAR_VERIFY(r); + return overflow; +} + +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + secp256k1_uint128 t; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(bit < 256); + + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ + secp256k1_u128_from_u64(&t, r->d[0]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[1]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[3]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); + r->d[3] = secp256k1_u128_to_u64(&t); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0); +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + int over; + r->d[0] = secp256k1_read_be64(&b32[24]); + r->d[1] = secp256k1_read_be64(&b32[16]); + r->d[2] = secp256k1_read_be64(&b32[8]); + r->d[3] = secp256k1_read_be64(&b32[0]); + over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + SECP256K1_SCALAR_VERIFY(a); + + secp256k1_write_be64(&bin[0], a->d[3]); + secp256k1_write_be64(&bin[8], a->d[2]); + secp256k1_write_be64(&bin[16], a->d[1]); + secp256k1_write_be64(&bin[24], a->d[0]); +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); + secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + + secp256k1_u128_from_u64(&t, ~a->d[0]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1); + r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[1]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_1); + r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[2]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_2); + r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[3]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_3); + r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { + /* Writing `/` for field division and `//` for integer division, we compute + * + * a/2 = (a - (a&1))/2 + (a&1)/2 + * = (a >> 1) + (a&1 ? 1/2 : 0) + * = (a >> 1) + (a&1 ? n//2+1 : 0), + * + * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). + * For n//2, we have the constants SECP256K1_N_H_0, ... + * + * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: + * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 + * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 + * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. + */ + uint64_t mask = -(uint64_t)(a->d[0] & 1U); + secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + + secp256k1_u128_from_u64(&t, (a->d[0] >> 1) | (a->d[1] << 63)); + secp256k1_u128_accum_u64(&t, (SECP256K1_N_H_0 + 1U) & mask); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, (a->d[1] >> 1) | (a->d[2] << 63)); + secp256k1_u128_accum_u64(&t, SECP256K1_N_H_1 & mask); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, (a->d[2] >> 1) | (a->d[3] << 63)); + secp256k1_u128_accum_u64(&t, SECP256K1_N_H_2 & mask); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + r->d[3] = secp256k1_u128_to_u64(&t) + (a->d[3] >> 1) + (SECP256K1_N_H_3 & mask); +#ifdef VERIFY + /* The line above only computed the bottom 64 bits of r->d[3]; redo the computation + * in full 128 bits to make sure the top 64 bits are indeed zero. */ + secp256k1_u128_accum_u64(&t, a->d[3] >> 1); + secp256k1_u128_accum_u64(&t, SECP256K1_N_H_3 & mask); + secp256k1_u128_rshift(&t, 64); + VERIFY_CHECK(secp256k1_u128_to_u64(&t) == 0); + + SECP256K1_SCALAR_VERIFY(r); +#endif +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + int yes = 0; + int no = 0; + SECP256K1_SCALAR_VERIFY(a); + + no |= (a->d[3] < SECP256K1_N_H_3); + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + volatile int vflag = flag; + uint64_t mask = -vflag; + uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; + secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(r); + + secp256k1_u128_from_u64(&t, r->d[0] ^ mask); + secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask); + r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[1] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_1 & mask); + r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_2 & mask); + r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[3] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask); + r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; + + SECP256K1_SCALAR_VERIFY(r); + return 2 * (mask == 0) - 1; +} + +/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint64_t tl, th; \ + { \ + secp256k1_uint128 t; \ + secp256k1_u128_mul(&t, a, b); \ + th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = secp256k1_u128_to_u64(&t); \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint64_t tl, th; \ + { \ + secp256k1_uint128 t; \ + secp256k1_u128_mul(&t, a, b); \ + th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = secp256k1_u128_to_u64(&t); \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + unsigned int over; \ + c0 += (a); /* overflow is handled on the next line */ \ + over = (c0 < (a)); \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over); /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) { +#ifdef USE_ASM_X86_64 + /* Reduce 512 bits into 385. */ + uint64_t m0, m1, m2, m3, m4, m5, m6; + uint64_t p0, p1, p2, p3, p4; + uint64_t c; + + __asm__ __volatile__( + /* Preload. */ + "movq 32(%%rsi), %%r11\n" + "movq 40(%%rsi), %%r12\n" + "movq 48(%%rsi), %%r13\n" + "movq 56(%%rsi), %%r14\n" + /* Initialize r8,r9,r10 */ + "movq 0(%%rsi), %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9) += n0 * c0 */ + "movq %8, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract m0 */ + "movq %%r8, %q0\n" + "xorq %%r8, %%r8\n" + /* (r9,r10) += l1 */ + "addq 8(%%rsi), %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += n1 * c0 */ + "movq %8, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n0 * c1 */ + "movq %9, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract m1 */ + "movq %%r9, %q1\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += l2 */ + "addq 16(%%rsi), %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n2 * c0 */ + "movq %8, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n1 * c1 */ + "movq %9, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n0 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract m2 */ + "movq %%r10, %q2\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += l3 */ + "addq 24(%%rsi), %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n3 * c0 */ + "movq %8, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n2 * c1 */ + "movq %9, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n1 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* extract m3 */ + "movq %%r8, %q3\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += n3 * c1 */ + "movq %9, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n2 */ + "addq %%r13, %%r9\n" + "adcq $0, %%r10\n" + "adcq $0, %%r8\n" + /* extract m4 */ + "movq %%r9, %q4\n" + /* (r10,r8) += n3 */ + "addq %%r14, %%r10\n" + "adcq $0, %%r8\n" + /* extract m5 */ + "movq %%r10, %q5\n" + /* extract m6 */ + "movq %%r8, %q6\n" + : "=&g"(m0), "=&g"(m1), "=&g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) + : "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(&m0, sizeof(m0)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m1, sizeof(m1)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m2, sizeof(m2)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m3, sizeof(m3)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m4, sizeof(m4)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m5, sizeof(m5)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m6, sizeof(m6)); + + /* Reduce 385 bits into 258. */ + __asm__ __volatile__( + /* Preload */ + "movq %q9, %%r11\n" + "movq %q10, %%r12\n" + "movq %q11, %%r13\n" + /* Initialize (r8,r9,r10) */ + "movq %q5, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9) += m4 * c0 */ + "movq %12, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract p0 */ + "movq %%r8, %q0\n" + "xorq %%r8, %%r8\n" + /* (r9,r10) += m1 */ + "addq %q6, %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += m5 * c0 */ + "movq %12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += m4 * c1 */ + "movq %13, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract p1 */ + "movq %%r9, %q1\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += m2 */ + "addq %q7, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m6 * c0 */ + "movq %12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m5 * c1 */ + "movq %13, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m4 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract p2 */ + "movq %%r10, %q2\n" + /* (r8,r9) += m3 */ + "addq %q8, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += m6 * c1 */ + "movq %13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* (r8,r9) += m5 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + /* extract p3 */ + "movq %%r8, %q3\n" + /* (r9) += m6 */ + "addq %%r13, %%r9\n" + /* extract p4 */ + "movq %%r9, %q4\n" + : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) + : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(&p0, sizeof(p0)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p1, sizeof(p1)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p2, sizeof(p2)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p3, sizeof(p3)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p4, sizeof(p4)); + + /* Reduce 258 bits into 256. */ + __asm__ __volatile__( + /* Preload */ + "movq %q5, %%r10\n" + /* (rax,rdx) = p4 * c0 */ + "movq %7, %%rax\n" + "mulq %%r10\n" + /* (rax,rdx) += p0 */ + "addq %q1, %%rax\n" + "adcq $0, %%rdx\n" + /* extract r0 */ + "movq %%rax, 0(%q6)\n" + /* Move to (r8,r9) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + /* (r8,r9) += p1 */ + "addq %q2, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += p4 * c1 */ + "movq %8, %%rax\n" + "mulq %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* Extract r1 */ + "movq %%r8, 8(%q6)\n" + "xorq %%r8, %%r8\n" + /* (r9,r8) += p4 */ + "addq %%r10, %%r9\n" + "adcq $0, %%r8\n" + /* (r9,r8) += p2 */ + "addq %q3, %%r9\n" + "adcq $0, %%r8\n" + /* Extract r2 */ + "movq %%r9, 16(%q6)\n" + "xorq %%r9, %%r9\n" + /* (r8,r9) += p3 */ + "addq %q4, %%r8\n" + "adcq $0, %%r9\n" + /* Extract r3 */ + "movq %%r8, 24(%q6)\n" + /* Extract c */ + "movq %%r9, %q0\n" + : "=g"(c) + : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(r, sizeof(*r)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&c, sizeof(c)); + +#else + secp256k1_uint128 c128; + uint64_t c, c0, c1, c2; + uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; + uint64_t m0, m1, m2, m3, m4, m5; + uint32_t m6; + uint64_t p0, p1, p2, p3; + uint32_t p4; + + /* Reduce 512 bits into 385. */ + /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */ + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + sumadd(n0); + extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + sumadd(n1); + extract(m3); + muladd(n3, SECP256K1_N_C_1); + sumadd(n2); + extract(m4); + sumadd_fast(n3); + extract_fast(m5); + VERIFY_CHECK(c0 <= 1); + m6 = c0; + + /* Reduce 385 bits into 258. */ + /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */ + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m4, SECP256K1_N_C_0); + extract_fast(p0); + sumadd_fast(m1); + muladd(m5, SECP256K1_N_C_0); + muladd(m4, SECP256K1_N_C_1); + extract(p1); + sumadd(m2); + muladd(m6, SECP256K1_N_C_0); + muladd(m5, SECP256K1_N_C_1); + sumadd(m4); + extract(p2); + sumadd_fast(m3); + muladd_fast(m6, SECP256K1_N_C_1); + sumadd_fast(m5); + extract_fast(p3); + p4 = c0 + m6; + VERIFY_CHECK(p4 <= 2); + + /* Reduce 258 bits into 256. */ + /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ + secp256k1_u128_from_u64(&c128, p0); + secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_0, p4); + r->d[0] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); + secp256k1_u128_accum_u64(&c128, p1); + secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_1, p4); + r->d[1] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); + secp256k1_u128_accum_u64(&c128, p2); + secp256k1_u128_accum_u64(&c128, p4); + r->d[2] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); + secp256k1_u128_accum_u64(&c128, p3); + r->d[3] = secp256k1_u128_to_u64(&c128); + c = secp256k1_u128_hi_u64(&c128); +#endif + + /* Final reduction of r. */ + secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); +} + +static void secp256k1_scalar_mul_512(uint64_t *l8, const secp256k1_scalar *a, const secp256k1_scalar *b) { +#ifdef USE_ASM_X86_64 + const uint64_t *pb = b->d; + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r15\n" + "movq 8(%%rdi), %%rbx\n" + "movq 16(%%rdi), %%rcx\n" + "movq 0(%%rdx), %%r11\n" + "movq 8(%%rdx), %%r12\n" + "movq 16(%%rdx), %%r13\n" + "movq 24(%%rdx), %%r14\n" + /* (rax,rdx) = a0 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + /* Extract l8[0] */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a0 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a1 * b0 */ + "movq %%rbx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l8[1] */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a0 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * b1 */ + "movq %%rbx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a2 * b0 */ + "movq %%rcx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l8[2] */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += a0 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Preload a3 */ + "movq 24(%%rdi), %%r15\n" + /* (r10,r8,r9) += a1 * b2 */ + "movq %%rbx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a2 * b1 */ + "movq %%rcx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a3 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l8[3] */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a1 * b3 */ + "movq %%rbx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * b2 */ + "movq %%rcx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a3 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l8[4] */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a2 * b3 */ + "movq %%rcx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a3 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l8[5] */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l8[6] */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l8[7] */ + "movq %%r8, 56(%%rsi)\n" + : "+d"(pb) + : "S"(l8), "D"(a->d) + : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(l8, sizeof(*l8) * 8); + +#else + /* 160 bit accumulator. */ + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + /* l8[0..7] = a[0..3] * b[0..3]. */ + muladd_fast(a->d[0], b->d[0]); + extract_fast(l8[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l8[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l8[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l8[3]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + extract(l8[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + extract(l8[5]); + muladd_fast(a->d[3], b->d[3]); + extract_fast(l8[6]); + VERIFY_CHECK(c1 == 0); + l8[7] = c0; +#endif +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef extract +#undef extract_fast + +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + uint64_t l[8]; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + secp256k1_scalar_mul_512(l, a, b); + secp256k1_scalar_reduce_512(r, l); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { + SECP256K1_SCALAR_VERIFY(k); + + r1->d[0] = k->d[0]; + r1->d[1] = k->d[1]; + r1->d[2] = 0; + r1->d[3] = 0; + r2->d[0] = k->d[2]; + r2->d[1] = k->d[3]; + r2->d[2] = 0; + r2->d[3] = 0; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); +} + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { + uint64_t l[8]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + VERIFY_CHECK(shift >= 256); + + secp256k1_scalar_mul_512(l, a, b); + shiftlimbs = shift >> 6; + shiftlow = shift & 0x3F; + shifthigh = 64 - shiftlow; + r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { + uint64_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); + + mask0 = vflag + ~((uint64_t)0); + mask1 = ~mask0; + r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); + r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); + r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1); + r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_from_signed62(secp256k1_scalar *r, const secp256k1_modinv64_signed62 *a) { + const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4]; + + /* The output from secp256k1_modinv64{_var} should be normalized to range [0,modulus), and + * have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4). + */ + VERIFY_CHECK(a0 >> 62 == 0); + VERIFY_CHECK(a1 >> 62 == 0); + VERIFY_CHECK(a2 >> 62 == 0); + VERIFY_CHECK(a3 >> 62 == 0); + VERIFY_CHECK(a4 >> 8 == 0); + + r->d[0] = a0 | a1 << 62; + r->d[1] = a1 >> 2 | a2 << 60; + r->d[2] = a2 >> 4 | a3 << 58; + r->d[3] = a3 >> 6 | a4 << 56; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_scalar *a) { + const uint64_t M62 = UINT64_MAX >> 2; + const uint64_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3]; + SECP256K1_SCALAR_VERIFY(a); + + r->v[0] = a0 & M62; + r->v[1] = (a0 >> 62 | a1 << 2) & M62; + r->v[2] = (a1 >> 60 | a2 << 4) & M62; + r->v[3] = (a2 >> 58 | a3 << 6) & M62; + r->v[4] = a3 >> 56; +} + +static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_scalar = { + {{0x3FD25E8CD0364141LL, 0x2ABB739ABD2280EELL, -0x15LL, 0, 256}}, + 0x34F20099AA774EC1LL +}; + +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_modinv64_signed62 s; +#ifdef VERIFY + int zero_in = secp256k1_scalar_is_zero(x); +#endif + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_to_signed62(&s, x); + secp256k1_modinv64(&s, &secp256k1_const_modinfo_scalar); + secp256k1_scalar_from_signed62(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); +} + +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_modinv64_signed62 s; +#ifdef VERIFY + int zero_in = secp256k1_scalar_is_zero(x); +#endif + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_to_signed62(&s, x); + secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_scalar); + secp256k1_scalar_from_signed62(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); +} + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return !(a->d[0] & 1); +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/external/secp256k1/src/scalar_8x32.h b/external/secp256k1/src/scalar_8x32.h new file mode 100644 index 00000000000..17863ef9371 --- /dev/null +++ b/external/secp256k1/src/scalar_8x32.h @@ -0,0 +1,19 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint32_t d[8]; +} secp256k1_scalar; + +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/external/secp256k1/src/scalar_8x32_impl.h b/external/secp256k1/src/scalar_8x32_impl.h new file mode 100644 index 00000000000..26104960524 --- /dev/null +++ b/external/secp256k1/src/scalar_8x32_impl.h @@ -0,0 +1,816 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "checkmem.h" +#include "modinv32_impl.h" +#include "util.h" + +/* Limbs of the secp256k1 order. */ +#define SECP256K1_N_0 ((uint32_t)0xD0364141UL) +#define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL) +#define SECP256K1_N_2 ((uint32_t)0xAF48A03BUL) +#define SECP256K1_N_3 ((uint32_t)0xBAAEDCE6UL) +#define SECP256K1_N_4 ((uint32_t)0xFFFFFFFEUL) +#define SECP256K1_N_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_7 ((uint32_t)0xFFFFFFFFUL) + +/* Limbs of 2^256 minus the secp256k1 order. */ +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (~SECP256K1_N_2) +#define SECP256K1_N_C_3 (~SECP256K1_N_3) +#define SECP256K1_N_C_4 (1) + +/* Limbs of half the secp256k1 order. */ +#define SECP256K1_N_H_0 ((uint32_t)0x681B20A0UL) +#define SECP256K1_N_H_1 ((uint32_t)0xDFE92F46UL) +#define SECP256K1_N_H_2 ((uint32_t)0x57A4501DUL) +#define SECP256K1_N_H_3 ((uint32_t)0x5D576E73UL) +#define SECP256K1_N_H_4 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) + +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; + r->d[4] = 0; + r->d[5] = 0; + r->d[6] = 0; + r->d[7] = 0; + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); + VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); + + return (a->d[offset >> 5] >> (offset & 0x1F)) & (0xFFFFFFFF >> (32 - count)); +} + +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); + VERIFY_CHECK(offset + count <= 256); + + if ((offset + count - 1) >> 5 == offset >> 5) { + return secp256k1_scalar_get_bits_limb32(a, offset, count); + } else { + VERIFY_CHECK((offset >> 5) + 1 < 8); + return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & (0xFFFFFFFF >> (32 - count)); + } +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ + no |= (a->d[6] < SECP256K1_N_6); /* No need for a > check. */ + no |= (a->d[5] < SECP256K1_N_5); /* No need for a > check. */ + no |= (a->d[4] < SECP256K1_N_4); + yes |= (a->d[4] > SECP256K1_N_4) & ~no; + no |= (a->d[3] < SECP256K1_N_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_3) & ~no; + no |= (a->d[2] < SECP256K1_N_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) { + uint64_t t; + VERIFY_CHECK(overflow <= 1); + + t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; + r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; + r->d[1] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[2] + overflow * SECP256K1_N_C_2; + r->d[2] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[3] + overflow * SECP256K1_N_C_3; + r->d[3] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[4] + overflow * SECP256K1_N_C_4; + r->d[4] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[5]; + r->d[5] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[6]; + r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[7]; + r->d[7] = t & 0xFFFFFFFFUL; + + SECP256K1_SCALAR_VERIFY(r); + return overflow; +} + +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + int overflow; + uint64_t t = (uint64_t)a->d[0] + b->d[0]; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[1] + b->d[1]; + r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[2] + b->d[2]; + r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[3] + b->d[3]; + r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[4] + b->d[4]; + r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[5] + b->d[5]; + r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[6] + b->d[6]; + r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[7] + b->d[7]; + r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; + overflow = t + secp256k1_scalar_check_overflow(r); + VERIFY_CHECK(overflow == 0 || overflow == 1); + secp256k1_scalar_reduce(r, overflow); + + SECP256K1_SCALAR_VERIFY(r); + return overflow; +} + +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + uint64_t t; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(bit < 256); + + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ + t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); + r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F)); + r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F)); + r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F)); + r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F)); + r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F)); + r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F)); + r->d[7] = t & 0xFFFFFFFFULL; + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK((t >> 32) == 0); +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + int over; + r->d[0] = secp256k1_read_be32(&b32[28]); + r->d[1] = secp256k1_read_be32(&b32[24]); + r->d[2] = secp256k1_read_be32(&b32[20]); + r->d[3] = secp256k1_read_be32(&b32[16]); + r->d[4] = secp256k1_read_be32(&b32[12]); + r->d[5] = secp256k1_read_be32(&b32[8]); + r->d[6] = secp256k1_read_be32(&b32[4]); + r->d[7] = secp256k1_read_be32(&b32[0]); + over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + SECP256K1_SCALAR_VERIFY(a); + + secp256k1_write_be32(&bin[0], a->d[7]); + secp256k1_write_be32(&bin[4], a->d[6]); + secp256k1_write_be32(&bin[8], a->d[5]); + secp256k1_write_be32(&bin[12], a->d[4]); + secp256k1_write_be32(&bin[16], a->d[3]); + secp256k1_write_be32(&bin[20], a->d[2]); + secp256k1_write_be32(&bin[24], a->d[1]); + secp256k1_write_be32(&bin[28], a->d[0]); +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); + uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; + SECP256K1_SCALAR_VERIFY(a); + + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[2]) + SECP256K1_N_2; + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[3]) + SECP256K1_N_3; + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[4]) + SECP256K1_N_4; + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[5]) + SECP256K1_N_5; + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[6]) + SECP256K1_N_6; + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; + r->d[7] = t & nonzero; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { + /* Writing `/` for field division and `//` for integer division, we compute + * + * a/2 = (a - (a&1))/2 + (a&1)/2 + * = (a >> 1) + (a&1 ? 1/2 : 0) + * = (a >> 1) + (a&1 ? n//2+1 : 0), + * + * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). + * For n//2, we have the constants SECP256K1_N_H_0, ... + * + * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: + * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 + * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 + * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. + */ + uint32_t mask = -(uint32_t)(a->d[0] & 1U); + uint64_t t = (uint32_t)((a->d[0] >> 1) | (a->d[1] << 31)); + SECP256K1_SCALAR_VERIFY(a); + + t += (SECP256K1_N_H_0 + 1U) & mask; + r->d[0] = t; t >>= 32; + t += (uint32_t)((a->d[1] >> 1) | (a->d[2] << 31)); + t += SECP256K1_N_H_1 & mask; + r->d[1] = t; t >>= 32; + t += (uint32_t)((a->d[2] >> 1) | (a->d[3] << 31)); + t += SECP256K1_N_H_2 & mask; + r->d[2] = t; t >>= 32; + t += (uint32_t)((a->d[3] >> 1) | (a->d[4] << 31)); + t += SECP256K1_N_H_3 & mask; + r->d[3] = t; t >>= 32; + t += (uint32_t)((a->d[4] >> 1) | (a->d[5] << 31)); + t += SECP256K1_N_H_4 & mask; + r->d[4] = t; t >>= 32; + t += (uint32_t)((a->d[5] >> 1) | (a->d[6] << 31)); + t += SECP256K1_N_H_5 & mask; + r->d[5] = t; t >>= 32; + t += (uint32_t)((a->d[6] >> 1) | (a->d[7] << 31)); + t += SECP256K1_N_H_6 & mask; + r->d[6] = t; t >>= 32; + r->d[7] = (uint32_t)t + (uint32_t)(a->d[7] >> 1) + (SECP256K1_N_H_7 & mask); + + /* The line above only computed the bottom 32 bits of r->d[7]. Redo the computation + * in full 64 bits to make sure the top 32 bits are indeed zero. */ + VERIFY_CHECK((t + (a->d[7] >> 1) + (SECP256K1_N_H_7 & mask)) >> 32 == 0); + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + int yes = 0; + int no = 0; + SECP256K1_SCALAR_VERIFY(a); + + no |= (a->d[7] < SECP256K1_N_H_7); + yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; + no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */ + no |= (a->d[5] < SECP256K1_N_H_5) & ~yes; /* No need for a > check. */ + no |= (a->d[4] < SECP256K1_N_H_4) & ~yes; /* No need for a > check. */ + no |= (a->d[3] < SECP256K1_N_H_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_H_2) & ~no; + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + volatile int vflag = flag; + uint32_t mask = -vflag; + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); + uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + SECP256K1_SCALAR_VERIFY(r); + + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask); + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask); + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask); + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); + r->d[7] = t & nonzero; + + SECP256K1_SCALAR_VERIFY(r); + return 2 * (mask == 0) - 1; +} + + +/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl); /* at most 0xFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl); /* at most 0xFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + unsigned int over; \ + c0 += (a); /* overflow is handled on the next line */ \ + over = (c0 < (a)); \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over); /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) { + uint64_t c; + uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; + uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; + uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8; + + /* 96 bit accumulator. */ + uint32_t c0, c1, c2; + + /* Reduce 512 bits into 385. */ + /* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */ + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + muladd(n0, SECP256K1_N_C_2); + extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + muladd(n1, SECP256K1_N_C_2); + muladd(n0, SECP256K1_N_C_3); + extract(m3); + sumadd(l[4]); + muladd(n4, SECP256K1_N_C_0); + muladd(n3, SECP256K1_N_C_1); + muladd(n2, SECP256K1_N_C_2); + muladd(n1, SECP256K1_N_C_3); + sumadd(n0); + extract(m4); + sumadd(l[5]); + muladd(n5, SECP256K1_N_C_0); + muladd(n4, SECP256K1_N_C_1); + muladd(n3, SECP256K1_N_C_2); + muladd(n2, SECP256K1_N_C_3); + sumadd(n1); + extract(m5); + sumadd(l[6]); + muladd(n6, SECP256K1_N_C_0); + muladd(n5, SECP256K1_N_C_1); + muladd(n4, SECP256K1_N_C_2); + muladd(n3, SECP256K1_N_C_3); + sumadd(n2); + extract(m6); + sumadd(l[7]); + muladd(n7, SECP256K1_N_C_0); + muladd(n6, SECP256K1_N_C_1); + muladd(n5, SECP256K1_N_C_2); + muladd(n4, SECP256K1_N_C_3); + sumadd(n3); + extract(m7); + muladd(n7, SECP256K1_N_C_1); + muladd(n6, SECP256K1_N_C_2); + muladd(n5, SECP256K1_N_C_3); + sumadd(n4); + extract(m8); + muladd(n7, SECP256K1_N_C_2); + muladd(n6, SECP256K1_N_C_3); + sumadd(n5); + extract(m9); + muladd(n7, SECP256K1_N_C_3); + sumadd(n6); + extract(m10); + sumadd_fast(n7); + extract_fast(m11); + VERIFY_CHECK(c0 <= 1); + m12 = c0; + + /* Reduce 385 bits into 258. */ + /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */ + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m8, SECP256K1_N_C_0); + extract_fast(p0); + sumadd_fast(m1); + muladd(m9, SECP256K1_N_C_0); + muladd(m8, SECP256K1_N_C_1); + extract(p1); + sumadd(m2); + muladd(m10, SECP256K1_N_C_0); + muladd(m9, SECP256K1_N_C_1); + muladd(m8, SECP256K1_N_C_2); + extract(p2); + sumadd(m3); + muladd(m11, SECP256K1_N_C_0); + muladd(m10, SECP256K1_N_C_1); + muladd(m9, SECP256K1_N_C_2); + muladd(m8, SECP256K1_N_C_3); + extract(p3); + sumadd(m4); + muladd(m12, SECP256K1_N_C_0); + muladd(m11, SECP256K1_N_C_1); + muladd(m10, SECP256K1_N_C_2); + muladd(m9, SECP256K1_N_C_3); + sumadd(m8); + extract(p4); + sumadd(m5); + muladd(m12, SECP256K1_N_C_1); + muladd(m11, SECP256K1_N_C_2); + muladd(m10, SECP256K1_N_C_3); + sumadd(m9); + extract(p5); + sumadd(m6); + muladd(m12, SECP256K1_N_C_2); + muladd(m11, SECP256K1_N_C_3); + sumadd(m10); + extract(p6); + sumadd_fast(m7); + muladd_fast(m12, SECP256K1_N_C_3); + sumadd_fast(m11); + extract_fast(p7); + p8 = c0 + m12; + VERIFY_CHECK(p8 <= 2); + + /* Reduce 258 bits into 256. */ + /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */ + c = p0 + (uint64_t)SECP256K1_N_C_0 * p8; + r->d[0] = c & 0xFFFFFFFFUL; c >>= 32; + c += p1 + (uint64_t)SECP256K1_N_C_1 * p8; + r->d[1] = c & 0xFFFFFFFFUL; c >>= 32; + c += p2 + (uint64_t)SECP256K1_N_C_2 * p8; + r->d[2] = c & 0xFFFFFFFFUL; c >>= 32; + c += p3 + (uint64_t)SECP256K1_N_C_3 * p8; + r->d[3] = c & 0xFFFFFFFFUL; c >>= 32; + c += p4 + (uint64_t)p8; + r->d[4] = c & 0xFFFFFFFFUL; c >>= 32; + c += p5; + r->d[5] = c & 0xFFFFFFFFUL; c >>= 32; + c += p6; + r->d[6] = c & 0xFFFFFFFFUL; c >>= 32; + c += p7; + r->d[7] = c & 0xFFFFFFFFUL; c >>= 32; + + /* Final reduction of r. */ + secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); +} + +static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) { + /* 96 bit accumulator. */ + uint32_t c0 = 0, c1 = 0, c2 = 0; + + /* l[0..15] = a[0..7] * b[0..7]. */ + muladd_fast(a->d[0], b->d[0]); + extract_fast(l[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l[3]); + muladd(a->d[0], b->d[4]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + muladd(a->d[4], b->d[0]); + extract(l[4]); + muladd(a->d[0], b->d[5]); + muladd(a->d[1], b->d[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + muladd(a->d[4], b->d[1]); + muladd(a->d[5], b->d[0]); + extract(l[5]); + muladd(a->d[0], b->d[6]); + muladd(a->d[1], b->d[5]); + muladd(a->d[2], b->d[4]); + muladd(a->d[3], b->d[3]); + muladd(a->d[4], b->d[2]); + muladd(a->d[5], b->d[1]); + muladd(a->d[6], b->d[0]); + extract(l[6]); + muladd(a->d[0], b->d[7]); + muladd(a->d[1], b->d[6]); + muladd(a->d[2], b->d[5]); + muladd(a->d[3], b->d[4]); + muladd(a->d[4], b->d[3]); + muladd(a->d[5], b->d[2]); + muladd(a->d[6], b->d[1]); + muladd(a->d[7], b->d[0]); + extract(l[7]); + muladd(a->d[1], b->d[7]); + muladd(a->d[2], b->d[6]); + muladd(a->d[3], b->d[5]); + muladd(a->d[4], b->d[4]); + muladd(a->d[5], b->d[3]); + muladd(a->d[6], b->d[2]); + muladd(a->d[7], b->d[1]); + extract(l[8]); + muladd(a->d[2], b->d[7]); + muladd(a->d[3], b->d[6]); + muladd(a->d[4], b->d[5]); + muladd(a->d[5], b->d[4]); + muladd(a->d[6], b->d[3]); + muladd(a->d[7], b->d[2]); + extract(l[9]); + muladd(a->d[3], b->d[7]); + muladd(a->d[4], b->d[6]); + muladd(a->d[5], b->d[5]); + muladd(a->d[6], b->d[4]); + muladd(a->d[7], b->d[3]); + extract(l[10]); + muladd(a->d[4], b->d[7]); + muladd(a->d[5], b->d[6]); + muladd(a->d[6], b->d[5]); + muladd(a->d[7], b->d[4]); + extract(l[11]); + muladd(a->d[5], b->d[7]); + muladd(a->d[6], b->d[6]); + muladd(a->d[7], b->d[5]); + extract(l[12]); + muladd(a->d[6], b->d[7]); + muladd(a->d[7], b->d[6]); + extract(l[13]); + muladd_fast(a->d[7], b->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef extract +#undef extract_fast + +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + uint32_t l[16]; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + secp256k1_scalar_mul_512(l, a, b); + secp256k1_scalar_reduce_512(r, l); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { + SECP256K1_SCALAR_VERIFY(k); + + r1->d[0] = k->d[0]; + r1->d[1] = k->d[1]; + r1->d[2] = k->d[2]; + r1->d[3] = k->d[3]; + r1->d[4] = 0; + r1->d[5] = 0; + r1->d[6] = 0; + r1->d[7] = 0; + r2->d[0] = k->d[4]; + r2->d[1] = k->d[5]; + r2->d[2] = k->d[6]; + r2->d[3] = k->d[7]; + r2->d[4] = 0; + r2->d[5] = 0; + r2->d[6] = 0; + r2->d[7] = 0; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); +} + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { + uint32_t l[16]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + VERIFY_CHECK(shift >= 256); + + secp256k1_scalar_mul_512(l, a, b); + shiftlimbs = shift >> 5; + shiftlow = shift & 0x1F; + shifthigh = 32 - shiftlow; + r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { + uint32_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); + + mask0 = vflag + ~((uint32_t)0); + mask1 = ~mask0; + r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); + r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); + r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1); + r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1); + r->d[4] = (r->d[4] & mask0) | (a->d[4] & mask1); + r->d[5] = (r->d[5] & mask0) | (a->d[5] & mask1); + r->d[6] = (r->d[6] & mask0) | (a->d[6] & mask1); + r->d[7] = (r->d[7] & mask0) | (a->d[7] & mask1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_from_signed30(secp256k1_scalar *r, const secp256k1_modinv32_signed30 *a) { + const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4], + a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8]; + + /* The output from secp256k1_modinv32{_var} should be normalized to range [0,modulus), and + * have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8). + */ + VERIFY_CHECK(a0 >> 30 == 0); + VERIFY_CHECK(a1 >> 30 == 0); + VERIFY_CHECK(a2 >> 30 == 0); + VERIFY_CHECK(a3 >> 30 == 0); + VERIFY_CHECK(a4 >> 30 == 0); + VERIFY_CHECK(a5 >> 30 == 0); + VERIFY_CHECK(a6 >> 30 == 0); + VERIFY_CHECK(a7 >> 30 == 0); + VERIFY_CHECK(a8 >> 16 == 0); + + r->d[0] = a0 | a1 << 30; + r->d[1] = a1 >> 2 | a2 << 28; + r->d[2] = a2 >> 4 | a3 << 26; + r->d[3] = a3 >> 6 | a4 << 24; + r->d[4] = a4 >> 8 | a5 << 22; + r->d[5] = a5 >> 10 | a6 << 20; + r->d[6] = a6 >> 12 | a7 << 18; + r->d[7] = a7 >> 14 | a8 << 16; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_scalar *a) { + const uint32_t M30 = UINT32_MAX >> 2; + const uint32_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3], + a4 = a->d[4], a5 = a->d[5], a6 = a->d[6], a7 = a->d[7]; + SECP256K1_SCALAR_VERIFY(a); + + r->v[0] = a0 & M30; + r->v[1] = (a0 >> 30 | a1 << 2) & M30; + r->v[2] = (a1 >> 28 | a2 << 4) & M30; + r->v[3] = (a2 >> 26 | a3 << 6) & M30; + r->v[4] = (a3 >> 24 | a4 << 8) & M30; + r->v[5] = (a4 >> 22 | a5 << 10) & M30; + r->v[6] = (a5 >> 20 | a6 << 12) & M30; + r->v[7] = (a6 >> 18 | a7 << 14) & M30; + r->v[8] = a7 >> 16; +} + +static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_scalar = { + {{0x10364141L, 0x3F497A33L, 0x348A03BBL, 0x2BB739ABL, -0x146L, 0, 0, 0, 65536}}, + 0x2A774EC1L +}; + +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_modinv32_signed30 s; +#ifdef VERIFY + int zero_in = secp256k1_scalar_is_zero(x); +#endif + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_to_signed30(&s, x); + secp256k1_modinv32(&s, &secp256k1_const_modinfo_scalar); + secp256k1_scalar_from_signed30(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); +} + +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_modinv32_signed30 s; +#ifdef VERIFY + int zero_in = secp256k1_scalar_is_zero(x); +#endif + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_to_signed30(&s, x); + secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_scalar); + secp256k1_scalar_from_signed30(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); +} + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return !(a->d[0] & 1); +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/external/secp256k1/src/scalar_impl.h b/external/secp256k1/src/scalar_impl.h new file mode 100644 index 00000000000..dbb5b0a01ca --- /dev/null +++ b/external/secp256k1/src/scalar_impl.h @@ -0,0 +1,321 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_IMPL_H +#define SECP256K1_SCALAR_IMPL_H + +#ifdef VERIFY +#include +#endif + +#include "scalar.h" +#include "util.h" + +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low_impl.h" +#elif defined(SECP256K1_WIDEMUL_INT128) +#include "scalar_4x64_impl.h" +#elif defined(SECP256K1_WIDEMUL_INT64) +#include "scalar_8x32_impl.h" +#else +#error "Please select wide multiplication implementation" +#endif + +static const secp256k1_scalar secp256k1_scalar_one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); +static const secp256k1_scalar secp256k1_scalar_zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { + secp256k1_memclear(r, sizeof(secp256k1_scalar)); +} + +static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) { + int overflow; + secp256k1_scalar_set_b32(r, bin, &overflow); + + SECP256K1_SCALAR_VERIFY(r); + return (!overflow) & (!secp256k1_scalar_is_zero(r)); +} + +static void secp256k1_scalar_verify(const secp256k1_scalar *r) { + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); + + (void)r; +} + +#if defined(EXHAUSTIVE_TEST_ORDER) +/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ +# if EXHAUSTIVE_TEST_ORDER == 7 +# define EXHAUSTIVE_TEST_LAMBDA 2 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define EXHAUSTIVE_TEST_LAMBDA 9 +# elif EXHAUSTIVE_TEST_ORDER == 199 +# define EXHAUSTIVE_TEST_LAMBDA 92 +# else +# error No known lambda for the specified exhaustive test group order. +# endif +/* End of section generated by sage/gen_exhaustive_groups.sage. */ + +/** + * Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n; unlike in the + * full case we don't bother making r1 and r2 be small, we just want them to be + * nontrivial to get full test coverage for the exhaustive tests. We therefore + * (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n). + */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) { + SECP256K1_SCALAR_VERIFY(k); + VERIFY_CHECK(r1 != k); + VERIFY_CHECK(r2 != k); + VERIFY_CHECK(r1 != r2); + + *r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER; + *r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); +} +#else +/** + * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where + * lambda is: */ +static const secp256k1_scalar secp256k1_const_lambda = SECP256K1_SCALAR_CONST( + 0x5363AD4CUL, 0xC05C30E0UL, 0xA5261C02UL, 0x8812645AUL, + 0x122E22EAUL, 0x20816678UL, 0xDF02967CUL, 0x1B23BD72UL +); + +#ifdef VERIFY +static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, const secp256k1_scalar *r2, const secp256k1_scalar *k); +#endif + +/* + * Both lambda and beta are primitive cube roots of unity. That is lamba^3 == 1 mod n and + * beta^3 == 1 mod p, where n is the curve order and p is the field order. + * + * Furthermore, because (X^3 - 1) = (X - 1)(X^2 + X + 1), the primitive cube roots of unity are + * roots of X^2 + X + 1. Therefore lambda^2 + lamba == -1 mod n and beta^2 + beta == -1 mod p. + * (The other primitive cube roots of unity are lambda^2 and beta^2 respectively.) + * + * Let l = -1/2 + i*sqrt(3)/2, the complex root of X^2 + X + 1. We can define a ring + * homomorphism phi : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n. The kernel of phi + * is a lattice over Z[l] (considering Z[l] as a Z-module). This lattice is generated by a + * reduced basis {a1 + b1*l, a2 + b2*l} where + * + * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} + * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} + * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * + * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm + * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 + * and k2 are small in absolute value. + * + * The algorithm computes c1 = round(b2 * k / n) and c2 = round((-b1) * k / n), and gives + * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and + * compute r2 = k2 mod n, and r1 = k1 mod n = (k - r2 * lambda) mod n, avoiding the need for + * the constants a1 and a2. + * + * g1, g2 are precomputed constants used to replace division with a rounded multiplication + * when decomposing the scalar for an endomorphism-based point multiplication. + * + * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve + * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5. + * + * The derivation is described in the paper "Efficient Software Implementation of Public-Key + * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), + * Section 4.3 (here we use a somewhat higher-precision estimate): + * d = a1*b2 - b1*a2 + * g1 = round(2^384 * b2/d) + * g2 = round(2^384 * (-b1)/d) + * + * (Note that d is also equal to the curve order, n, here because [a1,b1] and [a2,b2] + * can be found as outputs of the Extended Euclidean Algorithm on inputs n and lambda). + * + * The function below splits k into r1 and r2, such that + * - r1 + lambda * r2 == k (mod n) + * - either r1 < 2^128 or -r1 mod n < 2^128 + * - either r2 < 2^128 or -r2 mod n < 2^128 + * + * See proof below. + */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) { + secp256k1_scalar c1, c2; + static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, + 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL + ); + static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL + ); + static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( + 0x3086D221UL, 0xA7D46BCDUL, 0xE86C90E4UL, 0x9284EB15UL, + 0x3DAA8A14UL, 0x71E8CA7FUL, 0xE893209AUL, 0x45DBB031UL + ); + static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( + 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C4UL, + 0x221208ACUL, 0x9DF506C6UL, 0x1571B4AEUL, 0x8AC47F71UL + ); + SECP256K1_SCALAR_VERIFY(k); + VERIFY_CHECK(r1 != k); + VERIFY_CHECK(r2 != k); + VERIFY_CHECK(r1 != r2); + + /* these _var calls are constant time since the shift amount is constant */ + secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384); + secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384); + secp256k1_scalar_mul(&c1, &c1, &minus_b1); + secp256k1_scalar_mul(&c2, &c2, &minus_b2); + secp256k1_scalar_add(r2, &c1, &c2); + secp256k1_scalar_mul(r1, r2, &secp256k1_const_lambda); + secp256k1_scalar_negate(r1, r1); + secp256k1_scalar_add(r1, r1, k); + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); +#ifdef VERIFY + secp256k1_scalar_split_lambda_verify(r1, r2, k); +#endif +} + +#ifdef VERIFY +/* + * Proof for secp256k1_scalar_split_lambda's bounds. + * + * Let + * - epsilon1 = 2^256 * |g1/2^384 - b2/d| + * - epsilon2 = 2^256 * |g2/2^384 - (-b1)/d| + * - c1 = round(k*g1/2^384) + * - c2 = round(k*g2/2^384) + * + * Lemma 1: |c1 - k*b2/d| < 2^-1 + epsilon1 + * + * |c1 - k*b2/d| + * = + * |c1 - k*g1/2^384 + k*g1/2^384 - k*b2/d| + * <= {triangle inequality} + * |c1 - k*g1/2^384| + |k*g1/2^384 - k*b2/d| + * = + * |c1 - k*g1/2^384| + k*|g1/2^384 - b2/d| + * < {rounding in c1 and 0 <= k < 2^256} + * 2^-1 + 2^256 * |g1/2^384 - b2/d| + * = {definition of epsilon1} + * 2^-1 + epsilon1 + * + * Lemma 2: |c2 - k*(-b1)/d| < 2^-1 + epsilon2 + * + * |c2 - k*(-b1)/d| + * = + * |c2 - k*g2/2^384 + k*g2/2^384 - k*(-b1)/d| + * <= {triangle inequality} + * |c2 - k*g2/2^384| + |k*g2/2^384 - k*(-b1)/d| + * = + * |c2 - k*g2/2^384| + k*|g2/2^384 - (-b1)/d| + * < {rounding in c2 and 0 <= k < 2^256} + * 2^-1 + 2^256 * |g2/2^384 - (-b1)/d| + * = {definition of epsilon2} + * 2^-1 + epsilon2 + * + * Let + * - k1 = k - c1*a1 - c2*a2 + * - k2 = - c1*b1 - c2*b2 + * + * Lemma 3: |k1| < (a1 + a2 + 1)/2 < 2^128 + * + * |k1| + * = {definition of k1} + * |k - c1*a1 - c2*a2| + * = {(a1*b2 - b1*a2)/n = 1} + * |k*(a1*b2 - b1*a2)/n - c1*a1 - c2*a2| + * = + * |a1*(k*b2/n - c1) + a2*(k*(-b1)/n - c2)| + * <= {triangle inequality} + * a1*|k*b2/n - c1| + a2*|k*(-b1)/n - c2| + * < {Lemma 1 and Lemma 2} + * a1*(2^-1 + epsilon1) + a2*(2^-1 + epsilon2) + * < {rounding up to an integer} + * (a1 + a2 + 1)/2 + * < {rounding up to a power of 2} + * 2^128 + * + * Lemma 4: |k2| < (-b1 + b2)/2 + 1 < 2^128 + * + * |k2| + * = {definition of k2} + * |- c1*a1 - c2*a2| + * = {(b1*b2 - b1*b2)/n = 0} + * |k*(b1*b2 - b1*b2)/n - c1*b1 - c2*b2| + * = + * |b1*(k*b2/n - c1) + b2*(k*(-b1)/n - c2)| + * <= {triangle inequality} + * (-b1)*|k*b2/n - c1| + b2*|k*(-b1)/n - c2| + * < {Lemma 1 and Lemma 2} + * (-b1)*(2^-1 + epsilon1) + b2*(2^-1 + epsilon2) + * < {rounding up to an integer} + * (-b1 + b2)/2 + 1 + * < {rounding up to a power of 2} + * 2^128 + * + * Let + * - r2 = k2 mod n + * - r1 = k - r2*lambda mod n. + * + * Notice that r1 is defined such that r1 + r2 * lambda == k (mod n). + * + * Lemma 5: r1 == k1 mod n. + * + * r1 + * == {definition of r1 and r2} + * k - k2*lambda + * == {definition of k2} + * k - (- c1*b1 - c2*b2)*lambda + * == + * k + c1*b1*lambda + c2*b2*lambda + * == {a1 + b1*lambda == 0 mod n and a2 + b2*lambda == 0 mod n} + * k - c1*a1 - c2*a2 + * == {definition of k1} + * k1 + * + * From Lemma 3, Lemma 4, Lemma 5 and the definition of r2, we can conclude that + * + * - either r1 < 2^128 or -r1 mod n < 2^128 + * - either r2 < 2^128 or -r2 mod n < 2^128. + * + * Q.E.D. + */ +static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, const secp256k1_scalar *r2, const secp256k1_scalar *k) { + secp256k1_scalar s; + unsigned char buf1[32]; + unsigned char buf2[32]; + + /* (a1 + a2 + 1)/2 is 0xa2a8918ca85bafe22016d0b917e4dd77 */ + static const unsigned char k1_bound[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa2, 0xa8, 0x91, 0x8c, 0xa8, 0x5b, 0xaf, 0xe2, 0x20, 0x16, 0xd0, 0xb9, 0x17, 0xe4, 0xdd, 0x77 + }; + + /* (-b1 + b2)/2 + 1 is 0x8a65287bd47179fb2be08846cea267ed */ + static const unsigned char k2_bound[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x65, 0x28, 0x7b, 0xd4, 0x71, 0x79, 0xfb, 0x2b, 0xe0, 0x88, 0x46, 0xce, 0xa2, 0x67, 0xed + }; + + secp256k1_scalar_mul(&s, &secp256k1_const_lambda, r2); + secp256k1_scalar_add(&s, &s, r1); + VERIFY_CHECK(secp256k1_scalar_eq(&s, k)); + + secp256k1_scalar_negate(&s, r1); + secp256k1_scalar_get_b32(buf1, r1); + secp256k1_scalar_get_b32(buf2, &s); + VERIFY_CHECK(secp256k1_memcmp_var(buf1, k1_bound, 32) < 0 || secp256k1_memcmp_var(buf2, k1_bound, 32) < 0); + + secp256k1_scalar_negate(&s, r2); + secp256k1_scalar_get_b32(buf1, r2); + secp256k1_scalar_get_b32(buf2, &s); + VERIFY_CHECK(secp256k1_memcmp_var(buf1, k2_bound, 32) < 0 || secp256k1_memcmp_var(buf2, k2_bound, 32) < 0); +} +#endif /* VERIFY */ +#endif /* !defined(EXHAUSTIVE_TEST_ORDER) */ + +#endif /* SECP256K1_SCALAR_IMPL_H */ diff --git a/external/secp256k1/src/scalar_low.h b/external/secp256k1/src/scalar_low.h new file mode 100644 index 00000000000..2711eb932dc --- /dev/null +++ b/external/secp256k1/src/scalar_low.h @@ -0,0 +1,24 @@ +/*********************************************************************** + * Copyright (c) 2015, 2022 Andrew Poelstra, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef uint32_t secp256k1_scalar; + +/* A compile-time constant equal to 2^32 (modulo order). */ +#define SCALAR_2P32 ((0xffffffffUL % EXHAUSTIVE_TEST_ORDER) + 1U) + +/* Compute a*2^32 + b (modulo order). */ +#define SCALAR_HORNER(a, b) (((uint64_t)(a) * SCALAR_2P32 + (b)) % EXHAUSTIVE_TEST_ORDER) + +/* Evaluates to the provided 256-bit constant reduced modulo order. */ +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER((d7), (d6)), (d5)), (d4)), (d3)), (d2)), (d1)), (d0)) + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/external/secp256k1/src/scalar_low_impl.h b/external/secp256k1/src/scalar_low_impl.h new file mode 100644 index 00000000000..84e1a380a3b --- /dev/null +++ b/external/secp256k1/src/scalar_low_impl.h @@ -0,0 +1,206 @@ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "checkmem.h" +#include "scalar.h" +#include "util.h" + +#include + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return !(*a & 1); +} + +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { + *r = v % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + + VERIFY_CHECK(count > 0 && count <= 32); + if (offset < 32) { + return (*a >> offset) & (0xFFFFFFFF >> (32 - count)); + } else { + return 0; + } +} + +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + + return secp256k1_scalar_get_bits_limb32(a, offset, count); +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } + +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r); + return *r < *b; +} + +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + SECP256K1_SCALAR_VERIFY(r); + + if (flag && bit < 32) + *r += ((uint32_t)1 << bit); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(bit < 32); + /* Verify that adding (1 << bit) will not overflow any in-range scalar *r by overflowing the underlying uint32_t. */ + VERIFY_CHECK(((uint32_t)1 << bit) - 1 <= UINT32_MAX - EXHAUSTIVE_TEST_ORDER); +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + int i; + int over = 0; + *r = 0; + for (i = 0; i < 32; i++) { + *r = (*r * 0x100) + b32[i]; + if (*r >= EXHAUSTIVE_TEST_ORDER) { + over = 1; + *r %= EXHAUSTIVE_TEST_ORDER; + } + } + if (overflow) *overflow = over; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + SECP256K1_SCALAR_VERIFY(a); + + memset(bin, 0, 32); + bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return *a == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + if (*a == 0) { + *r = 0; + } else { + *r = EXHAUSTIVE_TEST_ORDER - *a; + } + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return *a == 1; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return *a > EXHAUSTIVE_TEST_ORDER / 2; +} + +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + SECP256K1_SCALAR_VERIFY(r); + + if (flag) secp256k1_scalar_negate(r, r); + + SECP256K1_SCALAR_VERIFY(r); + return flag ? -1 : 1; +} + +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + *r1 = *a; + *r2 = 0; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); +} + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + return *a == *b; +} + +static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { + uint32_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r)); + + mask0 = vflag + ~((uint32_t)0); + mask1 = ~mask0; + *r = (*r & mask0) | (*a & mask1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { + int i; + uint32_t res = 0; + SECP256K1_SCALAR_VERIFY(x); + + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) { + res = i; + break; + } + } + + /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus + * have a composite group order; fix it in exhaustive_tests.c). */ + VERIFY_CHECK(res != 0); + *r = res; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_inverse(r, x); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + *r = (*a + ((-(uint32_t)(*a & 1)) & EXHAUSTIVE_TEST_ORDER)) >> 1; + + SECP256K1_SCALAR_VERIFY(r); +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/external/secp256k1/src/scratch.h b/external/secp256k1/src/scratch.h new file mode 100644 index 00000000000..6164330b394 --- /dev/null +++ b/external/secp256k1/src/scratch.h @@ -0,0 +1,44 @@ +/*********************************************************************** + * Copyright (c) 2017 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCRATCH_H +#define SECP256K1_SCRATCH_H + +/* The typedef is used internally; the struct name is used in the public API + * (where it is exposed as a different typedef) */ +typedef struct secp256k1_scratch_space_struct { + /** guard against interpreting this object as other types */ + unsigned char magic[8]; + /** actual allocated data */ + void *data; + /** amount that has been allocated (i.e. `data + offset` is the next + * available pointer) */ + size_t alloc_size; + /** maximum size available to allocate */ + size_t max_size; +} secp256k1_scratch; + +typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space; + +static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size); + +static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch); + +/** Returns an opaque object used to "checkpoint" a scratch space. Used + * with `secp256k1_scratch_apply_checkpoint` to undo allocations. */ +static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch); + +/** Applies a check point received from `secp256k1_scratch_checkpoint`, + * undoing all allocations since that point. */ +static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint); + +/** Returns the maximum allocation the scratch space will allow */ +static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t n_objects); + +/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ +static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t n); + +#endif diff --git a/external/secp256k1/src/scratch_impl.h b/external/secp256k1/src/scratch_impl.h new file mode 100644 index 00000000000..f71a20b9637 --- /dev/null +++ b/external/secp256k1/src/scratch_impl.h @@ -0,0 +1,99 @@ +/*********************************************************************** + * Copyright (c) 2017 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCRATCH_IMPL_H +#define SECP256K1_SCRATCH_IMPL_H + +#include "util.h" +#include "scratch.h" + +static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) { + const size_t base_alloc = ROUND_TO_ALIGN(sizeof(secp256k1_scratch)); + void *alloc = checked_malloc(error_callback, base_alloc + size); + secp256k1_scratch* ret = (secp256k1_scratch *)alloc; + if (ret != NULL) { + memset(ret, 0, sizeof(*ret)); + memcpy(ret->magic, "scratch", 8); + ret->data = (void *) ((char *) alloc + base_alloc); + ret->max_size = size; + } + return ret; +} + +static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) { + if (scratch != NULL) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return; + } + VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */ + memset(scratch->magic, 0, sizeof(scratch->magic)); + free(scratch); + } +} + +static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return 0; + } + return scratch->alloc_size; +} + +static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return; + } + if (checkpoint > scratch->alloc_size) { + secp256k1_callback_call(error_callback, "invalid checkpoint"); + return; + } + scratch->alloc_size = checkpoint; +} + +static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t objects) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return 0; + } + /* Ensure that multiplication will not wrap around */ + if (ALIGNMENT > 1 && objects > SIZE_MAX/(ALIGNMENT - 1)) { + return 0; + } + if (scratch->max_size - scratch->alloc_size <= objects * (ALIGNMENT - 1)) { + return 0; + } + return scratch->max_size - scratch->alloc_size - objects * (ALIGNMENT - 1); +} + +static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) { + void *ret; + size_t rounded_size; + + rounded_size = ROUND_TO_ALIGN(size); + /* Check that rounding did not wrap around */ + if (rounded_size < size) { + return NULL; + } + size = rounded_size; + + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return NULL; + } + + if (size > scratch->max_size - scratch->alloc_size) { + return NULL; + } + ret = (void *) ((char *) scratch->data + scratch->alloc_size); + memset(ret, 0, size); + scratch->alloc_size += size; + + return ret; +} + +#endif diff --git a/external/secp256k1/src/secp256k1.c b/external/secp256k1/src/secp256k1.c new file mode 100644 index 00000000000..a248519dfd8 --- /dev/null +++ b/external/secp256k1/src/secp256k1.c @@ -0,0 +1,831 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +/* This is a C project. It should not be compiled with a C++ compiler, + * and we error out if we detect one. + * + * We still want to be able to test the project with a C++ compiler + * because it is still good to know if this will lead to real trouble, so + * there is a possibility to override the check. But be warned that + * compiling with a C++ compiler is not supported. */ +#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE) +#error Trying to compile a C project with a C++ compiler. +#endif + +#define SECP256K1_BUILD + +#include "../include/secp256k1.h" +#include "../include/secp256k1_preallocated.h" + +#include "assumptions.h" +#include "checkmem.h" +#include "util.h" + +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_impl.h" +#include "ecmult_const_impl.h" +#include "ecmult_gen_impl.h" +#include "ecdsa_impl.h" +#include "eckey_impl.h" +#include "hash_impl.h" +#include "int128_impl.h" +#include "scratch_impl.h" +#include "selftest.h" +#include "hsort_impl.h" + +#ifdef SECP256K1_NO_BUILD +# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c" +#endif + +#define ARG_CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_callback_call(&ctx->illegal_callback, #cond); \ + return 0; \ + } \ +} while(0) + +#define ARG_CHECK_VOID(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_callback_call(&ctx->illegal_callback, #cond); \ + return; \ + } \ +} while(0) + +/* Note that whenever you change the context struct, you must also change the + * context_eq function. */ +struct secp256k1_context_struct { + secp256k1_ecmult_gen_context ecmult_gen_ctx; + secp256k1_callback illegal_callback; + secp256k1_callback error_callback; + int declassify; +}; + +static const secp256k1_context secp256k1_context_static_ = { + { 0 }, + { secp256k1_default_illegal_callback_fn, 0 }, + { secp256k1_default_error_callback_fn, 0 }, + 0 +}; +const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_; +const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_; + +/* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof. + * + * This is intended for "context" functions such as secp256k1_context_clone. Functions that need specific + * features of a context should still check for these features directly. For example, a function that needs + * ecmult_gen should directly check for the existence of the ecmult_gen context. */ +static int secp256k1_context_is_proper(const secp256k1_context* ctx) { + return secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx); +} + +void secp256k1_selftest(void) { + if (!secp256k1_selftest_passes()) { + secp256k1_callback_call(&default_error_callback, "self test failed"); + } +} + +size_t secp256k1_context_preallocated_size(unsigned int flags) { + size_t ret = sizeof(secp256k1_context); + /* A return value of 0 is reserved as an indicator for errors when we call this function internally. */ + VERIFY_CHECK(ret != 0); + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + secp256k1_callback_call(&default_illegal_callback, + "Invalid flags"); + return 0; + } + + if (EXPECT(!SECP256K1_CHECKMEM_RUNNING() && (flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY), 0)) { + secp256k1_callback_call(&default_illegal_callback, + "Declassify flag requires running with memory checking"); + return 0; + } + + return ret; +} + +size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + return sizeof(secp256k1_context); +} + +secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) { + size_t prealloc_size; + secp256k1_context* ret; + + secp256k1_selftest(); + + prealloc_size = secp256k1_context_preallocated_size(flags); + if (prealloc_size == 0) { + return NULL; + } + VERIFY_CHECK(prealloc != NULL); + ret = (secp256k1_context*)prealloc; + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; + + /* Flags have been checked by secp256k1_context_preallocated_size. */ + VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT); + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx); + ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY); + + return ret; +} + +secp256k1_context* secp256k1_context_create(unsigned int flags) { + size_t const prealloc_size = secp256k1_context_preallocated_size(flags); + secp256k1_context* ctx = (secp256k1_context*)checked_malloc(&default_error_callback, prealloc_size); + if (EXPECT(secp256k1_context_preallocated_create(ctx, flags) == NULL, 0)) { + free(ctx); + return NULL; + } + + return ctx; +} + +secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* ctx, void* prealloc) { + secp256k1_context* ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(prealloc != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + + ret = (secp256k1_context*)prealloc; + *ret = *ctx; + return ret; +} + +secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { + secp256k1_context* ret; + size_t prealloc_size; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + + prealloc_size = secp256k1_context_preallocated_clone_size(ctx); + ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size); + ret = secp256k1_context_preallocated_clone(ctx, ret); + return ret; +} + +void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) { + ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); + + /* Defined as noop */ + if (ctx == NULL) { + return; + } + + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); +} + +void secp256k1_context_destroy(secp256k1_context* ctx) { + ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); + + /* Defined as noop */ + if (ctx == NULL) { + return; + } + + secp256k1_context_preallocated_destroy(ctx); + free(ctx); +} + +void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + /* We compare pointers instead of checking secp256k1_context_is_proper() here + because setting callbacks is allowed on *copies* of the static context: + it's harmless and makes testing easier. */ + ARG_CHECK_VOID(ctx != secp256k1_context_static); + if (fun == NULL) { + fun = secp256k1_default_illegal_callback_fn; + } + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} + +void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + /* We compare pointers instead of checking secp256k1_context_is_proper() here + because setting callbacks is allowed on *copies* of the static context: + it's harmless and makes testing easier. */ + ARG_CHECK_VOID(ctx != secp256k1_context_static); + if (fun == NULL) { + fun = secp256k1_default_error_callback_fn; + } + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; +} + +static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { + VERIFY_CHECK(ctx != NULL); + return secp256k1_scratch_create(&ctx->error_callback, max_size); +} + +static void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) { + VERIFY_CHECK(ctx != NULL); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); +} + +/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour + * of the software. + */ +static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) { + if (EXPECT(ctx->declassify, 0)) SECP256K1_CHECKMEM_DEFINE(p, len); +} + +static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { + secp256k1_ge_from_bytes(ge, pubkey->data); + ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); + return 1; +} + +static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { + secp256k1_ge_to_bytes(pubkey->data, ge); +} + +int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { + secp256k1_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input != NULL); + if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { + return 0; + } + if (!secp256k1_ge_is_in_correct_subgroup(&Q)) { + return 0; + } + secp256k1_pubkey_save(pubkey, &Q); + secp256k1_ge_clear(&Q); + return 1; +} + +int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) { + secp256k1_ge Q; + size_t len; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u)); + len = *outputlen; + *outputlen = 0; + ARG_CHECK(output != NULL); + memset(output, 0, len); + ARG_CHECK(pubkey != NULL); + ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); + if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { + ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + if (ret) { + *outputlen = len; + } + } + return ret; +} + +int secp256k1_ec_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_pubkey* pubkey0, const secp256k1_pubkey* pubkey1) { + unsigned char out[2][33]; + const secp256k1_pubkey* pk[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + pk[0] = pubkey0; pk[1] = pubkey1; + for (i = 0; i < 2; i++) { + size_t out_size = sizeof(out[i]); + /* If the public key is NULL or invalid, ec_pubkey_serialize will call + * the illegal_callback and return 0. In that case we will serialize the + * key as all zeros which is less than any valid public key. This + * results in consistent comparisons even if NULL or invalid pubkeys are + * involved and prevents edge cases such as sorting algorithms that use + * this function and do not terminate as a result. */ + if (!secp256k1_ec_pubkey_serialize(ctx, out[i], &out_size, pk[i], SECP256K1_EC_COMPRESSED)) { + /* Note that ec_pubkey_serialize should already set the output to + * zero in that case, but it's not guaranteed by the API, we can't + * test it and writing a VERIFY_CHECK is more complex than + * explicitly memsetting (again). */ + memset(out[i], 0, sizeof(out[i])); + } + } + return secp256k1_memcmp_var(out[0], out[1], sizeof(out[0])); +} + +static int secp256k1_ec_pubkey_sort_cmp(const void* pk1, const void* pk2, void *ctx) { + return secp256k1_ec_pubkey_cmp((secp256k1_context *)ctx, + *(secp256k1_pubkey **)pk1, + *(secp256k1_pubkey **)pk2); +} + +int secp256k1_ec_pubkey_sort(const secp256k1_context* ctx, const secp256k1_pubkey **pubkeys, size_t n_pubkeys) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkeys != NULL); + + /* Suppress wrong warning (fixed in MSVC 19.33) */ + #if defined(_MSC_VER) && (_MSC_VER < 1933) + #pragma warning(push) + #pragma warning(disable: 4090) + #endif + + /* Casting away const is fine because neither secp256k1_hsort nor + * secp256k1_ec_pubkey_sort_cmp modify the data pointed to by the cmp_data + * argument. */ + secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_ec_pubkey_sort_cmp, (void *)ctx); + + #if defined(_MSC_VER) && (_MSC_VER < 1933) + #pragma warning(pop) + #endif + + return 1; +} + +static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } +} + +static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } +} + +int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; + } else { + memset(sig, 0, sizeof(*sig)); + return 0; + } +} + +int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); +} + +int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) { + secp256k1_scalar r, s; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = secp256k1_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + secp256k1_scalar_negate(&s, &s); + } + secp256k1_ecdsa_signature_save(sigout, &r, &s); + } + + return ret; +} + +int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msghash32, const secp256k1_pubkey *pubkey) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_scalar_set_b32(&m, msghash32, NULL); + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return (!secp256k1_scalar_is_high(&s) && + secp256k1_pubkey_load(ctx, &q, pubkey) && + secp256k1_ecdsa_sig_verify(&r, &s, &q, &m)); +} + +static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) { + memcpy(buf + *offset, data, len); + *offset += len; +} + +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + unsigned char keydata[112]; + unsigned int offset = 0; + secp256k1_rfc6979_hmac_sha256 rng; + unsigned int i; + secp256k1_scalar msg; + unsigned char msgmod32[32]; + secp256k1_scalar_set_b32(&msg, msg32, NULL); + secp256k1_scalar_get_b32(msgmod32, &msg); + /* We feed a byte array to the PRNG as input, consisting of: + * - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d. + * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. + * - optionally 16 extra bytes with the algorithm name. + * Because the arguments have distinct fixed lengths it is not possible for + * different argument mixtures to emulate each other and result in the same + * nonces. + */ + buffer_append(keydata, &offset, key32, 32); + buffer_append(keydata, &offset, msgmod32, 32); + if (data != NULL) { + buffer_append(keydata, &offset, data, 32); + } + if (algo16 != NULL) { + buffer_append(keydata, &offset, algo16, 16); + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); + for (i = 0; i <= counter; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_memclear(keydata, sizeof(keydata)); + secp256k1_rfc6979_hmac_sha256_clear(&rng); + return 1; +} + +const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; +const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; + +static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar sec, non, msg; + int ret = 0; + int is_sec_valid; + unsigned char nonce32[32]; + unsigned int count = 0; + /* Default initialization here is important so we won't pass uninit values to the cmov in the end */ + *r = secp256k1_scalar_zero; + *s = secp256k1_scalar_zero; + if (recid) { + *recid = 0; + } + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + /* Fail if the secret key is invalid. */ + is_sec_valid = secp256k1_scalar_set_b32_seckey(&sec, seckey); + secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, !is_sec_valid); + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + int is_nonce_valid; + ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + is_nonce_valid = secp256k1_scalar_set_b32_seckey(&non, nonce32); + /* The nonce is still secret here, but it being invalid is less likely than 1:2^255. */ + secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); + if (is_nonce_valid) { + ret = secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid); + /* The final signature is no longer a secret, nor is the fact that we were successful or not. */ + secp256k1_declassify(ctx, &ret, sizeof(ret)); + if (ret) { + break; + } + } + count++; + } + /* We don't want to declassify is_sec_valid and therefore the range of + * seckey. As a result is_sec_valid is included in ret only after ret was + * used as a branching variable. */ + ret &= is_sec_valid; + secp256k1_memclear(nonce32, sizeof(nonce32)); + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + secp256k1_scalar_cmov(r, &secp256k1_scalar_zero, !ret); + secp256k1_scalar_cmov(s, &secp256k1_scalar_zero, !ret); + if (recid) { + const int zero = 0; + secp256k1_int_cmov(recid, &zero, !ret); + } + return ret; +} + +int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar r, s; + int ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + + ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, msghash32, seckey, noncefp, noncedata); + secp256k1_ecdsa_signature_save(signature, &r, &s); + return ret; +} + +int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { + secp256k1_scalar sec; + int ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); + secp256k1_scalar_clear(&sec); + return ret; +} + +static int secp256k1_ec_pubkey_create_helper(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_scalar *seckey_scalar, secp256k1_ge *p, const unsigned char *seckey) { + secp256k1_gej pj; + int ret; + + ret = secp256k1_scalar_set_b32_seckey(seckey_scalar, seckey); + secp256k1_scalar_cmov(seckey_scalar, &secp256k1_scalar_one, !ret); + + secp256k1_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar); + secp256k1_ge_set_gej(p, &pj); + secp256k1_gej_clear(&pj); + return ret; +} + +int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) { + secp256k1_ge p; + secp256k1_scalar seckey_scalar; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey != NULL); + + ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey); + secp256k1_pubkey_save(pubkey, &p); + secp256k1_memczero(pubkey, sizeof(*pubkey), !ret); + + secp256k1_scalar_clear(&seckey_scalar); + return ret; +} + +int secp256k1_ec_seckey_negate(const secp256k1_context* ctx, unsigned char *seckey) { + secp256k1_scalar sec; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); + secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret); + secp256k1_scalar_negate(&sec, &sec); + secp256k1_scalar_get_b32(seckey, &sec); + + secp256k1_scalar_clear(&sec); + return ret; +} + +int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) { + return secp256k1_ec_seckey_negate(ctx, seckey); +} + +int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { + int ret = 0; + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + + ret = secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + secp256k1_ge_neg(&p, &p); + secp256k1_pubkey_save(pubkey, &p); + } + return ret; +} + + +static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak32) { + secp256k1_scalar term; + int overflow = 0; + int ret = 0; + + secp256k1_scalar_set_b32(&term, tweak32, &overflow); + ret = (!overflow) & secp256k1_eckey_privkey_tweak_add(sec, &term); + secp256k1_scalar_clear(&term); + return ret; +} + +int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + secp256k1_scalar sec; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak32 != NULL); + + ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); + ret &= secp256k1_ec_seckey_tweak_add_helper(&sec, tweak32); + secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret); + secp256k1_scalar_get_b32(seckey, &sec); + + secp256k1_scalar_clear(&sec); + return ret; +} + +int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + return secp256k1_ec_seckey_tweak_add(ctx, seckey, tweak32); +} + +static int secp256k1_ec_pubkey_tweak_add_helper(secp256k1_ge *p, const unsigned char *tweak32) { + secp256k1_scalar term; + int overflow = 0; + secp256k1_scalar_set_b32(&term, tweak32, &overflow); + return !overflow && secp256k1_eckey_pubkey_tweak_add(p, &term); +} + +int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) { + secp256k1_ge p; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + ret = secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + ret = ret && secp256k1_ec_pubkey_tweak_add_helper(&p, tweak32); + if (ret) { + secp256k1_pubkey_save(pubkey, &p); + } + + return ret; +} + +int secp256k1_ec_seckey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + secp256k1_scalar factor; + secp256k1_scalar sec; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak32 != NULL); + + secp256k1_scalar_set_b32(&factor, tweak32, &overflow); + ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); + ret &= (!overflow) & secp256k1_eckey_privkey_tweak_mul(&sec, &factor); + secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret); + secp256k1_scalar_get_b32(seckey, &sec); + + secp256k1_scalar_clear(&sec); + secp256k1_scalar_clear(&factor); + return ret; +} + +int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + return secp256k1_ec_seckey_tweak_mul(ctx, seckey, tweak32); +} + +int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) { + secp256k1_ge p; + secp256k1_scalar factor; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + secp256k1_scalar_set_b32(&factor, tweak32, &overflow); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_eckey_pubkey_tweak_mul(&p, &factor)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; + } + } + + return ret; +} + +int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + + if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + } + return 1; +} + +int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) { + size_t i; + secp256k1_gej Qj; + secp256k1_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(n >= 1); + ARG_CHECK(pubnonces != NULL); + + secp256k1_gej_set_infinity(&Qj); + + for (i = 0; i < n; i++) { + ARG_CHECK(pubnonces[i] != NULL); + secp256k1_pubkey_load(ctx, &Q, pubnonces[i]); + secp256k1_gej_add_ge(&Qj, &Qj, &Q); + } + if (secp256k1_gej_is_infinity(&Qj)) { + return 0; + } + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(pubnonce, &Q); + return 1; +} + +int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, const unsigned char *msg, size_t msglen) { + secp256k1_sha256 sha; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(hash32 != NULL); + ARG_CHECK(tag != NULL); + ARG_CHECK(msg != NULL); + + secp256k1_sha256_initialize_tagged(&sha, tag, taglen); + secp256k1_sha256_write(&sha, msg, msglen); + secp256k1_sha256_finalize(&sha, hash32); + secp256k1_sha256_clear(&sha); + return 1; +} + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "modules/extrakeys/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/main_impl.h" +#endif diff --git a/external/secp256k1/src/selftest.h b/external/secp256k1/src/selftest.h new file mode 100644 index 00000000000..d083ac95248 --- /dev/null +++ b/external/secp256k1/src/selftest.h @@ -0,0 +1,32 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SELFTEST_H +#define SECP256K1_SELFTEST_H + +#include "hash.h" + +#include + +static int secp256k1_selftest_sha256(void) { + static const char *input63 = "For this sample, this 63-byte string will be used as input data"; + static const unsigned char output32[32] = { + 0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, + 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42, + }; + unsigned char out[32]; + secp256k1_sha256 hasher; + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, (const unsigned char*)input63, 63); + secp256k1_sha256_finalize(&hasher, out); + return secp256k1_memcmp_var(out, output32, 32) == 0; +} + +static int secp256k1_selftest_passes(void) { + return secp256k1_selftest_sha256(); +} + +#endif /* SECP256K1_SELFTEST_H */ diff --git a/external/secp256k1/src/testrand.h b/external/secp256k1/src/testrand.h new file mode 100644 index 00000000000..3c1ed3d45dc --- /dev/null +++ b/external/secp256k1/src/testrand.h @@ -0,0 +1,48 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_TESTRAND_H +#define SECP256K1_TESTRAND_H + +#include "util.h" + +/* A non-cryptographic RNG used only for test infrastructure. */ + +/** Seed the pseudorandom number generator for testing. */ +SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16); + +/** Generate a pseudorandom number in the range [0..2**32-1]. */ +SECP256K1_INLINE static uint32_t testrand32(void); + +/** Generate a pseudorandom number in the range [0..2**64-1]. */ +SECP256K1_INLINE static uint64_t testrand64(void); + +/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or + * more. */ +SECP256K1_INLINE static uint64_t testrand_bits(int bits); + +/** Generate a pseudorandom number in the range [0..range-1]. */ +static uint32_t testrand_int(uint32_t range); + +/** Generate a pseudorandom 32-byte array. */ +static void testrand256(unsigned char *b32); + +/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ +static void testrand256_test(unsigned char *b32); + +/** Generate pseudorandom bytes with long sequences of zero and one bits. */ +static void testrand_bytes_test(unsigned char *bytes, size_t len); + +/** Flip a single random bit in a byte array */ +static void testrand_flip(unsigned char *b, size_t len); + +/** Initialize the test RNG using (hex encoded) array up to 16 bytes, or randomly if hexseed is NULL. */ +static void testrand_init(const char* hexseed); + +/** Print final test information. */ +static void testrand_finish(void); + +#endif /* SECP256K1_TESTRAND_H */ diff --git a/external/secp256k1/src/testrand_impl.h b/external/secp256k1/src/testrand_impl.h new file mode 100644 index 00000000000..b84f5730a91 --- /dev/null +++ b/external/secp256k1/src/testrand_impl.h @@ -0,0 +1,167 @@ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_TESTRAND_IMPL_H +#define SECP256K1_TESTRAND_IMPL_H + +#include +#include +#include + +#include "testrand.h" +#include "hash.h" +#include "util.h" + +static uint64_t secp256k1_test_state[4]; + +SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16) { + static const unsigned char PREFIX[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', ' ', 't', 'e', 's', 't', ' ', 'i', 'n', 'i', 't'}; + unsigned char out32[32]; + secp256k1_sha256 hash; + int i; + + /* Use SHA256(PREFIX || seed16) as initial state. */ + secp256k1_sha256_initialize(&hash); + secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX)); + secp256k1_sha256_write(&hash, seed16, 16); + secp256k1_sha256_finalize(&hash, out32); + for (i = 0; i < 4; ++i) { + uint64_t s = 0; + int j; + for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j]; + secp256k1_test_state[i] = s; + } +} + +SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + +SECP256K1_INLINE static uint64_t testrand64(void) { + /* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */ + const uint64_t result = rotl(secp256k1_test_state[0] + secp256k1_test_state[3], 23) + secp256k1_test_state[0]; + const uint64_t t = secp256k1_test_state[1] << 17; + secp256k1_test_state[2] ^= secp256k1_test_state[0]; + secp256k1_test_state[3] ^= secp256k1_test_state[1]; + secp256k1_test_state[1] ^= secp256k1_test_state[2]; + secp256k1_test_state[0] ^= secp256k1_test_state[3]; + secp256k1_test_state[2] ^= t; + secp256k1_test_state[3] = rotl(secp256k1_test_state[3], 45); + return result; +} + +SECP256K1_INLINE static uint64_t testrand_bits(int bits) { + if (bits == 0) return 0; + return testrand64() >> (64 - bits); +} + +SECP256K1_INLINE static uint32_t testrand32(void) { + return testrand64() >> 32; +} + +static uint32_t testrand_int(uint32_t range) { + uint32_t mask = 0; + uint32_t range_copy; + /* Reduce range by 1, changing its meaning to "maximum value". */ + VERIFY_CHECK(range != 0); + range -= 1; + /* Count the number of bits in range. */ + range_copy = range; + while (range_copy) { + mask = (mask << 1) | 1U; + range_copy >>= 1; + } + /* Generation loop. */ + while (1) { + uint32_t val = testrand64() & mask; + if (val <= range) return val; + } +} + +static void testrand256(unsigned char *b32) { + int i; + for (i = 0; i < 4; ++i) { + uint64_t val = testrand64(); + b32[0] = val; + b32[1] = val >> 8; + b32[2] = val >> 16; + b32[3] = val >> 24; + b32[4] = val >> 32; + b32[5] = val >> 40; + b32[6] = val >> 48; + b32[7] = val >> 56; + b32 += 8; + } +} + +static void testrand_bytes_test(unsigned char *bytes, size_t len) { + size_t bits = 0; + memset(bytes, 0, len); + while (bits < len * 8) { + int now; + uint32_t val; + now = 1 + (testrand_bits(6) * testrand_bits(5) + 16) / 31; + val = testrand_bits(1); + while (now > 0 && bits < len * 8) { + bytes[bits / 8] |= val << (bits % 8); + now--; + bits++; + } + } +} + +static void testrand256_test(unsigned char *b32) { + testrand_bytes_test(b32, 32); +} + +static void testrand_flip(unsigned char *b, size_t len) { + b[testrand_int(len)] ^= (1 << testrand_bits(3)); +} + +static void testrand_init(const char* hexseed) { + unsigned char seed16[16] = {0}; + if (hexseed && strlen(hexseed) != 0) { + int pos = 0; + while (pos < 16 && hexseed[0] != 0 && hexseed[1] != 0) { + unsigned short sh; + if ((sscanf(hexseed, "%2hx", &sh)) == 1) { + seed16[pos] = sh; + } else { + break; + } + hexseed += 2; + pos++; + } + } else { + FILE *frand = fopen("/dev/urandom", "rb"); + if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) { + uint64_t t = time(NULL) * (uint64_t)1337; + fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n"); + seed16[0] ^= t; + seed16[1] ^= t >> 8; + seed16[2] ^= t >> 16; + seed16[3] ^= t >> 24; + seed16[4] ^= t >> 32; + seed16[5] ^= t >> 40; + seed16[6] ^= t >> 48; + seed16[7] ^= t >> 56; + } + if (frand) { + fclose(frand); + } + } + + printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); + testrand_seed(seed16); +} + +static void testrand_finish(void) { + unsigned char run32[32]; + testrand256(run32); + printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); +} + +#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/external/secp256k1/src/tests.c b/external/secp256k1/src/tests.c new file mode 100644 index 00000000000..78533b11c28 --- /dev/null +++ b/external/secp256k1/src/tests.c @@ -0,0 +1,7841 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#include +#include +#include + +#include + +#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS + #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in tests.") + #undef USE_EXTERNAL_DEFAULT_CALLBACKS +#endif +#if defined(VERIFY) && defined(COVERAGE) + #pragma message("Defining VERIFY for tests being built for coverage analysis support is meaningless.") +#endif +#include "secp256k1.c" + +#include "../include/secp256k1.h" +#include "../include/secp256k1_preallocated.h" +#include "testrand_impl.h" +#include "checkmem.h" +#include "testutil.h" +#include "util.h" + +#include "../contrib/lax_der_parsing.c" +#include "../contrib/lax_der_privatekey_parsing.c" + +#include "modinv32_impl.h" +#ifdef SECP256K1_WIDEMUL_INT128 +#include "modinv64_impl.h" +#include "int128_impl.h" +#endif + +#define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else + +static int COUNT = 16; +static secp256k1_context *CTX = NULL; +static secp256k1_context *STATIC_CTX = NULL; + +static int all_bytes_equal(const void* s, unsigned char value, size_t n) { + const unsigned char *p = s; + size_t i; + + for (i = 0; i < n; i++) { + if (p[i] != value) { + return 0; + } + } + return 1; +} + +#define CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, callback, callback_setter) do { \ + int32_t _calls_to_callback = 0; \ + secp256k1_callback _saved_callback = ctx->callback; \ + callback_setter(ctx, counting_callback_fn, &_calls_to_callback); \ + { expr_or_stmt; } \ + ctx->callback = _saved_callback; \ + CHECK(_calls_to_callback == 1); \ +} while(0); + +/* CHECK that expr_or_stmt calls the error or illegal callback of ctx exactly once + * + * Useful for checking functions that return void (e.g., API functions that use ARG_CHECK_VOID) */ +#define CHECK_ERROR_VOID(ctx, expr_or_stmt) \ + CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, error_callback, secp256k1_context_set_error_callback) +#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) \ + CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, illegal_callback, secp256k1_context_set_illegal_callback) + +/* CHECK that + * - expr calls the illegal callback of ctx exactly once and, + * - expr == 0 (or equivalently, expr == NULL) + * + * Useful for checking functions that return an integer or a pointer. */ +#define CHECK_ILLEGAL(ctx, expr) CHECK_ILLEGAL_VOID(ctx, CHECK((expr) == 0)) +#define CHECK_ERROR(ctx, expr) CHECK_ERROR_VOID(ctx, CHECK((expr) == 0)) + +static void counting_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts. */ + int32_t *p; + (void)str; + p = data; + CHECK(*p != INT32_MAX); + (*p)++; +} + +static void uncounting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts (backwards). */ + int32_t *p; + (void)str; + p = data; + CHECK(*p != INT32_MIN); + (*p)--; +} + +static void run_xoshiro256pp_tests(void) { + { + size_t i; + /* Sanity check that we run before the actual seeding. */ + for (i = 0; i < sizeof(secp256k1_test_state)/sizeof(secp256k1_test_state[0]); i++) { + CHECK(secp256k1_test_state[i] == 0); + } + } + { + int i; + unsigned char buf32[32]; + unsigned char seed16[16] = { + 'C', 'H', 'I', 'C', 'K', 'E', 'N', '!', + 'C', 'H', 'I', 'C', 'K', 'E', 'N', '!', + }; + unsigned char buf32_expected[32] = { + 0xAF, 0xCC, 0xA9, 0x16, 0xB5, 0x6C, 0xE3, 0xF0, + 0x44, 0x3F, 0x45, 0xE0, 0x47, 0xA5, 0x08, 0x36, + 0x4C, 0xCC, 0xC1, 0x18, 0xB2, 0xD8, 0x8F, 0xEF, + 0x43, 0x26, 0x15, 0x57, 0x37, 0x00, 0xEF, 0x30, + }; + testrand_seed(seed16); + for (i = 0; i < 17; i++) { + testrand256(buf32); + } + CHECK(secp256k1_memcmp_var(buf32, buf32_expected, sizeof(buf32)) == 0); + } +} + +static void run_selftest_tests(void) { + /* Test public API */ + secp256k1_selftest(); +} + +static int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const secp256k1_ecmult_gen_context *b) { + return a->built == b->built + && secp256k1_scalar_eq(&a->scalar_offset, &b->scalar_offset) + && secp256k1_ge_eq_var(&a->ge_offset, &b->ge_offset) + && secp256k1_fe_equal(&a->proj_blind, &b->proj_blind); +} + +static int context_eq(const secp256k1_context *a, const secp256k1_context *b) { + return a->declassify == b->declassify + && ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx) + && a->illegal_callback.fn == b->illegal_callback.fn + && a->illegal_callback.data == b->illegal_callback.data + && a->error_callback.fn == b->error_callback.fn + && a->error_callback.data == b->error_callback.data; +} + +static void run_deprecated_context_flags_test(void) { + /* Check that a context created with any of the flags in the flags array is + * identical to the NONE context. */ + unsigned int flags[] = { SECP256K1_CONTEXT_SIGN, + SECP256K1_CONTEXT_VERIFY, + SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY }; + secp256k1_context *none_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + int i; + for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) { + secp256k1_context *tmp_ctx; + CHECK(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE) == secp256k1_context_preallocated_size(flags[i])); + tmp_ctx = secp256k1_context_create(flags[i]); + CHECK(context_eq(none_ctx, tmp_ctx)); + secp256k1_context_destroy(tmp_ctx); + } + secp256k1_context_destroy(none_ctx); +} + +static void run_ec_illegal_argument_tests(void) { + secp256k1_pubkey pubkey; + secp256k1_pubkey zero_pubkey; + secp256k1_ecdsa_signature sig; + unsigned char ctmp[32]; + + /* Setup */ + memset(ctmp, 1, 32); + memset(&zero_pubkey, 0, sizeof(zero_pubkey)); + + /* Verify context-type checking illegal-argument errors. */ + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL)); + SECP256K1_CHECKMEM_UNDEFINE(&sig, sizeof(sig)); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, ctmp, ctmp, NULL, NULL) == 1); + SECP256K1_CHECKMEM_CHECK(&sig, sizeof(sig)); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, ctmp, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(STATIC_CTX, &sig, ctmp, &pubkey) == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp) == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(STATIC_CTX, &pubkey, ctmp) == 1); + CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp) == 1); + CHECK(secp256k1_ec_pubkey_negate(STATIC_CTX, &pubkey) == 1); + CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey) == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_negate(STATIC_CTX, &zero_pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_negate(CTX, NULL)); + CHECK(secp256k1_ec_pubkey_tweak_mul(STATIC_CTX, &pubkey, ctmp) == 1); +} + +static void run_static_context_tests(int use_prealloc) { + /* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */ + CHECK(secp256k1_context_no_precomp == secp256k1_context_static); + + { + unsigned char seed[32] = {0x17}; + + /* Randomizing secp256k1_context_static is not supported. */ + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, seed)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, NULL)); + + /* Destroying or cloning secp256k1_context_static is not supported. */ + if (use_prealloc) { + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone_size(STATIC_CTX)); + { + secp256k1_context *my_static_ctx = malloc(sizeof(*STATIC_CTX)); + CHECK(my_static_ctx != NULL); + memset(my_static_ctx, 0x2a, sizeof(*my_static_ctx)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone(STATIC_CTX, my_static_ctx)); + CHECK(all_bytes_equal(my_static_ctx, 0x2a, sizeof(*my_static_ctx))); + free(my_static_ctx); + } + CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_preallocated_destroy(STATIC_CTX)); + } else { + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_clone(STATIC_CTX)); + CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_destroy(STATIC_CTX)); + } + } + + { + /* Verify that setting and resetting illegal callback works */ + int32_t dummy = 0; + secp256k1_context_set_illegal_callback(STATIC_CTX, counting_callback_fn, &dummy); + CHECK(STATIC_CTX->illegal_callback.fn == counting_callback_fn); + CHECK(STATIC_CTX->illegal_callback.data == &dummy); + secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn); + CHECK(STATIC_CTX->illegal_callback.data == NULL); + } +} + +static void run_proper_context_tests(int use_prealloc) { + int32_t dummy = 0; + secp256k1_context *my_ctx, *my_ctx_fresh; + void *my_ctx_prealloc = NULL; + unsigned char seed[32] = {0x17}; + + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar msg, key, nonce; + secp256k1_scalar sigr, sigs; + + /* Fresh reference context for comparison */ + my_ctx_fresh = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + + if (use_prealloc) { + my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(my_ctx_prealloc != NULL); + my_ctx = secp256k1_context_preallocated_create(my_ctx_prealloc, SECP256K1_CONTEXT_NONE); + } else { + my_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + } + + /* Randomize and reset randomization */ + CHECK(context_eq(my_ctx, my_ctx_fresh)); + CHECK(secp256k1_context_randomize(my_ctx, seed) == 1); + CHECK(!context_eq(my_ctx, my_ctx_fresh)); + CHECK(secp256k1_context_randomize(my_ctx, NULL) == 1); + CHECK(context_eq(my_ctx, my_ctx_fresh)); + + /* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */ + secp256k1_context_set_error_callback(my_ctx, secp256k1_default_illegal_callback_fn, NULL); + CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn); + CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn); + + /* check if sizes for cloning are consistent */ + CHECK(secp256k1_context_preallocated_clone_size(my_ctx) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + + /*** clone and destroy all of them to make sure cloning was complete ***/ + { + secp256k1_context *ctx_tmp; + + if (use_prealloc) { + /* clone into a non-preallocated context and then again into a new preallocated one. */ + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_clone(my_ctx); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_preallocated_destroy(ctx_tmp); + + free(my_ctx_prealloc); + my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(my_ctx_prealloc != NULL); + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_preallocated_clone(my_ctx, my_ctx_prealloc); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_destroy(ctx_tmp); + } else { + /* clone into a preallocated context and then again into a new non-preallocated one. */ + void *prealloc_tmp; + + prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(prealloc_tmp != NULL); + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_preallocated_clone(my_ctx, prealloc_tmp); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_destroy(ctx_tmp); + + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_clone(my_ctx); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + } + } + + /* Verify that the error callback makes it across the clone. */ + CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn); + CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn); + /* And that it resets back to default. */ + secp256k1_context_set_error_callback(my_ctx, NULL, NULL); + CHECK(my_ctx->error_callback.fn == secp256k1_default_error_callback_fn); + CHECK(context_eq(my_ctx, my_ctx_fresh)); + + /* Verify that setting and resetting illegal callback works */ + secp256k1_context_set_illegal_callback(my_ctx, counting_callback_fn, &dummy); + CHECK(my_ctx->illegal_callback.fn == counting_callback_fn); + CHECK(my_ctx->illegal_callback.data == &dummy); + secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL); + CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn); + CHECK(my_ctx->illegal_callback.data == NULL); + CHECK(context_eq(my_ctx, my_ctx_fresh)); + + /*** attempt to use them ***/ + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + secp256k1_ecmult_gen(&my_ctx->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + + /* obtain a working nonce */ + do { + testutil_random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + + /* try signing */ + CHECK(secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + + /* try verifying */ + CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); + + /* cleanup */ + if (use_prealloc) { + secp256k1_context_preallocated_destroy(my_ctx); + free(my_ctx_prealloc); + } else { + secp256k1_context_destroy(my_ctx); + } + secp256k1_context_destroy(my_ctx_fresh); + + /* Defined as no-op. */ + secp256k1_context_destroy(NULL); + secp256k1_context_preallocated_destroy(NULL); +} + +static void run_scratch_tests(void) { + const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; + + size_t checkpoint; + size_t checkpoint_2; + secp256k1_scratch_space *scratch; + secp256k1_scratch_space local_scratch; + + /* Test public API */ + scratch = secp256k1_scratch_space_create(CTX, 1000); + CHECK(scratch != NULL); + + /* Test internal API */ + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1)); + CHECK(scratch->alloc_size == 0); + CHECK(scratch->alloc_size % ALIGNMENT == 0); + + /* Allocating 500 bytes succeeds */ + checkpoint = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + CHECK(scratch->alloc_size != 0); + CHECK(scratch->alloc_size % ALIGNMENT == 0); + + /* Allocating another 501 bytes fails */ + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 501) == NULL); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + CHECK(scratch->alloc_size != 0); + CHECK(scratch->alloc_size % ALIGNMENT == 0); + + /* ...but it succeeds once we apply the checkpoint to undo it */ + secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); + CHECK(scratch->alloc_size == 0); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000); + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL); + CHECK(scratch->alloc_size != 0); + + /* try to apply a bad checkpoint */ + checkpoint_2 = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); + secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); + CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2)); /* checkpoint_2 is after checkpoint */ + CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1)); /* this is just wildly invalid */ + + /* try to use badly initialized scratch space */ + secp256k1_scratch_space_destroy(CTX, scratch); + memset(&local_scratch, 0, sizeof(local_scratch)); + scratch = &local_scratch; + CHECK_ERROR(CTX, secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0)); + CHECK_ERROR(CTX, secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500)); + CHECK_ERROR_VOID(CTX, secp256k1_scratch_space_destroy(CTX, scratch)); + + /* Test that large integers do not wrap around in a bad way */ + scratch = secp256k1_scratch_space_create(CTX, 1000); + /* Try max allocation with a large number of objects. Only makes sense if + * ALIGNMENT is greater than 1 because otherwise the objects take no extra + * space. */ + CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1)); + /* Try allocating SIZE_MAX to test wrap around which only happens if + * ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch + * space is too small. */ + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, SIZE_MAX) == NULL); + secp256k1_scratch_space_destroy(CTX, scratch); + + /* cleanup */ + secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */ +} + +static void run_ctz_tests(void) { + static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129}; + static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef}; + int shift; + unsigned i; + for (i = 0; i < sizeof(b32) / sizeof(b32[0]); ++i) { + for (shift = 0; shift < 32; ++shift) { + CHECK(secp256k1_ctz32_var_debruijn(b32[i] << shift) == shift); + CHECK(secp256k1_ctz32_var(b32[i] << shift) == shift); + } + } + for (i = 0; i < sizeof(b64) / sizeof(b64[0]); ++i) { + for (shift = 0; shift < 64; ++shift) { + CHECK(secp256k1_ctz64_var_debruijn(b64[i] << shift) == shift); + CHECK(secp256k1_ctz64_var(b64[i] << shift) == shift); + } + } +} + +/***** HASH TESTS *****/ + +static void run_sha256_known_output_tests(void) { + static const char *inputs[] = { + "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "For this sample, this 63-byte string will be used as input data", + "This is exactly 64 bytes long, not counting the terminating byte", + "aaaaa", + }; + static const unsigned int repeat[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1000000/5 + }; + static const unsigned char outputs[][32] = { + {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, + {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, + {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, + {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}, + {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, + {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, + {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, + {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}, + {0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}, + }; + unsigned int i, ninputs; + + /* Skip last input vector for low iteration counts */ + ninputs = sizeof(inputs)/sizeof(inputs[0]) - 1; + CONDITIONAL_TEST(16, "run_sha256_known_output_tests 1000000") ninputs++; + + for (i = 0; i < ninputs; i++) { + unsigned char out[32]; + secp256k1_sha256 hasher; + unsigned int j; + /* 1. Run: simply write the input bytestrings */ + j = repeat[i]; + secp256k1_sha256_initialize(&hasher); + while (j > 0) { + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + j--; + } + secp256k1_sha256_finalize(&hasher, out); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); + /* 2. Run: split the input bytestrings randomly before writing */ + if (strlen(inputs[i]) > 0) { + int split = testrand_int(strlen(inputs[i])); + secp256k1_sha256_initialize(&hasher); + j = repeat[i]; + while (j > 0) { + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + j--; + } + secp256k1_sha256_finalize(&hasher, out); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); + } + } +} + +/** SHA256 counter tests + +The tests verify that the SHA256 counter doesn't wrap around at message length +2^i bytes for i = 20, ..., 33. This wide range aims at being independent of the +implementation of the counter and it catches multiple natural 32-bit overflows +(e.g., counting bits, counting bytes, counting blocks, ...). + +The test vectors have been generated using following Python script which relies +on https://github.com/cloudtools/sha256/ (v0.3 on Python v3.10.2). + +``` +from sha256 import sha256 +from copy import copy + +def midstate_c_definition(hasher): + ret = ' {{0x' + hasher.state[0].hex('_', 4).replace('_', ', 0x') + '},\n' + ret += ' {0x00}, ' + str(hex(hasher.state[1])) + '}' + return ret + +def output_c_literal(hasher): + return '{0x' + hasher.digest().hex('_').replace('_', ', 0x') + '}' + +MESSAGE = b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno' +assert(len(MESSAGE) == 64) +BYTE_BOUNDARIES = [(2**b)//len(MESSAGE) - 1 for b in range(20, 34)] + +midstates = [] +digests = [] +hasher = sha256() +for i in range(BYTE_BOUNDARIES[-1] + 1): + if i in BYTE_BOUNDARIES: + midstates.append(midstate_c_definition(hasher)) + hasher_copy = copy(hasher) + hasher_copy.update(MESSAGE) + digests.append(output_c_literal(hasher_copy)) + hasher.update(MESSAGE) + +for x in midstates: + print(x + ',') + +for x in digests: + print(x + ',') +``` +*/ +static void run_sha256_counter_tests(void) { + static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; + static const secp256k1_sha256 midstates[] = { + {{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda}, + {0x00}, 0xfffc0}, + {{0xa0d29445, 0x9287de66, 0x76aabd71, 0x41acd765, 0x0c7528b4, 0x84e14906, 0x942faec6, 0xcc5a7b26}, + {0x00}, 0x1fffc0}, + {{0x50449526, 0xb9f1d657, 0xa0fc13e9, 0x50860f10, 0xa550c431, 0x3fbc97c1, 0x7bbb2d89, 0xdb67bac1}, + {0x00}, 0x3fffc0}, + {{0x54a6efdc, 0x46762e7b, 0x88bfe73f, 0xbbd149c7, 0x41620c43, 0x1168da7b, 0x2c5960f9, 0xeccffda6}, + {0x00}, 0x7fffc0}, + {{0x2515a8f5, 0x5faa2977, 0x3a850486, 0xac858cad, 0x7b7276ee, 0x235c0385, 0xc53a157c, 0x7cb3e69c}, + {0x00}, 0xffffc0}, + {{0x34f39828, 0x409fedb7, 0x4bbdd0fb, 0x3b643634, 0x7806bf2e, 0xe0d1b713, 0xca3f2e1e, 0xe38722c2}, + {0x00}, 0x1ffffc0}, + {{0x389ef5c5, 0x38c54167, 0x8f5d56ab, 0x582a75cc, 0x8217caef, 0xf10947dd, 0x6a1998a8, 0x048f0b8c}, + {0x00}, 0x3ffffc0}, + {{0xd6c3f394, 0x0bee43b9, 0x6783f497, 0x29fa9e21, 0x6ce491c1, 0xa81fe45e, 0x2fc3859a, 0x269012d0}, + {0x00}, 0x7ffffc0}, + {{0x6dd3c526, 0x44d88aa0, 0x806a1bae, 0xfbcc0d32, 0x9d6144f3, 0x9d2bd757, 0x9851a957, 0xb50430ad}, + {0x00}, 0xfffffc0}, + {{0x2add4021, 0xdfe8a9e6, 0xa56317c6, 0x7a15f5bb, 0x4a48aacd, 0x5d368414, 0x4f00e6f0, 0xd9355023}, + {0x00}, 0x1fffffc0}, + {{0xb66666b4, 0xdbeac32b, 0x0ea351ae, 0xcba9da46, 0x6278b874, 0x8c508e23, 0xe16ca776, 0x8465bac1}, + {0x00}, 0x3fffffc0}, + {{0xb6744789, 0x9cce87aa, 0xc4c478b7, 0xf38404d8, 0x2e38ba62, 0xa3f7019b, 0x50458fe7, 0x3047dbec}, + {0x00}, 0x7fffffc0}, + {{0x8b1297ba, 0xba261a80, 0x2ba1b0dd, 0xfbc67d6d, 0x61072c4e, 0x4b5a2a0f, 0x52872760, 0x2dfeb162}, + {0x00}, 0xffffffc0}, + {{0x24f33cf7, 0x41ad6583, 0x41c8ff5d, 0xca7ef35f, 0x50395756, 0x021b743e, 0xd7126cd7, 0xd037473a}, + {0x00}, 0x1ffffffc0}, + }; + static const unsigned char outputs[][32] = { + {0x0e, 0x83, 0xe2, 0xc9, 0x4f, 0xb2, 0xb8, 0x2b, 0x89, 0x06, 0x92, 0x78, 0x04, 0x03, 0x48, 0x5c, 0x48, 0x44, 0x67, 0x61, 0x77, 0xa4, 0xc7, 0x90, 0x9e, 0x92, 0x55, 0x10, 0x05, 0xfe, 0x39, 0x15}, + {0x1d, 0x1e, 0xd7, 0xb8, 0xa3, 0xa7, 0x8a, 0x79, 0xfd, 0xa0, 0x05, 0x08, 0x9c, 0xeb, 0xf0, 0xec, 0x67, 0x07, 0x9f, 0x8e, 0x3c, 0x0d, 0x8e, 0xf9, 0x75, 0x55, 0x13, 0xc1, 0xe8, 0x77, 0xf8, 0xbb}, + {0x66, 0x95, 0x6c, 0xc9, 0xe0, 0x39, 0x65, 0xb6, 0xb0, 0x05, 0xd1, 0xaf, 0xaf, 0xf3, 0x1d, 0xb9, 0xa4, 0xda, 0x6f, 0x20, 0xcd, 0x3a, 0xae, 0x64, 0xc2, 0xdb, 0xee, 0xf5, 0xb8, 0x8d, 0x57, 0x0e}, + {0x3c, 0xbb, 0x1c, 0x12, 0x5e, 0x17, 0xfd, 0x54, 0x90, 0x45, 0xa7, 0x7b, 0x61, 0x6c, 0x1d, 0xfe, 0xe6, 0xcc, 0x7f, 0xee, 0xcf, 0xef, 0x33, 0x35, 0x50, 0x62, 0x16, 0x70, 0x2f, 0x87, 0xc3, 0xc9}, + {0x53, 0x4d, 0xa8, 0xe7, 0x1e, 0x98, 0x73, 0x8d, 0xd9, 0xa3, 0x54, 0xa5, 0x0e, 0x59, 0x2c, 0x25, 0x43, 0x6f, 0xaa, 0xa2, 0xf5, 0x21, 0x06, 0x3e, 0xc9, 0x82, 0x06, 0x94, 0x98, 0x72, 0x9d, 0xa7}, + {0xef, 0x7e, 0xe9, 0x6b, 0xd3, 0xe5, 0xb7, 0x41, 0x4c, 0xc8, 0xd3, 0x07, 0x52, 0x9a, 0x5a, 0x8b, 0x4e, 0x1e, 0x75, 0xa4, 0x17, 0x78, 0xc8, 0x36, 0xcd, 0xf8, 0x2e, 0xd9, 0x57, 0xe3, 0xd7, 0x07}, + {0x87, 0x16, 0xfb, 0xf9, 0xa5, 0xf8, 0xc4, 0x56, 0x2b, 0x48, 0x52, 0x8e, 0x2d, 0x30, 0x85, 0xb6, 0x4c, 0x56, 0xb5, 0xd1, 0x16, 0x9c, 0xcf, 0x32, 0x95, 0xad, 0x03, 0xe8, 0x05, 0x58, 0x06, 0x76}, + {0x75, 0x03, 0x80, 0x28, 0xf2, 0xa7, 0x63, 0x22, 0x1a, 0x26, 0x9c, 0x68, 0xe0, 0x58, 0xfc, 0x73, 0xeb, 0x42, 0xf6, 0x86, 0x16, 0x24, 0x4b, 0xbc, 0x24, 0xf7, 0x02, 0xc8, 0x3d, 0x90, 0xe2, 0xb0}, + {0xdf, 0x49, 0x0f, 0x15, 0x7b, 0x7d, 0xbf, 0xe0, 0xd4, 0xcf, 0x47, 0xc0, 0x80, 0x93, 0x4a, 0x61, 0xaa, 0x03, 0x07, 0x66, 0xb3, 0x38, 0x5d, 0xc8, 0xc9, 0x07, 0x61, 0xfb, 0x97, 0x10, 0x2f, 0xd8}, + {0x77, 0x19, 0x40, 0x56, 0x41, 0xad, 0xbc, 0x59, 0xda, 0x1e, 0xc5, 0x37, 0x14, 0x63, 0x7b, 0xfb, 0x79, 0xe2, 0x7a, 0xb1, 0x55, 0x42, 0x99, 0x42, 0x56, 0xfe, 0x26, 0x9d, 0x0f, 0x7e, 0x80, 0xc6}, + {0x50, 0xe7, 0x2a, 0x0e, 0x26, 0x44, 0x2f, 0xe2, 0x55, 0x2d, 0xc3, 0x93, 0x8a, 0xc5, 0x86, 0x58, 0x22, 0x8c, 0x0c, 0xbf, 0xb1, 0xd2, 0xca, 0x87, 0x2a, 0xe4, 0x35, 0x26, 0x6f, 0xcd, 0x05, 0x5e}, + {0xe4, 0x80, 0x6f, 0xdb, 0x3d, 0x7d, 0xba, 0xde, 0x50, 0x3f, 0xea, 0x00, 0x3d, 0x46, 0x59, 0x64, 0xfd, 0x58, 0x1c, 0xa1, 0xb8, 0x7d, 0x5f, 0xac, 0x94, 0x37, 0x9e, 0xa0, 0xc0, 0x9c, 0x93, 0x8b}, + {0x2c, 0xf3, 0xa9, 0xf6, 0x15, 0x25, 0x80, 0x70, 0x76, 0x99, 0x7d, 0xf1, 0xc3, 0x2f, 0xa3, 0x31, 0xff, 0x92, 0x35, 0x2e, 0x8d, 0x04, 0x13, 0x33, 0xd8, 0x0d, 0xdb, 0x4a, 0xf6, 0x8c, 0x03, 0x34}, + {0xec, 0x12, 0x24, 0x9f, 0x35, 0xa4, 0x29, 0x8b, 0x9e, 0x4a, 0x95, 0xf8, 0x61, 0xaf, 0x61, 0xc5, 0x66, 0x55, 0x3e, 0x3f, 0x2a, 0x98, 0xea, 0x71, 0x16, 0x6b, 0x1c, 0xd9, 0xe4, 0x09, 0xd2, 0x8e}, + }; + unsigned int i; + for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) { + unsigned char out[32]; + secp256k1_sha256 hasher = midstates[i]; + secp256k1_sha256_write(&hasher, (const unsigned char*)input, strlen(input)); + secp256k1_sha256_finalize(&hasher, out); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); + } +} + +/* Tests for the equality of two sha256 structs. This function only produces a + * correct result if an integer multiple of 64 many bytes have been written + * into the hash functions. This function is used by some module tests. */ +static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) { + /* Is buffer fully consumed? */ + CHECK((sha1->bytes & 0x3F) == 0); + + CHECK(sha1->bytes == sha2->bytes); + CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); +} + +static void run_hmac_sha256_tests(void) { + static const char *keys[6] = { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "\x4a\x65\x66\x65", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + }; + static const char *inputs[6] = { + "\x48\x69\x20\x54\x68\x65\x72\x65", + "\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", + "\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74", + "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e" + }; + static const unsigned char outputs[6][32] = { + {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, + {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, + {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, + {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, + {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, + {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} + }; + int i; + for (i = 0; i < 6; i++) { + secp256k1_hmac_sha256 hasher; + unsigned char out[32]; + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + int split = testrand_int(strlen(inputs[i])); + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); + } + } +} + +static void run_rfc6979_hmac_sha256_tests(void) { + static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; + static const unsigned char out1[3][32] = { + {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, + {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a}, + {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e} + }; + + static const unsigned char key2[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; + static const unsigned char out2[3][32] = { + {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, + {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, + {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} + }; + + secp256k1_rfc6979_hmac_sha256 rng; + unsigned char out[32]; + int i; + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(secp256k1_memcmp_var(out, out1[i], 32) == 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(secp256k1_memcmp_var(out, out1[i], 32) != 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(secp256k1_memcmp_var(out, out2[i], 32) == 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); +} + +static void run_tagged_sha256_tests(void) { + unsigned char tag[32] = { 0 }; + unsigned char msg[32] = { 0 }; + unsigned char hash32[32]; + unsigned char hash_expected[32] = { + 0x04, 0x7A, 0x5E, 0x17, 0xB5, 0x86, 0x47, 0xC1, + 0x3C, 0xC6, 0xEB, 0xC0, 0xAA, 0x58, 0x3B, 0x62, + 0xFB, 0x16, 0x43, 0x32, 0x68, 0x77, 0x40, 0x6C, + 0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3 + }; + + /* API test */ + CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1); + CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, NULL, tag, sizeof(tag), msg, sizeof(msg))); + CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, NULL, 0, msg, sizeof(msg))); + CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), NULL, 0)); + + /* Static test vector */ + memcpy(tag, "tag", 3); + memcpy(msg, "msg", 3); + CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, 3, msg, 3) == 1); + CHECK(secp256k1_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0); +} + +/***** MODINV TESTS *****/ + +/* Compute the modular inverse of (odd) x mod 2^64. */ +static uint64_t modinv2p64(uint64_t x) { + /* If w = 1/x mod 2^(2^L), then w*(2 - w*x) = 1/x mod 2^(2^(L+1)). See + * Hacker's Delight second edition, Henry S. Warren, Jr., pages 245-247 for + * why. Start with L=0, for which it is true for every odd x that + * 1/x=1 mod 2. Iterating 6 times gives us 1/x mod 2^64. */ + int l; + uint64_t w = 1; + CHECK(x & 1); + for (l = 0; l < 6; ++l) w *= (2 - w*x); + return w; +} + + +/* compute out = (a*b) mod m; if b=NULL, treat b=1; if m=NULL, treat m=infinity. + * + * Out is a 512-bit number (represented as 32 uint16_t's in LE order). The other + * arguments are 256-bit numbers (represented as 16 uint16_t's in LE order). */ +static void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16_t* m) { + uint16_t mul[32]; + uint64_t c = 0; + int i, j; + int m_bitlen = 0; + int mul_bitlen = 0; + + if (b != NULL) { + /* Compute the product of a and b, and put it in mul. */ + for (i = 0; i < 32; ++i) { + for (j = i <= 15 ? 0 : i - 15; j <= i && j <= 15; j++) { + c += (uint64_t)a[j] * b[i - j]; + } + mul[i] = c & 0xFFFF; + c >>= 16; + } + CHECK(c == 0); + + /* compute the highest set bit in mul */ + for (i = 511; i >= 0; --i) { + if ((mul[i >> 4] >> (i & 15)) & 1) { + mul_bitlen = i; + break; + } + } + } else { + /* if b==NULL, set mul=a. */ + memcpy(mul, a, 32); + memset(mul + 16, 0, 32); + /* compute the highest set bit in mul */ + for (i = 255; i >= 0; --i) { + if ((mul[i >> 4] >> (i & 15)) & 1) { + mul_bitlen = i; + break; + } + } + } + + if (m) { + /* Compute the highest set bit in m. */ + for (i = 255; i >= 0; --i) { + if ((m[i >> 4] >> (i & 15)) & 1) { + m_bitlen = i; + break; + } + } + + /* Try do mul -= m<= 0; --i) { + uint16_t mul2[32]; + int64_t cs; + + /* Compute mul2 = mul - m<= 0 && bitpos < 256) { + sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p; + } + } + /* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */ + cs += mul[j]; + cs -= sub; + mul2[j] = (cs & 0xFFFF); + cs >>= 16; + } + /* If remainder of subtraction is 0, set mul = mul2. */ + if (cs == 0) { + memcpy(mul, mul2, sizeof(mul)); + } + } + /* Sanity check: test that all limbs higher than m's highest are zero */ + for (i = (m_bitlen >> 4) + 1; i < 32; ++i) { + CHECK(mul[i] == 0); + } + } + memcpy(out, mul, 32); +} + +/* Convert a 256-bit number represented as 16 uint16_t's to signed30 notation. */ +static void uint16_to_signed30(secp256k1_modinv32_signed30* out, const uint16_t* in) { + int i; + memset(out->v, 0, sizeof(out->v)); + for (i = 0; i < 256; ++i) { + out->v[i / 30] |= (int32_t)(((in[i >> 4]) >> (i & 15)) & 1) << (i % 30); + } +} + +/* Convert a 256-bit number in signed30 notation to a representation as 16 uint16_t's. */ +static void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) { + int i; + memset(out, 0, 32); + for (i = 0; i < 256; ++i) { + out[i >> 4] |= (((in->v[i / 30]) >> (i % 30)) & 1) << (i & 15); + } +} + +/* Randomly mutate the sign of limbs in signed30 representation, without changing the value. */ +static void mutate_sign_signed30(secp256k1_modinv32_signed30* x) { + int i; + for (i = 0; i < 16; ++i) { + int pos = testrand_bits(3); + if (x->v[pos] > 0 && x->v[pos + 1] <= 0x3fffffff) { + x->v[pos] -= 0x40000000; + x->v[pos + 1] += 1; + } else if (x->v[pos] < 0 && x->v[pos + 1] >= 0x3fffffff) { + x->v[pos] += 0x40000000; + x->v[pos + 1] -= 1; + } + } +} + +/* Test secp256k1_modinv32{_var}, using inputs in 16-bit limb format, and returning inverse. */ +static void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { + uint16_t tmp[16]; + secp256k1_modinv32_signed30 x; + secp256k1_modinv32_modinfo m; + int i, vartime, nonzero; + + uint16_to_signed30(&x, in); + nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4] | x.v[5] | x.v[6] | x.v[7] | x.v[8]) != 0; + uint16_to_signed30(&m.modulus, mod); + + /* compute 1/modulus mod 2^30 */ + m.modulus_inv30 = modinv2p64(m.modulus.v[0]) & 0x3fffffff; + CHECK(((m.modulus_inv30 * m.modulus.v[0]) & 0x3fffffff) == 1); + + /* Test secp256k1_jacobi32_maybe_var. */ + if (nonzero) { + int jac; + uint16_t sqr[16], negone[16]; + mulmod256(sqr, in, in, mod); + uint16_to_signed30(&x, sqr); + /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ + jac = secp256k1_jacobi32_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1); + /* Then compute the jacobi symbol of -(in^2). x and -x have opposite + * jacobi symbols if and only if (mod % 4) == 3. */ + negone[0] = mod[0] - 1; + for (i = 1; i < 16; ++i) negone[i] = mod[i]; + mulmod256(sqr, sqr, negone, mod); + uint16_to_signed30(&x, sqr); + jac = secp256k1_jacobi32_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); + } + + uint16_to_signed30(&x, in); + mutate_sign_signed30(&m.modulus); + for (vartime = 0; vartime < 2; ++vartime) { + /* compute inverse */ + (vartime ? secp256k1_modinv32_var : secp256k1_modinv32)(&x, &m); + + /* produce output */ + signed30_to_uint16(out, &x); + + /* check if the inverse times the input is 1 (mod m), unless x is 0. */ + mulmod256(tmp, out, in, mod); + CHECK(tmp[0] == nonzero); + for (i = 1; i < 16; ++i) CHECK(tmp[i] == 0); + + /* invert again */ + (vartime ? secp256k1_modinv32_var : secp256k1_modinv32)(&x, &m); + + /* check if the result is equal to the input */ + signed30_to_uint16(tmp, &x); + for (i = 0; i < 16; ++i) CHECK(tmp[i] == in[i]); + } +} + +#ifdef SECP256K1_WIDEMUL_INT128 +/* Convert a 256-bit number represented as 16 uint16_t's to signed62 notation. */ +static void uint16_to_signed62(secp256k1_modinv64_signed62* out, const uint16_t* in) { + int i; + memset(out->v, 0, sizeof(out->v)); + for (i = 0; i < 256; ++i) { + out->v[i / 62] |= (int64_t)(((in[i >> 4]) >> (i & 15)) & 1) << (i % 62); + } +} + +/* Convert a 256-bit number in signed62 notation to a representation as 16 uint16_t's. */ +static void signed62_to_uint16(uint16_t* out, const secp256k1_modinv64_signed62* in) { + int i; + memset(out, 0, 32); + for (i = 0; i < 256; ++i) { + out[i >> 4] |= (((in->v[i / 62]) >> (i % 62)) & 1) << (i & 15); + } +} + +/* Randomly mutate the sign of limbs in signed62 representation, without changing the value. */ +static void mutate_sign_signed62(secp256k1_modinv64_signed62* x) { + static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); + int i; + for (i = 0; i < 8; ++i) { + int pos = testrand_bits(2); + if (x->v[pos] > 0 && x->v[pos + 1] <= M62) { + x->v[pos] -= (M62 + 1); + x->v[pos + 1] += 1; + } else if (x->v[pos] < 0 && x->v[pos + 1] >= -M62) { + x->v[pos] += (M62 + 1); + x->v[pos + 1] -= 1; + } + } +} + +/* Test secp256k1_modinv64{_var}, using inputs in 16-bit limb format, and returning inverse. */ +static void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { + static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); + uint16_t tmp[16]; + secp256k1_modinv64_signed62 x; + secp256k1_modinv64_modinfo m; + int i, vartime, nonzero; + + uint16_to_signed62(&x, in); + nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4]) != 0; + uint16_to_signed62(&m.modulus, mod); + + /* compute 1/modulus mod 2^62 */ + m.modulus_inv62 = modinv2p64(m.modulus.v[0]) & M62; + CHECK(((m.modulus_inv62 * m.modulus.v[0]) & M62) == 1); + + /* Test secp256k1_jacobi64_maybe_var. */ + if (nonzero) { + int jac; + uint16_t sqr[16], negone[16]; + mulmod256(sqr, in, in, mod); + uint16_to_signed62(&x, sqr); + /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ + jac = secp256k1_jacobi64_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1); + /* Then compute the jacobi symbol of -(in^2). x and -x have opposite + * jacobi symbols if and only if (mod % 4) == 3. */ + negone[0] = mod[0] - 1; + for (i = 1; i < 16; ++i) negone[i] = mod[i]; + mulmod256(sqr, sqr, negone, mod); + uint16_to_signed62(&x, sqr); + jac = secp256k1_jacobi64_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); + } + + uint16_to_signed62(&x, in); + mutate_sign_signed62(&m.modulus); + for (vartime = 0; vartime < 2; ++vartime) { + /* compute inverse */ + (vartime ? secp256k1_modinv64_var : secp256k1_modinv64)(&x, &m); + + /* produce output */ + signed62_to_uint16(out, &x); + + /* check if the inverse times the input is 1 (mod m), unless x is 0. */ + mulmod256(tmp, out, in, mod); + CHECK(tmp[0] == nonzero); + for (i = 1; i < 16; ++i) CHECK(tmp[i] == 0); + + /* invert again */ + (vartime ? secp256k1_modinv64_var : secp256k1_modinv64)(&x, &m); + + /* check if the result is equal to the input */ + signed62_to_uint16(tmp, &x); + for (i = 0; i < 16; ++i) CHECK(tmp[i] == in[i]); + } +} +#endif + +/* test if a and b are coprime */ +static int coprime(const uint16_t* a, const uint16_t* b) { + uint16_t x[16], y[16], t[16]; + int i; + int iszero; + memcpy(x, a, 32); + memcpy(y, b, 32); + + /* simple gcd loop: while x!=0, (x,y)=(y%x,x) */ + while (1) { + iszero = 1; + for (i = 0; i < 16; ++i) { + if (x[i] != 0) { + iszero = 0; + break; + } + } + if (iszero) break; + mulmod256(t, y, NULL, x); + memcpy(y, x, 32); + memcpy(x, t, 32); + } + + /* return whether y=1 */ + if (y[0] != 1) return 0; + for (i = 1; i < 16; ++i) { + if (y[i] != 0) return 0; + } + return 1; +} + +static void run_modinv_tests(void) { + /* Fixed test cases. Each tuple is (input, modulus, output), each as 16x16 bits in LE order. */ + static const uint16_t CASES[][3][16] = { + /* Test cases triggering edge cases in divsteps */ + + /* Test case known to need 713 divsteps */ + {{0x1513, 0x5389, 0x54e9, 0x2798, 0x1957, 0x66a0, 0x8057, 0x3477, + 0x7784, 0x1052, 0x326a, 0x9331, 0x6506, 0xa95c, 0x91f3, 0xfb5e}, + {0x2bdd, 0x8df4, 0xcc61, 0x481f, 0xdae5, 0x5ca7, 0xf43b, 0x7d54, + 0x13d6, 0x469b, 0x2294, 0x20f4, 0xb2a4, 0xa2d1, 0x3ff1, 0xfd4b}, + {0xffd8, 0xd9a0, 0x456e, 0x81bb, 0xbabd, 0x6cea, 0x6dbd, 0x73ab, + 0xbb94, 0x3d3c, 0xdf08, 0x31c4, 0x3e32, 0xc179, 0x2486, 0xb86b}}, + /* Test case known to need 589 divsteps, reaching delta=-140 and + delta=141. */ + {{0x3fb1, 0x903b, 0x4eb7, 0x4813, 0xd863, 0x26bf, 0xd89f, 0xa8a9, + 0x02fe, 0x57c6, 0x554a, 0x4eab, 0x165e, 0x3d61, 0xee1e, 0x456c}, + {0x9295, 0x823b, 0x5c1f, 0x5386, 0x48e0, 0x02ff, 0x4c2a, 0xa2da, + 0xe58f, 0x967c, 0xc97e, 0x3f5a, 0x69fb, 0x52d9, 0x0a86, 0xb4a3}, + {0x3d30, 0xb893, 0xa809, 0xa7a8, 0x26f5, 0x5b42, 0x55be, 0xf4d0, + 0x12c2, 0x7e6a, 0xe41a, 0x90c7, 0xebfa, 0xf920, 0x304e, 0x1419}}, + /* Test case known to need 650 divsteps, and doing 65 consecutive (f,g/2) steps. */ + {{0x8583, 0x5058, 0xbeae, 0xeb69, 0x48bc, 0x52bb, 0x6a9d, 0xcc94, + 0x2a21, 0x87d5, 0x5b0d, 0x42f6, 0x5b8a, 0x2214, 0xe9d6, 0xa040}, + {0x7531, 0x27cb, 0x7e53, 0xb739, 0x6a5f, 0x83f5, 0xa45c, 0xcb1d, + 0x8a87, 0x1c9c, 0x51d7, 0x851c, 0xb9d8, 0x1fbe, 0xc241, 0xd4a3}, + {0xcdb4, 0x275c, 0x7d22, 0xa906, 0x0173, 0xc054, 0x7fdf, 0x5005, + 0x7fb8, 0x9059, 0xdf51, 0x99df, 0x2654, 0x8f6e, 0x070f, 0xb347}}, + /* example needing 713 divsteps; delta=-2..3 */ + {{0xe2e9, 0xee91, 0x4345, 0xe5ad, 0xf3ec, 0x8f42, 0x0364, 0xd5c9, + 0xff49, 0xbef5, 0x4544, 0x4c7c, 0xae4b, 0xfd9d, 0xb35b, 0xda9d}, + {0x36e7, 0x8cca, 0x2ed0, 0x47b3, 0xaca4, 0xb374, 0x7d2a, 0x0772, + 0x6bdb, 0xe0a7, 0x900b, 0xfe10, 0x788c, 0x6f22, 0xd909, 0xf298}, + {0xd8c6, 0xba39, 0x13ed, 0x198c, 0x16c8, 0xb837, 0xa5f2, 0x9797, + 0x0113, 0x882a, 0x15b5, 0x324c, 0xabee, 0xe465, 0x8170, 0x85ac}}, + /* example needing 713 divsteps; delta=-2..3 */ + {{0xd5b7, 0x2966, 0x040e, 0xf59a, 0x0387, 0xd96d, 0xbfbc, 0xd850, + 0x2d96, 0x872a, 0xad81, 0xc03c, 0xbb39, 0xb7fa, 0xd904, 0xef78}, + {0x6279, 0x4314, 0xfdd3, 0x1568, 0x0982, 0x4d13, 0x625f, 0x010c, + 0x22b1, 0x0cc3, 0xf22d, 0x5710, 0x1109, 0x5751, 0x7714, 0xfcf2}, + {0xdb13, 0x5817, 0x232e, 0xe456, 0xbbbc, 0x6fbe, 0x4572, 0xa358, + 0xc76d, 0x928e, 0x0162, 0x5314, 0x8325, 0x5683, 0xe21b, 0xda88}}, + /* example needing 713 divsteps; delta=-2..3 */ + {{0xa06f, 0x71ee, 0x3bac, 0x9ebb, 0xdeaa, 0x09ed, 0x1cf7, 0x9ec9, + 0x7158, 0x8b72, 0x5d53, 0x5479, 0x5c75, 0xbb66, 0x9125, 0xeccc}, + {0x2941, 0xd46c, 0x3cd4, 0x4a9d, 0x5c4a, 0x256b, 0xbd6c, 0x9b8e, + 0x8fe0, 0x8a14, 0xffe8, 0x2496, 0x618d, 0xa9d7, 0x5018, 0xfb29}, + {0x437c, 0xbd60, 0x7590, 0x94bb, 0x0095, 0xd35e, 0xd4fe, 0xd6da, + 0x0d4e, 0x5342, 0x4cd2, 0x169b, 0x661c, 0x1380, 0xed2d, 0x85c1}}, + /* example reaching delta=-64..65; 661 divsteps */ + {{0xfde4, 0x68d6, 0x6c48, 0x7f77, 0x1c78, 0x96de, 0x2fd9, 0xa6c2, + 0xbbb5, 0xd319, 0x69cf, 0xd4b3, 0xa321, 0xcda0, 0x172e, 0xe530}, + {0xd9e3, 0x0f60, 0x3d86, 0xeeab, 0x25ee, 0x9582, 0x2d50, 0xfe16, + 0xd4e2, 0xe3ba, 0x94e2, 0x9833, 0x6c5e, 0x8982, 0x13b6, 0xe598}, + {0xe675, 0xf55a, 0x10f6, 0xabde, 0x5113, 0xecaa, 0x61ae, 0xad9f, + 0x0c27, 0xef33, 0x62e5, 0x211d, 0x08fa, 0xa78d, 0xc675, 0x8bae}}, + /* example reaching delta=-64..65; 661 divsteps */ + {{0x21bf, 0x52d5, 0x8fd4, 0xaa18, 0x156a, 0x7247, 0xebb8, 0x5717, + 0x4eb5, 0x1421, 0xb58f, 0x3b0b, 0x5dff, 0xe533, 0xb369, 0xd28a}, + {0x9f6b, 0xe463, 0x2563, 0xc74d, 0x6d81, 0x636a, 0x8fc8, 0x7a94, + 0x9429, 0x1585, 0xf35e, 0x7ff5, 0xb64f, 0x9720, 0xba74, 0xe108}, + {0xa5ab, 0xea7b, 0xfe5e, 0x8a85, 0x13be, 0x7934, 0xe8a0, 0xa187, + 0x86b5, 0xe477, 0xb9a4, 0x75d7, 0x538f, 0xdd70, 0xc781, 0xb67d}}, + /* example reaching delta=-64..65; 661 divsteps */ + {{0xa41a, 0x3e8d, 0xf1f5, 0x9493, 0x868c, 0x5103, 0x2725, 0x3ceb, + 0x6032, 0x3624, 0xdc6b, 0x9120, 0xbf4c, 0x8821, 0x91ad, 0xb31a}, + {0x5c0b, 0xdda5, 0x20f8, 0x32a1, 0xaf73, 0x6ec5, 0x4779, 0x43d6, + 0xd454, 0x9573, 0xbf84, 0x5a58, 0xe04e, 0x307e, 0xd1d5, 0xe230}, + {0xda15, 0xbcd6, 0x7180, 0xabd3, 0x04e6, 0x6986, 0xc0d7, 0x90bb, + 0x3a4d, 0x7c95, 0xaaab, 0x9ab3, 0xda34, 0xa7f6, 0x9636, 0x6273}}, + /* example doing 123 consecutive (f,g/2) steps; 615 divsteps */ + {{0xb4d6, 0xb38f, 0x00aa, 0xebda, 0xd4c2, 0x70b8, 0x9dad, 0x58ee, + 0x68f8, 0x48d3, 0xb5ff, 0xf422, 0x9e46, 0x2437, 0x18d0, 0xd9cc}, + {0x5c83, 0xfed7, 0x97f5, 0x3f07, 0xcaad, 0x95b1, 0xb4a4, 0xb005, + 0x23af, 0xdd27, 0x6c0d, 0x932c, 0xe2b2, 0xe3ae, 0xfb96, 0xdf67}, + {0x3105, 0x0127, 0xfd48, 0x039b, 0x35f1, 0xbc6f, 0x6c0a, 0xb572, + 0xe4df, 0xebad, 0x8edc, 0xb89d, 0x9555, 0x4c26, 0x1fef, 0x997c}}, + /* example doing 123 consecutive (f,g/2) steps; 614 divsteps */ + {{0x5138, 0xd474, 0x385f, 0xc964, 0x00f2, 0x6df7, 0x862d, 0xb185, + 0xb264, 0xe9e1, 0x466c, 0xf39e, 0xafaf, 0x5f41, 0x47e2, 0xc89d}, + {0x8607, 0x9c81, 0x46a2, 0x7dcc, 0xcb0c, 0x9325, 0xe149, 0x2bde, + 0x6632, 0x2869, 0xa261, 0xb163, 0xccee, 0x22ae, 0x91e0, 0xcfd5}, + {0x831c, 0xda22, 0xb080, 0xba7a, 0x26e2, 0x54b0, 0x073b, 0x5ea0, + 0xed4b, 0xcb3d, 0xbba1, 0xbec8, 0xf2ad, 0xae0d, 0x349b, 0x17d1}}, + /* example doing 123 consecutive (f,g/2) steps; 614 divsteps */ + {{0xe9a5, 0xb4ad, 0xd995, 0x9953, 0xcdff, 0x50d7, 0xf715, 0x9dc7, + 0x3e28, 0x15a9, 0x95a3, 0x8554, 0x5b5e, 0xad1d, 0x6d57, 0x3d50}, + {0x3ad9, 0xbd60, 0x5cc7, 0x6b91, 0xadeb, 0x71f6, 0x7cc4, 0xa58a, + 0x2cce, 0xf17c, 0x38c9, 0x97ed, 0x65fb, 0x3fa6, 0xa6bc, 0xeb24}, + {0xf96c, 0x1963, 0x8151, 0xa0cc, 0x299b, 0xf277, 0x001a, 0x16bb, + 0xfd2e, 0x532d, 0x0410, 0xe117, 0x6b00, 0x44ec, 0xca6a, 0x1745}}, + /* example doing 446 (f,g/2) steps; 523 divsteps */ + {{0x3758, 0xa56c, 0xe41e, 0x4e47, 0x0975, 0xa82b, 0x107c, 0x89cf, + 0x2093, 0x5a0c, 0xda37, 0xe007, 0x6074, 0x4f68, 0x2f5a, 0xbb8a}, + {0x4beb, 0xa40f, 0x2c42, 0xd9d6, 0x97e8, 0xca7c, 0xd395, 0x894f, + 0x1f50, 0x8067, 0xa233, 0xb850, 0x1746, 0x1706, 0xbcda, 0xdf32}, + {0x762a, 0xceda, 0x4c45, 0x1ca0, 0x8c37, 0xd8c5, 0xef57, 0x7a2c, + 0x6e98, 0xe38a, 0xc50e, 0x2ca9, 0xcb85, 0x24d5, 0xc29c, 0x61f6}}, + /* example doing 446 (f,g/2) steps; 523 divsteps */ + {{0x6f38, 0x74ad, 0x7332, 0x4073, 0x6521, 0xb876, 0xa370, 0xa6bd, + 0xcea5, 0xbd06, 0x969f, 0x77c6, 0x1e69, 0x7c49, 0x7d51, 0xb6e7}, + {0x3f27, 0x4be4, 0xd81e, 0x1396, 0xb21f, 0x92aa, 0x6dc3, 0x6283, + 0x6ada, 0x3ca2, 0xc1e5, 0x8b9b, 0xd705, 0x5598, 0x8ba1, 0xe087}, + {0x6a22, 0xe834, 0xbc8d, 0xcee9, 0x42fc, 0xfc77, 0x9c45, 0x1ca8, + 0xeb66, 0xed74, 0xaaf9, 0xe75f, 0xfe77, 0x46d2, 0x179b, 0xbf3e}}, + /* example doing 336 (f,(f+g)/2) steps; 693 divsteps */ + {{0x7ea7, 0x444e, 0x84ea, 0xc447, 0x7c1f, 0xab97, 0x3de6, 0x5878, + 0x4e8b, 0xc017, 0x03e0, 0xdc40, 0xbbd0, 0x74ce, 0x0169, 0x7ab5}, + {0x4023, 0x154f, 0xfbe4, 0x8195, 0xfda0, 0xef54, 0x9e9a, 0xc703, + 0x2803, 0xf760, 0x6302, 0xed5b, 0x7157, 0x6456, 0xdd7d, 0xf14b}, + {0xb6fb, 0xe3b3, 0x0733, 0xa77e, 0x44c5, 0x3003, 0xc937, 0xdd4d, + 0x5355, 0x14e9, 0x184e, 0xcefe, 0xe6b5, 0xf2e0, 0x0a28, 0x5b74}}, + /* example doing 336 (f,(f+g)/2) steps; 687 divsteps */ + {{0xa893, 0xb5f4, 0x1ede, 0xa316, 0x242c, 0xbdcc, 0xb017, 0x0836, + 0x3a37, 0x27fb, 0xfb85, 0x251e, 0xa189, 0xb15d, 0xa4b8, 0xc24c}, + {0xb0b7, 0x57ba, 0xbb6d, 0x9177, 0xc896, 0xc7f2, 0x43b4, 0x85a6, + 0xe6c4, 0xe50e, 0x3109, 0x7ca5, 0xd73d, 0x13ff, 0x0c3d, 0xcd62}, + {0x48ca, 0xdb34, 0xe347, 0x2cef, 0x4466, 0x10fb, 0x7ee1, 0x6344, + 0x4308, 0x966d, 0xd4d1, 0xb099, 0x994f, 0xd025, 0x2187, 0x5866}}, + /* example doing 267 (g,(g-f)/2) steps; 678 divsteps */ + {{0x0775, 0x1754, 0x01f6, 0xdf37, 0xc0be, 0x8197, 0x072f, 0x6cf5, + 0x8b36, 0x8069, 0x5590, 0xb92d, 0x6084, 0x47a4, 0x23fe, 0xddd5}, + {0x8e1b, 0xda37, 0x27d9, 0x312e, 0x3a2f, 0xef6d, 0xd9eb, 0x8153, + 0xdcba, 0x9fa3, 0x9f80, 0xead5, 0x134d, 0x2ebb, 0x5ec0, 0xe032}, + {0x1cb6, 0x5a61, 0x1bed, 0x77d6, 0xd5d1, 0x7498, 0xef33, 0x2dd2, + 0x1089, 0xedbd, 0x6958, 0x16ae, 0x336c, 0x45e6, 0x4361, 0xbadc}}, + /* example doing 267 (g,(g-f)/2) steps; 676 divsteps */ + {{0x0207, 0xf948, 0xc430, 0xf36b, 0xf0a7, 0x5d36, 0x751f, 0x132c, + 0x6f25, 0xa630, 0xca1f, 0xc967, 0xaf9c, 0x34e7, 0xa38f, 0xbe9f}, + {0x5fb9, 0x7321, 0x6561, 0x5fed, 0x54ec, 0x9c3a, 0xee0e, 0x6717, + 0x49af, 0xb896, 0xf4f5, 0x451c, 0x722a, 0xf116, 0x64a9, 0xcf0b}, + {0xf4d7, 0xdb47, 0xfef2, 0x4806, 0x4cb8, 0x18c7, 0xd9a7, 0x4951, + 0x14d8, 0x5c3a, 0xd22d, 0xd7b2, 0x750c, 0x3de7, 0x8b4a, 0x19aa}}, + + /* Test cases triggering edge cases in divsteps variant starting with delta=1/2 */ + + /* example needing 590 divsteps; delta=-5/2..7/2 */ + {{0x9118, 0xb640, 0x53d7, 0x30ab, 0x2a23, 0xd907, 0x9323, 0x5b3a, + 0xb6d4, 0x538a, 0x7637, 0xfe97, 0xfd05, 0x3cc0, 0x453a, 0xfb7e}, + {0x6983, 0x4f75, 0x4ad1, 0x48ad, 0xb2d9, 0x521d, 0x3dbc, 0x9cc0, + 0x4b60, 0x0ac6, 0xd3be, 0x0fb6, 0xd305, 0x3895, 0x2da5, 0xfdf8}, + {0xcec1, 0x33ac, 0xa801, 0x8194, 0xe36c, 0x65ef, 0x103b, 0xca54, + 0xfa9b, 0xb41d, 0x9b52, 0xb6f7, 0xa611, 0x84aa, 0x3493, 0xbf54}}, + /* example needing 590 divsteps; delta=-3/2..5/2 */ + {{0xb5f2, 0x42d0, 0x35e8, 0x8ca0, 0x4b62, 0x6e1d, 0xbdf3, 0x890e, + 0x8c82, 0x23d8, 0xc79a, 0xc8e8, 0x789e, 0x353d, 0x9766, 0xea9d}, + {0x6fa1, 0xacba, 0x4b7a, 0x5de1, 0x95d0, 0xc845, 0xebbf, 0x6f5a, + 0x30cf, 0x52db, 0x69b7, 0xe278, 0x4b15, 0x8411, 0x2ab2, 0xf3e7}, + {0xf12c, 0x9d6d, 0x95fa, 0x1878, 0x9f13, 0x4fb5, 0x3c8b, 0xa451, + 0x7182, 0xc4b6, 0x7e2a, 0x7bb7, 0x6e0e, 0x5b68, 0xde55, 0x9927}}, + /* example needing 590 divsteps; delta=-3/2..5/2 */ + {{0x229c, 0x4ef8, 0x1e93, 0xe5dc, 0xcde5, 0x6d62, 0x263b, 0xad11, + 0xced0, 0x88ff, 0xae8e, 0x3183, 0x11d2, 0xa50b, 0x350d, 0xeb40}, + {0x3157, 0xe2ea, 0x8a02, 0x0aa3, 0x5ae1, 0xb26c, 0xea27, 0x6805, + 0x87e2, 0x9461, 0x37c1, 0x2f8d, 0x85d2, 0x77a8, 0xf805, 0xeec9}, + {0x6f4e, 0x2748, 0xf7e5, 0xd8d3, 0xabe2, 0x7270, 0xc4e0, 0xedc7, + 0xf196, 0x78ca, 0x9139, 0xd8af, 0x72c6, 0xaf2f, 0x85d2, 0x6cd3}}, + /* example needing 590 divsteps; delta=-5/2..7/2 */ + {{0xdce8, 0xf1fe, 0x6708, 0x021e, 0xf1ca, 0xd609, 0x5443, 0x85ce, + 0x7a05, 0x8f9c, 0x90c3, 0x52e7, 0x8e1d, 0x97b8, 0xc0bf, 0xf2a1}, + {0xbd3d, 0xed11, 0x1625, 0xb4c5, 0x844c, 0xa413, 0x2569, 0xb9ba, + 0xcd35, 0xff84, 0xcd6e, 0x7f0b, 0x7d5d, 0x10df, 0x3efe, 0xfbe5}, + {0xa9dd, 0xafef, 0xb1b7, 0x4c8d, 0x50e4, 0xafbf, 0x2d5a, 0xb27c, + 0x0653, 0x66b6, 0x5d36, 0x4694, 0x7e35, 0xc47c, 0x857f, 0x32c5}}, + /* example needing 590 divsteps; delta=-3/2..5/2 */ + {{0x7902, 0xc9f8, 0x926b, 0xaaeb, 0x90f8, 0x1c89, 0xcce3, 0x96b7, + 0x28b2, 0x87a2, 0x136d, 0x695a, 0xa8df, 0x9061, 0x9e31, 0xee82}, + {0xd3a9, 0x3c02, 0x818c, 0x6b81, 0x34b3, 0xebbb, 0xe2c8, 0x7712, + 0xbfd6, 0x8248, 0xa6f4, 0xba6f, 0x03bb, 0xfb54, 0x7575, 0xfe89}, + {0x8246, 0x0d63, 0x478e, 0xf946, 0xf393, 0x0451, 0x08c2, 0x5919, + 0x5fd6, 0x4c61, 0xbeb7, 0x9a15, 0x30e1, 0x55fc, 0x6a01, 0x3724}}, + /* example reaching delta=-127/2..129/2; 571 divsteps */ + {{0x3eff, 0x926a, 0x77f5, 0x1fff, 0x1a5b, 0xf3ef, 0xf64b, 0x8681, + 0xf800, 0xf9bc, 0x761d, 0xe268, 0x62b0, 0xa032, 0xba9c, 0xbe56}, + {0xb8f9, 0x00e7, 0x47b7, 0xdffc, 0xfd9d, 0x5abb, 0xa19b, 0x1868, + 0x31fd, 0x3b29, 0x3674, 0x5449, 0xf54d, 0x1d19, 0x6ac7, 0xff6f}, + {0xf1d7, 0x3551, 0x5682, 0x9adf, 0xe8aa, 0x19a5, 0x8340, 0x71db, + 0xb7ab, 0x4cfd, 0xf661, 0x632c, 0xc27e, 0xd3c6, 0xdf42, 0xd306}}, + /* example reaching delta=-127/2..129/2; 571 divsteps */ + {{0x0000, 0x0000, 0x0000, 0x0000, 0x3aff, 0x2ed7, 0xf2e0, 0xabc7, + 0x8aee, 0x166e, 0x7ed0, 0x9ac7, 0x714a, 0xb9c5, 0x4d58, 0xad6c}, + {0x9cf9, 0x47e2, 0xa421, 0xb277, 0xffc2, 0x2747, 0x6486, 0x94c1, + 0x1d99, 0xd49b, 0x1096, 0x991a, 0xe986, 0xae02, 0xe89b, 0xea36}, + {0x1fb4, 0x98d8, 0x19b7, 0x80e9, 0xcdac, 0xaa5a, 0xf1e6, 0x0074, + 0xe393, 0xed8b, 0x8d5c, 0xe17d, 0x81b3, 0xc16d, 0x54d3, 0x9be3}}, + /* example reaching delta=-127/2..129/2; 571 divsteps */ + {{0xd047, 0x7e36, 0x3157, 0x7ab6, 0xb4d9, 0x8dae, 0x7534, 0x4f5d, + 0x489e, 0xa8ab, 0x8a3d, 0xd52c, 0x62af, 0xa032, 0xba9c, 0xbe56}, + {0xb1f1, 0x737f, 0x5964, 0x5afb, 0x3712, 0x8ef9, 0x19f7, 0x9669, + 0x664d, 0x03ad, 0xc352, 0xf7a5, 0xf545, 0x1d19, 0x6ac7, 0xff6f}, + {0xa834, 0x5256, 0x27bc, 0x33bd, 0xba11, 0x5a7b, 0x791e, 0xe6c0, + 0x9ac4, 0x9370, 0x1130, 0x28b4, 0x2b2e, 0x231b, 0x082a, 0x796e}}, + /* example doing 123 consecutive (f,g/2) steps; 554 divsteps */ + {{0x6ab1, 0x6ea0, 0x1a99, 0xe0c2, 0xdd45, 0x645d, 0x8dbc, 0x466a, + 0xfa64, 0x4289, 0xd3f7, 0xfc8f, 0x2894, 0xe3c5, 0xa008, 0xcc14}, + {0xc75f, 0xc083, 0x4cc2, 0x64f2, 0x2aff, 0x4c12, 0x8461, 0xc4ae, + 0xbbfa, 0xb336, 0xe4b2, 0x3ac5, 0x2c22, 0xf56c, 0x5381, 0xe943}, + {0xcd80, 0x760d, 0x4395, 0xb3a6, 0xd497, 0xf583, 0x82bd, 0x1daa, + 0xbe92, 0x2613, 0xfdfb, 0x869b, 0x0425, 0xa333, 0x7056, 0xc9c5}}, + /* example doing 123 consecutive (f,g/2) steps; 554 divsteps */ + {{0x71d4, 0x64df, 0xec4f, 0x74d8, 0x7e0c, 0x40d3, 0x7073, 0x4cc8, + 0x2a2a, 0xb1ff, 0x8518, 0x6513, 0xb0ea, 0x640a, 0x62d9, 0xd5f4}, + {0xdc75, 0xd937, 0x3b13, 0x1d36, 0xdf83, 0xd034, 0x1c1c, 0x4332, + 0x4cc3, 0xeeec, 0x7d94, 0x6771, 0x3384, 0x74b0, 0x947d, 0xf2c4}, + {0x0a82, 0x37a4, 0x12d5, 0xec97, 0x972c, 0xe6bf, 0xc348, 0xa0a9, + 0xc50c, 0xdc7c, 0xae30, 0x19d1, 0x0fca, 0x35e1, 0xd6f6, 0x81ee}}, + /* example doing 123 consecutive (f,g/2) steps; 554 divsteps */ + {{0xa6b1, 0xabc5, 0x5bbc, 0x7f65, 0xdd32, 0xaa73, 0xf5a3, 0x1982, + 0xced4, 0xe949, 0x0fd6, 0x2bc4, 0x2bd7, 0xe3c5, 0xa008, 0xcc14}, + {0x4b5f, 0x8f96, 0xa375, 0xfbcf, 0x1c7d, 0xf1ec, 0x03f5, 0xb35d, + 0xb999, 0xdb1f, 0xc9a1, 0xb4c7, 0x1dd5, 0xf56c, 0x5381, 0xe943}, + {0xaa3d, 0x38b9, 0xf17d, 0xeed9, 0x9988, 0x69ee, 0xeb88, 0x1495, + 0x203f, 0x18c8, 0x82b7, 0xdcb2, 0x34a7, 0x6b00, 0x6998, 0x589a}}, + /* example doing 453 (f,g/2) steps; 514 divsteps */ + {{0xa478, 0xe60d, 0x3244, 0x60e6, 0xada3, 0xfe50, 0xb6b1, 0x2eae, + 0xd0ef, 0xa7b1, 0xef63, 0x05c0, 0xe213, 0x443e, 0x4427, 0x2448}, + {0x258f, 0xf9ef, 0xe02b, 0x92dd, 0xd7f3, 0x252b, 0xa503, 0x9089, + 0xedff, 0x96c1, 0xfe3a, 0x3a39, 0x198a, 0x981d, 0x0627, 0xedb7}, + {0x595a, 0x45be, 0x8fb0, 0x2265, 0xc210, 0x02b8, 0xdce9, 0xe241, + 0xcab6, 0xbf0d, 0x0049, 0x8d9a, 0x2f51, 0xae54, 0x5785, 0xb411}}, + /* example doing 453 (f,g/2) steps; 514 divsteps */ + {{0x48f0, 0x7db3, 0xdafe, 0x1c92, 0x5912, 0xe11a, 0xab52, 0xede1, + 0x3182, 0x8980, 0x5d2b, 0x9b5b, 0x8718, 0xda27, 0x1683, 0x1de2}, + {0x168f, 0x6f36, 0xce7a, 0xf435, 0x19d4, 0xda5e, 0x2351, 0x9af5, + 0xb003, 0x0ef5, 0x3b4c, 0xecec, 0xa9f0, 0x78e1, 0xdfef, 0xe823}, + {0x5f55, 0xfdcc, 0xb233, 0x2914, 0x84f0, 0x97d1, 0x9cf4, 0x2159, + 0xbf56, 0xb79c, 0x17a3, 0x7cef, 0xd5de, 0x34f0, 0x5311, 0x4c54}}, + /* example doing 510 (f,(f+g)/2) steps; 512 divsteps */ + {{0x2789, 0x2e04, 0x6e0e, 0xb6cd, 0xe4de, 0x4dbf, 0x228d, 0x7877, + 0xc335, 0x806b, 0x38cd, 0x8049, 0xa73b, 0xcfa2, 0x82f7, 0x9e19}, + {0xc08d, 0xb99d, 0xb8f3, 0x663d, 0xbbb3, 0x1284, 0x1485, 0x1d49, + 0xc98f, 0x9e78, 0x1588, 0x11e3, 0xd91a, 0xa2c7, 0xfff1, 0xc7b9}, + {0x1e1f, 0x411d, 0x7c49, 0x0d03, 0xe789, 0x2f8e, 0x5d55, 0xa95e, + 0x826e, 0x8de5, 0x52a0, 0x1abc, 0x4cd7, 0xd13a, 0x4395, 0x63e1}}, + /* example doing 510 (f,(f+g)/2) steps; 512 divsteps */ + {{0xd5a1, 0xf786, 0x555c, 0xb14b, 0x44ae, 0x535f, 0x4a49, 0xffc3, + 0xf497, 0x70d1, 0x57c8, 0xa933, 0xc85a, 0x1910, 0x75bf, 0x960b}, + {0xfe53, 0x5058, 0x496d, 0xfdff, 0x6fb8, 0x4100, 0x92bd, 0xe0c4, + 0xda89, 0xe0a4, 0x841b, 0x43d4, 0xa388, 0x957f, 0x99ca, 0x9abf}, + {0xe530, 0x05bc, 0xfeec, 0xfc7e, 0xbcd3, 0x1239, 0x54cb, 0x7042, + 0xbccb, 0x139e, 0x9076, 0x0203, 0x6068, 0x90c7, 0x1ddf, 0x488d}}, + /* example doing 228 (g,(g-f)/2) steps; 538 divsteps */ + {{0x9488, 0xe54b, 0x0e43, 0x81d2, 0x06e7, 0x4b66, 0x36d0, 0x53d6, + 0x2b68, 0x22ec, 0x3fa9, 0xc1a7, 0x9ad2, 0xa596, 0xb3ac, 0xdf42}, + {0xe31f, 0x0b28, 0x5f3b, 0xc1ff, 0x344c, 0xbf5f, 0xd2ec, 0x2936, + 0x9995, 0xdeb2, 0xae6c, 0x2852, 0xa2c6, 0xb306, 0x8120, 0xe305}, + {0xa56e, 0xfb98, 0x1537, 0x4d85, 0x619e, 0x866c, 0x3cd4, 0x779a, + 0xdd66, 0xa80d, 0xdc2f, 0xcae4, 0xc74c, 0x5175, 0xa65d, 0x605e}}, + /* example doing 228 (g,(g-f)/2) steps; 537 divsteps */ + {{0x8cd5, 0x376d, 0xd01b, 0x7176, 0x19ef, 0xcf09, 0x8403, 0x5e52, + 0x83c1, 0x44de, 0xb91e, 0xb33d, 0xe15c, 0x51e7, 0xbad8, 0x6359}, + {0x3b75, 0xf812, 0x5f9e, 0xa04e, 0x92d3, 0x226e, 0x540e, 0x7c9a, + 0x31c6, 0x46d2, 0x0b7b, 0xdb4a, 0xe662, 0x4950, 0x0265, 0xf76f}, + {0x09ed, 0x692f, 0xe8f1, 0x3482, 0xab54, 0x36b4, 0x8442, 0x6ae9, + 0x4329, 0x6505, 0x183b, 0x1c1d, 0x482d, 0x7d63, 0xb44f, 0xcc09}}, + + /* Test cases with the group order as modulus. */ + + /* Test case with the group order as modulus, needing 635 divsteps. */ + {{0x95ed, 0x6c01, 0xd113, 0x5ff1, 0xd7d0, 0x29cc, 0x5817, 0x6120, + 0xca8e, 0xaad1, 0x25ae, 0x8e84, 0x9af6, 0x30bf, 0xf0ed, 0x1686}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x1631, 0xbf4a, 0x286a, 0x2716, 0x469f, 0x2ac8, 0x1312, 0xe9bc, + 0x04f4, 0x304b, 0x9931, 0x113b, 0xd932, 0xc8f4, 0x0d0d, 0x01a1}}, + /* example with group size as modulus needing 631 divsteps */ + {{0x85ed, 0xc284, 0x9608, 0x3c56, 0x19b6, 0xbb5b, 0x2850, 0xdab7, + 0xa7f5, 0xe9ab, 0x06a4, 0x5bbb, 0x1135, 0xa186, 0xc424, 0xc68b}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x8479, 0x450a, 0x8fa3, 0xde05, 0xb2f5, 0x7793, 0x7269, 0xbabb, + 0xc3b3, 0xd49b, 0x3377, 0x03c6, 0xe694, 0xc760, 0xd3cb, 0x2811}}, + /* example with group size as modulus needing 565 divsteps starting at delta=1/2 */ + {{0x8432, 0x5ceb, 0xa847, 0x6f1e, 0x51dd, 0x535a, 0x6ddc, 0x70ce, + 0x6e70, 0xc1f6, 0x18f2, 0x2a7e, 0xc8e7, 0x39f8, 0x7e96, 0xebbf}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x257e, 0x449f, 0x689f, 0x89aa, 0x3989, 0xb661, 0x376c, 0x1e32, + 0x654c, 0xee2e, 0xf4e2, 0x33c8, 0x3f2f, 0x9716, 0x6046, 0xcaa3}}, + /* Test case with the group size as modulus, needing 981 divsteps with + broken eta handling. */ + {{0xfeb9, 0xb877, 0xee41, 0x7fa3, 0x87da, 0x94c4, 0x9d04, 0xc5ae, + 0x5708, 0x0994, 0xfc79, 0x0916, 0xbf32, 0x3ad8, 0xe11c, 0x5ca2}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0f12, 0x075e, 0xce1c, 0x6f92, 0xc80f, 0xca92, 0x9a04, 0x6126, + 0x4b6c, 0x57d6, 0xca31, 0x97f3, 0x1f99, 0xf4fd, 0xda4d, 0x42ce}}, + /* Test case with the group size as modulus, input = 0. */ + {{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + /* Test case with the group size as modulus, input = 1. */ + {{0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + /* Test case with the group size as modulus, input = 2. */ + {{0x0002, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x20a1, 0x681b, 0x2f46, 0xdfe9, 0x501d, 0x57a4, 0x6e73, 0x5d57, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x7fff}}, + /* Test case with the group size as modulus, input = group - 1. */ + {{0x4140, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x4140, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}}, + + /* Test cases with the field size as modulus. */ + + /* Test case with the field size as modulus, needing 637 divsteps. */ + {{0x9ec3, 0x1919, 0xca84, 0x7c11, 0xf996, 0x06f3, 0x5408, 0x6688, + 0x1320, 0xdb8a, 0x632a, 0x0dcb, 0x8a84, 0x6bee, 0x9c95, 0xe34e}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x18e5, 0x19b6, 0xdf92, 0x1aaa, 0x09fb, 0x8a3f, 0x52b0, 0x8701, + 0xac0c, 0x2582, 0xda44, 0x9bcc, 0x6828, 0x1c53, 0xbd8f, 0xbd2c}}, + /* example with field size as modulus needing 637 divsteps */ + {{0xaec3, 0xa7cf, 0x2f2d, 0x0693, 0x5ad5, 0xa8ff, 0x7ec7, 0x30ff, + 0x0c8b, 0xc242, 0xcab2, 0x063a, 0xf86e, 0x6057, 0x9cbd, 0xf6d8}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0310, 0x579d, 0xcb38, 0x9030, 0x3ded, 0x9bb9, 0x1234, 0x63ce, + 0x0c63, 0x8e3d, 0xacfe, 0x3c20, 0xdc85, 0xf859, 0x919e, 0x1d45}}, + /* example with field size as modulus needing 564 divsteps starting at delta=1/2 */ + {{0x63ae, 0x8d10, 0x0071, 0xdb5c, 0xb454, 0x78d1, 0x744a, 0x5f8e, + 0xe4d8, 0x87b1, 0x8e62, 0x9590, 0xcede, 0xa070, 0x36b4, 0x7f6f}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0xfdc8, 0xe8d5, 0xbe15, 0x9f86, 0xa5fe, 0xf18e, 0xa7ff, 0xd291, + 0xf4c2, 0x9c87, 0xf150, 0x073e, 0x69b8, 0xf7c4, 0xee4b, 0xc7e6}}, + /* Test case with the field size as modulus, needing 935 divsteps with + broken eta handling. */ + {{0x1b37, 0xbdc3, 0x8bcd, 0x25e3, 0x1eae, 0x567d, 0x30b6, 0xf0d8, + 0x9277, 0x0cf8, 0x9c2e, 0xecd7, 0x631d, 0xe38f, 0xd4f8, 0x5c93}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x1622, 0xe05b, 0xe880, 0x7de9, 0x3e45, 0xb682, 0xee6c, 0x67ed, + 0xa179, 0x15db, 0x6b0d, 0xa656, 0x7ccb, 0x8ef7, 0xa2ff, 0xe279}}, + /* Test case with the field size as modulus, input = 0. */ + {{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + /* Test case with the field size as modulus, input = 1. */ + {{0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + /* Test case with the field size as modulus, input = 2. */ + {{0x0002, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0xfe18, 0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x7fff}}, + /* Test case with the field size as modulus, input = field - 1. */ + {{0xfc2e, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0xfc2e, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}}, + + /* Selected from a large number of random inputs to reach small/large + * d/e values in various configurations. */ + {{0x3a08, 0x23e1, 0x4d8c, 0xe606, 0x3263, 0x67af, 0x9bf1, 0x9d70, + 0xf5fd, 0x12e4, 0x03c8, 0xb9ca, 0xe847, 0x8c5d, 0x6322, 0xbd30}, + {0x8359, 0x59dd, 0x1831, 0x7c1a, 0x1e83, 0xaee1, 0x770d, 0xcea8, + 0xfbb1, 0xeed6, 0x10b5, 0xe2c6, 0x36ea, 0xee17, 0xe32c, 0xffff}, + {0x1727, 0x0f36, 0x6f85, 0x5d0c, 0xca6c, 0x3072, 0x9628, 0x5842, + 0xcb44, 0x7c2b, 0xca4f, 0x62e5, 0x29b1, 0x6ffd, 0x9055, 0xc196}}, + {{0x905d, 0x41c8, 0xa2ff, 0x295b, 0x72bb, 0x4679, 0x6d01, 0x2c98, + 0xb3e0, 0xc537, 0xa310, 0xe07e, 0xe72f, 0x4999, 0x1148, 0xf65e}, + {0x5b41, 0x4239, 0x3c37, 0x5130, 0x30e3, 0xff35, 0xc51f, 0x1a43, + 0xdb23, 0x13cf, 0x9f49, 0xf70c, 0x5e70, 0xd411, 0x3005, 0xf8c6}, + {0xc30e, 0x68f0, 0x201a, 0xe10c, 0x864a, 0x6243, 0xe946, 0x43ae, + 0xf3f1, 0x52dc, 0x1f7f, 0x50d4, 0x2797, 0x064c, 0x5ca4, 0x90e3}}, + {{0xf1b5, 0xc6e5, 0xd2c4, 0xff95, 0x27c5, 0x0c92, 0x5d19, 0x7ae5, + 0x4fbe, 0x5438, 0x99e1, 0x880d, 0xd892, 0xa05c, 0x6ffd, 0x7eac}, + {0x2153, 0xcc9d, 0xfc6c, 0x8358, 0x49a1, 0x01e2, 0xcef0, 0x4969, + 0xd69a, 0x8cef, 0xf5b2, 0xfd95, 0xdcc2, 0x71f4, 0x6ae2, 0xceeb}, + {0x9b2e, 0xcdc6, 0x0a5c, 0x7317, 0x9084, 0xe228, 0x56cf, 0xd512, + 0x628a, 0xce21, 0x3473, 0x4e13, 0x8823, 0x1ed0, 0x34d0, 0xbfa3}}, + {{0x5bae, 0x53e5, 0x5f4d, 0x21ca, 0xb875, 0x8ecf, 0x9aa6, 0xbe3c, + 0x9f96, 0x7b82, 0x375d, 0x4d3e, 0x491c, 0xb1eb, 0x04c9, 0xb6c8}, + {0xfcfd, 0x10b7, 0x73b2, 0xd23b, 0xa357, 0x67da, 0x0d9f, 0x8702, + 0xa037, 0xff8e, 0x0e8b, 0x1801, 0x2c5c, 0x4e6e, 0x4558, 0xfff2}, + {0xc50f, 0x5654, 0x6713, 0x5ef5, 0xa7ce, 0xa647, 0xc832, 0x69ce, + 0x1d5c, 0x4310, 0x0746, 0x5a01, 0x96ea, 0xde4b, 0xa88b, 0x5543}}, + {{0xdc7f, 0x5e8c, 0x89d1, 0xb077, 0xd521, 0xcf90, 0x32fa, 0x5737, + 0x839e, 0x1464, 0x007c, 0x09c6, 0x9371, 0xe8ea, 0xc1cb, 0x75c4}, + {0xe3a3, 0x107f, 0xa82a, 0xa375, 0x4578, 0x60f4, 0x75c9, 0x5ee4, + 0x3fd7, 0x2736, 0x2871, 0xd3d2, 0x5f1d, 0x1abb, 0xa764, 0xffff}, + {0x45c6, 0x1f2e, 0xb14c, 0x84d7, 0x7bb7, 0x5a04, 0x0504, 0x3f33, + 0x5cc1, 0xb07a, 0x6a6c, 0x786f, 0x647f, 0xe1d7, 0x78a2, 0x4cf4}}, + {{0xc006, 0x356f, 0x8cd2, 0x967b, 0xb49e, 0x2d4e, 0x14bf, 0x4bcb, + 0xddab, 0xd3f9, 0xa068, 0x2c1c, 0xd242, 0xa56d, 0xf2c7, 0x5f97}, + {0x465b, 0xb745, 0x0e0d, 0x69a9, 0x987d, 0xcb37, 0xf637, 0xb311, + 0xc4d6, 0x2ddb, 0xf68f, 0x2af9, 0x959d, 0x3f53, 0x98f2, 0xf640}, + {0xc0f2, 0x6bfb, 0xf5c3, 0x91c1, 0x6b05, 0x0825, 0x5ca0, 0x7df7, + 0x9d55, 0x6d9e, 0xfe94, 0x2ad9, 0xd9f0, 0xe68b, 0xa72b, 0xd1b2}}, + {{0x2279, 0x61ba, 0x5bc6, 0x136b, 0xf544, 0x717c, 0xafda, 0x02bd, + 0x79af, 0x1fad, 0xea09, 0x81bb, 0x932b, 0x32c9, 0xdf1d, 0xe576}, + {0x8215, 0x7817, 0xca82, 0x43b0, 0x9b06, 0xea65, 0x1291, 0x0621, + 0x0089, 0x46fe, 0xc5a6, 0xddd7, 0x8065, 0xc6a0, 0x214b, 0xfc64}, + {0x04bf, 0x6f2a, 0x86b2, 0x841a, 0x4a95, 0xc632, 0x97b7, 0x5821, + 0x2b18, 0x1bb0, 0x3e97, 0x935e, 0xcc7d, 0x066b, 0xd513, 0xc251}}, + {{0x76e8, 0x5bc2, 0x3eaa, 0x04fc, 0x9974, 0x92c1, 0x7c15, 0xfa89, + 0x1151, 0x36ee, 0x48b2, 0x049c, 0x5f16, 0xcee4, 0x925b, 0xe98e}, + {0x913f, 0x0a2d, 0xa185, 0x9fea, 0xda5a, 0x4025, 0x40d7, 0x7cfa, + 0x88ca, 0xbbe8, 0xb265, 0xb7e4, 0x6cb1, 0xed64, 0xc6f9, 0xffb5}, + {0x6ab1, 0x1a86, 0x5009, 0x152b, 0x1cc4, 0xe2c8, 0x960b, 0x19d0, + 0x3554, 0xc562, 0xd013, 0xcf91, 0x10e1, 0x7933, 0xe195, 0xcf49}}, + {{0x9cb5, 0xd2d7, 0xc6ed, 0xa818, 0xb495, 0x06ee, 0x0f4a, 0x06e3, + 0x4c5a, 0x80ce, 0xd49a, 0x4cd7, 0x7487, 0x92af, 0xe516, 0x676c}, + {0xd6e9, 0x6b85, 0x619a, 0xb52c, 0x20a0, 0x2f79, 0x3545, 0x1edd, + 0x5a6f, 0x8082, 0x9b80, 0xf8f8, 0xc78a, 0xd0a3, 0xadf4, 0xffff}, + {0x01c2, 0x2118, 0xef5e, 0xa877, 0x046a, 0xd2c2, 0x2ad5, 0x951c, + 0x8900, 0xa5c9, 0x8d0f, 0x6b61, 0x55d3, 0xd572, 0x48de, 0x9219}}, + {{0x5114, 0x0644, 0x23dd, 0x01d3, 0xc101, 0xa659, 0xea17, 0x640f, + 0xf767, 0x2644, 0x9cec, 0xd8ba, 0xd6da, 0x9156, 0x8aeb, 0x875a}, + {0xc1bf, 0xdae9, 0xe96b, 0xce77, 0xf7a1, 0x3e99, 0x5c2e, 0x973b, + 0xd048, 0x5bd0, 0x4e8a, 0xcb85, 0xce39, 0x37f5, 0x815d, 0xffff}, + {0x48cc, 0x35b6, 0x26d4, 0x2ea6, 0x50d6, 0xa2f9, 0x64b6, 0x03bf, + 0xd00c, 0xe057, 0x3343, 0xfb79, 0x3ce5, 0xf717, 0xc5af, 0xe185}}, + {{0x13ff, 0x6c76, 0x2077, 0x16e0, 0xd5ca, 0xf2ad, 0x8dba, 0x8f49, + 0x7887, 0x16f9, 0xb646, 0xfc87, 0xfa31, 0x5096, 0xf08c, 0x3fbe}, + {0x8139, 0x6fd7, 0xf6df, 0xa7bf, 0x6699, 0x5361, 0x6f65, 0x13c8, + 0xf4d1, 0xe28f, 0xc545, 0x0a8c, 0x5274, 0xb0a6, 0xffff, 0xffff}, + {0x22ca, 0x0cd6, 0xc1b5, 0xb064, 0x44a7, 0x297b, 0x495f, 0x34ac, + 0xfa95, 0xec62, 0xf08d, 0x621c, 0x66a6, 0xba94, 0x84c6, 0x8ee0}}, + {{0xaa30, 0x312e, 0x439c, 0x4e88, 0x2e2f, 0x32dc, 0xb880, 0xa28e, + 0xf795, 0xc910, 0xb406, 0x8dd7, 0xb187, 0xa5a5, 0x38f1, 0xe49e}, + {0xfb19, 0xf64a, 0xba6a, 0x8ec2, 0x7255, 0xce89, 0x2cf9, 0x9cba, + 0xe1fe, 0x50da, 0x1705, 0xac52, 0xe3d4, 0x4269, 0x0648, 0xfd77}, + {0xb4c8, 0x6e8a, 0x2b5f, 0x4c2d, 0x5a67, 0xa7bb, 0x7d6d, 0x5569, + 0xa0ea, 0x244a, 0xc0f2, 0xf73d, 0x58cf, 0xac7f, 0xd32b, 0x3018}}, + {{0xc953, 0x1ae1, 0xae46, 0x8709, 0x19c2, 0xa986, 0x9abe, 0x1611, + 0x0395, 0xd5ab, 0xf0f6, 0xb5b0, 0x5b2b, 0x0317, 0x80ba, 0x376d}, + {0xfe77, 0xbc03, 0xac2f, 0x9d00, 0xa175, 0x293d, 0x3b56, 0x0e3a, + 0x0a9c, 0xf40c, 0x690e, 0x1508, 0x95d4, 0xddc4, 0xe805, 0xffff}, + {0xb1ce, 0x0929, 0xa5fe, 0x4b50, 0x9d5d, 0x8187, 0x2557, 0x4376, + 0x11ba, 0xdcef, 0xc1f3, 0xd531, 0x1824, 0x93f6, 0xd81f, 0x8f83}}, + {{0xb8d2, 0xb900, 0x4a0c, 0x7188, 0xa5bf, 0x1b0b, 0x2ae5, 0xa35b, + 0x98e0, 0x610c, 0x86db, 0x2487, 0xa267, 0x002c, 0xebb6, 0xc5f4}, + {0x9cdd, 0x1c1b, 0x2f06, 0x43d1, 0xce47, 0xc334, 0x6e60, 0xc016, + 0x989e, 0x0ab2, 0x0cac, 0x1196, 0xe2d9, 0x2e04, 0xc62b, 0xffff}, + {0xdc36, 0x1f05, 0x6aa9, 0x7a20, 0x944f, 0x2fd3, 0xa553, 0xdb4f, + 0xbd5c, 0x3a75, 0x25d4, 0xe20e, 0xa387, 0x1410, 0xdbb1, 0x1b60}}, + {{0x76b3, 0x2207, 0x4930, 0x5dd7, 0x65a0, 0xd55c, 0xb443, 0x53b7, + 0x5c22, 0x818a, 0xb2e7, 0x9de8, 0x9985, 0xed45, 0x33b1, 0x53e8}, + {0x7913, 0x44e1, 0xf15b, 0x5edd, 0x34f3, 0x4eba, 0x0758, 0x7104, + 0x32d9, 0x28f3, 0x4401, 0x85c5, 0xb695, 0xb899, 0xc0f2, 0xffff}, + {0x7f43, 0xd202, 0x24c9, 0x69f3, 0x74dc, 0x1a69, 0xeaee, 0x5405, + 0x1755, 0x4bb8, 0x04e3, 0x2fd2, 0xada8, 0x39eb, 0x5b4d, 0x96ca}}, + {{0x807b, 0x7112, 0xc088, 0xdafd, 0x02fa, 0x9d95, 0x5e42, 0xc033, + 0xde0a, 0xeecf, 0x8e90, 0x8da1, 0xb17e, 0x9a5b, 0x4c6d, 0x1914}, + {0x4871, 0xd1cb, 0x47d7, 0x327f, 0x09ec, 0x97bb, 0x2fae, 0xd346, + 0x6b78, 0x3707, 0xfeb2, 0xa6ab, 0x13df, 0x76b0, 0x8fb9, 0xffb3}, + {0x179e, 0xb63b, 0x4784, 0x231e, 0x9f42, 0x7f1a, 0xa3fb, 0xdd8c, + 0xd1eb, 0xb4c9, 0x8ca7, 0x018c, 0xf691, 0x576c, 0xa7d6, 0xce27}}, + {{0x5f45, 0x7c64, 0x083d, 0xedd5, 0x08a0, 0x0c64, 0x6c6f, 0xec3c, + 0xe2fb, 0x352c, 0x9303, 0x75e4, 0xb4e0, 0x8b09, 0xaca4, 0x7025}, + {0x1025, 0xb482, 0xfed5, 0xa678, 0x8966, 0x9359, 0x5329, 0x98bb, + 0x85b2, 0x73ba, 0x9982, 0x6fdc, 0xf190, 0xbe8c, 0xdc5c, 0xfd93}, + {0x83a2, 0x87a4, 0xa680, 0x52a1, 0x1ba1, 0x8848, 0x5db7, 0x9744, + 0x409c, 0x0745, 0x0e1e, 0x1cfc, 0x00cd, 0xf573, 0x2071, 0xccaa}}, + {{0xf61f, 0x63d4, 0x536c, 0x9eb9, 0x5ddd, 0xbb11, 0x9014, 0xe904, + 0xfe01, 0x6b45, 0x1858, 0xcb5b, 0x4c38, 0x43e1, 0x381d, 0x7f94}, + {0xf61f, 0x63d4, 0xd810, 0x7ca3, 0x8a04, 0x4b83, 0x11fc, 0xdf94, + 0x4169, 0xbd05, 0x608e, 0x7151, 0x4fbf, 0xb31a, 0x38a7, 0xa29b}, + {0xe621, 0xdfa5, 0x3d06, 0x1d03, 0x81e6, 0x00da, 0x53a6, 0x965e, + 0x93e5, 0x2164, 0x5b61, 0x59b8, 0xa629, 0x8d73, 0x699a, 0x6111}}, + {{0x4cc3, 0xd29e, 0xf4a3, 0x3428, 0x2048, 0xeec9, 0x5f50, 0x99a4, + 0x6de9, 0x05f2, 0x5aa9, 0x5fd2, 0x98b4, 0x1adc, 0x225f, 0x777f}, + {0xe649, 0x37da, 0x5ba6, 0x5765, 0x3f4a, 0x8a1c, 0x2e79, 0xf550, + 0x1a54, 0xcd1e, 0x7218, 0x3c3c, 0x6311, 0xfe28, 0x95fb, 0xed97}, + {0xe9b6, 0x0c47, 0x3f0e, 0x849b, 0x11f8, 0xe599, 0x5e4d, 0xd618, + 0xa06d, 0x33a0, 0x9a3e, 0x44db, 0xded8, 0x10f0, 0x94d2, 0x81fb}}, + {{0x2e59, 0x7025, 0xd413, 0x455a, 0x1ce3, 0xbd45, 0x7263, 0x27f7, + 0x23e3, 0x518e, 0xbe06, 0xc8c4, 0xe332, 0x4276, 0x68b4, 0xb166}, + {0x596f, 0x0cf6, 0xc8ec, 0x787b, 0x04c1, 0x473c, 0xd2b8, 0x8d54, + 0x9cdf, 0x77f2, 0xd3f3, 0x6735, 0x0638, 0xf80e, 0x9467, 0xc6aa}, + {0xc7e7, 0x1822, 0xb62a, 0xec0d, 0x89cd, 0x7846, 0xbfa2, 0x35d5, + 0xfa38, 0x870f, 0x494b, 0x1697, 0x8b17, 0xf904, 0x10b6, 0x9822}}, + {{0x6d5b, 0x1d4f, 0x0aaf, 0x807b, 0x35fb, 0x7ee8, 0x00c6, 0x059a, + 0xddf0, 0x1fb1, 0xc38a, 0xd78e, 0x2aa4, 0x79e7, 0xad28, 0xc3f1}, + {0xe3bb, 0x174e, 0xe0a8, 0x74b6, 0xbd5b, 0x35f6, 0x6d23, 0x6328, + 0xc11f, 0x83e1, 0xf928, 0xa918, 0x838e, 0xbf43, 0xe243, 0xfffb}, + {0x9cf2, 0x6b8b, 0x3476, 0x9d06, 0xdcf2, 0xdb8a, 0x89cd, 0x4857, + 0x75c2, 0xabb8, 0x490b, 0xc9bd, 0x890e, 0xe36e, 0xd552, 0xfffa}}, + {{0x2f09, 0x9d62, 0xa9fc, 0xf090, 0xd6d1, 0x9d1d, 0x1828, 0xe413, + 0xc92b, 0x3d5a, 0x1373, 0x368c, 0xbaf2, 0x2158, 0x71eb, 0x08a3}, + {0x2f09, 0x1d62, 0x4630, 0x0de1, 0x06dc, 0xf7f1, 0xc161, 0x1e92, + 0x7495, 0x97e4, 0x94b6, 0xa39e, 0x4f1b, 0x18f8, 0x7bd4, 0x0c4c}, + {0xeb3d, 0x723d, 0x0907, 0x525b, 0x463a, 0x49a8, 0xc6b8, 0xce7f, + 0x740c, 0x0d7d, 0xa83b, 0x457f, 0xae8e, 0xc6af, 0xd331, 0x0475}}, + {{0x6abd, 0xc7af, 0x3e4e, 0x95fd, 0x8fc4, 0xee25, 0x1f9c, 0x0afe, + 0x291d, 0xcde0, 0x48f4, 0xb2e8, 0xf7af, 0x8f8d, 0x0bd6, 0x078d}, + {0x4037, 0xbf0e, 0x2081, 0xf363, 0x13b2, 0x381e, 0xfb6e, 0x818e, + 0x27e4, 0x5662, 0x18b0, 0x0cd2, 0x81f5, 0x9415, 0x0d6c, 0xf9fb}, + {0xd205, 0x0981, 0x0498, 0x1f08, 0xdb93, 0x1732, 0x0579, 0x1424, + 0xad95, 0x642f, 0x050c, 0x1d6d, 0xfc95, 0xfc4a, 0xd41b, 0x3521}}, + {{0xf23a, 0x4633, 0xaef4, 0x1a92, 0x3c8b, 0x1f09, 0x30f3, 0x4c56, + 0x2a2f, 0x4f62, 0xf5e4, 0x8329, 0x63cc, 0xb593, 0xec6a, 0xc428}, + {0x93a7, 0xfcf6, 0x606d, 0xd4b2, 0x2aad, 0x28b4, 0xc65b, 0x8998, + 0x4e08, 0xd178, 0x0900, 0xc82b, 0x7470, 0xa342, 0x7c0f, 0xffff}, + {0x315f, 0xf304, 0xeb7b, 0xe5c3, 0x1451, 0x6311, 0x8f37, 0x93a8, + 0x4a38, 0xa6c6, 0xe393, 0x1087, 0x6301, 0xd673, 0x4ec4, 0xffff}}, + {{0x892e, 0xeed0, 0x1165, 0xcbc1, 0x5545, 0xa280, 0x7243, 0x10c9, + 0x9536, 0x36af, 0xb3fc, 0x2d7c, 0xe8a5, 0x09d6, 0xe1d4, 0xe85d}, + {0xae09, 0xc28a, 0xd777, 0xbd80, 0x23d6, 0xf980, 0xeb7c, 0x4e0e, + 0xf7dc, 0x6475, 0xf10a, 0x2d33, 0x5dfd, 0x797a, 0x7f1c, 0xf71a}, + {0x4064, 0x8717, 0xd091, 0x80b0, 0x4527, 0x8442, 0xac8b, 0x9614, + 0xc633, 0x35f5, 0x7714, 0x2e83, 0x4aaa, 0xd2e4, 0x1acd, 0x0562}}, + {{0xdb64, 0x0937, 0x308b, 0x53b0, 0x00e8, 0xc77f, 0x2f30, 0x37f7, + 0x79ce, 0xeb7f, 0xde81, 0x9286, 0xafda, 0x0e62, 0xae00, 0x0067}, + {0x2cc7, 0xd362, 0xb161, 0x0557, 0x4ff2, 0xb9c8, 0x06fe, 0x5f2b, + 0xde33, 0x0190, 0x28c6, 0xb886, 0xee2b, 0x5a4e, 0x3289, 0x0185}, + {0x4215, 0x923e, 0xf34f, 0xb362, 0x88f8, 0xceec, 0xafdd, 0x7f42, + 0x0c57, 0x56b2, 0xa366, 0x6a08, 0x0826, 0xfb8f, 0x1b03, 0x0163}}, + {{0xa4ba, 0x8408, 0x810a, 0xdeba, 0x47a3, 0x853a, 0xeb64, 0x2f74, + 0x3039, 0x038c, 0x7fbb, 0x498e, 0xd1e9, 0x46fb, 0x5691, 0x32a4}, + {0xd749, 0xb49d, 0x20b7, 0x2af6, 0xd34a, 0xd2da, 0x0a10, 0xf781, + 0x58c9, 0x171f, 0x3cb6, 0x6337, 0x88cd, 0xcf1e, 0xb246, 0x7351}, + {0xf729, 0xcf0a, 0x96ea, 0x032c, 0x4a8f, 0x42fe, 0xbac8, 0xec65, + 0x1510, 0x0d75, 0x4c17, 0x8d29, 0xa03f, 0x8b7e, 0x2c49, 0x0000}}, + {{0x0fa4, 0x8e1c, 0x3788, 0xba3c, 0x8d52, 0xd89d, 0x12c8, 0xeced, + 0x9fe6, 0x9b88, 0xecf3, 0xe3c8, 0xac48, 0x76ed, 0xf23e, 0xda79}, + {0x1103, 0x227c, 0x5b00, 0x3fcf, 0xc5d0, 0x2d28, 0x8020, 0x4d1c, + 0xc6b9, 0x67f9, 0x6f39, 0x989a, 0xda53, 0x3847, 0xd416, 0xe0d0}, + {0xdd8e, 0xcf31, 0x3710, 0x7e44, 0xa511, 0x933c, 0x0cc3, 0x5145, + 0xf632, 0x5e1d, 0x038f, 0x5ce7, 0x7265, 0xda9d, 0xded6, 0x08f8}}, + {{0xe2c8, 0x91d5, 0xa5f5, 0x735f, 0x6b58, 0x56dc, 0xb39d, 0x5c4a, + 0x57d0, 0xa1c2, 0xd92f, 0x9ad4, 0xf7c4, 0x51dd, 0xaf5c, 0x0096}, + {0x1739, 0x7207, 0x7505, 0xbf35, 0x42de, 0x0a29, 0xa962, 0xdedf, + 0x53e8, 0x12bf, 0xcde7, 0xd8e2, 0x8d4d, 0x2c4b, 0xb1b1, 0x0628}, + {0x992d, 0xe3a7, 0xb422, 0xc198, 0x23ab, 0xa6ef, 0xb45d, 0x50da, + 0xa738, 0x014a, 0x2310, 0x85fb, 0x5fe8, 0x1b18, 0x1774, 0x03a7}}, + {{0x1f16, 0x2b09, 0x0236, 0xee90, 0xccf9, 0x9775, 0x8130, 0x4c91, + 0x9091, 0x310b, 0x6dc4, 0x86f6, 0xc2e8, 0xef60, 0xfc0e, 0xf3a4}, + {0x9f49, 0xac15, 0x02af, 0x110f, 0xc59d, 0x5677, 0xa1a9, 0x38d5, + 0x914f, 0xa909, 0x3a3a, 0x4a39, 0x3703, 0xea30, 0x73da, 0xffad}, + {0x15ed, 0xdd16, 0x83c7, 0x270a, 0x862f, 0xd8ad, 0xcaa1, 0x5f41, + 0x99a9, 0x3fc8, 0x7bb2, 0x360a, 0xb06d, 0xfadc, 0x1b36, 0xffa8}}, + {{0xc4e0, 0xb8fd, 0x5106, 0xe169, 0x754c, 0xa58c, 0xc413, 0x8224, + 0x5483, 0x63ec, 0xd477, 0x8473, 0x4778, 0x9281, 0x0000, 0x0000}, + {0x85e1, 0xff54, 0xb200, 0xe413, 0xf4f4, 0x4c0f, 0xfcec, 0xc183, + 0x60d3, 0x1b0c, 0x3834, 0x601c, 0x943c, 0xbe6e, 0x0002, 0x0000}, + {0xf4f8, 0xfd5e, 0x61ef, 0xece8, 0x9199, 0xe5c4, 0x05a6, 0xe6c3, + 0xc4ae, 0x8b28, 0x66b1, 0x8a95, 0x9ece, 0x8f4a, 0x0001, 0x0000}}, + {{0xeae9, 0xa1b4, 0xc6d8, 0x2411, 0x2b5a, 0x1dd0, 0x2dc9, 0xb57b, + 0x5ccd, 0x4957, 0xaf59, 0xa04b, 0x5f42, 0xab7c, 0x2826, 0x526f}, + {0xf407, 0x165a, 0xb724, 0x2f12, 0x2ea1, 0x470b, 0x4464, 0xbd35, + 0x606f, 0xd73e, 0x50d3, 0x8a7f, 0x8029, 0x7ffc, 0xbe31, 0x6cfb}, + {0x8171, 0x1f4c, 0xced2, 0x9c99, 0x6d7e, 0x5a0f, 0xfefb, 0x59e3, + 0xa0c8, 0xabd9, 0xc4c5, 0x57d3, 0xbfa3, 0x4f11, 0x96a2, 0x5a7d}}, + {{0xe068, 0x4cc0, 0x8bcd, 0xc903, 0x9e52, 0xb3e1, 0xd745, 0x0995, + 0xdd8f, 0xf14b, 0xd2ac, 0xd65a, 0xda1d, 0xa742, 0xbac5, 0x474c}, + {0x7481, 0xf2ad, 0x9757, 0x2d82, 0xb683, 0xb16b, 0x0002, 0x7b60, + 0x8f0c, 0x2594, 0x8f64, 0x3b7a, 0x3552, 0x8d9d, 0xb9d7, 0x67eb}, + {0xcaab, 0xb9a1, 0xf966, 0xe311, 0x5b34, 0x0fa0, 0x6abc, 0x8134, + 0xab3d, 0x90f6, 0x1984, 0x9232, 0xec17, 0x74e5, 0x2ceb, 0x434e}}, + {{0x0fb1, 0x7a55, 0x1a5c, 0x53eb, 0xd7b3, 0x7a01, 0xca32, 0x31f6, + 0x3b74, 0x679e, 0x1501, 0x6c57, 0xdb20, 0x8b7c, 0xd7d0, 0x8097}, + {0xb127, 0xb20c, 0xe3a2, 0x96f3, 0xe0d8, 0xd50c, 0x14b4, 0x0b40, + 0x6eeb, 0xa258, 0x99db, 0x3c8c, 0x0f51, 0x4198, 0x3887, 0xffd0}, + {0x0273, 0x9f8c, 0x9669, 0xbbba, 0x1c49, 0x767c, 0xc2af, 0x59f0, + 0x1366, 0xd397, 0x63ac, 0x6fe8, 0x1a9a, 0x1259, 0x01d0, 0x0016}}, + {{0x7876, 0x2a35, 0xa24a, 0x433e, 0x5501, 0x573c, 0xd76d, 0xcb82, + 0x1334, 0xb4a6, 0xf290, 0xc797, 0xeae9, 0x2b83, 0x1e2b, 0x8b14}, + {0x3885, 0x8aef, 0x9dea, 0x2b8c, 0xdd7c, 0xd7cd, 0xb0cc, 0x05ee, + 0x361b, 0x3800, 0xb0d4, 0x4c23, 0xbd3f, 0x5180, 0x9783, 0xff80}, + {0xab36, 0x3104, 0xdae8, 0x0704, 0x4a28, 0x6714, 0x824b, 0x0051, + 0x8134, 0x1f6a, 0x712d, 0x1f03, 0x03b2, 0xecac, 0x377d, 0xfef9}} + }; + + int i, j, ok; + + /* Test known inputs/outputs */ + for (i = 0; (size_t)i < sizeof(CASES) / sizeof(CASES[0]); ++i) { + uint16_t out[16]; + test_modinv32_uint16(out, CASES[i][0], CASES[i][1]); + for (j = 0; j < 16; ++j) CHECK(out[j] == CASES[i][2][j]); +#ifdef SECP256K1_WIDEMUL_INT128 + test_modinv64_uint16(out, CASES[i][0], CASES[i][1]); + for (j = 0; j < 16; ++j) CHECK(out[j] == CASES[i][2][j]); +#endif + } + + for (i = 0; i < 100 * COUNT; ++i) { + /* 256-bit numbers in 16-uint16_t's notation */ + static const uint16_t ZERO[16] = {0}; + uint16_t xd[16]; /* the number (in range [0,2^256)) to be inverted */ + uint16_t md[16]; /* the modulus (odd, in range [3,2^256)) */ + uint16_t id[16]; /* the inverse of xd mod md */ + + /* generate random xd and md, so that md is odd, md>1, xd>= 16; + } +} + +/* Negate a 256-bit number (represented as 16 uint16_t's in LE order) mod 2^256. */ +static void neg256(uint16_t* out, const uint16_t* a) { + int i; + uint32_t carry = 1; + for (i = 0; i < 16; ++i) { + carry += (uint16_t)~a[i]; + out[i] = carry; + carry >>= 16; + } +} + +/* Right-shift a 256-bit number (represented as 16 uint16_t's in LE order). */ +static void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) { + uint16_t sign = sign_extend && (a[15] >> 15); + int i, j; + for (i = 15; i >= 0; --i) { + uint16_t v = 0; + for (j = 0; j < 16; ++j) { + int frompos = i*16 + j + n; + if (frompos >= 256) { + v |= sign << j; + } else { + v |= ((uint16_t)((a[frompos >> 4] >> (frompos & 15)) & 1)) << j; + } + } + out[i] = v; + } +} + +/* Load a 64-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ +static void load256u64(uint16_t* out, uint64_t v, int is_signed) { + int i; + uint64_t sign = is_signed && (v >> 63) ? UINT64_MAX : 0; + for (i = 0; i < 4; ++i) { + out[i] = v >> (16 * i); + } + for (i = 4; i < 16; ++i) { + out[i] = sign; + } +} + +/* Load a 128-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ +static void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) { + int i; + uint64_t sign = is_signed && (hi >> 63) ? UINT64_MAX : 0; + for (i = 0; i < 4; ++i) { + out[i] = lo >> (16 * i); + } + for (i = 4; i < 8; ++i) { + out[i] = hi >> (16 * (i - 4)); + } + for (i = 8; i < 16; ++i) { + out[i] = sign; + } +} + +/* Check whether the 256-bit value represented by array of 16-bit values is in range -2^127 < v < 2^127. */ +static int int256is127(const uint16_t* v) { + int all_0 = ((v[7] & 0x8000) == 0), all_1 = ((v[7] & 0x8000) == 0x8000); + int i; + for (i = 8; i < 16; ++i) { + if (v[i] != 0) all_0 = 0; + if (v[i] != 0xffff) all_1 = 0; + } + return all_0 || all_1; +} + +static void load256u128(uint16_t* out, const secp256k1_uint128* v) { + uint64_t lo = secp256k1_u128_to_u64(v), hi = secp256k1_u128_hi_u64(v); + load256two64(out, hi, lo, 0); +} + +static void load256i128(uint16_t* out, const secp256k1_int128* v) { + uint64_t lo; + int64_t hi; + secp256k1_int128 c = *v; + lo = secp256k1_i128_to_u64(&c); + secp256k1_i128_rshift(&c, 64); + hi = secp256k1_i128_to_i64(&c); + load256two64(out, hi, lo, 1); +} + +static void run_int128_test_case(void) { + unsigned char buf[32]; + uint64_t v[4]; + secp256k1_int128 swa, swz; + secp256k1_uint128 uwa, uwz; + uint64_t ub, uc; + int64_t sb, sc; + uint16_t rswa[16], rswz[32], rswr[32], ruwa[16], ruwz[32], ruwr[32]; + uint16_t rub[16], ruc[16], rsb[16], rsc[16]; + int i; + + /* Generate 32-byte random value. */ + testrand256_test(buf); + /* Convert into 4 64-bit integers. */ + for (i = 0; i < 4; ++i) { + uint64_t vi = 0; + int j; + for (j = 0; j < 8; ++j) vi = (vi << 8) + buf[8*i + j]; + v[i] = vi; + } + /* Convert those into a 128-bit value and two 64-bit values (signed and unsigned). */ + secp256k1_u128_load(&uwa, v[1], v[0]); + secp256k1_i128_load(&swa, v[1], v[0]); + ub = v[2]; + sb = v[2]; + uc = v[3]; + sc = v[3]; + /* Load those also into 16-bit array representations. */ + load256u128(ruwa, &uwa); + load256i128(rswa, &swa); + load256u64(rub, ub, 0); + load256u64(rsb, sb, 1); + load256u64(ruc, uc, 0); + load256u64(rsc, sc, 1); + /* test secp256k1_u128_mul */ + mulmod256(ruwr, rub, ruc, NULL); + secp256k1_u128_mul(&uwz, ub, uc); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_accum_mul */ + mulmod256(ruwr, rub, ruc, NULL); + add256(ruwr, ruwr, ruwa); + uwz = uwa; + secp256k1_u128_accum_mul(&uwz, ub, uc); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_accum_u64 */ + add256(ruwr, rub, ruwa); + uwz = uwa; + secp256k1_u128_accum_u64(&uwz, ub); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_rshift */ + rshift256(ruwr, ruwa, uc % 128, 0); + uwz = uwa; + secp256k1_u128_rshift(&uwz, uc % 128); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_to_u64 */ + CHECK(secp256k1_u128_to_u64(&uwa) == v[0]); + /* test secp256k1_u128_hi_u64 */ + CHECK(secp256k1_u128_hi_u64(&uwa) == v[1]); + /* test secp256k1_u128_from_u64 */ + secp256k1_u128_from_u64(&uwz, ub); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(rub, ruwz, 16) == 0); + /* test secp256k1_u128_check_bits */ + { + int uwa_bits = 0; + int j; + for (j = 0; j < 128; ++j) { + if (ruwa[j / 16] >> (j % 16)) uwa_bits = 1 + j; + } + for (j = 0; j < 128; ++j) { + CHECK(secp256k1_u128_check_bits(&uwa, j) == (uwa_bits <= j)); + } + } + /* test secp256k1_i128_mul */ + mulmod256(rswr, rsb, rsc, NULL); + secp256k1_i128_mul(&swz, sb, sc); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + /* test secp256k1_i128_accum_mul */ + mulmod256(rswr, rsb, rsc, NULL); + add256(rswr, rswr, rswa); + if (int256is127(rswr)) { + swz = swa; + secp256k1_i128_accum_mul(&swz, sb, sc); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + } + /* test secp256k1_i128_det */ + { + uint16_t rsd[16], rse[16], rst[32]; + int64_t sd = v[0], se = v[1]; + load256u64(rsd, sd, 1); + load256u64(rse, se, 1); + mulmod256(rst, rsc, rsd, NULL); + neg256(rst, rst); + mulmod256(rswr, rsb, rse, NULL); + add256(rswr, rswr, rst); + secp256k1_i128_det(&swz, sb, sc, sd, se); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + } + /* test secp256k1_i128_rshift */ + rshift256(rswr, rswa, uc % 127, 1); + swz = swa; + secp256k1_i128_rshift(&swz, uc % 127); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + /* test secp256k1_i128_to_u64 */ + CHECK(secp256k1_i128_to_u64(&swa) == v[0]); + /* test secp256k1_i128_from_i64 */ + secp256k1_i128_from_i64(&swz, sb); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rsb, rswz, 16) == 0); + /* test secp256k1_i128_to_i64 */ + CHECK(secp256k1_i128_to_i64(&swz) == sb); + /* test secp256k1_i128_eq_var */ + { + int expect = (uc & 1); + swz = swa; + if (!expect) { + /* Make sure swz != swa */ + uint64_t v0c = v[0], v1c = v[1]; + if (ub & 64) { + v1c ^= (((uint64_t)1) << (ub & 63)); + } else { + v0c ^= (((uint64_t)1) << (ub & 63)); + } + secp256k1_i128_load(&swz, v1c, v0c); + } + CHECK(secp256k1_i128_eq_var(&swa, &swz) == expect); + } + /* test secp256k1_i128_check_pow2 (sign == 1) */ + { + int expect = (uc & 1); + int pos = ub % 127; + if (expect) { + /* If expect==1, set swz to exactly 2^pos. */ + uint64_t hi = 0; + uint64_t lo = 0; + if (pos >= 64) { + hi = (((uint64_t)1) << (pos & 63)); + } else { + lo = (((uint64_t)1) << (pos & 63)); + } + secp256k1_i128_load(&swz, hi, lo); + } else { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal 2^pos. */ + if (pos >= 64) { + if ((v[1] == (((uint64_t)1) << (pos & 63))) && v[0] == 0) expect = 1; + } else { + if ((v[0] == (((uint64_t)1) << (pos & 63))) && v[1] == 0) expect = 1; + } + swz = swa; + } + CHECK(secp256k1_i128_check_pow2(&swz, pos, 1) == expect); + } + /* test secp256k1_i128_check_pow2 (sign == -1) */ + { + int expect = (uc & 1); + int pos = ub % 127; + if (expect) { + /* If expect==1, set swz to exactly -2^pos. */ + uint64_t hi = ~(uint64_t)0; + uint64_t lo = ~(uint64_t)0; + if (pos >= 64) { + hi <<= (pos & 63); + lo = 0; + } else { + lo <<= (pos & 63); + } + secp256k1_i128_load(&swz, hi, lo); + } else { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal -2^pos. */ + if (pos >= 64) { + if ((v[1] == ((~(uint64_t)0) << (pos & 63))) && v[0] == 0) expect = 1; + } else { + if ((v[0] == ((~(uint64_t)0) << (pos & 63))) && v[1] == ~(uint64_t)0) expect = 1; + } + swz = swa; + } + CHECK(secp256k1_i128_check_pow2(&swz, pos, -1) == expect); + } +} + +static void run_int128_tests(void) { + { /* secp256k1_u128_accum_mul */ + secp256k1_uint128 res; + + /* Check secp256k1_u128_accum_mul overflow */ + secp256k1_u128_mul(&res, UINT64_MAX, UINT64_MAX); + secp256k1_u128_accum_mul(&res, UINT64_MAX, UINT64_MAX); + CHECK(secp256k1_u128_to_u64(&res) == 2); + CHECK(secp256k1_u128_hi_u64(&res) == 18446744073709551612U); + } + { /* secp256k1_u128_accum_mul */ + secp256k1_int128 res; + + /* Compute INT128_MAX = 2^127 - 1 with secp256k1_i128_accum_mul */ + secp256k1_i128_mul(&res, INT64_MAX, INT64_MAX); + secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MAX); + CHECK(secp256k1_i128_to_u64(&res) == 2); + secp256k1_i128_accum_mul(&res, 4, 9223372036854775807); + secp256k1_i128_accum_mul(&res, 1, 1); + CHECK(secp256k1_i128_to_u64(&res) == UINT64_MAX); + secp256k1_i128_rshift(&res, 64); + CHECK(secp256k1_i128_to_i64(&res) == INT64_MAX); + + /* Compute INT128_MIN = - 2^127 with secp256k1_i128_accum_mul */ + secp256k1_i128_mul(&res, INT64_MAX, INT64_MIN); + CHECK(secp256k1_i128_to_u64(&res) == (uint64_t)INT64_MIN); + secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MIN); + CHECK(secp256k1_i128_to_u64(&res) == 0); + secp256k1_i128_accum_mul(&res, 2, INT64_MIN); + CHECK(secp256k1_i128_to_u64(&res) == 0); + secp256k1_i128_rshift(&res, 64); + CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN); + } + { + /* Randomized tests. */ + int i; + for (i = 0; i < 256 * COUNT; ++i) run_int128_test_case(); + } +} +#endif + +/***** SCALAR TESTS *****/ + +static void scalar_test(void) { + secp256k1_scalar s; + secp256k1_scalar s1; + secp256k1_scalar s2; + unsigned char c[32]; + + /* Set 's' to a random scalar, with value 'snum'. */ + testutil_random_scalar_order_test(&s); + + /* Set 's1' to a random scalar, with value 's1num'. */ + testutil_random_scalar_order_test(&s1); + + /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ + testutil_random_scalar_order_test(&s2); + secp256k1_scalar_get_b32(c, &s2); + + { + int i; + /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ + secp256k1_scalar n; + secp256k1_scalar_set_int(&n, 0); + for (i = 0; i < 256; i += 4) { + secp256k1_scalar t; + int j; + secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_limb32(&s, 256 - 4 - i, 4)); + for (j = 0; j < 4; j++) { + secp256k1_scalar_add(&n, &n, &n); + } + secp256k1_scalar_add(&n, &n, &t); + } + CHECK(secp256k1_scalar_eq(&n, &s)); + } + + { + /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ + secp256k1_scalar n; + int i = 0; + secp256k1_scalar_set_int(&n, 0); + while (i < 256) { + secp256k1_scalar t; + int j; + int now = testrand_int(15) + 1; + if (now + i > 256) { + now = 256 - i; + } + secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now)); + for (j = 0; j < now; j++) { + secp256k1_scalar_add(&n, &n, &n); + } + secp256k1_scalar_add(&n, &n, &t); + i += now; + } + CHECK(secp256k1_scalar_eq(&n, &s)); + } + + { + /* Test commutativity of add. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_add(&r2, &s2, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + secp256k1_scalar r1, r2; + secp256k1_scalar b; + int i; + /* Test add_bit. */ + int bit = testrand_bits(8); + secp256k1_scalar_set_int(&b, 1); + CHECK(secp256k1_scalar_is_one(&b)); + for (i = 0; i < bit; i++) { + secp256k1_scalar_add(&b, &b, &b); + } + r1 = s1; + r2 = s1; + if (!secp256k1_scalar_add(&r1, &r1, &b)) { + /* No overflow happened. */ + secp256k1_scalar_cadd_bit(&r2, bit, 1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + /* cadd is a noop when flag is zero */ + secp256k1_scalar_cadd_bit(&r2, bit, 0); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + } + + { + /* Test commutativity of mul. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_mul(&r1, &s1, &s2); + secp256k1_scalar_mul(&r2, &s2, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test associativity of add. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_add(&r1, &r1, &s); + secp256k1_scalar_add(&r2, &s2, &s); + secp256k1_scalar_add(&r2, &s1, &r2); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test associativity of mul. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_mul(&r1, &s1, &s2); + secp256k1_scalar_mul(&r1, &r1, &s); + secp256k1_scalar_mul(&r2, &s2, &s); + secp256k1_scalar_mul(&r2, &s1, &r2); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test distributitivity of mul over add. */ + secp256k1_scalar r1, r2, t; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_mul(&r1, &r1, &s); + secp256k1_scalar_mul(&r2, &s1, &s); + secp256k1_scalar_mul(&t, &s2, &s); + secp256k1_scalar_add(&r2, &r2, &t); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test multiplicative identity. */ + secp256k1_scalar r1; + secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_one); + CHECK(secp256k1_scalar_eq(&r1, &s1)); + } + + { + /* Test additive identity. */ + secp256k1_scalar r1; + secp256k1_scalar_add(&r1, &s1, &secp256k1_scalar_zero); + CHECK(secp256k1_scalar_eq(&r1, &s1)); + } + + { + /* Test zero product property. */ + secp256k1_scalar r1; + secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_zero); + CHECK(secp256k1_scalar_eq(&r1, &secp256k1_scalar_zero)); + } + + { + /* Test halving. */ + secp256k1_scalar r; + secp256k1_scalar_add(&r, &s, &s); + secp256k1_scalar_half(&r, &r); + CHECK(secp256k1_scalar_eq(&r, &s)); + } +} + +static void run_scalar_set_b32_seckey_tests(void) { + unsigned char b32[32]; + secp256k1_scalar s1; + secp256k1_scalar s2; + + /* Usually set_b32 and set_b32_seckey give the same result */ + testutil_random_scalar_order_b32(b32); + secp256k1_scalar_set_b32(&s1, b32, NULL); + CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 1); + CHECK(secp256k1_scalar_eq(&s1, &s2) == 1); + + memset(b32, 0, sizeof(b32)); + CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0); + memset(b32, 0xFF, sizeof(b32)); + CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0); +} + +static void run_scalar_tests(void) { + int i; + for (i = 0; i < 128 * COUNT; i++) { + scalar_test(); + } + for (i = 0; i < COUNT; i++) { + run_scalar_set_b32_seckey_tests(); + } + + { + /* Check that the scalar constants secp256k1_scalar_zero and + secp256k1_scalar_one contain the expected values. */ + secp256k1_scalar zero, one; + + CHECK(secp256k1_scalar_is_zero(&secp256k1_scalar_zero)); + secp256k1_scalar_set_int(&zero, 0); + CHECK(secp256k1_scalar_eq(&zero, &secp256k1_scalar_zero)); + + CHECK(secp256k1_scalar_is_one(&secp256k1_scalar_one)); + secp256k1_scalar_set_int(&one, 1); + CHECK(secp256k1_scalar_eq(&one, &secp256k1_scalar_one)); + } + + { + /* (-1)+1 should be zero. */ + secp256k1_scalar o; + secp256k1_scalar_negate(&o, &secp256k1_scalar_one); + secp256k1_scalar_add(&o, &o, &secp256k1_scalar_one); + CHECK(secp256k1_scalar_is_zero(&o)); + secp256k1_scalar_negate(&o, &o); + CHECK(secp256k1_scalar_is_zero(&o)); + } + + { + /* Test that halving and doubling roundtrips on some fixed values. */ + static const secp256k1_scalar HALF_TESTS[] = { + /* 0 */ + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0), + /* 1 */ + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1), + /* -1 */ + SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd0364140ul), + /* -2 (largest odd value) */ + SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd036413Ful), + /* Half the secp256k1 order */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a0ul), + /* Half the secp256k1 order + 1 */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a1ul), + /* 2^255 */ + SECP256K1_SCALAR_CONST(0x80000000ul, 0, 0, 0, 0, 0, 0, 0), + /* 2^255 - 1 */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful), + }; + unsigned n; + for (n = 0; n < sizeof(HALF_TESTS) / sizeof(HALF_TESTS[0]); ++n) { + secp256k1_scalar s; + secp256k1_scalar_half(&s, &HALF_TESTS[n]); + secp256k1_scalar_add(&s, &s, &s); + CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n])); + secp256k1_scalar_add(&s, &s, &s); + secp256k1_scalar_half(&s, &s); + CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n])); + } + } + + { + /* Does check_overflow check catch all ones? */ + static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + CHECK(secp256k1_scalar_check_overflow(&overflowed)); + } + + { + /* Static test vectors. + * These were reduced from ~10^12 random vectors based on comparison-decision + * and edge-case coverage on 32-bit and 64-bit implementations. + * The responses were generated with Sage 5.9. + */ + secp256k1_scalar x; + secp256k1_scalar y; + secp256k1_scalar z; + secp256k1_scalar zz; + secp256k1_scalar r1; + secp256k1_scalar r2; + secp256k1_scalar zzv; + int overflow; + unsigned char chal[33][2][32] = { + {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}}, + {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f}, + {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff}, + {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, + 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, + 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}}, + {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00}, + {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}}, + {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00}, + {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}}, + {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}}, + {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f, + 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}}, + {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, + 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}, + {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}, + {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}} + }; + unsigned char res[33][2][32] = { + {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9, + 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1, + 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6, + 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35}, + {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d, + 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c, + 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49, + 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}}, + {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22, + 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c, + 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f, + 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8}, + {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77, + 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4, + 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59, + 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}}, + {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef, + 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab, + 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55, + 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c}, + {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96, + 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f, + 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12, + 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}}, + {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c, + 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf, + 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9, + 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48}, + {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42, + 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5, + 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c, + 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}}, + {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb, + 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74, + 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6, + 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63}, + {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3, + 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99, + 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58, + 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}}, + {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b, + 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7, + 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f, + 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0}, + {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d, + 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d, + 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9, + 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}}, + {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7, + 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70, + 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06, + 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e}, + {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9, + 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79, + 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e, + 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}}, + {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb, + 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5, + 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a, + 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe}, + {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48, + 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e, + 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc, + 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}}, + {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b, + 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0, + 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53, + 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8}, + {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c, + 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01, + 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f, + 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}}, + {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7, + 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c, + 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92, + 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30}, + {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62, + 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e, + 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb, + 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}}, + {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25, + 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d, + 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0, + 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13}, + {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60, + 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00, + 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4, + 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}}, + {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31, + 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4, + 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88, + 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa}, + {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57, + 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38, + 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51, + 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}}, + {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c, + 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f, + 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2, + 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4}, + {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01, + 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4, + 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86, + 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}}, + {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5, + 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51, + 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3, + 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62}, + {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c, + 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91, + 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c, + 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}}, + {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e, + 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56, + 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58, + 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4}, + {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41, + 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7, + 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92, + 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}}, + {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec, + 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19, + 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3, + 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4}, + {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87, + 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a, + 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92, + 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}}, + {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64, + 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3, + 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f, + 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33}, + {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c, + 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d, + 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea, + 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}}, + {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7, + 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a, + 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae, + 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe}, + {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc, + 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39, + 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14, + 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}}, + {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23, + 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d, + 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2, + 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16}, + {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c, + 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84, + 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0, + 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}}, + {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb, + 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94, + 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b, + 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e}, + {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54, + 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00, + 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb, + 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0, + 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b, + 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94, + 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8}, + {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26, + 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d, + 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a, + 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39, + 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea, + 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf, + 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae}, + {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b, + 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb, + 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6, + 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}}, + {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a, + 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f, + 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9, + 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56}, + {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93, + 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07, + 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71, + 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}}, + {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87, + 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9, + 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55, + 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73}, + {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d, + 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86, + 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb, + 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}}, + {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2, + 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7, + 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41, + 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7}, + {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06, + 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04, + 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08, + 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}}, + {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2, + 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b, + 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40, + 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68}, + {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e, + 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a, + 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b, + 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}}, + {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67, + 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f, + 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a, + 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51}, + {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2, + 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38, + 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34, + 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}, + {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}, + {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} + }; + for (i = 0; i < 33; i++) { + secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&y, chal[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r1, res[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r2, res[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_mul(&z, &x, &y); + CHECK(secp256k1_scalar_eq(&r1, &z)); + if (!secp256k1_scalar_is_zero(&y)) { + secp256k1_scalar_inverse(&zz, &y); + secp256k1_scalar_inverse_var(&zzv, &y); + CHECK(secp256k1_scalar_eq(&zzv, &zz)); + secp256k1_scalar_mul(&z, &z, &zz); + CHECK(secp256k1_scalar_eq(&x, &z)); + secp256k1_scalar_mul(&zz, &zz, &y); + CHECK(secp256k1_scalar_eq(&secp256k1_scalar_one, &zz)); + } + secp256k1_scalar_mul(&z, &x, &x); + CHECK(secp256k1_scalar_eq(&r2, &z)); + } + } +} + +/***** FIELD TESTS *****/ + +static void random_fe_non_square(secp256k1_fe *ns) { + secp256k1_fe r; + testutil_random_fe_non_zero(ns); + if (secp256k1_fe_sqrt(&r, ns)) { + secp256k1_fe_negate(ns, ns, 1); + } +} + +static int fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe an = *a; + secp256k1_fe bn = *b; + secp256k1_fe_normalize_weak(&an); + return secp256k1_fe_equal(&an, &bn); +} + +static void run_field_convert(void) { + static const unsigned char b32[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 + }; + static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + static const secp256k1_fe fe = SECP256K1_FE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + secp256k1_fe fe2; + unsigned char b322[32]; + secp256k1_fe_storage fes2; + /* Check conversions to fe. */ + CHECK(secp256k1_fe_set_b32_limit(&fe2, b32)); + CHECK(secp256k1_fe_equal(&fe, &fe2)); + secp256k1_fe_from_storage(&fe2, &fes); + CHECK(secp256k1_fe_equal(&fe, &fe2)); + /* Check conversion from fe. */ + secp256k1_fe_get_b32(b322, &fe); + CHECK(secp256k1_memcmp_var(b322, b32, 32) == 0); + secp256k1_fe_to_storage(&fes2, &fe); + CHECK(secp256k1_memcmp_var(&fes2, &fes, sizeof(fes)) == 0); +} + +static void run_field_be32_overflow(void) { + { + static const unsigned char zero_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, + }; + static const unsigned char zero[32] = { 0x00 }; + unsigned char out[32]; + secp256k1_fe fe; + CHECK(secp256k1_fe_set_b32_limit(&fe, zero_overflow) == 0); + secp256k1_fe_set_b32_mod(&fe, zero_overflow); + CHECK(secp256k1_fe_normalizes_to_zero(&fe) == 1); + secp256k1_fe_normalize(&fe); + CHECK(secp256k1_fe_is_zero(&fe) == 1); + secp256k1_fe_get_b32(out, &fe); + CHECK(secp256k1_memcmp_var(out, zero, 32) == 0); + } + { + static const unsigned char one_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30, + }; + static const unsigned char one[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + unsigned char out[32]; + secp256k1_fe fe; + CHECK(secp256k1_fe_set_b32_limit(&fe, one_overflow) == 0); + secp256k1_fe_set_b32_mod(&fe, one_overflow); + secp256k1_fe_normalize(&fe); + CHECK(secp256k1_fe_cmp_var(&fe, &secp256k1_fe_one) == 0); + secp256k1_fe_get_b32(out, &fe); + CHECK(secp256k1_memcmp_var(out, one, 32) == 0); + } + { + static const unsigned char ff_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }; + static const unsigned char ff[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xD0, + }; + unsigned char out[32]; + secp256k1_fe fe; + const secp256k1_fe fe_ff = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0x01, 0x000003d0); + CHECK(secp256k1_fe_set_b32_limit(&fe, ff_overflow) == 0); + secp256k1_fe_set_b32_mod(&fe, ff_overflow); + secp256k1_fe_normalize(&fe); + CHECK(secp256k1_fe_cmp_var(&fe, &fe_ff) == 0); + secp256k1_fe_get_b32(out, &fe); + CHECK(secp256k1_memcmp_var(out, ff, 32) == 0); + } +} + +/* Returns true if two field elements have the same representation. */ +static int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) { + int ret = 1; + /* Compare the struct member that holds the limbs. */ + ret &= (secp256k1_memcmp_var(a->n, b->n, sizeof(a->n)) == 0); + return ret; +} + +static void run_field_half(void) { + secp256k1_fe t, u; + int m; + + /* Check magnitude 0 input */ + secp256k1_fe_get_bounds(&t, 0); + secp256k1_fe_half(&t); +#ifdef VERIFY + CHECK(t.magnitude == 1); + CHECK(t.normalized == 0); +#endif + CHECK(secp256k1_fe_normalizes_to_zero(&t)); + + /* Check non-zero magnitudes in the supported range */ + for (m = 1; m < 32; m++) { + /* Check max-value input */ + secp256k1_fe_get_bounds(&t, m); + + u = t; + secp256k1_fe_half(&u); +#ifdef VERIFY + CHECK(u.magnitude == (m >> 1) + 1); + CHECK(u.normalized == 0); +#endif + secp256k1_fe_normalize_weak(&u); + secp256k1_fe_add(&u, &u); + CHECK(fe_equal(&t, &u)); + + /* Check worst-case input: ensure the LSB is 1 so that P will be added, + * which will also cause all carries to be 1, since all limbs that can + * generate a carry are initially even and all limbs of P are odd in + * every existing field implementation. */ + secp256k1_fe_get_bounds(&t, m); + CHECK(t.n[0] > 0); + CHECK((t.n[0] & 1) == 0); + --t.n[0]; + + u = t; + secp256k1_fe_half(&u); +#ifdef VERIFY + CHECK(u.magnitude == (m >> 1) + 1); + CHECK(u.normalized == 0); +#endif + secp256k1_fe_normalize_weak(&u); + secp256k1_fe_add(&u, &u); + CHECK(fe_equal(&t, &u)); + } +} + +static void run_field_misc(void) { + secp256k1_fe x; + secp256k1_fe y; + secp256k1_fe z; + secp256k1_fe q; + int v; + secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); + int i, j; + for (i = 0; i < 1000 * COUNT; i++) { + secp256k1_fe_storage xs, ys, zs; + if (i & 1) { + testutil_random_fe(&x); + } else { + testutil_random_fe_test(&x); + } + testutil_random_fe_non_zero(&y); + v = testrand_bits(15); + /* Test that fe_add_int is equivalent to fe_set_int + fe_add. */ + secp256k1_fe_set_int(&q, v); /* q = v */ + z = x; /* z = x */ + secp256k1_fe_add(&z, &q); /* z = x+v */ + q = x; /* q = x */ + secp256k1_fe_add_int(&q, v); /* q = x+v */ + CHECK(fe_equal(&q, &z)); + /* Test the fe equality and comparison operations. */ + CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); + CHECK(secp256k1_fe_equal(&x, &x)); + z = x; + secp256k1_fe_add(&z,&y); + /* Test fe conditional move; z is not normalized here. */ + q = x; + secp256k1_fe_cmov(&x, &z, 0); +#ifdef VERIFY + CHECK(!x.normalized); + CHECK((x.magnitude == q.magnitude) || (x.magnitude == z.magnitude)); + CHECK((x.magnitude >= q.magnitude) && (x.magnitude >= z.magnitude)); +#endif + x = q; + secp256k1_fe_cmov(&x, &x, 1); + CHECK(!fe_identical(&x, &z)); + CHECK(fe_identical(&x, &q)); + secp256k1_fe_cmov(&q, &z, 1); +#ifdef VERIFY + CHECK(!q.normalized); + CHECK((q.magnitude == x.magnitude) || (q.magnitude == z.magnitude)); + CHECK((q.magnitude >= x.magnitude) && (q.magnitude >= z.magnitude)); +#endif + CHECK(fe_identical(&q, &z)); + q = z; + secp256k1_fe_normalize_var(&x); + secp256k1_fe_normalize_var(&z); + CHECK(!secp256k1_fe_equal(&x, &z)); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (i&1)); +#ifdef VERIFY + CHECK(q.normalized && q.magnitude == 1); +#endif + for (j = 0; j < 6; j++) { + secp256k1_fe_negate_unchecked(&z, &z, j+1); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (j&1)); +#ifdef VERIFY + CHECK(!q.normalized && q.magnitude == z.magnitude); +#endif + } + secp256k1_fe_normalize_var(&z); + /* Test storage conversion and conditional moves. */ + secp256k1_fe_to_storage(&xs, &x); + secp256k1_fe_to_storage(&ys, &y); + secp256k1_fe_to_storage(&zs, &z); + secp256k1_fe_storage_cmov(&zs, &xs, 0); + secp256k1_fe_storage_cmov(&zs, &zs, 1); + CHECK(secp256k1_memcmp_var(&xs, &zs, sizeof(xs)) != 0); + secp256k1_fe_storage_cmov(&ys, &xs, 1); + CHECK(secp256k1_memcmp_var(&xs, &ys, sizeof(xs)) == 0); + secp256k1_fe_from_storage(&x, &xs); + secp256k1_fe_from_storage(&y, &ys); + secp256k1_fe_from_storage(&z, &zs); + /* Test that mul_int, mul, and add agree. */ + secp256k1_fe_add(&y, &x); + secp256k1_fe_add(&y, &x); + z = x; + secp256k1_fe_mul_int(&z, 3); + CHECK(fe_equal(&y, &z)); + secp256k1_fe_add(&y, &x); + secp256k1_fe_add(&z, &x); + CHECK(fe_equal(&z, &y)); + z = x; + secp256k1_fe_mul_int(&z, 5); + secp256k1_fe_mul(&q, &x, &fe5); + CHECK(fe_equal(&z, &q)); + secp256k1_fe_negate(&x, &x, 1); + secp256k1_fe_add(&z, &x); + secp256k1_fe_add(&q, &x); + CHECK(fe_equal(&y, &z)); + CHECK(fe_equal(&q, &y)); + /* Check secp256k1_fe_half. */ + z = x; + secp256k1_fe_half(&z); + secp256k1_fe_add(&z, &z); + CHECK(fe_equal(&x, &z)); + secp256k1_fe_add(&z, &z); + secp256k1_fe_half(&z); + CHECK(fe_equal(&x, &z)); + } +} + +static void test_fe_mul(const secp256k1_fe* a, const secp256k1_fe* b, int use_sqr) +{ + secp256k1_fe c, an, bn; + /* Variables in BE 32-byte format. */ + unsigned char a32[32], b32[32], c32[32]; + /* Variables in LE 16x uint16_t format. */ + uint16_t a16[16], b16[16], c16[16]; + /* Field modulus in LE 16x uint16_t format. */ + static const uint16_t m16[16] = { + 0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + }; + uint16_t t16[32]; + int i; + + /* Compute C = A * B in fe format. */ + c = *a; + if (use_sqr) { + secp256k1_fe_sqr(&c, &c); + } else { + secp256k1_fe_mul(&c, &c, b); + } + + /* Convert A, B, C into LE 16x uint16_t format. */ + an = *a; + bn = *b; + secp256k1_fe_normalize_var(&c); + secp256k1_fe_normalize_var(&an); + secp256k1_fe_normalize_var(&bn); + secp256k1_fe_get_b32(a32, &an); + secp256k1_fe_get_b32(b32, &bn); + secp256k1_fe_get_b32(c32, &c); + for (i = 0; i < 16; ++i) { + a16[i] = a32[31 - 2*i] + ((uint16_t)a32[30 - 2*i] << 8); + b16[i] = b32[31 - 2*i] + ((uint16_t)b32[30 - 2*i] << 8); + c16[i] = c32[31 - 2*i] + ((uint16_t)c32[30 - 2*i] << 8); + } + /* Compute T = A * B in LE 16x uint16_t format. */ + mulmod256(t16, a16, b16, m16); + /* Compare */ + CHECK(secp256k1_memcmp_var(t16, c16, 32) == 0); +} + +static void run_fe_mul(void) { + int i; + for (i = 0; i < 100 * COUNT; ++i) { + secp256k1_fe a, b, c, d; + testutil_random_fe(&a); + testutil_random_fe_magnitude(&a, 8); + testutil_random_fe(&b); + testutil_random_fe_magnitude(&b, 8); + testutil_random_fe_test(&c); + testutil_random_fe_magnitude(&c, 8); + testutil_random_fe_test(&d); + testutil_random_fe_magnitude(&d, 8); + test_fe_mul(&a, &a, 1); + test_fe_mul(&c, &c, 1); + test_fe_mul(&a, &b, 0); + test_fe_mul(&a, &c, 0); + test_fe_mul(&c, &b, 0); + test_fe_mul(&c, &d, 0); + } +} + +static void run_sqr(void) { + int i; + secp256k1_fe x, y, lhs, rhs, tmp; + + secp256k1_fe_set_int(&x, 1); + secp256k1_fe_negate(&x, &x, 1); + + for (i = 1; i <= 512; ++i) { + secp256k1_fe_mul_int(&x, 2); + secp256k1_fe_normalize(&x); + + /* Check that (x+y)*(x-y) = x^2 - y*2 for some random values y */ + testutil_random_fe_test(&y); + + lhs = x; + secp256k1_fe_add(&lhs, &y); /* lhs = x+y */ + secp256k1_fe_negate(&tmp, &y, 1); /* tmp = -y */ + secp256k1_fe_add(&tmp, &x); /* tmp = x-y */ + secp256k1_fe_mul(&lhs, &lhs, &tmp); /* lhs = (x+y)*(x-y) */ + + secp256k1_fe_sqr(&rhs, &x); /* rhs = x^2 */ + secp256k1_fe_sqr(&tmp, &y); /* tmp = y^2 */ + secp256k1_fe_negate(&tmp, &tmp, 1); /* tmp = -y^2 */ + secp256k1_fe_add(&rhs, &tmp); /* rhs = x^2 - y^2 */ + + CHECK(fe_equal(&lhs, &rhs)); + } +} + +static void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { + secp256k1_fe r1, r2; + int v = secp256k1_fe_sqrt(&r1, a); + CHECK((v == 0) == (k == NULL)); + + if (k != NULL) { + /* Check that the returned root is +/- the given known answer */ + secp256k1_fe_negate(&r2, &r1, 1); + secp256k1_fe_add(&r1, k); secp256k1_fe_add(&r2, k); + secp256k1_fe_normalize(&r1); secp256k1_fe_normalize(&r2); + CHECK(secp256k1_fe_is_zero(&r1) || secp256k1_fe_is_zero(&r2)); + } +} + +static void run_sqrt(void) { + secp256k1_fe ns, x, s, t; + int i; + + /* Check sqrt(0) is 0 */ + secp256k1_fe_set_int(&x, 0); + secp256k1_fe_sqr(&s, &x); + test_sqrt(&s, &x); + + /* Check sqrt of small squares (and their negatives) */ + for (i = 1; i <= 100; i++) { + secp256k1_fe_set_int(&x, i); + secp256k1_fe_sqr(&s, &x); + test_sqrt(&s, &x); + secp256k1_fe_negate(&t, &s, 1); + test_sqrt(&t, NULL); + } + + /* Consistency checks for large random values */ + for (i = 0; i < 10; i++) { + int j; + random_fe_non_square(&ns); + for (j = 0; j < COUNT; j++) { + testutil_random_fe(&x); + secp256k1_fe_sqr(&s, &x); + CHECK(secp256k1_fe_is_square_var(&s)); + test_sqrt(&s, &x); + secp256k1_fe_negate(&t, &s, 1); + CHECK(!secp256k1_fe_is_square_var(&t)); + test_sqrt(&t, NULL); + secp256k1_fe_mul(&t, &s, &ns); + test_sqrt(&t, NULL); + } + } +} + +/***** FIELD/SCALAR INVERSE TESTS *****/ + +static const secp256k1_scalar scalar_minus_one = SECP256K1_SCALAR_CONST( + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, + 0xBAAEDCE6, 0xAF48A03B, 0xBFD25E8C, 0xD0364140 +); + +static const secp256k1_fe fe_minus_one = SECP256K1_FE_CONST( + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFC2E +); + +/* These tests test the following identities: + * + * for x==0: 1/x == 0 + * for x!=0: x*(1/x) == 1 + * for x!=0 and x!=1: 1/(1/x - 1) + 1 == -1/(x-1) + */ + +static void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int var) +{ + secp256k1_scalar l, r, t; + + (var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse)(&l, x); /* l = 1/x */ + if (out) *out = l; + if (secp256k1_scalar_is_zero(x)) { + CHECK(secp256k1_scalar_is_zero(&l)); + return; + } + secp256k1_scalar_mul(&t, x, &l); /* t = x*(1/x) */ + CHECK(secp256k1_scalar_is_one(&t)); /* x*(1/x) == 1 */ + secp256k1_scalar_add(&r, x, &scalar_minus_one); /* r = x-1 */ + if (secp256k1_scalar_is_zero(&r)) return; + (var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse)(&r, &r); /* r = 1/(x-1) */ + secp256k1_scalar_add(&l, &scalar_minus_one, &l); /* l = 1/x-1 */ + (var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse)(&l, &l); /* l = 1/(1/x-1) */ + secp256k1_scalar_add(&l, &l, &secp256k1_scalar_one); /* l = 1/(1/x-1)+1 */ + secp256k1_scalar_add(&l, &r, &l); /* l = 1/(1/x-1)+1 + 1/(x-1) */ + CHECK(secp256k1_scalar_is_zero(&l)); /* l == 0 */ +} + +static void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var) +{ + secp256k1_fe l, r, t; + + (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, x) ; /* l = 1/x */ + if (out) *out = l; + t = *x; /* t = x */ + if (secp256k1_fe_normalizes_to_zero_var(&t)) { + CHECK(secp256k1_fe_normalizes_to_zero(&l)); + return; + } + secp256k1_fe_mul(&t, x, &l); /* t = x*(1/x) */ + secp256k1_fe_add(&t, &fe_minus_one); /* t = x*(1/x)-1 */ + CHECK(secp256k1_fe_normalizes_to_zero(&t)); /* x*(1/x)-1 == 0 */ + r = *x; /* r = x */ + secp256k1_fe_add(&r, &fe_minus_one); /* r = x-1 */ + if (secp256k1_fe_normalizes_to_zero_var(&r)) return; + (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&r, &r); /* r = 1/(x-1) */ + secp256k1_fe_add(&l, &fe_minus_one); /* l = 1/x-1 */ + (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, &l); /* l = 1/(1/x-1) */ + secp256k1_fe_add_int(&l, 1); /* l = 1/(1/x-1)+1 */ + secp256k1_fe_add(&l, &r); /* l = 1/(1/x-1)+1 + 1/(x-1) */ + CHECK(secp256k1_fe_normalizes_to_zero_var(&l)); /* l == 0 */ +} + +static void run_inverse_tests(void) +{ + /* Fixed test cases for field inverses: pairs of (x, 1/x) mod p. */ + static const secp256k1_fe fe_cases[][2] = { + /* 0 */ + {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), + SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}, + /* 1 */ + {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), + SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1)}, + /* -1 */ + {SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc2e), + SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc2e)}, + /* 2 */ + {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2), + SECP256K1_FE_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffe18)}, + /* 2**128 */ + {SECP256K1_FE_CONST(0, 0, 0, 1, 0, 0, 0, 0), + SECP256K1_FE_CONST(0xbcb223fe, 0xdc24a059, 0xd838091d, 0xd2253530, 0xffffffff, 0xffffffff, 0xffffffff, 0x434dd931)}, + /* Input known to need 637 divsteps */ + {SECP256K1_FE_CONST(0xe34e9c95, 0x6bee8a84, 0x0dcb632a, 0xdb8a1320, 0x66885408, 0x06f3f996, 0x7c11ca84, 0x19199ec3), + SECP256K1_FE_CONST(0xbd2cbd8f, 0x1c536828, 0x9bccda44, 0x2582ac0c, 0x870152b0, 0x8a3f09fb, 0x1aaadf92, 0x19b618e5)}, + /* Input known to need 567 divsteps starting with delta=1/2. */ + {SECP256K1_FE_CONST(0xf6bc3ba3, 0x636451c4, 0x3e46357d, 0x2c21d619, 0x0988e234, 0x15985661, 0x6672982b, 0xa7549bfc), + SECP256K1_FE_CONST(0xb024fdc7, 0x5547451e, 0x426c585f, 0xbd481425, 0x73df6b75, 0xeef6d9d0, 0x389d87d4, 0xfbb440ba)}, + /* Input known to need 566 divsteps starting with delta=1/2. */ + {SECP256K1_FE_CONST(0xb595d81b, 0x2e3c1e2f, 0x482dbc65, 0xe4865af7, 0x9a0a50aa, 0x29f9e618, 0x6f87d7a5, 0x8d1063ae), + SECP256K1_FE_CONST(0xc983337c, 0x5d5c74e1, 0x49918330, 0x0b53afb5, 0xa0428a0b, 0xce6eef86, 0x059bd8ef, 0xe5b908de)}, + /* Set of 10 inputs accessing all 128 entries in the modinv32 divsteps_var table */ + {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0xe0ff1f80, 0x1f000000, 0x00000000, 0x00000000, 0xfeff0100, 0x00000000), + SECP256K1_FE_CONST(0x9faf9316, 0x77e5049d, 0x0b5e7a1b, 0xef70b893, 0x18c9e30c, 0x045e7fd7, 0x29eddf8c, 0xd62e9e3d)}, + {SECP256K1_FE_CONST(0x621a538d, 0x511b2780, 0x35688252, 0x53f889a4, 0x6317c3ac, 0x32ba0a46, 0x6277c0d1, 0xccd31192), + SECP256K1_FE_CONST(0x38513b0c, 0x5eba856f, 0xe29e882e, 0x9b394d8c, 0x34bda011, 0xeaa66943, 0x6a841a4c, 0x6ae8bcff)}, + {SECP256K1_FE_CONST(0x00000200, 0xf0ffff1f, 0x00000000, 0x0000e0ff, 0xffffffff, 0xfffcffff, 0xffffffff, 0xffff0100), + SECP256K1_FE_CONST(0x5da42a52, 0x3640de9e, 0x13e64343, 0x0c7591b7, 0x6c1e3519, 0xf048c5b6, 0x0484217c, 0xedbf8b2f)}, + {SECP256K1_FE_CONST(0xd1343ef9, 0x4b952621, 0x7c52a2ee, 0x4ea1281b, 0x4ab46410, 0x9f26998d, 0xa686a8ff, 0x9f2103e8), + SECP256K1_FE_CONST(0x84044385, 0x9a4619bf, 0x74e35b6d, 0xa47e0c46, 0x6b7fb47d, 0x9ffab128, 0xb0775aa3, 0xcb318bd1)}, + {SECP256K1_FE_CONST(0xb27235d2, 0xc56a52be, 0x210db37a, 0xd50d23a4, 0xbe621bdd, 0x5df22c6a, 0xe926ba62, 0xd2e4e440), + SECP256K1_FE_CONST(0x67a26e54, 0x483a9d3c, 0xa568469e, 0xd258ab3d, 0xb9ec9981, 0xdca9b1bd, 0x8d2775fe, 0x53ae429b)}, + {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00e0ffff, 0xffffff83, 0xffffffff, 0x3f00f00f, 0x000000e0, 0xffffffff), + SECP256K1_FE_CONST(0x310e10f8, 0x23bbfab0, 0xac94907d, 0x076c9a45, 0x8d357d7f, 0xc763bcee, 0x00d0e615, 0x5a6acef6)}, + {SECP256K1_FE_CONST(0xfeff0300, 0x001c0000, 0xf80700c0, 0x0ff0ffff, 0xffffffff, 0x0fffffff, 0xffff0100, 0x7f0000fe), + SECP256K1_FE_CONST(0x28e2fdb4, 0x0709168b, 0x86f598b0, 0x3453a370, 0x530cf21f, 0x32f978d5, 0x1d527a71, 0x59269b0c)}, + {SECP256K1_FE_CONST(0xc2591afa, 0x7bb98ef7, 0x090bb273, 0x85c14f87, 0xbb0b28e0, 0x54d3c453, 0x85c66753, 0xd5574d2f), + SECP256K1_FE_CONST(0xfdca70a2, 0x70ce627c, 0x95e66fae, 0x848a6dbb, 0x07ffb15c, 0x5f63a058, 0xba4140ed, 0x6113b503)}, + {SECP256K1_FE_CONST(0xf5475db3, 0xedc7b5a3, 0x411c047e, 0xeaeb452f, 0xc625828e, 0x1cf5ad27, 0x8eec1060, 0xc7d3e690), + SECP256K1_FE_CONST(0x5eb756c0, 0xf963f4b9, 0xdc6a215e, 0xec8cc2d8, 0x2e9dec01, 0xde5eb88d, 0x6aba7164, 0xaecb2c5a)}, + {SECP256K1_FE_CONST(0x00000000, 0x00f8ffff, 0xffffffff, 0x01000000, 0xe0ff1f00, 0x00000000, 0xffffff7f, 0x00000000), + SECP256K1_FE_CONST(0xe0d2e3d8, 0x49b6157d, 0xe54e88c2, 0x1a7f02ca, 0x7dd28167, 0xf1125d81, 0x7bfa444e, 0xbe110037)}, + /* Selection of randomly generated inputs that reach high/low d/e values in various configurations. */ + {SECP256K1_FE_CONST(0x13cc08a4, 0xd8c41f0f, 0x179c3e67, 0x54c46c67, 0xc4109221, 0x09ab3b13, 0xe24d9be1, 0xffffe950), + SECP256K1_FE_CONST(0xb80c8006, 0xd16abaa7, 0xcabd71e5, 0xcf6714f4, 0x966dd3d0, 0x64767a2d, 0xe92c4441, 0x51008cd1)}, + {SECP256K1_FE_CONST(0xaa6db990, 0x95efbca1, 0x3cc6ff71, 0x0602e24a, 0xf49ff938, 0x99fffc16, 0x46f40993, 0xc6e72057), + SECP256K1_FE_CONST(0xd5d3dd69, 0xb0c195e5, 0x285f1d49, 0xe639e48c, 0x9223f8a9, 0xca1d731d, 0x9ca482f9, 0xa5b93e06)}, + {SECP256K1_FE_CONST(0x1c680eac, 0xaeabffd8, 0x9bdc4aee, 0x1781e3de, 0xa3b08108, 0x0015f2e0, 0x94449e1b, 0x2f67a058), + SECP256K1_FE_CONST(0x7f083f8d, 0x31254f29, 0x6510f475, 0x245c373d, 0xc5622590, 0x4b323393, 0x32ed1719, 0xc127444b)}, + {SECP256K1_FE_CONST(0x147d44b3, 0x012d83f8, 0xc160d386, 0x1a44a870, 0x9ba6be96, 0x8b962707, 0x267cbc1a, 0xb65b2f0a), + SECP256K1_FE_CONST(0x555554ff, 0x170aef1e, 0x50a43002, 0xe51fbd36, 0xafadb458, 0x7a8aded1, 0x0ca6cd33, 0x6ed9087c)}, + {SECP256K1_FE_CONST(0x12423796, 0x22f0fe61, 0xf9ca017c, 0x5384d107, 0xa1fbf3b2, 0x3b018013, 0x916a3c37, 0x4000b98c), + SECP256K1_FE_CONST(0x20257700, 0x08668f94, 0x1177e306, 0x136c01f5, 0x8ed1fbd2, 0x95ec4589, 0xae38edb9, 0xfd19b6d7)}, + {SECP256K1_FE_CONST(0xdcf2d030, 0x9ab42cb4, 0x93ffa181, 0xdcd23619, 0x39699b52, 0x08909a20, 0xb5a17695, 0x3a9dcf21), + SECP256K1_FE_CONST(0x1f701dea, 0xe211fb1f, 0x4f37180d, 0x63a0f51c, 0x29fe1e40, 0xa40b6142, 0x2e7b12eb, 0x982b06b6)}, + {SECP256K1_FE_CONST(0x79a851f6, 0xa6314ed3, 0xb35a55e6, 0xca1c7d7f, 0xe32369ea, 0xf902432e, 0x375308c5, 0xdfd5b600), + SECP256K1_FE_CONST(0xcaae00c5, 0xe6b43851, 0x9dabb737, 0x38cba42c, 0xa02c8549, 0x7895dcbf, 0xbd183d71, 0xafe4476a)}, + {SECP256K1_FE_CONST(0xede78fdd, 0xcfc92bf1, 0x4fec6c6c, 0xdb8d37e2, 0xfb66bc7b, 0x28701870, 0x7fa27c9a, 0x307196ec), + SECP256K1_FE_CONST(0x68193a6c, 0x9a8b87a7, 0x2a760c64, 0x13e473f6, 0x23ae7bed, 0x1de05422, 0x88865427, 0xa3418265)}, + {SECP256K1_FE_CONST(0xa40b2079, 0xb8f88e89, 0xa7617997, 0x89baf5ae, 0x174df343, 0x75138eae, 0x2711595d, 0x3fc3e66c), + SECP256K1_FE_CONST(0x9f99c6a5, 0x6d685267, 0xd4b87c37, 0x9d9c4576, 0x358c692b, 0x6bbae0ed, 0x3389c93d, 0x7fdd2655)}, + {SECP256K1_FE_CONST(0x7c74c6b6, 0xe98d9151, 0x72645cf1, 0x7f06e321, 0xcefee074, 0x15b2113a, 0x10a9be07, 0x08a45696), + SECP256K1_FE_CONST(0x8c919a88, 0x898bc1e0, 0x77f26f97, 0x12e655b7, 0x9ba0ac40, 0xe15bb19e, 0x8364cc3b, 0xe227a8ee)}, + {SECP256K1_FE_CONST(0x109ba1ce, 0xdafa6d4a, 0xa1cec2b2, 0xeb1069f4, 0xb7a79e5b, 0xec6eb99b, 0xaec5f643, 0xee0e723e), + SECP256K1_FE_CONST(0x93d13eb8, 0x4bb0bcf9, 0xe64f5a71, 0xdbe9f359, 0x7191401c, 0x6f057a4a, 0xa407fe1b, 0x7ecb65cc)}, + {SECP256K1_FE_CONST(0x3db076cd, 0xec74a5c9, 0xf61dd138, 0x90e23e06, 0xeeedd2d0, 0x74cbc4e0, 0x3dbe1e91, 0xded36a78), + SECP256K1_FE_CONST(0x3f07f966, 0x8e2a1e09, 0x706c71df, 0x02b5e9d5, 0xcb92ddbf, 0xcdd53010, 0x16545564, 0xe660b107)}, + {SECP256K1_FE_CONST(0xe31c73ed, 0xb4c4b82c, 0x02ae35f7, 0x4cdec153, 0x98b522fd, 0xf7d2460c, 0x6bf7c0f8, 0x4cf67b0d), + SECP256K1_FE_CONST(0x4b8f1faf, 0x94e8b070, 0x19af0ff6, 0xa319cd31, 0xdf0a7ffb, 0xefaba629, 0x59c50666, 0x1fe5b843)}, + {SECP256K1_FE_CONST(0x4c8b0e6e, 0x83392ab6, 0xc0e3e9f1, 0xbbd85497, 0x16698897, 0xf552d50d, 0x79652ddb, 0x12f99870), + SECP256K1_FE_CONST(0x56d5101f, 0xd23b7949, 0x17dc38d6, 0xf24022ef, 0xcf18e70a, 0x5cc34424, 0x438544c3, 0x62da4bca)}, + {SECP256K1_FE_CONST(0xb0e040e2, 0x40cc35da, 0x7dd5c611, 0x7fccb178, 0x28888137, 0xbc930358, 0xea2cbc90, 0x775417dc), + SECP256K1_FE_CONST(0xca37f0d4, 0x016dd7c8, 0xab3ae576, 0x96e08d69, 0x68ed9155, 0xa9b44270, 0x900ae35d, 0x7c7800cd)}, + {SECP256K1_FE_CONST(0x8a32ea49, 0x7fbb0bae, 0x69724a9d, 0x8e2105b2, 0xbdf69178, 0x862577ef, 0x35055590, 0x667ddaef), + SECP256K1_FE_CONST(0xd02d7ead, 0xc5e190f0, 0x559c9d72, 0xdaef1ffc, 0x64f9f425, 0xf43645ea, 0x7341e08d, 0x11768e96)}, + {SECP256K1_FE_CONST(0xa3592d98, 0x9abe289d, 0x579ebea6, 0xbb0857a8, 0xe242ab73, 0x85f9a2ce, 0xb6998f0f, 0xbfffbfc6), + SECP256K1_FE_CONST(0x093c1533, 0x32032efa, 0x6aa46070, 0x0039599e, 0x589c35f4, 0xff525430, 0x7fe3777a, 0x44b43ddc)}, + {SECP256K1_FE_CONST(0x647178a3, 0x229e607b, 0xcc98521a, 0xcce3fdd9, 0x1e1bc9c9, 0x97fb7c6a, 0x61b961e0, 0x99b10709), + SECP256K1_FE_CONST(0x98217c13, 0xd51ddf78, 0x96310e77, 0xdaebd908, 0x602ca683, 0xcb46d07a, 0xa1fcf17e, 0xc8e2feb3)}, + {SECP256K1_FE_CONST(0x7334627c, 0x73f98968, 0x99464b4b, 0xf5964958, 0x1b95870d, 0xc658227e, 0x5e3235d8, 0xdcab5787), + SECP256K1_FE_CONST(0x000006fd, 0xc7e9dd94, 0x40ae367a, 0xe51d495c, 0x07603b9b, 0x2d088418, 0x6cc5c74c, 0x98514307)}, + {SECP256K1_FE_CONST(0x82e83876, 0x96c28938, 0xa50dd1c5, 0x605c3ad1, 0xc048637d, 0x7a50825f, 0x335ed01a, 0x00005760), + SECP256K1_FE_CONST(0xb0393f9f, 0x9f2aa55e, 0xf5607e2e, 0x5287d961, 0x60b3e704, 0xf3e16e80, 0xb4f9a3ea, 0xfec7f02d)}, + {SECP256K1_FE_CONST(0xc97b6cec, 0x3ee6b8dc, 0x98d24b58, 0x3c1970a1, 0xfe06297a, 0xae813529, 0xe76bb6bd, 0x771ae51d), + SECP256K1_FE_CONST(0x0507c702, 0xd407d097, 0x47ddeb06, 0xf6625419, 0x79f48f79, 0x7bf80d0b, 0xfc34b364, 0x253a5db1)}, + {SECP256K1_FE_CONST(0xd559af63, 0x77ea9bc4, 0x3cf1ad14, 0x5c7a4bbb, 0x10e7d18b, 0x7ce0dfac, 0x380bb19d, 0x0bb99bd3), + SECP256K1_FE_CONST(0x00196119, 0xb9b00d92, 0x34edfdb5, 0xbbdc42fc, 0xd2daa33a, 0x163356ca, 0xaa8754c8, 0xb0ec8b0b)}, + {SECP256K1_FE_CONST(0x8ddfa3dc, 0x52918da0, 0x640519dc, 0x0af8512a, 0xca2d33b2, 0xbde52514, 0xda9c0afc, 0xcb29fce4), + SECP256K1_FE_CONST(0xb3e4878d, 0x5cb69148, 0xcd54388b, 0xc23acce0, 0x62518ba8, 0xf09def92, 0x7b31e6aa, 0x6ba35b02)}, + {SECP256K1_FE_CONST(0xf8207492, 0xe3049f0a, 0x65285f2b, 0x0bfff996, 0x00ca112e, 0xc05da837, 0x546d41f9, 0x5194fb91), + SECP256K1_FE_CONST(0x7b7ee50b, 0xa8ed4bbd, 0xf6469930, 0x81419a5c, 0x071441c7, 0x290d046e, 0x3b82ea41, 0x611c5f95)}, + {SECP256K1_FE_CONST(0x050f7c80, 0x5bcd3c6b, 0x823cb724, 0x5ce74db7, 0xa4e39f5c, 0xbd8828d7, 0xfd4d3e07, 0x3ec2926a), + SECP256K1_FE_CONST(0x000d6730, 0xb0171314, 0x4764053d, 0xee157117, 0x48fd61da, 0xdea0b9db, 0x1d5e91c6, 0xbdc3f59e)}, + {SECP256K1_FE_CONST(0x3e3ea8eb, 0x05d760cf, 0x23009263, 0xb3cb3ac9, 0x088f6f0d, 0x3fc182a3, 0xbd57087c, 0xe67c62f9), + SECP256K1_FE_CONST(0xbe988716, 0xa29c1bf6, 0x4456aed6, 0xab1e4720, 0x49929305, 0x51043bf4, 0xebd833dd, 0xdd511e8b)}, + {SECP256K1_FE_CONST(0x6964d2a9, 0xa7fa6501, 0xa5959249, 0x142f4029, 0xea0c1b5f, 0x2f487ef6, 0x301ac80a, 0x768be5cd), + SECP256K1_FE_CONST(0x3918ffe4, 0x07492543, 0xed24d0b7, 0x3df95f8f, 0xaffd7cb4, 0x0de2191c, 0x9ec2f2ad, 0x2c0cb3c6)}, + {SECP256K1_FE_CONST(0x37c93520, 0xf6ddca57, 0x2b42fd5e, 0xb5c7e4de, 0x11b5b81c, 0xb95e91f3, 0x95c4d156, 0x39877ccb), + SECP256K1_FE_CONST(0x9a94b9b5, 0x57eb71ee, 0x4c975b8b, 0xac5262a8, 0x077b0595, 0xe12a6b1f, 0xd728edef, 0x1a6bf956)} + }; + /* Fixed test cases for scalar inverses: pairs of (x, 1/x) mod n. */ + static const secp256k1_scalar scalar_cases[][2] = { + /* 0 */ + {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0), + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0)}, + /* 1 */ + {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1), + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1)}, + /* -1 */ + {SECP256K1_SCALAR_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xbaaedce6, 0xaf48a03b, 0xbfd25e8c, 0xd0364140), + SECP256K1_SCALAR_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xbaaedce6, 0xaf48a03b, 0xbfd25e8c, 0xd0364140)}, + /* 2 */ + {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 2), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x5d576e73, 0x57a4501d, 0xdfe92f46, 0x681b20a1)}, + /* 2**128 */ + {SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0), + SECP256K1_SCALAR_CONST(0x50a51ac8, 0x34b9ec24, 0x4b0dff66, 0x5588b13e, 0x9984d5b3, 0xcf80ef0f, 0xd6a23766, 0xa3ee9f22)}, + /* Input known to need 635 divsteps */ + {SECP256K1_SCALAR_CONST(0xcb9f1d35, 0xdd4416c2, 0xcd71bf3f, 0x6365da66, 0x3c9b3376, 0x8feb7ae9, 0x32a5ef60, 0x19199ec3), + SECP256K1_SCALAR_CONST(0x1d7c7bba, 0xf1893d53, 0xb834bd09, 0x36b411dc, 0x42c2e42f, 0xec72c428, 0x5e189791, 0x8e9bc708)}, + /* Input known to need 566 divsteps starting with delta=1/2. */ + {SECP256K1_SCALAR_CONST(0x7e3c993d, 0xa4272488, 0xbc015b49, 0x2db54174, 0xd382083a, 0xebe6db35, 0x80f82eff, 0xcd132c72), + SECP256K1_SCALAR_CONST(0x086f34a0, 0x3e631f76, 0x77418f28, 0xcc84ac95, 0x6304439d, 0x365db268, 0x312c6ded, 0xd0b934f8)}, + /* Input known to need 565 divsteps starting with delta=1/2. */ + {SECP256K1_SCALAR_CONST(0xbad7e587, 0x3f307859, 0x60d93147, 0x8a18491e, 0xb38a9fd5, 0x254350d3, 0x4b1f0e4b, 0x7dd6edc4), + SECP256K1_SCALAR_CONST(0x89f2df26, 0x39e2b041, 0xf19bd876, 0xd039c8ac, 0xc2223add, 0x29c4943e, 0x6632d908, 0x515f467b)}, + /* Selection of randomly generated inputs that reach low/high d/e values in various configurations. */ + {SECP256K1_SCALAR_CONST(0x1950d757, 0xb37a5809, 0x435059bb, 0x0bb8997e, 0x07e1e3c8, 0x5e5d7d2c, 0x6a0ed8e3, 0xdbde180e), + SECP256K1_SCALAR_CONST(0xbf72af9b, 0x750309e2, 0x8dda230b, 0xfe432b93, 0x7e25e475, 0x4388251e, 0x633d894b, 0x3bcb6f8c)}, + {SECP256K1_SCALAR_CONST(0x9bccf4e7, 0xc5a515e3, 0x50637aa9, 0xbb65a13f, 0x391749a1, 0x62de7d4e, 0xf6d7eabb, 0x3cd10ce0), + SECP256K1_SCALAR_CONST(0xaf2d5623, 0xb6385a33, 0xcd0365be, 0x5e92a70d, 0x7f09179c, 0x3baaf30f, 0x8f9cc83b, 0x20092f67)}, + {SECP256K1_SCALAR_CONST(0x73a57111, 0xb242952a, 0x5c5dee59, 0xf3be2ace, 0xa30a7659, 0xa46e5f47, 0xd21267b1, 0x39e642c9), + SECP256K1_SCALAR_CONST(0xa711df07, 0xcbcf13ef, 0xd61cc6be, 0xbcd058ce, 0xb02cf157, 0x272d4a18, 0x86d0feb3, 0xcd5fa004)}, + {SECP256K1_SCALAR_CONST(0x04884963, 0xce0580b1, 0xba547030, 0x3c691db3, 0x9cd2c84f, 0x24c7cebd, 0x97ebfdba, 0x3e785ec2), + SECP256K1_SCALAR_CONST(0xaaaaaf14, 0xd7c99ba7, 0x517ce2c1, 0x78a28b4c, 0x3769a851, 0xe5c5a03d, 0x4cc28f33, 0x0ec4dc5d)}, + {SECP256K1_SCALAR_CONST(0x1679ed49, 0x21f537b1, 0x815cb8ae, 0x9efc511c, 0x5b9fa037, 0x0b0f275e, 0x6c985281, 0x6c4a9905), + SECP256K1_SCALAR_CONST(0xb14ac3d5, 0x62b52999, 0xef34ead1, 0xffca4998, 0x0294341a, 0x1f8172aa, 0xea1624f9, 0x302eea62)}, + {SECP256K1_SCALAR_CONST(0x626b37c0, 0xf0057c35, 0xee982f83, 0x452a1fd3, 0xea826506, 0x48b08a9d, 0x1d2c4799, 0x4ad5f6ec), + SECP256K1_SCALAR_CONST(0xe38643b7, 0x567bfc2f, 0x5d2f1c15, 0xe327239c, 0x07112443, 0x69509283, 0xfd98e77a, 0xdb71c1e8)}, + {SECP256K1_SCALAR_CONST(0x1850a3a7, 0x759efc56, 0x54f287b2, 0x14d1234b, 0xe263bbc9, 0xcf4d8927, 0xd5f85f27, 0x965bd816), + SECP256K1_SCALAR_CONST(0x3b071831, 0xcac9619a, 0xcceb0596, 0xf614d63b, 0x95d0db2f, 0xc6a00901, 0x8eaa2621, 0xabfa0009)}, + {SECP256K1_SCALAR_CONST(0x94ae5d06, 0xa27dc400, 0x487d72be, 0xaa51ebed, 0xe475b5c0, 0xea675ffc, 0xf4df627a, 0xdca4222f), + SECP256K1_SCALAR_CONST(0x01b412ed, 0xd7830956, 0x1532537e, 0xe5e3dc99, 0x8fd3930a, 0x54f8d067, 0x32ef5760, 0x594438a5)}, + {SECP256K1_SCALAR_CONST(0x1f24278a, 0xb5bfe374, 0xa328dbbc, 0xebe35f48, 0x6620e009, 0xd58bb1b4, 0xb5a6bf84, 0x8815f63a), + SECP256K1_SCALAR_CONST(0xfe928416, 0xca5ba2d3, 0xfde513da, 0x903a60c7, 0x9e58ad8a, 0x8783bee4, 0x083a3843, 0xa608c914)}, + {SECP256K1_SCALAR_CONST(0xdc107d58, 0x274f6330, 0x67dba8bc, 0x26093111, 0x5201dfb8, 0x968ce3f5, 0xf34d1bd4, 0xf2146504), + SECP256K1_SCALAR_CONST(0x660cfa90, 0x13c3d93e, 0x7023b1e5, 0xedd09e71, 0x6d9c9d10, 0x7a3d2cdb, 0xdd08edc3, 0xaa78fcfb)}, + {SECP256K1_SCALAR_CONST(0x7cd1e905, 0xc6f02776, 0x2f551cc7, 0x5da61cff, 0x7da05389, 0x1119d5a4, 0x631c7442, 0x894fd4f7), + SECP256K1_SCALAR_CONST(0xff20862a, 0x9d3b1a37, 0x1628803b, 0x3004ccae, 0xaa23282a, 0xa89a1109, 0xd94ece5e, 0x181bdc46)}, + {SECP256K1_SCALAR_CONST(0x5b9dade8, 0x23d26c58, 0xcd12d818, 0x25b8ae97, 0x3dea04af, 0xf482c96b, 0xa062f254, 0x9e453640), + SECP256K1_SCALAR_CONST(0x50c38800, 0x15fa53f4, 0xbe1e5392, 0x5c9b120a, 0x262c22c7, 0x18fa0816, 0x5f2baab4, 0x8cb5db46)}, + {SECP256K1_SCALAR_CONST(0x11cdaeda, 0x969c464b, 0xef1f4ab0, 0x5b01d22e, 0x656fd098, 0x882bea84, 0x65cdbe7a, 0x0c19ff03), + SECP256K1_SCALAR_CONST(0x1968d0fa, 0xac46f103, 0xb55f1f72, 0xb3820bed, 0xec6b359a, 0x4b1ae0ad, 0x7e38e1fb, 0x295ccdfb)}, + {SECP256K1_SCALAR_CONST(0x2c351aa1, 0x26e91589, 0x194f8a1e, 0x06561f66, 0x0cb97b7f, 0x10914454, 0x134d1c03, 0x157266b4), + SECP256K1_SCALAR_CONST(0xbe49ada6, 0x92bd8711, 0x41b176c4, 0xa478ba95, 0x14883434, 0x9d1cd6f3, 0xcc4b847d, 0x22af80f5)}, + {SECP256K1_SCALAR_CONST(0x6ba07c6e, 0x13a60edb, 0x6247f5c3, 0x84b5fa56, 0x76fe3ec5, 0x80426395, 0xf65ec2ae, 0x623ba730), + SECP256K1_SCALAR_CONST(0x25ac23f7, 0x418cd747, 0x98376f9d, 0x4a11c7bf, 0x24c8ebfe, 0x4c8a8655, 0x345f4f52, 0x1c515595)}, + {SECP256K1_SCALAR_CONST(0x9397a712, 0x8abb6951, 0x2d4a3d54, 0x703b1c2a, 0x0661dca8, 0xd75c9b31, 0xaed4d24b, 0xd2ab2948), + SECP256K1_SCALAR_CONST(0xc52e8bef, 0xd55ce3eb, 0x1c897739, 0xeb9fb606, 0x36b9cd57, 0x18c51cc2, 0x6a87489e, 0xffd0dcf3)}, + {SECP256K1_SCALAR_CONST(0xe6a808cc, 0xeb437888, 0xe97798df, 0x4e224e44, 0x7e3b380a, 0x207c1653, 0x889f3212, 0xc6738b6f), + SECP256K1_SCALAR_CONST(0x31f9ae13, 0xd1e08b20, 0x757a2e5e, 0x5243a0eb, 0x8ae35f73, 0x19bb6122, 0xb910f26b, 0xda70aa55)}, + {SECP256K1_SCALAR_CONST(0xd0320548, 0xab0effe7, 0xa70779e0, 0x61a347a6, 0xb8c1e010, 0x9d5281f8, 0x2ee588a6, 0x80000000), + SECP256K1_SCALAR_CONST(0x1541897e, 0x78195c90, 0x7583dd9e, 0x728b6100, 0xbce8bc6d, 0x7a53b471, 0x5dcd9e45, 0x4425fcaf)}, + {SECP256K1_SCALAR_CONST(0x93d623f1, 0xd45b50b0, 0x796e9186, 0x9eac9407, 0xd30edc20, 0xef6304cf, 0x250494e7, 0xba503de9), + SECP256K1_SCALAR_CONST(0x7026d638, 0x1178b548, 0x92043952, 0x3c7fb47c, 0xcd3ea236, 0x31d82b01, 0x612fc387, 0x80b9b957)}, + {SECP256K1_SCALAR_CONST(0xf860ab39, 0x55f5d412, 0xa4d73bcc, 0x3b48bd90, 0xc248ffd3, 0x13ca10be, 0x8fba84cc, 0xdd28d6a3), + SECP256K1_SCALAR_CONST(0x5c32fc70, 0xe0b15d67, 0x76694700, 0xfe62be4d, 0xeacdb229, 0x7a4433d9, 0x52155cd0, 0x7649ab59)}, + {SECP256K1_SCALAR_CONST(0x4e41311c, 0x0800af58, 0x7a690a8e, 0xe175c9ba, 0x6981ab73, 0xac532ea8, 0x5c1f5e63, 0x6ac1f189), + SECP256K1_SCALAR_CONST(0xfffffff9, 0xd075982c, 0x7fbd3825, 0xc05038a2, 0x4533b91f, 0x94ec5f45, 0xb280b28f, 0x842324dc)}, + {SECP256K1_SCALAR_CONST(0x48e473bf, 0x3555eade, 0xad5d7089, 0x2424c4e4, 0x0a99397c, 0x2dc796d8, 0xb7a43a69, 0xd0364141), + SECP256K1_SCALAR_CONST(0x634976b2, 0xa0e47895, 0x1ec38593, 0x266d6fd0, 0x6f602644, 0x9bb762f1, 0x7180c704, 0xe23a4daa)}, + {SECP256K1_SCALAR_CONST(0xbe83878d, 0x3292fc54, 0x26e71c62, 0x556ccedc, 0x7cbb8810, 0x4032a720, 0x34ead589, 0xe4d6bd13), + SECP256K1_SCALAR_CONST(0x6cd150ad, 0x25e59d0f, 0x74cbae3d, 0x6377534a, 0x1e6562e8, 0xb71b9d18, 0xe1e5d712, 0x8480abb3)}, + {SECP256K1_SCALAR_CONST(0xcdddf2e5, 0xefc15f88, 0xc9ee06de, 0x8a846ca9, 0x28561581, 0x68daa5fb, 0xd1cf3451, 0xeb1782d0), + SECP256K1_SCALAR_CONST(0xffffffd9, 0xed8d2af4, 0x993c865a, 0x23e9681a, 0x3ca3a3dc, 0xe6d5a46e, 0xbd86bd87, 0x61b55c70)}, + {SECP256K1_SCALAR_CONST(0xb6a18f1f, 0x04872df9, 0x08165ec4, 0x319ca19c, 0x6c0359ab, 0x1f7118fb, 0xc2ef8082, 0xca8b7785), + SECP256K1_SCALAR_CONST(0xff55b19b, 0x0f1ac78c, 0x0f0c88c2, 0x2358d5ad, 0x5f455e4e, 0x3330b72f, 0x274dc153, 0xffbf272b)}, + {SECP256K1_SCALAR_CONST(0xea4898e5, 0x30eba3e8, 0xcf0e5c3d, 0x06ec6844, 0x01e26fb6, 0x75636225, 0xc5d08f4c, 0x1decafa0), + SECP256K1_SCALAR_CONST(0xe5a014a8, 0xe3c4ec1e, 0xea4f9b32, 0xcfc7b386, 0x00630806, 0x12c08d02, 0x6407ccc2, 0xb067d90e)}, + {SECP256K1_SCALAR_CONST(0x70e9aea9, 0x7e933af0, 0x8a23bfab, 0x23e4b772, 0xff951863, 0x5ffcf47d, 0x6bebc918, 0x2ca58265), + SECP256K1_SCALAR_CONST(0xf4e00006, 0x81bc6441, 0x4eb6ec02, 0xc194a859, 0x80ad7c48, 0xba4e9afb, 0x8b6bdbe0, 0x989d8f77)}, + {SECP256K1_SCALAR_CONST(0x3c56c774, 0x46efe6f0, 0xe93618b8, 0xf9b5a846, 0xd247df61, 0x83b1e215, 0x06dc8bcc, 0xeefc1bf5), + SECP256K1_SCALAR_CONST(0xfff8937a, 0x2cd9586b, 0x43c25e57, 0xd1cefa7a, 0x9fb91ed3, 0x95b6533d, 0x8ad0de5b, 0xafb93f00)}, + {SECP256K1_SCALAR_CONST(0xfb5c2772, 0x5cb30e83, 0xe38264df, 0xe4e3ebf3, 0x392aa92e, 0xa68756a1, 0x51279ac5, 0xb50711a8), + SECP256K1_SCALAR_CONST(0x000013af, 0x1105bfe7, 0xa6bbd7fb, 0x3d638f99, 0x3b266b02, 0x072fb8bc, 0x39251130, 0x2e0fd0ea)} + }; + int i, var, testrand; + unsigned char b32[32]; + secp256k1_fe x_fe; + secp256k1_scalar x_scalar; + memset(b32, 0, sizeof(b32)); + /* Test fixed test cases through test_inverse_{scalar,field}, both ways. */ + for (i = 0; (size_t)i < sizeof(fe_cases)/sizeof(fe_cases[0]); ++i) { + for (var = 0; var <= 1; ++var) { + test_inverse_field(&x_fe, &fe_cases[i][0], var); + CHECK(fe_equal(&x_fe, &fe_cases[i][1])); + test_inverse_field(&x_fe, &fe_cases[i][1], var); + CHECK(fe_equal(&x_fe, &fe_cases[i][0])); + } + } + for (i = 0; (size_t)i < sizeof(scalar_cases)/sizeof(scalar_cases[0]); ++i) { + for (var = 0; var <= 1; ++var) { + test_inverse_scalar(&x_scalar, &scalar_cases[i][0], var); + CHECK(secp256k1_scalar_eq(&x_scalar, &scalar_cases[i][1])); + test_inverse_scalar(&x_scalar, &scalar_cases[i][1], var); + CHECK(secp256k1_scalar_eq(&x_scalar, &scalar_cases[i][0])); + } + } + /* Test inputs 0..999 and their respective negations. */ + for (i = 0; i < 1000; ++i) { + b32[31] = i & 0xff; + b32[30] = (i >> 8) & 0xff; + secp256k1_scalar_set_b32(&x_scalar, b32, NULL); + secp256k1_fe_set_b32_mod(&x_fe, b32); + for (var = 0; var <= 1; ++var) { + test_inverse_scalar(NULL, &x_scalar, var); + test_inverse_field(NULL, &x_fe, var); + } + secp256k1_scalar_negate(&x_scalar, &x_scalar); + secp256k1_fe_negate(&x_fe, &x_fe, 1); + for (var = 0; var <= 1; ++var) { + test_inverse_scalar(NULL, &x_scalar, var); + test_inverse_field(NULL, &x_fe, var); + } + } + /* test 128*count random inputs; half with testrand256_test, half with testrand256 */ + for (testrand = 0; testrand <= 1; ++testrand) { + for (i = 0; i < 64 * COUNT; ++i) { + (testrand ? testrand256_test : testrand256)(b32); + secp256k1_scalar_set_b32(&x_scalar, b32, NULL); + secp256k1_fe_set_b32_mod(&x_fe, b32); + for (var = 0; var <= 1; ++var) { + test_inverse_scalar(NULL, &x_scalar, var); + test_inverse_field(NULL, &x_fe, var); + } + } + } +} + +/***** HSORT TESTS *****/ + +static void test_heap_swap(void) { + unsigned char a[600]; + unsigned char e[sizeof(a)]; + memset(a, 21, 200); + memset(a + 200, 99, 200); + memset(a + 400, 42, 200); + memset(e, 42, 200); + memset(e + 200, 99, 200); + memset(e + 400, 21, 200); + secp256k1_heap_swap(a, 0, 2, 200); + CHECK(secp256k1_memcmp_var(a, e, sizeof(a)) == 0); +} + +static void test_hsort_is_sorted(unsigned char *elements, size_t n, size_t len) { + size_t i; + for (i = 1; i < n; i++) { + CHECK(secp256k1_memcmp_var(&elements[(i-1) * len], &elements[i * len], len) <= 0); + } +} + +struct test_hsort_cmp_data { + size_t counter; + size_t element_len; +}; + + +static int test_hsort_cmp(const void *ele1, const void *ele2, void *data) { + struct test_hsort_cmp_data *d = (struct test_hsort_cmp_data *) data; + d->counter += 1; + return secp256k1_memcmp_var((unsigned char *)ele1, (unsigned char *)ele2, d->element_len); +} + +#define NUM 65 +#define MAX_ELEMENT_LEN 65 +static void test_hsort(size_t element_len) { + unsigned char elements[NUM * MAX_ELEMENT_LEN] = { 0 }; + struct test_hsort_cmp_data data; + int i; + + VERIFY_CHECK(element_len <= MAX_ELEMENT_LEN); + data.counter = 0; + data.element_len = element_len; + + secp256k1_hsort(elements, 0, element_len, test_hsort_cmp, &data); + CHECK(data.counter == 0); + secp256k1_hsort(elements, 1, element_len, test_hsort_cmp, &data); + CHECK(data.counter == 0); + secp256k1_hsort(elements, NUM, element_len, test_hsort_cmp, &data); + CHECK(data.counter >= NUM - 1); + test_hsort_is_sorted(elements, NUM, element_len); + + /* Test hsort with array of random length n */ + for (i = 0; i < COUNT; i++) { + int n = testrand_int(NUM); + testrand_bytes_test(elements, n*element_len); + secp256k1_hsort(elements, n, element_len, test_hsort_cmp, &data); + test_hsort_is_sorted(elements, n, element_len); + } +} +#undef NUM +#undef MAX_ELEMENT_LEN + + +static void run_hsort_tests(void) { + test_heap_swap(); + test_hsort(1); + test_hsort(64); + test_hsort(65); +} + +/***** GROUP TESTS *****/ + +/* This compares jacobian points including their Z, not just their geometric meaning. */ +static int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej a2; + secp256k1_gej b2; + int ret = 1; + ret &= a->infinity == b->infinity; + if (ret && !a->infinity) { + a2 = *a; + b2 = *b; + secp256k1_fe_normalize(&a2.x); + secp256k1_fe_normalize(&a2.y); + secp256k1_fe_normalize(&a2.z); + secp256k1_fe_normalize(&b2.x); + secp256k1_fe_normalize(&b2.y); + secp256k1_fe_normalize(&b2.z); + ret &= secp256k1_fe_cmp_var(&a2.x, &b2.x) == 0; + ret &= secp256k1_fe_cmp_var(&a2.y, &b2.y) == 0; + ret &= secp256k1_fe_cmp_var(&a2.z, &b2.z) == 0; + } + return ret; +} + +static void test_ge(void) { + int i, i1; + int runs = 6; + /* 25 points are used: + * - infinity + * - for each of four random points p1 p2 p3 p4, we add the point, its + * negation, and then those two again but with randomized Z coordinate. + * - The same is then done for lambda*p1 and lambda^2*p1. + */ + secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); + secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); + secp256k1_fe zf, r; + secp256k1_fe zfi2, zfi3; + + secp256k1_gej_set_infinity(&gej[0]); + secp256k1_ge_set_infinity(&ge[0]); + for (i = 0; i < runs; i++) { + int j, k; + secp256k1_ge g; + testutil_random_ge_test(&g); + if (i >= runs - 2) { + secp256k1_ge_mul_lambda(&g, &ge[1]); + CHECK(!secp256k1_ge_eq_var(&g, &ge[1])); + } + if (i >= runs - 1) { + secp256k1_ge_mul_lambda(&g, &g); + } + ge[1 + 4 * i] = g; + ge[2 + 4 * i] = g; + secp256k1_ge_neg(&ge[3 + 4 * i], &g); + secp256k1_ge_neg(&ge[4 + 4 * i], &g); + secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); + testutil_random_ge_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); + secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); + testutil_random_ge_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); + for (j = 0; j < 4; j++) { + testutil_random_ge_x_magnitude(&ge[1 + j + 4 * i]); + testutil_random_ge_y_magnitude(&ge[1 + j + 4 * i]); + testutil_random_gej_x_magnitude(&gej[1 + j + 4 * i]); + testutil_random_gej_y_magnitude(&gej[1 + j + 4 * i]); + testutil_random_gej_z_magnitude(&gej[1 + j + 4 * i]); + } + + for (j = 0; j < 4; ++j) { + for (k = 0; k < 4; ++k) { + int expect_equal = (j >> 1) == (k >> 1); + CHECK(secp256k1_ge_eq_var(&ge[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); + CHECK(secp256k1_gej_eq_var(&gej[1 + j + 4 * i], &gej[1 + k + 4 * i]) == expect_equal); + CHECK(secp256k1_gej_eq_ge_var(&gej[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); + CHECK(secp256k1_gej_eq_ge_var(&gej[1 + k + 4 * i], &ge[1 + j + 4 * i]) == expect_equal); + } + } + } + + /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ + testutil_random_fe_non_zero_test(&zf); + testutil_random_fe_magnitude(&zf, 8); + secp256k1_fe_inv_var(&zfi3, &zf); + secp256k1_fe_sqr(&zfi2, &zfi3); + secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); + + /* Generate random r */ + testutil_random_fe_non_zero_test(&r); + + for (i1 = 0; i1 < 1 + 4 * runs; i1++) { + int i2; + for (i2 = 0; i2 < 1 + 4 * runs; i2++) { + /* Compute reference result using gej + gej (var). */ + secp256k1_gej refj, resj; + secp256k1_ge ref; + secp256k1_fe zr; + secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); + /* Check Z ratio. */ + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal(&zrz, &refj.z)); + } + secp256k1_ge_set_gej_var(&ref, &refj); + + /* Test gej + ge with Z ratio result (var). */ + secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal(&zrz, &resj.z)); + } + + /* Test gej + ge (var, with additional Z factor). */ + { + secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ + secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); + secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); + testutil_random_ge_x_magnitude(&ge2_zfi); + testutil_random_ge_y_magnitude(&ge2_zfi); + secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); + } + + /* Test gej + ge (const). */ + if (i2 != 0) { + /* secp256k1_gej_add_ge does not support its second argument being infinity. */ + secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); + } + + /* Test doubling (var). */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { + secp256k1_fe zr2; + /* Normal doubling with Z ratio result. */ + secp256k1_gej_double_var(&resj, &gej[i1], &zr2); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); + /* Check Z ratio. */ + secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z); + CHECK(secp256k1_fe_equal(&zr2, &resj.z)); + /* Normal doubling. */ + secp256k1_gej_double_var(&resj, &gej[i2], NULL); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); + /* Constant-time doubling. */ + secp256k1_gej_double(&resj, &gej[i2]); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); + } + + /* Test adding opposites. */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) { + CHECK(secp256k1_ge_is_infinity(&ref)); + } + + /* Test adding infinity. */ + if (i1 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i1])); + CHECK(secp256k1_gej_is_infinity(&gej[i1])); + CHECK(secp256k1_gej_eq_ge_var(&gej[i2], &ref)); + } + if (i2 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i2])); + CHECK(secp256k1_gej_is_infinity(&gej[i2])); + CHECK(secp256k1_gej_eq_ge_var(&gej[i1], &ref)); + } + } + } + + /* Test adding all points together in random order equals infinity. */ + { + secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; + secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej)); + for (i = 0; i < 4 * runs + 1; i++) { + gej_shuffled[i] = gej[i]; + } + for (i = 0; i < 4 * runs + 1; i++) { + int swap = i + testrand_int(4 * runs + 1 - i); + if (swap != i) { + secp256k1_gej t = gej_shuffled[i]; + gej_shuffled[i] = gej_shuffled[swap]; + gej_shuffled[swap] = t; + } + } + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); + } + CHECK(secp256k1_gej_is_infinity(&sum)); + free(gej_shuffled); + } + + /* Test batch gej -> ge conversion without known z ratios. */ + { + secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); + secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1); + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_fe s; + testutil_random_fe_non_zero(&s); + secp256k1_gej_rescale(&gej[i], &s); + CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all[i])); + } + free(ge_set_all); + } + + /* Test that all elements have X coordinates on the curve. */ + for (i = 1; i < 4 * runs + 1; i++) { + secp256k1_fe n; + CHECK(secp256k1_ge_x_on_curve_var(&ge[i].x)); + /* And the same holds after random rescaling. */ + secp256k1_fe_mul(&n, &zf, &ge[i].x); + CHECK(secp256k1_ge_x_frac_on_curve_var(&n, &zf)); + } + + /* Test correspondence of secp256k1_ge_x{,_frac}_on_curve_var with ge_set_xo. */ + { + secp256k1_fe n; + secp256k1_ge q; + int ret_on_curve, ret_frac_on_curve, ret_set_xo; + secp256k1_fe_mul(&n, &zf, &r); + ret_on_curve = secp256k1_ge_x_on_curve_var(&r); + ret_frac_on_curve = secp256k1_ge_x_frac_on_curve_var(&n, &zf); + ret_set_xo = secp256k1_ge_set_xo_var(&q, &r, 0); + CHECK(ret_on_curve == ret_frac_on_curve); + CHECK(ret_on_curve == ret_set_xo); + if (ret_set_xo) CHECK(secp256k1_fe_equal(&r, &q.x)); + } + + /* Test batch gej -> ge conversion with many infinities. */ + for (i = 0; i < 4 * runs + 1; i++) { + int odd; + testutil_random_ge_test(&ge[i]); + odd = secp256k1_fe_is_odd(&ge[i].x); + CHECK(odd == 0 || odd == 1); + /* randomly set half the points to infinity */ + if (odd == i % 2) { + secp256k1_ge_set_infinity(&ge[i]); + } + secp256k1_gej_set_ge(&gej[i], &ge[i]); + } + /* batch convert */ + secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1); + /* check result */ + for (i = 0; i < 4 * runs + 1; i++) { + CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge[i])); + } + + /* Test batch gej -> ge conversion with all infinities. */ + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_gej_set_infinity(&gej[i]); + } + /* batch convert */ + secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1); + /* check result */ + for (i = 0; i < 4 * runs + 1; i++) { + CHECK(secp256k1_ge_is_infinity(&ge[i])); + } + + free(ge); + free(gej); +} + +static void test_intialized_inf(void) { + secp256k1_ge p; + secp256k1_gej pj, npj, infj1, infj2, infj3; + secp256k1_fe zinv; + + /* Test that adding P+(-P) results in a fully initialized infinity*/ + testutil_random_ge_test(&p); + secp256k1_gej_set_ge(&pj, &p); + secp256k1_gej_neg(&npj, &pj); + + secp256k1_gej_add_var(&infj1, &pj, &npj, NULL); + CHECK(secp256k1_gej_is_infinity(&infj1)); + CHECK(secp256k1_fe_is_zero(&infj1.x)); + CHECK(secp256k1_fe_is_zero(&infj1.y)); + CHECK(secp256k1_fe_is_zero(&infj1.z)); + + secp256k1_gej_add_ge_var(&infj2, &npj, &p, NULL); + CHECK(secp256k1_gej_is_infinity(&infj2)); + CHECK(secp256k1_fe_is_zero(&infj2.x)); + CHECK(secp256k1_fe_is_zero(&infj2.y)); + CHECK(secp256k1_fe_is_zero(&infj2.z)); + + secp256k1_fe_set_int(&zinv, 1); + secp256k1_gej_add_zinv_var(&infj3, &npj, &p, &zinv); + CHECK(secp256k1_gej_is_infinity(&infj3)); + CHECK(secp256k1_fe_is_zero(&infj3.x)); + CHECK(secp256k1_fe_is_zero(&infj3.y)); + CHECK(secp256k1_fe_is_zero(&infj3.z)); + + +} + +static void test_add_neg_y_diff_x(void) { + /* The point of this test is to check that we can add two points + * whose y-coordinates are negatives of each other but whose x + * coordinates differ. If the x-coordinates were the same, these + * points would be negatives of each other and their sum is + * infinity. This is cool because it "covers up" any degeneracy + * in the addition algorithm that would cause the xy coordinates + * of the sum to be wrong (since infinity has no xy coordinates). + * HOWEVER, if the x-coordinates are different, infinity is the + * wrong answer, and such degeneracies are exposed. This is the + * root of https://github.com/bitcoin-core/secp256k1/issues/257 + * which this test is a regression test for. + * + * These points were generated in sage as + * + * load("secp256k1_params.sage") + * + * # random "bad pair" + * P = C.random_element() + * Q = -int(LAMBDA) * P + * print(" P: %x %x" % P.xy()) + * print(" Q: %x %x" % Q.xy()) + * print("P + Q: %x %x" % (P + Q).xy()) + */ + secp256k1_gej aj = SECP256K1_GEJ_CONST( + 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, + 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, + 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, + 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d + ); + secp256k1_gej bj = SECP256K1_GEJ_CONST( + 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, + 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, + 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, + 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 + ); + secp256k1_gej sumj = SECP256K1_GEJ_CONST( + 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, + 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, + 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, + 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe + ); + secp256k1_ge b; + secp256k1_gej resj; + secp256k1_ge res; + secp256k1_ge_set_gej(&b, &bj); + + secp256k1_gej_add_var(&resj, &aj, &bj, NULL); + secp256k1_ge_set_gej(&res, &resj); + CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); + + secp256k1_gej_add_ge(&resj, &aj, &b); + secp256k1_ge_set_gej(&res, &resj); + CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); + + secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); + secp256k1_ge_set_gej(&res, &resj); + CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); +} + +static void test_ge_bytes(void) { + int i; + + for (i = 0; i < COUNT + 1; i++) { + unsigned char buf[64]; + secp256k1_ge p, q; + + if (i == 0) { + secp256k1_ge_set_infinity(&p); + } else { + testutil_random_ge_test(&p); + } + + if (!secp256k1_ge_is_infinity(&p)) { + secp256k1_ge_to_bytes(buf, &p); + + secp256k1_ge_from_bytes(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); + + secp256k1_ge_from_bytes_ext(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); + } + secp256k1_ge_to_bytes_ext(buf, &p); + secp256k1_ge_from_bytes_ext(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); + } +} + +static void run_ge(void) { + int i; + for (i = 0; i < COUNT * 32; i++) { + test_ge(); + } + test_add_neg_y_diff_x(); + test_intialized_inf(); + test_ge_bytes(); +} + +static void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej t = *a; + secp256k1_gej_cmov(&t, b, 0); + CHECK(gej_xyz_equals_gej(&t, a)); + secp256k1_gej_cmov(&t, b, 1); + CHECK(gej_xyz_equals_gej(&t, b)); +} + +static void run_gej(void) { + int i; + secp256k1_gej a, b; + + /* Tests for secp256k1_gej_cmov */ + for (i = 0; i < COUNT; i++) { + secp256k1_gej_set_infinity(&a); + secp256k1_gej_set_infinity(&b); + test_gej_cmov(&a, &b); + + testutil_random_gej_test(&a); + test_gej_cmov(&a, &b); + test_gej_cmov(&b, &a); + + b = a; + test_gej_cmov(&a, &b); + + testutil_random_gej_test(&b); + test_gej_cmov(&a, &b); + test_gej_cmov(&b, &a); + } + + /* Tests for secp256k1_gej_eq_var */ + for (i = 0; i < COUNT; i++) { + secp256k1_fe fe; + testutil_random_gej_test(&a); + testutil_random_gej_test(&b); + CHECK(!secp256k1_gej_eq_var(&a, &b)); + + b = a; + testutil_random_fe_non_zero_test(&fe); + secp256k1_gej_rescale(&a, &fe); + CHECK(secp256k1_gej_eq_var(&a, &b)); + } +} + +static void test_ec_combine(void) { + secp256k1_scalar sum = secp256k1_scalar_zero; + secp256k1_pubkey data[6]; + const secp256k1_pubkey* d[6]; + secp256k1_pubkey sd; + secp256k1_pubkey sd2; + secp256k1_gej Qj; + secp256k1_ge Q; + int i; + for (i = 1; i <= 6; i++) { + secp256k1_scalar s; + testutil_random_scalar_order_test(&s); + secp256k1_scalar_add(&sum, &sum, &s); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &s); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&data[i - 1], &Q); + d[i - 1] = &data[i - 1]; + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &sum); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&sd, &Q); + CHECK(secp256k1_ec_pubkey_combine(CTX, &sd2, d, i) == 1); + CHECK(secp256k1_memcmp_var(&sd, &sd2, sizeof(sd)) == 0); + } +} + +static void run_ec_combine(void) { + int i; + for (i = 0; i < COUNT * 8; i++) { + test_ec_combine(); + } +} + +static void test_group_decompress(const secp256k1_fe* x) { + /* The input itself, normalized. */ + secp256k1_fe fex = *x; + /* Results of set_xo_var(..., 0), set_xo_var(..., 1). */ + secp256k1_ge ge_even, ge_odd; + /* Return values of the above calls. */ + int res_even, res_odd; + + secp256k1_fe_normalize_var(&fex); + + res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0); + res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1); + + CHECK(res_even == res_odd); + + if (res_even) { + secp256k1_fe_normalize_var(&ge_odd.x); + secp256k1_fe_normalize_var(&ge_even.x); + secp256k1_fe_normalize_var(&ge_odd.y); + secp256k1_fe_normalize_var(&ge_even.y); + + /* No infinity allowed. */ + CHECK(!ge_even.infinity); + CHECK(!ge_odd.infinity); + + /* Check that the x coordinates check out. */ + CHECK(secp256k1_fe_equal(&ge_even.x, x)); + CHECK(secp256k1_fe_equal(&ge_odd.x, x)); + + /* Check odd/even Y in ge_odd, ge_even. */ + CHECK(secp256k1_fe_is_odd(&ge_odd.y)); + CHECK(!secp256k1_fe_is_odd(&ge_even.y)); + } +} + +static void run_group_decompress(void) { + int i; + for (i = 0; i < COUNT * 4; i++) { + secp256k1_fe fe; + testutil_random_fe_test(&fe); + test_group_decompress(&fe); + } +} + +/***** ECMULT TESTS *****/ + +static void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) { + /* Tests the pre_g / pre_g_128 tables for consistency. + * For independent verification we take a "geometric" approach to verification. + * We check that every entry is on-curve. + * We check that for consecutive entries p and q, that p + gg - q = 0 by checking + * (1) p, gg, and -q are colinear. + * (2) p, gg, and -q are all distinct. + * where gg is twice the generator, where the generator is the first table entry. + * + * Checking the table's generators are correct is done in run_ecmult_pre_g. + */ + secp256k1_gej g2; + secp256k1_ge p, q, gg; + secp256k1_fe dpx, dpy, dqx, dqy; + size_t i; + + CHECK(0 < n); + + secp256k1_ge_from_storage(&p, &pre_g[0]); + CHECK(secp256k1_ge_is_valid_var(&p)); + + secp256k1_gej_set_ge(&g2, &p); + secp256k1_gej_double_var(&g2, &g2, NULL); + secp256k1_ge_set_gej_var(&gg, &g2); + for (i = 1; i < n; ++i) { + secp256k1_fe_negate(&dpx, &p.x, 1); secp256k1_fe_add(&dpx, &gg.x); secp256k1_fe_normalize_weak(&dpx); + secp256k1_fe_negate(&dpy, &p.y, 1); secp256k1_fe_add(&dpy, &gg.y); secp256k1_fe_normalize_weak(&dpy); + /* Check that p is not equal to gg */ + CHECK(!secp256k1_fe_normalizes_to_zero_var(&dpx) || !secp256k1_fe_normalizes_to_zero_var(&dpy)); + + secp256k1_ge_from_storage(&q, &pre_g[i]); + CHECK(secp256k1_ge_is_valid_var(&q)); + + secp256k1_fe_negate(&dqx, &q.x, 1); secp256k1_fe_add(&dqx, &gg.x); + dqy = q.y; secp256k1_fe_add(&dqy, &gg.y); + /* Check that -q is not equal to gg */ + CHECK(!secp256k1_fe_normalizes_to_zero_var(&dqx) || !secp256k1_fe_normalizes_to_zero_var(&dqy)); + + /* Check that -q is not equal to p */ + CHECK(!secp256k1_fe_equal(&dpx, &dqx) || !secp256k1_fe_equal(&dpy, &dqy)); + + /* Check that p, -q and gg are colinear */ + secp256k1_fe_mul(&dpx, &dpx, &dqy); + secp256k1_fe_mul(&dpy, &dpy, &dqx); + CHECK(secp256k1_fe_equal(&dpx, &dpy)); + + p = q; + } +} + +static void run_ecmult_pre_g(void) { + secp256k1_ge_storage gs; + secp256k1_gej gj; + secp256k1_ge g; + size_t i; + + /* Check that the pre_g and pre_g_128 tables are consistent. */ + test_pre_g_table(secp256k1_pre_g, ECMULT_TABLE_SIZE(WINDOW_G)); + test_pre_g_table(secp256k1_pre_g_128, ECMULT_TABLE_SIZE(WINDOW_G)); + + /* Check the first entry from the pre_g table. */ + secp256k1_ge_to_storage(&gs, &secp256k1_ge_const_g); + CHECK(secp256k1_memcmp_var(&gs, &secp256k1_pre_g[0], sizeof(gs)) == 0); + + /* Check the first entry from the pre_g_128 table. */ + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); + for (i = 0; i < 128; ++i) { + secp256k1_gej_double_var(&gj, &gj, NULL); + } + secp256k1_ge_set_gej(&g, &gj); + secp256k1_ge_to_storage(&gs, &g); + CHECK(secp256k1_memcmp_var(&gs, &secp256k1_pre_g_128[0], sizeof(gs)) == 0); +} + +static void run_ecmult_chain(void) { + /* random starting point A (on the curve) */ + secp256k1_gej a = SECP256K1_GEJ_CONST( + 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, + 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, + 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, + 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f + ); + /* two random initial factors xn and gn */ + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( + 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, + 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 + ); + secp256k1_scalar gn = SECP256K1_SCALAR_CONST( + 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, + 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de + ); + /* two small multipliers to be applied to xn and gn in every iteration: */ + static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); + static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); + /* accumulators with the resulting coefficients to A and G */ + secp256k1_scalar ae = secp256k1_scalar_one; + secp256k1_scalar ge = secp256k1_scalar_zero; + /* actual points */ + secp256k1_gej x; + secp256k1_gej x2; + int i; + + /* the point being computed */ + x = a; + for (i = 0; i < 200*COUNT; i++) { + /* in each iteration, compute X = xn*X + gn*G; */ + secp256k1_ecmult(&x, &x, &xn, &gn); + /* also compute ae and ge: the actual accumulated factors for A and G */ + /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ + secp256k1_scalar_mul(&ae, &ae, &xn); + secp256k1_scalar_mul(&ge, &ge, &xn); + secp256k1_scalar_add(&ge, &ge, &gn); + /* modify xn and gn */ + secp256k1_scalar_mul(&xn, &xn, &xf); + secp256k1_scalar_mul(&gn, &gn, &gf); + + /* verify */ + if (i == 19999) { + /* expected result after 19999 iterations */ + secp256k1_gej rp = SECP256K1_GEJ_CONST( + 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, + 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, + 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, + 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 + ); + CHECK(secp256k1_gej_eq_var(&rp, &x)); + } + } + /* redo the computation, but directly with the resulting ae and ge coefficients: */ + secp256k1_ecmult(&x2, &a, &ae, &ge); + CHECK(secp256k1_gej_eq_var(&x, &x2)); +} + +static void test_point_times_order(const secp256k1_gej *point) { + /* X * (point + G) + (order-X) * (pointer + G) = 0 */ + secp256k1_scalar x; + secp256k1_scalar nx; + secp256k1_gej res1, res2; + secp256k1_ge res3; + unsigned char pub[65]; + size_t psize = 65; + testutil_random_scalar_order_test(&x); + secp256k1_scalar_negate(&nx, &x); + secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */ + secp256k1_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ + secp256k1_gej_add_var(&res1, &res1, &res2, NULL); + CHECK(secp256k1_gej_is_infinity(&res1)); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_is_infinity(&res3)); + CHECK(secp256k1_ge_is_valid_var(&res3) == 0); + CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); + psize = 65; + CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); + /* check zero/one edge cases */ + secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_zero); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_is_infinity(&res3)); + secp256k1_ecmult(&res1, point, &secp256k1_scalar_one, &secp256k1_scalar_zero); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_gej_eq_ge_var(point, &res3)); + secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_one); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_eq_var(&secp256k1_ge_const_g, &res3)); +} + +/* These scalars reach large (in absolute value) outputs when fed to secp256k1_scalar_split_lambda. + * + * They are computed as: + * - For a in [-2, -1, 0, 1, 2]: + * - For b in [-3, -1, 1, 3]: + * - Output (a*LAMBDA + (ORDER+b)/2) % ORDER + */ +static const secp256k1_scalar scalars_near_split_bounds[20] = { + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fc), + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fd), + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fe), + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6ff), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632d), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632e), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632f), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf76330), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b209f), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a0), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a1), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a2), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede11), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede12), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede13), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede14), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a42), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a43), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a44), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a45) +}; + +static void test_ecmult_target(const secp256k1_scalar* target, int mode) { + /* Mode: 0=ecmult_gen, 1=ecmult, 2=ecmult_const */ + secp256k1_scalar n1, n2; + secp256k1_ge p; + secp256k1_gej pj, p1j, p2j, ptj; + + /* Generate random n1,n2 such that n1+n2 = -target. */ + testutil_random_scalar_order_test(&n1); + secp256k1_scalar_add(&n2, &n1, target); + secp256k1_scalar_negate(&n2, &n2); + + /* Generate a random input point. */ + if (mode != 0) { + testutil_random_ge_test(&p); + secp256k1_gej_set_ge(&pj, &p); + } + + /* EC multiplications */ + if (mode == 0) { + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p1j, &n1); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p2j, &n2); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &ptj, target); + } else if (mode == 1) { + secp256k1_ecmult(&p1j, &pj, &n1, &secp256k1_scalar_zero); + secp256k1_ecmult(&p2j, &pj, &n2, &secp256k1_scalar_zero); + secp256k1_ecmult(&ptj, &pj, target, &secp256k1_scalar_zero); + } else { + secp256k1_ecmult_const(&p1j, &p, &n1); + secp256k1_ecmult_const(&p2j, &p, &n2); + secp256k1_ecmult_const(&ptj, &p, target); + } + + /* Add them all up: n1*P + n2*P + target*P = (n1+n2+target)*P = (n1+n1-n1-n2)*P = 0. */ + secp256k1_gej_add_var(&ptj, &ptj, &p1j, NULL); + secp256k1_gej_add_var(&ptj, &ptj, &p2j, NULL); + CHECK(secp256k1_gej_is_infinity(&ptj)); +} + +static void run_ecmult_near_split_bound(void) { + int i; + unsigned j; + for (i = 0; i < 4*COUNT; ++i) { + for (j = 0; j < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++j) { + test_ecmult_target(&scalars_near_split_bounds[j], 0); + test_ecmult_target(&scalars_near_split_bounds[j], 1); + test_ecmult_target(&scalars_near_split_bounds[j], 2); + } + } +} + +static void run_point_times_order(void) { + int i; + secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); + static const secp256k1_fe xr = SECP256K1_FE_CONST( + 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, + 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 + ); + for (i = 0; i < 500; i++) { + secp256k1_ge p; + if (secp256k1_ge_set_xo_var(&p, &x, 1)) { + secp256k1_gej j; + CHECK(secp256k1_ge_is_valid_var(&p)); + secp256k1_gej_set_ge(&j, &p); + test_point_times_order(&j); + } + secp256k1_fe_sqr(&x, &x); + } + secp256k1_fe_normalize_var(&x); + CHECK(secp256k1_fe_equal(&x, &xr)); +} + +static void ecmult_const_random_mult(void) { + /* random starting point A (on the curve) */ + secp256k1_ge a = SECP256K1_GE_CONST( + 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, + 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, + 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, + 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d + ); + /* random initial factor xn */ + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( + 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, + 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b + ); + /* expected xn * A (from sage) */ + secp256k1_ge expected_b = SECP256K1_GE_CONST( + 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, + 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, + 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, + 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 + ); + secp256k1_gej b; + secp256k1_ecmult_const(&b, &a, &xn); + + CHECK(secp256k1_ge_is_valid_var(&a)); + CHECK(secp256k1_gej_eq_ge_var(&b, &expected_b)); +} + +static void ecmult_const_commutativity(void) { + secp256k1_scalar a; + secp256k1_scalar b; + secp256k1_gej res1; + secp256k1_gej res2; + secp256k1_ge mid1; + secp256k1_ge mid2; + testutil_random_scalar_order_test(&a); + testutil_random_scalar_order_test(&b); + + secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); + secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + secp256k1_ecmult_const(&res1, &mid1, &b); + secp256k1_ecmult_const(&res2, &mid2, &a); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + CHECK(secp256k1_ge_eq_var(&mid1, &mid2)); +} + +static void ecmult_const_mult_zero_one(void) { + secp256k1_scalar s; + secp256k1_scalar negone; + secp256k1_gej res1; + secp256k1_ge res2; + secp256k1_ge point; + secp256k1_ge inf; + + testutil_random_scalar_order_test(&s); + secp256k1_scalar_negate(&negone, &secp256k1_scalar_one); + testutil_random_ge_test(&point); + secp256k1_ge_set_infinity(&inf); + + /* 0*point */ + secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_zero); + CHECK(secp256k1_gej_is_infinity(&res1)); + + /* s*inf */ + secp256k1_ecmult_const(&res1, &inf, &s); + CHECK(secp256k1_gej_is_infinity(&res1)); + + /* 1*point */ + secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_one); + secp256k1_ge_set_gej(&res2, &res1); + CHECK(secp256k1_ge_eq_var(&res2, &point)); + + /* -1*point */ + secp256k1_ecmult_const(&res1, &point, &negone); + secp256k1_gej_neg(&res1, &res1); + secp256k1_ge_set_gej(&res2, &res1); + CHECK(secp256k1_ge_eq_var(&res2, &point)); +} + +static void ecmult_const_check_result(const secp256k1_ge *A, const secp256k1_scalar* q, const secp256k1_gej *res) { + secp256k1_gej pointj, res2j; + secp256k1_ge res2; + secp256k1_gej_set_ge(&pointj, A); + secp256k1_ecmult(&res2j, &pointj, q, &secp256k1_scalar_zero); + secp256k1_ge_set_gej(&res2, &res2j); + CHECK(secp256k1_gej_eq_ge_var(res, &res2)); +} + +static void ecmult_const_edges(void) { + secp256k1_scalar q; + secp256k1_ge point; + secp256k1_gej res; + size_t i; + size_t cases = 1 + sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); + + /* We are trying to reach the following edge cases (variables are defined as + * in ecmult_const_impl.h): + * 1. i = 0: s = 0 <=> q = -K + * 2. i > 0: v1, v2 large values + * <=> s1, s2 large values + * <=> s = scalars_near_split_bounds[i] + * <=> q = 2*scalars_near_split_bounds[i] - K + */ + for (i = 0; i < cases; ++i) { + secp256k1_scalar_negate(&q, &secp256k1_ecmult_const_K); + if (i > 0) { + secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); + secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); + } + testutil_random_ge_test(&point); + secp256k1_ecmult_const(&res, &point, &q); + ecmult_const_check_result(&point, &q, &res); + } +} + +static void ecmult_const_mult_xonly(void) { + int i; + + /* Test correspondence between secp256k1_ecmult_const and secp256k1_ecmult_const_xonly. */ + for (i = 0; i < 2*COUNT; ++i) { + secp256k1_ge base; + secp256k1_gej basej, resj; + secp256k1_fe n, d, resx, v; + secp256k1_scalar q; + int res; + /* Random base point. */ + testutil_random_ge_test(&base); + /* Random scalar to multiply it with. */ + testutil_random_scalar_order_test(&q); + /* If i is odd, n=d*base.x for random non-zero d */ + if (i & 1) { + testutil_random_fe_non_zero_test(&d); + secp256k1_fe_mul(&n, &base.x, &d); + } else { + n = base.x; + } + /* Perform x-only multiplication. */ + res = secp256k1_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, i & 2); + CHECK(res); + /* Perform normal multiplication. */ + secp256k1_gej_set_ge(&basej, &base); + secp256k1_ecmult(&resj, &basej, &q, NULL); + /* Check that resj's X coordinate corresponds with resx. */ + secp256k1_fe_sqr(&v, &resj.z); + secp256k1_fe_mul(&v, &v, &resx); + CHECK(fe_equal(&v, &resj.x)); + } + + /* Test that secp256k1_ecmult_const_xonly correctly rejects X coordinates not on curve. */ + for (i = 0; i < 2*COUNT; ++i) { + secp256k1_fe x, n, d, r; + int res; + secp256k1_scalar q; + testutil_random_scalar_order_test(&q); + /* Generate random X coordinate not on the curve. */ + do { + testutil_random_fe_test(&x); + } while (secp256k1_ge_x_on_curve_var(&x)); + /* If i is odd, n=d*x for random non-zero d. */ + if (i & 1) { + testutil_random_fe_non_zero_test(&d); + secp256k1_fe_mul(&n, &x, &d); + } else { + n = x; + } + res = secp256k1_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 0); + CHECK(res == 0); + } +} + +static void ecmult_const_chain_multiply(void) { + /* Check known result (randomly generated test problem from sage) */ + const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST( + 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, + 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b + ); + const secp256k1_gej expected_point = SECP256K1_GEJ_CONST( + 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, + 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, + 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, + 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 + ); + secp256k1_gej point; + secp256k1_ge res; + int i; + + secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g); + for (i = 0; i < 100; ++i) { + secp256k1_ge tmp; + secp256k1_ge_set_gej(&tmp, &point); + secp256k1_ecmult_const(&point, &tmp, &scalar); + } + secp256k1_ge_set_gej(&res, &point); + CHECK(secp256k1_gej_eq_ge_var(&expected_point, &res)); +} + +static void run_ecmult_const_tests(void) { + ecmult_const_mult_zero_one(); + ecmult_const_edges(); + ecmult_const_random_mult(); + ecmult_const_commutativity(); + ecmult_const_chain_multiply(); + ecmult_const_mult_xonly(); +} + +typedef struct { + secp256k1_scalar *sc; + secp256k1_ge *pt; +} ecmult_multi_data; + +static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ecmult_multi_data *data = (ecmult_multi_data*) cbdata; + *sc = data->sc[idx]; + *pt = data->pt[idx]; + return 1; +} + +static int ecmult_multi_false_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + (void)sc; + (void)pt; + (void)idx; + (void)cbdata; + return 0; +} + +static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) { + int ncount; + secp256k1_scalar sc[32]; + secp256k1_ge pt[32]; + secp256k1_gej r; + secp256k1_gej r2; + ecmult_multi_data data; + + data.sc = sc; + data.pt = pt; + + /* No points to multiply */ + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); + + /* Check 1- and 2-point multiplies against ecmult */ + for (ncount = 0; ncount < COUNT; ncount++) { + secp256k1_ge ptg; + secp256k1_gej ptgj; + testutil_random_scalar_order(&sc[0]); + testutil_random_scalar_order(&sc[1]); + + testutil_random_ge_test(&ptg); + secp256k1_gej_set_ge(&ptgj, &ptg); + pt[0] = ptg; + pt[1] = secp256k1_ge_const_g; + + /* only G scalar */ + secp256k1_ecmult(&r2, &ptgj, &secp256k1_scalar_zero, &sc[0]); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + + /* 1-point */ + secp256k1_ecmult(&r2, &ptgj, &sc[0], &secp256k1_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + + /* Try to multiply 1 point, but callback returns false */ + CHECK(!ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_false_callback, &data, 1)); + + /* 2-point */ + secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + + /* 2-point with G scalar */ + secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + } + + /* Check infinite outputs of various forms */ + for (ncount = 0; ncount < COUNT; ncount++) { + secp256k1_ge ptg; + size_t i, j; + size_t sizes[] = { 2, 10, 32 }; + + for (j = 0; j < 3; j++) { + for (i = 0; i < 32; i++) { + testutil_random_scalar_order(&sc[i]); + secp256k1_ge_set_infinity(&pt[i]); + } + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + for (j = 0; j < 3; j++) { + for (i = 0; i < 32; i++) { + testutil_random_ge_test(&ptg); + pt[i] = ptg; + secp256k1_scalar_set_int(&sc[i], 0); + } + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + for (j = 0; j < 3; j++) { + testutil_random_ge_test(&ptg); + for (i = 0; i < 16; i++) { + testutil_random_scalar_order(&sc[2*i]); + secp256k1_scalar_negate(&sc[2*i + 1], &sc[2*i]); + pt[2 * i] = ptg; + pt[2 * i + 1] = ptg; + } + + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + + testutil_random_scalar_order(&sc[0]); + for (i = 0; i < 16; i++) { + testutil_random_ge_test(&ptg); + + sc[2*i] = sc[0]; + sc[2*i+1] = sc[0]; + pt[2 * i] = ptg; + secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]); + } + + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + testutil_random_ge_test(&ptg); + secp256k1_scalar_set_int(&sc[0], 0); + pt[0] = ptg; + for (i = 1; i < 32; i++) { + pt[i] = ptg; + + testutil_random_scalar_order(&sc[i]); + secp256k1_scalar_add(&sc[0], &sc[0], &sc[i]); + secp256k1_scalar_negate(&sc[i], &sc[i]); + } + + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 32)); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + /* Check random points, constant scalar */ + for (ncount = 0; ncount < COUNT; ncount++) { + size_t i; + secp256k1_gej_set_infinity(&r); + + testutil_random_scalar_order(&sc[0]); + for (i = 0; i < 20; i++) { + secp256k1_ge ptg; + sc[i] = sc[0]; + testutil_random_ge_test(&ptg); + pt[i] = ptg; + secp256k1_gej_add_ge_var(&r, &r, &pt[i], NULL); + } + + secp256k1_ecmult(&r2, &r, &sc[0], &secp256k1_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + } + + /* Check random scalars, constant point */ + for (ncount = 0; ncount < COUNT; ncount++) { + size_t i; + secp256k1_ge ptg; + secp256k1_gej p0j; + secp256k1_scalar rs; + secp256k1_scalar_set_int(&rs, 0); + + testutil_random_ge_test(&ptg); + for (i = 0; i < 20; i++) { + testutil_random_scalar_order(&sc[i]); + pt[i] = ptg; + secp256k1_scalar_add(&rs, &rs, &sc[i]); + } + + secp256k1_gej_set_ge(&p0j, &pt[0]); + secp256k1_ecmult(&r2, &p0j, &rs, &secp256k1_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + } + + /* Sanity check that zero scalars don't cause problems */ + for (ncount = 0; ncount < 20; ncount++) { + testutil_random_scalar_order(&sc[ncount]); + testutil_random_ge_test(&pt[ncount]); + } + + secp256k1_scalar_set_int(&sc[0], 0); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20)); + secp256k1_scalar_set_int(&sc[1], 0); + secp256k1_scalar_set_int(&sc[2], 0); + secp256k1_scalar_set_int(&sc[3], 0); + secp256k1_scalar_set_int(&sc[4], 0); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 6)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 5)); + CHECK(secp256k1_gej_is_infinity(&r)); + + /* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */ + { + const size_t TOP = 8; + size_t s0i, s1i; + size_t t0i, t1i; + secp256k1_ge ptg; + secp256k1_gej ptgj; + + testutil_random_ge_test(&ptg); + secp256k1_gej_set_ge(&ptgj, &ptg); + + for(t0i = 0; t0i < TOP; t0i++) { + for(t1i = 0; t1i < TOP; t1i++) { + secp256k1_gej t0p, t1p; + secp256k1_scalar t0, t1; + + secp256k1_scalar_set_int(&t0, (t0i + 1) / 2); + secp256k1_scalar_cond_negate(&t0, t0i & 1); + secp256k1_scalar_set_int(&t1, (t1i + 1) / 2); + secp256k1_scalar_cond_negate(&t1, t1i & 1); + + secp256k1_ecmult(&t0p, &ptgj, &t0, &secp256k1_scalar_zero); + secp256k1_ecmult(&t1p, &ptgj, &t1, &secp256k1_scalar_zero); + + for(s0i = 0; s0i < TOP; s0i++) { + for(s1i = 0; s1i < TOP; s1i++) { + secp256k1_scalar tmp1, tmp2; + secp256k1_gej expected, actual; + + secp256k1_ge_set_gej(&pt[0], &t0p); + secp256k1_ge_set_gej(&pt[1], &t1p); + + secp256k1_scalar_set_int(&sc[0], (s0i + 1) / 2); + secp256k1_scalar_cond_negate(&sc[0], s0i & 1); + secp256k1_scalar_set_int(&sc[1], (s1i + 1) / 2); + secp256k1_scalar_cond_negate(&sc[1], s1i & 1); + + secp256k1_scalar_mul(&tmp1, &t0, &sc[0]); + secp256k1_scalar_mul(&tmp2, &t1, &sc[1]); + secp256k1_scalar_add(&tmp1, &tmp1, &tmp2); + + secp256k1_ecmult(&expected, &ptgj, &tmp1, &secp256k1_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &actual, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2)); + CHECK(secp256k1_gej_eq_var(&actual, &expected)); + } + } + } + } + } +} + +static int test_ecmult_multi_random(secp256k1_scratch *scratch) { + /* Large random test for ecmult_multi_* functions which exercises: + * - Few or many inputs (0 up to 128, roughly exponentially distributed). + * - Few or many 0*P or a*INF inputs (roughly uniformly distributed). + * - Including or excluding an nonzero a*G term (or such a term at all). + * - Final expected result equal to infinity or not (roughly 50%). + * - ecmult_multi_var, ecmult_strauss_single_batch, ecmult_pippenger_single_batch + */ + + /* These 4 variables define the eventual input to the ecmult_multi function. + * g_scalar is the G scalar fed to it (or NULL, possibly, if g_scalar=0), and + * scalars[0..filled-1] and gejs[0..filled-1] are the scalars and points + * which form its normal inputs. */ + int filled = 0; + secp256k1_scalar g_scalar = secp256k1_scalar_zero; + secp256k1_scalar scalars[128]; + secp256k1_gej gejs[128]; + /* The expected result, and the computed result. */ + secp256k1_gej expected, computed; + /* Temporaries. */ + secp256k1_scalar sc_tmp; + secp256k1_ge ge_tmp; + /* Variables needed for the actual input to ecmult_multi. */ + secp256k1_ge ges[128]; + ecmult_multi_data data; + + int i; + /* Which multiplication function to use */ + int fn = testrand_int(3); + secp256k1_ecmult_multi_func ecmult_multi = fn == 0 ? secp256k1_ecmult_multi_var : + fn == 1 ? secp256k1_ecmult_strauss_batch_single : + secp256k1_ecmult_pippenger_batch_single; + /* Simulate exponentially distributed num. */ + int num_bits = 2 + testrand_int(6); + /* Number of (scalar, point) inputs (excluding g). */ + int num = testrand_int((1 << num_bits) + 1); + /* Number of those which are nonzero. */ + int num_nonzero = testrand_int(num + 1); + /* Whether we're aiming to create an input with nonzero expected result. */ + int nonzero_result = testrand_bits(1); + /* Whether we will provide nonzero g multiplicand. In some cases our hand + * is forced here based on num_nonzero and nonzero_result. */ + int g_nonzero = num_nonzero == 0 ? nonzero_result : + num_nonzero == 1 && !nonzero_result ? 1 : + (int)testrand_bits(1); + /* Which g_scalar pointer to pass into ecmult_multi(). */ + const secp256k1_scalar* g_scalar_ptr = (g_nonzero || testrand_bits(1)) ? &g_scalar : NULL; + /* How many EC multiplications were performed in this function. */ + int mults = 0; + /* How many randomization steps to apply to the input list. */ + int rands = (int)testrand_bits(3); + if (rands > num_nonzero) rands = num_nonzero; + + secp256k1_gej_set_infinity(&expected); + secp256k1_gej_set_infinity(&gejs[0]); + secp256k1_scalar_set_int(&scalars[0], 0); + + if (g_nonzero) { + /* If g_nonzero, set g_scalar to nonzero value r. */ + testutil_random_scalar_order_test(&g_scalar); + if (!nonzero_result) { + /* If expected=0 is desired, add a (a*r, -(1/a)*g) term to compensate. */ + CHECK(num_nonzero > filled); + testutil_random_scalar_order_test(&sc_tmp); + secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar); + secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp); + secp256k1_scalar_negate(&sc_tmp, &sc_tmp); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &gejs[filled], &sc_tmp); + ++filled; + ++mults; + } + } + + if (nonzero_result && filled < num_nonzero) { + /* If a nonzero result is desired, and there is space, add a random nonzero term. */ + testutil_random_scalar_order_test(&scalars[filled]); + testutil_random_ge_test(&ge_tmp); + secp256k1_gej_set_ge(&gejs[filled], &ge_tmp); + ++filled; + } + + if (nonzero_result) { + /* Compute the expected result using normal ecmult. */ + CHECK(filled <= 1); + secp256k1_ecmult(&expected, &gejs[0], &scalars[0], &g_scalar); + mults += filled + g_nonzero; + } + + /* At this point we have expected = scalar_g*G + sum(scalars[i]*gejs[i] for i=0..filled-1). */ + CHECK(filled <= 1 + !nonzero_result); + CHECK(filled <= num_nonzero); + + /* Add entries to scalars,gejs so that there are num of them. All the added entries + * either have scalar=0 or point=infinity, so these do not change the expected result. */ + while (filled < num) { + if (testrand_bits(1)) { + secp256k1_gej_set_infinity(&gejs[filled]); + testutil_random_scalar_order_test(&scalars[filled]); + } else { + secp256k1_scalar_set_int(&scalars[filled], 0); + testutil_random_ge_test(&ge_tmp); + secp256k1_gej_set_ge(&gejs[filled], &ge_tmp); + } + ++filled; + } + + /* Now perform cheapish transformations on gejs and scalars, for indices + * 0..num_nonzero-1, which do not change the expected result, but may + * convert some of them to be both non-0-scalar and non-infinity-point. */ + for (i = 0; i < rands; ++i) { + int j; + secp256k1_scalar v, iv; + /* Shuffle the entries. */ + for (j = 0; j < num_nonzero; ++j) { + int k = testrand_int(num_nonzero - j); + if (k != 0) { + secp256k1_gej gej = gejs[j]; + secp256k1_scalar sc = scalars[j]; + gejs[j] = gejs[j + k]; + scalars[j] = scalars[j + k]; + gejs[j + k] = gej; + scalars[j + k] = sc; + } + } + /* Perturb all consecutive pairs of inputs: + * a*P + b*Q -> (a+b)*P + b*(Q-P). */ + for (j = 0; j + 1 < num_nonzero; j += 2) { + secp256k1_gej gej; + secp256k1_scalar_add(&scalars[j], &scalars[j], &scalars[j+1]); + secp256k1_gej_neg(&gej, &gejs[j]); + secp256k1_gej_add_var(&gejs[j+1], &gejs[j+1], &gej, NULL); + } + /* Transform the last input: a*P -> (v*a) * ((1/v)*P). */ + CHECK(num_nonzero >= 1); + testutil_random_scalar_order_test(&v); + secp256k1_scalar_inverse(&iv, &v); + secp256k1_scalar_mul(&scalars[num_nonzero - 1], &scalars[num_nonzero - 1], &v); + secp256k1_ecmult(&gejs[num_nonzero - 1], &gejs[num_nonzero - 1], &iv, NULL); + ++mults; + } + + /* Shuffle all entries (0..num-1). */ + for (i = 0; i < num; ++i) { + int j = testrand_int(num - i); + if (j != 0) { + secp256k1_gej gej = gejs[i]; + secp256k1_scalar sc = scalars[i]; + gejs[i] = gejs[i + j]; + scalars[i] = scalars[i + j]; + gejs[i + j] = gej; + scalars[i + j] = sc; + } + } + + /* Compute affine versions of all inputs. */ + secp256k1_ge_set_all_gej_var(ges, gejs, filled); + /* Invoke ecmult_multi code. */ + data.sc = scalars; + data.pt = ges; + CHECK(ecmult_multi(&CTX->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled)); + mults += num_nonzero + g_nonzero; + /* Compare with expected result. */ + CHECK(secp256k1_gej_eq_var(&computed, &expected)); + return mults; +} + +static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) { + secp256k1_scalar sc; + secp256k1_ge pt; + secp256k1_gej r; + ecmult_multi_data data; + secp256k1_scratch *scratch_empty; + + testutil_random_ge_test(&pt); + testutil_random_scalar_order(&sc); + data.sc = ≻ + data.pt = &pt; + + /* Try to multiply 1 point, but scratch space is empty.*/ + scratch_empty = secp256k1_scratch_create(&CTX->error_callback, 0); + CHECK(!ecmult_multi(&CTX->error_callback, scratch_empty, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1)); + secp256k1_scratch_destroy(&CTX->error_callback, scratch_empty); +} + +static void test_secp256k1_pippenger_bucket_window_inv(void) { + int i; + + CHECK(secp256k1_pippenger_bucket_window_inv(0) == 0); + for(i = 1; i <= PIPPENGER_MAX_BUCKET_WINDOW; i++) { + /* Bucket_window of 8 is not used with endo */ + if (i == 8) { + continue; + } + CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)) == i); + if (i != PIPPENGER_MAX_BUCKET_WINDOW) { + CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)+1) > i); + } + } +} + +/** + * Probabilistically test the function returning the maximum number of possible points + * for a given scratch space. + */ +static void test_ecmult_multi_pippenger_max_points(void) { + size_t scratch_size = testrand_bits(8); + size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); + secp256k1_scratch *scratch; + size_t n_points_supported; + int bucket_window = 0; + + for(; scratch_size < max_size; scratch_size+=256) { + size_t i; + size_t total_alloc; + size_t checkpoint; + scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size); + CHECK(scratch != NULL); + checkpoint = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); + n_points_supported = secp256k1_pippenger_max_points(&CTX->error_callback, scratch); + if (n_points_supported == 0) { + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + continue; + } + bucket_window = secp256k1_pippenger_bucket_window(n_points_supported); + /* allocate `total_alloc` bytes over `PIPPENGER_SCRATCH_OBJECTS` many allocations */ + total_alloc = secp256k1_pippenger_scratch_size(n_points_supported, bucket_window); + for (i = 0; i < PIPPENGER_SCRATCH_OBJECTS - 1; i++) { + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 1)); + total_alloc--; + } + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, total_alloc)); + secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + } + CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW); +} + +static void test_ecmult_multi_batch_size_helper(void) { + size_t n_batches, n_batch_points, max_n_batch_points, n; + + max_n_batch_points = 0; + n = 1; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 0); + + max_n_batch_points = 1; + n = 0; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == 0); + CHECK(n_batch_points == 0); + + max_n_batch_points = 2; + n = 5; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == 3); + CHECK(n_batch_points == 2); + + max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH; + n = ECMULT_MAX_POINTS_PER_BATCH; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == 1); + CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH); + + max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH + 1; + n = ECMULT_MAX_POINTS_PER_BATCH + 1; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == 2); + CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH/2 + 1); + + max_n_batch_points = 1; + n = SIZE_MAX; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == SIZE_MAX); + CHECK(n_batch_points == 1); + + max_n_batch_points = 2; + n = SIZE_MAX; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == SIZE_MAX/2 + 1); + CHECK(n_batch_points == 2); +} + +/** + * Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to + * 1 <= i <= num points. + */ +static void test_ecmult_multi_batching(void) { + static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD; + secp256k1_scalar scG; + secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_scalar) * n_points); + secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * n_points); + secp256k1_gej r; + secp256k1_gej r2; + ecmult_multi_data data; + int i; + secp256k1_scratch *scratch; + + secp256k1_gej_set_infinity(&r2); + + /* Get random scalars and group elements and compute result */ + testutil_random_scalar_order(&scG); + secp256k1_ecmult(&r2, &r2, &secp256k1_scalar_zero, &scG); + for(i = 0; i < n_points; i++) { + secp256k1_ge ptg; + secp256k1_gej ptgj; + testutil_random_ge_test(&ptg); + secp256k1_gej_set_ge(&ptgj, &ptg); + pt[i] = ptg; + testutil_random_scalar_order(&sc[i]); + secp256k1_ecmult(&ptgj, &ptgj, &sc[i], NULL); + secp256k1_gej_add_var(&r2, &r2, &ptgj, NULL); + } + data.sc = sc; + data.pt = pt; + secp256k1_gej_neg(&r2, &r2); + + /* Test with empty scratch space. It should compute the correct result using + * ecmult_mult_simple algorithm which doesn't require a scratch space. */ + scratch = secp256k1_scratch_create(&CTX->error_callback, 0); + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + + /* Test with space for 1 point in pippenger. That's not enough because + * ecmult_multi selects strauss which requires more memory. It should + * therefore select the simple algorithm. */ + scratch = secp256k1_scratch_create(&CTX->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + + for(i = 1; i <= n_points; i++) { + if (i > ECMULT_PIPPENGER_THRESHOLD) { + int bucket_window = secp256k1_pippenger_bucket_window(i); + size_t scratch_size = secp256k1_pippenger_scratch_size(i, bucket_window); + scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + } else { + size_t scratch_size = secp256k1_strauss_scratch_size(i); + scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + } + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + } + free(sc); + free(pt); +} + +static void run_ecmult_multi_tests(void) { + secp256k1_scratch *scratch; + int64_t todo = (int64_t)320 * COUNT; + + test_secp256k1_pippenger_bucket_window_inv(); + test_ecmult_multi_pippenger_max_points(); + scratch = secp256k1_scratch_create(&CTX->error_callback, 819200); + test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); + test_ecmult_multi(NULL, secp256k1_ecmult_multi_var); + test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single); + test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single); + test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single); + test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single); + while (todo > 0) { + todo -= test_ecmult_multi_random(scratch); + } + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + + /* Run test_ecmult_multi with space for exactly one point */ + scratch = secp256k1_scratch_create(&CTX->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + + test_ecmult_multi_batch_size_helper(); + test_ecmult_multi_batching(); +} + +static void test_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, two, t; + int wnaf[256]; + int zeroes = -1; + int i; + int bits; + secp256k1_scalar_set_int(&x, 0); + secp256k1_scalar_set_int(&two, 2); + bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w); + CHECK(bits <= 256); + for (i = bits-1; i >= 0; i--) { + int v = wnaf[i]; + secp256k1_scalar_mul(&x, &x, &two); + if (v) { + CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */ + zeroes=0; + CHECK((v & 1) == 1); /* check non-zero elements are odd */ + CHECK(v <= (1 << (w-1)) - 1); /* check range below */ + CHECK(v >= -(1 << (w-1)) - 1); /* check range above */ + } else { + CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */ + zeroes++; + } + if (v >= 0) { + secp256k1_scalar_set_int(&t, v); + } else { + secp256k1_scalar_set_int(&t, -v); + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_add(&x, &x, &t); + } + CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ +} + +static void test_fixed_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, shift; + int wnaf[256] = {0}; + int i; + int skew; + secp256k1_scalar num, unused; + + secp256k1_scalar_set_int(&x, 0); + secp256k1_scalar_set_int(&shift, 1 << w); + /* Make num a 128-bit scalar. */ + secp256k1_scalar_split_128(&num, &unused, number); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + + for (i = WNAF_SIZE(w)-1; i >= 0; --i) { + secp256k1_scalar t; + int v = wnaf[i]; + CHECK(v == 0 || v & 1); /* check parity */ + CHECK(v > -(1 << w)); /* check range above */ + CHECK(v < (1 << w)); /* check range below */ + + secp256k1_scalar_mul(&x, &x, &shift); + if (v >= 0) { + secp256k1_scalar_set_int(&t, v); + } else { + secp256k1_scalar_set_int(&t, -v); + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_add(&x, &x, &t); + } + /* If skew is 1 then add 1 to num */ + secp256k1_scalar_cadd_bit(&num, 0, skew == 1); + CHECK(secp256k1_scalar_eq(&x, &num)); +} + +/* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the + * rest is 0.*/ +static void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { + int i; + for (i = WNAF_SIZE(w)-1; i >= 8; --i) { + CHECK(wnaf[i] == 0); + } + for (i = 7; i >= 0; --i) { + CHECK(wnaf[i] == wnaf_expected[i]); + } +} + +static void test_fixed_wnaf_small(void) { + int w = 4; + int wnaf[256] = {0}; + int i; + int skew; + secp256k1_scalar num; + + secp256k1_scalar_set_int(&num, 0); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + for (i = WNAF_SIZE(w)-1; i >= 0; --i) { + int v = wnaf[i]; + CHECK(v == 0); + } + CHECK(skew == 0); + + secp256k1_scalar_set_int(&num, 1); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + for (i = WNAF_SIZE(w)-1; i >= 1; --i) { + int v = wnaf[i]; + CHECK(v == 0); + } + CHECK(wnaf[0] == 1); + CHECK(skew == 0); + + { + int wnaf_expected[8] = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }; + secp256k1_scalar_set_int(&num, 0xffffffff); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } + { + int wnaf_expected[8] = { -1, -1, -1, -1, -1, -1, -1, 0xf }; + secp256k1_scalar_set_int(&num, 0xeeeeeeee); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 1); + } + { + int wnaf_expected[8] = { 1, 0, 1, 0, 1, 0, 1, 0 }; + secp256k1_scalar_set_int(&num, 0x01010101); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } + { + int wnaf_expected[8] = { -0xf, 0, 0xf, -0xf, 0, 0xf, 1, 0 }; + secp256k1_scalar_set_int(&num, 0x01ef1ef1); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } +} + +static void run_wnaf(void) { + int i; + secp256k1_scalar n; + + /* Test 0 for fixed wnaf */ + test_fixed_wnaf_small(); + /* Random tests */ + for (i = 0; i < COUNT; i++) { + testutil_random_scalar_order(&n); + test_wnaf(&n, 4+(i%10)); + test_fixed_wnaf(&n, 4 + (i % 10)); + } + secp256k1_scalar_set_int(&n, 0); + CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1); + CHECK(secp256k1_scalar_is_zero(&n)); + CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1); + CHECK(secp256k1_scalar_is_zero(&n)); +} + +static int test_ecmult_accumulate_cb(secp256k1_scalar* sc, secp256k1_ge* pt, size_t idx, void* data) { + const secp256k1_scalar* indata = (const secp256k1_scalar*)data; + *sc = *indata; + *pt = secp256k1_ge_const_g; + CHECK(idx == 0); + return 1; +} + +static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, secp256k1_scratch* scratch) { + /* Compute x*G in 6 different ways, serialize it uncompressed, and feed it into acc. */ + secp256k1_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj; + secp256k1_ge r; + unsigned char bytes[65]; + size_t size = 65; + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); + secp256k1_gej_set_infinity(&infj); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj1, x); + secp256k1_ecmult(&rj2, &gj, x, &secp256k1_scalar_zero); + secp256k1_ecmult(&rj3, &infj, &secp256k1_scalar_zero, x); + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj4, x, NULL, NULL, 0)); + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj5, &secp256k1_scalar_zero, test_ecmult_accumulate_cb, (void*)x, 1)); + secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x); + secp256k1_ge_set_gej_var(&r, &rj1); + CHECK(secp256k1_gej_eq_ge_var(&rj2, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj3, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj4, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj5, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj6, &r)); + if (secp256k1_ge_is_infinity(&r)) { + /* Store infinity as 0x00 */ + const unsigned char zerobyte[1] = {0}; + secp256k1_sha256_write(acc, zerobyte, 1); + } else { + /* Store other points using their uncompressed serialization. */ + secp256k1_eckey_pubkey_serialize(&r, bytes, &size, 0); + CHECK(size == 65); + secp256k1_sha256_write(acc, bytes, size); + } +} + +static void test_ecmult_constants_2bit(void) { + /* Using test_ecmult_accumulate, test ecmult for: + * - For i in 0..36: + * - Key i + * - Key -i + * - For i in 0..255: + * - For j in 1..255 (only odd values): + * - Key (j*2^i) mod order + */ + secp256k1_scalar x; + secp256k1_sha256 acc; + unsigned char b32[32]; + int i, j; + secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536); + + /* Expected hash of all the computed points; created with an independent + * implementation. */ + static const unsigned char expected32[32] = { + 0xe4, 0x71, 0x1b, 0x4d, 0x14, 0x1e, 0x68, 0x48, + 0xb7, 0xaf, 0x47, 0x2b, 0x4c, 0xd2, 0x04, 0x14, + 0x3a, 0x75, 0x87, 0x60, 0x1a, 0xf9, 0x63, 0x60, + 0xd0, 0xcb, 0x1f, 0xaa, 0x85, 0x9a, 0xb7, 0xb4 + }; + secp256k1_sha256_initialize(&acc); + for (i = 0; i <= 36; ++i) { + secp256k1_scalar_set_int(&x, i); + test_ecmult_accumulate(&acc, &x, scratch); + secp256k1_scalar_negate(&x, &x); + test_ecmult_accumulate(&acc, &x, scratch); + }; + for (i = 0; i < 256; ++i) { + for (j = 1; j < 256; j += 2) { + int k; + secp256k1_scalar_set_int(&x, j); + for (k = 0; k < i; ++k) secp256k1_scalar_add(&x, &x, &x); + test_ecmult_accumulate(&acc, &x, scratch); + } + } + secp256k1_sha256_finalize(&acc, b32); + CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0); + + secp256k1_scratch_space_destroy(CTX, scratch); +} + +static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) { + /* Using test_ecmult_accumulate, test ecmult for: + * - Key 0 + * - Key 1 + * - Key -1 + * - For i in range(iter): + * - Key SHA256(LE32(prefix) || LE16(i)) + */ + secp256k1_scalar x; + secp256k1_sha256 acc; + unsigned char b32[32]; + unsigned char inp[6]; + size_t i; + secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536); + + inp[0] = prefix & 0xFF; + inp[1] = (prefix >> 8) & 0xFF; + inp[2] = (prefix >> 16) & 0xFF; + inp[3] = (prefix >> 24) & 0xFF; + secp256k1_sha256_initialize(&acc); + secp256k1_scalar_set_int(&x, 0); + test_ecmult_accumulate(&acc, &x, scratch); + secp256k1_scalar_set_int(&x, 1); + test_ecmult_accumulate(&acc, &x, scratch); + secp256k1_scalar_negate(&x, &x); + test_ecmult_accumulate(&acc, &x, scratch); + + for (i = 0; i < iter; ++i) { + secp256k1_sha256 gen; + inp[4] = i & 0xff; + inp[5] = (i >> 8) & 0xff; + secp256k1_sha256_initialize(&gen); + secp256k1_sha256_write(&gen, inp, sizeof(inp)); + secp256k1_sha256_finalize(&gen, b32); + secp256k1_scalar_set_b32(&x, b32, NULL); + test_ecmult_accumulate(&acc, &x, scratch); + } + secp256k1_sha256_finalize(&acc, b32); + CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0); + + secp256k1_scratch_space_destroy(CTX, scratch); +} + +static void run_ecmult_constants(void) { + /* Expected hashes of all points in the tests below. Computed using an + * independent implementation. */ + static const unsigned char expected32_6bit20[32] = { + 0x68, 0xb6, 0xed, 0x6f, 0x28, 0xca, 0xc9, 0x7f, + 0x8e, 0x8b, 0xd6, 0xc0, 0x61, 0x79, 0x34, 0x6e, + 0x5a, 0x8f, 0x2b, 0xbc, 0x3e, 0x1f, 0xc5, 0x2e, + 0x2a, 0xd0, 0x45, 0x67, 0x7f, 0x95, 0x95, 0x8e + }; + static const unsigned char expected32_8bit8[32] = { + 0x8b, 0x65, 0x8e, 0xea, 0x86, 0xae, 0x3c, 0x95, + 0x90, 0xb6, 0x77, 0xa4, 0x8c, 0x76, 0xd9, 0xec, + 0xf5, 0xab, 0x8a, 0x2f, 0xfd, 0xdb, 0x19, 0x12, + 0x1a, 0xee, 0xe6, 0xb7, 0x6e, 0x05, 0x3f, 0xc6 + }; + /* For every combination of 6 bit positions out of 256, restricted to + * 20-bit windows (i.e., the first and last bit position are no more than + * 19 bits apart), all 64 bit patterns occur in the input scalars used in + * this test. */ + CONDITIONAL_TEST(1, "test_ecmult_constants_sha 1024") { + test_ecmult_constants_sha(4808378u, 1024, expected32_6bit20); + } + + /* For every combination of 8 consecutive bit positions, all 256 bit + * patterns occur in the input scalars used in this test. */ + CONDITIONAL_TEST(3, "test_ecmult_constants_sha 2048") { + test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8); + } + + CONDITIONAL_TEST(16, "test_ecmult_constants_2bit") { + test_ecmult_constants_2bit(); + } +} + +static void test_ecmult_gen_blind(void) { + /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ + secp256k1_scalar key; + secp256k1_scalar b; + unsigned char seed32[32]; + secp256k1_gej pgej; + secp256k1_gej pgej2; + secp256k1_ge p; + secp256k1_ge pge; + testutil_random_scalar_order_test(&key); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej, &key); + testrand256(seed32); + b = CTX->ecmult_gen_ctx.scalar_offset; + p = CTX->ecmult_gen_ctx.ge_offset; + secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, seed32); + CHECK(!secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej2, &key); + CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); + CHECK(!secp256k1_ge_eq_var(&p, &CTX->ecmult_gen_ctx.ge_offset)); + secp256k1_ge_set_gej(&pge, &pgej); + CHECK(secp256k1_gej_eq_ge_var(&pgej2, &pge)); +} + +static void test_ecmult_gen_blind_reset(void) { + /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ + secp256k1_scalar b; + secp256k1_ge p1, p2; + secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); + b = CTX->ecmult_gen_ctx.scalar_offset; + p1 = CTX->ecmult_gen_ctx.ge_offset; + secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); + CHECK(secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); + p2 = CTX->ecmult_gen_ctx.ge_offset; + CHECK(secp256k1_ge_eq_var(&p1, &p2)); +} + +/* Verify that ecmult_gen for scalars gn for which gn + scalar_offset = {-1,0,1}. */ +static void test_ecmult_gen_edge_cases(void) { + int i; + secp256k1_gej res1, res2, res3; + secp256k1_scalar gn = secp256k1_scalar_one; /* gn = 1 */ + secp256k1_scalar_add(&gn, &gn, &CTX->ecmult_gen_ctx.scalar_offset); /* gn = 1 + scalar_offset */ + secp256k1_scalar_negate(&gn, &gn); /* gn = -1 - scalar_offset */ + + for (i = -1; i < 2; ++i) { + /* Run test with gn = i - scalar_offset (so that the ecmult_gen recoded value represents i). */ + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &res1, &gn); + secp256k1_ecmult(&res2, NULL, &secp256k1_scalar_zero, &gn); + secp256k1_ecmult_const(&res3, &secp256k1_ge_const_g, &gn); + CHECK(secp256k1_gej_eq_var(&res1, &res2)); + CHECK(secp256k1_gej_eq_var(&res1, &res3)); + secp256k1_scalar_add(&gn, &gn, &secp256k1_scalar_one); + } +} + +static void run_ecmult_gen_blind(void) { + int i; + test_ecmult_gen_blind_reset(); + test_ecmult_gen_edge_cases(); + for (i = 0; i < 10; i++) { + test_ecmult_gen_blind(); + } +} + +/***** ENDOMORPHISH TESTS *****/ +static void test_scalar_split(const secp256k1_scalar* full) { + secp256k1_scalar s, s1, slam; + const unsigned char zero[32] = {0}; + unsigned char tmp[32]; + + secp256k1_scalar_split_lambda(&s1, &slam, full); + + /* check slam*lambda + s1 == full */ + secp256k1_scalar_mul(&s, &secp256k1_const_lambda, &slam); + secp256k1_scalar_add(&s, &s, &s1); + CHECK(secp256k1_scalar_eq(&s, full)); + + /* check that both are <= 128 bits in size */ + if (secp256k1_scalar_is_high(&s1)) { + secp256k1_scalar_negate(&s1, &s1); + } + if (secp256k1_scalar_is_high(&slam)) { + secp256k1_scalar_negate(&slam, &slam); + } + + secp256k1_scalar_get_b32(tmp, &s1); + CHECK(secp256k1_memcmp_var(zero, tmp, 16) == 0); + secp256k1_scalar_get_b32(tmp, &slam); + CHECK(secp256k1_memcmp_var(zero, tmp, 16) == 0); +} + + +static void run_endomorphism_tests(void) { + unsigned i; + static secp256k1_scalar s; + test_scalar_split(&secp256k1_scalar_zero); + test_scalar_split(&secp256k1_scalar_one); + secp256k1_scalar_negate(&s,&secp256k1_scalar_one); + test_scalar_split(&s); + test_scalar_split(&secp256k1_const_lambda); + secp256k1_scalar_add(&s, &secp256k1_const_lambda, &secp256k1_scalar_one); + test_scalar_split(&s); + + for (i = 0; i < 100U * COUNT; ++i) { + secp256k1_scalar full; + testutil_random_scalar_order_test(&full); + test_scalar_split(&full); + } + for (i = 0; i < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++i) { + test_scalar_split(&scalars_near_split_bounds[i]); + } +} + +static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { + unsigned char pubkeyc[65]; + secp256k1_pubkey pubkey; + secp256k1_ge ge; + size_t pubkeyclen; + + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { + /* Smaller sizes are tested exhaustively elsewhere. */ + int32_t i; + memcpy(&pubkeyc[1], input, 64); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + for (i = 0; i < 256; i++) { + /* Try all type bytes. */ + int xpass; + int ypass; + int ysign; + pubkeyc[0] = i; + /* What sign does this point have? */ + ysign = (input[63] & 1) + 2; + /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */ + xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2); + /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */ + ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) && + ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65)); + if (xpass || ypass) { + /* These cases must parse. */ + unsigned char pubkeyo[65]; + size_t outl; + memset(&pubkey, 0, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); + CHECK(outl == 33); + CHECK(secp256k1_memcmp_var(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); + if (ypass) { + /* This test isn't always done because we decode with alternative signs, so the y won't match. */ + CHECK(pubkeyo[0] == ysign); + CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + secp256k1_pubkey_save(&pubkey, &ge); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); + CHECK(outl == 65); + CHECK(pubkeyo[0] == 4); + CHECK(secp256k1_memcmp_var(&pubkeyo[1], input, 64) == 0); + } + } else { + /* These cases must fail to parse. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); + } + } + } +} + +static void run_ec_pubkey_parse_test(void) { +#define SECP256K1_EC_PARSE_TEST_NVALID (12) + const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { + { + /* Point with leading and trailing zeros in x and y serialization. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83, + 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00 + }, + { + /* Point with x equal to a 3rd root of unity.*/ + 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, + 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with largest x. (1/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e, + 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d, + }, + { + /* Point with largest x. (2/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1, + 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2, + }, + { + /* Point with smallest x. (1/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with smallest x. (2/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* Point with largest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with smallest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } + }; +#define SECP256K1_EC_PARSE_TEST_NXVALID (4) + const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = { + { + /* Valid if y overflow ignored (y = 1 mod p). (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* x on curve, y is from y^2 = x^3 + 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 + } + }; +#define SECP256K1_EC_PARSE_TEST_NINVALID (7) + const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = { + { + /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */ + 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, + 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f, + 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0, + 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d, + 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2, + 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53 + } + }; + const unsigned char pubkeyc[66] = { + /* Serialization of G. */ + 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, + 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, + 0xB8, 0x00 + }; + unsigned char sout[65]; + unsigned char shortkey[2] = { 0 }; + secp256k1_ge ge; + secp256k1_pubkey pubkey; + size_t len; + int32_t i; + + /* Nothing should be reading this far into pubkeyc. */ + SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[65], 1); + /* Zero length claimed, fail, zeroize, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(shortkey, 2); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 0) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); + /* Length one claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 256 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + shortkey[0] = i; + SECP256K1_CHECKMEM_UNDEFINE(&shortkey[1], 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 1) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); + } + /* Length two claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 65536 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + shortkey[0] = i & 255; + shortkey[1] = i >> 8; + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 2) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); + } + memset(&pubkey, 0xfe, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 33) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); + /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, pubkeyc, 65)); + /* NULL input string. Illegal arg and zeroize output. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, &pubkey, NULL, 65)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); + /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 64) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); + /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 66) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); + /* Valid parse. */ + memset(&pubkey, 0, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 65) == 1); + CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, pubkeyc, 65) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&ge, sizeof(ge)); + CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1); + SECP256K1_CHECKMEM_CHECK(&ge.x, sizeof(ge.x)); + SECP256K1_CHECKMEM_CHECK(&ge.y, sizeof(ge.y)); + SECP256K1_CHECKMEM_CHECK(&ge.infinity, sizeof(ge.infinity)); + CHECK(secp256k1_ge_eq_var(&ge, &secp256k1_ge_const_g)); + /* secp256k1_ec_pubkey_serialize illegal args. */ + len = 65; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED)); + CHECK(len == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED)); + len = 65; + SECP256K1_CHECKMEM_UNDEFINE(sout, 65); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED)); + SECP256K1_CHECKMEM_CHECK(sout, 65); + CHECK(len == 0); + len = 65; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, ~0)); + CHECK(len == 0); + len = 65; + SECP256K1_CHECKMEM_UNDEFINE(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + SECP256K1_CHECKMEM_CHECK(sout, 65); + CHECK(len == 65); + /* Multiple illegal args. Should still set arg error only once. */ + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65)); + /* Try a bunch of prefabbed points with all possible encodings. */ + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { + ec_pubkey_parse_pointtest(valid[i], 1, 1); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) { + ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) { + ec_pubkey_parse_pointtest(invalid[i], 0, 0); + } +} + +static void run_eckey_edge_case_test(void) { + const unsigned char orderc[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00}; + unsigned char ctmp[33]; + unsigned char ctmp2[33]; + secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey2; + secp256k1_pubkey pubkey_one; + secp256k1_pubkey pubkey_negone; + const secp256k1_pubkey *pubkeys[3]; + size_t len; + /* Group order is too large, reject. */ + CHECK(secp256k1_ec_seckey_verify(CTX, orderc) == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, orderc) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Maximum value is too large, reject. */ + memset(ctmp, 255, 32); + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Zero is too small, reject. */ + memset(ctmp, 0, 32); + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* One must be accepted. */ + ctmp[31] = 0x01; + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_one = pubkey; + /* Group order + 1 is too large, reject. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x42; + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* -1 must be accepted. */ + ctmp[31] = 0x40; + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_negone = pubkey; + /* Tweak of zero leaves the value unchanged. */ + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 1); + CHECK(secp256k1_memcmp_var(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + memcpy(&pubkey2, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Multiply tweak of zero zeroizes the output. */ + CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing + seckey, the seckey is zeroized. */ + memcpy(ctmp, orderc, 32); + memset(ctmp2, 0, 32); + ctmp2[31] = 0x01; + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp2) == 1); + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); + /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing + tweak, the seckey is zeroized. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, orderc) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, orderc) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + /* If pubkey_tweak_add or pubkey_tweak_mul are called with an overflowing + tweak, the pubkey is zeroized. */ + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, orderc) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, orderc) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* If the resulting key in secp256k1_ec_seckey_tweak_add and + * secp256k1_ec_pubkey_tweak_add is 0 the functions fail and in the latter + * case the pubkey is zeroized. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + memset(ctmp2, 0, 32); + ctmp2[31] = 1; + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp2, 32) == 0); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Tweak computation wraps and results in a key of 1. */ + ctmp2[31] = 2; + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 1); + CHECK(secp256k1_memcmp_var(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, ctmp2) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Tweak mul * 2 = 1+1. */ + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Zeroize pubkey on parse error. */ + memset(&pubkey, 0, 32); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + memset(&pubkey2, 0, 32); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2)); + CHECK(secp256k1_memcmp_var(&pubkey2, zeros, sizeof(pubkey2)) == 0); + /* Plain argument errors. */ + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_verify(CTX, NULL)); + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, NULL)); + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, NULL)); + memset(ctmp2, 0, 32); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, ctmp, NULL)); + memset(ctmp2, 0, 32); + ctmp2[31] = 1; + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, ctmp, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, NULL, ctmp)); + memset(&pubkey, 1, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* secp256k1_ec_pubkey_combine tests. */ + pubkeys[0] = &pubkey_one; + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[0], sizeof(secp256k1_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[1], sizeof(secp256k1_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[2], sizeof(secp256k1_pubkey *)); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, NULL, pubkeys, 1)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, NULL, 1)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + pubkeys[0] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 1) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0); + /* Result is infinity. */ + pubkeys[0] = &pubkey_one; + pubkeys[1] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Passes through infinity but comes out one. */ + pubkeys[2] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0); + /* Adds to two. */ + pubkeys[1] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); +} + +static void run_eckey_negate_test(void) { + unsigned char seckey[32]; + unsigned char seckey_tmp[32]; + + testutil_random_scalar_order_b32(seckey); + memcpy(seckey_tmp, seckey, 32); + + /* Verify negation changes the key and changes it back */ + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) != 0); + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); + + /* Check that privkey alias gives same result */ + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); + CHECK(secp256k1_ec_privkey_negate(CTX, seckey_tmp) == 1); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); + + /* Negating all 0s fails */ + memset(seckey, 0, 32); + memset(seckey_tmp, 0, 32); + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 0); + /* Check that seckey is not modified */ + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); + + /* Negating an overflowing seckey fails and the seckey is zeroed. In this + * test, the seckey has 16 random bytes to ensure that ec_seckey_negate + * doesn't just set seckey to a constant value in case of failure. */ + testutil_random_scalar_order_b32(seckey); + memset(seckey, 0xFF, 16); + memset(seckey_tmp, 0, 32); + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 0); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); +} + +static void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { + secp256k1_scalar nonce; + do { + testutil_random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&CTX->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); +} + +static void test_ecdsa_sign_verify(void) { + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar one; + secp256k1_scalar msg, key; + secp256k1_scalar sigr, sigs; + int getrec; + int recid; + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + getrec = testrand_bits(1); + /* The specific way in which this conditional is written sidesteps a potential bug in clang. + See the commit messages of the commit that introduced this comment for details. */ + if (getrec) { + random_sign(&sigr, &sigs, &key, &msg, &recid); + CHECK(recid >= 0 && recid < 4); + } else { + random_sign(&sigr, &sigs, &key, &msg, NULL); + } + CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); + secp256k1_scalar_set_int(&one, 1); + secp256k1_scalar_add(&msg, &msg, &one); + CHECK(!secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); +} + +static void run_ecdsa_sign_verify(void) { + int i; + for (i = 0; i < 10*COUNT; i++) { + test_ecdsa_sign_verify(); + } +} + +/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ +static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void)msg32; + (void)key32; + (void)algo16; + memcpy(nonce32, data, 32); + return (counter == 0); +} + +static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + /* Dummy nonce generator that has a fatal error on the first counter value. */ + if (counter == 0) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1); +} + +static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ + if (counter < 3) { + memset(nonce32, counter==0 ? 0 : 255, 32); + if (counter == 2) { + nonce32[31]--; + } + return 1; + } + if (counter < 5) { + static const unsigned char order[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 + }; + memcpy(nonce32, order, 32); + if (counter == 4) { + nonce32[31]++; + } + return 1; + } + /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */ + /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ + if (counter > 5) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); +} + +static int is_empty_signature(const secp256k1_ecdsa_signature *sig) { + static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; + return secp256k1_memcmp_var(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; +} + +static void test_ecdsa_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + unsigned char privkey2[32]; + secp256k1_ecdsa_signature signature[6]; + secp256k1_scalar r, s; + unsigned char sig[74]; + size_t siglen = 74; + unsigned char pubkeyc[65]; + size_t pubkeyclen = 65; + secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey_tmp; + unsigned char seckey[300]; + size_t seckeylen = 300; + + /* Generate a random key and message. */ + { + secp256k1_scalar msg, key; + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); + + /* Verify exporting and importing public key. */ + CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyc, &pubkeyclen, &pubkey, testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + memset(&pubkey, 0, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); + + /* Verify negation changes the key and changes it back */ + memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey_tmp) == 1); + CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); + CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey_tmp) == 1); + CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); + + /* Verify private key import and export. */ + CHECK(ec_privkey_export_der(CTX, seckey, &seckeylen, privkey, testrand_bits(1) == 1)); + CHECK(ec_privkey_import_der(CTX, privkey2, seckey, seckeylen) == 1); + CHECK(secp256k1_memcmp_var(privkey, privkey2, 32) == 0); + + /* Optionally tweak the keys using addition. */ + if (testrand_int(3) == 0) { + int ret1; + int ret2; + int ret3; + unsigned char rnd[32]; + unsigned char privkey_tmp[32]; + secp256k1_pubkey pubkey2; + testrand256_test(rnd); + memcpy(privkey_tmp, privkey, 32); + ret1 = secp256k1_ec_seckey_tweak_add(CTX, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, rnd); + /* Check that privkey alias gives same result */ + ret3 = secp256k1_ec_privkey_tweak_add(CTX, privkey_tmp, rnd); + CHECK(ret1 == ret2); + CHECK(ret2 == ret3); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + } + + /* Optionally tweak the keys using multiplication. */ + if (testrand_int(3) == 0) { + int ret1; + int ret2; + int ret3; + unsigned char rnd[32]; + unsigned char privkey_tmp[32]; + secp256k1_pubkey pubkey2; + testrand256_test(rnd); + memcpy(privkey_tmp, privkey, 32); + ret1 = secp256k1_ec_seckey_tweak_mul(CTX, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, rnd); + /* Check that privkey alias gives same result */ + ret3 = secp256k1_ec_privkey_tweak_mul(CTX, privkey_tmp, rnd); + CHECK(ret1 == ret2); + CHECK(ret2 == ret3); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + } + + /* Sign. */ + CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &signature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &signature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_ecdsa_sign(CTX, &signature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_ecdsa_sign(CTX, &signature[3], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[2], &signature[3], sizeof(signature[0])) != 0); + /* Verify. */ + CHECK(secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[1], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[2], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[3], message, &pubkey) == 1); + /* Test lower-S form, malleate, verify and fail, test again, malleate again */ + CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[0])); + secp256k1_ecdsa_signature_load(CTX, &r, &s, &signature[0]); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_signature_normalize(CTX, &signature[5], &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(CTX, &signature[5], &signature[5])); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1); + CHECK(secp256k1_memcmp_var(&signature[5], &signature[0], 64) == 0); + + /* Serialize/parse DER and verify again */ + CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1); + memset(&signature[0], 0, sizeof(signature[0])); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1); + /* Serialize/destroy/parse DER and verify again. */ + siglen = 74; + CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1); + sig[testrand_int(siglen)] += 1 + testrand_int(255); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 0 || + secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 0); +} + +static void test_random_pubkeys(void) { + secp256k1_ge elem; + secp256k1_ge elem2; + unsigned char in[65]; + /* Generate some randomly sized pubkeys. */ + size_t len = testrand_bits(2) == 0 ? 65 : 33; + if (testrand_bits(2) == 0) { + len = testrand_bits(6); + } + if (len == 65) { + in[0] = testrand_bits(1) ? 4 : (testrand_bits(1) ? 6 : 7); + } else { + in[0] = testrand_bits(1) ? 2 : 3; + } + if (testrand_bits(3) == 0) { + in[0] = testrand_bits(8); + } + if (len > 1) { + testrand256(&in[1]); + } + if (len > 33) { + testrand256(&in[33]); + } + if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { + unsigned char out[65]; + unsigned char firstb; + int res; + size_t size = len; + firstb = in[0]; + /* If the pubkey can be parsed, it should round-trip... */ + CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); + CHECK(size == len); + CHECK(secp256k1_memcmp_var(&in[1], &out[1], len-1) == 0); + /* ... except for the type of hybrid inputs. */ + if ((in[0] != 6) && (in[0] != 7)) { + CHECK(in[0] == out[0]); + } + size = 65; + CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); + CHECK(size == 65); + CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); + CHECK(secp256k1_ge_eq_var(&elem2, &elem)); + /* Check that the X9.62 hybrid type is checked. */ + in[0] = testrand_bits(1) ? 6 : 7; + res = secp256k1_eckey_pubkey_parse(&elem2, in, size); + if (firstb == 2 || firstb == 3) { + if (in[0] == firstb + 4) { + CHECK(res); + } else { + CHECK(!res); + } + } + if (res) { + CHECK(secp256k1_ge_eq_var(&elem, &elem2)); + CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); + CHECK(secp256k1_memcmp_var(&in[1], &out[1], 64) == 0); + } + } +} + +static void run_pubkey_comparison(void) { + unsigned char pk1_ser[33] = { + 0x02, + 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, + 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 + }; + const unsigned char pk2_ser[33] = { + 0x02, + 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, + 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c + }; + secp256k1_pubkey pk1; + secp256k1_pubkey pk2; + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk1, pk1_ser, sizeof(pk1_ser)) == 1); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk2_ser, sizeof(pk2_ser)) == 1); + + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, NULL, &pk2) < 0)); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, NULL) > 0)); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk2) == 0); + { + secp256k1_pubkey pk_tmp; + memset(&pk_tmp, 0, sizeof(pk_tmp)); /* illegal pubkey */ + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk2) < 0)); + { + int32_t ecount = 0; + secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk_tmp) == 0); + CHECK(ecount == 2); + secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + } + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk_tmp) > 0)); + } + + /* Make pk2 the same as pk1 but with 3 rather than 2. Note that in + * an uncompressed encoding, these would have the opposite ordering */ + pk1_ser[0] = 3; + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk1_ser, sizeof(pk1_ser)) == 1); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0); +} + +static void test_sort_helper(secp256k1_pubkey *pk, size_t *pk_order, size_t n_pk) { + size_t i; + const secp256k1_pubkey *pk_test[5]; + + for (i = 0; i < n_pk; i++) { + pk_test[i] = &pk[pk_order[i]]; + } + secp256k1_ec_pubkey_sort(CTX, pk_test, n_pk); + for (i = 0; i < n_pk; i++) { + CHECK(secp256k1_memcmp_var(pk_test[i], &pk[i], sizeof(*pk_test[i])) == 0); + } +} + +static void permute(size_t *arr, size_t n) { + size_t i; + for (i = n - 1; i >= 1; i--) { + size_t tmp, j; + j = testrand_int(i + 1); + tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } +} + +static void test_sort_api(void) { + secp256k1_pubkey pks[2]; + const secp256k1_pubkey *pks_ptr[2]; + + pks_ptr[0] = &pks[0]; + pks_ptr[1] = &pks[1]; + + testutil_random_pubkey_test(&pks[0]); + testutil_random_pubkey_test(&pks[1]); + + CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_sort(CTX, NULL, 2)); + CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 0) == 1); + /* Test illegal public keys */ + memset(&pks[0], 0, sizeof(pks[0])); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1)); + memset(&pks[1], 0, sizeof(pks[1])); + { + int32_t ecount = 0; + secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); + CHECK(ecount == 2); + secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + } +} + +static void test_sort(void) { + secp256k1_pubkey pk[5]; + unsigned char pk_ser[5][33] = { + { 0x02, 0x08 }, + { 0x02, 0x0b }, + { 0x02, 0x0c }, + { 0x03, 0x05 }, + { 0x03, 0x0a }, + }; + int i; + size_t pk_order[5] = { 0, 1, 2, 3, 4 }; + + for (i = 0; i < 5; i++) { + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk[i], pk_ser[i], sizeof(pk_ser[i]))); + } + + permute(pk_order, 1); + test_sort_helper(pk, pk_order, 1); + permute(pk_order, 2); + test_sort_helper(pk, pk_order, 2); + permute(pk_order, 3); + test_sort_helper(pk, pk_order, 3); + for (i = 0; i < COUNT; i++) { + permute(pk_order, 4); + test_sort_helper(pk, pk_order, 4); + } + for (i = 0; i < COUNT; i++) { + permute(pk_order, 5); + test_sort_helper(pk, pk_order, 5); + } + /* Check that sorting also works for random pubkeys */ + for (i = 0; i < COUNT; i++) { + int j; + const secp256k1_pubkey *pk_ptr[5]; + for (j = 0; j < 5; j++) { + testutil_random_pubkey_test(&pk[j]); + pk_ptr[j] = &pk[j]; + } + secp256k1_ec_pubkey_sort(CTX, pk_ptr, 5); + for (j = 1; j < 5; j++) { + CHECK(secp256k1_ec_pubkey_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], CTX) <= 0); + } + } +} + +/* Test vectors from BIP-MuSig2 */ +static void test_sort_vectors(void) { + enum { N_PUBKEYS = 6 }; + unsigned char pk_ser[N_PUBKEYS][33] = { + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }, + { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, + 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, + 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, + 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, + 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }, + { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, + 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, + 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 }, + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xFF }, + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 } + }; + secp256k1_pubkey pubkeys[N_PUBKEYS]; + secp256k1_pubkey *sorted[N_PUBKEYS]; + const secp256k1_pubkey *pks_ptr[N_PUBKEYS]; + int i; + + sorted[0] = &pubkeys[3]; + sorted[1] = &pubkeys[0]; + sorted[2] = &pubkeys[0]; + sorted[3] = &pubkeys[4]; + sorted[4] = &pubkeys[1]; + sorted[5] = &pubkeys[2]; + + for (i = 0; i < N_PUBKEYS; i++) { + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkeys[i], pk_ser[i], sizeof(pk_ser[i]))); + pks_ptr[i] = &pubkeys[i]; + } + CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, N_PUBKEYS) == 1); + for (i = 0; i < N_PUBKEYS; i++) { + CHECK(secp256k1_memcmp_var(pks_ptr[i], sorted[i], sizeof(secp256k1_pubkey)) == 0); + } +} + +static void run_pubkey_sort(void) { + test_sort_api(); + test_sort(); + test_sort_vectors(); +} + + +static void run_random_pubkeys(void) { + int i; + for (i = 0; i < 10*COUNT; i++) { + test_random_pubkeys(); + } +} + +static void run_ecdsa_end_to_end(void) { + int i; + for (i = 0; i < 64*COUNT; i++) { + test_ecdsa_end_to_end(); + } +} + +static int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { + static const unsigned char zeroes[32] = {0}; + + int ret = 0; + + secp256k1_ecdsa_signature sig_der; + unsigned char roundtrip_der[2048]; + unsigned char compact_der[64]; + size_t len_der = 2048; + int parsed_der = 0, valid_der = 0, roundtrips_der = 0; + + secp256k1_ecdsa_signature sig_der_lax; + unsigned char roundtrip_der_lax[2048]; + unsigned char compact_der_lax[64]; + size_t len_der_lax = 2048; + int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; + + parsed_der = secp256k1_ecdsa_signature_parse_der(CTX, &sig_der, sig, siglen); + if (parsed_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(CTX, compact_der, &sig_der)) << 0; + valid_der = (secp256k1_memcmp_var(compact_der, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der + 32, zeroes, 32) != 0); + } + if (valid_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(CTX, roundtrip_der, &len_der, &sig_der)) << 1; + roundtrips_der = (len_der == siglen) && secp256k1_memcmp_var(roundtrip_der, sig, siglen) == 0; + } + + parsed_der_lax = ecdsa_signature_parse_der_lax(CTX, &sig_der_lax, sig, siglen); + if (parsed_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(CTX, compact_der_lax, &sig_der_lax)) << 10; + valid_der_lax = (secp256k1_memcmp_var(compact_der_lax, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der_lax + 32, zeroes, 32) != 0); + } + if (valid_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(CTX, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; + roundtrips_der_lax = (len_der_lax == siglen) && secp256k1_memcmp_var(roundtrip_der_lax, sig, siglen) == 0; + } + + if (certainly_der) { + ret |= (!parsed_der) << 2; + } + if (certainly_not_der) { + ret |= (parsed_der) << 17; + } + if (valid_der) { + ret |= (!roundtrips_der) << 3; + } + + if (valid_der) { + ret |= (!roundtrips_der_lax) << 12; + ret |= (len_der != len_der_lax) << 13; + ret |= ((len_der != len_der_lax) || (secp256k1_memcmp_var(roundtrip_der_lax, roundtrip_der, len_der) != 0)) << 14; + } + ret |= (roundtrips_der != roundtrips_der_lax) << 15; + if (parsed_der) { + ret |= (!parsed_der_lax) << 16; + } + + return ret; +} + +static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { + size_t i; + for (i = 0; i < ptrlen; i++) { + int shift = ptrlen - 1 - i; + if (shift >= 4) { + ptr[i] = 0; + } else { + ptr[i] = (val >> shift) & 0xFF; + } + } +} + +static void damage_array(unsigned char *sig, size_t *len) { + int pos; + int action = testrand_bits(3); + if (action < 1 && *len > 3) { + /* Delete a byte. */ + pos = testrand_int(*len); + memmove(sig + pos, sig + pos + 1, *len - pos - 1); + (*len)--; + return; + } else if (action < 2 && *len < 2048) { + /* Insert a byte. */ + pos = testrand_int(1 + *len); + memmove(sig + pos + 1, sig + pos, *len - pos); + sig[pos] = testrand_bits(8); + (*len)++; + return; + } else if (action < 4) { + /* Modify a byte. */ + sig[testrand_int(*len)] += 1 + testrand_int(255); + return; + } else { /* action < 8 */ + /* Modify a bit. */ + sig[testrand_int(*len)] ^= 1 << testrand_bits(3); + return; + } +} + +static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) { + int der; + int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2]; + size_t tlen, elen, glen; + int indet; + int n; + + *len = 0; + der = testrand_bits(2) == 0; + *certainly_der = der; + *certainly_not_der = 0; + indet = der ? 0 : testrand_int(10) == 0; + + for (n = 0; n < 2; n++) { + /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ + nlow[n] = der ? 1 : (testrand_bits(3) != 0); + /* The length of the number in bytes (the first byte of which will always be nonzero) */ + nlen[n] = nlow[n] ? testrand_int(33) : 32 + testrand_int(200) * testrand_bits(3) / 8; + CHECK(nlen[n] <= 232); + /* The top bit of the number. */ + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : testrand_bits(1)); + /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + testrand_bits(7) : 1 + testrand_int(127)); + /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? testrand_int(3) : testrand_int(300 - nlen[n]) * testrand_bits(3) / 8); + if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { + *certainly_not_der = 1; + } + CHECK(nlen[n] + nzlen[n] <= 300); + /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */ + nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); + if (!der) { + /* nlenlen[n] max 127 bytes */ + int add = testrand_int(127 - nlenlen[n]) * testrand_bits(4) * testrand_bits(4) / 256; + nlenlen[n] += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427); + } + + /* The total length of the data to go, so far */ + tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1]; + CHECK(tlen <= 856); + + /* The length of the garbage inside the tuple. */ + elen = (der || indet) ? 0 : testrand_int(980 - tlen) * testrand_bits(3) / 8; + if (elen != 0) { + *certainly_not_der = 1; + } + tlen += elen; + CHECK(tlen <= 980); + + /* The length of the garbage after the end of the tuple. */ + glen = der ? 0 : testrand_int(990 - tlen) * testrand_bits(3) / 8; + if (glen != 0) { + *certainly_not_der = 1; + } + CHECK(tlen + glen <= 990); + + /* Write the tuple header. */ + sig[(*len)++] = 0x30; + if (indet) { + /* Indeterminate length */ + sig[(*len)++] = 0x80; + *certainly_not_der = 1; + } else { + int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); + if (!der) { + int add = testrand_int(127 - tlenlen) * testrand_bits(4) * testrand_bits(4) / 256; + tlenlen += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + if (tlenlen == 0) { + /* Short length notation */ + sig[(*len)++] = tlen; + } else { + /* Long length notation */ + sig[(*len)++] = 128 + tlenlen; + assign_big_endian(sig + *len, tlenlen, tlen); + *len += tlenlen; + } + tlen += tlenlen; + } + tlen += 2; + CHECK(tlen + glen <= 1119); + + for (n = 0; n < 2; n++) { + /* Write the integer header. */ + sig[(*len)++] = 0x02; + if (nlenlen[n] == 0) { + /* Short length notation */ + sig[(*len)++] = nlen[n] + nzlen[n]; + } else { + /* Long length notation. */ + sig[(*len)++] = 128 + nlenlen[n]; + assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]); + *len += nlenlen[n]; + } + /* Write zero padding */ + while (nzlen[n] > 0) { + sig[(*len)++] = 0x00; + nzlen[n]--; + } + if (nlen[n] == 32 && !nlow[n]) { + /* Special extra 16 0xFF bytes in "high" 32-byte numbers */ + int i; + for (i = 0; i < 16; i++) { + sig[(*len)++] = 0xFF; + } + nlen[n] -= 16; + } + /* Write first byte of number */ + if (nlen[n] > 0) { + sig[(*len)++] = nhbyte[n]; + nlen[n]--; + } + /* Generate remaining random bytes of number */ + testrand_bytes_test(sig + *len, nlen[n]); + *len += nlen[n]; + nlen[n] = 0; + } + + /* Generate random garbage inside tuple. */ + testrand_bytes_test(sig + *len, elen); + *len += elen; + + /* Generate end-of-contents bytes. */ + if (indet) { + sig[(*len)++] = 0; + sig[(*len)++] = 0; + tlen += 2; + } + CHECK(tlen + glen <= 1121); + + /* Generate random garbage outside tuple. */ + testrand_bytes_test(sig + *len, glen); + *len += glen; + tlen += glen; + CHECK(tlen <= 1121); + CHECK(tlen == *len); +} + +static void run_ecdsa_der_parse(void) { + int i,j; + for (i = 0; i < 200 * COUNT; i++) { + unsigned char buffer[2048]; + size_t buflen = 0; + int certainly_der = 0; + int certainly_not_der = 0; + random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der); + CHECK(buflen <= 2048); + for (j = 0; j < 16; j++) { + int ret = 0; + if (j > 0) { + damage_array(buffer, &buflen); + /* We don't know anything anymore about the DERness of the result */ + certainly_der = 0; + certainly_not_der = 0; + } + ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der); + if (ret != 0) { + size_t k; + fprintf(stderr, "Failure %x on ", ret); + for (k = 0; k < buflen; k++) { + fprintf(stderr, "%02x ", buffer[k]); + } + fprintf(stderr, "\n"); + } + CHECK(ret == 0); + } + } +} + +/* Tests several edge cases. */ +static void test_ecdsa_edge_cases(void) { + int t; + secp256k1_ecdsa_signature sig; + + /* Test the case where ECDSA recomputes a point that is infinity. */ + { + secp256k1_gej keyj; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_negate(&ss, &ss); + secp256k1_scalar_inverse(&ss, &ss); + secp256k1_scalar_set_int(&sr, 1); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &keyj, &sr); + secp256k1_ge_set_gej(&key, &keyj); + msg = ss; + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with r of zero fails. */ + { + const unsigned char pubkey_mods_zero[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x41 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 0); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); + CHECK(secp256k1_ecdsa_sig_verify( &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with s of zero fails. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 0); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 1); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with message 0 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02 + }; + const unsigned char pubkey2[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x43 + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 2); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message 1 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22, + 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05, + 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c, + 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76, + 0x25 + }; + const unsigned char pubkey2[33] = { + 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40, + 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae, + 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f, + 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10, + 0x62 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message -1 passes. */ + { + const unsigned char pubkey[33] = { + 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0, + 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52, + 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27, + 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20, + 0xf1 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_negate(&msg, &msg); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + secp256k1_scalar_set_int(&ss, 3); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + } + + /* Signature where s would be zero. */ + { + secp256k1_pubkey pubkey; + size_t siglen; + unsigned char signature[72]; + static const unsigned char nonce[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + static const unsigned char nonce2[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 + }; + const unsigned char key[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + unsigned char msg[32] = { + 0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53, + 0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7, + 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, + 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, + }; + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); + msg[31] = 0xaa; + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2)); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, key) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, NULL, msg, &pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, NULL, &pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, NULL)); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL)); + /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey)); + siglen = 72; + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, NULL, signature, siglen)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen)); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, signature, siglen) == 1); + siglen = 10; + /* Too little room for a signature does not fail via ARGCHECK. */ + CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_normalize(CTX, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, NULL, &sig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, signature, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, &sig) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, NULL, signature)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, &sig, NULL)); + CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 1); + memset(signature, 255, 64); + CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 0); + } + + /* Nonce function corner cases. */ + for (t = 0; t < 2; t++) { + static const unsigned char zero[32] = {0x00}; + int i; + unsigned char key[32]; + unsigned char msg[32]; + secp256k1_ecdsa_signature sig2; + secp256k1_scalar sr[512], ss; + const unsigned char *extra; + extra = t == 0 ? NULL : zero; + memset(msg, 0, 32); + msg[31] = 1; + /* High key results in signature failure. */ + memset(key, 0xFF, 32); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* Zero key results in signature failure. */ + memset(key, 0, 32); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* Nonce function failure results in signature failure. */ + key[31] = 1; + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_fail, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* The retry loop successfully makes its way to the first good value. */ + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_retry, extra) == 1); + CHECK(!is_empty_signature(&sig)); + CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function is deterministic. */ + CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function changes output with different messages. */ + for(i = 0; i < 256; i++) { + int j; + msg[0] = i; + CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); + } + } + msg[0] = 0; + msg[31] = 2; + /* The default nonce function changes output with different keys. */ + for(i = 256; i < 512; i++) { + int j; + key[0] = i - 256; + CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); + } + } + key[0] = 0; + } + + { + /* Check that optional nonce arguments do not have equivalent effect. */ + const unsigned char zeros[32] = {0}; + unsigned char nonce[32]; + unsigned char nonce2[32]; + unsigned char nonce3[32]; + unsigned char nonce4[32]; + SECP256K1_CHECKMEM_UNDEFINE(nonce,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce2,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce3,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce4,32); + CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); + SECP256K1_CHECKMEM_CHECK(nonce,32); + CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); + SECP256K1_CHECKMEM_CHECK(nonce2,32); + CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); + SECP256K1_CHECKMEM_CHECK(nonce3,32); + CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); + SECP256K1_CHECKMEM_CHECK(nonce4,32); + CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce, nonce3, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce, nonce4, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce2, nonce3, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce2, nonce4, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce3, nonce4, 32) != 0); + } + + + /* Privkey export where pubkey is the point at infinity. */ + { + unsigned char privkey[300]; + unsigned char seckey[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, + }; + size_t outlen = 300; + CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 0)); + outlen = 300; + CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 1)); + } +} + +static void run_ecdsa_edge_cases(void) { + test_ecdsa_edge_cases(); +} + +/** Wycheproof tests + +The tests check for known attacks (range checks in (r,s), arithmetic errors, malleability). +*/ +static void test_ecdsa_wycheproof(void) { + #include "wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h" + + int t; + for (t = 0; t < SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS; t++) { + secp256k1_ecdsa_signature signature; + secp256k1_sha256 hasher; + secp256k1_pubkey pubkey; + const unsigned char *msg, *sig, *pk; + unsigned char out[32] = {0}; + int actual_verify = 0; + + memset(&pubkey, 0, sizeof(pubkey)); + pk = &wycheproof_ecdsa_public_keys[testvectors[t].pk_offset]; + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pk, 65) == 1); + + secp256k1_sha256_initialize(&hasher); + msg = &wycheproof_ecdsa_messages[testvectors[t].msg_offset]; + secp256k1_sha256_write(&hasher, msg, testvectors[t].msg_len); + secp256k1_sha256_finalize(&hasher, out); + + sig = &wycheproof_ecdsa_signatures[testvectors[t].sig_offset]; + if (secp256k1_ecdsa_signature_parse_der(CTX, &signature, sig, testvectors[t].sig_len) == 1) { + actual_verify = secp256k1_ecdsa_verify(CTX, (const secp256k1_ecdsa_signature *)&signature, out, &pubkey); + } + CHECK(testvectors[t].expected_verify == actual_verify); + } +} + +/* Tests cases from Wycheproof test suite. */ +static void run_ecdsa_wycheproof(void) { + test_ecdsa_wycheproof(); +} + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "modules/extrakeys/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/tests_impl.h" +#endif + +static void run_secp256k1_memczero_test(void) { + unsigned char buf1[6] = {1, 2, 3, 4, 5, 6}; + unsigned char buf2[sizeof(buf1)]; + + /* secp256k1_memczero(..., ..., 0) is a noop. */ + memcpy(buf2, buf1, sizeof(buf1)); + secp256k1_memczero(buf1, sizeof(buf1), 0); + CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); + + /* secp256k1_memczero(..., ..., 1) zeros the buffer. */ + memset(buf2, 0, sizeof(buf2)); + secp256k1_memczero(buf1, sizeof(buf1) , 1); + CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); +} + + +static void run_secp256k1_is_zero_array_test(void) { + unsigned char buf1[3] = {0, 1}; + unsigned char buf2[3] = {1, 0}; + + CHECK(secp256k1_is_zero_array(buf1, 0) == 1); + CHECK(secp256k1_is_zero_array(buf1, 1) == 1); + CHECK(secp256k1_is_zero_array(buf1, 2) == 0); + CHECK(secp256k1_is_zero_array(buf2, 1) == 0); + CHECK(secp256k1_is_zero_array(buf2, 2) == 0); +} + +static void run_secp256k1_byteorder_tests(void) { + { + const uint32_t x = 0xFF03AB45; + const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45}; + unsigned char buf[4]; + uint32_t x_; + + secp256k1_write_be32(buf, x); + CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0); + + x_ = secp256k1_read_be32(buf); + CHECK(x == x_); + } + + { + const uint64_t x = 0xCAFE0123BEEF4567; + const unsigned char x_be[8] = {0xCA, 0xFE, 0x01, 0x23, 0xBE, 0xEF, 0x45, 0x67}; + unsigned char buf[8]; + uint64_t x_; + + secp256k1_write_be64(buf, x); + CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0); + + x_ = secp256k1_read_be64(buf); + CHECK(x == x_); + } +} + +static void int_cmov_test(void) { + int r = INT_MAX; + int a = 0; + + secp256k1_int_cmov(&r, &a, 0); + CHECK(r == INT_MAX); + + r = 0; a = INT_MAX; + secp256k1_int_cmov(&r, &a, 1); + CHECK(r == INT_MAX); + + a = 0; + secp256k1_int_cmov(&r, &a, 1); + CHECK(r == 0); + + a = 1; + secp256k1_int_cmov(&r, &a, 1); + CHECK(r == 1); + + r = 1; a = 0; + secp256k1_int_cmov(&r, &a, 0); + CHECK(r == 1); + +} + +static void fe_cmov_test(void) { + static const secp256k1_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0); + static const secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + static const secp256k1_fe max = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + secp256k1_fe r = max; + secp256k1_fe a = zero; + + secp256k1_fe_cmov(&r, &a, 0); + CHECK(fe_identical(&r, &max)); + + r = zero; a = max; + secp256k1_fe_cmov(&r, &a, 1); + CHECK(fe_identical(&r, &max)); + + a = zero; + secp256k1_fe_cmov(&r, &a, 1); + CHECK(fe_identical(&r, &zero)); + + a = one; + secp256k1_fe_cmov(&r, &a, 1); + CHECK(fe_identical(&r, &one)); + + r = one; a = zero; + secp256k1_fe_cmov(&r, &a, 0); + CHECK(fe_identical(&r, &one)); +} + +static void fe_storage_cmov_test(void) { + static const secp256k1_fe_storage zero = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0); + static const secp256k1_fe_storage one = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + static const secp256k1_fe_storage max = SECP256K1_FE_STORAGE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + secp256k1_fe_storage r = max; + secp256k1_fe_storage a = zero; + + secp256k1_fe_storage_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + r = zero; a = max; + secp256k1_fe_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + a = zero; + secp256k1_fe_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); + + a = one; + secp256k1_fe_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); + + r = one; a = zero; + secp256k1_fe_storage_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); +} + +static void scalar_cmov_test(void) { + static const secp256k1_scalar max = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364140UL + ); + secp256k1_scalar r = max; + secp256k1_scalar a = secp256k1_scalar_zero; + + secp256k1_scalar_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + r = secp256k1_scalar_zero; a = max; + secp256k1_scalar_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + a = secp256k1_scalar_zero; + secp256k1_scalar_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_zero, sizeof(r)) == 0); + + a = secp256k1_scalar_one; + secp256k1_scalar_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_one, sizeof(r)) == 0); + + r = secp256k1_scalar_one; a = secp256k1_scalar_zero; + secp256k1_scalar_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_one, sizeof(r)) == 0); +} + +static void ge_storage_cmov_test(void) { + static const secp256k1_ge_storage zero = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + static const secp256k1_ge_storage one = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1); + static const secp256k1_ge_storage max = SECP256K1_GE_STORAGE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + secp256k1_ge_storage r = max; + secp256k1_ge_storage a = zero; + + secp256k1_ge_storage_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + r = zero; a = max; + secp256k1_ge_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + a = zero; + secp256k1_ge_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); + + a = one; + secp256k1_ge_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); + + r = one; a = zero; + secp256k1_ge_storage_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); +} + +static void run_cmov_tests(void) { + int_cmov_test(); + fe_cmov_test(); + fe_storage_cmov_test(); + scalar_cmov_test(); + ge_storage_cmov_test(); +} + +int main(int argc, char **argv) { + /* Disable buffering for stdout to improve reliability of getting + * diagnostic information. Happens right at the start of main because + * setbuf must be used before any other operation on the stream. */ + setbuf(stdout, NULL); + /* Also disable buffering for stderr because it's not guaranteed that it's + * unbuffered on all systems. */ + setbuf(stderr, NULL); + + /* find iteration count */ + if (argc > 1) { + COUNT = strtol(argv[1], NULL, 0); + } else { + const char* env = getenv("SECP256K1_TEST_ITERS"); + if (env && strlen(env) > 0) { + COUNT = strtol(env, NULL, 0); + } + } + if (COUNT <= 0) { + fputs("An iteration count of 0 or less is not allowed.\n", stderr); + return EXIT_FAILURE; + } + printf("test count = %i\n", COUNT); + + /* run test RNG tests (must run before we really initialize the test RNG) */ + run_xoshiro256pp_tests(); + + /* find random seed */ + testrand_init(argc > 2 ? argv[2] : NULL); + + /*** Setup test environment ***/ + + /* Create a global context available to all tests */ + CTX = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + /* Randomize the context only with probability 15/16 + to make sure we test without context randomization from time to time. + TODO Reconsider this when recalibrating the tests. */ + if (testrand_bits(4)) { + unsigned char rand32[32]; + testrand256(rand32); + CHECK(secp256k1_context_randomize(CTX, rand32)); + } + /* Make a writable copy of secp256k1_context_static in order to test the effect of API functions + that write to the context. The API does not support cloning the static context, so we use + memcpy instead. The user is not supposed to copy a context but we should still ensure that + the API functions handle copies of the static context gracefully. */ + STATIC_CTX = malloc(sizeof(*secp256k1_context_static)); + CHECK(STATIC_CTX != NULL); + memcpy(STATIC_CTX, secp256k1_context_static, sizeof(secp256k1_context)); + CHECK(!secp256k1_context_is_proper(STATIC_CTX)); + + /*** Run actual tests ***/ + + /* selftest tests */ + run_selftest_tests(); + + /* context tests */ + run_proper_context_tests(0); run_proper_context_tests(1); + run_static_context_tests(0); run_static_context_tests(1); + run_deprecated_context_flags_test(); + + /* scratch tests */ + run_scratch_tests(); + + /* integer arithmetic tests */ +#ifdef SECP256K1_WIDEMUL_INT128 + run_int128_tests(); +#endif + run_ctz_tests(); + run_modinv_tests(); + run_inverse_tests(); + + /* sorting tests */ + run_hsort_tests(); + + /* hash tests */ + run_sha256_known_output_tests(); + run_sha256_counter_tests(); + run_hmac_sha256_tests(); + run_rfc6979_hmac_sha256_tests(); + run_tagged_sha256_tests(); + + /* scalar tests */ + run_scalar_tests(); + + /* field tests */ + run_field_half(); + run_field_misc(); + run_field_convert(); + run_field_be32_overflow(); + run_fe_mul(); + run_sqr(); + run_sqrt(); + + /* group tests */ + run_ge(); + run_gej(); + run_group_decompress(); + + /* ecmult tests */ + run_ecmult_pre_g(); + run_wnaf(); + run_point_times_order(); + run_ecmult_near_split_bound(); + run_ecmult_chain(); + run_ecmult_constants(); + run_ecmult_gen_blind(); + run_ecmult_const_tests(); + run_ecmult_multi_tests(); + run_ec_combine(); + + /* endomorphism tests */ + run_endomorphism_tests(); + + /* EC point parser test */ + run_ec_pubkey_parse_test(); + + /* EC key edge cases */ + run_eckey_edge_case_test(); + + /* EC key arithmetic test */ + run_eckey_negate_test(); + +#ifdef ENABLE_MODULE_ECDH + /* ecdh tests */ + run_ecdh_tests(); +#endif + + /* ecdsa tests */ + run_ec_illegal_argument_tests(); + run_pubkey_comparison(); + run_pubkey_sort(); + run_random_pubkeys(); + run_ecdsa_der_parse(); + run_ecdsa_sign_verify(); + run_ecdsa_end_to_end(); + run_ecdsa_edge_cases(); + run_ecdsa_wycheproof(); + +#ifdef ENABLE_MODULE_RECOVERY + /* ECDSA pubkey recovery tests */ + run_recovery_tests(); +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS + run_extrakeys_tests(); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + run_schnorrsig_tests(); +#endif + +#ifdef ENABLE_MODULE_MUSIG + run_musig_tests(); +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT + run_ellswift_tests(); +#endif + + /* util tests */ + run_secp256k1_memczero_test(); + run_secp256k1_is_zero_array_test(); + run_secp256k1_byteorder_tests(); + + run_cmov_tests(); + + /*** Tear down test environment ***/ + free(STATIC_CTX); + secp256k1_context_destroy(CTX); + + testrand_finish(); + + printf("no problems found\n"); + return 0; +} diff --git a/external/secp256k1/src/tests_exhaustive.c b/external/secp256k1/src/tests_exhaustive.c new file mode 100644 index 00000000000..6efa88982ef --- /dev/null +++ b/external/secp256k1/src/tests_exhaustive.c @@ -0,0 +1,466 @@ +/*********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#include +#include +#include + +#ifndef EXHAUSTIVE_TEST_ORDER +/* see group_impl.h for allowable values */ +#define EXHAUSTIVE_TEST_ORDER 13 +#endif + +/* These values of B are all values in [1, 8] that result in a curve with even order. */ +#define EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER (SECP256K1_B == 1 || SECP256K1_B == 6 || SECP256K1_B == 8) + +#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS + #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in exhaustive_tests.") + #undef USE_EXTERNAL_DEFAULT_CALLBACKS +#endif +#include "secp256k1.c" + +#include "../include/secp256k1.h" +#include "assumptions.h" +#include "group.h" +#include "testrand_impl.h" +#include "ecmult_compute_table_impl.h" +#include "ecmult_gen_compute_table_impl.h" +#include "testutil.h" +#include "util.h" + +static int count = 2; + +static uint32_t num_cores = 1; +static uint32_t this_core = 0; + +SECP256K1_INLINE static int skip_section(uint64_t* iter) { + if (num_cores == 1) return 0; + *iter += 0xe7037ed1a0b428dbULL; + return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core; +} + +static int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, + const unsigned char *key32, const unsigned char *algo16, + void *data, unsigned int attempt) { + secp256k1_scalar s; + int *idata = data; + (void)msg32; + (void)key32; + (void)algo16; + /* Some nonces cannot be used because they'd cause s and/or r to be zero. + * The signing function has retry logic here that just re-calls the nonce + * function with an increased `attempt`. So if attempt > 0 this means we + * need to change the nonce to avoid an infinite loop. */ + if (attempt > 0) { + *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER; + } + secp256k1_scalar_set_int(&s, *idata); + secp256k1_scalar_get_b32(nonce32, &s); + return 1; +} + +static void test_exhaustive_endomorphism(const secp256k1_ge *group) { + int i; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_ge res; + secp256k1_ge_mul_lambda(&res, &group[i]); + CHECK(secp256k1_ge_eq_var(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res)); + } +} + +static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) { + int i, j; + uint64_t iter = 0; + + /* Sanity-check (and check infinity functions) */ + CHECK(secp256k1_ge_is_infinity(&group[0])); + CHECK(secp256k1_gej_is_infinity(&groupj[0])); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + CHECK(!secp256k1_ge_is_infinity(&group[i])); + CHECK(!secp256k1_gej_is_infinity(&groupj[i])); + } + + /* Check all addition formulae */ + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + secp256k1_fe fe_inv; + if (skip_section(&iter)) continue; + secp256k1_fe_inv(&fe_inv, &groupj[j].z); + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_ge zless_gej; + secp256k1_gej tmp; + /* add_var */ + secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); + /* add_ge */ + if (j > 0) { + secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); + } + /* add_ge_var */ + secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); + /* add_zinv_var */ + zless_gej.infinity = groupj[j].infinity; + zless_gej.x = groupj[j].x; + zless_gej.y = groupj[j].y; + secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); + } + } + + /* Check doubling */ + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_gej tmp; + secp256k1_gej_double(&tmp, &groupj[i]); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); + secp256k1_gej_double_var(&tmp, &groupj[i], NULL); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); + } + + /* Check negation */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_ge tmp; + secp256k1_gej tmpj; + secp256k1_ge_neg(&tmp, &group[i]); + CHECK(secp256k1_ge_eq_var(&tmp, &group[EXHAUSTIVE_TEST_ORDER - i])); + secp256k1_gej_neg(&tmpj, &groupj[i]); + CHECK(secp256k1_gej_eq_ge_var(&tmpj, &group[EXHAUSTIVE_TEST_ORDER - i])); + } +} + +static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_gej *groupj) { + int i, j, r_log; + uint64_t iter = 0; + for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + if (skip_section(&iter)) continue; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_gej tmp; + secp256k1_scalar na, ng; + secp256k1_scalar_set_int(&na, i); + secp256k1_scalar_set_int(&ng, j); + + secp256k1_ecmult(&tmp, &groupj[r_log], &na, &ng); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER])); + } + } + } + + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + int ret; + secp256k1_gej tmp; + secp256k1_fe xn, xd, tmpf; + secp256k1_scalar ng; + + if (skip_section(&iter)) continue; + + secp256k1_scalar_set_int(&ng, j); + + /* Test secp256k1_ecmult_const. */ + secp256k1_ecmult_const(&tmp, &group[i], &ng); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * j) % EXHAUSTIVE_TEST_ORDER])); + + if (i != 0 && j != 0) { + /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */ + ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0); + CHECK(ret); + CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); + + /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, with random xd. */ + testutil_random_fe_non_zero(&xd); + secp256k1_fe_mul(&xn, &xd, &group[i].x); + ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0); + CHECK(ret); + CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); + } + } + } +} + +typedef struct { + secp256k1_scalar sc[2]; + secp256k1_ge pt[2]; +} ecmult_multi_data; + +static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ecmult_multi_data *data = (ecmult_multi_data*) cbdata; + *sc = data->sc[idx]; + *pt = data->pt[idx]; + return 1; +} + +static void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i, j, k, x, y; + uint64_t iter = 0; + secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096); + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { + for (x = 0; x < EXHAUSTIVE_TEST_ORDER; x++) { + if (skip_section(&iter)) continue; + for (y = 0; y < EXHAUSTIVE_TEST_ORDER; y++) { + secp256k1_gej tmp; + secp256k1_scalar g_sc; + ecmult_multi_data data; + + secp256k1_scalar_set_int(&data.sc[0], i); + secp256k1_scalar_set_int(&data.sc[1], j); + secp256k1_scalar_set_int(&g_sc, k); + data.pt[0] = group[x]; + data.pt[1] = group[y]; + + secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER])); + } + } + } + } + } + secp256k1_scratch_destroy(&ctx->error_callback, scratch); +} + +static void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) { + secp256k1_fe x; + unsigned char x_bin[32]; + k %= EXHAUSTIVE_TEST_ORDER; + x = group[k].x; + secp256k1_fe_normalize(&x); + secp256k1_fe_get_b32(x_bin, &x); + secp256k1_scalar_set_b32(r, x_bin, overflow); +} + +static void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { + int s, r, msg, key; + uint64_t iter = 0; + for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { + for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { + for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { + for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int k, should_verify; + unsigned char msg32[32]; + + if (skip_section(&iter)) continue; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k, NULL); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* Verify by calling verify */ + secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + secp256k1_scalar_get_b32(msg32, &msg_s); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i, j, k; + uint64_t iter = 0; + + /* Loop */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ + if (skip_section(&iter)) continue; + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ + const int starting_k = k; + int ret; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + ret = secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + CHECK(ret == 1); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k, NULL); + CHECK(r == expected_r); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } + + /* We would like to verify zero-knowledge here by counting how often every + * possible (s, r) tuple appears, but because the group order is larger + * than the field order, when coercing the x-values to scalar values, some + * appear more often than others, so we are actually not zero-knowledge. + * (This effect also appears in the real code, but the difference is on the + * order of 1/2^128th the field order, so the deviation is not useful to a + * computationally bounded attacker.) + */ +} + +#ifdef ENABLE_MODULE_RECOVERY +#include "modules/recovery/tests_exhaustive_impl.h" +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +#include "modules/extrakeys/tests_exhaustive_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +#include "modules/schnorrsig/tests_exhaustive_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +#include "modules/ellswift/tests_exhaustive_impl.h" +#endif + +int main(int argc, char** argv) { + int i; + secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; + secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; + unsigned char rand32[32]; + secp256k1_context *ctx; + + /* Disable buffering for stdout to improve reliability of getting + * diagnostic information. Happens right at the start of main because + * setbuf must be used before any other operation on the stream. */ + setbuf(stdout, NULL); + /* Also disable buffering for stderr because it's not guaranteed that it's + * unbuffered on all systems. */ + setbuf(stderr, NULL); + + printf("Exhaustive tests for order %lu\n", (unsigned long)EXHAUSTIVE_TEST_ORDER); + + /* find iteration count */ + if (argc > 1) { + count = strtol(argv[1], NULL, 0); + } + printf("test count = %i\n", count); + + /* find random seed */ + testrand_init(argc > 2 ? argv[2] : NULL); + + /* set up split processing */ + if (argc > 4) { + num_cores = strtol(argv[3], NULL, 0); + this_core = strtol(argv[4], NULL, 0); + if (num_cores < 1 || this_core >= num_cores) { + fprintf(stderr, "Usage: %s [count] [seed] [numcores] [thiscore]\n", argv[0]); + return 1; + } + printf("running tests for core %lu (out of [0..%lu])\n", (unsigned long)this_core, (unsigned long)num_cores - 1); + } + + /* Recreate the ecmult{,_gen} tables using the right generator (as selected via EXHAUSTIVE_TEST_ORDER) */ + secp256k1_ecmult_gen_compute_table(&secp256k1_ecmult_gen_prec_table[0][0], &secp256k1_ge_const_g, COMB_BLOCKS, COMB_TEETH, COMB_SPACING); + secp256k1_ecmult_compute_two_tables(secp256k1_pre_g, secp256k1_pre_g_128, WINDOW_G, &secp256k1_ge_const_g); + + while (count--) { + /* Build context */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + testrand256(rand32); + CHECK(secp256k1_context_randomize(ctx, rand32)); + + /* Generate the entire group */ + secp256k1_gej_set_infinity(&groupj[0]); + secp256k1_ge_set_gej(&group[0], &groupj[0]); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); + secp256k1_ge_set_gej(&group[i], &groupj[i]); + if (count != 0) { + /* Set a different random z-value for each Jacobian point, except z=1 + is used in the last iteration. */ + secp256k1_fe z; + testutil_random_fe(&z); + secp256k1_gej_rescale(&groupj[i], &z); + } + + /* Verify against ecmult_gen */ + { + secp256k1_scalar scalar_i; + secp256k1_gej generatedj; + secp256k1_ge generated; + + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); + secp256k1_ge_set_gej(&generated, &generatedj); + + CHECK(group[i].infinity == 0); + CHECK(generated.infinity == 0); + CHECK(secp256k1_fe_equal(&generated.x, &group[i].x)); + CHECK(secp256k1_fe_equal(&generated.y, &group[i].y)); + } + } + + /* Run the tests */ + test_exhaustive_endomorphism(group); + test_exhaustive_addition(group, groupj); + test_exhaustive_ecmult(group, groupj); + test_exhaustive_ecmult_multi(ctx, group); + test_exhaustive_sign(ctx, group); + test_exhaustive_verify(ctx, group); + +#ifdef ENABLE_MODULE_RECOVERY + test_exhaustive_recovery(ctx, group); +#endif +#ifdef ENABLE_MODULE_EXTRAKEYS + test_exhaustive_extrakeys(ctx, group); +#endif +#ifdef ENABLE_MODULE_SCHNORRSIG + test_exhaustive_schnorrsig(ctx); +#endif +#ifdef ENABLE_MODULE_ELLSWIFT + /* The ellswift algorithm does have additional edge cases when operating on + * curves of even order, which are not included in the code as secp256k1 is + * of odd order. Skip the ellswift tests if the used exhaustive tests curve + * is even-ordered accordingly. */ + #if !EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER + test_exhaustive_ellswift(ctx, group); + #endif +#endif + + secp256k1_context_destroy(ctx); + } + + testrand_finish(); + + printf("no problems found\n"); + return 0; +} diff --git a/external/secp256k1/src/testutil.h b/external/secp256k1/src/testutil.h new file mode 100644 index 00000000000..64b3bb41c01 --- /dev/null +++ b/external/secp256k1/src/testutil.h @@ -0,0 +1,148 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_TESTUTIL_H +#define SECP256K1_TESTUTIL_H + +#include "field.h" +#include "group.h" +#include "testrand.h" +#include "util.h" + +static void testutil_random_fe(secp256k1_fe *x) { + unsigned char bin[32]; + do { + testrand256(bin); + if (secp256k1_fe_set_b32_limit(x, bin)) { + return; + } + } while(1); +} + +static void testutil_random_fe_non_zero(secp256k1_fe *nz) { + do { + testutil_random_fe(nz); + } while (secp256k1_fe_is_zero(nz)); +} + +static void testutil_random_fe_magnitude(secp256k1_fe *fe, int m) { + secp256k1_fe zero; + int n = testrand_int(m + 1); + secp256k1_fe_normalize(fe); + if (n == 0) { + return; + } + secp256k1_fe_set_int(&zero, 0); + secp256k1_fe_negate(&zero, &zero, 0); + secp256k1_fe_mul_int_unchecked(&zero, n - 1); + secp256k1_fe_add(fe, &zero); +#ifdef VERIFY + CHECK(fe->magnitude == n); +#endif +} + +static void testutil_random_fe_test(secp256k1_fe *x) { + unsigned char bin[32]; + do { + testrand256_test(bin); + if (secp256k1_fe_set_b32_limit(x, bin)) { + return; + } + } while(1); +} + +static void testutil_random_fe_non_zero_test(secp256k1_fe *fe) { + do { + testutil_random_fe_test(fe); + } while(secp256k1_fe_is_zero(fe)); +} + +static void testutil_random_ge_x_magnitude(secp256k1_ge *ge) { + testutil_random_fe_magnitude(&ge->x, SECP256K1_GE_X_MAGNITUDE_MAX); +} + +static void testutil_random_ge_y_magnitude(secp256k1_ge *ge) { + testutil_random_fe_magnitude(&ge->y, SECP256K1_GE_Y_MAGNITUDE_MAX); +} + +static void testutil_random_gej_x_magnitude(secp256k1_gej *gej) { + testutil_random_fe_magnitude(&gej->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); +} + +static void testutil_random_gej_y_magnitude(secp256k1_gej *gej) { + testutil_random_fe_magnitude(&gej->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); +} + +static void testutil_random_gej_z_magnitude(secp256k1_gej *gej) { + testutil_random_fe_magnitude(&gej->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); +} + +static void testutil_random_ge_test(secp256k1_ge *ge) { + secp256k1_fe fe; + do { + testutil_random_fe_test(&fe); + if (secp256k1_ge_set_xo_var(ge, &fe, testrand_bits(1))) { + secp256k1_fe_normalize(&ge->y); + break; + } + } while(1); + ge->infinity = 0; +} + +static void testutil_random_ge_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { + secp256k1_fe z2, z3; + testutil_random_fe_non_zero_test(&gej->z); + secp256k1_fe_sqr(&z2, &gej->z); + secp256k1_fe_mul(&z3, &z2, &gej->z); + secp256k1_fe_mul(&gej->x, &ge->x, &z2); + secp256k1_fe_mul(&gej->y, &ge->y, &z3); + gej->infinity = ge->infinity; +} + +static void testutil_random_gej_test(secp256k1_gej *gej) { + secp256k1_ge ge; + testutil_random_ge_test(&ge); + testutil_random_ge_jacobian_test(gej, &ge); +} + +static void testutil_random_pubkey_test(secp256k1_pubkey *pk) { + secp256k1_ge ge; + testutil_random_ge_test(&ge); + secp256k1_pubkey_save(pk, &ge); +} + +static void testutil_random_scalar_order_test(secp256k1_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + testrand256_test(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +static void testutil_random_scalar_order(secp256k1_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + testrand256(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +static void testutil_random_scalar_order_b32(unsigned char *b32) { + secp256k1_scalar num; + testutil_random_scalar_order(&num); + secp256k1_scalar_get_b32(b32, &num); +} + +#endif /* SECP256K1_TESTUTIL_H */ diff --git a/external/secp256k1/src/util.h b/external/secp256k1/src/util.h new file mode 100644 index 00000000000..88a4149421a --- /dev/null +++ b/external/secp256k1/src/util.h @@ -0,0 +1,451 @@ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_UTIL_H +#define SECP256K1_UTIL_H + +#include "../include/secp256k1.h" +#include "checkmem.h" + +#include +#include +#include +#include +#include +#if defined(_MSC_VER) +/* For SecureZeroMemory */ +#include +#endif + +#define STR_(x) #x +#define STR(x) STR_(x) +#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x +#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x)) + +/* Debug helper for printing arrays of unsigned char. */ +#define PRINT_BUF(buf, len) do { \ + printf("%s[%lu] = ", #buf, (unsigned long)len); \ + print_buf_plain(buf, len); \ +} while(0) + +static void print_buf_plain(const unsigned char *buf, size_t len) { + size_t i; + printf("{"); + for (i = 0; i < len; i++) { + if (i % 8 == 0) { + printf("\n "); + } else { + printf(" "); + } + printf("0x%02X,", buf[i]); + } + printf("\n}\n"); +} + +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(2,7) +# define SECP256K1_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define SECP256K1_INLINE __inline +# else +# define SECP256K1_INLINE +# endif +# else +# define SECP256K1_INLINE inline +# endif + +/** Assert statically that expr is true. + * + * This is a statement-like macro and can only be used inside functions. + */ +#define STATIC_ASSERT(expr) do { \ + switch(0) { \ + case 0: \ + /* If expr evaluates to 0, we have two case labels "0", which is illegal. */ \ + case /* ERROR: static assertion failed */ (expr): \ + ; \ + } \ +} while(0) + +/** Assert statically that expr is an integer constant expression, and run stmt. + * + * Useful for example to enforce that magnitude arguments are constant. + */ +#define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \ + switch(42) { \ + /* C allows only integer constant expressions as case labels. */ \ + case /* ERROR: integer argument is not constant */ (expr): \ + break; \ + default: ; \ + } \ + stmt; \ +} while(0) + +typedef struct { + void (*fn)(const char *text, void* data); + const void* data; +} secp256k1_callback; + +static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * const cb, const char * const text) { + cb->fn(text, (void*)cb->data); +} + +#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS +static void secp256k1_default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} +static void secp256k1_default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} +#else +void secp256k1_default_illegal_callback_fn(const char* str, void* data); +void secp256k1_default_error_callback_fn(const char* str, void* data); +#endif + +static const secp256k1_callback default_illegal_callback = { + secp256k1_default_illegal_callback_fn, + NULL +}; + +static const secp256k1_callback default_error_callback = { + secp256k1_default_error_callback_fn, + NULL +}; + + +#ifdef DETERMINISTIC +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s\n", msg); \ + abort(); \ +} while(0); +#else +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ + abort(); \ +} while(0) +#endif + +#if SECP256K1_GNUC_PREREQ(3, 0) +#define EXPECT(x,c) __builtin_expect((x),(c)) +#else +#define EXPECT(x,c) (x) +#endif + +#ifdef DETERMINISTIC +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed"); \ + } \ +} while(0) +#else +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed: " #cond); \ + } \ +} while(0) +#endif + +/* Like assert(), but when VERIFY is defined. */ +#if defined(VERIFY) +#define VERIFY_CHECK CHECK +#else +#define VERIFY_CHECK(cond) +#endif + +static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { + void *ret = malloc(size); + if (ret == NULL) { + secp256k1_callback_call(cb, "Out of memory"); + } + return ret; +} + +#if defined(__BIGGEST_ALIGNMENT__) +#define ALIGNMENT __BIGGEST_ALIGNMENT__ +#else +/* Using 16 bytes alignment because common architectures never have alignment + * requirements above 8 for any of the types we care about. In addition we + * leave some room because currently we don't care about a few bytes. */ +#define ALIGNMENT 16 +#endif + +/* ceil(x/y) for integers x > 0 and y > 0. Here, / denotes rational division. */ +#define CEIL_DIV(x, y) (1 + ((x) - 1) / (y)) + +#define ROUND_TO_ALIGN(size) (CEIL_DIV(size, ALIGNMENT) * ALIGNMENT) + +/* Macro for restrict, when available and not in a VERIFY build. */ +#if defined(SECP256K1_BUILD) && defined(VERIFY) +# define SECP256K1_RESTRICT +#else +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(3,0) +# define SECP256K1_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define SECP256K1_RESTRICT __restrict +# else +# define SECP256K1_RESTRICT +# endif +# else +# define SECP256K1_RESTRICT restrict +# endif +#endif + +#if defined(__GNUC__) +# define SECP256K1_GNUC_EXT __extension__ +#else +# define SECP256K1_GNUC_EXT +#endif + +/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */ +static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) { + unsigned char *p = (unsigned char *)s; + /* Access flag with a volatile-qualified lvalue. + This prevents clang from figuring out (after inlining) that flag can + take only be 0 or 1, which leads to variable time code. */ + volatile int vflag = flag; + unsigned char mask = -(unsigned char) vflag; + while (len) { + *p &= ~mask; + p++; + len--; + } +} + +/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ +static SECP256K1_INLINE void secp256k1_memclear(void *ptr, size_t len) { +#if defined(_MSC_VER) + /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ + SecureZeroMemory(ptr, len); +#elif defined(__GNUC__) + /* We use a memory barrier that scares the compiler away from optimizing out the memset. + * + * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f + * in BoringSSL (ISC License): + * As best as we can tell, this is sufficient to break any optimisations that + * might try to eliminate "superfluous" memsets. + * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it + * is pretty efficient, because the compiler can still implement the memset() efficently, + * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by + * Yang et al. (USENIX Security 2017) for more background. + */ + memset(ptr, 0, len); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#else + void *(*volatile const volatile_memset)(void *, int, size_t) = memset; + volatile_memset(ptr, 0, len); +#endif +#ifdef VERIFY + SECP256K1_CHECKMEM_UNDEFINE(ptr, len); +#endif +} + +/** Semantics like memcmp. Variable-time. + * + * We use this to avoid possible compiler bugs with memcmp, e.g. + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189 + */ +static SECP256K1_INLINE int secp256k1_memcmp_var(const void *s1, const void *s2, size_t n) { + const unsigned char *p1 = s1, *p2 = s2; + size_t i; + + for (i = 0; i < n; i++) { + int diff = p1[i] - p2[i]; + if (diff != 0) { + return diff; + } + } + return 0; +} + +/* Return 1 if all elements of array s are 0 and otherwise return 0. + * Constant-time. */ +static SECP256K1_INLINE int secp256k1_is_zero_array(const unsigned char *s, size_t len) { + unsigned char acc = 0; + int ret; + size_t i; + + for (i = 0; i < len; i++) { + acc |= s[i]; + } + ret = (acc == 0); + /* acc may contain secret values. Try to explicitly clear it. */ + secp256k1_memclear(&acc, sizeof(acc)); + return ret; +} + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/ +static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) { + unsigned int mask0, mask1, r_masked, a_masked; + /* Access flag with a volatile-qualified lvalue. + This prevents clang from figuring out (after inlining) that flag can + take only be 0 or 1, which leads to variable time code. */ + volatile int vflag = flag; + + /* Casting a negative int to unsigned and back to int is implementation defined behavior */ + VERIFY_CHECK(*r >= 0 && *a >= 0); + + mask0 = (unsigned int)vflag + ~0u; + mask1 = ~mask0; + r_masked = ((unsigned int)*r & mask0); + a_masked = ((unsigned int)*a & mask1); + + *r = (int)(r_masked | a_masked); +} + +#if defined(USE_FORCE_WIDEMUL_INT128_STRUCT) +/* If USE_FORCE_WIDEMUL_INT128_STRUCT is set, use int128_struct. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif defined(USE_FORCE_WIDEMUL_INT128) +/* If USE_FORCE_WIDEMUL_INT128 is set, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 +#elif defined(USE_FORCE_WIDEMUL_INT64) +/* If USE_FORCE_WIDEMUL_INT64 is set, use int64. */ +# define SECP256K1_WIDEMUL_INT64 1 +#elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__) +/* If a native 128-bit integer type exists, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) +/* On 64-bit MSVC targets (x86_64 and arm64), use int128_struct + * (which has special logic to implement using intrinsics on those systems). */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif SIZE_MAX > 0xffffffff +/* Systems with 64-bit pointers (and thus registers) very likely benefit from + * using 64-bit based arithmetic (even if we need to fall back to 32x32->64 based + * multiplication logic). */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#else +/* Lastly, fall back to int64 based arithmetic. */ +# define SECP256K1_WIDEMUL_INT64 1 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. + * This function is only intended to be used as fallback for + * secp256k1_ctz32_var, but permits it to be tested separately. */ +static SECP256K1_INLINE int secp256k1_ctz32_var_debruijn(uint32_t x) { + static const uint8_t debruijn[32] = { + 0x00, 0x01, 0x02, 0x18, 0x03, 0x13, 0x06, 0x19, 0x16, 0x04, 0x14, 0x0A, + 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, + 0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B + }; + return debruijn[(uint32_t)((x & -x) * 0x04D7651FU) >> 27]; +} + +/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. + * This function is only intended to be used as fallback for + * secp256k1_ctz64_var, but permits it to be tested separately. */ +static SECP256K1_INLINE int secp256k1_ctz64_var_debruijn(uint64_t x) { + static const uint8_t debruijn[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + return debruijn[(uint64_t)((x & -x) * 0x022FDD63CC95386DU) >> 58]; +} + +/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */ +static SECP256K1_INLINE int secp256k1_ctz32_var(uint32_t x) { + VERIFY_CHECK(x != 0); +#if (__has_builtin(__builtin_ctz) || SECP256K1_GNUC_PREREQ(3,4)) + /* If the unsigned type is sufficient to represent the largest uint32_t, consider __builtin_ctz. */ + if (((unsigned)UINT32_MAX) == UINT32_MAX) { + return __builtin_ctz(x); + } +#endif +#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) + /* Otherwise consider __builtin_ctzl (the unsigned long type is always at least 32 bits). */ + return __builtin_ctzl(x); +#else + /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ + return secp256k1_ctz32_var_debruijn(x); +#endif +} + +/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. */ +static SECP256K1_INLINE int secp256k1_ctz64_var(uint64_t x) { + VERIFY_CHECK(x != 0); +#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) + /* If the unsigned long type is sufficient to represent the largest uint64_t, consider __builtin_ctzl. */ + if (((unsigned long)UINT64_MAX) == UINT64_MAX) { + return __builtin_ctzl(x); + } +#endif +#if (__has_builtin(__builtin_ctzll) || SECP256K1_GNUC_PREREQ(3,4)) + /* Otherwise consider __builtin_ctzll (the unsigned long long type is always at least 64 bits). */ + return __builtin_ctzll(x); +#else + /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ + return secp256k1_ctz64_var_debruijn(x); +#endif +} + +/* Read a uint32_t in big endian */ +SECP256K1_INLINE static uint32_t secp256k1_read_be32(const unsigned char* p) { + return (uint32_t)p[0] << 24 | + (uint32_t)p[1] << 16 | + (uint32_t)p[2] << 8 | + (uint32_t)p[3]; +} + +/* Write a uint32_t in big endian */ +SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x) { + p[3] = x; + p[2] = x >> 8; + p[1] = x >> 16; + p[0] = x >> 24; +} + +/* Read a uint64_t in big endian */ +SECP256K1_INLINE static uint64_t secp256k1_read_be64(const unsigned char* p) { + return (uint64_t)p[0] << 56 | + (uint64_t)p[1] << 48 | + (uint64_t)p[2] << 40 | + (uint64_t)p[3] << 32 | + (uint64_t)p[4] << 24 | + (uint64_t)p[5] << 16 | + (uint64_t)p[6] << 8 | + (uint64_t)p[7]; +} + +/* Write a uint64_t in big endian */ +SECP256K1_INLINE static void secp256k1_write_be64(unsigned char* p, uint64_t x) { + p[7] = x; + p[6] = x >> 8; + p[5] = x >> 16; + p[4] = x >> 24; + p[3] = x >> 32; + p[2] = x >> 40; + p[1] = x >> 48; + p[0] = x >> 56; +} + +/* Rotate a uint32_t to the right. */ +SECP256K1_INLINE static uint32_t secp256k1_rotr32(const uint32_t x, const unsigned int by) { +#if defined(_MSC_VER) + return _rotr(x, by); /* needs */ +#else + /* Reduce rotation amount to avoid UB when shifting. */ + const unsigned int mask = CHAR_BIT * sizeof(x) - 1; + /* Turned into a rot instruction by GCC and clang. */ + return (x >> (by & mask)) | (x << ((-by) & mask)); +#endif +} + +#endif /* SECP256K1_UTIL_H */ diff --git a/external/secp256k1/src/wycheproof/WYCHEPROOF_COPYING b/external/secp256k1/src/wycheproof/WYCHEPROOF_COPYING new file mode 100644 index 00000000000..cddf9d9182b --- /dev/null +++ b/external/secp256k1/src/wycheproof/WYCHEPROOF_COPYING @@ -0,0 +1,212 @@ +* The file `ecdsa_secp256k1_sha256_bitcoin_test.json` in this directory + comes from Google's project Wycheproof with git commit + `b063b4aedae951c69df014cd25fa6d69ae9e8cb9`, see + https://github.com/google/wycheproof/blob/b063b4aedae951c69df014cd25fa6d69ae9e8cb9/testvectors_v1/ecdsa_secp256k1_sha256_bitcoin_test.json + +* The file `ecdsa_secp256k1_sha256_bitcoin_test.h` is generated from + `ecdsa_secp256k1_sha256_bitcoin_test.json` using the script + `tests_wycheproof_generate.py`. + +------------------------------------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h b/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h new file mode 100644 index 00000000000..736737fd61f --- /dev/null +++ b/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h @@ -0,0 +1,1564 @@ +/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */ +#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS (463) + +typedef struct { + size_t pk_offset; + size_t msg_offset; + size_t msg_len; + size_t sig_offset; + size_t sig_len; + int expected_verify; +} wycheproof_ecdsa_testvector; + +static const unsigned char wycheproof_ecdsa_messages[] = { 0x31,0x32,0x33,0x34,0x30,0x30, + 0x32,0x35,0x35,0x38,0x35, + 0x34,0x32,0x36,0x34,0x37,0x39,0x37,0x32,0x34, + 0x37,0x31,0x33,0x38,0x36,0x38,0x34,0x38,0x39,0x31, + 0x31,0x30,0x33,0x35,0x39,0x33,0x33,0x31,0x36,0x36,0x38, + 0x33,0x39,0x34,0x39,0x34,0x30,0x31,0x32,0x31,0x35, + 0x31,0x33,0x34,0x34,0x32,0x39,0x33,0x30,0x37,0x39, + 0x33,0x37,0x30,0x36,0x32,0x31,0x31,0x37,0x31,0x32, + 0x33,0x34,0x33,0x36,0x38,0x38,0x37,0x31,0x32, + 0x31,0x33,0x35,0x31,0x35,0x33,0x30,0x33,0x37,0x30, + 0x36,0x35,0x35,0x33,0x32,0x30,0x33,0x31,0x32,0x36, + 0x31,0x35,0x36,0x34,0x33,0x34,0x36,0x36,0x30,0x33, + 0x34,0x34,0x32,0x39,0x35,0x33,0x39,0x31,0x31,0x37, + 0x31,0x30,0x39,0x35,0x33,0x32,0x36,0x31,0x33,0x35,0x31, + 0x35,0x39,0x38,0x37,0x33,0x35,0x30,0x30,0x34,0x31, + 0x33,0x34,0x36,0x33,0x30,0x30,0x36,0x38,0x37,0x38, + 0x39,0x38,0x31,0x37,0x33,0x32,0x30,0x32,0x38,0x37, + 0x33,0x32,0x32,0x32,0x30,0x34,0x31,0x30,0x34,0x36, + 0x36,0x36,0x36,0x36,0x33,0x30,0x37,0x31,0x30,0x34, + 0x31,0x30,0x33,0x35,0x39,0x35,0x31,0x38,0x39,0x38, + 0x31,0x38,0x34,0x36,0x35,0x39,0x37,0x31,0x39,0x35, + 0x33,0x31,0x33,0x36,0x30,0x34,0x36,0x31,0x38,0x39, + 0x32,0x36,0x36,0x33,0x37,0x38,0x34,0x32,0x35,0x34, + 0x31,0x36,0x35,0x32,0x31,0x30,0x30,0x35,0x32,0x34, + 0x35,0x37,0x34,0x38,0x30,0x38,0x31,0x36,0x39,0x36, + 0x36,0x33,0x34,0x33,0x39,0x31,0x33,0x34,0x36,0x38, + 0x31,0x35,0x34,0x31,0x31,0x30,0x33,0x35,0x39,0x38, + 0x31,0x30,0x34,0x37,0x38,0x35,0x38,0x30,0x31,0x32,0x38, + 0x31,0x30,0x35,0x33,0x36,0x32,0x38,0x35,0x35,0x36,0x38, + 0x39,0x35,0x33,0x39,0x30,0x34,0x31,0x30,0x35, + 0x39,0x37,0x38,0x38,0x34,0x38,0x30,0x33,0x39, + 0x33,0x36,0x31,0x30,0x36,0x37,0x32,0x34,0x34,0x32, + 0x31,0x30,0x35,0x34,0x32,0x34,0x30,0x37,0x30,0x35, + 0x35,0x31,0x37,0x34,0x34,0x34,0x38,0x31,0x39,0x37, + 0x31,0x39,0x36,0x37,0x35,0x36,0x31,0x32,0x35,0x31, + 0x33,0x34,0x34,0x37,0x32,0x35,0x33,0x33,0x34,0x33, + 0x33,0x36,0x38,0x32,0x36,0x34,0x33,0x31,0x38, + 0x33,0x32,0x36,0x31,0x31,0x39,0x38,0x36,0x30,0x38, + 0x39,0x36,0x37,0x38,0x37,0x38,0x31,0x30,0x39,0x34, + 0x34,0x39,0x35,0x38,0x38,0x32,0x33,0x38,0x32,0x33, + 0x38,0x32,0x34,0x36,0x33,0x37,0x38,0x33,0x37, + 0x31,0x31,0x30,0x32,0x30,0x38,0x33,0x33,0x37,0x37,0x36, + 0x31,0x33,0x33,0x38,0x37,0x31,0x36,0x34,0x38, + 0x33,0x32,0x32,0x31,0x34,0x34,0x31,0x36,0x32, + 0x31,0x30,0x36,0x38,0x36,0x36,0x35,0x35,0x35,0x34,0x36, + 0x36,0x32,0x31,0x35,0x35,0x32,0x34,0x36, + 0x37,0x30,0x33,0x30,0x38,0x31,0x38,0x37,0x37,0x34, + 0x35,0x39,0x32,0x34,0x35,0x32,0x33,0x37,0x34,0x34, + 0x31,0x34,0x39,0x35,0x35,0x38,0x36,0x36,0x32,0x31, + 0x34,0x30,0x30,0x35,0x33,0x31,0x34,0x34,0x30,0x36, + 0x33,0x30,0x39,0x36,0x34,0x35,0x37,0x35,0x31,0x32, + 0x32,0x37,0x38,0x34,0x30,0x32,0x35,0x36,0x32,0x30, + 0x32,0x36,0x31,0x38,0x37,0x38,0x37,0x34,0x31,0x38, + 0x31,0x36,0x34,0x32,0x36,0x32,0x35,0x32,0x36,0x32, + 0x36,0x38,0x32,0x34,0x31,0x38,0x39,0x34,0x33,0x36, + 0x34,0x38,0x34,0x32,0x34,0x35,0x34,0x32,0x35, + 0x4d,0x73,0x67, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4d,0x65,0x73,0x73,0x61,0x67,0x65}; + +static const unsigned char wycheproof_ecdsa_public_keys[] = { 0x04,0xb8,0x38,0xff,0x44,0xe5,0xbc,0x17,0x7b,0xf2,0x11,0x89,0xd0,0x76,0x60,0x82,0xfc,0x9d,0x84,0x32,0x26,0x88,0x7f,0xc9,0x76,0x03,0x71,0x10,0x0b,0x7e,0xe2,0x0a,0x6f,0xf0,0xc9,0xd7,0x5b,0xfb,0xa7,0xb3,0x1a,0x6b,0xca,0x19,0x74,0x49,0x6e,0xeb,0x56,0xde,0x35,0x70,0x71,0x95,0x5d,0x83,0xc4,0xb1,0xba,0xda,0xa0,0xb2,0x18,0x32,0xe9, + 0x04,0x07,0x31,0x0f,0x90,0xa9,0xea,0xe1,0x49,0xa0,0x84,0x02,0xf5,0x41,0x94,0xa0,0xf7,0xb4,0xac,0x42,0x7b,0xf8,0xd9,0xbd,0x6c,0x76,0x81,0x07,0x1d,0xc4,0x7d,0xc3,0x62,0x26,0xa6,0xd3,0x7a,0xc4,0x6d,0x61,0xfd,0x60,0x0c,0x0b,0xf1,0xbf,0xf8,0x76,0x89,0xed,0x11,0x7d,0xda,0x6b,0x0e,0x59,0x31,0x8a,0xe0,0x10,0xa1,0x97,0xa2,0x6c,0xa0, + 0x04,0xbc,0x97,0xe7,0x58,0x5e,0xec,0xad,0x48,0xe1,0x66,0x83,0xbc,0x40,0x91,0x70,0x8e,0x1a,0x93,0x0c,0x68,0x3f,0xc4,0x70,0x01,0xd4,0xb3,0x83,0x59,0x4f,0x2c,0x4e,0x22,0x70,0x59,0x89,0xcf,0x69,0xda,0xea,0xdd,0x4e,0x4e,0x4b,0x81,0x51,0xed,0x88,0x8d,0xfe,0xc2,0x0f,0xb0,0x17,0x28,0xd8,0x9d,0x56,0xb3,0xf3,0x8f,0x2a,0xe9,0xc8,0xc5, + 0x04,0x44,0xad,0x33,0x9a,0xfb,0xc2,0x1e,0x9a,0xbf,0x7b,0x60,0x2a,0x5c,0xa5,0x35,0xea,0x37,0x81,0x35,0xb6,0xd1,0x0d,0x81,0x31,0x0b,0xdd,0x82,0x93,0xd1,0xdf,0x32,0x52,0xb6,0x3f,0xf7,0xd0,0x77,0x47,0x70,0xf8,0xfe,0x1d,0x17,0x22,0xfa,0x83,0xac,0xd0,0x2f,0x43,0x4e,0x4f,0xc1,0x10,0xa0,0xcc,0x8f,0x6d,0xdd,0xd3,0x7d,0x56,0xc4,0x63, + 0x04,0x12,0x60,0xc2,0x12,0x2c,0x9e,0x24,0x4e,0x1a,0xf5,0x15,0x1b,0xed,0xe0,0xc3,0xae,0x23,0xb5,0x4d,0x7c,0x59,0x68,0x81,0xd3,0xee,0xba,0xd2,0x1f,0x37,0xdd,0x87,0x8c,0x5c,0x9a,0x0c,0x1a,0x9a,0xde,0x76,0x73,0x7a,0x88,0x11,0xbd,0x6a,0x7f,0x92,0x87,0xc9,0x78,0xee,0x39,0x6a,0xa8,0x9c,0x11,0xe4,0x72,0x29,0xd2,0xcc,0xb5,0x52,0xf0, + 0x04,0x18,0x77,0x04,0x5b,0xe2,0x5d,0x34,0xa1,0xd0,0x60,0x0f,0x9d,0x5c,0x00,0xd0,0x64,0x5a,0x2a,0x54,0x37,0x9b,0x6c,0xee,0xfa,0xd2,0xe6,0xbf,0x5c,0x2a,0x33,0x52,0xce,0x82,0x1a,0x53,0x2c,0xc1,0x75,0x1e,0xe1,0xd3,0x6d,0x41,0xc3,0xd6,0xab,0x4e,0x9b,0x14,0x3e,0x44,0xec,0x46,0xd7,0x34,0x78,0xea,0x6a,0x79,0xa5,0xc0,0xe5,0x41,0x59, + 0x04,0x45,0x54,0x39,0xfc,0xc3,0xd2,0xde,0xec,0xed,0xde,0xae,0xce,0x60,0xe7,0xbd,0x17,0x30,0x4f,0x36,0xeb,0xb6,0x02,0xad,0xf5,0xa2,0x2e,0x0b,0x8f,0x1d,0xb4,0x6a,0x50,0xae,0xc3,0x8f,0xb2,0xba,0xf2,0x21,0xe9,0xa8,0xd1,0x88,0x7c,0x7b,0xf6,0x22,0x2d,0xd1,0x83,0x46,0x34,0xe7,0x72,0x63,0x31,0x5a,0xf6,0xd2,0x36,0x09,0xd0,0x4f,0x77, + 0x04,0x2e,0x1f,0x46,0x6b,0x02,0x4c,0x0c,0x3a,0xce,0x24,0x37,0xde,0x09,0x12,0x7f,0xed,0x04,0xb7,0x06,0xf9,0x4b,0x19,0xa2,0x1b,0xb1,0xc2,0xac,0xf3,0x5c,0xec,0xe7,0x18,0x04,0x49,0xae,0x35,0x23,0xd7,0x25,0x34,0xe9,0x64,0x97,0x2c,0xfd,0x3b,0x38,0xaf,0x0b,0xdd,0xd9,0x61,0x9e,0x5a,0xf2,0x23,0xe4,0xd1,0xa4,0x0f,0x34,0xcf,0x9f,0x1d, + 0x04,0x8e,0x7a,0xbd,0xbb,0xd1,0x8d,0xe7,0x45,0x23,0x74,0xc1,0x87,0x9a,0x1c,0x3b,0x01,0xd1,0x32,0x61,0xe7,0xd4,0x57,0x1c,0x3b,0x47,0xa1,0xc7,0x6c,0x55,0xa2,0x33,0x73,0x26,0xed,0x89,0x7c,0xd5,0x17,0xa4,0xf5,0x34,0x9d,0xb8,0x09,0x78,0x0f,0x6d,0x2f,0x2b,0x9f,0x62,0x99,0xd8,0xb5,0xa8,0x90,0x77,0xf1,0x11,0x9a,0x71,0x8f,0xd7,0xb3, + 0x04,0x7b,0x33,0x3d,0x43,0x40,0xd3,0xd7,0x18,0xdd,0x3e,0x6a,0xff,0x7d,0xe7,0xbb,0xf8,0xb7,0x2b,0xfd,0x61,0x6c,0x84,0x20,0x05,0x60,0x52,0x84,0x23,0x76,0xb9,0xaf,0x19,0x42,0x11,0x7c,0x5a,0xfe,0xac,0x75,0x5d,0x6f,0x37,0x6f,0xc6,0x32,0x9a,0x7d,0x76,0x05,0x1b,0x87,0x12,0x3a,0x4a,0x5d,0x0b,0xc4,0xa5,0x39,0x38,0x0f,0x03,0xde,0x7b, + 0x04,0xd3,0x0c,0xa4,0xa0,0xdd,0xb6,0x61,0x6c,0x85,0x1d,0x30,0xce,0xd6,0x82,0xc4,0x0f,0x83,0xc6,0x27,0x58,0xa1,0xf2,0x75,0x99,0x88,0xd6,0x76,0x3a,0x88,0xf1,0xc0,0xe5,0x03,0xa8,0x0d,0x54,0x15,0x65,0x0d,0x41,0x23,0x97,0x84,0xe8,0xe2,0xfb,0x12,0x35,0xe9,0xfe,0x99,0x1d,0x11,0x2e,0xbb,0x81,0x18,0x6c,0xbf,0x0d,0xa2,0xde,0x3a,0xff, + 0x04,0x48,0x96,0x9b,0x39,0x99,0x12,0x97,0xb3,0x32,0xa6,0x52,0xd3,0xee,0x6e,0x01,0xe9,0x09,0xb3,0x99,0x04,0xe7,0x1f,0xa2,0x35,0x4a,0x78,0x30,0xc7,0x75,0x0b,0xaf,0x24,0xb4,0x01,0x2d,0x1b,0x83,0x0d,0x19,0x9c,0xcb,0x1f,0xc9,0x72,0xb3,0x2b,0xfd,0xed,0x55,0xf0,0x9c,0xd6,0x2d,0x25,0x7e,0x5e,0x84,0x4e,0x27,0xe5,0x7a,0x15,0x94,0xec, + 0x04,0x02,0xef,0x4d,0x6d,0x6c,0xfd,0x5a,0x94,0xf1,0xd7,0x78,0x42,0x26,0xe3,0xe2,0xa6,0xc0,0xa4,0x36,0xc5,0x58,0x39,0x61,0x9f,0x38,0xfb,0x44,0x72,0xb5,0xf9,0xee,0x77,0x7e,0xb4,0xac,0xd4,0xee,0xbd,0xa5,0xcd,0x72,0x87,0x5f,0xfd,0x2a,0x2f,0x26,0x22,0x9c,0x2d,0xc6,0xb4,0x65,0x00,0x91,0x9a,0x43,0x2c,0x86,0x73,0x9f,0x3a,0xe8,0x66, + 0x04,0x46,0x4f,0x4f,0xf7,0x15,0x72,0x9c,0xae,0x50,0x72,0xca,0x3b,0xd8,0x01,0xd3,0x19,0x5b,0x67,0xae,0xc6,0x5e,0x9b,0x01,0xaa,0xd2,0x0a,0x29,0x43,0xdc,0xbc,0xb5,0x84,0xb1,0xaf,0xd2,0x9d,0x31,0xa3,0x9a,0x11,0xd5,0x70,0xaa,0x15,0x97,0x43,0x9b,0x3b,0x2d,0x19,0x71,0xbf,0x2f,0x1a,0xbf,0x15,0x43,0x2d,0x02,0x07,0xb1,0x0d,0x1d,0x08, + 0x04,0x15,0x7f,0x8f,0xdd,0xf3,0x73,0xeb,0x5f,0x49,0xcf,0xcf,0x10,0xd8,0xb8,0x53,0xcf,0x91,0xcb,0xcd,0x7d,0x66,0x5c,0x35,0x22,0xba,0x7d,0xd7,0x38,0xdd,0xb7,0x9a,0x4c,0xde,0xad,0xf1,0xa5,0xc4,0x48,0xea,0x3c,0x9f,0x41,0x91,0xa8,0x99,0x9a,0xbf,0xcc,0x75,0x7a,0xc6,0xd6,0x45,0x67,0xef,0x07,0x2c,0x47,0xfe,0xc6,0x13,0x44,0x3b,0x8f, + 0x04,0x09,0x34,0xa5,0x37,0x46,0x6c,0x07,0x43,0x0e,0x2c,0x48,0xfe,0xb9,0x90,0xbb,0x19,0xfb,0x78,0xce,0xcc,0x9c,0xee,0x42,0x4e,0xa4,0xd1,0x30,0x29,0x1a,0xa2,0x37,0xf0,0xd4,0xf9,0x2d,0x23,0xb4,0x62,0x80,0x4b,0x5b,0x68,0xc5,0x25,0x58,0xc0,0x1c,0x99,0x96,0xdb,0xf7,0x27,0xfc,0xca,0xbb,0xee,0xdb,0x96,0x21,0xa4,0x00,0x53,0x5a,0xfa, + 0x04,0xd6,0xef,0x20,0xbe,0x66,0xc8,0x93,0xf7,0x41,0xa9,0xbf,0x90,0xd9,0xb7,0x46,0x75,0xd1,0xc2,0xa3,0x12,0x96,0x39,0x7a,0xcb,0x3e,0xf1,0x74,0xfd,0x0b,0x30,0x0c,0x65,0x4a,0x0c,0x95,0x47,0x8c,0xa0,0x03,0x99,0x16,0x2d,0x7f,0x0f,0x2d,0xc8,0x9e,0xfd,0xc2,0xb2,0x8a,0x30,0xfb,0xab,0xe2,0x85,0x85,0x72,0x95,0xa4,0xb0,0xc4,0xe2,0x65, + 0x04,0xb7,0x29,0x1d,0x14,0x04,0xe0,0xc0,0xc0,0x7d,0xab,0x93,0x72,0x18,0x9f,0x4b,0xd5,0x8d,0x2c,0xea,0xa8,0xd1,0x5e,0xde,0x54,0x4d,0x95,0x14,0x54,0x5b,0xa9,0xee,0x06,0x29,0xc9,0xa6,0x3d,0x5e,0x30,0x87,0x69,0xcc,0x30,0xec,0x27,0x6a,0x41,0x0e,0x64,0x64,0xa2,0x7e,0xea,0xfd,0x9e,0x59,0x9d,0xb1,0x0f,0x05,0x3a,0x4f,0xe4,0xa8,0x29, + 0x04,0x6e,0x28,0x30,0x33,0x05,0xd6,0x42,0xcc,0xb9,0x23,0xb7,0x22,0xea,0x86,0xb2,0xa0,0xbc,0x8e,0x37,0x35,0xec,0xb2,0x6e,0x84,0x9b,0x19,0xc9,0xf7,0x6b,0x2f,0xdb,0xb8,0x18,0x6e,0x80,0xd6,0x4d,0x8c,0xab,0x16,0x4f,0x52,0x38,0xf5,0x31,0x84,0x61,0xbf,0x89,0xd4,0xd9,0x6e,0xe6,0x54,0x4c,0x81,0x6c,0x75,0x66,0x94,0x77,0x74,0xe0,0xf6, + 0x04,0x37,0x5b,0xda,0x93,0xf6,0xaf,0x92,0xfb,0x5f,0x8f,0x4b,0x1b,0x5f,0x05,0x34,0xe3,0xba,0xfa,0xb3,0x4c,0xb7,0xad,0x9f,0xb9,0xd0,0xb7,0x22,0xe4,0xa5,0xc3,0x02,0xa9,0xa0,0x0b,0x9f,0x38,0x7a,0x5a,0x39,0x60,0x97,0xaa,0x21,0x62,0xfc,0x5b,0xbc,0xf4,0xa5,0x26,0x33,0x72,0xf6,0x81,0xc9,0x4d,0xa5,0x1e,0x97,0x99,0x12,0x09,0x90,0xfd, + 0x04,0xd7,0x5b,0x68,0x21,0x6b,0xab,0xe0,0x3a,0xe2,0x57,0xe9,0x4b,0x4e,0x3b,0xf1,0xc5,0x2f,0x44,0xe3,0xdf,0x26,0x6d,0x15,0x24,0xff,0x8c,0x5e,0xa6,0x9d,0xa7,0x31,0x97,0xda,0x4b,0xff,0x9e,0xd1,0xc5,0x3f,0x44,0x91,0x7a,0x67,0xd7,0xb9,0x78,0x59,0x8e,0x89,0xdf,0x35,0x9e,0x3d,0x59,0x13,0xea,0xea,0x24,0xf3,0xae,0x25,0x9a,0xbc,0x44, + 0x04,0x78,0xbc,0xda,0x14,0x0a,0xed,0x23,0xd4,0x30,0xcb,0x23,0xc3,0xdc,0x0d,0x01,0xf4,0x23,0xdb,0x13,0x4e,0xe9,0x4a,0x3a,0x8c,0xb4,0x83,0xf2,0xde,0xac,0x2a,0xc6,0x53,0x11,0x81,0x14,0xf6,0xf3,0x30,0x45,0xd4,0xe9,0xed,0x91,0x07,0x08,0x50,0x07,0xbf,0xbd,0xdf,0x8f,0x58,0xfe,0x7a,0x1a,0x24,0x45,0xd6,0x6a,0x99,0x00,0x45,0x47,0x6e, + 0x04,0xbb,0x79,0xf6,0x18,0x57,0xf7,0x43,0xbf,0xa1,0xb6,0xe7,0x11,0x1c,0xe4,0x09,0x43,0x77,0x25,0x69,0x69,0xe4,0xe1,0x51,0x59,0x12,0x3d,0x95,0x48,0xac,0xc3,0xbe,0x6c,0x1f,0x9d,0x9f,0x88,0x60,0xdc,0xff,0xd3,0xeb,0x36,0xdd,0x6c,0x31,0xff,0x2e,0x72,0x26,0xc2,0x00,0x9c,0x4c,0x94,0xd8,0xd7,0xd2,0xb5,0x68,0x6b,0xf7,0xab,0xd6,0x77, + 0x04,0x93,0x59,0x18,0x27,0xd9,0xe6,0x71,0x3b,0x4e,0x9f,0xae,0xa6,0x2c,0x72,0xb2,0x8d,0xfe,0xfa,0x68,0xe0,0xc0,0x51,0x60,0xb5,0xd6,0xaa,0xe8,0x8f,0xd2,0xe3,0x6c,0x36,0x07,0x3f,0x55,0x45,0xad,0x5a,0xf4,0x10,0xaf,0x26,0xaf,0xff,0x68,0x65,0x4c,0xf7,0x2d,0x45,0xe4,0x93,0x48,0x93,0x11,0x20,0x32,0x47,0x34,0x7a,0x89,0x0f,0x45,0x18, + 0x04,0x31,0xed,0x30,0x81,0xae,0xfe,0x00,0x1e,0xb6,0x40,0x20,0x69,0xee,0x2c,0xcc,0x18,0x62,0x93,0x7b,0x85,0x99,0x51,0x44,0xdb,0xa9,0x50,0x39,0x43,0x58,0x7b,0xf0,0xda,0xda,0x01,0xb8,0xcc,0x4d,0xf3,0x4f,0x5a,0xb3,0xb1,0xa3,0x59,0x61,0x52,0x08,0x94,0x6e,0x5e,0xe3,0x5f,0x98,0xee,0x77,0x5b,0x8c,0xce,0xcd,0x86,0xcc,0xc1,0x65,0x0f, + 0x04,0x7d,0xff,0x66,0xfa,0x98,0x50,0x9f,0xf3,0xe2,0xe5,0x10,0x45,0xf4,0x39,0x05,0x23,0xdc,0xcd,0xa4,0x3a,0x3b,0xc2,0x88,0x5e,0x58,0xc2,0x48,0x09,0x09,0x90,0xee,0xa8,0x54,0xc7,0x6c,0x2b,0x9a,0xde,0xb6,0xbb,0x57,0x18,0x23,0xe0,0x7f,0xd7,0xc6,0x5c,0x86,0x39,0xcf,0x9d,0x90,0x52,0x60,0x06,0x4c,0x8e,0x76,0x75,0xce,0x6d,0x98,0xb4, + 0x04,0x42,0x80,0x50,0x9a,0xab,0x64,0xed,0xfc,0x0b,0x4a,0x29,0x67,0xe4,0xcb,0xce,0x84,0x9c,0xb5,0x44,0xe4,0xa7,0x73,0x13,0xc8,0xe6,0xec,0xe5,0x79,0xfb,0xd7,0x42,0x0a,0x2e,0x89,0xfe,0x5c,0xc1,0x92,0x7d,0x55,0x4e,0x6a,0x3b,0xb1,0x40,0x33,0xea,0x7c,0x92,0x2c,0xd7,0x5c,0xba,0x2c,0x74,0x15,0xfd,0xab,0x52,0xf2,0x0b,0x18,0x60,0xf1, + 0x04,0x4f,0x8d,0xf1,0x45,0x19,0x4e,0x3c,0x4f,0xc3,0xee,0xa2,0x6d,0x43,0xce,0x75,0xb4,0x02,0xd6,0xb1,0x74,0x72,0xdd,0xcb,0xb2,0x54,0xb8,0xa7,0x9b,0x0b,0xf3,0xd9,0xcb,0x2a,0xa2,0x0d,0x82,0x84,0x4c,0xb2,0x66,0x34,0x4e,0x71,0xca,0x78,0xf2,0xad,0x27,0xa7,0x5a,0x09,0xe5,0xbc,0x0f,0xa5,0x7e,0x4e,0xfd,0x9d,0x46,0x5a,0x08,0x88,0xdb, + 0x04,0x95,0x98,0xa5,0x7d,0xd6,0x7e,0xc3,0xe1,0x6b,0x58,0x7a,0x33,0x8a,0xa3,0xa1,0x0a,0x3a,0x39,0x13,0xb4,0x1a,0x3a,0xf3,0x2e,0x3e,0xd3,0xff,0x01,0x35,0x8c,0x6b,0x14,0x12,0x28,0x19,0xed,0xf8,0x07,0x4b,0xbc,0x52,0x1f,0x7d,0x4c,0xdc,0xe8,0x2f,0xef,0x7a,0x51,0x67,0x06,0xaf,0xfb,0xa1,0xd9,0x3d,0x9d,0xea,0x9c,0xca,0xe1,0xa2,0x07, + 0x04,0x91,0x71,0xfe,0xc3,0xca,0x20,0x80,0x6b,0xc0,0x84,0xf1,0x2f,0x07,0x60,0x91,0x1b,0x60,0x99,0x0b,0xd8,0x0e,0x5b,0x2a,0x71,0xca,0x03,0xa0,0x48,0xb2,0x0f,0x83,0x7e,0x63,0x4f,0xd1,0x78,0x63,0x76,0x1b,0x29,0x58,0xd2,0xbe,0x4e,0x14,0x9f,0x8d,0x3d,0x7a,0xbb,0xdc,0x18,0xbe,0x03,0xf4,0x51,0xab,0x6c,0x17,0xfa,0x0a,0x1f,0x83,0x30, + 0x04,0x77,0x7c,0x89,0x30,0xb6,0xe1,0xd2,0x71,0x10,0x0f,0xe6,0x8c,0xe9,0x3f,0x16,0x3f,0xa3,0x76,0x12,0xc5,0xff,0xf6,0x7f,0x4a,0x62,0xfc,0x3b,0xaf,0xaf,0x3d,0x17,0xa9,0xed,0x73,0xd8,0x6f,0x60,0xa5,0x1b,0x5e,0xd9,0x13,0x53,0xa3,0xb0,0x54,0xed,0xc0,0xaa,0x92,0xc9,0xeb,0xcb,0xd0,0xb7,0x5d,0x18,0x8f,0xdc,0x88,0x27,0x91,0xd6,0x8d, + 0x04,0xea,0xbc,0x24,0x8f,0x62,0x6e,0x0a,0x63,0xe1,0xeb,0x81,0xc4,0x3d,0x46,0x1a,0x39,0xa1,0xdb,0xa8,0x81,0xeb,0x6e,0xe2,0x15,0x2b,0x07,0xc3,0x2d,0x71,0xbc,0xf4,0x70,0x06,0x03,0xca,0xa8,0xb9,0xd3,0x3d,0xb1,0x3a,0xf4,0x4c,0x6e,0xfb,0xec,0x8a,0x19,0x8e,0xd6,0x12,0x4a,0xc9,0xeb,0x17,0xea,0xaf,0xd2,0x82,0x4a,0x54,0x5e,0xc0,0x00, + 0x04,0x9f,0x7a,0x13,0xad,0xa1,0x58,0xa5,0x5f,0x9d,0xdf,0x1a,0x45,0xf0,0x44,0xf0,0x73,0xd9,0xb8,0x00,0x30,0xef,0xdc,0xfc,0x9f,0x9f,0x58,0x41,0x8f,0xbc,0xea,0xf0,0x01,0xf8,0xad,0xa0,0x17,0x50,0x90,0xf8,0x0d,0x47,0x22,0x7d,0x67,0x13,0xb6,0x74,0x0f,0x9a,0x00,0x91,0xd8,0x8a,0x83,0x7d,0x0a,0x1c,0xd7,0x7b,0x58,0xa8,0xf2,0x8d,0x73, + 0x04,0x11,0xc4,0xf3,0xe4,0x61,0xcd,0x01,0x9b,0x5c,0x06,0xea,0x0c,0xea,0x4c,0x40,0x90,0xc3,0xcc,0x3e,0x3c,0x5d,0x9f,0x3c,0x6d,0x65,0xb4,0x36,0x82,0x6d,0xa9,0xb4,0xdb,0xbb,0xeb,0x7a,0x77,0xe4,0xcb,0xfd,0xa2,0x07,0x09,0x7c,0x43,0x42,0x37,0x05,0xf7,0x2c,0x80,0x47,0x6d,0xa3,0xda,0xc4,0x0a,0x48,0x3b,0x0a,0xb0,0xf2,0xea,0xd1,0xcb, + 0x04,0xe2,0xe1,0x86,0x82,0xd5,0x31,0x23,0xaa,0x01,0xa6,0xc5,0xd0,0x0b,0x0c,0x62,0x3d,0x67,0x1b,0x46,0x2e,0xa8,0x0b,0xdd,0xd6,0x52,0x27,0xfd,0x51,0x05,0x98,0x8a,0xa4,0x16,0x19,0x07,0xb3,0xfd,0x25,0x04,0x4a,0x94,0x9e,0xa4,0x1c,0x8e,0x2e,0xa8,0x45,0x9d,0xc6,0xf1,0x65,0x48,0x56,0xb8,0xb6,0x1b,0x31,0x54,0x3b,0xb1,0xb4,0x5b,0xdb, + 0x04,0x90,0xf8,0xd4,0xca,0x73,0xde,0x08,0xa6,0x56,0x4a,0xaf,0x00,0x52,0x47,0xb6,0xf0,0xff,0xe9,0x78,0x50,0x4d,0xce,0x52,0x60,0x5f,0x46,0xb7,0xc3,0xe5,0x61,0x97,0xda,0xfa,0xdb,0xe5,0x28,0xeb,0x70,0xd9,0xee,0x7e,0xa0,0xe7,0x07,0x02,0xdb,0x54,0xf7,0x21,0x51,0x4c,0x7b,0x86,0x04,0xac,0x2c,0xb2,0x14,0xf1,0xde,0xcb,0x7e,0x38,0x3d, + 0x04,0x82,0x4c,0x19,0x5c,0x73,0xcf,0xfd,0xf0,0x38,0xd1,0x01,0xbc,0xe1,0x68,0x7b,0x5c,0x3b,0x61,0x46,0xf3,0x95,0xc8,0x85,0x97,0x6f,0x77,0x53,0xb2,0x37,0x6b,0x94,0x8e,0x3c,0xde,0xfa,0x6f,0xc3,0x47,0xd1,0x3e,0x4d,0xcb,0xc6,0x3a,0x0b,0x03,0xa1,0x65,0x18,0x0c,0xd2,0xbe,0x14,0x31,0xa0,0xcf,0x74,0xce,0x1e,0xa2,0x50,0x82,0xd2,0xbc, + 0x04,0x27,0x88,0xa5,0x2f,0x07,0x8e,0xb3,0xf2,0x02,0xc4,0xfa,0x73,0xe0,0xd3,0x38,0x6f,0xaf,0x3d,0xf6,0xbe,0x85,0x60,0x03,0x63,0x6f,0x59,0x99,0x22,0xd4,0xf5,0x26,0x8f,0x30,0xb4,0xf2,0x07,0xc9,0x19,0xbb,0xdf,0x5e,0x67,0xa8,0xbe,0x42,0x65,0xa8,0x17,0x47,0x54,0xb3,0xab,0xa8,0xf1,0x6e,0x57,0x5b,0x77,0xff,0x4d,0x5a,0x7e,0xb6,0x4f, + 0x04,0xd5,0x33,0xb7,0x89,0xa4,0xaf,0x89,0x0f,0xa7,0xa8,0x2a,0x1f,0xae,0x58,0xc4,0x04,0xf9,0xa6,0x2a,0x50,0xb4,0x9a,0xda,0xfa,0xb3,0x49,0xc5,0x13,0xb4,0x15,0x08,0x74,0x01,0xb4,0x17,0x1b,0x80,0x3e,0x76,0xb3,0x4a,0x98,0x61,0xe1,0x0f,0x7b,0xc2,0x89,0xa0,0x66,0xfd,0x01,0xbd,0x29,0xf8,0x4c,0x98,0x7a,0x10,0xa5,0xfb,0x18,0xc2,0xd4, + 0x04,0x3a,0x31,0x50,0x79,0x8c,0x8a,0xf6,0x9d,0x1e,0x6e,0x98,0x1f,0x3a,0x45,0x40,0x2b,0xa1,0xd7,0x32,0xf4,0xbe,0x83,0x30,0xc5,0x16,0x4f,0x49,0xe1,0x0e,0xc5,0x55,0xb4,0x22,0x1b,0xd8,0x42,0xbc,0x5e,0x4d,0x97,0xef,0xf3,0x71,0x65,0xf6,0x0e,0x39,0x98,0xa4,0x24,0xd7,0x2a,0x45,0x0c,0xf9,0x5e,0xa4,0x77,0xc7,0x82,0x87,0xd0,0x34,0x3a, + 0x04,0x3b,0x37,0xdf,0x5f,0xb3,0x47,0xc6,0x9a,0x0f,0x17,0xd8,0x5c,0x0c,0x7c,0xa8,0x37,0x36,0x88,0x3a,0x82,0x5e,0x13,0x14,0x3d,0x0f,0xcf,0xc8,0x10,0x1e,0x85,0x1e,0x80,0x0d,0xe3,0xc0,0x90,0xb6,0xca,0x21,0xba,0x54,0x35,0x17,0x33,0x0c,0x04,0xb1,0x2f,0x94,0x8c,0x6b,0xad,0xf1,0x4a,0x63,0xab,0xff,0xdf,0x4e,0xf8,0xc7,0x53,0x70,0x26, + 0x04,0xfe,0xb5,0x16,0x3b,0x0e,0xce,0x30,0xff,0x3e,0x03,0xc7,0xd5,0x5c,0x43,0x80,0xfa,0x2f,0xa8,0x1e,0xe2,0xc0,0x35,0x49,0x42,0xff,0x6f,0x08,0xc9,0x9d,0x0c,0xd8,0x2c,0xe8,0x7d,0xe0,0x5e,0xe1,0xbd,0xa0,0x89,0xd3,0xe4,0xe2,0x48,0xfa,0x0f,0x72,0x11,0x02,0xac,0xff,0xfd,0xf5,0x0e,0x65,0x4b,0xe2,0x81,0x43,0x39,0x99,0xdf,0x89,0x7e, + 0x04,0x23,0x8c,0xed,0x00,0x1c,0xf2,0x2b,0x88,0x53,0xe0,0x2e,0xdc,0x89,0xcb,0xec,0xa5,0x05,0x0b,0xa7,0xe0,0x42,0xa7,0xa7,0x7f,0x93,0x82,0xcd,0x41,0x49,0x22,0x89,0x76,0x40,0x68,0x3d,0x30,0x94,0x64,0x38,0x40,0xf2,0x95,0x89,0x0a,0xa4,0xc1,0x8a,0xa3,0x9b,0x41,0xd7,0x7d,0xd0,0xfb,0x3b,0xb2,0x70,0x0e,0x4f,0x9e,0xc2,0x84,0xff,0xc2, + 0x04,0x96,0x1c,0xf6,0x48,0x17,0xc0,0x6c,0x0e,0x51,0xb3,0xc2,0x73,0x6c,0x92,0x2f,0xde,0x18,0xbd,0x8c,0x49,0x06,0xfc,0xd7,0xf5,0xef,0x66,0xc4,0x67,0x85,0x08,0xf3,0x5e,0xd2,0xc5,0xd1,0x81,0x68,0xcf,0xbe,0x70,0xf2,0xf1,0x23,0xbd,0x74,0x19,0x23,0x2b,0xb9,0x2d,0xd6,0x91,0x13,0xe2,0x94,0x10,0x61,0x88,0x94,0x81,0xc5,0xa0,0x27,0xbf, + 0x04,0x13,0x68,0x1e,0xae,0x16,0x8c,0xd4,0xea,0x7c,0xf2,0xe2,0xa4,0x5d,0x05,0x27,0x42,0xd1,0x0a,0x9f,0x64,0xe7,0x96,0x86,0x7d,0xbd,0xcb,0x82,0x9f,0xe0,0xb1,0x02,0x88,0x16,0x52,0x87,0x60,0xd1,0x77,0x37,0x6c,0x09,0xdf,0x79,0xde,0x39,0x55,0x7c,0x32,0x9c,0xc1,0x75,0x35,0x17,0xac,0xff,0xe8,0xfa,0x2e,0xc2,0x98,0x02,0x6b,0x83,0x84, + 0x04,0x5a,0xa7,0xab,0xfd,0xb6,0xb4,0x08,0x6d,0x54,0x33,0x25,0xe5,0xd7,0x9c,0x6e,0x95,0xce,0x42,0xf8,0x66,0xd2,0xbb,0x84,0x90,0x96,0x33,0xa0,0x4b,0xb1,0xaa,0x31,0xc2,0x91,0xc8,0x00,0x88,0x79,0x49,0x05,0xe1,0xda,0x33,0x33,0x6d,0x87,0x4e,0x2f,0x91,0xcc,0xf4,0x5c,0xc5,0x91,0x85,0xbe,0xde,0x5d,0xd6,0xf3,0xf7,0xac,0xaa,0xe1,0x8b, + 0x04,0x00,0x27,0x77,0x91,0xb3,0x05,0xa4,0x5b,0x2b,0x39,0x59,0x0b,0x2f,0x05,0xd3,0x39,0x2a,0x6c,0x81,0x82,0xce,0xf4,0xeb,0x54,0x01,0x20,0xe0,0xf5,0xc2,0x06,0xc3,0xe4,0x64,0x10,0x82,0x33,0xfb,0x0b,0x8c,0x3a,0xc8,0x92,0xd7,0x9e,0xf8,0xe0,0xfb,0xf9,0x2e,0xd1,0x33,0xad,0xdb,0x45,0x54,0x27,0x01,0x32,0x58,0x4d,0xc5,0x2e,0xef,0x41, + 0x04,0x6e,0xfa,0x09,0x2b,0x68,0xde,0x94,0x60,0xf0,0xbc,0xc9,0x19,0x00,0x5a,0x5f,0x6e,0x80,0xe1,0x9d,0xe9,0x89,0x68,0xbe,0x3c,0xd2,0xc7,0x70,0xa9,0x94,0x9b,0xfb,0x1a,0xc7,0x5e,0x6e,0x50,0x87,0xd6,0x55,0x0d,0x5f,0x9b,0xeb,0x1e,0x79,0xe5,0x02,0x93,0x07,0xbc,0x25,0x52,0x35,0xe2,0xd5,0xdc,0x99,0x24,0x1a,0xc3,0xab,0x88,0x6c,0x49, + 0x04,0x72,0xd4,0xa1,0x9c,0x4f,0x9d,0x2c,0xf5,0x84,0x8e,0xa4,0x04,0x45,0xb7,0x0d,0x46,0x96,0xb5,0xf0,0x2d,0x63,0x2c,0x0c,0x65,0x4c,0xc7,0xd7,0xee,0xb0,0xc6,0xd0,0x58,0xe8,0xc4,0xcd,0x99,0x43,0xe4,0x59,0x17,0x4c,0x7a,0xc0,0x1f,0xa7,0x42,0x19,0x8e,0x47,0xe6,0xc1,0x9a,0x6b,0xdb,0x0c,0x4f,0x6c,0x23,0x78,0x31,0xc1,0xb3,0xf9,0x42, + 0x04,0x2a,0x8e,0xa2,0xf5,0x0d,0xcc,0xed,0x0c,0x21,0x75,0x75,0xbd,0xfa,0x7c,0xd4,0x7d,0x1c,0x6f,0x10,0x00,0x41,0xec,0x0e,0x35,0x51,0x27,0x94,0xc1,0xbe,0x7e,0x74,0x02,0x58,0xf8,0xc1,0x71,0x22,0xed,0x30,0x3f,0xda,0x71,0x43,0xeb,0x58,0xbe,0xde,0x70,0x29,0x5b,0x65,0x32,0x66,0x01,0x3b,0x0b,0x0e,0xbd,0x3f,0x05,0x31,0x37,0xf6,0xec, + 0x04,0x88,0xde,0x68,0x9c,0xe9,0xaf,0x1e,0x94,0xbe,0x6a,0x20,0x89,0xc8,0xa8,0xb1,0x25,0x3f,0xfd,0xbb,0x6c,0x8e,0x9c,0x86,0x24,0x9b,0xa2,0x20,0x00,0x1a,0x4a,0xd3,0xb8,0x0c,0x49,0x98,0xe5,0x48,0x42,0xf4,0x13,0xb9,0xed,0xb1,0x82,0x5a,0xcb,0xb6,0x33,0x5e,0x81,0xe4,0xd1,0x84,0xb2,0xb0,0x1c,0x8b,0xeb,0xdc,0x85,0xd1,0xf2,0x89,0x46, + 0x04,0xfe,0xa2,0xd3,0x1f,0x70,0xf9,0x0d,0x5f,0xb3,0xe0,0x0e,0x18,0x6a,0xc4,0x2a,0xb3,0xc1,0x61,0x5c,0xee,0x71,0x4e,0x0b,0x4e,0x11,0x31,0xb3,0xd4,0xd8,0x22,0x5b,0xf7,0xb0,0x37,0xa1,0x8d,0xf2,0xac,0x15,0x34,0x3f,0x30,0xf7,0x40,0x67,0xdd,0xf2,0x9e,0x81,0x7d,0x5f,0x77,0xf8,0xdc,0xe0,0x57,0x14,0xda,0x59,0xc0,0x94,0xf0,0xcd,0xa9, + 0x04,0x72,0x58,0x91,0x1e,0x3d,0x42,0x33,0x49,0x16,0x64,0x79,0xdb,0xe0,0xb8,0x34,0x1a,0xf7,0xfb,0xd0,0x3d,0x0a,0x7e,0x10,0xed,0xcc,0xb3,0x6b,0x6c,0xee,0xa5,0xa3,0xdb,0x17,0xac,0x2b,0x89,0x92,0x79,0x11,0x28,0xfa,0x3b,0x96,0xdc,0x2f,0xbd,0x4c,0xa3,0xbf,0xa7,0x82,0xef,0x28,0x32,0xfc,0x66,0x56,0x94,0x3d,0xb1,0x8e,0x73,0x46,0xb0, + 0x04,0x4f,0x28,0x46,0x1d,0xea,0x64,0x47,0x4d,0x6b,0xb3,0x4d,0x14,0x99,0xc9,0x7d,0x37,0xb9,0xe9,0x56,0x33,0xdf,0x1c,0xee,0xea,0xac,0xd4,0x50,0x16,0xc9,0x8b,0x39,0x14,0xc8,0x81,0x88,0x10,0xb8,0xcc,0x06,0xdd,0xb4,0x0e,0x8a,0x12,0x61,0xc5,0x28,0xfa,0xa5,0x89,0x45,0x5d,0x5a,0x6d,0xf9,0x3b,0x77,0xbc,0x5e,0x0e,0x49,0x3c,0x74,0x70, + 0x04,0x74,0xf2,0xa8,0x14,0xfb,0x5d,0x8e,0xca,0x91,0xa6,0x9b,0x5e,0x60,0x71,0x27,0x32,0xb3,0x93,0x7d,0xe3,0x28,0x29,0xbe,0x97,0x4e,0xd7,0xb6,0x8c,0x5c,0x2f,0x5d,0x66,0xef,0xf0,0xf0,0x7c,0x56,0xf9,0x87,0xa6,0x57,0xf4,0x21,0x96,0x20,0x5f,0x58,0x8c,0x0f,0x1d,0x96,0xfd,0x8a,0x63,0xa5,0xf2,0x38,0xb4,0x8f,0x47,0x87,0x88,0xfe,0x3b, + 0x04,0x19,0x5b,0x51,0xa7,0xcc,0x4a,0x21,0xb8,0x27,0x4a,0x70,0xa9,0x0d,0xe7,0x79,0x81,0x4c,0x3c,0x8c,0xa3,0x58,0x32,0x82,0x08,0xc0,0x9a,0x29,0xf3,0x36,0xb8,0x2d,0x6a,0xb2,0x41,0x6b,0x7c,0x92,0xff,0xfd,0xc2,0x9c,0x3b,0x12,0x82,0xdd,0x2a,0x77,0xa4,0xd0,0x4d,0xf7,0xf7,0x45,0x20,0x47,0x39,0x3d,0x84,0x99,0x89,0xc5,0xce,0xe9,0xad, + 0x04,0x62,0x2f,0xc7,0x47,0x32,0x03,0x4b,0xec,0x2d,0xdf,0x3b,0xc1,0x6d,0x34,0xb3,0xd1,0xf7,0xa3,0x27,0xdd,0x2a,0x8c,0x19,0xba,0xb4,0xbb,0x4f,0xe3,0xa2,0x4b,0x58,0xaa,0x73,0x6b,0x2f,0x2f,0xae,0x76,0xf4,0xdf,0xae,0xcc,0x90,0x96,0x33,0x3b,0x01,0x32,0x8d,0x51,0xeb,0x3f,0xda,0x9c,0x92,0x27,0xe9,0x0d,0x0b,0x44,0x99,0x83,0xc4,0xf0, + 0x04,0x1f,0x7f,0x85,0xca,0xf2,0xd7,0x55,0x0e,0x7a,0xf9,0xb6,0x50,0x23,0xeb,0xb4,0xdc,0xe3,0x45,0x03,0x11,0x69,0x23,0x09,0xdb,0x26,0x99,0x69,0xb8,0x34,0xb6,0x11,0xc7,0x08,0x27,0xf4,0x5b,0x78,0x02,0x0e,0xcb,0xba,0xf4,0x84,0xfd,0xd5,0xbf,0xaa,0xe6,0x87,0x0f,0x11,0x84,0xc2,0x15,0x81,0xba,0xf6,0xef,0x82,0xbd,0x7b,0x53,0x0f,0x93, + 0x04,0x49,0xc1,0x97,0xdc,0x80,0xad,0x1d,0xa4,0x7a,0x43,0x42,0xb9,0x38,0x93,0xe8,0xe1,0xfb,0x0b,0xb9,0x4f,0xc3,0x3a,0x83,0xe7,0x83,0xc0,0x0b,0x24,0xc7,0x81,0x37,0x7a,0xef,0xc2,0x0d,0xa9,0x2b,0xac,0x76,0x29,0x51,0xf7,0x24,0x74,0xbe,0xcc,0x73,0x4d,0x4c,0xc2,0x2b,0xa8,0x1b,0x89,0x5e,0x28,0x2f,0xda,0xc4,0xdf,0x7a,0xf0,0xf3,0x7d, + 0x04,0xd8,0xcb,0x68,0x51,0x7b,0x61,0x6a,0x56,0x40,0x0a,0xa3,0x86,0x86,0x35,0xe5,0x4b,0x6f,0x69,0x95,0x98,0xa2,0xf6,0x16,0x77,0x57,0x65,0x49,0x80,0xba,0xf6,0xac,0xbe,0x7e,0xc8,0xcf,0x44,0x9c,0x84,0x9a,0xa0,0x34,0x61,0xa3,0x0e,0xfa,0xda,0x41,0x45,0x3c,0x57,0xc6,0xe6,0xfb,0xc9,0x3b,0xbc,0x6f,0xa4,0x9a,0xda,0x6d,0xc0,0x55,0x5c, + 0x04,0x03,0x07,0x13,0xfb,0x63,0xf2,0xaa,0x6f,0xe2,0xca,0xdf,0x1b,0x20,0xef,0xc2,0x59,0xc7,0x74,0x45,0xda,0xfa,0x87,0xda,0xc3,0x98,0xb8,0x40,0x65,0xca,0x34,0x7d,0xf3,0xb2,0x27,0x81,0x8d,0xe1,0xa3,0x9b,0x58,0x9c,0xb0,0x71,0xd8,0x3e,0x53,0x17,0xcc,0xcd,0xc2,0x33,0x8e,0x51,0xe3,0x12,0xfe,0x31,0xd8,0xdc,0x34,0xa4,0x80,0x17,0x50, + 0x04,0xba,0xbb,0x36,0x77,0xb0,0x95,0x58,0x02,0xd8,0xe9,0x29,0xa4,0x13,0x55,0x64,0x0e,0xaf,0x1e,0xa1,0x35,0x3f,0x8a,0x77,0x13,0x31,0xc4,0x94,0x6e,0x34,0x80,0xaf,0xa7,0x25,0x2f,0x19,0x6c,0x87,0xed,0x3d,0x2a,0x59,0xd3,0xb1,0xb5,0x59,0x13,0x7f,0xed,0x00,0x13,0xfe,0xce,0xfc,0x19,0xfb,0x5a,0x92,0x68,0x2b,0x9b,0xca,0x51,0xb9,0x50, + 0x04,0x1a,0xab,0x20,0x18,0x79,0x34,0x71,0x11,0x1a,0x8a,0x0e,0x9b,0x14,0x3f,0xde,0x02,0xfc,0x95,0x92,0x07,0x96,0xd3,0xa6,0x3d,0xe3,0x29,0xb4,0x24,0x39,0x6f,0xba,0x60,0xbb,0xe4,0x13,0x07,0x05,0x17,0x47,0x92,0x44,0x1b,0x31,0x8d,0x3a,0xa3,0x1d,0xfe,0x85,0x77,0x82,0x1e,0x9b,0x44,0x6e,0xc5,0x73,0xd2,0x72,0xe0,0x36,0xc4,0xeb,0xe9, + 0x04,0x8c,0xb0,0xb9,0x09,0x49,0x9c,0x83,0xea,0x80,0x6c,0xd8,0x85,0xb1,0xdd,0x46,0x7a,0x01,0x19,0xf0,0x6a,0x88,0xa0,0x27,0x6e,0xb0,0xcf,0xda,0x27,0x45,0x35,0xa8,0xff,0x47,0xb5,0x42,0x88,0x33,0xbc,0x3f,0x2c,0x8b,0xf9,0xd9,0x04,0x11,0x58,0xcf,0x33,0x71,0x8a,0x69,0x96,0x1c,0xd0,0x17,0x29,0xbc,0x00,0x11,0xd1,0xe5,0x86,0xab,0x75, + 0x04,0x8f,0x03,0xcf,0x1a,0x42,0x27,0x2b,0xb1,0x53,0x27,0x23,0x09,0x3f,0x72,0xe6,0xfe,0xea,0xc8,0x5e,0x17,0x00,0xe9,0xfb,0xe9,0xa6,0xa2,0xdd,0x64,0x2d,0x74,0xbf,0x5d,0x3b,0x89,0xa7,0x18,0x9d,0xad,0x8c,0xf7,0x5f,0xc2,0x2f,0x6f,0x15,0x8a,0xa2,0x7f,0x9c,0x2c,0xa0,0x0d,0xac,0xa7,0x85,0xbe,0x33,0x58,0xf2,0xbd,0xa3,0x86,0x2c,0xa0, + 0x04,0x44,0xde,0x3b,0x9c,0x7a,0x57,0xa8,0xc9,0xe8,0x20,0x95,0x27,0x53,0x42,0x1e,0x7d,0x98,0x7b,0xb3,0xd7,0x9f,0x71,0xf0,0x13,0x80,0x5c,0x89,0x7e,0x01,0x8f,0x8a,0xce,0xa2,0x46,0x07,0x58,0xc8,0xf9,0x8d,0x3f,0xdc,0xe1,0x21,0xa9,0x43,0x65,0x9e,0x37,0x2c,0x32,0x6f,0xff,0x2e,0x5f,0xc2,0xae,0x7f,0xa3,0xf7,0x9d,0xaa,0xe1,0x3c,0x12, + 0x04,0x6f,0xb8,0xb2,0xb4,0x8e,0x33,0x03,0x12,0x68,0xad,0x6a,0x51,0x74,0x84,0xdc,0x88,0x39,0xea,0x90,0xf6,0x66,0x9e,0xa0,0xc7,0xac,0x32,0x33,0xe2,0xac,0x31,0x39,0x4a,0x0a,0xc8,0xbb,0xe7,0xf7,0x3c,0x2f,0xf4,0xdf,0x99,0x78,0x72,0x7a,0xc1,0xdf,0xc2,0xfd,0x58,0x64,0x7d,0x20,0xf3,0x1f,0x99,0x10,0x53,0x16,0xb6,0x46,0x71,0xf2,0x04, + 0x04,0xbe,0xa7,0x11,0x22,0xa0,0x48,0x69,0x3e,0x90,0x5f,0xf6,0x02,0xb3,0xcf,0x9d,0xd1,0x8a,0xf6,0x9b,0x9f,0xc9,0xd8,0x43,0x1d,0x2b,0x1d,0xd2,0x6b,0x94,0x2c,0x95,0xe6,0xf4,0x3c,0x7b,0x8b,0x95,0xeb,0x62,0x08,0x2c,0x12,0xdb,0x9d,0xbd,0xa7,0xfe,0x38,0xe4,0x5c,0xbe,0x4a,0x48,0x86,0x90,0x7f,0xb8,0x1b,0xdb,0x0c,0x5e,0xa9,0x24,0x6c, + 0x04,0xda,0x91,0x8c,0x73,0x1b,0xa0,0x6a,0x20,0xcb,0x94,0xef,0x33,0xb7,0x78,0xe9,0x81,0xa4,0x04,0xa3,0x05,0xf1,0x94,0x1f,0xe3,0x36,0x66,0xb4,0x5b,0x03,0x35,0x31,0x56,0xe2,0xbb,0x26,0x94,0xf5,0x75,0xb4,0x51,0x83,0xbe,0x78,0xe5,0xc9,0xb5,0x21,0x0b,0xf3,0xbf,0x48,0x8f,0xd4,0xc8,0x29,0x45,0x16,0xd8,0x95,0x72,0xca,0x4f,0x53,0x91, + 0x04,0x30,0x07,0xe9,0x2c,0x39,0x37,0xda,0xde,0x79,0x64,0xdf,0xa3,0x5b,0x0e,0xff,0x03,0x1f,0x7e,0xb0,0x2a,0xed,0x0a,0x03,0x14,0x41,0x11,0x06,0xcd,0xeb,0x70,0xfe,0x3d,0x5a,0x75,0x46,0xfc,0x05,0x52,0x99,0x7b,0x20,0xe3,0xd6,0xf4,0x13,0xe7,0x5e,0x2c,0xb6,0x6e,0x11,0x63,0x22,0x69,0x71,0x14,0xb7,0x9b,0xac,0x73,0x4b,0xfc,0x4d,0xc5, + 0x04,0x60,0xe7,0x34,0xef,0x56,0x24,0xd3,0xcb,0xf0,0xdd,0xd3,0x75,0x01,0x1b,0xd6,0x63,0xd6,0xd6,0xae,0xbc,0x64,0x4e,0xb5,0x99,0xfd,0xf9,0x8d,0xbd,0xcd,0x18,0xce,0x9b,0xd2,0xd9,0x0b,0x3a,0xc3,0x1f,0x13,0x9a,0xf8,0x32,0xcc,0xcf,0x6c,0xcb,0xbb,0x2c,0x6e,0xa1,0x1f,0xa9,0x73,0x70,0xdc,0x99,0x06,0xda,0x47,0x4d,0x7d,0x8a,0x75,0x67, + 0x04,0x85,0xa9,0x00,0xe9,0x78,0x58,0xf6,0x93,0xc0,0xb7,0xdf,0xa2,0x61,0xe3,0x80,0xda,0xd6,0xea,0x04,0x6d,0x1f,0x65,0xdd,0xee,0xed,0xd5,0xf7,0xd8,0xaf,0x0b,0xa3,0x37,0x69,0x74,0x4d,0x15,0xad,0xd4,0xf6,0xc0,0xbc,0x3b,0x0d,0xa2,0xae,0xc9,0x3b,0x34,0xcb,0x8c,0x65,0xf9,0x34,0x0d,0xdf,0x74,0xe7,0xb0,0x00,0x9e,0xee,0xcc,0xce,0x3c, + 0x04,0x38,0x06,0x6f,0x75,0xd8,0x8e,0xfc,0x4c,0x93,0xde,0x36,0xf4,0x9e,0x03,0x7b,0x23,0x4c,0xc1,0x8b,0x1d,0xe5,0x60,0x87,0x50,0xa6,0x2c,0xab,0x03,0x45,0x40,0x10,0x46,0xa3,0xe8,0x4b,0xed,0x8c,0xfc,0xb8,0x19,0xef,0x4d,0x55,0x04,0x44,0xf2,0xce,0x4b,0x65,0x17,0x66,0xb6,0x9e,0x2e,0x29,0x01,0xf8,0x88,0x36,0xff,0x90,0x03,0x4f,0xed, + 0x04,0x98,0xf6,0x81,0x77,0xdc,0x95,0xc1,0xb4,0xcb,0xfa,0x52,0x45,0x48,0x8c,0xa5,0x23,0xa7,0xd5,0x62,0x94,0x70,0xd0,0x35,0xd6,0x21,0xa4,0x43,0xc7,0x2f,0x39,0xaa,0xbf,0xa3,0x3d,0x29,0x54,0x6f,0xa1,0xc6,0x48,0xf2,0xc7,0xd5,0xcc,0xf7,0x0c,0xf1,0xce,0x4a,0xb7,0x9b,0x5d,0xb1,0xac,0x05,0x9d,0xbe,0xcd,0x06,0x8d,0xbd,0xff,0x1b,0x89, + 0x04,0x5c,0x2b,0xbf,0xa2,0x3c,0x9b,0x9a,0xd0,0x7f,0x03,0x8a,0xa8,0x9b,0x49,0x30,0xbf,0x26,0x7d,0x94,0x01,0xe4,0x25,0x5d,0xe9,0xe8,0xda,0x0a,0x50,0x78,0xec,0x82,0x77,0xe3,0xe8,0x82,0xa3,0x1d,0x5e,0x6a,0x37,0x9e,0x07,0x93,0x98,0x3c,0xcd,0xed,0x39,0xb9,0x5c,0x43,0x53,0xab,0x2f,0xf0,0x1e,0xa5,0x36,0x9b,0xa4,0x7b,0x0c,0x31,0x91, + 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0x35,0x47,0x80,0x82,0x98,0x44,0x8e,0xdb,0x5e,0x70,0x1a,0xde,0x84,0xcd,0x5f,0xb1,0xac,0x95,0x67,0xba,0x5e,0x8f,0xb6,0x8a,0x6b,0x93,0x3e,0xc4,0xb5,0xcc,0x84,0xcc, + 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0xca,0xb8,0x7f,0x7d,0x67,0xbb,0x71,0x24,0xa1,0x8f,0xe5,0x21,0x7b,0x32,0xa0,0x4e,0x53,0x6a,0x98,0x45,0xa1,0x70,0x49,0x75,0x94,0x6c,0xc1,0x3a,0x4a,0x33,0x77,0x63, + 0x04,0x8a,0xa2,0xc6,0x4f,0xa9,0xc6,0x43,0x75,0x63,0xab,0xfb,0xcb,0xd0,0x0b,0x20,0x48,0xd4,0x8c,0x18,0xc1,0x52,0xa2,0xa6,0xf4,0x90,0x36,0xde,0x76,0x47,0xeb,0xe8,0x2e,0x1c,0xe6,0x43,0x87,0x99,0x5c,0x68,0xa0,0x60,0xfa,0x3b,0xc0,0x39,0x9b,0x05,0xcc,0x06,0xee,0xc7,0xd5,0x98,0xf7,0x50,0x41,0xa4,0x91,0x7e,0x69,0x2b,0x7f,0x51,0xff, + 0x04,0x39,0x14,0x27,0xff,0x7e,0xe7,0x80,0x13,0xc1,0x4a,0xec,0x7d,0x96,0xa8,0xa0,0x62,0x20,0x92,0x98,0xa7,0x83,0x83,0x5e,0x94,0xfd,0x65,0x49,0xd5,0x02,0xff,0xf7,0x1f,0xdd,0x66,0x24,0xec,0x34,0x3a,0xd9,0xfc,0xf4,0xd9,0x87,0x21,0x81,0xe5,0x9f,0x84,0x2f,0x9b,0xa4,0xcc,0xca,0xe0,0x9a,0x6c,0x09,0x72,0xfb,0x6a,0xc6,0xb4,0xc6,0xbd, + 0x04,0xe7,0x62,0xb8,0xa2,0x19,0xb4,0xf1,0x80,0x21,0x9c,0xc7,0xa9,0x05,0x92,0x45,0xe4,0x96,0x1b,0xd1,0x91,0xc0,0x38,0x99,0x78,0x9c,0x7a,0x34,0xb8,0x9e,0x8c,0x13,0x8e,0xc1,0x53,0x3e,0xf0,0x41,0x9b,0xb7,0x37,0x6e,0x0b,0xfd,0xe9,0x31,0x9d,0x10,0xa0,0x69,0x68,0x79,0x1d,0x9e,0xa0,0xee,0xd9,0xc1,0xce,0x63,0x45,0xae,0xd9,0x75,0x9e, + 0x04,0x9a,0xed,0xb0,0xd2,0x81,0xdb,0x16,0x4e,0x13,0x00,0x00,0xc5,0x69,0x7f,0xae,0x0f,0x30,0x5e,0xf8,0x48,0xbe,0x6f,0xff,0xb4,0x3a,0xc5,0x93,0xfb,0xb9,0x50,0xe9,0x52,0xfa,0x6f,0x63,0x33,0x59,0xbd,0xcd,0x82,0xb5,0x6b,0x0b,0x9f,0x96,0x5b,0x03,0x77,0x89,0xd4,0x6b,0x9a,0x81,0x41,0xb7,0x91,0xb2,0xae,0xfa,0x71,0x3f,0x96,0xc1,0x75, + 0x04,0x8a,0xd4,0x45,0xdb,0x62,0x81,0x62,0x60,0xe4,0xe6,0x87,0xfd,0x18,0x84,0xe4,0x8b,0x9f,0xc0,0x63,0x6d,0x03,0x15,0x47,0xd6,0x33,0x15,0xe7,0x92,0xe1,0x9b,0xfa,0xee,0x1d,0xe6,0x4f,0x99,0xd5,0xf1,0xcd,0x8b,0x6e,0xc9,0xcb,0x0f,0x78,0x7a,0x65,0x4a,0xe8,0x69,0x93,0xba,0x3d,0xb1,0x00,0x8e,0xf4,0x3c,0xff,0x06,0x84,0xcb,0x22,0xbd, + 0x04,0x1f,0x57,0x99,0xc9,0x5b,0xe8,0x90,0x63,0xb2,0x4f,0x26,0xe4,0x0c,0xb9,0x28,0xc1,0xa8,0x68,0xa7,0x6f,0xb0,0x09,0x46,0x07,0xe8,0x04,0x3d,0xb4,0x09,0xc9,0x1c,0x32,0xe7,0x57,0x24,0xe8,0x13,0xa4,0x19,0x1e,0x3a,0x83,0x90,0x07,0xf0,0x8e,0x2e,0x89,0x73,0x88,0xb0,0x6d,0x4a,0x00,0xde,0x6d,0xe6,0x0e,0x53,0x6d,0x91,0xfa,0xb5,0x66, + 0x04,0xa3,0x33,0x1a,0x4e,0x1b,0x42,0x23,0xec,0x2c,0x02,0x7e,0xdd,0x48,0x2c,0x92,0x8a,0x14,0xed,0x35,0x8d,0x93,0xf1,0xd4,0x21,0x7d,0x39,0xab,0xf6,0x9f,0xcb,0x5c,0xcc,0x28,0xd6,0x84,0xd2,0xaa,0xab,0xcd,0x63,0x83,0x77,0x5c,0xaa,0x62,0x39,0xde,0x26,0xd4,0xc6,0x93,0x7b,0xb6,0x03,0xec,0xb4,0x19,0x60,0x82,0xf4,0xcf,0xfd,0x50,0x9d, + 0x04,0x3f,0x39,0x52,0x19,0x97,0x74,0xc7,0xcf,0x39,0xb3,0x8b,0x66,0xcb,0x10,0x42,0xa6,0x26,0x0d,0x86,0x80,0x80,0x38,0x45,0xe4,0xd4,0x33,0xad,0xba,0x3b,0xb2,0x48,0x18,0x5e,0xa4,0x95,0xb6,0x8c,0xbc,0x7e,0xd4,0x17,0x3e,0xe6,0x3c,0x90,0x42,0xdc,0x50,0x26,0x25,0xc7,0xeb,0x7e,0x21,0xfb,0x02,0xca,0x9a,0x91,0x14,0xe0,0xa3,0xa1,0x8d, + 0x04,0xcd,0xfb,0x8c,0x0f,0x42,0x2e,0x14,0x4e,0x13,0x7c,0x24,0x12,0xc8,0x6c,0x17,0x1f,0x5f,0xe3,0xfa,0x3f,0x5b,0xbb,0x54,0x4e,0x90,0x76,0x28,0x8f,0x3c,0xed,0x78,0x6e,0x05,0x4f,0xd0,0x72,0x1b,0x77,0xc1,0x1c,0x79,0xbe,0xac,0xb3,0xc9,0x42,0x11,0xb0,0xa1,0x9b,0xda,0x08,0x65,0x2e,0xfe,0xaf,0x92,0x51,0x3a,0x3b,0x0a,0x16,0x36,0x98, + 0x04,0x73,0x59,0x8a,0x6a,0x1c,0x68,0x27,0x8f,0xa6,0xbf,0xd0,0xce,0x40,0x64,0xe6,0x82,0x35,0xbc,0x1c,0x0f,0x6b,0x20,0xa9,0x28,0x10,0x8b,0xe3,0x36,0x73,0x0f,0x87,0xe3,0xcb,0xae,0x61,0x25,0x19,0xb5,0x03,0x2e,0xcc,0x85,0xae,0xd8,0x11,0x27,0x1a,0x95,0xfe,0x79,0x39,0xd5,0xd3,0x46,0x01,0x40,0xba,0x31,0x8f,0x4d,0x14,0xab,0xa3,0x1d, + 0x04,0x58,0xde,0xbd,0x9a,0x7e,0xe2,0xc9,0xd5,0x91,0x32,0x47,0x8a,0x54,0x40,0xae,0x4d,0x5d,0x7e,0xd4,0x37,0x30,0x83,0x69,0xf9,0x2e,0xa8,0x6c,0x82,0x18,0x3f,0x10,0xa1,0x67,0x73,0xe7,0x6f,0x5e,0xdb,0xf4,0xda,0x0e,0x4f,0x1b,0xdf,0xfa,0xc0,0xf5,0x72,0x57,0xe1,0xdf,0xa4,0x65,0x84,0x29,0x31,0x30,0x9a,0x24,0x24,0x5f,0xda,0x6a,0x5d, + 0x04,0x8b,0x90,0x4d,0xe4,0x79,0x67,0x34,0x0c,0x5f,0x8c,0x35,0x72,0xa7,0x20,0x92,0x4e,0xf7,0x57,0x86,0x37,0xfe,0xab,0x19,0x49,0xac,0xb2,0x41,0xa5,0xa6,0xac,0x3f,0x5b,0x95,0x09,0x04,0x49,0x6f,0x98,0x24,0xb1,0xd6,0x3f,0x33,0x13,0xba,0xe2,0x1b,0x89,0xfa,0xe8,0x9a,0xfd,0xfc,0x81,0x1b,0x5e,0xce,0x03,0xfd,0x5a,0xa3,0x01,0x86,0x4f, + 0x04,0xf4,0x89,0x2b,0x6d,0x52,0x5c,0x77,0x1e,0x03,0x5f,0x2a,0x25,0x27,0x08,0xf3,0x78,0x4e,0x48,0x23,0x86,0x04,0xb4,0xf9,0x4d,0xc5,0x6e,0xaa,0x1e,0x54,0x6d,0x94,0x1a,0x34,0x6b,0x1a,0xa0,0xbc,0xe6,0x8b,0x1c,0x50,0xe5,0xb5,0x2f,0x50,0x9f,0xb5,0x52,0x2e,0x5c,0x25,0xe0,0x28,0xbc,0x8f,0x86,0x34,0x02,0xed,0xb7,0xbc,0xad,0x8b,0x1b, + 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x48,0x3a,0xda,0x77,0x26,0xa3,0xc4,0x65,0x5d,0xa4,0xfb,0xfc,0x0e,0x11,0x08,0xa8,0xfd,0x17,0xb4,0x48,0xa6,0x85,0x54,0x19,0x9c,0x47,0xd0,0x8f,0xfb,0x10,0xd4,0xb8, + 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0xb7,0xc5,0x25,0x88,0xd9,0x5c,0x3b,0x9a,0xa2,0x5b,0x04,0x03,0xf1,0xee,0xf7,0x57,0x02,0xe8,0x4b,0xb7,0x59,0x7a,0xab,0xe6,0x63,0xb8,0x2f,0x6f,0x04,0xef,0x27,0x77, + 0x04,0x78,0x2c,0x8e,0xd1,0x7e,0x3b,0x2a,0x78,0x3b,0x54,0x64,0xf3,0x3b,0x09,0x65,0x2a,0x71,0xc6,0x78,0xe0,0x5e,0xc5,0x1e,0x84,0xe2,0xbc,0xfc,0x66,0x3a,0x3d,0xe9,0x63,0xaf,0x9a,0xcb,0x42,0x80,0xb8,0xc7,0xf7,0xc4,0x2f,0x4e,0xf9,0xab,0xa6,0x24,0x5e,0xc1,0xec,0x17,0x12,0xfd,0x38,0xa0,0xfa,0x96,0x41,0x8d,0x8c,0xd6,0xaa,0x61,0x52, + 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0x00,0x00,0x00,0x01,0x06,0x04,0x92,0xd5,0xa5,0x67,0x3e,0x0f,0x25,0xd8,0xd5,0x0f,0xb7,0xe5,0x8c,0x49,0xd8,0x6d,0x46,0xd4,0x21,0x69,0x55,0xe0,0xaa,0x3d,0x40,0xe1, + 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0xff,0xff,0xff,0xfe,0xf9,0xfb,0x6d,0x2a,0x5a,0x98,0xc1,0xf0,0xda,0x27,0x2a,0xf0,0x48,0x1a,0x73,0xb6,0x27,0x92,0xb9,0x2b,0xde,0x96,0xaa,0x1e,0x55,0xc2,0xbb,0x4e, + 0x04,0x00,0x00,0x00,0x01,0x3f,0xd2,0x22,0x48,0xd6,0x4d,0x95,0xf7,0x3c,0x29,0xb4,0x8a,0xb4,0x86,0x31,0x85,0x0b,0xe5,0x03,0xfd,0x00,0xf8,0x46,0x8b,0x5f,0x0f,0x70,0xe0,0xf6,0xee,0x7a,0xa4,0x3b,0xc2,0xc6,0xfd,0x25,0xb1,0xd8,0x26,0x92,0x41,0xcb,0xdd,0x9d,0xbb,0x0d,0xac,0x96,0xdc,0x96,0x23,0x1f,0x43,0x07,0x05,0xf8,0x38,0x71,0x7d, + 0x04,0x25,0xaf,0xd6,0x89,0xac,0xab,0xae,0xd6,0x7c,0x1f,0x29,0x6d,0xe5,0x94,0x06,0xf8,0xc5,0x50,0xf5,0x71,0x46,0xa0,0xb4,0xec,0x2c,0x97,0x87,0x6d,0xff,0xff,0xff,0xff,0xfa,0x46,0xa7,0x6e,0x52,0x03,0x22,0xdf,0xbc,0x49,0x1e,0xc4,0xf0,0xcc,0x19,0x74,0x20,0xfc,0x4e,0xa5,0x88,0x3d,0x8f,0x6d,0xd5,0x3c,0x35,0x4b,0xc4,0xf6,0x7c,0x35, + 0x04,0xd1,0x2e,0x6c,0x66,0xb6,0x77,0x34,0xc3,0xc8,0x4d,0x26,0x01,0xcf,0x5d,0x35,0xdc,0x09,0x7e,0x27,0x63,0x7f,0x0a,0xca,0x4a,0x4f,0xdb,0x74,0xb6,0xaa,0xdd,0x3b,0xb9,0x3f,0x5b,0xdf,0xf8,0x8b,0xd5,0x73,0x6d,0xf8,0x98,0xe6,0x99,0x00,0x6e,0xd7,0x50,0xf1,0x1c,0xf0,0x7c,0x58,0x66,0xcd,0x7a,0xd7,0x0c,0x71,0x21,0xff,0xff,0xff,0xff, + 0x04,0x6d,0x4a,0x7f,0x60,0xd4,0x77,0x4a,0x4f,0x0a,0xa8,0xbb,0xde,0xdb,0x95,0x3c,0x7e,0xea,0x79,0x09,0x40,0x7e,0x31,0x64,0x75,0x56,0x64,0xbc,0x28,0x00,0x00,0x00,0x00,0xe6,0x59,0xd3,0x4e,0x4d,0xf3,0x8d,0x9e,0x8c,0x9e,0xaa,0xdf,0xba,0x36,0x61,0x2c,0x76,0x91,0x95,0xbe,0x86,0xc7,0x7a,0xac,0x3f,0x36,0xe7,0x8b,0x53,0x86,0x80,0xfb}; + +static const unsigned char wycheproof_ecdsa_signatures[] = { 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x00,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7d,0xb3,0x7c,0x21,0xf4,0xaf,0xd3,0x20,0x3a,0xe8,0xdc,0x4a,0xe7,0x79,0x4b,0x0f,0x87, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x81,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x85,0x01,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x84,0x7f,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x84,0x80,0x00,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x84,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x85,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x47,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00, + 0x30,0x4a,0x49,0x81,0x77,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x25,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef, + 0x30,0x4d,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x22,0x29,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x28,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x81, + 0x30,0x4b,0xaa,0x02,0xaa,0xbb,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x80,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x80,0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x05,0x00, + 0x2e,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x2f,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x32,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0xff,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x00, + 0x30,0x49,0x30,0x01,0x02,0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31, + 0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x10,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x06,0x08,0x11,0x22,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0xfe,0x02,0xbe,0xef, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x02,0xbe,0xef, + 0x30,0x47,0x30,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x30,0x00, + 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x01,0x00, + 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xbf,0x7f,0x00, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x02,0x05,0x00, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x00, + 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65, + 0x30,0x67,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x64,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xca,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x13,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x08,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x81,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x82,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x85,0x01,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4e,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x84,0x7f,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x84,0x80,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x84,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x80,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x23,0x02,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02, + 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x23,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x22,0x26,0x49,0x81,0x77,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x25,0x25,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x22,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x04,0xde,0xad,0xbe,0xef,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x02,0x81,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4b,0x22,0x27,0xaa,0x02,0xaa,0xbb,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x80,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x01,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x04,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0xff,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x02,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x25,0x02,0x01,0x00,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x02,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0xe5,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x10,0x48,0x02,0x82,0x10,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x22,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x25,0x09,0x01,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x25,0x02,0x01,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xbb, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa4,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf7,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x01,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0x01,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4e,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x7f,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x80,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x80,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00, + 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x25,0x49,0x81,0x77,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x25,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef, + 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81, + 0x30,0x4b,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x26,0xaa,0x02,0xaa,0xbb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x01,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x04,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0xff,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x00, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x02,0x01,0x6f,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6d,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0x3a, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x10,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x10,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x09,0x01,0x80, + 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x01,0x00, + 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x83,0xb9,0x0d,0xea,0xbc,0xa4,0xb0,0x5c,0x45,0x74,0xe4,0x9b,0x58,0x99,0xb9,0x64,0xa6,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x86,0x43,0xb0,0x30,0xef,0x46,0x1f,0x1b,0xcd,0xf5,0x3f,0xde,0x3e,0xf9,0x4c,0xe2,0x24,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x22,0x01,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x84,0x3f,0xad,0x3b,0xf4,0x85,0x3e,0x07,0xf7,0xc9,0x87,0x70,0xc9,0x9b,0xff,0xc4,0x64,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xff,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7b,0x01,0xa0,0xf2,0x2a,0x0a,0x98,0x43,0xf6,0x4a,0xed,0xc3,0x34,0x36,0x7c,0xdc,0x9b,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x79,0xbc,0x4f,0xcf,0x10,0xb9,0xe0,0xe4,0x32,0x0a,0xc0,0x21,0xc1,0x06,0xb3,0x1d,0xdc,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xfe,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7c,0x46,0xf2,0x15,0x43,0x5b,0x4f,0xa3,0xba,0x8b,0x1b,0x64,0xa7,0x66,0x46,0x9b,0x5a,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x7f,0xc1,0xe1,0x97,0xd8,0xae,0xbe,0x20,0x3c,0x96,0xc8,0x72,0x32,0x27,0x21,0x72,0xfb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x82,0x4c,0x83,0xde,0x0b,0x50,0x2c,0xdf,0xc5,0x17,0x23,0xb5,0x18,0x86,0xb4,0xf0,0x79,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x22,0x01,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9a,0x3b,0xb6,0x0f,0xa1,0xa1,0x48,0x15,0xbb,0xc0,0xa9,0x54,0xa0,0x75,0x8d,0x2c,0x72,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7e,0xf8,0xcd,0x45,0x0e,0x00,0x8a,0x7f,0xff,0x29,0x09,0xec,0x5a,0xa9,0x14,0xce,0x46,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xfe,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x80,0x3e,0x1e,0x68,0x27,0x51,0x41,0xdf,0xc3,0x69,0x37,0x8d,0xcd,0xd8,0xde,0x8d,0x05,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x00, + 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0xff, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x00, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0xff, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x00, + 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0xff, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x08,0x02,0x01,0x00,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x02,0x01,0x00,0x09,0x01,0x42, + 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x01, + 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x00, + 0x30,0x05,0x02,0x01,0x00,0x05,0x00, + 0x30,0x05,0x02,0x01,0x00,0x0c,0x00, + 0x30,0x06,0x02,0x01,0x00,0x0c,0x01,0x30, + 0x30,0x05,0x02,0x01,0x00,0x30,0x00, + 0x30,0x08,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00, + 0x30,0x08,0x02,0x01,0x01,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x02,0x01,0x01,0x09,0x01,0x42, + 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x01, + 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x00, + 0x30,0x05,0x02,0x01,0x01,0x05,0x00, + 0x30,0x05,0x02,0x01,0x01,0x0c,0x00, + 0x30,0x06,0x02,0x01,0x01,0x0c,0x01,0x30, + 0x30,0x05,0x02,0x01,0x01,0x30,0x00, + 0x30,0x08,0x02,0x01,0x01,0x30,0x03,0x02,0x01,0x00, + 0x30,0x08,0x02,0x01,0xff,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x02,0x01,0xff,0x09,0x01,0x42, + 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x01, + 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x00, + 0x30,0x05,0x02,0x01,0xff,0x05,0x00, + 0x30,0x05,0x02,0x01,0xff,0x0c,0x00, + 0x30,0x06,0x02,0x01,0xff,0x0c,0x01,0x30, + 0x30,0x05,0x02,0x01,0xff,0x30,0x00, + 0x30,0x08,0x02,0x01,0xff,0x30,0x03,0x02,0x01,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x01,0x42, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x05,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x01,0x30, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x03,0x02,0x01,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x01,0x42, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x05,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x01,0x30, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x03,0x02,0x01,0x00, + 0x30,0x0a,0x09,0x03,0x80,0xfe,0x01,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x09,0x01,0x42,0x09,0x01,0x42, + 0x30,0x06,0x01,0x01,0x01,0x01,0x01,0x01, + 0x30,0x06,0x01,0x01,0x00,0x01,0x01,0x00, + 0x30,0x04,0x05,0x00,0x05,0x00, + 0x30,0x04,0x0c,0x00,0x0c,0x00, + 0x30,0x06,0x0c,0x01,0x30,0x0c,0x01,0x30, + 0x30,0x04,0x30,0x00,0x30,0x00, + 0x30,0x0a,0x30,0x03,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00, + 0x30,0x08,0x09,0x03,0x80,0xfe,0x01,0x02,0x01,0x00, + 0x30,0x06,0x09,0x01,0x42,0x02,0x01,0x00, + 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x00, + 0x30,0x06,0x01,0x01,0x00,0x02,0x01,0x00, + 0x30,0x05,0x05,0x00,0x02,0x01,0x00, + 0x30,0x05,0x0c,0x00,0x02,0x01,0x00, + 0x30,0x06,0x0c,0x01,0x30,0x02,0x01,0x00, + 0x30,0x05,0x30,0x00,0x02,0x01,0x00, + 0x30,0x08,0x30,0x03,0x02,0x01,0x00,0x02,0x01,0x00, + 0x30,0x45,0x02,0x21,0x00,0xdd,0x1b,0x7d,0x09,0xa7,0xbd,0x82,0x18,0x96,0x10,0x34,0xa3,0x9a,0x87,0xfe,0xcf,0x53,0x14,0xf0,0x0c,0x4d,0x25,0xeb,0x58,0xa0,0x7a,0xc8,0x5e,0x85,0xea,0xb5,0x16,0x02,0x20,0x35,0x13,0x8c,0x40,0x1e,0xf8,0xd3,0x49,0x3d,0x65,0xc9,0x00,0x2f,0xe6,0x2b,0x43,0xae,0xe5,0x68,0x73,0x1b,0x74,0x45,0x48,0x35,0x89,0x96,0xd9,0xcc,0x42,0x7e,0x06, + 0x30,0x45,0x02,0x21,0x00,0x95,0xc2,0x92,0x67,0xd9,0x72,0xa0,0x43,0xd9,0x55,0x22,0x45,0x46,0x22,0x2b,0xba,0x34,0x3f,0xc1,0xd4,0xdb,0x0f,0xec,0x26,0x2a,0x33,0xac,0x61,0x30,0x56,0x96,0xae,0x02,0x20,0x6e,0xdf,0xe9,0x67,0x13,0xae,0xd5,0x6f,0x8a,0x28,0xa6,0x65,0x3f,0x57,0xe0,0xb8,0x29,0x71,0x2e,0x5e,0xdd,0xc6,0x7f,0x34,0x68,0x2b,0x24,0xf0,0x67,0x6b,0x26,0x40, + 0x30,0x44,0x02,0x20,0x28,0xf9,0x4a,0x89,0x4e,0x92,0x02,0x46,0x99,0xe3,0x45,0xfe,0x66,0x97,0x1e,0x3e,0xdc,0xd0,0x50,0x02,0x33,0x86,0x13,0x5a,0xb3,0x93,0x9d,0x55,0x08,0x98,0xfb,0x25,0x02,0x20,0x32,0x96,0x3e,0x5b,0xd4,0x1f,0xa5,0x91,0x1e,0xd8,0xf3,0x7d,0xeb,0x86,0xda,0xe0,0xa7,0x62,0xbb,0x61,0x21,0xc8,0x94,0x61,0x50,0x83,0xc5,0xd9,0x5e,0xa0,0x1d,0xb3, + 0x30,0x45,0x02,0x21,0x00,0xbe,0x26,0xb1,0x8f,0x95,0x49,0xf8,0x9f,0x41,0x1a,0x9b,0x52,0x53,0x6b,0x15,0xaa,0x27,0x0b,0x84,0x54,0x8d,0x0e,0x85,0x9a,0x19,0x52,0xa2,0x7a,0xf1,0xa7,0x7a,0xc6,0x02,0x20,0x70,0xc1,0xd4,0xfa,0x9c,0xd0,0x3c,0xc8,0xea,0xa8,0xd5,0x06,0xed,0xb9,0x7e,0xed,0x7b,0x83,0x58,0xb4,0x53,0xc8,0x8a,0xef,0xbb,0x88,0x0a,0x3f,0x0e,0x8d,0x47,0x2f, + 0x30,0x45,0x02,0x21,0x00,0xb1,0xa4,0xb1,0x47,0x8e,0x65,0xcc,0x3e,0xaf,0xdf,0x22,0x5d,0x12,0x98,0xb4,0x3f,0x2d,0xa1,0x9e,0x4b,0xcf,0xf7,0xea,0xcc,0x0a,0x2e,0x98,0xcd,0x4b,0x74,0xb1,0x14,0x02,0x20,0x17,0x9a,0xa3,0x1e,0x30,0x4c,0xc1,0x42,0xcf,0x50,0x73,0x17,0x17,0x51,0xb2,0x8f,0x3f,0x5e,0x0f,0xa8,0x8c,0x99,0x4e,0x7c,0x55,0xf1,0xbc,0x07,0xb8,0xd5,0x6c,0x16, + 0x30,0x44,0x02,0x20,0x32,0x53,0x32,0x02,0x12,0x61,0xf1,0xbd,0x18,0xf2,0x71,0x2a,0xa1,0xe2,0x25,0x2d,0xa2,0x37,0x96,0xda,0x8a,0x4b,0x1f,0xf6,0xea,0x18,0xca,0xfe,0xc7,0xe1,0x71,0xf2,0x02,0x20,0x40,0xb4,0xf5,0xe2,0x87,0xee,0x61,0xfc,0x3c,0x80,0x41,0x86,0x98,0x23,0x60,0x89,0x1e,0xaa,0x35,0xc7,0x5f,0x05,0xa4,0x3e,0xcd,0x48,0xb3,0x5d,0x98,0x4a,0x66,0x48, + 0x30,0x45,0x02,0x21,0x00,0xa2,0x3a,0xd1,0x8d,0x8f,0xc6,0x6d,0x81,0xaf,0x09,0x03,0x89,0x0c,0xbd,0x45,0x3a,0x55,0x4c,0xb0,0x4c,0xdc,0x1a,0x8c,0xa7,0xf7,0xf7,0x8e,0x53,0x67,0xed,0x88,0xa0,0x02,0x20,0x23,0xe3,0xeb,0x2c,0xe1,0xc0,0x4e,0xa7,0x48,0xc3,0x89,0xbd,0x97,0x37,0x4a,0xa9,0x41,0x3b,0x92,0x68,0x85,0x1c,0x04,0xdc,0xd9,0xf8,0x8e,0x78,0x81,0x3f,0xee,0x56, + 0x30,0x44,0x02,0x20,0x2b,0xde,0xa4,0x1c,0xda,0x63,0xa2,0xd1,0x4b,0xf4,0x73,0x53,0xbd,0x20,0x88,0x0a,0x69,0x09,0x01,0xde,0x7c,0xd6,0xe3,0xcc,0x6d,0x8e,0xd5,0xba,0x0c,0xdb,0x10,0x91,0x02,0x20,0x3c,0xea,0x66,0xbc,0xcf,0xc9,0xf9,0xbf,0x8c,0x7c,0xa4,0xe1,0xc1,0x45,0x7c,0xc9,0x14,0x5e,0x13,0xe9,0x36,0xd9,0x0b,0x3d,0x9c,0x77,0x86,0xb8,0xb2,0x6c,0xf4,0xc7, + 0x30,0x45,0x02,0x21,0x00,0xd7,0xcd,0x76,0xec,0x01,0xc1,0xb1,0x07,0x9e,0xba,0x9e,0x2a,0xa2,0xa3,0x97,0x24,0x3c,0x47,0x58,0xc9,0x8a,0x1b,0xa0,0xb7,0x40,0x4a,0x34,0x0b,0x9b,0x00,0xce,0xd6,0x02,0x20,0x35,0x75,0x00,0x1e,0x19,0xd9,0x22,0xe6,0xde,0x8b,0x3d,0x6c,0x84,0xea,0x43,0xb5,0xc3,0x33,0x81,0x06,0xcf,0x29,0x99,0x01,0x34,0xe7,0x66,0x9a,0x82,0x6f,0x78,0xe6, + 0x30,0x45,0x02,0x21,0x00,0xa8,0x72,0xc7,0x44,0xd9,0x36,0xdb,0x21,0xa1,0x0c,0x36,0x1d,0xd5,0xc9,0x06,0x33,0x55,0xf8,0x49,0x02,0x21,0x96,0x52,0xf6,0xfc,0x56,0xdc,0x95,0xa7,0x13,0x9d,0x96,0x02,0x20,0x40,0x0d,0xf7,0x57,0x5d,0x97,0x56,0x21,0x0e,0x9c,0xcc,0x77,0x16,0x2c,0x6b,0x59,0x3c,0x77,0x46,0xcf,0xb4,0x8a,0xc2,0x63,0xc4,0x27,0x50,0xb4,0x21,0xef,0x4b,0xb9, + 0x30,0x45,0x02,0x21,0x00,0x9f,0xa9,0xaf,0xe0,0x77,0x52,0xda,0x10,0xb3,0x6d,0x3a,0xfc,0xd0,0xfe,0x44,0xbf,0xc4,0x02,0x44,0xd7,0x52,0x03,0x59,0x9c,0xf8,0xf5,0x04,0x7f,0xa3,0x45,0x38,0x54,0x02,0x20,0x50,0xe0,0xa7,0xc0,0x13,0xbf,0xbf,0x51,0x81,0x97,0x36,0x97,0x2d,0x44,0xb4,0xb5,0x6b,0xc2,0xa2,0xb2,0xc1,0x80,0xdf,0x6e,0xc6,0x72,0xdf,0x17,0x14,0x10,0xd7,0x7a, + 0x30,0x45,0x02,0x21,0x00,0x88,0x56,0x40,0x38,0x4d,0x0d,0x91,0x0e,0xfb,0x17,0x7b,0x46,0xbe,0x6c,0x3d,0xc5,0xca,0xc8,0x1f,0x0b,0x88,0xc3,0x19,0x0b,0xb6,0xb5,0xf9,0x9c,0x26,0x41,0xf2,0x05,0x02,0x20,0x73,0x8e,0xd9,0xbf,0xf1,0x16,0x30,0x6d,0x9c,0xaa,0x0f,0x8f,0xc6,0x08,0xbe,0x24,0x3e,0x0b,0x56,0x77,0x79,0xd8,0xda,0xb0,0x3e,0x8e,0x19,0xd5,0x53,0xf1,0xdc,0x8e, + 0x30,0x44,0x02,0x20,0x2d,0x05,0x1f,0x91,0xc5,0xa9,0xd4,0x40,0xc5,0x67,0x69,0x85,0x71,0x04,0x83,0xbc,0x4f,0x1a,0x6c,0x61,0x1b,0x10,0xc9,0x5a,0x2f,0xf0,0x36,0x3d,0x90,0xc2,0xa4,0x58,0x02,0x20,0x6d,0xdf,0x94,0xe6,0xfb,0xa5,0xbe,0x58,0x68,0x33,0xd0,0xc5,0x3c,0xf2,0x16,0xad,0x39,0x48,0xf3,0x79,0x53,0xc2,0x6c,0x1c,0xf4,0x96,0x8e,0x9a,0x9e,0x82,0x43,0xdc, + 0x30,0x45,0x02,0x21,0x00,0xf3,0xac,0x25,0x23,0x96,0x74,0x82,0xf5,0x3d,0x50,0x85,0x22,0x71,0x2d,0x58,0x3f,0x43,0x79,0xcd,0x82,0x41,0x01,0xff,0x63,0x5e,0xa0,0x93,0x51,0x17,0xba,0xa5,0x4f,0x02,0x20,0x27,0xf1,0x08,0x12,0x22,0x73,0x97,0xe0,0x2c,0xea,0x96,0xfb,0x0e,0x68,0x07,0x61,0x63,0x6d,0xab,0x2b,0x08,0x0d,0x1f,0xc5,0xd1,0x16,0x85,0xcb,0xe8,0x50,0x0c,0xfe, + 0x30,0x45,0x02,0x21,0x00,0x96,0x44,0x7c,0xf6,0x8c,0x3a,0xb7,0x26,0x6e,0xd7,0x44,0x7d,0xe3,0xac,0x52,0xfe,0xd7,0xcc,0x08,0xcb,0xdf,0xea,0x39,0x1c,0x18,0xa9,0xb8,0xab,0x37,0x0b,0xc9,0x13,0x02,0x20,0x0f,0x5e,0x78,0x74,0xd3,0xac,0x0e,0x91,0x8f,0x01,0xc8,0x85,0xa1,0x63,0x91,0x77,0xc9,0x23,0xf8,0x66,0x0d,0x1c,0xeb,0xa1,0xca,0x1f,0x30,0x1b,0xc6,0x75,0xcd,0xbc, + 0x30,0x44,0x02,0x20,0x53,0x0a,0x08,0x32,0xb6,0x91,0xda,0x0b,0x56,0x19,0xa0,0xb1,0x1d,0xe6,0x87,0x7f,0x3c,0x09,0x71,0xba,0xaa,0x68,0xed,0x12,0x27,0x58,0xc2,0x9c,0xaa,0xf4,0x6b,0x72,0x02,0x20,0x6c,0x89,0xe4,0x4f,0x5e,0xb3,0x30,0x60,0xea,0x4b,0x46,0x31,0x8c,0x39,0x13,0x8e,0xae,0xde,0xc7,0x2d,0xe4,0x2b,0xa5,0x76,0x57,0x9a,0x6a,0x46,0x90,0xe3,0x39,0xf3, + 0x30,0x45,0x02,0x21,0x00,0x9c,0x54,0xc2,0x55,0x00,0xbd,0xe0,0xb9,0x2d,0x72,0xd6,0xec,0x48,0x3d,0xc2,0x48,0x2f,0x36,0x54,0x29,0x4c,0xa7,0x4d,0xe7,0x96,0xb6,0x81,0x25,0x5e,0xd5,0x8a,0x77,0x02,0x20,0x67,0x74,0x53,0xc6,0xb5,0x6f,0x52,0x76,0x31,0xc9,0xf6,0x7b,0x3f,0x3e,0xb6,0x21,0xfd,0x88,0x58,0x2b,0x4a,0xff,0x15,0x6d,0x2f,0x15,0x67,0xd6,0x21,0x1a,0x2a,0x33, + 0x30,0x45,0x02,0x21,0x00,0xe7,0x90,0x9d,0x41,0x43,0x9e,0x2f,0x6a,0xf2,0x91,0x36,0xc7,0x34,0x8c,0xa2,0x64,0x1a,0x2b,0x07,0x0d,0x5b,0x64,0xf9,0x1e,0xa9,0xda,0x70,0x70,0xc7,0xa2,0x61,0x8b,0x02,0x20,0x42,0xd7,0x82,0xf1,0x32,0xfa,0x1d,0x36,0xc2,0xc8,0x8b,0xa2,0x7c,0x3d,0x67,0x8d,0x80,0x18,0x4a,0x5d,0x1e,0xcc,0xac,0x75,0x01,0xf0,0xb4,0x7e,0x3d,0x20,0x50,0x08, + 0x30,0x44,0x02,0x20,0x59,0x24,0x87,0x32,0x09,0x59,0x31,0x35,0xa4,0xc3,0xda,0x7b,0xb3,0x81,0x22,0x7f,0x8a,0x4b,0x6a,0xa9,0xf3,0x4f,0xe5,0xbb,0x7f,0x8f,0xbc,0x13,0x1a,0x03,0x9f,0xfe,0x02,0x20,0x1f,0x1b,0xb1,0x1b,0x44,0x1c,0x8f,0xea,0xa4,0x0f,0x44,0x21,0x3d,0x9a,0x40,0x5e,0xd7,0x92,0xd5,0x9f,0xb4,0x9d,0x5b,0xcd,0xd9,0xa4,0x28,0x5a,0xe5,0x69,0x30,0x22, + 0x30,0x45,0x02,0x21,0x00,0xee,0xb6,0x92,0xc9,0xb2,0x62,0x96,0x9b,0x23,0x1c,0x38,0xb5,0xa7,0xf6,0x06,0x49,0xe0,0xc8,0x75,0xcd,0x64,0xdf,0x88,0xf3,0x3a,0xa5,0x71,0xfa,0x3d,0x29,0xab,0x0e,0x02,0x20,0x21,0x8b,0x3a,0x1e,0xb0,0x63,0x79,0xc2,0xc1,0x8c,0xf5,0x1b,0x06,0x43,0x07,0x86,0xd1,0xc6,0x4c,0xd2,0xd2,0x4c,0x9b,0x23,0x2b,0x23,0xe5,0xba,0xc7,0x98,0x9a,0xcd, + 0x30,0x45,0x02,0x21,0x00,0xa4,0x00,0x34,0x17,0x7f,0x36,0x09,0x1c,0x2b,0x65,0x36,0x84,0xa0,0xe3,0xeb,0x5d,0x4b,0xff,0x18,0xe4,0xd0,0x9f,0x66,0x4c,0x28,0x00,0xe7,0xca,0xfd,0xa1,0xda,0xf8,0x02,0x20,0x3a,0x3e,0xc2,0x98,0x53,0x70,0x4e,0x52,0x03,0x1c,0x58,0x92,0x7a,0x80,0x0a,0x96,0x83,0x53,0xad,0xc3,0xd9,0x73,0xbe,0xba,0x91,0x72,0xcb,0xbe,0xab,0x4d,0xd1,0x49, + 0x30,0x45,0x02,0x21,0x00,0xb5,0xd7,0x95,0xcc,0x75,0xce,0xa5,0xc4,0x34,0xfa,0x41,0x85,0x18,0x0c,0xd6,0xbd,0x21,0x22,0x3f,0x3d,0x5a,0x86,0xda,0x66,0x70,0xd7,0x1d,0x95,0x68,0x0d,0xad,0xbf,0x02,0x20,0x54,0xe4,0xd8,0x81,0x0a,0x00,0x1e,0xcb,0xb9,0xf7,0xca,0x1c,0x2e,0xbf,0xdb,0x9d,0x00,0x9e,0x90,0x31,0xa4,0x31,0xac,0xa3,0xc2,0x0a,0xb4,0xe0,0xd1,0x37,0x4e,0xc1, + 0x30,0x44,0x02,0x20,0x07,0xdc,0x24,0x78,0xd4,0x3c,0x12,0x32,0xa4,0x59,0x56,0x08,0xc6,0x44,0x26,0xc3,0x55,0x10,0x05,0x1a,0x63,0x1a,0xe6,0xa5,0xa6,0xeb,0x11,0x61,0xe5,0x7e,0x42,0xe1,0x02,0x20,0x4a,0x59,0xea,0x0f,0xdb,0x72,0xd1,0x21,0x65,0xce,0xa3,0xbf,0x1c,0xa8,0x6b,0xa9,0x75,0x17,0xbd,0x18,0x8d,0xb3,0xdb,0xd2,0x1a,0x5a,0x15,0x78,0x50,0x02,0x19,0x84, + 0x30,0x45,0x02,0x21,0x00,0xdd,0xd2,0x0c,0x4a,0x05,0x59,0x6c,0xa8,0x68,0xb5,0x58,0x83,0x9f,0xce,0x9f,0x65,0x11,0xdd,0xd8,0x3d,0x1c,0xcb,0x53,0xf8,0x2e,0x52,0x69,0xd5,0x59,0xa0,0x15,0x52,0x02,0x20,0x5b,0x91,0x73,0x47,0x29,0xd9,0x30,0x93,0xff,0x22,0x12,0x3c,0x4a,0x25,0x81,0x9d,0x7f,0xeb,0x66,0xa2,0x50,0x66,0x3f,0xc7,0x80,0xcb,0x66,0xfc,0x7b,0x6e,0x6d,0x17, + 0x30,0x45,0x02,0x21,0x00,0x9c,0xde,0x6e,0x0e,0xde,0x0a,0x00,0x3f,0x02,0xfd,0xa0,0xa0,0x1b,0x59,0xfa,0xcf,0xe5,0xde,0xc0,0x63,0x31,0x8f,0x27,0x9c,0xe2,0xde,0x7a,0x9b,0x10,0x62,0xf7,0xb7,0x02,0x20,0x28,0x86,0xa5,0xb8,0xc6,0x79,0xbd,0xf8,0x22,0x4c,0x66,0xf9,0x08,0xfd,0x62,0x05,0x49,0x2c,0xb7,0x0b,0x00,0x68,0xd4,0x6a,0xe4,0xf3,0x3a,0x41,0x49,0xb1,0x2a,0x52, + 0x30,0x45,0x02,0x21,0x00,0xc5,0x77,0x10,0x16,0xd0,0xdd,0x63,0x57,0x14,0x3c,0x89,0xf6,0x84,0xcd,0x74,0x04,0x23,0x50,0x25,0x54,0xc0,0xc5,0x9a,0xa8,0xc9,0x95,0x84,0xf1,0xff,0x38,0xf6,0x09,0x02,0x20,0x54,0xb4,0x05,0xf4,0x47,0x75,0x46,0x68,0x6e,0x46,0x4c,0x54,0x63,0xb4,0xfd,0x41,0x90,0x57,0x2e,0x58,0xd0,0xf7,0xe7,0x35,0x7f,0x6e,0x61,0x94,0x7d,0x20,0x71,0x5c, + 0x30,0x45,0x02,0x21,0x00,0xa2,0x4e,0xbc,0x0e,0xc2,0x24,0xbd,0x67,0xae,0x39,0x7c,0xbe,0x6f,0xa3,0x7b,0x31,0x25,0xad,0xbd,0x34,0x89,0x1a,0xbe,0x2d,0x7c,0x73,0x56,0x92,0x19,0x16,0xdf,0xe6,0x02,0x20,0x34,0xf6,0xeb,0x63,0x74,0x73,0x1b,0xbb,0xaf,0xc4,0x92,0x4f,0xb8,0xb0,0xbd,0xcd,0xda,0x49,0x45,0x6d,0x72,0x4c,0xda,0xe6,0x17,0x8d,0x87,0x01,0x4c,0xb5,0x3d,0x8c, + 0x30,0x44,0x02,0x20,0x25,0x57,0xd6,0x4a,0x7a,0xee,0x2e,0x09,0x31,0xc0,0x12,0xe4,0xfe,0xa1,0xcd,0x3a,0x2c,0x33,0x4e,0xda,0xe6,0x8c,0xde,0xb7,0x15,0x8c,0xaf,0x21,0xb6,0x8e,0x5a,0x24,0x02,0x20,0x7f,0x06,0xcd,0xbb,0x6a,0x90,0x02,0x3a,0x97,0x38,0x82,0xed,0x97,0xb0,0x80,0xfe,0x6b,0x05,0xaf,0x3e,0xc9,0x3d,0xb6,0xf1,0xa4,0x39,0x9a,0x69,0xed,0xf7,0x67,0x0d, + 0x30,0x45,0x02,0x21,0x00,0xc4,0xf2,0xec,0xcb,0xb6,0xa2,0x43,0x50,0xc8,0x46,0x64,0x50,0xb9,0xd6,0x1b,0x20,0x7e,0xe3,0x59,0xe0,0x37,0xb3,0xdc,0xed,0xb4,0x2a,0x3f,0x2e,0x6d,0xd6,0xae,0xb5,0x02,0x20,0x32,0x63,0xc6,0xb5,0x9a,0x2f,0x55,0xcd,0xd1,0xc6,0xe1,0x48,0x94,0xd5,0xe5,0x96,0x3b,0x28,0xbc,0x3e,0x24,0x69,0xac,0x9b,0xa1,0x19,0x79,0x91,0xca,0x7f,0xf9,0xc7, + 0x30,0x45,0x02,0x21,0x00,0xef,0xf0,0x47,0x81,0xc9,0xcb,0xcd,0x16,0x2d,0x0a,0x25,0xa6,0xe2,0xeb,0xcc,0xa4,0x35,0x06,0xc5,0x23,0x38,0x5c,0xb5,0x15,0xd4,0x9e,0xa3,0x8a,0x1b,0x12,0xfc,0xad,0x02,0x20,0x15,0xac,0xd7,0x31,0x94,0xc9,0x1a,0x95,0x47,0x85,0x34,0xf2,0x30,0x15,0xb6,0x72,0xeb,0xed,0x21,0x3e,0x45,0x42,0x4d,0xd2,0xc8,0xe2,0x6a,0xc8,0xb3,0xeb,0x34,0xa5, + 0x30,0x45,0x02,0x21,0x00,0xf5,0x8b,0x4e,0x31,0x10,0xa6,0x4b,0xf1,0xb5,0xdb,0x97,0x63,0x9e,0xe0,0xe5,0xa9,0xc8,0xdf,0xa4,0x9d,0xc5,0x9b,0x67,0x98,0x91,0xf5,0x20,0xfd,0xf0,0x58,0x4c,0x87,0x02,0x20,0x2c,0xd8,0xfe,0x51,0x88,0x8a,0xee,0x9d,0xb3,0xe0,0x75,0x44,0x0f,0xd4,0xdb,0x73,0xb5,0xc7,0x32,0xfb,0x87,0xb5,0x10,0xe9,0x70,0x93,0xd6,0x64,0x15,0xf6,0x2a,0xf7, + 0x30,0x45,0x02,0x21,0x00,0xf8,0xab,0xec,0xaa,0x4f,0x0c,0x50,0x2d,0xe4,0xbf,0x59,0x03,0xd4,0x84,0x17,0xf7,0x86,0xbf,0x92,0xe8,0xad,0x72,0xfe,0xc0,0xbd,0x7f,0xcb,0x78,0x00,0xc0,0xbb,0xe3,0x02,0x20,0x4c,0x7f,0x9e,0x23,0x10,0x76,0xa3,0x0b,0x7a,0xe3,0x6b,0x0c,0xeb,0xe6,0x9c,0xce,0xf1,0xcd,0x19,0x4f,0x7c,0xce,0x93,0xa5,0x58,0x8f,0xd6,0x81,0x4f,0x43,0x7c,0x0e, + 0x30,0x44,0x02,0x20,0x5d,0x5b,0x38,0xbd,0x37,0xad,0x49,0x8b,0x22,0x27,0xa6,0x33,0x26,0x8a,0x8c,0xca,0x87,0x9a,0x5c,0x7c,0x94,0xa4,0xe4,0x16,0xbd,0x0a,0x61,0x4d,0x09,0xe6,0x06,0xd2,0x02,0x20,0x12,0xb8,0xd6,0x64,0xea,0x99,0x91,0x06,0x2e,0xcb,0xb8,0x34,0xe5,0x84,0x00,0xe2,0x5c,0x46,0x00,0x7a,0xf8,0x4f,0x60,0x07,0xd7,0xf1,0x68,0x54,0x43,0x26,0x9a,0xfe, + 0x30,0x44,0x02,0x20,0x0c,0x1c,0xd9,0xfe,0x40,0x34,0xf0,0x86,0xa2,0xb5,0x2d,0x65,0xb9,0xd3,0x83,0x4d,0x72,0xae,0xbe,0x7f,0x33,0xdf,0xe8,0xf9,0x76,0xda,0x82,0x64,0x81,0x77,0xd8,0xe3,0x02,0x20,0x13,0x10,0x57,0x82,0xe3,0xd0,0xcf,0xe8,0x5c,0x27,0x78,0xde,0xc1,0xa8,0x48,0xb2,0x7a,0xc0,0xae,0x07,0x1a,0xa6,0xda,0x34,0x1a,0x95,0x53,0xa9,0x46,0xb4,0x1e,0x59, + 0x30,0x45,0x02,0x21,0x00,0xae,0x79,0x35,0xfb,0x96,0xff,0x24,0x6b,0x7b,0x5d,0x56,0x62,0x87,0x0d,0x1b,0xa5,0x87,0xb0,0x3d,0x6e,0x13,0x60,0xba,0xf4,0x79,0x88,0xb5,0xc0,0x2c,0xcc,0x1a,0x5b,0x02,0x20,0x5f,0x00,0xc3,0x23,0x27,0x20,0x83,0x78,0x2d,0x4a,0x59,0xf2,0xdf,0xd6,0x5e,0x49,0xde,0x06,0x93,0x62,0x70,0x16,0x90,0x0e,0xf7,0xe6,0x14,0x28,0x05,0x66,0x64,0xb3, + 0x30,0x44,0x02,0x20,0x00,0xa1,0x34,0xb5,0xc6,0xcc,0xbc,0xef,0xd4,0xc8,0x82,0xb9,0x45,0xba,0xeb,0x49,0x33,0x44,0x41,0x72,0x79,0x5f,0xa6,0x79,0x6a,0xae,0x14,0x90,0x67,0x54,0x70,0x98,0x02,0x20,0x56,0x6e,0x46,0x10,0x5d,0x24,0xd8,0x90,0x15,0x1e,0x3e,0xea,0x3e,0xbf,0x88,0xf5,0xb9,0x2b,0x3f,0x5e,0xc9,0x3a,0x21,0x77,0x65,0xa6,0xdc,0xbd,0x94,0xf2,0xc5,0x5b, + 0x30,0x44,0x02,0x20,0x2e,0x47,0x21,0x36,0x3a,0xd3,0x99,0x2c,0x13,0x9e,0x5a,0x1c,0x26,0x39,0x5d,0x2c,0x2d,0x77,0x78,0x24,0xaa,0x24,0xfd,0xe0,0x75,0xe0,0xd7,0x38,0x11,0x71,0x30,0x9d,0x02,0x20,0x74,0x0f,0x7c,0x49,0x44,0x18,0xe1,0x30,0x0d,0xd4,0x51,0x2f,0x78,0x2a,0x58,0x80,0x0b,0xff,0x6a,0x7a,0xbd,0xfd,0xd2,0x0f,0xbb,0xd4,0xf0,0x55,0x15,0xca,0x1a,0x4f, + 0x30,0x44,0x02,0x20,0x68,0x52,0xe9,0xd3,0xcd,0x9f,0xe3,0x73,0xc2,0xd5,0x04,0x87,0x79,0x67,0xd3,0x65,0xab,0x14,0x56,0x70,0x7b,0x68,0x17,0xa0,0x42,0x86,0x46,0x94,0xe1,0x96,0x0c,0xcf,0x02,0x20,0x06,0x4b,0x27,0xea,0x14,0x2b,0x30,0x88,0x7b,0x84,0xc8,0x6a,0xdc,0xcb,0x2f,0xa3,0x9a,0x69,0x11,0xad,0x21,0xfc,0x7e,0x81,0x9f,0x59,0x3b,0xe5,0x2b,0xc4,0xf3,0xbd, + 0x30,0x44,0x02,0x20,0x18,0x8a,0x8c,0x56,0x48,0xdc,0x79,0xea,0xce,0x15,0x8c,0xf8,0x86,0xc6,0x2b,0x54,0x68,0xf0,0x5f,0xd9,0x5f,0x03,0xa7,0x63,0x5c,0x5b,0x4c,0x31,0xf0,0x9a,0xf4,0xc5,0x02,0x20,0x36,0x36,0x1a,0x0b,0x57,0x1a,0x00,0xc6,0xcd,0x5e,0x68,0x6c,0xcb,0xfc,0xfa,0x70,0x3c,0x4f,0x97,0xe4,0x89,0x38,0x34,0x6d,0x0c,0x10,0x3f,0xdc,0x76,0xdc,0x58,0x67, + 0x30,0x45,0x02,0x21,0x00,0xa7,0x4f,0x1f,0xb9,0xa8,0x26,0x3f,0x62,0xfc,0x44,0x16,0xa5,0xb7,0xd5,0x84,0xf4,0x20,0x6f,0x39,0x96,0xbb,0x91,0xf6,0xfc,0x8e,0x73,0xb9,0xe9,0x2b,0xad,0x0e,0x13,0x02,0x20,0x68,0x15,0x03,0x2e,0x8c,0x7d,0x76,0xc3,0xab,0x06,0xa8,0x6f,0x33,0x24,0x9c,0xe9,0x94,0x01,0x48,0xcb,0x36,0xd1,0xf4,0x17,0xc2,0xe9,0x92,0xe8,0x01,0xaf,0xa3,0xfa, + 0x30,0x44,0x02,0x20,0x07,0x24,0x48,0x65,0xb7,0x2f,0xf3,0x7e,0x62,0xe3,0x14,0x6f,0x0d,0xc1,0x46,0x82,0xba,0xdd,0x71,0x97,0x79,0x91,0x35,0xf0,0xb0,0x0a,0xde,0x76,0x71,0x74,0x2b,0xfe,0x02,0x20,0x0d,0x80,0xc2,0x23,0x8e,0xdb,0x4e,0x4a,0x7a,0x86,0xa8,0xc5,0x7c,0xa9,0xaf,0x17,0x11,0xf4,0x06,0xf7,0xf5,0xda,0x02,0x99,0xaa,0x04,0xe2,0x93,0x2d,0x96,0x07,0x54, + 0x30,0x45,0x02,0x21,0x00,0xda,0x7f,0xdd,0x05,0xb5,0xba,0xda,0xbd,0x61,0x9d,0x80,0x5c,0x4e,0xe7,0xd9,0xa8,0x4f,0x84,0xdd,0xd5,0xcf,0x9c,0x5b,0xf4,0xd4,0x33,0x81,0x40,0xd6,0x89,0xef,0x08,0x02,0x20,0x28,0xf1,0xcf,0x4f,0xa1,0xc3,0xc5,0x86,0x2c,0xfa,0x14,0x9c,0x00,0x13,0xcf,0x5f,0xe6,0xcf,0x50,0x76,0xca,0xe0,0x00,0x51,0x10,0x63,0xe7,0xde,0x25,0xbb,0x38,0xe5, + 0x30,0x45,0x02,0x21,0x00,0xd3,0x02,0x7c,0x65,0x6f,0x6d,0x4f,0xdf,0xd8,0xed,0xe2,0x20,0x93,0xe3,0xc3,0x03,0xb0,0x13,0x3c,0x34,0x0d,0x61,0x5e,0x77,0x56,0xf6,0x25,0x3a,0xea,0x92,0x72,0x38,0x02,0x20,0x09,0xae,0xf0,0x60,0xc8,0xe4,0xce,0xf9,0x72,0x97,0x40,0x11,0x55,0x8d,0xf1,0x44,0xfe,0xd2,0x5c,0xa6,0x9a,0xe8,0xd0,0xb2,0xea,0xf1,0xa8,0xfe,0xef,0xbe,0xc4,0x17, + 0x30,0x44,0x02,0x20,0x0b,0xf6,0xc0,0x18,0x8d,0xc9,0x57,0x1c,0xd0,0xe2,0x1e,0xec,0xac,0x5f,0xbb,0x19,0xd2,0x43,0x49,0x88,0xe9,0xcc,0x10,0x24,0x45,0x93,0xef,0x3a,0x98,0x09,0x9f,0x69,0x02,0x20,0x48,0x64,0xa5,0x62,0x66,0x1f,0x92,0x21,0xec,0x88,0xe3,0xdd,0x0b,0xc2,0xf6,0xe2,0x7a,0xc1,0x28,0xc3,0x0c,0xc1,0xa8,0x0f,0x79,0xec,0x67,0x0a,0x22,0xb0,0x42,0xee, + 0x30,0x45,0x02,0x21,0x00,0xae,0x45,0x96,0x40,0xd5,0xd1,0x17,0x9b,0xe4,0x7a,0x47,0xfa,0x53,0x8e,0x16,0xd9,0x4d,0xde,0xa5,0x58,0x5e,0x7a,0x24,0x48,0x04,0xa5,0x17,0x42,0xc6,0x86,0x44,0x3a,0x02,0x20,0x6c,0x8e,0x30,0xe5,0x30,0xa6,0x34,0xfa,0xe8,0x0b,0x3c,0xeb,0x06,0x29,0x78,0xb3,0x9e,0xdb,0xe1,0x97,0x77,0xe0,0xa2,0x45,0x53,0xb6,0x88,0x86,0x18,0x1f,0xd8,0x97, + 0x30,0x44,0x02,0x20,0x1c,0xf3,0x51,0x7b,0xa3,0xbf,0x2a,0xb8,0xb9,0xea,0xd4,0xeb,0xb6,0xe8,0x66,0xcb,0x88,0xa1,0xde,0xac,0xb6,0xa7,0x85,0xd3,0xb6,0x3b,0x48,0x3c,0xa0,0x2a,0xc4,0x95,0x02,0x20,0x24,0x9a,0x79,0x8b,0x73,0x60,0x6f,0x55,0xf5,0xf1,0xc7,0x0d,0xe6,0x7c,0xb1,0xa0,0xcf,0xf9,0x5d,0x7d,0xc5,0x0b,0x3a,0x61,0x7d,0xf8,0x61,0xba,0xd3,0xc6,0xb1,0xc9, + 0x30,0x45,0x02,0x21,0x00,0xe6,0x9b,0x52,0x38,0x26,0x5e,0xa3,0x5d,0x77,0xe4,0xdd,0x17,0x22,0x88,0xd8,0xce,0xa1,0x98,0x10,0xa1,0x02,0x92,0x61,0x7d,0x59,0x76,0x51,0x9d,0xc5,0x75,0x7c,0xb8,0x02,0x20,0x4b,0x03,0xc5,0xbc,0x47,0xe8,0x26,0xbd,0xb2,0x73,0x28,0xab,0xd3,0x8d,0x30,0x56,0xd7,0x74,0x76,0xb2,0x13,0x0f,0x3d,0xf6,0xec,0x48,0x91,0xaf,0x08,0xba,0x1e,0x29, + 0x30,0x44,0x02,0x20,0x5f,0x9d,0x7d,0x7c,0x87,0x0d,0x08,0x5f,0xc1,0xd4,0x9f,0xff,0x69,0xe4,0xa2,0x75,0x81,0x28,0x00,0xd2,0xcf,0x89,0x73,0xe7,0x32,0x58,0x66,0xcb,0x40,0xfa,0x2b,0x6f,0x02,0x20,0x6d,0x1f,0x54,0x91,0xd9,0xf7,0x17,0xa5,0x97,0xa1,0x5f,0xd5,0x40,0x40,0x64,0x86,0xd7,0x6a,0x44,0x69,0x7b,0x3f,0x0d,0x9d,0x6d,0xce,0xf6,0x66,0x9f,0x8a,0x0a,0x56, + 0x30,0x44,0x02,0x20,0x0a,0x7d,0x5b,0x19,0x59,0xf7,0x1d,0xf9,0xf8,0x17,0x14,0x6e,0xe4,0x9b,0xd5,0xc8,0x9b,0x43,0x1e,0x79,0x93,0xe2,0xfd,0xec,0xab,0x68,0x58,0x95,0x7d,0xa6,0x85,0xae,0x02,0x20,0x0f,0x8a,0xad,0x2d,0x25,0x46,0x90,0xbd,0xc1,0x3f,0x34,0xa4,0xfe,0xc4,0x4a,0x02,0xfd,0x74,0x5a,0x42,0x2d,0xf0,0x5c,0xcb,0xb5,0x46,0x35,0xa8,0xb8,0x6b,0x96,0x09, + 0x30,0x44,0x02,0x20,0x79,0xe8,0x8b,0xf5,0x76,0xb7,0x4b,0xc0,0x7c,0xa1,0x42,0x39,0x5f,0xda,0x28,0xf0,0x3d,0x3d,0x5e,0x64,0x0b,0x0b,0x4f,0xf0,0x75,0x2c,0x6d,0x94,0xcd,0x55,0x34,0x08,0x02,0x20,0x32,0xce,0xa0,0x5b,0xd2,0xd7,0x06,0xc8,0xf6,0x03,0x6a,0x50,0x7e,0x2a,0xb7,0x76,0x60,0x04,0xf0,0x90,0x4e,0x2e,0x5c,0x58,0x62,0x74,0x9c,0x00,0x73,0x24,0x5d,0x6a, + 0x30,0x45,0x02,0x21,0x00,0x9d,0x54,0xe0,0x37,0xa0,0x02,0x12,0xb3,0x77,0xbc,0x88,0x74,0x79,0x8b,0x8d,0xa0,0x80,0x56,0x4b,0xbd,0xf7,0xe0,0x75,0x91,0xb8,0x61,0x28,0x58,0x09,0xd0,0x14,0x88,0x02,0x20,0x18,0xb4,0xe5,0x57,0x66,0x7a,0x82,0xbd,0x95,0x96,0x5f,0x07,0x06,0xf8,0x1a,0x29,0x24,0x3f,0xbd,0xd8,0x69,0x68,0xa7,0xeb,0xeb,0x43,0x06,0x9d,0xb3,0xb1,0x8c,0x7f, + 0x30,0x44,0x02,0x20,0x26,0x64,0xf1,0xff,0xa9,0x82,0xfe,0xdb,0xcc,0x7c,0xab,0x1b,0x8b,0xc6,0xe2,0xcb,0x42,0x02,0x18,0xd2,0xa6,0x07,0x7a,0xd0,0x8e,0x59,0x1b,0xa9,0xfe,0xab,0x33,0xbd,0x02,0x20,0x49,0xf5,0xc7,0xcb,0x51,0x5e,0x83,0x87,0x2a,0x3d,0x41,0xb4,0xcd,0xb8,0x5f,0x24,0x2a,0xd9,0xd6,0x1a,0x5b,0xfc,0x01,0xde,0xbf,0xbb,0x52,0xc6,0xc8,0x4b,0xa7,0x28, + 0x30,0x44,0x02,0x20,0x58,0x27,0x51,0x83,0x44,0x84,0x4f,0xd6,0xa7,0xde,0x73,0xcb,0xb0,0xa6,0xbe,0xfd,0xea,0x7b,0x13,0xd2,0xde,0xe4,0x47,0x53,0x17,0xf0,0xf1,0x8f,0xfc,0x81,0x52,0x4b,0x02,0x20,0x4f,0x5c,0xcb,0x4e,0x0b,0x48,0x8b,0x5a,0x5d,0x76,0x0a,0xac,0xdd,0xb2,0xd7,0x91,0x97,0x0f,0xe4,0x3d,0xa6,0x1e,0xb3,0x0e,0x2e,0x90,0x20,0x8a,0x81,0x7e,0x46,0xdb, + 0x30,0x45,0x02,0x21,0x00,0x97,0xab,0x19,0xbd,0x13,0x9c,0xac,0x31,0x93,0x25,0x86,0x92,0x18,0xb1,0xbc,0xe1,0x11,0x87,0x5d,0x63,0xfb,0x12,0x09,0x8a,0x04,0xb0,0xcd,0x59,0xb6,0xfd,0xd3,0xa3,0x02,0x20,0x43,0x1d,0x9c,0xea,0x3a,0x24,0x38,0x47,0x30,0x3c,0xeb,0xda,0x56,0x47,0x64,0x31,0xd0,0x34,0x33,0x9f,0x31,0xd7,0x85,0xee,0x88,0x52,0xdb,0x4f,0x04,0x0d,0x49,0x21, + 0x30,0x44,0x02,0x20,0x52,0xc6,0x83,0x14,0x4e,0x44,0x11,0x9a,0xe2,0x01,0x37,0x49,0xd4,0x96,0x4e,0xf6,0x75,0x09,0x27,0x8f,0x6d,0x38,0xba,0x86,0x9a,0xdc,0xfa,0x69,0x97,0x0e,0x12,0x3d,0x02,0x20,0x34,0x79,0x91,0x01,0x67,0x40,0x8f,0x45,0xbd,0xa4,0x20,0xa6,0x26,0xec,0x9c,0x4e,0xc7,0x11,0xc1,0x27,0x4b,0xe0,0x92,0x19,0x8b,0x41,0x87,0xc0,0x18,0xb5,0x62,0xca, + 0x30,0x16,0x02,0x11,0x01,0x45,0x51,0x23,0x19,0x50,0xb7,0x5f,0xc4,0x40,0x2d,0xa1,0x72,0x2f,0xc9,0xba,0xeb,0x02,0x01,0x03, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2c,0x02,0x01,0x03, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x3f,0x02,0x01,0x03, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x9a,0x75,0x82,0x88,0x60,0x89,0xc6,0x2f,0xb8,0x40,0xcf,0x3b,0x83,0x06,0x1c,0xd1,0xcf,0xf3,0xae,0x43,0x41,0x80,0x8b,0xb5,0xbd,0xee,0x61,0x91,0x17,0x41,0x77, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x24,0x23,0x8e,0x70,0xb4,0x31,0xb1,0xa6,0x4e,0xfd,0xf9,0x03,0x26,0x69,0x93,0x9d,0x4b,0x77,0xf2,0x49,0x50,0x3f,0xc6,0x90,0x5f,0xeb,0x75,0x40,0xde,0xa3,0xe6,0xd2, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x02, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x03, + 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x02, + 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x03, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x43,0x02,0x01,0x03, + 0x30,0x08,0x02,0x01,0x02,0x02,0x03,0xed,0x29,0x79, + 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0x9f,0x8a,0xb3,0x73,0x2a,0x0a,0x89,0x60,0x4a,0x09,0xbc,0xe5,0xb2,0x91,0x6d,0xa4, + 0x30,0x2b,0x02,0x07,0x2d,0x9b,0x4d,0x34,0x79,0x52,0xcc,0x02,0x20,0x03,0x43,0xae,0xfc,0x2f,0x25,0xd9,0x8b,0x88,0x2e,0x86,0xeb,0x9e,0x30,0xd5,0x5a,0x6e,0xb5,0x08,0xb5,0x16,0x51,0x0b,0x34,0x02,0x4a,0xe4,0xb6,0x36,0x23,0x30,0xb3, + 0x30,0x31,0x02,0x0d,0x10,0x33,0xe6,0x7e,0x37,0xb3,0x2b,0x44,0x55,0x80,0xbf,0x4e,0xfc,0x02,0x20,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x8f,0xe1,0xca,0xb5,0xee,0xfd,0xb2,0x14,0x06,0x1d,0xce,0x3b,0x22,0x78,0x9f,0x1d,0x6f, + 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57, + 0x30,0x31,0x02,0x0d,0x06,0x25,0x22,0xbb,0xd3,0xec,0xbe,0x7c,0x39,0xe9,0x3e,0x7c,0x26,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57, + 0x30,0x45,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x40,0xc1,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x16,0x02,0x09,0x00,0x9c,0x44,0xfe,0xbf,0x31,0xc3,0x59,0x4d,0x02,0x09,0x00,0x83,0x9e,0xd2,0x82,0x47,0xc2,0xb0,0x6b, + 0x30,0x1e,0x02,0x0d,0x09,0xdf,0x8b,0x68,0x24,0x30,0xbe,0xef,0x6f,0x5f,0xd7,0xc7,0xcf,0x02,0x0d,0x0f,0xd0,0xa6,0x2e,0x13,0x77,0x8f,0x42,0x22,0xa0,0xd6,0x1c,0x8a, + 0x30,0x26,0x02,0x11,0x00,0x8a,0x59,0x8e,0x56,0x3a,0x89,0xf5,0x26,0xc3,0x2e,0xbe,0xc8,0xde,0x26,0x36,0x7a,0x02,0x11,0x00,0x84,0xf6,0x33,0xe2,0x04,0x26,0x30,0xe9,0x9d,0xd0,0xf1,0xe1,0x6f,0x7a,0x04,0xbf, + 0x30,0x2e,0x02,0x15,0x00,0xaa,0x6e,0xeb,0x58,0x23,0xf7,0xfa,0x31,0xb4,0x66,0xbb,0x47,0x37,0x97,0xf0,0xd0,0x31,0x4c,0x0b,0xdf,0x02,0x15,0x00,0xe2,0x97,0x7c,0x47,0x9e,0x6d,0x25,0x70,0x3c,0xeb,0xbc,0x6b,0xd5,0x61,0x93,0x8c,0xc9,0xd1,0xbf,0xb9, + 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x01, + 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x00, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x41,0x9d,0x98,0x1c,0x51,0x5a,0xf8,0xcc,0x82,0x54,0x5a,0xac,0x0c,0x85,0xe9,0xe3,0x08,0xfb,0xb2,0xea,0xb6,0xac,0xd7,0xed,0x49,0x7e,0x0b,0x41,0x45,0xa1,0x8f,0xd9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x1b,0x21,0x71,0x7a,0xd7,0x1d,0x23,0xbb,0xac,0x60,0xa9,0xad,0x0b,0xaf,0x75,0xb0,0x63,0xc9,0xfd,0xf5,0x2a,0x00,0xeb,0xf9,0x9d,0x02,0x21,0x72,0x91,0x09,0x93,0xc9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x2f,0x58,0x8f,0x66,0x01,0x8f,0x3d,0xd1,0x4d,0xb3,0xe2,0x8e,0x77,0x99,0x64,0x87,0xe3,0x24,0x86,0xb5,0x21,0xed,0x8e,0x5a,0x20,0xf0,0x65,0x91,0x95,0x17,0x77,0xe9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x09,0x1a,0x08,0x87,0x0f,0xf4,0xda,0xf9,0x12,0x3b,0x30,0xc2,0x0e,0x8c,0x4f,0xc8,0x50,0x57,0x58,0xdc,0xf4,0x07,0x4f,0xca,0xff,0x21,0x70,0xc9,0xbf,0xcf,0x74,0xf4, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7c,0x37,0x0d,0xc0,0xce,0x8c,0x59,0xa8,0xb2,0x73,0xcb,0xa4,0x4a,0x7c,0x11,0x91,0xfc,0x31,0x86,0xdc,0x03,0xca,0xb9,0x6b,0x05,0x67,0x31,0x2d,0xf0,0xd0,0xb2,0x50, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x70,0xb5,0x9a,0x7d,0x1e,0xe7,0x7a,0x2f,0x9e,0x04,0x91,0xc2,0xa7,0xcf,0xcd,0x0e,0xd0,0x4d,0xf4,0xa3,0x51,0x92,0xf6,0x13,0x2d,0xcc,0x66,0x8c,0x79,0xa6,0x16,0x0e, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x27,0x36,0xd7,0x6e,0x41,0x22,0x46,0xe0,0x97,0x14,0x8e,0x2b,0xf6,0x29,0x15,0x61,0x4e,0xb7,0xc4,0x28,0x91,0x3a,0x58,0xeb,0x5e,0x9c,0xd4,0x67,0x4a,0x94,0x23,0xde, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4a,0x1e,0x12,0x83,0x1f,0xbe,0x93,0x62,0x7b,0x02,0xd6,0xe7,0xf2,0x4b,0xcc,0xdd,0x6e,0xf4,0xb2,0xd0,0xf4,0x67,0x39,0xea,0xf3,0xb1,0xea,0xf0,0xca,0x11,0x77,0x70, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x06,0xc7,0x78,0xd4,0xdf,0xff,0x7d,0xee,0x06,0xed,0x88,0xbc,0x4e,0x0e,0xd3,0x4f,0xc5,0x53,0xaa,0xd6,0x7c,0xaf,0x79,0x6f,0x2a,0x1c,0x64,0x87,0xc1,0xb2,0xe8,0x77, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4d,0xe4,0x59,0xef,0x91,0x59,0xaf,0xa0,0x57,0xfe,0xb3,0xec,0x40,0xfe,0xf0,0x1c,0x45,0xb8,0x09,0xf4,0xab,0x29,0x6e,0xa4,0x8c,0x20,0x6d,0x42,0x49,0xa2,0xb4,0x51, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x74,0x5d,0x29,0x49,0x78,0x00,0x73,0x02,0x03,0x35,0x02,0xe1,0xac,0xc4,0x8b,0x63,0xae,0x65,0x00,0xbe,0x43,0xad,0xbe,0xa1,0xb2,0x58,0xd6,0xb4,0x23,0xdb,0xb4,0x16, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7b,0x2a,0x78,0x5e,0x38,0x96,0xf5,0x9b,0x2d,0x69,0xda,0x57,0x64,0x8e,0x80,0xad,0x3c,0x13,0x3a,0x75,0x0a,0x28,0x47,0xfd,0x20,0x98,0xcc,0xd9,0x02,0x04,0x2b,0x6c, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x71,0xae,0x94,0xa7,0x2c,0xa8,0x96,0x87,0x5e,0x7a,0xa4,0xa4,0xc3,0xd2,0x9a,0xfd,0xb4,0xb3,0x5b,0x69,0x96,0x27,0x3e,0x63,0xc4,0x7a,0xc5,0x19,0x25,0x6c,0x5e,0xb1, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x0f,0xa5,0x27,0xfa,0x73,0x43,0xc0,0xbc,0x9e,0xc3,0x5a,0x62,0x78,0xbf,0xbf,0xf4,0xd8,0x33,0x01,0xb1,0x54,0xfc,0x4b,0xd1,0x4a,0xee,0x7e,0xb9,0x34,0x45,0xb5,0xf9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x65,0x39,0xc0,0xad,0xad,0xd0,0x52,0x5f,0xf4,0x26,0x22,0x16,0x4c,0xe9,0x31,0x43,0x48,0xbd,0x08,0x63,0xb4,0xc8,0x0e,0x93,0x6b,0x23,0xca,0x04,0x14,0x26,0x46,0x71, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa1, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x1c,0x94,0x0f,0x31,0x3f,0x92,0x64,0x7b,0xe2,0x57,0xec,0xcd,0x7e,0xd0,0x8b,0x0b,0xae,0xf3,0xf0,0x47,0x8f,0x25,0x87,0x1b,0x53,0x63,0x53,0x02,0xc5,0xf6,0x31,0x4a, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x15,0xd9,0x4a,0x85,0x07,0x7b,0x49,0x3f,0x91,0xcb,0x71,0x01,0xec,0x63,0xe1,0xb0,0x1b,0xe5,0x8b,0x59,0x4e,0x85,0x5f,0x45,0x05,0x0a,0x8c,0x14,0x06,0x2d,0x68,0x9b, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x1d,0x27,0xa7,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9d,0x9e,0xf3,0xb9,0xfb,0x58,0x38,0x54,0x18,0xd9,0xc9,0x82,0x10,0x50,0x77,0xd1,0xb7, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2d,0x85,0x89,0x6b,0x3e,0xb9,0xdb,0xb5,0xa5,0x2f,0x42,0xf9,0xc9,0x26,0x1e,0xd3,0xfc,0x46,0x64,0x4e,0xc6,0x5f,0x06,0xad,0xe3,0xfd,0x78,0xf2,0x57,0xe4,0x34,0x32, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x0b,0x12,0xd6,0x7d,0x73,0xb7,0x6b,0x4a,0x5e,0x85,0xf3,0x92,0x4c,0x3d,0xa7,0xf8,0x8c,0xc8,0x9d,0x8c,0xbe,0x0d,0x5b,0xc7,0xfa,0xf1,0xe4,0xaf,0xc8,0x68,0x64, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x09,0xe6,0x0e,0x68,0xb9,0x0d,0x0b,0x5e,0x6c,0x5d,0xdd,0xd0,0xcb,0x69,0x4d,0x87,0x99, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3d,0x7f,0x48,0x7c,0x07,0xbf,0xc5,0xf3,0x08,0x46,0x93,0x8a,0x3d,0xce,0xf6,0x96,0x44,0x47,0x07,0xcf,0x96,0x77,0x25,0x4a,0x92,0xb0,0x6c,0x63,0xab,0x86,0x7d,0x22, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6c,0x76,0x48,0xfc,0x0f,0xbf,0x8a,0x06,0xad,0xb8,0xb8,0x39,0xf9,0x7b,0x4f,0xf7,0xa8,0x00,0xf1,0x1b,0x1e,0x37,0xc5,0x93,0xb2,0x61,0x39,0x45,0x99,0x79,0x2b,0xa4, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x1c,0x9c,0x5d,0x79,0x0d,0xc0,0x9c,0xdd,0x3d,0xfa,0xbb,0x62,0xcd,0xf4,0x53,0xe6,0x97,0x47,0xa7,0xe3,0xd7,0xaa,0x1a,0x71,0x41,0x89,0xef,0x53,0x17,0x1a,0x99, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x29,0x79,0x8c,0x5c,0x45,0xbd,0xf5,0x8b,0x4a,0x7b,0x2f,0xdc,0x2c,0x46,0xab,0x4a,0xf1,0x21,0x8c,0x7e,0xeb,0x9f,0x0f,0x27,0xa8,0x8f,0x12,0x67,0x67,0x4d,0xe3,0xb0, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x0b,0x70,0xf2,0x2c,0xa2,0xbb,0x3c,0xef,0xad,0xca,0x1a,0x57,0x11,0xfa,0x3a,0x59,0xf4,0x69,0x53,0x85,0xeb,0x5a,0xed,0xf3,0x49,0x5d,0x0b,0x6d,0x00,0xf8,0xfd,0x85, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x22,0x52,0xd6,0x85,0xe8,0x31,0xb6,0xcf,0x09,0x5e,0x4f,0x05,0x35,0xee,0xaf,0x0d,0xdd,0x3b,0xfa,0x91,0xc2,0x10,0xc9,0xd9,0xdc,0x17,0x22,0x47,0x02,0xea,0xf8,0x8f, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x75,0x13,0x5a,0xbd,0x7c,0x42,0x5b,0x60,0x37,0x1a,0x47,0x7f,0x09,0xce,0x0f,0x27,0x4f,0x64,0xa8,0xc6,0xb0,0x61,0xa0,0x7b,0x5d,0x63,0xe9,0x3c,0x65,0x04,0x6c,0x53, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x88,0x83,0x77,0xac,0x6c,0x71,0xac,0x9d,0xec,0x3f,0xdb,0x9b,0x56,0xc9,0xfe,0xaf,0x0c,0xfa,0xca,0x9f,0x82,0x7f,0xc5,0xeb,0x65,0xfc,0x3e,0xac,0x81,0x12,0x10, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x30,0xbb,0xb7,0x94,0xdb,0x58,0x83,0x63,0xb4,0x06,0x79,0xf6,0xc1,0x82,0xa5,0x0d,0x3c,0xe9,0x67,0x9a,0xcd,0xd3,0xff,0xbe,0x36,0xd7,0x81,0x3d,0xac,0xbd,0xc8,0x18, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2c,0x37,0xfd,0x99,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc7,0xce,0xe7,0x45,0x11,0x0c,0xb4,0x5a,0xb5,0x58,0xed,0x7c,0x90,0xc1,0x5a,0x2f, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x7f,0xd9,0x95,0x62,0x2c,0x4f,0xb7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x88,0x3f,0xfa,0xb5,0xb3,0x26,0x52,0xcc,0xdc,0xaa,0x29,0x0f,0xcc,0xb9,0x7d, + 0x30,0x43,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x1f,0x4c,0xd5,0x3b,0xa7,0x60,0x8f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9e,0x5c,0xf1,0x43,0xe2,0x53,0x96,0x26,0x19,0x0a,0x3a,0xb0,0x9c,0xce,0x47, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x92,0x8a,0x8f,0x1c,0x7a,0xc7,0xbe,0xc1,0x80,0x8b,0x9f,0x61,0xc0,0x1e,0xc3,0x27, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x44,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x03,0xb8,0x78,0x53,0xfd,0x3b,0x7d,0x3f,0x8e,0x17,0x51,0x25,0xb4,0x38,0x2f,0x25,0xed, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x27,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x05,0x56,0x02,0x98,0xd1,0xf2,0xf0,0x8d,0xc4,0x19,0xac,0x27,0x3a,0x5b,0x54,0xd9, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x48,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x31,0xc8,0x3a,0xe8,0x2e,0xbe,0x08,0x98,0x77,0x6b,0x4c,0x69,0xd1,0x1f,0x88,0xde, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x06,0xdd,0x3a,0x19,0xb8,0xd5,0xfb,0x87,0x52,0x35,0x96,0x3c,0x59,0x3b,0xd2,0xd3, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x15, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x18,0x5d,0xdb,0xca,0x6d,0xac,0x41,0xb1,0xda,0x03,0x3c,0xfb,0x60,0xc1,0x52,0x86,0x9e,0x74,0xb3,0xcd,0x66,0xe9,0xff,0xdf,0x1b,0x6b,0xc0,0x9e,0xd6,0x5e,0xe4,0x0c, + 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9, + 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0,0x02,0x20,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x32,0xf2,0x22,0xf8,0xfa,0xef,0xdb,0x53,0x3f,0x26,0x5d,0x46,0x1c,0x29,0xa4,0x73,0x73, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b, + 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x45,0x02,0x21,0x00,0xf8,0x0a,0xe4,0xf9,0x6c,0xdb,0xc9,0xd8,0x53,0xf8,0x3d,0x47,0xaa,0xe2,0x25,0xbf,0x40,0x7d,0x51,0xc5,0x6b,0x77,0x76,0xcd,0x67,0xd0,0xdc,0x19,0x5d,0x99,0xa9,0xdc,0x02,0x20,0x4c,0xfc,0x1d,0x94,0x1e,0x08,0xcb,0x9a,0xce,0xad,0xde,0x0f,0x4c,0xce,0xad,0x76,0xb3,0x0d,0x33,0x2f,0xc4,0x42,0x11,0x5d,0x50,0xe6,0x73,0xe2,0x86,0x86,0xb7,0x0b, + 0x30,0x44,0x02,0x20,0x10,0x9c,0xd8,0xae,0x03,0x74,0x35,0x89,0x84,0xa8,0x24,0x9c,0x0a,0x84,0x36,0x28,0xf2,0x83,0x5f,0xfa,0xd1,0xdf,0x1a,0x9a,0x69,0xaa,0x2f,0xe7,0x23,0x55,0x54,0x5c,0x02,0x20,0x53,0x90,0xff,0x25,0x0a,0xc4,0x27,0x4e,0x1c,0xb2,0x5c,0xd6,0xca,0x64,0x91,0xf6,0xb9,0x12,0x81,0xe3,0x2f,0x5b,0x26,0x4d,0x87,0x97,0x7a,0xed,0x4a,0x94,0xe7,0x7b, + 0x30,0x45,0x02,0x21,0x00,0xd0,0x35,0xee,0x1f,0x17,0xfd,0xb0,0xb2,0x68,0x1b,0x16,0x3e,0x33,0xc3,0x59,0x93,0x26,0x59,0x99,0x0a,0xf7,0x7d,0xca,0x63,0x20,0x12,0xb3,0x0b,0x27,0xa0,0x57,0xb3,0x02,0x20,0x19,0x39,0xd9,0xf3,0xb2,0x85,0x8b,0xc1,0x3e,0x34,0x74,0xcb,0x50,0xe6,0xa8,0x2b,0xe4,0x4f,0xaa,0x71,0x94,0x0f,0x87,0x6c,0x1c,0xba,0x4c,0x3e,0x98,0x92,0x02,0xb6, + 0x30,0x44,0x02,0x20,0x4f,0x05,0x3f,0x56,0x3a,0xd3,0x4b,0x74,0xfd,0x8c,0x99,0x34,0xce,0x59,0xe7,0x9c,0x2e,0xb8,0xe6,0xec,0xa0,0xfe,0xf5,0xb3,0x23,0xca,0x67,0xd5,0xac,0x7e,0xd2,0x38,0x02,0x20,0x4d,0x4b,0x05,0xda,0xa0,0x71,0x9e,0x77,0x3d,0x86,0x17,0xdc,0xe5,0x63,0x1c,0x5f,0xd6,0xf5,0x9c,0x9b,0xdc,0x74,0x8e,0x4b,0x55,0xc9,0x70,0x04,0x0a,0xf0,0x1b,0xe5, + 0x30,0x44,0x02,0x20,0x6d,0x6a,0x4f,0x55,0x6c,0xcc,0xe1,0x54,0xe7,0xfb,0x9f,0x19,0xe7,0x6c,0x3d,0xec,0xa1,0x3d,0x59,0xcc,0x2a,0xeb,0x4e,0xca,0xd9,0x68,0xaa,0xb2,0xde,0xd4,0x59,0x65,0x02,0x20,0x53,0xb9,0xfa,0x74,0x80,0x3e,0xde,0x0f,0xc4,0x44,0x1b,0xf6,0x83,0xd5,0x6c,0x56,0x4d,0x3e,0x27,0x4e,0x09,0xcc,0xf4,0x73,0x90,0xba,0xdd,0x14,0x71,0xc0,0x5f,0xb7, + 0x30,0x44,0x02,0x21,0x00,0xaa,0xd5,0x03,0xde,0x9b,0x9f,0xd6,0x6b,0x94,0x8e,0x9a,0xcf,0x59,0x6f,0x0a,0x0e,0x65,0xe7,0x00,0xb2,0x8b,0x26,0xec,0x56,0xe6,0xe4,0x5e,0x84,0x64,0x89,0xb3,0xc4,0x02,0x1f,0x0d,0xdc,0x3a,0x2f,0x89,0xab,0xb8,0x17,0xbb,0x85,0xc0,0x62,0xce,0x02,0xf8,0x23,0xc6,0x3f,0xc2,0x6b,0x26,0x9e,0x0b,0xc9,0xb8,0x4d,0x81,0xa5,0xaa,0x12,0x3d, + 0x30,0x45,0x02,0x21,0x00,0x91,0x82,0xce,0xbd,0x3b,0xb8,0xab,0x57,0x2e,0x16,0x71,0x74,0x39,0x72,0x09,0xef,0x4b,0x1d,0x43,0x9a,0xf3,0xb2,0x00,0xcd,0xf0,0x03,0x62,0x00,0x89,0xe4,0x32,0x25,0x02,0x20,0x54,0x47,0x7c,0x98,0x2e,0xa0,0x19,0xd2,0xe1,0x00,0x04,0x97,0xfc,0x25,0xfc,0xee,0x1b,0xcc,0xae,0x55,0xf2,0xac,0x27,0x53,0x0a,0xe5,0x3b,0x29,0xc4,0xb3,0x56,0xa4, + 0x30,0x44,0x02,0x20,0x38,0x54,0xa3,0x99,0x8a,0xeb,0xdf,0x2d,0xbc,0x28,0xad,0xac,0x41,0x81,0x46,0x2c,0xca,0xc7,0x87,0x39,0x07,0xab,0x7f,0x21,0x2c,0x42,0xdb,0x0e,0x69,0xb5,0x6e,0xd8,0x02,0x20,0x3e,0xd3,0xf6,0xb8,0xa3,0x88,0xd0,0x2f,0x3e,0x4d,0xf9,0xf2,0xae,0x9c,0x1b,0xd2,0xc3,0x91,0x6a,0x68,0x64,0x60,0xdf,0xfc,0xd4,0x29,0x09,0xcd,0x7f,0x82,0x05,0x8e, + 0x30,0x45,0x02,0x21,0x00,0xe9,0x4d,0xbd,0xc3,0x87,0x95,0xfe,0x5c,0x90,0x4d,0x8f,0x16,0xd9,0x69,0xd3,0xb5,0x87,0xf0,0xa2,0x5d,0x2d,0xe9,0x0b,0x6d,0x8c,0x5c,0x53,0xff,0x88,0x7e,0x36,0x07,0x02,0x20,0x7a,0x94,0x73,0x69,0xc1,0x64,0x97,0x25,0x21,0xbb,0x8a,0xf4,0x06,0x81,0x3b,0x2d,0x9f,0x94,0xd2,0xae,0xaa,0x53,0xd4,0xc2,0x15,0xaa,0xa0,0xa2,0x57,0x8a,0x2c,0x5d, + 0x30,0x44,0x02,0x20,0x49,0xfc,0x10,0x2a,0x08,0xca,0x47,0xb6,0x0e,0x08,0x58,0xcd,0x02,0x84,0xd2,0x2c,0xdd,0xd7,0x23,0x3f,0x94,0xaa,0xff,0xbb,0x2d,0xb1,0xdd,0x2c,0xf0,0x84,0x25,0xe1,0x02,0x20,0x5b,0x16,0xfc,0xa5,0xa1,0x2c,0xdb,0x39,0x70,0x16,0x97,0xad,0x8e,0x39,0xff,0xd6,0xbd,0xec,0x00,0x24,0x29,0x8a,0xfa,0xa2,0x32,0x6a,0xea,0x09,0x20,0x0b,0x14,0xd6, + 0x30,0x44,0x02,0x20,0x41,0xef,0xa7,0xd3,0xf0,0x5a,0x00,0x10,0x67,0x5f,0xcb,0x91,0x8a,0x45,0xc6,0x93,0xda,0x4b,0x34,0x8d,0xf2,0x1a,0x59,0xd6,0xf9,0xcd,0x73,0xe0,0xd8,0x31,0xd6,0x7a,0x02,0x20,0x44,0x54,0xad,0xa6,0x93,0xe5,0xe2,0x6b,0x7b,0xd6,0x93,0x23,0x6d,0x34,0x0f,0x80,0x54,0x5c,0x83,0x45,0x77,0xb6,0xf7,0x3d,0x37,0x8c,0x7b,0xcc,0x53,0x42,0x44,0xda, + 0x30,0x45,0x02,0x21,0x00,0xb6,0x15,0x69,0x8c,0x35,0x8b,0x35,0x92,0x0d,0xd8,0x83,0xec,0xa6,0x25,0xa6,0xc5,0xf7,0x56,0x39,0x70,0xcd,0xfc,0x37,0x8f,0x8f,0xe0,0xce,0xe1,0x70,0x92,0x14,0x4c,0x02,0x20,0x25,0xf4,0x7b,0x32,0x6b,0x5b,0xe1,0xfb,0x61,0x0b,0x88,0x51,0x53,0xea,0x84,0xd4,0x1e,0xb4,0x71,0x6b,0xe6,0x6a,0x99,0x4e,0x87,0x79,0x98,0x9d,0xf1,0xc8,0x63,0xd4, + 0x30,0x45,0x02,0x21,0x00,0x87,0xcf,0x8c,0x0e,0xb8,0x2d,0x44,0xf6,0x9c,0x60,0xa2,0xff,0x54,0x57,0xd3,0xaa,0xa3,0x22,0xe7,0xec,0x61,0xae,0x5a,0xec,0xfd,0x67,0x8a,0xe1,0xc1,0x93,0x2b,0x0e,0x02,0x20,0x3a,0xdd,0x3b,0x11,0x58,0x15,0x04,0x7d,0x6e,0xb3,0x40,0xa3,0xe0,0x08,0x98,0x9e,0xaa,0x0f,0x87,0x08,0xd1,0x79,0x48,0x14,0x72,0x90,0x94,0xd0,0x8d,0x24,0x60,0xd3, + 0x30,0x44,0x02,0x20,0x62,0xf4,0x8e,0xf7,0x1a,0xce,0x27,0xbf,0x5a,0x01,0x83,0x4d,0xe1,0xf7,0xe3,0xf9,0x48,0xb9,0xdc,0xe1,0xca,0x1e,0x91,0x1d,0x5e,0x13,0xd3,0xb1,0x04,0x47,0x1d,0x82,0x02,0x20,0x5e,0xa8,0xf3,0x3f,0x0c,0x77,0x89,0x72,0xc4,0x58,0x20,0x80,0xde,0xda,0x9b,0x34,0x18,0x57,0xdd,0x64,0x51,0x4f,0x08,0x49,0xa0,0x5f,0x69,0x64,0xc2,0xe3,0x40,0x22, + 0x30,0x45,0x02,0x21,0x00,0xf6,0xb0,0xe2,0xf6,0xfe,0x02,0x0c,0xf7,0xc0,0xc2,0x01,0x37,0x43,0x43,0x44,0xed,0x7a,0xdd,0x6c,0x4b,0xe5,0x18,0x61,0xe2,0xd1,0x4c,0xbd,0xa4,0x72,0xa6,0xff,0xb4,0x02,0x20,0x64,0x16,0xc8,0xdd,0x3e,0x5c,0x52,0x82,0xb3,0x06,0xe8,0xdc,0x8f,0xf3,0x4a,0xb6,0x4c,0xc9,0x95,0x49,0x23,0x2d,0x67,0x8d,0x71,0x44,0x02,0xeb,0x6c,0xa7,0xaa,0x0f, + 0x30,0x45,0x02,0x21,0x00,0xdb,0x09,0xd8,0x46,0x0f,0x05,0xef,0xf2,0x3b,0xc7,0xe4,0x36,0xb6,0x7d,0xa5,0x63,0xfa,0x4b,0x4e,0xdb,0x58,0xac,0x24,0xce,0x20,0x1f,0xa8,0xa3,0x58,0x12,0x50,0x57,0x02,0x20,0x46,0xda,0x11,0x67,0x54,0x60,0x29,0x40,0xc8,0x99,0x9c,0x8d,0x66,0x5f,0x78,0x6c,0x50,0xf5,0x77,0x2c,0x0a,0x3c,0xdb,0xda,0x07,0x5e,0x77,0xea,0xbc,0x64,0xdf,0x16, + 0x30,0x44,0x02,0x20,0x59,0x2c,0x41,0xe1,0x65,0x17,0xf1,0x2f,0xca,0xbd,0x98,0x26,0x76,0x74,0xf9,0x74,0xb5,0x88,0xe9,0xf3,0x5d,0x35,0x40,0x6c,0x1a,0x7b,0xb2,0xed,0x1d,0x19,0xb7,0xb8,0x02,0x20,0x3e,0x65,0xa0,0x6b,0xd9,0xf8,0x3c,0xaa,0xeb,0x7b,0x00,0xf2,0x36,0x8d,0x7e,0x0d,0xec,0xe6,0xb1,0x22,0x21,0x26,0x9a,0x9b,0x5b,0x76,0x51,0x98,0xf8,0x40,0xa3,0xa1, + 0x30,0x45,0x02,0x21,0x00,0xbe,0x0d,0x70,0x88,0x7d,0x5e,0x40,0x82,0x1a,0x61,0xb6,0x80,0x47,0xde,0x4e,0xa0,0x3d,0xeb,0xfd,0xf5,0x1c,0xdf,0x4d,0x4b,0x19,0x55,0x58,0xb9,0x59,0xa0,0x32,0xb2,0x02,0x20,0x7d,0x99,0x4b,0x2d,0x8f,0x1d,0xbb,0xeb,0x13,0x53,0x4e,0xb3,0xf6,0xe5,0xdc,0xcd,0x85,0xf5,0xc4,0x13,0x3c,0x27,0xd9,0xe6,0x42,0x71,0xb1,0x82,0x6c,0xe1,0xf6,0x7d, + 0x30,0x45,0x02,0x21,0x00,0xfa,0xe9,0x2d,0xfc,0xb2,0xee,0x39,0x2d,0x27,0x0a,0xf3,0xa5,0x73,0x9f,0xaa,0x26,0xd4,0xf9,0x7b,0xfd,0x39,0xed,0x3c,0xbe,0xe4,0xd2,0x9e,0x26,0xaf,0x3b,0x20,0x6a,0x02,0x20,0x6c,0x9b,0xa3,0x7f,0x9f,0xaa,0x6a,0x1f,0xd3,0xf6,0x5f,0x23,0xb4,0xe8,0x53,0xd4,0x69,0x2a,0x72,0x74,0x24,0x0a,0x12,0xdb,0x7b,0xa3,0x88,0x48,0x30,0x63,0x0d,0x16, + 0x30,0x44,0x02,0x20,0x17,0x6a,0x25,0x57,0x56,0x6f,0xfa,0x51,0x8b,0x11,0x22,0x66,0x94,0xeb,0x98,0x02,0xed,0x20,0x98,0xbf,0xe2,0x78,0xe5,0x57,0x0f,0xe1,0xd5,0xd7,0xaf,0x18,0xa9,0x43,0x02,0x20,0x12,0x91,0xdf,0x6a,0x0e,0xd5,0xfc,0x0d,0x15,0x09,0x8e,0x70,0xbc,0xf1,0x3a,0x00,0x92,0x84,0xdf,0xd0,0x68,0x9d,0x3b,0xb4,0xbe,0x6c,0xee,0xb9,0xbe,0x14,0x87,0xc4, + 0x30,0x44,0x02,0x20,0x60,0xbe,0x20,0xc3,0xdb,0xc1,0x62,0xdd,0x34,0xd2,0x67,0x80,0x62,0x1c,0x10,0x4b,0xbe,0x5d,0xac,0xe6,0x30,0x17,0x1b,0x2d,0xae,0xf0,0xd8,0x26,0x40,0x9e,0xe5,0xc2,0x02,0x20,0x42,0x7f,0x7e,0x4d,0x88,0x9d,0x54,0x91,0x70,0xbd,0xa6,0xa9,0x40,0x9f,0xb1,0xcb,0x8b,0x0e,0x76,0x3d,0x13,0xee,0xa7,0xbd,0x97,0xf6,0x4c,0xf4,0x1d,0xc6,0xe4,0x97, + 0x30,0x45,0x02,0x21,0x00,0xed,0xf0,0x3c,0xf6,0x3f,0x65,0x88,0x83,0x28,0x9a,0x1a,0x59,0x3d,0x10,0x07,0x89,0x5b,0x9f,0x23,0x6d,0x27,0xc9,0xc1,0xf1,0x31,0x30,0x89,0xaa,0xed,0x6b,0x16,0xae,0x02,0x20,0x1a,0x4d,0xd6,0xfc,0x08,0x14,0xdc,0x52,0x3d,0x1f,0xef,0xa8,0x1c,0x64,0xfb,0xf5,0xe6,0x18,0xe6,0x51,0xe7,0x09,0x6f,0xcc,0xad,0xbb,0x94,0xcd,0x48,0xe5,0xe0,0xcd}; + +static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = { + /* tcId: 1. Signature malleability */ + {0, 0, 6, 0, 72, 0 }, + /* tcId: 2. valid */ + {0, 0, 6, 72, 71, 1 }, + /* tcId: 3. length of sequence [r, s] uses long form encoding */ + {0, 0, 6, 143, 72, 0 }, + /* tcId: 4. length of sequence [r, s] contains a leading 0 */ + {0, 0, 6, 215, 73, 0 }, + /* tcId: 5. length of sequence [r, s] uses 70 instead of 69 */ + {0, 0, 6, 288, 71, 0 }, + /* tcId: 6. length of sequence [r, s] uses 68 instead of 69 */ + {0, 0, 6, 359, 71, 0 }, + /* tcId: 7. uint32 overflow in length of sequence [r, s] */ + {0, 0, 6, 430, 76, 0 }, + /* tcId: 8. uint64 overflow in length of sequence [r, s] */ + {0, 0, 6, 506, 80, 0 }, + /* tcId: 9. length of sequence [r, s] = 2**31 - 1 */ + {0, 0, 6, 586, 75, 0 }, + /* tcId: 10. length of sequence [r, s] = 2**31 */ + {0, 0, 6, 661, 75, 0 }, + /* tcId: 11. length of sequence [r, s] = 2**32 - 1 */ + {0, 0, 6, 736, 75, 0 }, + /* tcId: 12. length of sequence [r, s] = 2**40 - 1 */ + {0, 0, 6, 811, 76, 0 }, + /* tcId: 13. length of sequence [r, s] = 2**64 - 1 */ + {0, 0, 6, 887, 79, 0 }, + /* tcId: 14. incorrect length of sequence [r, s] */ + {0, 0, 6, 966, 71, 0 }, + /* tcId: 15. replaced sequence [r, s] by an indefinite length tag without termination */ + {0, 0, 6, 1037, 71, 0 }, + /* tcId: 16. removing sequence [r, s] */ + {0, 0, 6, 1108, 0, 0 }, + /* tcId: 17. lonely sequence tag */ + {0, 0, 6, 1108, 1, 0 }, + /* tcId: 18. appending 0's to sequence [r, s] */ + {0, 0, 6, 1109, 73, 0 }, + /* tcId: 19. prepending 0's to sequence [r, s] */ + {0, 0, 6, 1182, 73, 0 }, + /* tcId: 20. appending unused 0's to sequence [r, s] */ + {0, 0, 6, 1255, 73, 0 }, + /* tcId: 21. appending null value to sequence [r, s] */ + {0, 0, 6, 1328, 73, 0 }, + /* tcId: 22. prepending garbage to sequence [r, s] */ + {0, 0, 6, 1401, 76, 0 }, + /* tcId: 23. prepending garbage to sequence [r, s] */ + {0, 0, 6, 1477, 75, 0 }, + /* tcId: 24. appending garbage to sequence [r, s] */ + {0, 0, 6, 1552, 79, 0 }, + /* tcId: 25. including undefined tags */ + {0, 0, 6, 1631, 79, 0 }, + /* tcId: 26. including undefined tags */ + {0, 0, 6, 1710, 79, 0 }, + /* tcId: 27. including undefined tags */ + {0, 0, 6, 1789, 79, 0 }, + /* tcId: 28. truncated length of sequence [r, s] */ + {0, 0, 6, 1868, 2, 0 }, + /* tcId: 29. including undefined tags to sequence [r, s] */ + {0, 0, 6, 1870, 77, 0 }, + /* tcId: 30. using composition with indefinite length for sequence [r, s] */ + {0, 0, 6, 1947, 75, 0 }, + /* tcId: 31. using composition with wrong tag for sequence [r, s] */ + {0, 0, 6, 2022, 75, 0 }, + /* tcId: 32. Replacing sequence [r, s] with NULL */ + {0, 0, 6, 2097, 2, 0 }, + /* tcId: 33. changing tag value of sequence [r, s] */ + {0, 0, 6, 2099, 71, 0 }, + /* tcId: 34. changing tag value of sequence [r, s] */ + {0, 0, 6, 2170, 71, 0 }, + /* tcId: 35. changing tag value of sequence [r, s] */ + {0, 0, 6, 2241, 71, 0 }, + /* tcId: 36. changing tag value of sequence [r, s] */ + {0, 0, 6, 2312, 71, 0 }, + /* tcId: 37. changing tag value of sequence [r, s] */ + {0, 0, 6, 2383, 71, 0 }, + /* tcId: 38. dropping value of sequence [r, s] */ + {0, 0, 6, 2454, 2, 0 }, + /* tcId: 39. using composition for sequence [r, s] */ + {0, 0, 6, 2456, 75, 0 }, + /* tcId: 40. truncated sequence [r, s] */ + {0, 0, 6, 2531, 70, 0 }, + /* tcId: 41. truncated sequence [r, s] */ + {0, 0, 6, 2601, 70, 0 }, + /* tcId: 42. sequence [r, s] of size 4166 to check for overflows */ + {0, 0, 6, 2671, 4170, 0 }, + /* tcId: 43. indefinite length */ + {0, 0, 6, 6841, 73, 0 }, + /* tcId: 44. indefinite length with truncated delimiter */ + {0, 0, 6, 6914, 72, 0 }, + /* tcId: 45. indefinite length with additional element */ + {0, 0, 6, 6986, 75, 0 }, + /* tcId: 46. indefinite length with truncated element */ + {0, 0, 6, 7061, 77, 0 }, + /* tcId: 47. indefinite length with garbage */ + {0, 0, 6, 7138, 77, 0 }, + /* tcId: 48. indefinite length with nonempty EOC */ + {0, 0, 6, 7215, 75, 0 }, + /* tcId: 49. prepend empty sequence */ + {0, 0, 6, 7290, 73, 0 }, + /* tcId: 50. append empty sequence */ + {0, 0, 6, 7363, 73, 0 }, + /* tcId: 51. append zero */ + {0, 0, 6, 7436, 74, 0 }, + /* tcId: 52. append garbage with high tag number */ + {0, 0, 6, 7510, 74, 0 }, + /* tcId: 53. append null with explicit tag */ + {0, 0, 6, 7584, 75, 0 }, + /* tcId: 54. append null with implicit tag */ + {0, 0, 6, 7659, 73, 0 }, + /* tcId: 55. sequence of sequence */ + {0, 0, 6, 7732, 73, 0 }, + /* tcId: 56. truncated sequence: removed last 1 elements */ + {0, 0, 6, 7805, 37, 0 }, + /* tcId: 57. repeating element in sequence */ + {0, 0, 6, 7842, 105, 0 }, + /* tcId: 58. flipped bit 0 in r */ + {0, 0, 6, 7947, 69, 0 }, + /* tcId: 59. flipped bit 32 in r */ + {0, 0, 6, 8016, 69, 0 }, + /* tcId: 60. flipped bit 48 in r */ + {0, 0, 6, 8085, 69, 0 }, + /* tcId: 61. flipped bit 64 in r */ + {0, 0, 6, 8154, 69, 0 }, + /* tcId: 62. length of r uses long form encoding */ + {0, 0, 6, 8223, 72, 0 }, + /* tcId: 63. length of r contains a leading 0 */ + {0, 0, 6, 8295, 73, 0 }, + /* tcId: 64. length of r uses 34 instead of 33 */ + {0, 0, 6, 8368, 71, 0 }, + /* tcId: 65. length of r uses 32 instead of 33 */ + {0, 0, 6, 8439, 71, 0 }, + /* tcId: 66. uint32 overflow in length of r */ + {0, 0, 6, 8510, 76, 0 }, + /* tcId: 67. uint64 overflow in length of r */ + {0, 0, 6, 8586, 80, 0 }, + /* tcId: 68. length of r = 2**31 - 1 */ + {0, 0, 6, 8666, 75, 0 }, + /* tcId: 69. length of r = 2**31 */ + {0, 0, 6, 8741, 75, 0 }, + /* tcId: 70. length of r = 2**32 - 1 */ + {0, 0, 6, 8816, 75, 0 }, + /* tcId: 71. length of r = 2**40 - 1 */ + {0, 0, 6, 8891, 76, 0 }, + /* tcId: 72. length of r = 2**64 - 1 */ + {0, 0, 6, 8967, 79, 0 }, + /* tcId: 73. incorrect length of r */ + {0, 0, 6, 9046, 71, 0 }, + /* tcId: 74. replaced r by an indefinite length tag without termination */ + {0, 0, 6, 9117, 71, 0 }, + /* tcId: 75. removing r */ + {0, 0, 6, 9188, 36, 0 }, + /* tcId: 76. lonely integer tag */ + {0, 0, 6, 9224, 37, 0 }, + /* tcId: 77. lonely integer tag */ + {0, 0, 6, 9261, 38, 0 }, + /* tcId: 78. appending 0's to r */ + {0, 0, 6, 9299, 73, 0 }, + /* tcId: 79. prepending 0's to r */ + {0, 0, 6, 9372, 73, 0 }, + /* tcId: 80. appending unused 0's to r */ + {0, 0, 6, 9445, 73, 0 }, + /* tcId: 81. appending null value to r */ + {0, 0, 6, 9518, 73, 0 }, + /* tcId: 82. prepending garbage to r */ + {0, 0, 6, 9591, 76, 0 }, + /* tcId: 83. prepending garbage to r */ + {0, 0, 6, 9667, 75, 0 }, + /* tcId: 84. appending garbage to r */ + {0, 0, 6, 9742, 79, 0 }, + /* tcId: 85. truncated length of r */ + {0, 0, 6, 9821, 38, 0 }, + /* tcId: 86. including undefined tags to r */ + {0, 0, 6, 9859, 77, 0 }, + /* tcId: 87. using composition with indefinite length for r */ + {0, 0, 6, 9936, 75, 0 }, + /* tcId: 88. using composition with wrong tag for r */ + {0, 0, 6, 10011, 75, 0 }, + /* tcId: 89. Replacing r with NULL */ + {0, 0, 6, 10086, 38, 0 }, + /* tcId: 90. changing tag value of r */ + {0, 0, 6, 10124, 71, 0 }, + /* tcId: 91. changing tag value of r */ + {0, 0, 6, 10195, 71, 0 }, + /* tcId: 92. changing tag value of r */ + {0, 0, 6, 10266, 71, 0 }, + /* tcId: 93. changing tag value of r */ + {0, 0, 6, 10337, 71, 0 }, + /* tcId: 94. changing tag value of r */ + {0, 0, 6, 10408, 71, 0 }, + /* tcId: 95. dropping value of r */ + {0, 0, 6, 10479, 38, 0 }, + /* tcId: 96. using composition for r */ + {0, 0, 6, 10517, 75, 0 }, + /* tcId: 97. modifying first byte of r */ + {0, 0, 6, 10592, 71, 0 }, + /* tcId: 98. modifying last byte of r */ + {0, 0, 6, 10663, 71, 0 }, + /* tcId: 99. truncated r */ + {0, 0, 6, 10734, 70, 0 }, + /* tcId: 100. truncated r */ + {0, 0, 6, 10804, 70, 0 }, + /* tcId: 101. r of size 4130 to check for overflows */ + {0, 0, 6, 10874, 4172, 0 }, + /* tcId: 102. leading ff in r */ + {0, 0, 6, 15046, 72, 0 }, + /* tcId: 103. replaced r by infinity */ + {0, 0, 6, 15118, 39, 0 }, + /* tcId: 104. replacing r with zero */ + {0, 0, 6, 15157, 39, 0 }, + /* tcId: 105. flipped bit 0 in s */ + {0, 0, 6, 15196, 69, 0 }, + /* tcId: 106. flipped bit 32 in s */ + {0, 0, 6, 15265, 69, 0 }, + /* tcId: 107. flipped bit 48 in s */ + {0, 0, 6, 15334, 69, 0 }, + /* tcId: 108. flipped bit 64 in s */ + {0, 0, 6, 15403, 69, 0 }, + /* tcId: 109. length of s uses long form encoding */ + {0, 0, 6, 15472, 72, 0 }, + /* tcId: 110. length of s contains a leading 0 */ + {0, 0, 6, 15544, 73, 0 }, + /* tcId: 111. length of s uses 33 instead of 32 */ + {0, 0, 6, 15617, 71, 0 }, + /* tcId: 112. length of s uses 31 instead of 32 */ + {0, 0, 6, 15688, 71, 0 }, + /* tcId: 113. uint32 overflow in length of s */ + {0, 0, 6, 15759, 76, 0 }, + /* tcId: 114. uint64 overflow in length of s */ + {0, 0, 6, 15835, 80, 0 }, + /* tcId: 115. length of s = 2**31 - 1 */ + {0, 0, 6, 15915, 75, 0 }, + /* tcId: 116. length of s = 2**31 */ + {0, 0, 6, 15990, 75, 0 }, + /* tcId: 117. length of s = 2**32 - 1 */ + {0, 0, 6, 16065, 75, 0 }, + /* tcId: 118. length of s = 2**40 - 1 */ + {0, 0, 6, 16140, 76, 0 }, + /* tcId: 119. length of s = 2**64 - 1 */ + {0, 0, 6, 16216, 79, 0 }, + /* tcId: 120. incorrect length of s */ + {0, 0, 6, 16295, 71, 0 }, + /* tcId: 121. replaced s by an indefinite length tag without termination */ + {0, 0, 6, 16366, 71, 0 }, + /* tcId: 122. appending 0's to s */ + {0, 0, 6, 16437, 73, 0 }, + /* tcId: 123. prepending 0's to s */ + {0, 0, 6, 16510, 73, 0 }, + /* tcId: 124. appending null value to s */ + {0, 0, 6, 16583, 73, 0 }, + /* tcId: 125. prepending garbage to s */ + {0, 0, 6, 16656, 76, 0 }, + /* tcId: 126. prepending garbage to s */ + {0, 0, 6, 16732, 75, 0 }, + /* tcId: 127. appending garbage to s */ + {0, 0, 6, 16807, 79, 0 }, + /* tcId: 128. truncated length of s */ + {0, 0, 6, 16886, 39, 0 }, + /* tcId: 129. including undefined tags to s */ + {0, 0, 6, 16925, 77, 0 }, + /* tcId: 130. using composition with indefinite length for s */ + {0, 0, 6, 17002, 75, 0 }, + /* tcId: 131. using composition with wrong tag for s */ + {0, 0, 6, 17077, 75, 0 }, + /* tcId: 132. Replacing s with NULL */ + {0, 0, 6, 17152, 39, 0 }, + /* tcId: 133. changing tag value of s */ + {0, 0, 6, 17191, 71, 0 }, + /* tcId: 134. changing tag value of s */ + {0, 0, 6, 17262, 71, 0 }, + /* tcId: 135. changing tag value of s */ + {0, 0, 6, 17333, 71, 0 }, + /* tcId: 136. changing tag value of s */ + {0, 0, 6, 17404, 71, 0 }, + /* tcId: 137. changing tag value of s */ + {0, 0, 6, 17475, 71, 0 }, + /* tcId: 138. dropping value of s */ + {0, 0, 6, 17546, 39, 0 }, + /* tcId: 139. using composition for s */ + {0, 0, 6, 17585, 75, 0 }, + /* tcId: 140. modifying first byte of s */ + {0, 0, 6, 17660, 71, 0 }, + /* tcId: 141. modifying last byte of s */ + {0, 0, 6, 17731, 71, 0 }, + /* tcId: 142. truncated s */ + {0, 0, 6, 17802, 70, 0 }, + /* tcId: 143. truncated s */ + {0, 0, 6, 17872, 70, 0 }, + /* tcId: 144. s of size 4129 to check for overflows */ + {0, 0, 6, 17942, 4172, 0 }, + /* tcId: 145. leading ff in s */ + {0, 0, 6, 22114, 72, 0 }, + /* tcId: 146. replaced s by infinity */ + {0, 0, 6, 22186, 40, 0 }, + /* tcId: 147. replacing s with zero */ + {0, 0, 6, 22226, 40, 0 }, + /* tcId: 148. replaced r by r + n */ + {0, 0, 6, 22266, 71, 0 }, + /* tcId: 149. replaced r by r - n */ + {0, 0, 6, 22337, 70, 0 }, + /* tcId: 150. replaced r by r + 256 * n */ + {0, 0, 6, 22407, 72, 0 }, + /* tcId: 151. replaced r by -r */ + {0, 0, 6, 22479, 71, 0 }, + /* tcId: 152. replaced r by n - r */ + {0, 0, 6, 22550, 70, 0 }, + /* tcId: 153. replaced r by -n - r */ + {0, 0, 6, 22620, 71, 0 }, + /* tcId: 154. replaced r by r + 2**256 */ + {0, 0, 6, 22691, 71, 0 }, + /* tcId: 155. replaced r by r + 2**320 */ + {0, 0, 6, 22762, 79, 0 }, + /* tcId: 156. replaced s by s + n */ + {0, 0, 6, 22841, 71, 0 }, + /* tcId: 157. replaced s by s - n */ + {0, 0, 6, 22912, 71, 0 }, + /* tcId: 158. replaced s by s + 256 * n */ + {0, 0, 6, 22983, 72, 0 }, + /* tcId: 159. replaced s by -s */ + {0, 0, 6, 23055, 70, 0 }, + /* tcId: 160. replaced s by -n - s */ + {0, 0, 6, 23125, 71, 0 }, + /* tcId: 161. replaced s by s + 2**256 */ + {0, 0, 6, 23196, 71, 0 }, + /* tcId: 162. replaced s by s - 2**256 */ + {0, 0, 6, 23267, 71, 0 }, + /* tcId: 163. replaced s by s + 2**320 */ + {0, 0, 6, 23338, 79, 0 }, + /* tcId: 164. Signature with special case values r=0 and s=0 */ + {0, 0, 6, 23417, 8, 0 }, + /* tcId: 165. Signature with special case values r=0 and s=1 */ + {0, 0, 6, 23425, 8, 0 }, + /* tcId: 166. Signature with special case values r=0 and s=-1 */ + {0, 0, 6, 23433, 8, 0 }, + /* tcId: 167. Signature with special case values r=0 and s=n */ + {0, 0, 6, 23441, 40, 0 }, + /* tcId: 168. Signature with special case values r=0 and s=n - 1 */ + {0, 0, 6, 23481, 40, 0 }, + /* tcId: 169. Signature with special case values r=0 and s=n + 1 */ + {0, 0, 6, 23521, 40, 0 }, + /* tcId: 170. Signature with special case values r=0 and s=p */ + {0, 0, 6, 23561, 40, 0 }, + /* tcId: 171. Signature with special case values r=0 and s=p + 1 */ + {0, 0, 6, 23601, 40, 0 }, + /* tcId: 172. Signature with special case values r=1 and s=0 */ + {0, 0, 6, 23641, 8, 0 }, + /* tcId: 173. Signature with special case values r=1 and s=1 */ + {0, 0, 6, 23649, 8, 0 }, + /* tcId: 174. Signature with special case values r=1 and s=-1 */ + {0, 0, 6, 23657, 8, 0 }, + /* tcId: 175. Signature with special case values r=1 and s=n */ + {0, 0, 6, 23665, 40, 0 }, + /* tcId: 176. Signature with special case values r=1 and s=n - 1 */ + {0, 0, 6, 23705, 40, 0 }, + /* tcId: 177. Signature with special case values r=1 and s=n + 1 */ + {0, 0, 6, 23745, 40, 0 }, + /* tcId: 178. Signature with special case values r=1 and s=p */ + {0, 0, 6, 23785, 40, 0 }, + /* tcId: 179. Signature with special case values r=1 and s=p + 1 */ + {0, 0, 6, 23825, 40, 0 }, + /* tcId: 180. Signature with special case values r=-1 and s=0 */ + {0, 0, 6, 23865, 8, 0 }, + /* tcId: 181. Signature with special case values r=-1 and s=1 */ + {0, 0, 6, 23873, 8, 0 }, + /* tcId: 182. Signature with special case values r=-1 and s=-1 */ + {0, 0, 6, 23881, 8, 0 }, + /* tcId: 183. Signature with special case values r=-1 and s=n */ + {0, 0, 6, 23889, 40, 0 }, + /* tcId: 184. Signature with special case values r=-1 and s=n - 1 */ + {0, 0, 6, 23929, 40, 0 }, + /* tcId: 185. Signature with special case values r=-1 and s=n + 1 */ + {0, 0, 6, 23969, 40, 0 }, + /* tcId: 186. Signature with special case values r=-1 and s=p */ + {0, 0, 6, 24009, 40, 0 }, + /* tcId: 187. Signature with special case values r=-1 and s=p + 1 */ + {0, 0, 6, 24049, 40, 0 }, + /* tcId: 188. Signature with special case values r=n and s=0 */ + {0, 0, 6, 24089, 40, 0 }, + /* tcId: 189. Signature with special case values r=n and s=1 */ + {0, 0, 6, 24129, 40, 0 }, + /* tcId: 190. Signature with special case values r=n and s=-1 */ + {0, 0, 6, 24169, 40, 0 }, + /* tcId: 191. Signature with special case values r=n and s=n */ + {0, 0, 6, 24209, 72, 0 }, + /* tcId: 192. Signature with special case values r=n and s=n - 1 */ + {0, 0, 6, 24281, 72, 0 }, + /* tcId: 193. Signature with special case values r=n and s=n + 1 */ + {0, 0, 6, 24353, 72, 0 }, + /* tcId: 194. Signature with special case values r=n and s=p */ + {0, 0, 6, 24425, 72, 0 }, + /* tcId: 195. Signature with special case values r=n and s=p + 1 */ + {0, 0, 6, 24497, 72, 0 }, + /* tcId: 196. Signature with special case values r=n - 1 and s=0 */ + {0, 0, 6, 24569, 40, 0 }, + /* tcId: 197. Signature with special case values r=n - 1 and s=1 */ + {0, 0, 6, 24609, 40, 0 }, + /* tcId: 198. Signature with special case values r=n - 1 and s=-1 */ + {0, 0, 6, 24649, 40, 0 }, + /* tcId: 199. Signature with special case values r=n - 1 and s=n */ + {0, 0, 6, 24689, 72, 0 }, + /* tcId: 200. Signature with special case values r=n - 1 and s=n - 1 */ + {0, 0, 6, 24761, 72, 0 }, + /* tcId: 201. Signature with special case values r=n - 1 and s=n + 1 */ + {0, 0, 6, 24833, 72, 0 }, + /* tcId: 202. Signature with special case values r=n - 1 and s=p */ + {0, 0, 6, 24905, 72, 0 }, + /* tcId: 203. Signature with special case values r=n - 1 and s=p + 1 */ + {0, 0, 6, 24977, 72, 0 }, + /* tcId: 204. Signature with special case values r=n + 1 and s=0 */ + {0, 0, 6, 25049, 40, 0 }, + /* tcId: 205. Signature with special case values r=n + 1 and s=1 */ + {0, 0, 6, 25089, 40, 0 }, + /* tcId: 206. Signature with special case values r=n + 1 and s=-1 */ + {0, 0, 6, 25129, 40, 0 }, + /* tcId: 207. Signature with special case values r=n + 1 and s=n */ + {0, 0, 6, 25169, 72, 0 }, + /* tcId: 208. Signature with special case values r=n + 1 and s=n - 1 */ + {0, 0, 6, 25241, 72, 0 }, + /* tcId: 209. Signature with special case values r=n + 1 and s=n + 1 */ + {0, 0, 6, 25313, 72, 0 }, + /* tcId: 210. Signature with special case values r=n + 1 and s=p */ + {0, 0, 6, 25385, 72, 0 }, + /* tcId: 211. Signature with special case values r=n + 1 and s=p + 1 */ + {0, 0, 6, 25457, 72, 0 }, + /* tcId: 212. Signature with special case values r=p and s=0 */ + {0, 0, 6, 25529, 40, 0 }, + /* tcId: 213. Signature with special case values r=p and s=1 */ + {0, 0, 6, 25569, 40, 0 }, + /* tcId: 214. Signature with special case values r=p and s=-1 */ + {0, 0, 6, 25609, 40, 0 }, + /* tcId: 215. Signature with special case values r=p and s=n */ + {0, 0, 6, 25649, 72, 0 }, + /* tcId: 216. Signature with special case values r=p and s=n - 1 */ + {0, 0, 6, 25721, 72, 0 }, + /* tcId: 217. Signature with special case values r=p and s=n + 1 */ + {0, 0, 6, 25793, 72, 0 }, + /* tcId: 218. Signature with special case values r=p and s=p */ + {0, 0, 6, 25865, 72, 0 }, + /* tcId: 219. Signature with special case values r=p and s=p + 1 */ + {0, 0, 6, 25937, 72, 0 }, + /* tcId: 220. Signature with special case values r=p + 1 and s=0 */ + {0, 0, 6, 26009, 40, 0 }, + /* tcId: 221. Signature with special case values r=p + 1 and s=1 */ + {0, 0, 6, 26049, 40, 0 }, + /* tcId: 222. Signature with special case values r=p + 1 and s=-1 */ + {0, 0, 6, 26089, 40, 0 }, + /* tcId: 223. Signature with special case values r=p + 1 and s=n */ + {0, 0, 6, 26129, 72, 0 }, + /* tcId: 224. Signature with special case values r=p + 1 and s=n - 1 */ + {0, 0, 6, 26201, 72, 0 }, + /* tcId: 225. Signature with special case values r=p + 1 and s=n + 1 */ + {0, 0, 6, 26273, 72, 0 }, + /* tcId: 226. Signature with special case values r=p + 1 and s=p */ + {0, 0, 6, 26345, 72, 0 }, + /* tcId: 227. Signature with special case values r=p + 1 and s=p + 1 */ + {0, 0, 6, 26417, 72, 0 }, + /* tcId: 228. Signature encoding contains incorrect types: r=0, s=0.25 */ + {0, 0, 6, 26489, 10, 0 }, + /* tcId: 229. Signature encoding contains incorrect types: r=0, s=nan */ + {0, 0, 6, 26499, 8, 0 }, + /* tcId: 230. Signature encoding contains incorrect types: r=0, s=True */ + {0, 0, 6, 26507, 8, 0 }, + /* tcId: 231. Signature encoding contains incorrect types: r=0, s=False */ + {0, 0, 6, 26515, 8, 0 }, + /* tcId: 232. Signature encoding contains incorrect types: r=0, s=Null */ + {0, 0, 6, 26523, 7, 0 }, + /* tcId: 233. Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string */ + {0, 0, 6, 26530, 7, 0 }, + /* tcId: 234. Signature encoding contains incorrect types: r=0, s="0" */ + {0, 0, 6, 26537, 8, 0 }, + /* tcId: 235. Signature encoding contains incorrect types: r=0, s=empty list */ + {0, 0, 6, 26545, 7, 0 }, + /* tcId: 236. Signature encoding contains incorrect types: r=0, s=list containing 0 */ + {0, 0, 6, 26552, 10, 0 }, + /* tcId: 237. Signature encoding contains incorrect types: r=1, s=0.25 */ + {0, 0, 6, 26562, 10, 0 }, + /* tcId: 238. Signature encoding contains incorrect types: r=1, s=nan */ + {0, 0, 6, 26572, 8, 0 }, + /* tcId: 239. Signature encoding contains incorrect types: r=1, s=True */ + {0, 0, 6, 26580, 8, 0 }, + /* tcId: 240. Signature encoding contains incorrect types: r=1, s=False */ + {0, 0, 6, 26588, 8, 0 }, + /* tcId: 241. Signature encoding contains incorrect types: r=1, s=Null */ + {0, 0, 6, 26596, 7, 0 }, + /* tcId: 242. Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string */ + {0, 0, 6, 26603, 7, 0 }, + /* tcId: 243. Signature encoding contains incorrect types: r=1, s="0" */ + {0, 0, 6, 26610, 8, 0 }, + /* tcId: 244. Signature encoding contains incorrect types: r=1, s=empty list */ + {0, 0, 6, 26618, 7, 0 }, + /* tcId: 245. Signature encoding contains incorrect types: r=1, s=list containing 0 */ + {0, 0, 6, 26625, 10, 0 }, + /* tcId: 246. Signature encoding contains incorrect types: r=-1, s=0.25 */ + {0, 0, 6, 26635, 10, 0 }, + /* tcId: 247. Signature encoding contains incorrect types: r=-1, s=nan */ + {0, 0, 6, 26645, 8, 0 }, + /* tcId: 248. Signature encoding contains incorrect types: r=-1, s=True */ + {0, 0, 6, 26653, 8, 0 }, + /* tcId: 249. Signature encoding contains incorrect types: r=-1, s=False */ + {0, 0, 6, 26661, 8, 0 }, + /* tcId: 250. Signature encoding contains incorrect types: r=-1, s=Null */ + {0, 0, 6, 26669, 7, 0 }, + /* tcId: 251. Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string */ + {0, 0, 6, 26676, 7, 0 }, + /* tcId: 252. Signature encoding contains incorrect types: r=-1, s="0" */ + {0, 0, 6, 26683, 8, 0 }, + /* tcId: 253. Signature encoding contains incorrect types: r=-1, s=empty list */ + {0, 0, 6, 26691, 7, 0 }, + /* tcId: 254. Signature encoding contains incorrect types: r=-1, s=list containing 0 */ + {0, 0, 6, 26698, 10, 0 }, + /* tcId: 255. Signature encoding contains incorrect types: r=n, s=0.25 */ + {0, 0, 6, 26708, 42, 0 }, + /* tcId: 256. Signature encoding contains incorrect types: r=n, s=nan */ + {0, 0, 6, 26750, 40, 0 }, + /* tcId: 257. Signature encoding contains incorrect types: r=n, s=True */ + {0, 0, 6, 26790, 40, 0 }, + /* tcId: 258. Signature encoding contains incorrect types: r=n, s=False */ + {0, 0, 6, 26830, 40, 0 }, + /* tcId: 259. Signature encoding contains incorrect types: r=n, s=Null */ + {0, 0, 6, 26870, 39, 0 }, + /* tcId: 260. Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string */ + {0, 0, 6, 26909, 39, 0 }, + /* tcId: 261. Signature encoding contains incorrect types: r=n, s="0" */ + {0, 0, 6, 26948, 40, 0 }, + /* tcId: 262. Signature encoding contains incorrect types: r=n, s=empty list */ + {0, 0, 6, 26988, 39, 0 }, + /* tcId: 263. Signature encoding contains incorrect types: r=n, s=list containing 0 */ + {0, 0, 6, 27027, 42, 0 }, + /* tcId: 264. Signature encoding contains incorrect types: r=p, s=0.25 */ + {0, 0, 6, 27069, 42, 0 }, + /* tcId: 265. Signature encoding contains incorrect types: r=p, s=nan */ + {0, 0, 6, 27111, 40, 0 }, + /* tcId: 266. Signature encoding contains incorrect types: r=p, s=True */ + {0, 0, 6, 27151, 40, 0 }, + /* tcId: 267. Signature encoding contains incorrect types: r=p, s=False */ + {0, 0, 6, 27191, 40, 0 }, + /* tcId: 268. Signature encoding contains incorrect types: r=p, s=Null */ + {0, 0, 6, 27231, 39, 0 }, + /* tcId: 269. Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string */ + {0, 0, 6, 27270, 39, 0 }, + /* tcId: 270. Signature encoding contains incorrect types: r=p, s="0" */ + {0, 0, 6, 27309, 40, 0 }, + /* tcId: 271. Signature encoding contains incorrect types: r=p, s=empty list */ + {0, 0, 6, 27349, 39, 0 }, + /* tcId: 272. Signature encoding contains incorrect types: r=p, s=list containing 0 */ + {0, 0, 6, 27388, 42, 0 }, + /* tcId: 273. Signature encoding contains incorrect types: r=0.25, s=0.25 */ + {0, 0, 6, 27430, 12, 0 }, + /* tcId: 274. Signature encoding contains incorrect types: r=nan, s=nan */ + {0, 0, 6, 27442, 8, 0 }, + /* tcId: 275. Signature encoding contains incorrect types: r=True, s=True */ + {0, 0, 6, 27450, 8, 0 }, + /* tcId: 276. Signature encoding contains incorrect types: r=False, s=False */ + {0, 0, 6, 27458, 8, 0 }, + /* tcId: 277. Signature encoding contains incorrect types: r=Null, s=Null */ + {0, 0, 6, 27466, 6, 0 }, + /* tcId: 278. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string */ + {0, 0, 6, 27472, 6, 0 }, + /* tcId: 279. Signature encoding contains incorrect types: r="0", s="0" */ + {0, 0, 6, 27478, 8, 0 }, + /* tcId: 280. Signature encoding contains incorrect types: r=empty list, s=empty list */ + {0, 0, 6, 27486, 6, 0 }, + /* tcId: 281. Signature encoding contains incorrect types: r=list containing 0, s=list containing 0 */ + {0, 0, 6, 27492, 12, 0 }, + /* tcId: 282. Signature encoding contains incorrect types: r=0.25, s=0 */ + {0, 0, 6, 27504, 10, 0 }, + /* tcId: 283. Signature encoding contains incorrect types: r=nan, s=0 */ + {0, 0, 6, 27514, 8, 0 }, + /* tcId: 284. Signature encoding contains incorrect types: r=True, s=0 */ + {0, 0, 6, 27522, 8, 0 }, + /* tcId: 285. Signature encoding contains incorrect types: r=False, s=0 */ + {0, 0, 6, 27530, 8, 0 }, + /* tcId: 286. Signature encoding contains incorrect types: r=Null, s=0 */ + {0, 0, 6, 27538, 7, 0 }, + /* tcId: 287. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0 */ + {0, 0, 6, 27545, 7, 0 }, + /* tcId: 288. Signature encoding contains incorrect types: r="0", s=0 */ + {0, 0, 6, 27552, 8, 0 }, + /* tcId: 289. Signature encoding contains incorrect types: r=empty list, s=0 */ + {0, 0, 6, 27560, 7, 0 }, + /* tcId: 290. Signature encoding contains incorrect types: r=list containing 0, s=0 */ + {0, 0, 6, 27567, 10, 0 }, + /* tcId: 291. Edge case for Shamir multiplication */ + {0, 6, 5, 27577, 71, 1 }, + /* tcId: 292. special case hash */ + {0, 11, 9, 27648, 71, 1 }, + /* tcId: 293. special case hash */ + {0, 20, 10, 27719, 70, 1 }, + /* tcId: 294. special case hash */ + {0, 30, 11, 27789, 71, 1 }, + /* tcId: 295. special case hash */ + {0, 41, 10, 27860, 71, 1 }, + /* tcId: 296. special case hash */ + {0, 51, 10, 27931, 70, 1 }, + /* tcId: 297. special case hash */ + {0, 61, 10, 28001, 71, 1 }, + /* tcId: 298. special case hash */ + {0, 71, 9, 28072, 70, 1 }, + /* tcId: 299. special case hash */ + {0, 80, 10, 28142, 71, 1 }, + /* tcId: 300. special case hash */ + {0, 90, 10, 28213, 71, 1 }, + /* tcId: 301. special case hash */ + {0, 100, 10, 28284, 71, 1 }, + /* tcId: 302. special case hash */ + {0, 110, 10, 28355, 71, 1 }, + /* tcId: 303. special case hash */ + {0, 120, 11, 28426, 70, 1 }, + /* tcId: 304. special case hash */ + {0, 131, 10, 28496, 71, 1 }, + /* tcId: 305. special case hash */ + {0, 141, 10, 28567, 71, 1 }, + /* tcId: 306. special case hash */ + {0, 151, 10, 28638, 70, 1 }, + /* tcId: 307. special case hash */ + {0, 161, 10, 28708, 71, 1 }, + /* tcId: 308. special case hash */ + {0, 171, 10, 28779, 71, 1 }, + /* tcId: 309. special case hash */ + {0, 181, 10, 28850, 70, 1 }, + /* tcId: 310. special case hash */ + {0, 191, 10, 28920, 71, 1 }, + /* tcId: 311. special case hash */ + {0, 201, 10, 28991, 71, 1 }, + /* tcId: 312. special case hash */ + {0, 211, 10, 29062, 71, 1 }, + /* tcId: 313. special case hash */ + {0, 221, 10, 29133, 70, 1 }, + /* tcId: 314. special case hash */ + {0, 231, 10, 29203, 71, 1 }, + /* tcId: 315. special case hash */ + {0, 241, 10, 29274, 71, 1 }, + /* tcId: 316. special case hash */ + {0, 251, 10, 29345, 71, 1 }, + /* tcId: 317. special case hash */ + {0, 261, 11, 29416, 71, 1 }, + /* tcId: 318. special case hash */ + {0, 272, 11, 29487, 70, 1 }, + /* tcId: 319. special case hash */ + {0, 283, 9, 29557, 71, 1 }, + /* tcId: 320. special case hash */ + {0, 292, 9, 29628, 71, 1 }, + /* tcId: 321. special case hash */ + {0, 301, 10, 29699, 71, 1 }, + /* tcId: 322. special case hash */ + {0, 311, 10, 29770, 71, 1 }, + /* tcId: 323. special case hash */ + {0, 321, 10, 29841, 70, 1 }, + /* tcId: 324. special case hash */ + {0, 331, 10, 29911, 70, 1 }, + /* tcId: 325. special case hash */ + {0, 341, 10, 29981, 71, 1 }, + /* tcId: 326. special case hash */ + {0, 351, 9, 30052, 70, 1 }, + /* tcId: 327. special case hash */ + {0, 360, 10, 30122, 70, 1 }, + /* tcId: 328. special case hash */ + {0, 370, 10, 30192, 70, 1 }, + /* tcId: 329. special case hash */ + {0, 380, 10, 30262, 70, 1 }, + /* tcId: 330. special case hash */ + {0, 390, 9, 30332, 71, 1 }, + /* tcId: 331. special case hash */ + {0, 399, 11, 30403, 70, 1 }, + /* tcId: 332. special case hash */ + {0, 410, 9, 30473, 71, 1 }, + /* tcId: 333. special case hash */ + {0, 419, 9, 30544, 71, 1 }, + /* tcId: 334. special case hash */ + {0, 428, 11, 30615, 70, 1 }, + /* tcId: 335. special case hash */ + {0, 439, 8, 30685, 71, 1 }, + /* tcId: 336. special case hash */ + {0, 447, 10, 30756, 70, 1 }, + /* tcId: 337. special case hash */ + {0, 457, 10, 30826, 71, 1 }, + /* tcId: 338. special case hash */ + {0, 467, 10, 30897, 70, 1 }, + /* tcId: 339. special case hash */ + {0, 477, 10, 30967, 70, 1 }, + /* tcId: 340. special case hash */ + {0, 487, 10, 31037, 70, 1 }, + /* tcId: 341. special case hash */ + {0, 497, 10, 31107, 71, 1 }, + /* tcId: 342. special case hash */ + {0, 507, 10, 31178, 70, 1 }, + /* tcId: 343. special case hash */ + {0, 517, 10, 31248, 70, 1 }, + /* tcId: 344. special case hash */ + {0, 527, 10, 31318, 71, 1 }, + /* tcId: 345. special case hash */ + {0, 537, 9, 31389, 70, 1 }, + /* tcId: 346. k*G has a large x-coordinate */ + {65, 0, 6, 31459, 24, 1 }, + /* tcId: 347. r too large */ + {65, 0, 6, 31483, 40, 0 }, + /* tcId: 348. r,s are large */ + {130, 0, 6, 31523, 40, 1 }, + /* tcId: 349. r and s^-1 have a large Hamming weight */ + {195, 0, 6, 31563, 70, 1 }, + /* tcId: 350. r and s^-1 have a large Hamming weight */ + {260, 0, 6, 31633, 70, 1 }, + /* tcId: 351. small r and s */ + {325, 0, 6, 31703, 8, 1 }, + /* tcId: 352. small r and s */ + {390, 0, 6, 31711, 8, 1 }, + /* tcId: 353. small r and s */ + {455, 0, 6, 31719, 8, 1 }, + /* tcId: 354. small r and s */ + {520, 0, 6, 31727, 8, 1 }, + /* tcId: 355. small r and s */ + {585, 0, 6, 31735, 8, 1 }, + /* tcId: 356. small r and s */ + {650, 0, 6, 31743, 8, 1 }, + /* tcId: 357. r is larger than n */ + {650, 0, 6, 31751, 40, 0 }, + /* tcId: 358. s is larger than n */ + {715, 0, 6, 31791, 10, 0 }, + /* tcId: 359. small r and s^-1 */ + {780, 0, 6, 31801, 40, 1 }, + /* tcId: 360. smallish r and s^-1 */ + {845, 0, 6, 31841, 45, 1 }, + /* tcId: 361. 100-bit r and small s^-1 */ + {910, 0, 6, 31886, 51, 1 }, + /* tcId: 362. small r and 100 bit s^-1 */ + {975, 0, 6, 31937, 40, 1 }, + /* tcId: 363. 100-bit r and s^-1 */ + {1040, 0, 6, 31977, 51, 1 }, + /* tcId: 364. r and s^-1 are close to n */ + {1105, 0, 6, 32028, 71, 1 }, + /* tcId: 365. r and s are 64-bit integer */ + {1170, 0, 6, 32099, 24, 1 }, + /* tcId: 366. r and s are 100-bit integer */ + {1235, 0, 6, 32123, 32, 1 }, + /* tcId: 367. r and s are 128-bit integer */ + {1300, 0, 6, 32155, 40, 1 }, + /* tcId: 368. r and s are 160-bit integer */ + {1365, 0, 6, 32195, 48, 1 }, + /* tcId: 369. s == 1 */ + {1430, 0, 6, 32243, 39, 1 }, + /* tcId: 370. s == 0 */ + {1430, 0, 6, 32282, 39, 0 }, + /* tcId: 371. edge case modular inverse */ + {1495, 0, 6, 32321, 70, 1 }, + /* tcId: 372. edge case modular inverse */ + {1560, 0, 6, 32391, 70, 1 }, + /* tcId: 373. edge case modular inverse */ + {1625, 0, 6, 32461, 70, 1 }, + /* tcId: 374. edge case modular inverse */ + {1690, 0, 6, 32531, 70, 1 }, + /* tcId: 375. edge case modular inverse */ + {1755, 0, 6, 32601, 70, 1 }, + /* tcId: 376. edge case modular inverse */ + {1820, 0, 6, 32671, 70, 1 }, + /* tcId: 377. edge case modular inverse */ + {1885, 0, 6, 32741, 70, 1 }, + /* tcId: 378. edge case modular inverse */ + {1950, 0, 6, 32811, 70, 1 }, + /* tcId: 379. edge case modular inverse */ + {2015, 0, 6, 32881, 70, 1 }, + /* tcId: 380. edge case modular inverse */ + {2080, 0, 6, 32951, 70, 1 }, + /* tcId: 381. edge case modular inverse */ + {2145, 0, 6, 33021, 70, 1 }, + /* tcId: 382. edge case modular inverse */ + {2210, 0, 6, 33091, 70, 1 }, + /* tcId: 383. edge case modular inverse */ + {2275, 0, 6, 33161, 70, 1 }, + /* tcId: 384. edge case modular inverse */ + {2340, 0, 6, 33231, 70, 1 }, + /* tcId: 385. edge case modular inverse */ + {2405, 0, 6, 33301, 70, 1 }, + /* tcId: 386. point at infinity during verify */ + {2470, 0, 6, 33371, 70, 0 }, + /* tcId: 387. edge case for signature malleability */ + {2535, 0, 6, 33441, 70, 1 }, + /* tcId: 388. edge case for signature malleability */ + {2600, 0, 6, 33511, 70, 0 }, + /* tcId: 389. u1 == 1 */ + {2665, 0, 6, 33581, 70, 1 }, + /* tcId: 390. u1 == n - 1 */ + {2730, 0, 6, 33651, 70, 1 }, + /* tcId: 391. u2 == 1 */ + {2795, 0, 6, 33721, 70, 1 }, + /* tcId: 392. u2 == n - 1 */ + {2860, 0, 6, 33791, 70, 1 }, + /* tcId: 393. edge case for u1 */ + {2925, 0, 6, 33861, 70, 1 }, + /* tcId: 394. edge case for u1 */ + {2990, 0, 6, 33931, 70, 1 }, + /* tcId: 395. edge case for u1 */ + {3055, 0, 6, 34001, 70, 1 }, + /* tcId: 396. edge case for u1 */ + {3120, 0, 6, 34071, 70, 1 }, + /* tcId: 397. edge case for u1 */ + {3185, 0, 6, 34141, 70, 1 }, + /* tcId: 398. edge case for u1 */ + {3250, 0, 6, 34211, 70, 1 }, + /* tcId: 399. edge case for u1 */ + {3315, 0, 6, 34281, 70, 1 }, + /* tcId: 400. edge case for u1 */ + {3380, 0, 6, 34351, 70, 1 }, + /* tcId: 401. edge case for u1 */ + {3445, 0, 6, 34421, 70, 1 }, + /* tcId: 402. edge case for u1 */ + {3510, 0, 6, 34491, 70, 1 }, + /* tcId: 403. edge case for u1 */ + {3575, 0, 6, 34561, 70, 1 }, + /* tcId: 404. edge case for u1 */ + {3640, 0, 6, 34631, 70, 1 }, + /* tcId: 405. edge case for u1 */ + {3705, 0, 6, 34701, 70, 1 }, + /* tcId: 406. edge case for u1 */ + {3770, 0, 6, 34771, 70, 1 }, + /* tcId: 407. edge case for u1 */ + {3835, 0, 6, 34841, 70, 1 }, + /* tcId: 408. edge case for u2 */ + {3900, 0, 6, 34911, 70, 1 }, + /* tcId: 409. edge case for u2 */ + {3965, 0, 6, 34981, 70, 1 }, + /* tcId: 410. edge case for u2 */ + {4030, 0, 6, 35051, 70, 1 }, + /* tcId: 411. edge case for u2 */ + {4095, 0, 6, 35121, 70, 1 }, + /* tcId: 412. edge case for u2 */ + {4160, 0, 6, 35191, 70, 1 }, + /* tcId: 413. edge case for u2 */ + {4225, 0, 6, 35261, 69, 1 }, + /* tcId: 414. edge case for u2 */ + {4290, 0, 6, 35330, 70, 1 }, + /* tcId: 415. edge case for u2 */ + {4355, 0, 6, 35400, 70, 1 }, + /* tcId: 416. edge case for u2 */ + {4420, 0, 6, 35470, 70, 1 }, + /* tcId: 417. edge case for u2 */ + {4485, 0, 6, 35540, 70, 1 }, + /* tcId: 418. edge case for u2 */ + {4550, 0, 6, 35610, 70, 1 }, + /* tcId: 419. edge case for u2 */ + {4615, 0, 6, 35680, 70, 1 }, + /* tcId: 420. edge case for u2 */ + {4680, 0, 6, 35750, 70, 1 }, + /* tcId: 421. edge case for u2 */ + {4745, 0, 6, 35820, 70, 1 }, + /* tcId: 422. edge case for u2 */ + {4810, 0, 6, 35890, 70, 1 }, + /* tcId: 423. point duplication during verification */ + {4875, 0, 6, 35960, 70, 1 }, + /* tcId: 424. duplication bug */ + {4940, 0, 6, 36030, 70, 0 }, + /* tcId: 425. comparison with point at infinity */ + {5005, 0, 6, 36100, 70, 0 }, + /* tcId: 426. extreme value for k and edgecase s */ + {5070, 0, 6, 36170, 71, 1 }, + /* tcId: 427. extreme value for k and s^-1 */ + {5135, 0, 6, 36241, 71, 1 }, + /* tcId: 428. extreme value for k and s^-1 */ + {5200, 0, 6, 36312, 71, 1 }, + /* tcId: 429. extreme value for k and s^-1 */ + {5265, 0, 6, 36383, 71, 1 }, + /* tcId: 430. extreme value for k and s^-1 */ + {5330, 0, 6, 36454, 71, 1 }, + /* tcId: 431. extreme value for k */ + {5395, 0, 6, 36525, 71, 1 }, + /* tcId: 432. extreme value for k and edgecase s */ + {5460, 0, 6, 36596, 70, 1 }, + /* tcId: 433. extreme value for k and s^-1 */ + {5525, 0, 6, 36666, 70, 1 }, + /* tcId: 434. extreme value for k and s^-1 */ + {5590, 0, 6, 36736, 70, 1 }, + /* tcId: 435. extreme value for k and s^-1 */ + {5655, 0, 6, 36806, 70, 1 }, + /* tcId: 436. extreme value for k and s^-1 */ + {5720, 0, 6, 36876, 70, 1 }, + /* tcId: 437. extreme value for k */ + {5785, 0, 6, 36946, 70, 1 }, + /* tcId: 438. public key shares x-coordinate with generator */ + {5850, 0, 6, 37016, 71, 0 }, + /* tcId: 439. public key shares x-coordinate with generator */ + {5850, 0, 6, 37087, 70, 0 }, + /* tcId: 440. public key shares x-coordinate with generator */ + {5915, 0, 6, 37157, 71, 0 }, + /* tcId: 441. public key shares x-coordinate with generator */ + {5915, 0, 6, 37228, 70, 0 }, + /* tcId: 442. pseudorandom signature */ + {5980, 546, 0, 37298, 71, 1 }, + /* tcId: 443. pseudorandom signature */ + {5980, 546, 3, 37369, 70, 1 }, + /* tcId: 444. pseudorandom signature */ + {5980, 0, 6, 37439, 71, 1 }, + /* tcId: 445. pseudorandom signature */ + {5980, 549, 20, 37510, 70, 1 }, + /* tcId: 446. y-coordinate of the public key is small */ + {6045, 569, 7, 37580, 70, 1 }, + /* tcId: 447. y-coordinate of the public key is small */ + {6045, 569, 7, 37650, 70, 1 }, + /* tcId: 448. y-coordinate of the public key is small */ + {6045, 569, 7, 37720, 71, 1 }, + /* tcId: 449. y-coordinate of the public key is large */ + {6110, 569, 7, 37791, 70, 1 }, + /* tcId: 450. y-coordinate of the public key is large */ + {6110, 569, 7, 37861, 71, 1 }, + /* tcId: 451. y-coordinate of the public key is large */ + {6110, 569, 7, 37932, 70, 1 }, + /* tcId: 452. x-coordinate of the public key is small */ + {6175, 569, 7, 38002, 70, 1 }, + /* tcId: 453. x-coordinate of the public key is small */ + {6175, 569, 7, 38072, 71, 1 }, + /* tcId: 454. x-coordinate of the public key is small */ + {6175, 569, 7, 38143, 71, 1 }, + /* tcId: 455. x-coordinate of the public key has many trailing 1's */ + {6240, 569, 7, 38214, 70, 1 }, + /* tcId: 456. x-coordinate of the public key has many trailing 1's */ + {6240, 569, 7, 38284, 71, 1 }, + /* tcId: 457. x-coordinate of the public key has many trailing 1's */ + {6240, 569, 7, 38355, 71, 1 }, + /* tcId: 458. y-coordinate of the public key has many trailing 1's */ + {6305, 569, 7, 38426, 70, 1 }, + /* tcId: 459. y-coordinate of the public key has many trailing 1's */ + {6305, 569, 7, 38496, 71, 1 }, + /* tcId: 460. y-coordinate of the public key has many trailing 1's */ + {6305, 569, 7, 38567, 71, 1 }, + /* tcId: 461. x-coordinate of the public key has many trailing 0's */ + {6370, 569, 7, 38638, 70, 1 }, + /* tcId: 462. x-coordinate of the public key has many trailing 0's */ + {6370, 569, 7, 38708, 70, 1 }, + /* tcId: 463. x-coordinate of the public key has many trailing 0's */ + {6370, 569, 7, 38778, 71, 1 }, + +}; diff --git a/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json b/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json new file mode 100644 index 00000000000..9c90747993d --- /dev/null +++ b/external/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json @@ -0,0 +1,6360 @@ +{ + "algorithm" : "ECDSA", + "schema" : "ecdsa_bitcoin_verify_schema.json", + "generatorVersion" : "0.9rc5", + "numberOfTests" : 463, + "header" : [ + "Test vectors of type EcdsaBitcoinVerify are meant for the verification", + "of a ECDSA variant used for bitcoin, that add signature non-malleability." + ], + "notes" : { + "ArithmeticError" : { + "bugType" : "EDGE_CASE", + "description" : "Some implementations of ECDSA have arithmetic errors that occur when intermediate results have extreme values. This test vector has been constructed to test such occurences.", + "cves" : [ + "CVE-2017-18146" + ] + }, + "BerEncodedSignature" : { + "bugType" : "BER_ENCODING", + "description" : "ECDSA signatures are usually DER encoded. This signature contains valid values for r and s, but it uses alternative BER encoding.", + "effect" : "Accepting alternative BER encodings may be benign in some cases, or be an issue if protocol requires signature malleability.", + "cves" : [ + "CVE-2020-14966", + "CVE-2020-13822", + "CVE-2019-14859", + "CVE-2016-1000342" + ] + }, + "EdgeCasePublicKey" : { + "bugType" : "EDGE_CASE", + "description" : "The test vector uses a special case public key. " + }, + "EdgeCaseShamirMultiplication" : { + "bugType" : "EDGE_CASE", + "description" : "Shamir proposed a fast method for computing the sum of two scalar multiplications efficiently. This test vector has been constructed so that an intermediate result is the point at infinity if Shamir's method is used." + }, + "IntegerOverflow" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an r and s that has been modified, so that the original value is restored if the implementation ignores the most significant bits.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "InvalidEncoding" : { + "bugType" : "CAN_OF_WORMS", + "description" : "ECDSA signatures are encoded using ASN.1. This test vector contains an incorrectly encoded signature. The test vector itself was generated from a valid signature by modifying its encoding.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "InvalidSignature" : { + "bugType" : "AUTH_BYPASS", + "description" : "The signature contains special case values such as r=0 and s=0. Buggy implementations may accept such values, if the implementation does not check boundaries and computes s^(-1) == 0.", + "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", + "cves" : [ + "CVE-2022-21449", + "CVE-2021-43572", + "CVE-2022-24884" + ] + }, + "InvalidTypesInSignature" : { + "bugType" : "AUTH_BYPASS", + "description" : "The signature contains invalid types. Dynamic typed languages sometime coerce such values of different types into integers. If an implementation is careless and has additional bugs, such as not checking integer boundaries then it may be possible that such signatures are accepted.", + "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", + "cves" : [ + "CVE-2022-21449" + ] + }, + "ModifiedInteger" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an r and s that has been modified. The goal is to check for arithmetic errors.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "ModifiedSignature" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an invalid signature that was generated from a valid signature by modifying it.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "ModularInverse" : { + "bugType" : "EDGE_CASE", + "description" : "The test vectors contains a signature where computing the modular inverse of s hits an edge case.", + "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", + "cves" : [ + "CVE-2019-0865" + ] + }, + "PointDuplication" : { + "bugType" : "EDGE_CASE", + "description" : "Some implementations of ECDSA do not handle duplication and points at infinity correctly. This is a test vector that has been specially crafted to check for such an omission.", + "cves" : [ + "2020-12607", + "CVE-2015-2730" + ] + }, + "RangeCheck" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an r and s that has been modified. By adding or subtracting the order of the group (or other values) the test vector checks whether signature verification verifies the range of r and s.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "SignatureMalleabilityBitcoin" : { + "bugType" : "SIGNATURE_MALLEABILITY", + "description" : "\"BitCoins\"-curves are curves where signature malleability can be a serious issue. An implementation should only accept a signature s where s < n/2. If an implementation is not meant for uses cases that require signature malleability then this implemenation should be tested with another set of test vectors.", + "effect" : "In bitcoin exchanges, it may be used to make a double deposits or double withdrawals", + "links" : [ + "https://en.bitcoin.it/wiki/Transaction_malleability", + "https://en.bitcoinwiki.org/wiki/Transaction_Malleability" + ] + }, + "SmallRandS" : { + "bugType" : "EDGE_CASE", + "description" : "The test vectors contains a signature where both r and s are small integers. Some libraries cannot verify such signatures.", + "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", + "cves" : [ + "2020-13895" + ] + }, + "SpecialCaseHash" : { + "bugType" : "EDGE_CASE", + "description" : "The test vector contains a signature where the hash of the message is a special case, e.g., contains a long run of 0 or 1 bits." + }, + "ValidSignature" : { + "bugType" : "BASIC", + "description" : "The test vector contains a valid signature that was generated pseudorandomly. Such signatures should not fail to verify unless some of the parameters (e.g. curve or hash function) are not supported." + } + }, + "testGroups" : [ + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", + "wx" : "00b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6f", + "wy" : "00f0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEuDj/ROW8F3vyEYnQdmCC/J2EMiaIf8l2\nA3EQC37iCm/wyddb+6ezGmvKGXRJbutW3jVwcZVdg8Sxutqgshgy6Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 1, + "comment" : "Signature malleability", + "flags" : [ + "SignatureMalleabilityBitcoin" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022100900e75ad233fcc908509dbff5922647db37c21f4afd3203ae8dc4ae7794b0f87", + "result" : "invalid" + }, + { + "tcId" : 2, + "comment" : "valid", + "flags" : [ + "ValidSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "valid" + }, + { + "tcId" : 3, + "comment" : "length of sequence [r, s] uses long form encoding", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "308145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 4, + "comment" : "length of sequence [r, s] contains a leading 0", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "30820045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 5, + "comment" : "length of sequence [r, s] uses 70 instead of 69", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 6, + "comment" : "length of sequence [r, s] uses 68 instead of 69", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 7, + "comment" : "uint32 overflow in length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30850100000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 8, + "comment" : "uint64 overflow in length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3089010000000000000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 9, + "comment" : "length of sequence [r, s] = 2**31 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30847fffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 10, + "comment" : "length of sequence [r, s] = 2**31", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "308480000000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 11, + "comment" : "length of sequence [r, s] = 2**32 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3084ffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 12, + "comment" : "length of sequence [r, s] = 2**40 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3085ffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 13, + "comment" : "length of sequence [r, s] = 2**64 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3088ffffffffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 14, + "comment" : "incorrect length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30ff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 15, + "comment" : "replaced sequence [r, s] by an indefinite length tag without termination", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 16, + "comment" : "removing sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "", + "result" : "invalid" + }, + { + "tcId" : 17, + "comment" : "lonely sequence tag", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30", + "result" : "invalid" + }, + { + "tcId" : 18, + "comment" : "appending 0's to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 19, + "comment" : "prepending 0's to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30470000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 20, + "comment" : "appending unused 0's to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 21, + "comment" : "appending null value to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", + "result" : "invalid" + }, + { + "tcId" : 22, + "comment" : "prepending garbage to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a4981773045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 23, + "comment" : "prepending garbage to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304925003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 24, + "comment" : "appending garbage to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", + "result" : "invalid" + }, + { + "tcId" : 25, + "comment" : "including undefined tags", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "304daa00bb00cd003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 26, + "comment" : "including undefined tags", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d2229aa00bb00cd00022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 27, + "comment" : "including undefined tags", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652228aa00bb00cd0002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 28, + "comment" : "truncated length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3081", + "result" : "invalid" + }, + { + "tcId" : 29, + "comment" : "including undefined tags to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "304baa02aabb3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 30, + "comment" : "using composition with indefinite length for sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30803045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 31, + "comment" : "using composition with wrong tag for sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30803145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 32, + "comment" : "Replacing sequence [r, s] with NULL", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "0500", + "result" : "invalid" + }, + { + "tcId" : 33, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "2e45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 34, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "2f45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 35, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 36, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3245022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 37, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "ff45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 38, + "comment" : "dropping value of sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3000", + "result" : "invalid" + }, + { + "tcId" : 39, + "comment" : "using composition for sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304930010230442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 40, + "comment" : "truncated sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", + "result" : "invalid" + }, + { + "tcId" : 41, + "comment" : "truncated sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 42, + "comment" : "sequence [r, s] of size 4166 to check for overflows", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30821046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid" + }, + { + "tcId" : 43, + "comment" : "indefinite length", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 44, + "comment" : "indefinite length with truncated delimiter", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba00", + "result" : "invalid" + }, + { + "tcId" : 45, + "comment" : "indefinite length with additional element", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba05000000", + "result" : "invalid" + }, + { + "tcId" : 46, + "comment" : "indefinite length with truncated element", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba060811220000", + "result" : "invalid" + }, + { + "tcId" : 47, + "comment" : "indefinite length with garbage", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000fe02beef", + "result" : "invalid" + }, + { + "tcId" : 48, + "comment" : "indefinite length with nonempty EOC", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0002beef", + "result" : "invalid" + }, + { + "tcId" : 49, + "comment" : "prepend empty sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30473000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 50, + "comment" : "append empty sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba3000", + "result" : "invalid" + }, + { + "tcId" : 51, + "comment" : "append zero", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba020100", + "result" : "invalid" + }, + { + "tcId" : 52, + "comment" : "append garbage with high tag number", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31babf7f00", + "result" : "invalid" + }, + { + "tcId" : 53, + "comment" : "append null with explicit tag", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa0020500", + "result" : "invalid" + }, + { + "tcId" : 54, + "comment" : "append null with implicit tag", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa000", + "result" : "invalid" + }, + { + "tcId" : 55, + "comment" : "sequence of sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 56, + "comment" : "truncated sequence: removed last 1 elements", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3023022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365", + "result" : "invalid" + }, + { + "tcId" : 57, + "comment" : "repeating element in sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3067022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 58, + "comment" : "flipped bit 0 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 59, + "comment" : "flipped bit 32 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccac983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 60, + "comment" : "flipped bit 48 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5133ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 61, + "comment" : "flipped bit 64 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc08b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 62, + "comment" : "length of r uses long form encoding", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "304602812100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 63, + "comment" : "length of r contains a leading 0", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "30470282002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 64, + "comment" : "length of r uses 34 instead of 33", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 65, + "comment" : "length of r uses 32 instead of 33", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 66, + "comment" : "uint32 overflow in length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a0285010000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 67, + "comment" : "uint64 overflow in length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304e028901000000000000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 68, + "comment" : "length of r = 2**31 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304902847fffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 69, + "comment" : "length of r = 2**31", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304902848000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 70, + "comment" : "length of r = 2**32 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30490284ffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 71, + "comment" : "length of r = 2**40 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a0285ffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 72, + "comment" : "length of r = 2**64 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d0288ffffffffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 73, + "comment" : "incorrect length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304502ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 74, + "comment" : "replaced r by an indefinite length tag without termination", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045028000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 75, + "comment" : "removing r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "302202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 76, + "comment" : "lonely integer tag", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30230202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 77, + "comment" : "lonely integer tag", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3024022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502", + "result" : "invalid" + }, + { + "tcId" : 78, + "comment" : "appending 0's to r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 79, + "comment" : "prepending 0's to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30470223000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 80, + "comment" : "appending unused 0's to r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 81, + "comment" : "appending null value to r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 82, + "comment" : "prepending garbage to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a2226498177022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 83, + "comment" : "prepending garbage to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304922252500022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 84, + "comment" : "appending garbage to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d2223022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650004deadbeef02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 85, + "comment" : "truncated length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3024028102206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 86, + "comment" : "including undefined tags to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304b2227aa02aabb022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 87, + "comment" : "using composition with indefinite length for r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30492280022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 88, + "comment" : "using composition with wrong tag for r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30492280032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 89, + "comment" : "Replacing r with NULL", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3024050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 90, + "comment" : "changing tag value of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 91, + "comment" : "changing tag value of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045012100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 92, + "comment" : "changing tag value of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 93, + "comment" : "changing tag value of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045042100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 94, + "comment" : "changing tag value of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045ff2100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 95, + "comment" : "dropping value of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3024020002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 96, + "comment" : "using composition for r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304922250201000220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 97, + "comment" : "modifying first byte of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022102813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 98, + "comment" : "modifying last byte of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323e502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 99, + "comment" : "truncated r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3044022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832302206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 100, + "comment" : "truncated r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30440220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 101, + "comment" : "r of size 4130 to check for overflows", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "308210480282102200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 102, + "comment" : "leading ff in r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30460222ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 103, + "comment" : "replaced r by infinity", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "302509018002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 104, + "comment" : "replacing r with zero", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "302502010002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 105, + "comment" : "flipped bit 0 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31bb", + "result" : "invalid" + }, + { + "tcId" : 106, + "comment" : "flipped bit 32 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a456eb31ba", + "result" : "invalid" + }, + { + "tcId" : 107, + "comment" : "flipped bit 48 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f713a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 108, + "comment" : "flipped bit 64 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758001d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 109, + "comment" : "length of s uses long form encoding", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 110, + "comment" : "length of s contains a leading 0", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028200206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 111, + "comment" : "length of s uses 33 instead of 32", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 112, + "comment" : "length of s uses 31 instead of 32", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 113, + "comment" : "uint32 overflow in length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028501000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 114, + "comment" : "uint64 overflow in length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304e022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502890100000000000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 115, + "comment" : "length of s = 2**31 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502847fffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 116, + "comment" : "length of s = 2**31", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284800000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 117, + "comment" : "length of s = 2**32 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284ffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 118, + "comment" : "length of s = 2**40 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650285ffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 119, + "comment" : "length of s = 2**64 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650288ffffffffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 120, + "comment" : "incorrect length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 121, + "comment" : "replaced s by an indefinite length tag without termination", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502806ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 122, + "comment" : "appending 0's to s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 123, + "comment" : "prepending 0's to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022200006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 124, + "comment" : "appending null value to s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", + "result" : "invalid" + }, + { + "tcId" : 125, + "comment" : "prepending garbage to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222549817702206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 126, + "comment" : "prepending garbage to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652224250002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 127, + "comment" : "appending garbage to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", + "result" : "invalid" + }, + { + "tcId" : 128, + "comment" : "truncated length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281", + "result" : "invalid" + }, + { + "tcId" : 129, + "comment" : "including undefined tags to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304b022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652226aa02aabb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 130, + "comment" : "using composition with indefinite length for s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 131, + "comment" : "using composition with wrong tag for s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228003206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 132, + "comment" : "Replacing s with NULL", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650500", + "result" : "invalid" + }, + { + "tcId" : 133, + "comment" : "changing tag value of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236500206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 134, + "comment" : "changing tag value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236501206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 135, + "comment" : "changing tag value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236503206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 136, + "comment" : "changing tag value of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236504206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 137, + "comment" : "changing tag value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365ff206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 138, + "comment" : "dropping value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650200", + "result" : "invalid" + }, + { + "tcId" : 139, + "comment" : "using composition for s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222402016f021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 140, + "comment" : "modifying first byte of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206df18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 141, + "comment" : "modifying last byte of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb313a", + "result" : "invalid" + }, + { + "tcId" : 142, + "comment" : "truncated s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", + "result" : "invalid" + }, + { + "tcId" : 143, + "comment" : "truncated s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 144, + "comment" : "s of size 4129 to check for overflows", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30821048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028210216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid" + }, + { + "tcId" : 145, + "comment" : "leading ff in s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 146, + "comment" : "replaced s by infinity", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365090180", + "result" : "invalid" + }, + { + "tcId" : 147, + "comment" : "replacing s with zero", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365020100", + "result" : "invalid" + }, + { + "tcId" : 148, + "comment" : "replaced r by r + n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478583b90deabca4b05c4574e49b5899b964a602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 149, + "comment" : "replaced r by r - n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "30440220813ef79ccefa9a56f7ba805f0e47858643b030ef461f1bcdf53fde3ef94ce22402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 150, + "comment" : "replaced r by r + 256 * n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "304602220100813ef79ccefa9a56f7ba805f0e47843fad3bf4853e07f7c98770c99bffc4646502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 151, + "comment" : "replaced r by -r", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30450221ff7ec10863310565a908457fa0f1b87a7b01a0f22a0a9843f64aedc334367cdc9b02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 152, + "comment" : "replaced r by n - r", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "304402207ec10863310565a908457fa0f1b87a79bc4fcf10b9e0e4320ac021c106b31ddc02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 153, + "comment" : "replaced r by -n - r", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30450221fe7ec10863310565a908457fa0f1b87a7c46f215435b4fa3ba8b1b64a766469b5a02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 154, + "comment" : "replaced r by r + 2**256", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 155, + "comment" : "replaced r by r + 2**320", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "304d0229010000000000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 156, + "comment" : "replaced s by s + n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b7fc1e197d8aebe203c96c87232272172fb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 157, + "comment" : "replaced s by s - n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b824c83de0b502cdfc51723b51886b4f07902206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 158, + "comment" : "replaced s by s + 256 * n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "3046022201006ff18a52dcc0336f7af62400a6dd9a3bb60fa1a14815bbc0a954a0758d2c72ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 159, + "comment" : "replaced s by -s", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30440220900e75ad233fcc908509dbff5922647ef8cd450e008a7fff2909ec5aa914ce4602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 160, + "comment" : "replaced s by -n - s", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30450221fe900e75ad233fcc908509dbff592264803e1e68275141dfc369378dcdd8de8d0502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 161, + "comment" : "replaced s by s + 2**256", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 162, + "comment" : "replaced s by s - 2**256", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 163, + "comment" : "replaced s by s + 2**320", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "304d02290100000000000000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 164, + "comment" : "Signature with special case values r=0 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100020100", + "result" : "invalid" + }, + { + "tcId" : 165, + "comment" : "Signature with special case values r=0 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100020101", + "result" : "invalid" + }, + { + "tcId" : 166, + "comment" : "Signature with special case values r=0 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201000201ff", + "result" : "invalid" + }, + { + "tcId" : 167, + "comment" : "Signature with special case values r=0 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 168, + "comment" : "Signature with special case values r=0 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 169, + "comment" : "Signature with special case values r=0 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 170, + "comment" : "Signature with special case values r=0 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 171, + "comment" : "Signature with special case values r=0 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 172, + "comment" : "Signature with special case values r=1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101020100", + "result" : "invalid" + }, + { + "tcId" : 173, + "comment" : "Signature with special case values r=1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101020101", + "result" : "invalid" + }, + { + "tcId" : 174, + "comment" : "Signature with special case values r=1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201010201ff", + "result" : "invalid" + }, + { + "tcId" : 175, + "comment" : "Signature with special case values r=1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 176, + "comment" : "Signature with special case values r=1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 177, + "comment" : "Signature with special case values r=1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 178, + "comment" : "Signature with special case values r=1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 179, + "comment" : "Signature with special case values r=1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 180, + "comment" : "Signature with special case values r=-1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff020100", + "result" : "invalid" + }, + { + "tcId" : 181, + "comment" : "Signature with special case values r=-1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff020101", + "result" : "invalid" + }, + { + "tcId" : 182, + "comment" : "Signature with special case values r=-1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff0201ff", + "result" : "invalid" + }, + { + "tcId" : 183, + "comment" : "Signature with special case values r=-1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 184, + "comment" : "Signature with special case values r=-1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 185, + "comment" : "Signature with special case values r=-1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 186, + "comment" : "Signature with special case values r=-1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 187, + "comment" : "Signature with special case values r=-1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 188, + "comment" : "Signature with special case values r=n and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020100", + "result" : "invalid" + }, + { + "tcId" : 189, + "comment" : "Signature with special case values r=n and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101", + "result" : "invalid" + }, + { + "tcId" : 190, + "comment" : "Signature with special case values r=n and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410201ff", + "result" : "invalid" + }, + { + "tcId" : 191, + "comment" : "Signature with special case values r=n and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 192, + "comment" : "Signature with special case values r=n and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 193, + "comment" : "Signature with special case values r=n and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 194, + "comment" : "Signature with special case values r=n and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 195, + "comment" : "Signature with special case values r=n and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 196, + "comment" : "Signature with special case values r=n - 1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020100", + "result" : "invalid" + }, + { + "tcId" : 197, + "comment" : "Signature with special case values r=n - 1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020101", + "result" : "invalid" + }, + { + "tcId" : 198, + "comment" : "Signature with special case values r=n - 1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641400201ff", + "result" : "invalid" + }, + { + "tcId" : 199, + "comment" : "Signature with special case values r=n - 1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 200, + "comment" : "Signature with special case values r=n - 1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 201, + "comment" : "Signature with special case values r=n - 1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 202, + "comment" : "Signature with special case values r=n - 1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 203, + "comment" : "Signature with special case values r=n - 1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 204, + "comment" : "Signature with special case values r=n + 1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020100", + "result" : "invalid" + }, + { + "tcId" : 205, + "comment" : "Signature with special case values r=n + 1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020101", + "result" : "invalid" + }, + { + "tcId" : 206, + "comment" : "Signature with special case values r=n + 1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641420201ff", + "result" : "invalid" + }, + { + "tcId" : 207, + "comment" : "Signature with special case values r=n + 1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 208, + "comment" : "Signature with special case values r=n + 1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 209, + "comment" : "Signature with special case values r=n + 1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 210, + "comment" : "Signature with special case values r=n + 1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 211, + "comment" : "Signature with special case values r=n + 1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 212, + "comment" : "Signature with special case values r=p and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020100", + "result" : "invalid" + }, + { + "tcId" : 213, + "comment" : "Signature with special case values r=p and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020101", + "result" : "invalid" + }, + { + "tcId" : 214, + "comment" : "Signature with special case values r=p and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0201ff", + "result" : "invalid" + }, + { + "tcId" : 215, + "comment" : "Signature with special case values r=p and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 216, + "comment" : "Signature with special case values r=p and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 217, + "comment" : "Signature with special case values r=p and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 218, + "comment" : "Signature with special case values r=p and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 219, + "comment" : "Signature with special case values r=p and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 220, + "comment" : "Signature with special case values r=p + 1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020100", + "result" : "invalid" + }, + { + "tcId" : 221, + "comment" : "Signature with special case values r=p + 1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020101", + "result" : "invalid" + }, + { + "tcId" : 222, + "comment" : "Signature with special case values r=p + 1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc300201ff", + "result" : "invalid" + }, + { + "tcId" : 223, + "comment" : "Signature with special case values r=p + 1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 224, + "comment" : "Signature with special case values r=p + 1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 225, + "comment" : "Signature with special case values r=p + 1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 226, + "comment" : "Signature with special case values r=p + 1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 227, + "comment" : "Signature with special case values r=p + 1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 228, + "comment" : "Signature encoding contains incorrect types: r=0, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3008020100090380fe01", + "result" : "invalid" + }, + { + "tcId" : 229, + "comment" : "Signature encoding contains incorrect types: r=0, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100090142", + "result" : "invalid" + }, + { + "tcId" : 230, + "comment" : "Signature encoding contains incorrect types: r=0, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100010101", + "result" : "invalid" + }, + { + "tcId" : 231, + "comment" : "Signature encoding contains incorrect types: r=0, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100010100", + "result" : "invalid" + }, + { + "tcId" : 232, + "comment" : "Signature encoding contains incorrect types: r=0, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201000500", + "result" : "invalid" + }, + { + "tcId" : 233, + "comment" : "Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201000c00", + "result" : "invalid" + }, + { + "tcId" : 234, + "comment" : "Signature encoding contains incorrect types: r=0, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201000c0130", + "result" : "invalid" + }, + { + "tcId" : 235, + "comment" : "Signature encoding contains incorrect types: r=0, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201003000", + "result" : "invalid" + }, + { + "tcId" : 236, + "comment" : "Signature encoding contains incorrect types: r=0, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201003003020100", + "result" : "invalid" + }, + { + "tcId" : 237, + "comment" : "Signature encoding contains incorrect types: r=1, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3008020101090380fe01", + "result" : "invalid" + }, + { + "tcId" : 238, + "comment" : "Signature encoding contains incorrect types: r=1, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101090142", + "result" : "invalid" + }, + { + "tcId" : 239, + "comment" : "Signature encoding contains incorrect types: r=1, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101010101", + "result" : "invalid" + }, + { + "tcId" : 240, + "comment" : "Signature encoding contains incorrect types: r=1, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101010100", + "result" : "invalid" + }, + { + "tcId" : 241, + "comment" : "Signature encoding contains incorrect types: r=1, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201010500", + "result" : "invalid" + }, + { + "tcId" : 242, + "comment" : "Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201010c00", + "result" : "invalid" + }, + { + "tcId" : 243, + "comment" : "Signature encoding contains incorrect types: r=1, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201010c0130", + "result" : "invalid" + }, + { + "tcId" : 244, + "comment" : "Signature encoding contains incorrect types: r=1, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201013000", + "result" : "invalid" + }, + { + "tcId" : 245, + "comment" : "Signature encoding contains incorrect types: r=1, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201013003020100", + "result" : "invalid" + }, + { + "tcId" : 246, + "comment" : "Signature encoding contains incorrect types: r=-1, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201ff090380fe01", + "result" : "invalid" + }, + { + "tcId" : 247, + "comment" : "Signature encoding contains incorrect types: r=-1, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff090142", + "result" : "invalid" + }, + { + "tcId" : 248, + "comment" : "Signature encoding contains incorrect types: r=-1, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff010101", + "result" : "invalid" + }, + { + "tcId" : 249, + "comment" : "Signature encoding contains incorrect types: r=-1, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff010100", + "result" : "invalid" + }, + { + "tcId" : 250, + "comment" : "Signature encoding contains incorrect types: r=-1, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201ff0500", + "result" : "invalid" + }, + { + "tcId" : 251, + "comment" : "Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201ff0c00", + "result" : "invalid" + }, + { + "tcId" : 252, + "comment" : "Signature encoding contains incorrect types: r=-1, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff0c0130", + "result" : "invalid" + }, + { + "tcId" : 253, + "comment" : "Signature encoding contains incorrect types: r=-1, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201ff3000", + "result" : "invalid" + }, + { + "tcId" : 254, + "comment" : "Signature encoding contains incorrect types: r=-1, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201ff3003020100", + "result" : "invalid" + }, + { + "tcId" : 255, + "comment" : "Signature encoding contains incorrect types: r=n, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090380fe01", + "result" : "invalid" + }, + { + "tcId" : 256, + "comment" : "Signature encoding contains incorrect types: r=n, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090142", + "result" : "invalid" + }, + { + "tcId" : 257, + "comment" : "Signature encoding contains incorrect types: r=n, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010101", + "result" : "invalid" + }, + { + "tcId" : 258, + "comment" : "Signature encoding contains incorrect types: r=n, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010100", + "result" : "invalid" + }, + { + "tcId" : 259, + "comment" : "Signature encoding contains incorrect types: r=n, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410500", + "result" : "invalid" + }, + { + "tcId" : 260, + "comment" : "Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c00", + "result" : "invalid" + }, + { + "tcId" : 261, + "comment" : "Signature encoding contains incorrect types: r=n, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c0130", + "result" : "invalid" + }, + { + "tcId" : 262, + "comment" : "Signature encoding contains incorrect types: r=n, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413000", + "result" : "invalid" + }, + { + "tcId" : 263, + "comment" : "Signature encoding contains incorrect types: r=n, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413003020100", + "result" : "invalid" + }, + { + "tcId" : 264, + "comment" : "Signature encoding contains incorrect types: r=p, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090380fe01", + "result" : "invalid" + }, + { + "tcId" : 265, + "comment" : "Signature encoding contains incorrect types: r=p, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090142", + "result" : "invalid" + }, + { + "tcId" : 266, + "comment" : "Signature encoding contains incorrect types: r=p, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010101", + "result" : "invalid" + }, + { + "tcId" : 267, + "comment" : "Signature encoding contains incorrect types: r=p, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010100", + "result" : "invalid" + }, + { + "tcId" : 268, + "comment" : "Signature encoding contains incorrect types: r=p, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0500", + "result" : "invalid" + }, + { + "tcId" : 269, + "comment" : "Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c00", + "result" : "invalid" + }, + { + "tcId" : 270, + "comment" : "Signature encoding contains incorrect types: r=p, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c0130", + "result" : "invalid" + }, + { + "tcId" : 271, + "comment" : "Signature encoding contains incorrect types: r=p, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3000", + "result" : "invalid" + }, + { + "tcId" : 272, + "comment" : "Signature encoding contains incorrect types: r=p, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3003020100", + "result" : "invalid" + }, + { + "tcId" : 273, + "comment" : "Signature encoding contains incorrect types: r=0.25, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300a090380fe01090380fe01", + "result" : "invalid" + }, + { + "tcId" : 274, + "comment" : "Signature encoding contains incorrect types: r=nan, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006090142090142", + "result" : "invalid" + }, + { + "tcId" : 275, + "comment" : "Signature encoding contains incorrect types: r=True, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010101010101", + "result" : "invalid" + }, + { + "tcId" : 276, + "comment" : "Signature encoding contains incorrect types: r=False, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010100010100", + "result" : "invalid" + }, + { + "tcId" : 277, + "comment" : "Signature encoding contains incorrect types: r=Null, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300405000500", + "result" : "invalid" + }, + { + "tcId" : 278, + "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30040c000c00", + "result" : "invalid" + }, + { + "tcId" : 279, + "comment" : "Signature encoding contains incorrect types: r=\"0\", s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060c01300c0130", + "result" : "invalid" + }, + { + "tcId" : 280, + "comment" : "Signature encoding contains incorrect types: r=empty list, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300430003000", + "result" : "invalid" + }, + { + "tcId" : 281, + "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300a30030201003003020100", + "result" : "invalid" + }, + { + "tcId" : 282, + "comment" : "Signature encoding contains incorrect types: r=0.25, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3008090380fe01020100", + "result" : "invalid" + }, + { + "tcId" : 283, + "comment" : "Signature encoding contains incorrect types: r=nan, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006090142020100", + "result" : "invalid" + }, + { + "tcId" : 284, + "comment" : "Signature encoding contains incorrect types: r=True, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010101020100", + "result" : "invalid" + }, + { + "tcId" : 285, + "comment" : "Signature encoding contains incorrect types: r=False, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010100020100", + "result" : "invalid" + }, + { + "tcId" : 286, + "comment" : "Signature encoding contains incorrect types: r=Null, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050500020100", + "result" : "invalid" + }, + { + "tcId" : 287, + "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050c00020100", + "result" : "invalid" + }, + { + "tcId" : 288, + "comment" : "Signature encoding contains incorrect types: r=\"0\", s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060c0130020100", + "result" : "invalid" + }, + { + "tcId" : 289, + "comment" : "Signature encoding contains incorrect types: r=empty list, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30053000020100", + "result" : "invalid" + }, + { + "tcId" : 290, + "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30083003020100020100", + "result" : "invalid" + }, + { + "tcId" : 291, + "comment" : "Edge case for Shamir multiplication", + "flags" : [ + "EdgeCaseShamirMultiplication" + ], + "msg" : "3235353835", + "sig" : "3045022100dd1b7d09a7bd8218961034a39a87fecf5314f00c4d25eb58a07ac85e85eab516022035138c401ef8d3493d65c9002fe62b43aee568731b744548358996d9cc427e06", + "result" : "valid" + }, + { + "tcId" : 292, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "343236343739373234", + "sig" : "304502210095c29267d972a043d955224546222bba343fc1d4db0fec262a33ac61305696ae02206edfe96713aed56f8a28a6653f57e0b829712e5eddc67f34682b24f0676b2640", + "result" : "valid" + }, + { + "tcId" : 293, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "37313338363834383931", + "sig" : "3044022028f94a894e92024699e345fe66971e3edcd050023386135ab3939d550898fb25022032963e5bd41fa5911ed8f37deb86dae0a762bb6121c894615083c5d95ea01db3", + "result" : "valid" + }, + { + "tcId" : 294, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130333539333331363638", + "sig" : "3045022100be26b18f9549f89f411a9b52536b15aa270b84548d0e859a1952a27af1a77ac6022070c1d4fa9cd03cc8eaa8d506edb97eed7b8358b453c88aefbb880a3f0e8d472f", + "result" : "valid" + }, + { + "tcId" : 295, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33393439343031323135", + "sig" : "3045022100b1a4b1478e65cc3eafdf225d1298b43f2da19e4bcff7eacc0a2e98cd4b74b1140220179aa31e304cc142cf5073171751b28f3f5e0fa88c994e7c55f1bc07b8d56c16", + "result" : "valid" + }, + { + "tcId" : 296, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31333434323933303739", + "sig" : "30440220325332021261f1bd18f2712aa1e2252da23796da8a4b1ff6ea18cafec7e171f2022040b4f5e287ee61fc3c804186982360891eaa35c75f05a43ecd48b35d984a6648", + "result" : "valid" + }, + { + "tcId" : 297, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33373036323131373132", + "sig" : "3045022100a23ad18d8fc66d81af0903890cbd453a554cb04cdc1a8ca7f7f78e5367ed88a0022023e3eb2ce1c04ea748c389bd97374aa9413b9268851c04dcd9f88e78813fee56", + "result" : "valid" + }, + { + "tcId" : 298, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "333433363838373132", + "sig" : "304402202bdea41cda63a2d14bf47353bd20880a690901de7cd6e3cc6d8ed5ba0cdb109102203cea66bccfc9f9bf8c7ca4e1c1457cc9145e13e936d90b3d9c7786b8b26cf4c7", + "result" : "valid" + }, + { + "tcId" : 299, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31333531353330333730", + "sig" : "3045022100d7cd76ec01c1b1079eba9e2aa2a397243c4758c98a1ba0b7404a340b9b00ced602203575001e19d922e6de8b3d6c84ea43b5c3338106cf29990134e7669a826f78e6", + "result" : "valid" + }, + { + "tcId" : 300, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36353533323033313236", + "sig" : "3045022100a872c744d936db21a10c361dd5c9063355f84902219652f6fc56dc95a7139d960220400df7575d9756210e9ccc77162c6b593c7746cfb48ac263c42750b421ef4bb9", + "result" : "valid" + }, + { + "tcId" : 301, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31353634333436363033", + "sig" : "30450221009fa9afe07752da10b36d3afcd0fe44bfc40244d75203599cf8f5047fa3453854022050e0a7c013bfbf51819736972d44b4b56bc2a2b2c180df6ec672df171410d77a", + "result" : "valid" + }, + { + "tcId" : 302, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "34343239353339313137", + "sig" : "3045022100885640384d0d910efb177b46be6c3dc5cac81f0b88c3190bb6b5f99c2641f2050220738ed9bff116306d9caa0f8fc608be243e0b567779d8dab03e8e19d553f1dc8e", + "result" : "valid" + }, + { + "tcId" : 303, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130393533323631333531", + "sig" : "304402202d051f91c5a9d440c5676985710483bc4f1a6c611b10c95a2ff0363d90c2a45802206ddf94e6fba5be586833d0c53cf216ad3948f37953c26c1cf4968e9a9e8243dc", + "result" : "valid" + }, + { + "tcId" : 304, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35393837333530303431", + "sig" : "3045022100f3ac2523967482f53d508522712d583f4379cd824101ff635ea0935117baa54f022027f10812227397e02cea96fb0e680761636dab2b080d1fc5d11685cbe8500cfe", + "result" : "valid" + }, + { + "tcId" : 305, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33343633303036383738", + "sig" : "304502210096447cf68c3ab7266ed7447de3ac52fed7cc08cbdfea391c18a9b8ab370bc91302200f5e7874d3ac0e918f01c885a1639177c923f8660d1ceba1ca1f301bc675cdbc", + "result" : "valid" + }, + { + "tcId" : 306, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "39383137333230323837", + "sig" : "30440220530a0832b691da0b5619a0b11de6877f3c0971baaa68ed122758c29caaf46b7202206c89e44f5eb33060ea4b46318c39138eaedec72de42ba576579a6a4690e339f3", + "result" : "valid" + }, + { + "tcId" : 307, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33323232303431303436", + "sig" : "30450221009c54c25500bde0b92d72d6ec483dc2482f3654294ca74de796b681255ed58a770220677453c6b56f527631c9f67b3f3eb621fd88582b4aff156d2f1567d6211a2a33", + "result" : "valid" + }, + { + "tcId" : 308, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36363636333037313034", + "sig" : "3045022100e7909d41439e2f6af29136c7348ca2641a2b070d5b64f91ea9da7070c7a2618b022042d782f132fa1d36c2c88ba27c3d678d80184a5d1eccac7501f0b47e3d205008", + "result" : "valid" + }, + { + "tcId" : 309, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31303335393531383938", + "sig" : "304402205924873209593135a4c3da7bb381227f8a4b6aa9f34fe5bb7f8fbc131a039ffe02201f1bb11b441c8feaa40f44213d9a405ed792d59fb49d5bcdd9a4285ae5693022", + "result" : "valid" + }, + { + "tcId" : 310, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31383436353937313935", + "sig" : "3045022100eeb692c9b262969b231c38b5a7f60649e0c875cd64df88f33aa571fa3d29ab0e0220218b3a1eb06379c2c18cf51b06430786d1c64cd2d24c9b232b23e5bac7989acd", + "result" : "valid" + }, + { + "tcId" : 311, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33313336303436313839", + "sig" : "3045022100a40034177f36091c2b653684a0e3eb5d4bff18e4d09f664c2800e7cafda1daf802203a3ec29853704e52031c58927a800a968353adc3d973beba9172cbbeab4dd149", + "result" : "valid" + }, + { + "tcId" : 312, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "32363633373834323534", + "sig" : "3045022100b5d795cc75cea5c434fa4185180cd6bd21223f3d5a86da6670d71d95680dadbf022054e4d8810a001ecbb9f7ca1c2ebfdb9d009e9031a431aca3c20ab4e0d1374ec1", + "result" : "valid" + }, + { + "tcId" : 313, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31363532313030353234", + "sig" : "3044022007dc2478d43c1232a4595608c64426c35510051a631ae6a5a6eb1161e57e42e102204a59ea0fdb72d12165cea3bf1ca86ba97517bd188db3dbd21a5a157850021984", + "result" : "valid" + }, + { + "tcId" : 314, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35373438303831363936", + "sig" : "3045022100ddd20c4a05596ca868b558839fce9f6511ddd83d1ccb53f82e5269d559a0155202205b91734729d93093ff22123c4a25819d7feb66a250663fc780cb66fc7b6e6d17", + "result" : "valid" + }, + { + "tcId" : 315, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36333433393133343638", + "sig" : "30450221009cde6e0ede0a003f02fda0a01b59facfe5dec063318f279ce2de7a9b1062f7b702202886a5b8c679bdf8224c66f908fd6205492cb70b0068d46ae4f33a4149b12a52", + "result" : "valid" + }, + { + "tcId" : 316, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31353431313033353938", + "sig" : "3045022100c5771016d0dd6357143c89f684cd740423502554c0c59aa8c99584f1ff38f609022054b405f4477546686e464c5463b4fd4190572e58d0f7e7357f6e61947d20715c", + "result" : "valid" + }, + { + "tcId" : 317, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130343738353830313238", + "sig" : "3045022100a24ebc0ec224bd67ae397cbe6fa37b3125adbd34891abe2d7c7356921916dfe6022034f6eb6374731bbbafc4924fb8b0bdcdda49456d724cdae6178d87014cb53d8c", + "result" : "valid" + }, + { + "tcId" : 318, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130353336323835353638", + "sig" : "304402202557d64a7aee2e0931c012e4fea1cd3a2c334edae68cdeb7158caf21b68e5a2402207f06cdbb6a90023a973882ed97b080fe6b05af3ec93db6f1a4399a69edf7670d", + "result" : "valid" + }, + { + "tcId" : 319, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "393533393034313035", + "sig" : "3045022100c4f2eccbb6a24350c8466450b9d61b207ee359e037b3dcedb42a3f2e6dd6aeb502203263c6b59a2f55cdd1c6e14894d5e5963b28bc3e2469ac9ba1197991ca7ff9c7", + "result" : "valid" + }, + { + "tcId" : 320, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "393738383438303339", + "sig" : "3045022100eff04781c9cbcd162d0a25a6e2ebcca43506c523385cb515d49ea38a1b12fcad022015acd73194c91a95478534f23015b672ebed213e45424dd2c8e26ac8b3eb34a5", + "result" : "valid" + }, + { + "tcId" : 321, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33363130363732343432", + "sig" : "3045022100f58b4e3110a64bf1b5db97639ee0e5a9c8dfa49dc59b679891f520fdf0584c8702202cd8fe51888aee9db3e075440fd4db73b5c732fb87b510e97093d66415f62af7", + "result" : "valid" + }, + { + "tcId" : 322, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31303534323430373035", + "sig" : "3045022100f8abecaa4f0c502de4bf5903d48417f786bf92e8ad72fec0bd7fcb7800c0bbe302204c7f9e231076a30b7ae36b0cebe69ccef1cd194f7cce93a5588fd6814f437c0e", + "result" : "valid" + }, + { + "tcId" : 323, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35313734343438313937", + "sig" : "304402205d5b38bd37ad498b2227a633268a8cca879a5c7c94a4e416bd0a614d09e606d2022012b8d664ea9991062ecbb834e58400e25c46007af84f6007d7f1685443269afe", + "result" : "valid" + }, + { + "tcId" : 324, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31393637353631323531", + "sig" : "304402200c1cd9fe4034f086a2b52d65b9d3834d72aebe7f33dfe8f976da82648177d8e3022013105782e3d0cfe85c2778dec1a848b27ac0ae071aa6da341a9553a946b41e59", + "result" : "valid" + }, + { + "tcId" : 325, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33343437323533333433", + "sig" : "3045022100ae7935fb96ff246b7b5d5662870d1ba587b03d6e1360baf47988b5c02ccc1a5b02205f00c323272083782d4a59f2dfd65e49de0693627016900ef7e61428056664b3", + "result" : "valid" + }, + { + "tcId" : 326, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "333638323634333138", + "sig" : "3044022000a134b5c6ccbcefd4c882b945baeb4933444172795fa6796aae1490675470980220566e46105d24d890151e3eea3ebf88f5b92b3f5ec93a217765a6dcbd94f2c55b", + "result" : "valid" + }, + { + "tcId" : 327, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33323631313938363038", + "sig" : "304402202e4721363ad3992c139e5a1c26395d2c2d777824aa24fde075e0d7381171309d0220740f7c494418e1300dd4512f782a58800bff6a7abdfdd20fbbd4f05515ca1a4f", + "result" : "valid" + }, + { + "tcId" : 328, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "39363738373831303934", + "sig" : "304402206852e9d3cd9fe373c2d504877967d365ab1456707b6817a042864694e1960ccf0220064b27ea142b30887b84c86adccb2fa39a6911ad21fc7e819f593be52bc4f3bd", + "result" : "valid" + }, + { + "tcId" : 329, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "34393538383233383233", + "sig" : "30440220188a8c5648dc79eace158cf886c62b5468f05fd95f03a7635c5b4c31f09af4c5022036361a0b571a00c6cd5e686ccbfcfa703c4f97e48938346d0c103fdc76dc5867", + "result" : "valid" + }, + { + "tcId" : 330, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "383234363337383337", + "sig" : "3045022100a74f1fb9a8263f62fc4416a5b7d584f4206f3996bb91f6fc8e73b9e92bad0e1302206815032e8c7d76c3ab06a86f33249ce9940148cb36d1f417c2e992e801afa3fa", + "result" : "valid" + }, + { + "tcId" : 331, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3131303230383333373736", + "sig" : "3044022007244865b72ff37e62e3146f0dc14682badd7197799135f0b00ade7671742bfe02200d80c2238edb4e4a7a86a8c57ca9af1711f406f7f5da0299aa04e2932d960754", + "result" : "valid" + }, + { + "tcId" : 332, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "313333383731363438", + "sig" : "3045022100da7fdd05b5badabd619d805c4ee7d9a84f84ddd5cf9c5bf4d4338140d689ef08022028f1cf4fa1c3c5862cfa149c0013cf5fe6cf5076cae000511063e7de25bb38e5", + "result" : "valid" + }, + { + "tcId" : 333, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "333232313434313632", + "sig" : "3045022100d3027c656f6d4fdfd8ede22093e3c303b0133c340d615e7756f6253aea927238022009aef060c8e4cef972974011558df144fed25ca69ae8d0b2eaf1a8feefbec417", + "result" : "valid" + }, + { + "tcId" : 334, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130363836363535353436", + "sig" : "304402200bf6c0188dc9571cd0e21eecac5fbb19d2434988e9cc10244593ef3a98099f6902204864a562661f9221ec88e3dd0bc2f6e27ac128c30cc1a80f79ec670a22b042ee", + "result" : "valid" + }, + { + "tcId" : 335, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3632313535323436", + "sig" : "3045022100ae459640d5d1179be47a47fa538e16d94ddea5585e7a244804a51742c686443a02206c8e30e530a634fae80b3ceb062978b39edbe19777e0a24553b68886181fd897", + "result" : "valid" + }, + { + "tcId" : 336, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "37303330383138373734", + "sig" : "304402201cf3517ba3bf2ab8b9ead4ebb6e866cb88a1deacb6a785d3b63b483ca02ac4950220249a798b73606f55f5f1c70de67cb1a0cff95d7dc50b3a617df861bad3c6b1c9", + "result" : "valid" + }, + { + "tcId" : 337, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35393234353233373434", + "sig" : "3045022100e69b5238265ea35d77e4dd172288d8cea19810a10292617d5976519dc5757cb802204b03c5bc47e826bdb27328abd38d3056d77476b2130f3df6ec4891af08ba1e29", + "result" : "valid" + }, + { + "tcId" : 338, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31343935353836363231", + "sig" : "304402205f9d7d7c870d085fc1d49fff69e4a275812800d2cf8973e7325866cb40fa2b6f02206d1f5491d9f717a597a15fd540406486d76a44697b3f0d9d6dcef6669f8a0a56", + "result" : "valid" + }, + { + "tcId" : 339, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "34303035333134343036", + "sig" : "304402200a7d5b1959f71df9f817146ee49bd5c89b431e7993e2fdecab6858957da685ae02200f8aad2d254690bdc13f34a4fec44a02fd745a422df05ccbb54635a8b86b9609", + "result" : "valid" + }, + { + "tcId" : 340, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33303936343537353132", + "sig" : "3044022079e88bf576b74bc07ca142395fda28f03d3d5e640b0b4ff0752c6d94cd553408022032cea05bd2d706c8f6036a507e2ab7766004f0904e2e5c5862749c0073245d6a", + "result" : "valid" + }, + { + "tcId" : 341, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "32373834303235363230", + "sig" : "30450221009d54e037a00212b377bc8874798b8da080564bbdf7e07591b861285809d01488022018b4e557667a82bd95965f0706f81a29243fbdd86968a7ebeb43069db3b18c7f", + "result" : "valid" + }, + { + "tcId" : 342, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "32363138373837343138", + "sig" : "304402202664f1ffa982fedbcc7cab1b8bc6e2cb420218d2a6077ad08e591ba9feab33bd022049f5c7cb515e83872a3d41b4cdb85f242ad9d61a5bfc01debfbb52c6c84ba728", + "result" : "valid" + }, + { + "tcId" : 343, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31363432363235323632", + "sig" : "304402205827518344844fd6a7de73cbb0a6befdea7b13d2dee4475317f0f18ffc81524b02204f5ccb4e0b488b5a5d760aacddb2d791970fe43da61eb30e2e90208a817e46db", + "result" : "valid" + }, + { + "tcId" : 344, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36383234313839343336", + "sig" : "304502210097ab19bd139cac319325869218b1bce111875d63fb12098a04b0cd59b6fdd3a30220431d9cea3a243847303cebda56476431d034339f31d785ee8852db4f040d4921", + "result" : "valid" + }, + { + "tcId" : 345, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "343834323435343235", + "sig" : "3044022052c683144e44119ae2013749d4964ef67509278f6d38ba869adcfa69970e123d02203479910167408f45bda420a626ec9c4ec711c1274be092198b4187c018b562ca", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", + "wx" : "07310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc362", + "wy" : "26a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEBzEPkKnq4UmghAL1QZSg97SsQnv42b1s\ndoEHHcR9w2ImptN6xG1h/WAMC/G/+HaJ7RF92msOWTGK4BChl6JsoA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 346, + "comment" : "k*G has a large x-coordinate", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30160211014551231950b75fc4402da1722fc9baeb020103", + "result" : "valid" + }, + { + "tcId" : 347, + "comment" : "r too large", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c020103", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", + "wx" : "00bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22", + "wy" : "705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvJfnWF7srUjhZoO8QJFwjhqTDGg/xHAB\n1LODWU8sTiJwWYnPadrq3U5OS4FR7YiN/sIPsBco2J1Ws/OPKunIxQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 348, + "comment" : "r,s are large", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f020103", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", + "wx" : "44ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252", + "wy" : "00b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERK0zmvvCHpq/e2AqXKU16jeBNbbRDYEx\nC92Ck9HfMlK2P/fQd0dw+P4dFyL6g6zQL0NOT8EQoMyPbd3TfVbEYw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 349, + "comment" : "r and s^-1 have a large Hamming weight", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e9a7582886089c62fb840cf3b83061cd1cff3ae4341808bb5bdee6191174177", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", + "wx" : "1260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c", + "wy" : "5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEmDCEiyeJE4a9RUb7eDDriO1TXxZaIHT\n7rrSHzfdh4xcmgwamt52c3qIEb1qf5KHyXjuOWqonBHkcinSzLVS8A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 350, + "comment" : "r and s^-1 have a large Hamming weight", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022024238e70b431b1a64efdf9032669939d4b77f249503fc6905feb7540dea3e6d2", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", + "wx" : "1877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce", + "wy" : "00821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGHcEW+JdNKHQYA+dXADQZFoqVDebbO76\n0ua/XCozUs6CGlMswXUe4dNtQcPWq06bFD5E7EbXNHjqanmlwOVBWQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 351, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020101020101", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", + "wx" : "455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50", + "wy" : "00aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERVQ5/MPS3uzt3q7OYOe9FzBPNuu2Aq31\noi4Ljx20alCuw4+yuvIh6ajRiHx79iIt0YNGNOdyYzFa9tI2CdBPdw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 352, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020101020102", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", + "wx" : "2e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece718", + "wy" : "0449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELh9GawJMDDrOJDfeCRJ/7QS3BvlLGaIb\nscKs81zs5xgESa41I9clNOlklyz9OzivC93ZYZ5a8iPk0aQPNM+fHQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 353, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020101020103", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", + "wx" : "008e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a23373", + "wy" : "26ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjnq9u9GN50UjdMGHmhw7AdEyYefUVxw7\nR6HHbFWiM3Mm7Yl81Rek9TSduAl4D20vK59imdi1qJB38RGacY/Xsw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 354, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020102020101", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", + "wx" : "7b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af19", + "wy" : "42117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEezM9Q0DT1xjdPmr/fee7+Lcr/WFshCAF\nYFKEI3a5rxlCEXxa/qx1XW83b8Yymn12BRuHEjpKXQvEpTk4DwPeew==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 355, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020102020102", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", + "wx" : "00d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e5", + "wy" : "03a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0wykoN22YWyFHTDO1oLED4PGJ1ih8nWZ\niNZ2OojxwOUDqA1UFWUNQSOXhOji+xI16f6ZHREuu4EYbL8Not46/w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 356, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020102020103", + "result" : "valid" + }, + { + "tcId" : 357, + "comment" : "r is larger than n", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364143020103", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", + "wx" : "48969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24", + "wy" : "00b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAESJabOZkSl7MyplLT7m4B6QmzmQTnH6I1\nSngwx3ULryS0AS0bgw0ZnMsfyXKzK/3tVfCc1i0lfl6ETiflehWU7A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 358, + "comment" : "s is larger than n", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30080201020203ed2979", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", + "wx" : "02ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee77", + "wy" : "7eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAu9NbWz9WpTx13hCJuPipsCkNsVYOWGf\nOPtEcrX57nd+tKzU7r2lzXKHX/0qLyYinC3GtGUAkZpDLIZznzroZg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 359, + "comment" : "small r and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30260202010102203a74e9d3a74e9d3a74e9d3a74e9d3a749f8ab3732a0a89604a09bce5b2916da4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", + "wx" : "464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584", + "wy" : "00b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERk9P9xVynK5Qcso72AHTGVtnrsZemwGq\n0gopQ9y8tYSxr9KdMaOaEdVwqhWXQ5s7LRlxvy8avxVDLQIHsQ0dCA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 360, + "comment" : "smallish r and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "302b02072d9b4d347952cc02200343aefc2f25d98b882e86eb9e30d55a6eb508b516510b34024ae4b6362330b3", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", + "wx" : "157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4c", + "wy" : "00deadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEFX+P3fNz619Jz88Q2LhTz5HLzX1mXDUi\nun3XON23mkzerfGlxEjqPJ9BkaiZmr/MdXrG1kVn7wcsR/7GE0Q7jw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 361, + "comment" : "100-bit r and small s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3031020d1033e67e37b32b445580bf4efc02206f906f906f906f906f906f906f906f8fe1cab5eefdb214061dce3b22789f1d6f", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", + "wx" : "0934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0", + "wy" : "00d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECTSlN0ZsB0MOLEj+uZC7Gft4zsyc7kJO\npNEwKRqiN/DU+S0jtGKAS1toxSVYwByZltv3J/zKu+7bliGkAFNa+g==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 362, + "comment" : "small r and 100 bit s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026020201010220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", + "wx" : "00d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c65", + "wy" : "4a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1u8gvmbIk/dBqb+Q2bdGddHCoxKWOXrL\nPvF0/QswDGVKDJVHjKADmRYtfw8tyJ79wrKKMPur4oWFcpWksMTiZQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 363, + "comment" : "100-bit r and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3031020d062522bbd3ecbe7c39e93e7c260220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", + "wx" : "00b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee06", + "wy" : "29c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEtykdFATgwMB9q5NyGJ9L1Y0s6qjRXt5U\nTZUUVFup7gYpyaY9XjCHacww7CdqQQ5kZKJ+6v2eWZ2xDwU6T+SoKQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 364, + "comment" : "r and s^-1 are close to n", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03640c1022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", + "wx" : "6e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8", + "wy" : "186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbigwMwXWQsy5I7ci6oayoLyONzXssm6E\nmxnJ92sv27gYboDWTYyrFk9SOPUxhGG/idTZbuZUTIFsdWaUd3Tg9g==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 365, + "comment" : "r and s are 64-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30160209009c44febf31c3594d020900839ed28247c2b06b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", + "wx" : "375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9", + "wy" : "00a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEN1vak/avkvtfj0sbXwU047r6s0y3rZ+5\n0Lci5KXDAqmgC584elo5YJeqIWL8W7z0pSYzcvaByU2lHpeZEgmQ/Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 366, + "comment" : "r and s are 100-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "301e020d09df8b682430beef6f5fd7c7cf020d0fd0a62e13778f4222a0d61c8a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", + "wx" : "00d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197", + "wy" : "00da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE11toIWur4DriV+lLTjvxxS9E498mbRUk\n/4xepp2nMZfaS/+e0cU/RJF6Z9e5eFmOid81nj1ZE+rqJPOuJZq8RA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 367, + "comment" : "r and s are 128-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30260211008a598e563a89f526c32ebec8de26367a02110084f633e2042630e99dd0f1e16f7a04bf", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", + "wx" : "78bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653", + "wy" : "118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeLzaFArtI9QwyyPD3A0B9CPbE07pSjqM\ntIPy3qwqxlMRgRT28zBF1OntkQcIUAe/vd+PWP56GiRF1mqZAEVHbg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 368, + "comment" : "r and s are 160-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "302e021500aa6eeb5823f7fa31b466bb473797f0d0314c0bdf021500e2977c479e6d25703cebbc6bd561938cc9d1bfb9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", + "wx" : "00bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c", + "wy" : "1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEu3n2GFf3Q7+htucRHOQJQ3claWnk4VFZ\nEj2VSKzDvmwfnZ+IYNz/0+s23Wwx/y5yJsIAnEyU2NfStWhr96vWdw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 369, + "comment" : "s == 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020101", + "result" : "valid" + }, + { + "tcId" : 370, + "comment" : "s == 0", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020100", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", + "wx" : "0093591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36", + "wy" : "073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEk1kYJ9nmcTtOn66mLHKyjf76aODAUWC1\n1qroj9LjbDYHP1VFrVr0EK8mr/9oZUz3LUXkk0iTESAyRzR6iQ9FGA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 371, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220419d981c515af8cc82545aac0c85e9e308fbb2eab6acd7ed497e0b4145a18fd9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", + "wx" : "31ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0da", + "wy" : "00da01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMe0wga7+AB62QCBp7izMGGKTe4WZUUTb\nqVA5Q1h78NraAbjMTfNPWrOxo1lhUgiUbl7jX5jud1uMzs2GzMFlDw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 372, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102201b21717ad71d23bbac60a9ad0baf75b063c9fdf52a00ebf99d022172910993c9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", + "wx" : "7dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea8", + "wy" : "54c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEff9m+phQn/Pi5RBF9DkFI9zNpDo7wohe\nWMJICQmQ7qhUx2wrmt62u1cYI+B/18ZchjnPnZBSYAZMjnZ1zm2YtA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 373, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202f588f66018f3dd14db3e28e77996487e32486b521ed8e5a20f06591951777e9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", + "wx" : "4280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a", + "wy" : "2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEQoBQmqtk7fwLSiln5MvOhJy1ROSncxPI\n5uzlefvXQgouif5cwZJ9VU5qO7FAM+p8kizXXLosdBX9q1LyCxhg8Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 374, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220091a08870ff4daf9123b30c20e8c4fc8505758dcf4074fcaff2170c9bfcf74f4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", + "wx" : "4f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb", + "wy" : "2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAET43xRRlOPE/D7qJtQ851tALWsXRy3cuy\nVLinmwvz2csqog2ChEyyZjROccp48q0np1oJ5bwPpX5O/Z1GWgiI2w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 375, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207c370dc0ce8c59a8b273cba44a7c1191fc3186dc03cab96b0567312df0d0b250", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", + "wx" : "009598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14", + "wy" : "122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElZilfdZ+w+FrWHoziqOhCjo5E7QaOvMu\nPtP/ATWMaxQSKBnt+AdLvFIffUzc6C/velFnBq/7odk9neqcyuGiBw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 376, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022070b59a7d1ee77a2f9e0491c2a7cfcd0ed04df4a35192f6132dcc668c79a6160e", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", + "wx" : "009171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e", + "wy" : "634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkXH+w8oggGvAhPEvB2CRG2CZC9gOWypx\nygOgSLIPg35jT9F4Y3YbKVjSvk4Un409ervcGL4D9FGrbBf6Ch+DMA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 377, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202736d76e412246e097148e2bf62915614eb7c428913a58eb5e9cd4674a9423de", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", + "wx" : "777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9", + "wy" : "00ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEd3yJMLbh0nEQD+aM6T8WP6N2EsX/9n9K\nYvw7r689F6ntc9hvYKUbXtkTU6OwVO3AqpLJ68vQt10Yj9yIJ5HWjQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 378, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204a1e12831fbe93627b02d6e7f24bccdd6ef4b2d0f46739eaf3b1eaf0ca117770", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", + "wx" : "00eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf470", + "wy" : "0603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE6rwkj2JuCmPh64HEPUYaOaHbqIHrbuIV\nKwfDLXG89HAGA8qoudM9sTr0TG777IoZjtYSSsnrF+qv0oJKVF7AAA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 379, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022006c778d4dfff7dee06ed88bc4e0ed34fc553aad67caf796f2a1c6487c1b2e877", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", + "wx" : "009f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001", + "wy" : "00f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEn3oTraFYpV+d3xpF8ETwc9m4ADDv3Pyf\nn1hBj7zq8AH4raAXUJD4DUcifWcTtnQPmgCR2IqDfQoc13tYqPKNcw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 380, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204de459ef9159afa057feb3ec40fef01c45b809f4ab296ea48c206d4249a2b451", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", + "wx" : "11c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4db", + "wy" : "00bbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEcTz5GHNAZtcBuoM6kxAkMPMPjxdnzxt\nZbQ2gm2ptNu763p35Mv9ogcJfENCNwX3LIBHbaPaxApIOwqw8urRyw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 381, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220745d294978007302033502e1acc48b63ae6500be43adbea1b258d6b423dbb416", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", + "wx" : "00e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4", + "wy" : "161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE4uGGgtUxI6oBpsXQCwxiPWcbRi6oC93W\nUif9UQWYiqQWGQez/SUESpSepByOLqhFncbxZUhWuLYbMVQ7sbRb2w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 382, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207b2a785e3896f59b2d69da57648e80ad3c133a750a2847fd2098ccd902042b6c", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", + "wx" : "0090f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197da", + "wy" : "00fadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkPjUynPeCKZWSq8AUke28P/peFBNzlJg\nX0a3w+Vhl9r62+Uo63DZ7n6g5wcC21T3IVFMe4YErCyyFPHey344PQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 383, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022071ae94a72ca896875e7aa4a4c3d29afdb4b35b6996273e63c47ac519256c5eb1", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", + "wx" : "00824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e", + "wy" : "3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEgkwZXHPP/fA40QG84Wh7XDthRvOVyIWX\nb3dTsjdrlI483vpvw0fRPk3LxjoLA6FlGAzSvhQxoM90zh6iUILSvA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 384, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102200fa527fa7343c0bc9ec35a6278bfbff4d83301b154fc4bd14aee7eb93445b5f9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", + "wx" : "2788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f", + "wy" : "30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ4ilLweOs/ICxPpz4NM4b6899r6FYANj\nb1mZItT1Jo8wtPIHyRm7315nqL5CZagXR1Szq6jxbldbd/9NWn62Tw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 385, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102206539c0adadd0525ff42622164ce9314348bd0863b4c80e936b23ca0414264671", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", + "wx" : "00d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b4150874", + "wy" : "01b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1TO3iaSviQ+nqCofrljEBPmmKlC0mtr6\ns0nFE7QVCHQBtBcbgD52s0qYYeEPe8KJoGb9Ab0p+EyYehCl+xjC1A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 386, + "comment" : "point at infinity during verify", + "flags" : [ + "PointDuplication", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", + "wx" : "3a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4", + "wy" : "221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOjFQeYyK9p0ebpgfOkVAK6HXMvS+gzDF\nFk9J4Q7FVbQiG9hCvF5Nl+/zcWX2DjmYpCTXKkUM+V6kd8eCh9A0Og==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 387, + "comment" : "edge case for signature malleability", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", + "wx" : "3b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e80", + "wy" : "0de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOzffX7NHxpoPF9hcDHyoNzaIOoJeExQ9\nD8/IEB6FHoAN48CQtsohulQ1FzMMBLEvlIxrrfFKY6v/3074x1NwJg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 388, + "comment" : "edge case for signature malleability", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", + "wx" : "00feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82c", + "wy" : "00e87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/rUWOw7OMP8+A8fVXEOA+i+oHuLANUlC\n/28IyZ0M2CzofeBe4b2gidPk4kj6D3IRAqz//fUOZUvigUM5md+Jfg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 389, + "comment" : "u1 == 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", + "wx" : "238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd4149228976", + "wy" : "40683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEI4ztABzyK4hT4C7cicvspQULp+BCp6d/\nk4LNQUkiiXZAaD0wlGQ4QPKViQqkwYqjm0HXfdD7O7JwDk+ewoT/wg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 390, + "comment" : "u1 == n - 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", + "wx" : "00961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35e", + "wy" : "00d2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElhz2SBfAbA5Rs8JzbJIv3hi9jEkG/Nf1\n72bEZ4UI817SxdGBaM++cPLxI710GSMruS3WkRPilBBhiJSBxaAnvw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 391, + "comment" : "u2 == 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", + "wx" : "13681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b10288", + "wy" : "16528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEE2gerhaM1Op88uKkXQUnQtEKn2TnloZ9\nvcuCn+CxAogWUodg0Xc3bAnfed45VXwynMF1NRes/+j6LsKYAmuDhA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 392, + "comment" : "u2 == n - 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", + "wx" : "5aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c2", + "wy" : "0091c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWqer/ba0CG1UMyXl15xulc5C+GbSu4SQ\nljOgS7GqMcKRyACIeUkF4dozM22HTi+RzPRcxZGFvt5d1vP3rKrhiw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 393, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", + "wx" : "277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e4", + "wy" : "64108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEACd3kbMFpFsrOVkLLwXTOSpsgYLO9OtU\nASDg9cIGw+RkEIIz+wuMOsiS15744Pv5LtEzrdtFVCcBMlhNxS7vQQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 394, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02201c940f313f92647be257eccd7ed08b0baef3f0478f25871b53635302c5f6314a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", + "wx" : "6efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1a", + "wy" : "00c75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbvoJK2jelGDwvMkZAFpfboDhnemJaL48\n0sdwqZSb+xrHXm5Qh9ZVDV+b6x555QKTB7wlUjXi1dyZJBrDq4hsSQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 395, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022015d94a85077b493f91cb7101ec63e1b01be58b594e855f45050a8c14062d689b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", + "wx" : "72d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058", + "wy" : "00e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEctShnE+dLPWEjqQERbcNRpa18C1jLAxl\nTMfX7rDG0FjoxM2ZQ+RZF0x6wB+nQhmOR+bBmmvbDE9sI3gxwbP5Qg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 396, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b1d27a7694c146244a5ad0bd0636d9d9ef3b9fb58385418d9c982105077d1b7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", + "wx" : "2a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e7402", + "wy" : "58f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKo6i9Q3M7QwhdXW9+nzUfRxvEABB7A41\nUSeUwb5+dAJY+MFxIu0wP9pxQ+tYvt5wKVtlMmYBOwsOvT8FMTf27A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 397, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202d85896b3eb9dbb5a52f42f9c9261ed3fc46644ec65f06ade3fd78f257e43432", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", + "wx" : "0088de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b8", + "wy" : "0c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiN5onOmvHpS+aiCJyKixJT/9u2yOnIYk\nm6IgABpK07gMSZjlSEL0E7ntsYJay7YzXoHk0YSysByL69yF0fKJRg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 398, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b0b12d67d73b76b4a5e85f3924c3da7f88cc89d8cbe0d5bc7faf1e4afc86864", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", + "wx" : "00fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7", + "wy" : "00b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/qLTH3D5DV+z4A4YasQqs8FhXO5xTgtO\nETGz1NgiW/ewN6GN8qwVND8w90Bn3fKegX1fd/jc4FcU2lnAlPDNqQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 399, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220694c146244a5ad0bd0636d9e12bc9e09e60e68b90d0b5e6c5dddd0cb694d8799", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", + "wx" : "7258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db", + "wy" : "17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcliRHj1CM0kWZHnb4Lg0Gvf70D0KfhDt\nzLNrbO6lo9sXrCuJknkRKPo7ltwvvUyjv6eC7ygy/GZWlD2xjnNGsA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 400, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203d7f487c07bfc5f30846938a3dcef696444707cf9677254a92b06c63ab867d22", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", + "wx" : "4f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914", + "wy" : "00c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAETyhGHepkR01rs00Umcl9N7npVjPfHO7q\nrNRQFsmLORTIgYgQuMwG3bQOihJhxSj6pYlFXVpt+Tt3vF4OSTx0cA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 401, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206c7648fc0fbf8a06adb8b839f97b4ff7a800f11b1e37c593b261394599792ba4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", + "wx" : "74f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66", + "wy" : "00eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEdPKoFPtdjsqRppteYHEnMrOTfeMoKb6X\nTte2jFwvXWbv8PB8VvmHplf0IZYgX1iMDx2W/YpjpfI4tI9Hh4j+Ow==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 402, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220641c9c5d790dc09cdd3dfabb62cdf453e69747a7e3d7aa1a714189ef53171a99", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", + "wx" : "195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6a", + "wy" : "00b2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGVtRp8xKIbgnSnCpDed5gUw8jKNYMoII\nwJop8za4LWqyQWt8kv/9wpw7EoLdKnek0E3390UgRzk9hJmJxc7prQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 403, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022029798c5c45bdf58b4a7b2fdc2c46ab4af1218c7eeb9f0f27a88f1267674de3b0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", + "wx" : "622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa", + "wy" : "736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYi/HRzIDS+wt3zvBbTSz0fejJ90qjBm6\ntLtP46JLWKpzay8vrnb0367MkJYzOwEyjVHrP9qckifpDQtEmYPE8A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 404, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02200b70f22ca2bb3cefadca1a5711fa3a59f4695385eb5aedf3495d0b6d00f8fd85", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", + "wx" : "1f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c7", + "wy" : "0827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH3+FyvLXVQ56+bZQI+u03ONFAxFpIwnb\nJplpuDS2EccIJ/RbeAIOy7r0hP3Vv6rmhw8RhMIVgbr274K9e1MPkw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 405, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", + "wx" : "49c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377a", + "wy" : "00efc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEScGX3ICtHaR6Q0K5OJPo4fsLuU/DOoPn\ng8ALJMeBN3rvwg2pK6x2KVH3JHS+zHNNTMIrqBuJXigv2sTfevDzfQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 406, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202252d685e831b6cf095e4f0535eeaf0ddd3bfa91c210c9d9dc17224702eaf88f", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", + "wx" : "00d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe", + "wy" : "7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2MtoUXthalZACqOGhjXlS29plZii9hZ3\nV2VJgLr2rL5+yM9EnISaoDRhow762kFFPFfG5vvJO7xvpJrabcBVXA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 407, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022075135abd7c425b60371a477f09ce0f274f64a8c6b061a07b5d63e93c65046c53", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", + "wx" : "030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3", + "wy" : "00b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAwcT+2Pyqm/iyt8bIO/CWcd0Rdr6h9rD\nmLhAZco0ffOyJ4GN4aObWJywcdg+UxfMzcIzjlHjEv4x2Nw0pIAXUA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 408, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", + "wx" : "00babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7", + "wy" : "252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEurs2d7CVWALY6SmkE1VkDq8eoTU/incT\nMcSUbjSAr6clLxlsh+09KlnTsbVZE3/tABP+zvwZ+1qSaCubylG5UA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 409, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e888377ac6c71ac9dec3fdb9b56c9feaf0cfaca9f827fc5eb65fc3eac811210", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", + "wx" : "1aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60", + "wy" : "00bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGqsgGHk0cREaig6bFD/eAvyVkgeW06Y9\n4ym0JDlvumC75BMHBRdHkkQbMY06ox3+hXeCHptEbsVz0nLgNsTr6Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 410, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022030bbb794db588363b40679f6c182a50d3ce9679acdd3ffbe36d7813dacbdc818", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", + "wx" : "008cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff", + "wy" : "47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjLC5CUmcg+qAbNiFsd1GegEZ8GqIoCdu\nsM/aJ0U1qP9HtUKIM7w/LIv52QQRWM8zcYpplhzQFym8ABHR5YardQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 411, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202c37fd995622c4fb7fffffffffffffffc7cee745110cb45ab558ed7c90c15a2f", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", + "wx" : "008f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d", + "wy" : "3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjwPPGkInK7FTJyMJP3Lm/urIXhcA6fvp\npqLdZC10v107iacYna2M91/CL28ViqJ/nCygDaynhb4zWPK9o4YsoA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 412, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02207fd995622c4fb7ffffffffffffffffff5d883ffab5b32652ccdcaa290fccb97d", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", + "wx" : "44de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8ace", + "wy" : "00a2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERN47nHpXqMnoIJUnU0IefZh7s9efcfAT\ngFyJfgGPis6iRgdYyPmNP9zhIalDZZ43LDJv/y5fwq5/o/edquE8Eg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 413, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304302207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc021f4cd53ba7608fffffffffffffffffffff9e5cf143e2539626190a3ab09cce47", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", + "wx" : "6fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a", + "wy" : "0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEb7iytI4zAxJorWpRdITciDnqkPZmnqDH\nrDIz4qwxOUoKyLvn9zwv9N+ZeHJ6wd/C/VhkfSDzH5kQUxa2RnHyBA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 414, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205622c4fb7fffffffffffffffffffffff928a8f1c7ac7bec1808b9f61c01ec327", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", + "wx" : "00bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6", + "wy" : "00f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvqcRIqBIaT6QX/YCs8+d0Yr2m5/J2EMd\nKx3Sa5Qsleb0PHuLletiCCwS2529p/445Fy+SkiGkH+4G9sMXqkkbA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 415, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022044104104104104104104104104104103b87853fd3b7d3f8e175125b4382f25ed", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", + "wx" : "00da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156", + "wy" : "00e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2pGMcxugaiDLlO8zt3jpgaQEowXxlB/j\nNma0WwM1MVbiuyaU9XW0UYO+eOXJtSEL879Ij9TIKUUW2JVyyk9TkQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 416, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202739ce739ce739ce739ce739ce739ce705560298d1f2f08dc419ac273a5b54d9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", + "wx" : "3007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d", + "wy" : "5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMAfpLDk32t55ZN+jWw7/Ax9+sCrtCgMU\nQREGzetw/j1adUb8BVKZeyDj1vQT514stm4RYyJpcRS3m6xzS/xNxQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 417, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02204888888888888888888888888888888831c83ae82ebe0898776b4c69d11f88de", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", + "wx" : "60e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9b", + "wy" : "00d2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYOc071Yk08vw3dN1ARvWY9bWrrxkTrWZ\n/fmNvc0YzpvS2Qs6wx8TmvgyzM9sy7ssbqEfqXNw3JkG2kdNfYp1Zw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 418, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206492492492492492492492492492492406dd3a19b8d5fb875235963c593bd2d3", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", + "wx" : "0085a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba337", + "wy" : "69744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEhakA6XhY9pPAt9+iYeOA2tbqBG0fZd3u\n7dX32K8LozdpdE0VrdT2wLw7DaKuyTs0y4xl+TQN33TnsACe7szOPA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 419, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b15", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", + "wx" : "38066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046", + "wy" : "00a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOAZvddiO/EyT3jb0ngN7I0zBix3lYIdQ\npiyrA0VAEEaj6EvtjPy4Ge9NVQRE8s5LZRdmtp4uKQH4iDb/kANP7Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 420, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", + "wx" : "0098f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabf", + "wy" : "00a33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmPaBd9yVwbTL+lJFSIylI6fVYpRw0DXW\nIaRDxy85qr+jPSlUb6HGSPLH1cz3DPHOSrebXbGsBZ2+zQaNvf8biQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 421, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", + "wx" : "5c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277", + "wy" : "00e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEXCu/ojybmtB/A4qom0kwvyZ9lAHkJV3p\n6NoKUHjsgnfj6IKjHV5qN54Hk5g8ze05uVxDU6sv8B6lNpukewwxkQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 422, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220185ddbca6dac41b1da033cfb60c152869e74b3cd66e9ffdf1b6bc09ed65ee40c", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", + "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", + "wy" : "3547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4U1R4CCmESO215wGt6EzV+xrJVnul6Ptoprkz7EtcyEzA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 423, + "comment" : "point duplication during verification", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", + "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", + "wy" : "00cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4XKuH99Z7txJKGP5SF7MqBOU2qYRaFwSXWUbME6SjN3Yw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 424, + "comment" : "duplication bug", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", + "wx" : "008aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e", + "wy" : "1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiqLGT6nGQ3Vjq/vL0AsgSNSMGMFSoqb0\nkDbedkfr6C4c5kOHmVxooGD6O8A5mwXMBu7H1Zj3UEGkkX5pK39R/w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 425, + "comment" : "comparison with point at infinity ", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0022033333333333333333333333333333332f222f8faefdb533f265d461c29a47373", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", + "wx" : "391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71f", + "wy" : "00dd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEORQn/37ngBPBSux9lqigYiCSmKeDg16U\n/WVJ1QL/9x/dZiTsNDrZ/PTZhyGB5Z+EL5ukzMrgmmwJcvtqxrTGvQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 426, + "comment" : "extreme value for k and edgecase s", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", + "wx" : "00e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138e", + "wy" : "00c1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE52K4ohm08YAhnMepBZJF5JYb0ZHAOJl4\nnHo0uJ6ME47BUz7wQZu3N24L/ekxnRCgaWh5HZ6g7tnBzmNFrtl1ng==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 427, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", + "wx" : "009aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952", + "wy" : "00fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmu2w0oHbFk4TAADFaX+uDzBe+Ei+b/+0\nOsWT+7lQ6VL6b2MzWb3NgrVrC5+WWwN3idRrmoFBt5GyrvpxP5bBdQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 428, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", + "wx" : "008ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee", + "wy" : "1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEitRF22KBYmDk5of9GITki5/AY20DFUfW\nMxXnkuGb+u4d5k+Z1fHNi27Jyw94emVK6GmTuj2xAI70PP8GhMsivQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 429, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", + "wx" : "1f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32", + "wy" : "00e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH1eZyVvokGOyTybkDLkowahop2+wCUYH\n6AQ9tAnJHDLnVyToE6QZHjqDkAfwji6Jc4iwbUoA3m3mDlNtkfq1Zg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 430, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", + "wx" : "00a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc", + "wy" : "28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEozMaThtCI+wsAn7dSCySihTtNY2T8dQh\nfTmr9p/LXMwo1oTSqqvNY4N3XKpiOd4m1MaTe7YD7LQZYIL0z/1QnQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 431, + "comment" : "extreme value for k", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee502200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", + "wx" : "3f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb24818", + "wy" : "5ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPzlSGZd0x885s4tmyxBCpiYNhoCAOEXk\n1DOtujuySBhepJW2jLx+1Bc+5jyQQtxQJiXH634h+wLKmpEU4KOhjQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 432, + "comment" : "extreme value for k and edgecase s", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", + "wx" : "00cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e", + "wy" : "054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzfuMD0IuFE4TfCQSyGwXH1/j+j9bu1RO\nkHYojzzteG4FT9ByG3fBHHm+rLPJQhGwoZvaCGUu/q+SUTo7ChY2mA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 433, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", + "wx" : "73598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3", + "wy" : "00cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEc1mKahxoJ4+mv9DOQGTmgjW8HA9rIKko\nEIvjNnMPh+PLrmElGbUDLsyFrtgRJxqV/nk51dNGAUC6MY9NFKujHQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 434, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", + "wx" : "58debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a1", + "wy" : "6773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWN69mn7iydWRMkeKVECuTV1+1Dcwg2n5\nLqhsghg/EKFnc+dvXtv02g5PG9/6wPVyV+HfpGWEKTEwmiQkX9pqXQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 435, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", + "wx" : "008b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b", + "wy" : "00950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEi5BN5HlnNAxfjDVypyCSTvdXhjf+qxlJ\nrLJBpaasP1uVCQRJb5gksdY/MxO64huJ+uia/fyBG17OA/1aowGGTw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 436, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", + "wx" : "00f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a", + "wy" : "346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9IkrbVJcdx4DXyolJwjzeE5II4YEtPlN\nxW6qHlRtlBo0axqgvOaLHFDltS9Qn7VSLlwl4Ci8j4Y0Au23vK2LGw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 437, + "comment" : "extreme value for k", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179802200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "wy" : "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 438, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + }, + { + "tcId" : 439, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", + "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "wy" : "00b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5i3xSWI2Vw7mqJbBAPx7vdXAuhLt1l6q+ZjuC9vBO8ndw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 440, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + }, + { + "tcId" : 441, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", + "wx" : "782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963", + "wy" : "00af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeCyO0X47Kng7VGTzOwllKnHGeOBexR6E\n4rz8Zjo96WOvmstCgLjH98QvTvmrpiRewewXEv04oPqWQY2M1qphUg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 442, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "", + "sig" : "3045022100f80ae4f96cdbc9d853f83d47aae225bf407d51c56b7776cd67d0dc195d99a9dc02204cfc1d941e08cb9aceadde0f4ccead76b30d332fc442115d50e673e28686b70b", + "result" : "valid" + }, + { + "tcId" : 443, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "4d7367", + "sig" : "30440220109cd8ae0374358984a8249c0a843628f2835ffad1df1a9a69aa2fe72355545c02205390ff250ac4274e1cb25cd6ca6491f6b91281e32f5b264d87977aed4a94e77b", + "result" : "valid" + }, + { + "tcId" : 444, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100d035ee1f17fdb0b2681b163e33c359932659990af77dca632012b30b27a057b302201939d9f3b2858bc13e3474cb50e6a82be44faa71940f876c1cba4c3e989202b6", + "result" : "valid" + }, + { + "tcId" : 445, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "0000000000000000000000000000000000000000", + "sig" : "304402204f053f563ad34b74fd8c9934ce59e79c2eb8e6eca0fef5b323ca67d5ac7ed23802204d4b05daa0719e773d8617dce5631c5fd6f59c9bdc748e4b55c970040af01be5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", + "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", + "wy" : "01060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv8AAAABBgSS1aVnPg8l2NUPt+WMSdhtRtQhaVXgqj1A4Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 446, + "comment" : "y-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "304402206d6a4f556ccce154e7fb9f19e76c3deca13d59cc2aeb4ecad968aab2ded45965022053b9fa74803ede0fc4441bf683d56c564d3e274e09ccf47390badd1471c05fb7", + "result" : "valid" + }, + { + "tcId" : 447, + "comment" : "y-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022100aad503de9b9fd66b948e9acf596f0a0e65e700b28b26ec56e6e45e846489b3c4021f0ddc3a2f89abb817bb85c062ce02f823c63fc26b269e0bc9b84d81a5aa123d", + "result" : "valid" + }, + { + "tcId" : 448, + "comment" : "y-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "30450221009182cebd3bb8ab572e167174397209ef4b1d439af3b200cdf003620089e43225022054477c982ea019d2e1000497fc25fcee1bccae55f2ac27530ae53b29c4b356a4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", + "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", + "wy" : "00fffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv/////++fttKlqYwfDaJyrwSBpztieSuSvelqoeVcK7Tg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 449, + "comment" : "y-coordinate of the public key is large", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "304402203854a3998aebdf2dbc28adac4181462ccac7873907ab7f212c42db0e69b56ed802203ed3f6b8a388d02f3e4df9f2ae9c1bd2c3916a686460dffcd42909cd7f82058e", + "result" : "valid" + }, + { + "tcId" : 450, + "comment" : "y-coordinate of the public key is large", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100e94dbdc38795fe5c904d8f16d969d3b587f0a25d2de90b6d8c5c53ff887e360702207a947369c164972521bb8af406813b2d9f94d2aeaa53d4c215aaa0a2578a2c5d", + "result" : "valid" + }, + { + "tcId" : 451, + "comment" : "y-coordinate of the public key is large", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022049fc102a08ca47b60e0858cd0284d22cddd7233f94aaffbb2db1dd2cf08425e102205b16fca5a12cdb39701697ad8e39ffd6bdec0024298afaa2326aea09200b14d6", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", + "wx" : "013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0", + "wy" : "00f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAAAAAT/SIkjWTZX3PCm0irSGMYUL5QP9\nAPhGi18PcOD27nqkO8LG/SWx2CaSQcvdnbsNrJbcliMfQwcF+DhxfQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 452, + "comment" : "x-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022041efa7d3f05a0010675fcb918a45c693da4b348df21a59d6f9cd73e0d831d67a02204454ada693e5e26b7bd693236d340f80545c834577b6f73d378c7bcc534244da", + "result" : "valid" + }, + { + "tcId" : 453, + "comment" : "x-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100b615698c358b35920dd883eca625a6c5f7563970cdfc378f8fe0cee17092144c022025f47b326b5be1fb610b885153ea84d41eb4716be66a994e8779989df1c863d4", + "result" : "valid" + }, + { + "tcId" : 454, + "comment" : "x-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "304502210087cf8c0eb82d44f69c60a2ff5457d3aaa322e7ec61ae5aecfd678ae1c1932b0e02203add3b115815047d6eb340a3e008989eaa0f8708d1794814729094d08d2460d3", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", + "wx" : "25afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dffffffff", + "wy" : "00fa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJa/WiayrrtZ8Hylt5ZQG+MVQ9XFGoLTs\nLJeHbf/////6RqduUgMi37xJHsTwzBl0IPxOpYg9j23VPDVLxPZ8NQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 455, + "comment" : "x-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022062f48ef71ace27bf5a01834de1f7e3f948b9dce1ca1e911d5e13d3b104471d8202205ea8f33f0c778972c4582080deda9b341857dd64514f0849a05f6964c2e34022", + "result" : "valid" + }, + { + "tcId" : 456, + "comment" : "x-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100f6b0e2f6fe020cf7c0c20137434344ed7add6c4be51861e2d14cbda472a6ffb402206416c8dd3e5c5282b306e8dc8ff34ab64cc99549232d678d714402eb6ca7aa0f", + "result" : "valid" + }, + { + "tcId" : 457, + "comment" : "x-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100db09d8460f05eff23bc7e436b67da563fa4b4edb58ac24ce201fa8a358125057022046da116754602940c8999c8d665f786c50f5772c0a3cdbda075e77eabc64df16", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", + "wx" : "00d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb9", + "wy" : "3f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0S5sZrZ3NMPITSYBz1013Al+J2N/CspK\nT9t0tqrdO7k/W9/4i9VzbfiY5pkAbtdQ8RzwfFhmzXrXDHEh/////w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 458, + "comment" : "y-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "30440220592c41e16517f12fcabd98267674f974b588e9f35d35406c1a7bb2ed1d19b7b802203e65a06bd9f83caaeb7b00f2368d7e0dece6b12221269a9b5b765198f840a3a1", + "result" : "valid" + }, + { + "tcId" : 459, + "comment" : "y-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100be0d70887d5e40821a61b68047de4ea03debfdf51cdf4d4b195558b959a032b202207d994b2d8f1dbbeb13534eb3f6e5dccd85f5c4133c27d9e64271b1826ce1f67d", + "result" : "valid" + }, + { + "tcId" : 460, + "comment" : "y-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100fae92dfcb2ee392d270af3a5739faa26d4f97bfd39ed3cbee4d29e26af3b206a02206c9ba37f9faa6a1fd3f65f23b4e853d4692a7274240a12db7ba3884830630d16", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", + "wx" : "6d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000", + "wy" : "00e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbUp/YNR3Sk8KqLve25U8fup5CUB+MWR1\nVmS8KAAAAADmWdNOTfONnoyeqt+6NmEsdpGVvobHeqw/NueLU4aA+w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 461, + "comment" : "x-coordinate of the public key has many trailing 0's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "30440220176a2557566ffa518b11226694eb9802ed2098bfe278e5570fe1d5d7af18a94302201291df6a0ed5fc0d15098e70bcf13a009284dfd0689d3bb4be6ceeb9be1487c4", + "result" : "valid" + }, + { + "tcId" : 462, + "comment" : "x-coordinate of the public key has many trailing 0's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022060be20c3dbc162dd34d26780621c104bbe5dace630171b2daef0d826409ee5c20220427f7e4d889d549170bda6a9409fb1cb8b0e763d13eea7bd97f64cf41dc6e497", + "result" : "valid" + }, + { + "tcId" : 463, + "comment" : "x-coordinate of the public key has many trailing 0's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100edf03cf63f658883289a1a593d1007895b9f236d27c9c1f1313089aaed6b16ae02201a4dd6fc0814dc523d1fefa81c64fbf5e618e651e7096fccadbb94cd48e5e0cd", + "result" : "valid" + } + ] + } + ] +} diff --git a/external/secp256k1/tools/check-abi.sh b/external/secp256k1/tools/check-abi.sh new file mode 100755 index 00000000000..601a64ba961 --- /dev/null +++ b/external/secp256k1/tools/check-abi.sh @@ -0,0 +1,74 @@ +#!/bin/sh + +set -eu + +default_base_version="$(git describe --match "v*.*.*" --abbrev=0)" +default_new_version="HEAD" + +display_help_and_exit() { + echo "Usage: $0 [ []]" + echo "" + echo "Description: This script uses the ABI Compliance Checker tool to determine if the ABI" + echo " of a new version of libsecp256k1 has changed in a backward-incompatible way." + echo "" + echo "Options:" + echo " base_ver Specify the base version as a git commit-ish" + echo " (default: most recent reachable tag matching \"v.*.*\", currently \"$default_base_version\")" + echo " new_ver Specify the new version as a git commit-ish" + echo " (default: $default_new_version)" + echo " -h, --help Display this help message" + exit 0 +} + +if [ "$#" -eq 0 ]; then + base_version="$default_base_version" + new_version="$default_new_version" +elif [ "$#" -eq 1 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then + display_help_and_exit +elif [ "$#" -eq 1 ] || [ "$#" -eq 2 ]; then + base_version="$1" + if [ "$#" -eq 2 ]; then + new_version="$2" + fi +else + echo "Invalid usage. See help:" + echo "" + display_help_and_exit +fi + +checkout_and_build() { + _orig_dir="$(pwd)" + git worktree add --detach "$1" "$2" + cd "$1" + mkdir build && cd build + cmake -S .. --preset dev-mode \ + -DCMAKE_C_COMPILER=gcc -DCMAKE_BUILD_TYPE=None -DCMAKE_C_FLAGS="-g -Og -gdwarf-4" \ + -DSECP256K1_BUILD_BENCHMARK=OFF \ + -DSECP256K1_BUILD_TESTS=OFF \ + -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \ + -DSECP256K1_BUILD_CTIME_TESTS=OFF \ + -DSECP256K1_BUILD_EXAMPLES=OFF + cmake --build . -j "$(nproc)" + # FIXME: Just set LIBPATH to lib/libsecp256k1.so once version 0.6.0 is + # released. + if [ -f "src/libsecp256k1.so" ]; then + LIBPATH="src/libsecp256k1.so" + else + LIBPATH="lib/libsecp256k1.so" + fi + abi-dumper $LIBPATH -o ABI.dump -lver "$2" -public-headers ../include/ + cd "$_orig_dir" +} + +echo "Comparing $base_version (base version) to $new_version (new version)" +echo + +base_source_dir="$(mktemp -d)" +checkout_and_build "$base_source_dir" "$base_version" + +new_source_dir="$(mktemp -d)" +checkout_and_build "$new_source_dir" "$new_version" + +abi-compliance-checker -lib libsecp256k1 -old "${base_source_dir}/build/ABI.dump" -new "${new_source_dir}/build/ABI.dump" +git worktree remove "$base_source_dir" +git worktree remove "$new_source_dir" diff --git a/external/secp256k1/tools/test_vectors_musig2_generate.py b/external/secp256k1/tools/test_vectors_musig2_generate.py new file mode 100755 index 00000000000..97424419f3c --- /dev/null +++ b/external/secp256k1/tools/test_vectors_musig2_generate.py @@ -0,0 +1,656 @@ +#!/usr/bin/env python3 + +import sys +import json +import textwrap + +max_pubkeys = 0 + +if len(sys.argv) < 2: + print( + "This script converts BIP MuSig2 test vectors in a given directory to a C file that can be used in the test framework." + ) + print("Usage: %s " % sys.argv[0]) + sys.exit(1) + + +def hexstr_to_intarray(str): + return ", ".join([f"0x{b:02X}" for b in bytes.fromhex(str)]) + + +def create_init(name): + return """ +static const struct musig_%s_vector musig_%s_vector = { +""" % ( + name, + name, + ) + + +def init_array(key): + return textwrap.indent("{ %s },\n" % hexstr_to_intarray(data[key]), 4 * " ") + + +def init_arrays(key): + s = textwrap.indent("{\n", 4 * " ") + s += textwrap.indent( + ",\n".join(["{ %s }" % hexstr_to_intarray(x) for x in data[key]]), 8 * " " + ) + s += textwrap.indent("\n},\n", 4 * " ") + return s + + +def init_indices(array): + return " %d, { %s }" % ( + len(array), + ", ".join(map(str, array) if len(array) > 0 else "0"), + ) + + +def init_is_xonly(case): + if len(case["tweak_indices"]) > 0: + return ", ".join(map(lambda x: "1" if x else "0", case["is_xonly"])) + return "0" + + +def init_optional_expected(case): + return hexstr_to_intarray(case["expected"]) if "expected" in case else 0 + + +def init_cases(cases, f): + s = textwrap.indent("{\n", 4 * " ") + for (i, case) in enumerate(cases): + s += textwrap.indent("%s\n" % f(case), 8 * " ") + s += textwrap.indent("},\n", 4 * " ") + return s + + +def finish_init(): + return "};\n" + + +s = ( + """/** + * Automatically generated by %s. + * + * The test vectors for the KeySort function are included in this file. They can + * be found in src/modules/extrakeys/tests_impl.h. */ +""" + % sys.argv[0] +) + + +s += """ +enum MUSIG_ERROR { + MUSIG_PUBKEY, + MUSIG_TWEAK, + MUSIG_PUBNONCE, + MUSIG_AGGNONCE, + MUSIG_SECNONCE, + MUSIG_SIG, + MUSIG_SIG_VERIFY, + MUSIG_OTHER +}; +""" + +# key agg vectors +with open(sys.argv[1] + "/key_agg_vectors.json", "r") as f: + data = json.load(f) + + max_key_indices = max( + len(test_case["key_indices"]) for test_case in data["valid_test_cases"] + ) + max_tweak_indices = max( + len(test_case["tweak_indices"]) for test_case in data["error_test_cases"] + ) + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_tweaks = len(data["tweaks"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + # Add structures for valid and error cases + s += ( + """ +struct musig_key_agg_valid_test_case { + size_t key_indices_len; + size_t key_indices[%d]; + unsigned char expected[32]; +}; +""" + % max_key_indices + ) + s += """ +struct musig_key_agg_error_test_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t tweak_indices_len; + size_t tweak_indices[%d]; + int is_xonly[%d]; + enum MUSIG_ERROR error; +}; +""" % ( + max_key_indices, + max_tweak_indices, + max_tweak_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_key_agg_vector { + unsigned char pubkeys[%d][33]; + unsigned char tweaks[%d][32]; + struct musig_key_agg_valid_test_case valid_case[%d]; + struct musig_key_agg_error_test_case error_case[%d]; +}; +""" % ( + num_pubkeys, + num_tweaks, + num_valid_cases, + num_error_cases, + ) + + s += create_init("key_agg") + # Add pubkeys and tweaks to the vector + s += init_arrays("pubkeys") + s += init_arrays("tweaks") + + # Add valid cases to the vector + s += init_cases( + data["valid_test_cases"], + lambda case: "{ %s, { %s }}," + % (init_indices(case["key_indices"]), hexstr_to_intarray(case["expected"])), + ) + + def comment_to_error(case): + comment = case["comment"] + if "public key" in comment.lower(): + return "MUSIG_PUBKEY" + elif "tweak" in comment.lower(): + return "MUSIG_TWEAK" + else: + sys.exit("Unknown error") + + # Add error cases to the vector + s += init_cases( + data["error_test_cases"], + lambda case: "{ %s, %s, { %s }, %s }," + % ( + init_indices(case["key_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + comment_to_error(case), + ), + ) + + s += finish_init() + +# nonce gen vectors +with open(sys.argv[1] + "/nonce_gen_vectors.json", "r") as f: + data = json.load(f) + + # The MuSig2 implementation only allows messages of length 32 + data["test_cases"] = list( + filter(lambda c: c["msg"] is None or len(c["msg"]) == 64, data["test_cases"]) + ) + + num_tests = len(data["test_cases"]) + + s += """ +struct musig_nonce_gen_test_case { + unsigned char rand_[32]; + int has_sk; + unsigned char sk[32]; + unsigned char pk[33]; + int has_aggpk; + unsigned char aggpk[32]; + int has_msg; + unsigned char msg[32]; + int has_extra_in; + unsigned char extra_in[32]; + unsigned char expected_secnonce[97]; + unsigned char expected_pubnonce[66]; +}; +""" + + s += ( + """ +struct musig_nonce_gen_vector { + struct musig_nonce_gen_test_case test_case[%d]; +}; +""" + % num_tests + ) + + s += create_init("nonce_gen") + + def init_array_maybe(array): + return "%d , { %s }" % ( + 0 if array is None else 1, + hexstr_to_intarray(array) if array is not None else 0, + ) + + s += init_cases( + data["test_cases"], + lambda case: "{ { %s }, %s, { %s }, %s, %s, %s, { %s }, { %s } }," + % ( + hexstr_to_intarray(case["rand_"]), + init_array_maybe(case["sk"]), + hexstr_to_intarray(case["pk"]), + init_array_maybe(case["aggpk"]), + init_array_maybe(case["msg"]), + init_array_maybe(case["extra_in"]), + hexstr_to_intarray(case["expected_secnonce"]), + hexstr_to_intarray(case["expected_pubnonce"]), + ), + ) + + s += finish_init() + +# nonce agg vectors +with open(sys.argv[1] + "/nonce_agg_vectors.json", "r") as f: + data = json.load(f) + + num_pnonces = len(data["pnonces"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + pnonce_indices_len = 2 + for case in data["valid_test_cases"] + data["error_test_cases"]: + assert len(case["pnonce_indices"]) == pnonce_indices_len + + # Add structures for valid and error cases + s += """ +struct musig_nonce_agg_test_case { + size_t pnonce_indices[2]; + /* if valid case */ + unsigned char expected[66]; + /* if error case */ + int invalid_nonce_idx; +}; +""" + # Add structure for entire vector + s += """ +struct musig_nonce_agg_vector { + unsigned char pnonces[%d][66]; + struct musig_nonce_agg_test_case valid_case[%d]; + struct musig_nonce_agg_test_case error_case[%d]; +}; +""" % ( + num_pnonces, + num_valid_cases, + num_error_cases, + ) + + s += create_init("nonce_agg") + s += init_arrays("pnonces") + + for cases in (data["valid_test_cases"], data["error_test_cases"]): + s += init_cases( + cases, + lambda case: "{ { %s }, { %s }, %d }," + % ( + ", ".join(map(str, case["pnonce_indices"])), + init_optional_expected(case), + case["error"]["signer"] if "error" in case else 0, + ), + ) + s += finish_init() + +# sign/verify vectors +with open(sys.argv[1] + "/sign_verify_vectors.json", "r") as f: + data = json.load(f) + + # The MuSig2 implementation only allows messages of length 32 + assert list(filter(lambda x: len(x) == 64, data["msgs"]))[0] == data["msgs"][0] + data["msgs"] = [data["msgs"][0]] + + def filter_msg32(k): + return list(filter(lambda x: x["msg_index"] == 0, data[k])) + + data["valid_test_cases"] = filter_msg32("valid_test_cases") + data["sign_error_test_cases"] = filter_msg32("sign_error_test_cases") + data["verify_error_test_cases"] = filter_msg32("verify_error_test_cases") + data["verify_fail_test_cases"] = filter_msg32("verify_fail_test_cases") + + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_secnonces = len(data["secnonces"]) + num_pubnonces = len(data["pnonces"]) + num_aggnonces = len(data["aggnonces"]) + num_msgs = len(data["msgs"]) + num_valid_cases = len(data["valid_test_cases"]) + num_sign_error_cases = len(data["sign_error_test_cases"]) + num_verify_fail_cases = len(data["verify_fail_test_cases"]) + num_verify_error_cases = len(data["verify_error_test_cases"]) + + all_cases = ( + data["valid_test_cases"] + + data["sign_error_test_cases"] + + data["verify_error_test_cases"] + + data["verify_fail_test_cases"] + ) + max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) + max_nonce_indices = max( + len(test_case["nonce_indices"]) if "nonce_indices" in test_case else 0 + for test_case in all_cases + ) + # Add structures for valid and error cases + s += ( + """ +/* Omit pubnonces in the test vectors because our partial signature verification + * implementation is able to accept the aggnonce directly. */ +struct musig_valid_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t aggnonce_index; + size_t msg_index; + size_t signer_index; + unsigned char expected[32]; +}; +""" + % max_key_indices + ) + + s += ( + """ +struct musig_sign_error_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t aggnonce_index; + size_t msg_index; + size_t secnonce_index; + enum MUSIG_ERROR error; +}; +""" + % max_key_indices + ) + + s += """ +struct musig_verify_fail_error_case { + unsigned char sig[32]; + size_t key_indices_len; + size_t key_indices[%d]; + size_t nonce_indices_len; + size_t nonce_indices[%d]; + size_t msg_index; + size_t signer_index; + enum MUSIG_ERROR error; +}; +""" % ( + max_key_indices, + max_nonce_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_sign_verify_vector { + unsigned char sk[32]; + unsigned char pubkeys[%d][33]; + unsigned char secnonces[%d][194]; + unsigned char pubnonces[%d][194]; + unsigned char aggnonces[%d][66]; + unsigned char msgs[%d][32]; + struct musig_valid_case valid_case[%d]; + struct musig_sign_error_case sign_error_case[%d]; + struct musig_verify_fail_error_case verify_fail_case[%d]; + struct musig_verify_fail_error_case verify_error_case[%d]; +}; +""" % ( + num_pubkeys, + num_secnonces, + num_pubnonces, + num_aggnonces, + num_msgs, + num_valid_cases, + num_sign_error_cases, + num_verify_fail_cases, + num_verify_error_cases, + ) + + s += create_init("sign_verify") + s += init_array("sk") + s += init_arrays("pubkeys") + s += init_arrays("secnonces") + s += init_arrays("pnonces") + s += init_arrays("aggnonces") + s += init_arrays("msgs") + + s += init_cases( + data["valid_test_cases"], + lambda case: "{ %s, %d, %d, %d, { %s }}," + % ( + init_indices(case["key_indices"]), + case["aggnonce_index"], + case["msg_index"], + case["signer_index"], + init_optional_expected(case), + ), + ) + + def sign_error(case): + comment = case["comment"] + if "pubkey" in comment or "public key" in comment: + return "MUSIG_PUBKEY" + elif "Aggregate nonce" in comment: + return "MUSIG_AGGNONCE" + elif "Secnonce" in comment: + return "MUSIG_SECNONCE" + else: + sys.exit("Unknown sign error") + + s += init_cases( + data["sign_error_test_cases"], + lambda case: "{ %s, %d, %d, %d, %s }," + % ( + init_indices(case["key_indices"]), + case["aggnonce_index"], + case["msg_index"], + case["secnonce_index"], + sign_error(case), + ), + ) + + def verify_error(case): + comment = case["comment"] + if "exceeds" in comment: + return "MUSIG_SIG" + elif "Wrong signer" in comment or "Wrong signature" in comment: + return "MUSIG_SIG_VERIFY" + elif "pubnonce" in comment: + return "MUSIG_PUBNONCE" + elif "pubkey" in comment: + return "MUSIG_PUBKEY" + else: + sys.exit("Unknown verify error") + + for cases in ("verify_fail_test_cases", "verify_error_test_cases"): + s += init_cases( + data[cases], + lambda case: "{ { %s }, %s, %s, %d, %d, %s }," + % ( + hexstr_to_intarray(case["sig"]), + init_indices(case["key_indices"]), + init_indices(case["nonce_indices"]), + case["msg_index"], + case["signer_index"], + verify_error(case), + ), + ) + + s += finish_init() + +# tweak vectors +with open(sys.argv[1] + "/tweak_vectors.json", "r") as f: + data = json.load(f) + + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_pubnonces = len(data["pnonces"]) + num_tweaks = len(data["tweaks"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + all_cases = data["valid_test_cases"] + data["error_test_cases"] + max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) + max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases) + max_nonce_indices = max(len(test_case["nonce_indices"]) for test_case in all_cases) + # Add structures for valid and error cases + s += """ +struct musig_tweak_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t nonce_indices_len; + size_t nonce_indices[%d]; + size_t tweak_indices_len; + size_t tweak_indices[%d]; + int is_xonly[%d]; + size_t signer_index; + unsigned char expected[32]; +}; +""" % ( + max_key_indices, + max_nonce_indices, + max_tweak_indices, + max_tweak_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_tweak_vector { + unsigned char sk[32]; + unsigned char secnonce[97]; + unsigned char aggnonce[66]; + unsigned char msg[32]; + unsigned char pubkeys[%d][33]; + unsigned char pubnonces[%d][194]; + unsigned char tweaks[%d][32]; + struct musig_tweak_case valid_case[%d]; + struct musig_tweak_case error_case[%d]; +}; +""" % ( + num_pubkeys, + num_pubnonces, + num_tweaks, + num_valid_cases, + num_error_cases, + ) + s += create_init("tweak") + s += init_array("sk") + s += init_array("secnonce") + s += init_array("aggnonce") + s += init_array("msg") + s += init_arrays("pubkeys") + s += init_arrays("pnonces") + s += init_arrays("tweaks") + + s += init_cases( + data["valid_test_cases"], + lambda case: "{ %s, %s, %s, { %s }, %d, { %s }}," + % ( + init_indices(case["key_indices"]), + init_indices(case["nonce_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + case["signer_index"], + init_optional_expected(case), + ), + ) + + s += init_cases( + data["error_test_cases"], + lambda case: "{ %s, %s, %s, { %s }, %d, { %s }}," + % ( + init_indices(case["key_indices"]), + init_indices(case["nonce_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + case["signer_index"], + init_optional_expected(case), + ), + ) + + s += finish_init() + +# sigagg vectors +with open(sys.argv[1] + "/sig_agg_vectors.json", "r") as f: + data = json.load(f) + + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_tweaks = len(data["tweaks"]) + num_psigs = len(data["psigs"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + all_cases = data["valid_test_cases"] + data["error_test_cases"] + max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) + max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases) + max_psig_indices = max(len(test_case["psig_indices"]) for test_case in all_cases) + + # Add structures for valid and error cases + s += """ +/* Omit pubnonces in the test vectors because they're only needed for + * implementations that do not directly accept an aggnonce. */ +struct musig_sig_agg_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t tweak_indices_len; + size_t tweak_indices[%d]; + int is_xonly[%d]; + unsigned char aggnonce[66]; + size_t psig_indices_len; + size_t psig_indices[%d]; + /* if valid case */ + unsigned char expected[64]; + /* if error case */ + int invalid_sig_idx; +}; +""" % ( + max_key_indices, + max_tweak_indices, + max_tweak_indices, + max_psig_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_sig_agg_vector { + unsigned char pubkeys[%d][33]; + unsigned char tweaks[%d][32]; + unsigned char psigs[%d][32]; + unsigned char msg[32]; + struct musig_sig_agg_case valid_case[%d]; + struct musig_sig_agg_case error_case[%d]; +}; +""" % ( + num_pubkeys, + num_tweaks, + num_psigs, + num_valid_cases, + num_error_cases, + ) + + s += create_init("sig_agg") + s += init_arrays("pubkeys") + s += init_arrays("tweaks") + s += init_arrays("psigs") + s += init_array("msg") + + for cases in (data["valid_test_cases"], data["error_test_cases"]): + s += init_cases( + cases, + lambda case: "{ %s, %s, { %s }, { %s }, %s, { %s }, %d }," + % ( + init_indices(case["key_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + hexstr_to_intarray(case["aggnonce"]), + init_indices(case["psig_indices"]), + init_optional_expected(case), + case["error"]["signer"] if "error" in case else 0, + ), + ) + s += finish_init() +s += "enum { MUSIG_VECTORS_MAX_PUBKEYS = %d };" % max_pubkeys +print(s) diff --git a/external/secp256k1/tools/tests_wycheproof_generate.py b/external/secp256k1/tools/tests_wycheproof_generate.py new file mode 100755 index 00000000000..b26dfa89d66 --- /dev/null +++ b/external/secp256k1/tools/tests_wycheproof_generate.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Random "Randy" Lattice and Sean Andersen +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://www.opensource.org/licenses/mit-license.php. +''' +Generate a C file with ECDSA testvectors from the Wycheproof project. +''' + +import json +import sys + +filename_input = sys.argv[1] + +with open(filename_input) as f: + doc = json.load(f) + +num_groups = len(doc['testGroups']) + +def to_c_array(x): + if x == "": + return "" + s = ',0x'.join(a+b for a,b in zip(x[::2], x[1::2])) + return "0x" + s + + +num_vectors = 0 +offset_msg_running, offset_pk_running, offset_sig = 0, 0, 0 +out = "" +messages = "" +signatures = "" +public_keys = "" +cache_msgs = {} +cache_public_keys = {} + +for i in range(num_groups): + group = doc['testGroups'][i] + num_tests = len(group['tests']) + public_key = group['publicKey'] + for j in range(num_tests): + test_vector = group['tests'][j] + # // 2 to convert hex to byte length + sig_size = len(test_vector['sig']) // 2 + msg_size = len(test_vector['msg']) // 2 + + if test_vector['result'] == "invalid": + expected_verify = 0 + elif test_vector['result'] == "valid": + expected_verify = 1 + else: + raise ValueError("invalid result field") + + if num_vectors != 0 and sig_size != 0: + signatures += ",\n " + + new_msg = False + msg = to_c_array(test_vector['msg']) + msg_offset = offset_msg_running + # check for repeated msg + if msg not in cache_msgs: + if num_vectors != 0 and msg_size != 0: + messages += ",\n " + cache_msgs[msg] = offset_msg_running + messages += msg + new_msg = True + else: + msg_offset = cache_msgs[msg] + + new_pk = False + pk = to_c_array(public_key['uncompressed']) + pk_offset = offset_pk_running + # check for repeated pk + if pk not in cache_public_keys: + if num_vectors != 0: + public_keys += ",\n " + cache_public_keys[pk] = offset_pk_running + public_keys += pk + new_pk = True + else: + pk_offset = cache_public_keys[pk] + + signatures += to_c_array(test_vector['sig']) + + out += " /" + "* tcId: " + str(test_vector['tcId']) + ". " + test_vector['comment'] + " *" + "/\n" + out += f" {{{pk_offset}, {msg_offset}, {msg_size}, {offset_sig}, {sig_size}, {expected_verify} }},\n" + if new_msg: + offset_msg_running += msg_size + if new_pk: + offset_pk_running += 65 + offset_sig += sig_size + num_vectors += 1 + +struct_definition = """ +typedef struct { + size_t pk_offset; + size_t msg_offset; + size_t msg_len; + size_t sig_offset; + size_t sig_len; + int expected_verify; +} wycheproof_ecdsa_testvector; +""" + + +print("/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */") +print(f"#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({num_vectors})") + +print(struct_definition) + +print("static const unsigned char wycheproof_ecdsa_messages[] = { " + messages + "};\n") +print("static const unsigned char wycheproof_ecdsa_public_keys[] = { " + public_keys + "};\n") +print("static const unsigned char wycheproof_ecdsa_signatures[] = { " + signatures + "};\n") + +print("static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = {") +print(out) +print("};") diff --git a/external/snappy/conandata.yml b/external/snappy/conandata.yml new file mode 100644 index 00000000000..1488c7a2baf --- /dev/null +++ b/external/snappy/conandata.yml @@ -0,0 +1,40 @@ +sources: + "1.1.10": + url: "https://github.com/google/snappy/archive/1.1.10.tar.gz" + sha256: "49d831bffcc5f3d01482340fe5af59852ca2fe76c3e05df0e67203ebbe0f1d90" + "1.1.9": + url: "https://github.com/google/snappy/archive/1.1.9.tar.gz" + sha256: "75c1fbb3d618dd3a0483bff0e26d0a92b495bbe5059c8b4f1c962b478b6e06e7" + "1.1.8": + url: "https://github.com/google/snappy/archive/1.1.8.tar.gz" + sha256: "16b677f07832a612b0836178db7f374e414f94657c138e6993cbfc5dcc58651f" + "1.1.7": + url: "https://github.com/google/snappy/archive/1.1.7.tar.gz" + sha256: "3dfa02e873ff51a11ee02b9ca391807f0c8ea0529a4924afa645fbf97163f9d4" +patches: + "1.1.10": + - patch_file: "patches/1.1.10-0001-fix-inlining-failure.patch" + patch_description: "disable inlining for compilation error" + patch_type: "portability" + - patch_file: "patches/1.1.9-0002-no-Werror.patch" + patch_description: "disable 'warning as error' options" + patch_type: "portability" + - patch_file: "patches/1.1.10-0003-fix-clobber-list-older-llvm.patch" + patch_description: "disable inline asm on apple-clang" + patch_type: "portability" + - patch_file: "patches/1.1.9-0004-rtti-by-default.patch" + patch_description: "remove 'disable rtti'" + patch_type: "conan" + "1.1.9": + - patch_file: "patches/1.1.9-0001-fix-inlining-failure.patch" + patch_description: "disable inlining for compilation error" + patch_type: "portability" + - patch_file: "patches/1.1.9-0002-no-Werror.patch" + patch_description: "disable 'warning as error' options" + patch_type: "portability" + - patch_file: "patches/1.1.9-0003-fix-clobber-list-older-llvm.patch" + patch_description: "disable inline asm on apple-clang" + patch_type: "portability" + - patch_file: "patches/1.1.9-0004-rtti-by-default.patch" + patch_description: "remove 'disable rtti'" + patch_type: "conan" diff --git a/external/snappy/conanfile.py b/external/snappy/conanfile.py new file mode 100644 index 00000000000..23558639f46 --- /dev/null +++ b/external/snappy/conanfile.py @@ -0,0 +1,89 @@ +from conan import ConanFile +from conan.tools.build import check_min_cppstd +from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout +from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get, rmdir +from conan.tools.scm import Version +import os + +required_conan_version = ">=1.54.0" + + +class SnappyConan(ConanFile): + name = "snappy" + description = "A fast compressor/decompressor" + topics = ("google", "compressor", "decompressor") + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://github.com/google/snappy" + license = "BSD-3-Clause" + + package_type = "library" + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + } + default_options = { + "shared": False, + "fPIC": True, + } + + def export_sources(self): + export_conandata_patches(self) + + def config_options(self): + if self.settings.os == 'Windows': + del self.options.fPIC + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def layout(self): + cmake_layout(self, src_folder="src") + + def validate(self): + if self.settings.compiler.get_safe("cppstd"): + check_min_cppstd(self, 11) + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def generate(self): + tc = CMakeToolchain(self) + tc.variables["SNAPPY_BUILD_TESTS"] = False + if Version(self.version) >= "1.1.8": + tc.variables["SNAPPY_FUZZING_BUILD"] = False + tc.variables["SNAPPY_REQUIRE_AVX"] = False + tc.variables["SNAPPY_REQUIRE_AVX2"] = False + tc.variables["SNAPPY_INSTALL"] = True + if Version(self.version) >= "1.1.9": + tc.variables["SNAPPY_BUILD_BENCHMARKS"] = False + tc.generate() + + def build(self): + apply_conandata_patches(self) + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + copy(self, "COPYING", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) + cmake = CMake(self) + cmake.install() + rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) + + def package_info(self): + self.cpp_info.set_property("cmake_file_name", "Snappy") + self.cpp_info.set_property("cmake_target_name", "Snappy::snappy") + # TODO: back to global scope in conan v2 once cmake_find_package* generators removed + self.cpp_info.components["snappylib"].libs = ["snappy"] + if not self.options.shared: + if self.settings.os in ["Linux", "FreeBSD"]: + self.cpp_info.components["snappylib"].system_libs.append("m") + + # TODO: to remove in conan v2 once cmake_find_package* generators removed + self.cpp_info.names["cmake_find_package"] = "Snappy" + self.cpp_info.names["cmake_find_package_multi"] = "Snappy" + self.cpp_info.components["snappylib"].names["cmake_find_package"] = "snappy" + self.cpp_info.components["snappylib"].names["cmake_find_package_multi"] = "snappy" + self.cpp_info.components["snappylib"].set_property("cmake_target_name", "Snappy::snappy") diff --git a/external/snappy/patches/1.1.10-0001-fix-inlining-failure.patch b/external/snappy/patches/1.1.10-0001-fix-inlining-failure.patch new file mode 100644 index 00000000000..66b0f055219 --- /dev/null +++ b/external/snappy/patches/1.1.10-0001-fix-inlining-failure.patch @@ -0,0 +1,13 @@ +diff --git a/snappy-stubs-internal.h b/snappy-stubs-internal.h +index 1548ed7..3b4a9f3 100644 +--- a/snappy-stubs-internal.h ++++ b/snappy-stubs-internal.h +@@ -100,7 +100,7 @@ + + // Inlining hints. + #if HAVE_ATTRIBUTE_ALWAYS_INLINE +-#define SNAPPY_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) ++#define SNAPPY_ATTRIBUTE_ALWAYS_INLINE + #else + #define SNAPPY_ATTRIBUTE_ALWAYS_INLINE + #endif // HAVE_ATTRIBUTE_ALWAYS_INLINE diff --git a/external/snappy/patches/1.1.10-0003-fix-clobber-list-older-llvm.patch b/external/snappy/patches/1.1.10-0003-fix-clobber-list-older-llvm.patch new file mode 100644 index 00000000000..969ce3805da --- /dev/null +++ b/external/snappy/patches/1.1.10-0003-fix-clobber-list-older-llvm.patch @@ -0,0 +1,13 @@ +diff --git a/snappy.cc b/snappy.cc +index d414718..e4efb59 100644 +--- a/snappy.cc ++++ b/snappy.cc +@@ -1132,7 +1132,7 @@ inline size_t AdvanceToNextTagX86Optimized(const uint8_t** ip_p, size_t* tag) { + size_t literal_len = *tag >> 2; + size_t tag_type = *tag; + bool is_literal; +-#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__) ++#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__) && ( (!defined(__clang__) && !defined(__APPLE__)) || (!defined(__APPLE__) && defined(__clang__) && (__clang_major__ >= 9)) || (defined(__APPLE__) && defined(__clang__) && (__clang_major__ > 11)) ) + // TODO clang misses the fact that the (c & 3) already correctly + // sets the zero flag. + asm("and $3, %k[tag_type]\n\t" diff --git a/external/snappy/patches/1.1.9-0001-fix-inlining-failure.patch b/external/snappy/patches/1.1.9-0001-fix-inlining-failure.patch new file mode 100644 index 00000000000..cdc119c0d58 --- /dev/null +++ b/external/snappy/patches/1.1.9-0001-fix-inlining-failure.patch @@ -0,0 +1,14 @@ +Fixes the following error: +error: inlining failed in call to ‘always_inline’ ‘size_t snappy::AdvanceToNextTag(const uint8_t**, size_t*)’: function body can be overwritten at link time + +--- snappy-stubs-internal.h ++++ snappy-stubs-internal.h +@@ -100,7 +100,7 @@ + + // Inlining hints. + #ifdef HAVE_ATTRIBUTE_ALWAYS_INLINE +-#define SNAPPY_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) ++#define SNAPPY_ATTRIBUTE_ALWAYS_INLINE + #else + #define SNAPPY_ATTRIBUTE_ALWAYS_INLINE + #endif diff --git a/external/snappy/patches/1.1.9-0002-no-Werror.patch b/external/snappy/patches/1.1.9-0002-no-Werror.patch new file mode 100644 index 00000000000..d86e4e0a9df --- /dev/null +++ b/external/snappy/patches/1.1.9-0002-no-Werror.patch @@ -0,0 +1,12 @@ +--- CMakeLists.txt ++++ CMakeLists.txt +@@ -69,7 +69,7 @@ +- # Use -Werror for clang only. ++if(0) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(NOT CMAKE_CXX_FLAGS MATCHES "-Werror") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + endif(NOT CMAKE_CXX_FLAGS MATCHES "-Werror") + endif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") +- ++endif() diff --git a/external/snappy/patches/1.1.9-0003-fix-clobber-list-older-llvm.patch b/external/snappy/patches/1.1.9-0003-fix-clobber-list-older-llvm.patch new file mode 100644 index 00000000000..84bc674fdd5 --- /dev/null +++ b/external/snappy/patches/1.1.9-0003-fix-clobber-list-older-llvm.patch @@ -0,0 +1,12 @@ +asm clobbers do not work for clang < 9 and apple-clang < 11 (found by SpaceIm) +--- snappy.cc ++++ snappy.cc +@@ -1026,7 +1026,7 @@ + size_t literal_len = *tag >> 2; + size_t tag_type = *tag; + bool is_literal; +-#if defined(__GNUC__) && defined(__x86_64__) ++#if defined(__GNUC__) && defined(__x86_64__) && ( (!defined(__clang__) && !defined(__APPLE__)) || (!defined(__APPLE__) && defined(__clang__) && (__clang_major__ >= 9)) || (defined(__APPLE__) && defined(__clang__) && (__clang_major__ > 11)) ) + // TODO clang misses the fact that the (c & 3) already correctly + // sets the zero flag. + asm("and $3, %k[tag_type]\n\t" diff --git a/external/snappy/patches/1.1.9-0004-rtti-by-default.patch b/external/snappy/patches/1.1.9-0004-rtti-by-default.patch new file mode 100644 index 00000000000..c353a489d0e --- /dev/null +++ b/external/snappy/patches/1.1.9-0004-rtti-by-default.patch @@ -0,0 +1,20 @@ +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -53,8 +53,6 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_definitions(-D_HAS_EXCEPTIONS=0) + + # Disable RTTI. +- string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-") + else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + # Use -Wall for clang and gcc. + if(NOT CMAKE_CXX_FLAGS MATCHES "-Wall") +@@ -78,8 +76,6 @@ endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") + + # Disable RTTI. +- string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") + endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + + # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make diff --git a/external/soci/conandata.yml b/external/soci/conandata.yml new file mode 100644 index 00000000000..6eb59aaffa2 --- /dev/null +++ b/external/soci/conandata.yml @@ -0,0 +1,12 @@ +sources: + "4.0.3": + url: "https://github.com/SOCI/soci/archive/v4.0.3.tar.gz" + sha256: "4b1ff9c8545c5d802fbe06ee6cd2886630e5c03bf740e269bb625b45cf934928" +patches: + "4.0.3": + - patch_file: "patches/0001-Remove-hardcoded-INSTALL_NAME_DIR-for-relocatable-li.patch" + patch_description: "Generate relocatable libraries on MacOS" + patch_type: "portability" + - patch_file: "patches/0002-Fix-soci_backend.patch" + patch_description: "Fix variable names for dependencies" + patch_type: "conan" diff --git a/external/soci/conanfile.py b/external/soci/conanfile.py new file mode 100644 index 00000000000..7e611493d70 --- /dev/null +++ b/external/soci/conanfile.py @@ -0,0 +1,212 @@ +from conan import ConanFile +from conan.tools.build import check_min_cppstd +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get, rmdir +from conan.tools.microsoft import is_msvc +from conan.tools.scm import Version +from conan.errors import ConanInvalidConfiguration +import os + +required_conan_version = ">=1.55.0" + + +class SociConan(ConanFile): + name = "soci" + homepage = "https://github.com/SOCI/soci" + url = "https://github.com/conan-io/conan-center-index" + description = "The C++ Database Access Library " + topics = ("mysql", "odbc", "postgresql", "sqlite3") + license = "BSL-1.0" + + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + "empty": [True, False], + "with_sqlite3": [True, False], + "with_db2": [True, False], + "with_odbc": [True, False], + "with_oracle": [True, False], + "with_firebird": [True, False], + "with_mysql": [True, False], + "with_postgresql": [True, False], + "with_boost": [True, False], + } + default_options = { + "shared": False, + "fPIC": True, + "empty": False, + "with_sqlite3": False, + "with_db2": False, + "with_odbc": False, + "with_oracle": False, + "with_firebird": False, + "with_mysql": False, + "with_postgresql": False, + "with_boost": False, + } + + def export_sources(self): + export_conandata_patches(self) + + def layout(self): + cmake_layout(self, src_folder="src") + + def config_options(self): + if self.settings.os == "Windows": + self.options.rm_safe("fPIC") + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def requirements(self): + if self.options.with_sqlite3: + self.requires("sqlite3/3.47.0") + if self.options.with_odbc and self.settings.os != "Windows": + self.requires("odbc/2.3.11") + if self.options.with_mysql: + self.requires("libmysqlclient/8.1.0") + if self.options.with_postgresql: + self.requires("libpq/15.5") + if self.options.with_boost: + self.requires("boost/1.83.0") + + @property + def _minimum_compilers_version(self): + return { + "Visual Studio": "14", + "gcc": "4.8", + "clang": "3.8", + "apple-clang": "8.0" + } + + def validate(self): + if self.settings.compiler.get_safe("cppstd"): + check_min_cppstd(self, 11) + + compiler = str(self.settings.compiler) + compiler_version = Version(self.settings.compiler.version.value) + if compiler not in self._minimum_compilers_version: + self.output.warning("{} recipe lacks information about the {} compiler support.".format(self.name, self.settings.compiler)) + elif compiler_version < self._minimum_compilers_version[compiler]: + raise ConanInvalidConfiguration("{} requires a {} version >= {}".format(self.name, compiler, compiler_version)) + + prefix = "Dependencies for" + message = "not configured in this conan package." + if self.options.with_db2: + # self.requires("db2/0.0.0") # TODO add support for db2 + raise ConanInvalidConfiguration("{} DB2 {} ".format(prefix, message)) + if self.options.with_oracle: + # self.requires("oracle_db/0.0.0") # TODO add support for oracle + raise ConanInvalidConfiguration("{} ORACLE {} ".format(prefix, message)) + if self.options.with_firebird: + # self.requires("firebird/0.0.0") # TODO add support for firebird + raise ConanInvalidConfiguration("{} firebird {} ".format(prefix, message)) + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def generate(self): + tc = CMakeToolchain(self) + + tc.variables["SOCI_SHARED"] = self.options.shared + tc.variables["SOCI_STATIC"] = not self.options.shared + tc.variables["SOCI_TESTS"] = False + tc.variables["SOCI_CXX11"] = True + tc.variables["SOCI_EMPTY"] = self.options.empty + tc.variables["WITH_SQLITE3"] = self.options.with_sqlite3 + tc.variables["WITH_DB2"] = self.options.with_db2 + tc.variables["WITH_ODBC"] = self.options.with_odbc + tc.variables["WITH_ORACLE"] = self.options.with_oracle + tc.variables["WITH_FIREBIRD"] = self.options.with_firebird + tc.variables["WITH_MYSQL"] = self.options.with_mysql + tc.variables["WITH_POSTGRESQL"] = self.options.with_postgresql + tc.variables["WITH_BOOST"] = self.options.with_boost + tc.generate() + + deps = CMakeDeps(self) + deps.generate() + + def build(self): + apply_conandata_patches(self) + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + copy(self, "LICENSE_1_0.txt", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder) + + cmake = CMake(self) + cmake.install() + + rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) + + def package_info(self): + self.cpp_info.set_property("cmake_file_name", "SOCI") + + target_suffix = "" if self.options.shared else "_static" + lib_prefix = "lib" if is_msvc(self) and not self.options.shared else "" + version = Version(self.version) + lib_suffix = "_{}_{}".format(version.major, version.minor) if self.settings.os == "Windows" else "" + + # soci_core + self.cpp_info.components["soci_core"].set_property("cmake_target_name", "SOCI::soci_core{}".format(target_suffix)) + self.cpp_info.components["soci_core"].libs = ["{}soci_core{}".format(lib_prefix, lib_suffix)] + if self.options.with_boost: + self.cpp_info.components["soci_core"].requires.append("boost::boost") + + # soci_empty + if self.options.empty: + self.cpp_info.components["soci_empty"].set_property("cmake_target_name", "SOCI::soci_empty{}".format(target_suffix)) + self.cpp_info.components["soci_empty"].libs = ["{}soci_empty{}".format(lib_prefix, lib_suffix)] + self.cpp_info.components["soci_empty"].requires = ["soci_core"] + + # soci_sqlite3 + if self.options.with_sqlite3: + self.cpp_info.components["soci_sqlite3"].set_property("cmake_target_name", "SOCI::soci_sqlite3{}".format(target_suffix)) + self.cpp_info.components["soci_sqlite3"].libs = ["{}soci_sqlite3{}".format(lib_prefix, lib_suffix)] + self.cpp_info.components["soci_sqlite3"].requires = ["soci_core", "sqlite3::sqlite3"] + + # soci_odbc + if self.options.with_odbc: + self.cpp_info.components["soci_odbc"].set_property("cmake_target_name", "SOCI::soci_odbc{}".format(target_suffix)) + self.cpp_info.components["soci_odbc"].libs = ["{}soci_odbc{}".format(lib_prefix, lib_suffix)] + self.cpp_info.components["soci_odbc"].requires = ["soci_core"] + if self.settings.os == "Windows": + self.cpp_info.components["soci_odbc"].system_libs.append("odbc32") + else: + self.cpp_info.components["soci_odbc"].requires.append("odbc::odbc") + + # soci_mysql + if self.options.with_mysql: + self.cpp_info.components["soci_mysql"].set_property("cmake_target_name", "SOCI::soci_mysql{}".format(target_suffix)) + self.cpp_info.components["soci_mysql"].libs = ["{}soci_mysql{}".format(lib_prefix, lib_suffix)] + self.cpp_info.components["soci_mysql"].requires = ["soci_core", "libmysqlclient::libmysqlclient"] + + # soci_postgresql + if self.options.with_postgresql: + self.cpp_info.components["soci_postgresql"].set_property("cmake_target_name", "SOCI::soci_postgresql{}".format(target_suffix)) + self.cpp_info.components["soci_postgresql"].libs = ["{}soci_postgresql{}".format(lib_prefix, lib_suffix)] + self.cpp_info.components["soci_postgresql"].requires = ["soci_core", "libpq::libpq"] + + # TODO: to remove in conan v2 once cmake_find_package* generators removed + self.cpp_info.names["cmake_find_package"] = "SOCI" + self.cpp_info.names["cmake_find_package_multi"] = "SOCI" + self.cpp_info.components["soci_core"].names["cmake_find_package"] = "soci_core{}".format(target_suffix) + self.cpp_info.components["soci_core"].names["cmake_find_package_multi"] = "soci_core{}".format(target_suffix) + if self.options.empty: + self.cpp_info.components["soci_empty"].names["cmake_find_package"] = "soci_empty{}".format(target_suffix) + self.cpp_info.components["soci_empty"].names["cmake_find_package_multi"] = "soci_empty{}".format(target_suffix) + if self.options.with_sqlite3: + self.cpp_info.components["soci_sqlite3"].names["cmake_find_package"] = "soci_sqlite3{}".format(target_suffix) + self.cpp_info.components["soci_sqlite3"].names["cmake_find_package_multi"] = "soci_sqlite3{}".format(target_suffix) + if self.options.with_odbc: + self.cpp_info.components["soci_odbc"].names["cmake_find_package"] = "soci_odbc{}".format(target_suffix) + self.cpp_info.components["soci_odbc"].names["cmake_find_package_multi"] = "soci_odbc{}".format(target_suffix) + if self.options.with_mysql: + self.cpp_info.components["soci_mysql"].names["cmake_find_package"] = "soci_mysql{}".format(target_suffix) + self.cpp_info.components["soci_mysql"].names["cmake_find_package_multi"] = "soci_mysql{}".format(target_suffix) + if self.options.with_postgresql: + self.cpp_info.components["soci_postgresql"].names["cmake_find_package"] = "soci_postgresql{}".format(target_suffix) + self.cpp_info.components["soci_postgresql"].names["cmake_find_package_multi"] = "soci_postgresql{}".format(target_suffix) diff --git a/external/soci/patches/0001-Remove-hardcoded-INSTALL_NAME_DIR-for-relocatable-li.patch b/external/soci/patches/0001-Remove-hardcoded-INSTALL_NAME_DIR-for-relocatable-li.patch new file mode 100644 index 00000000000..5de0027f750 --- /dev/null +++ b/external/soci/patches/0001-Remove-hardcoded-INSTALL_NAME_DIR-for-relocatable-li.patch @@ -0,0 +1,39 @@ +From d491bf7b5040d314ffd0c6310ba01f78ff44c85e Mon Sep 17 00:00:00 2001 +From: Rasmus Thomsen +Date: Fri, 14 Apr 2023 09:16:29 +0200 +Subject: [PATCH] Remove hardcoded INSTALL_NAME_DIR for relocatable libraries + on MacOS + +--- + cmake/SociBackend.cmake | 2 +- + src/core/CMakeLists.txt | 1 - + 2 files changed, 1 insertion(+), 2 deletions(-) + +diff --git a/cmake/SociBackend.cmake b/cmake/SociBackend.cmake +index 5d4ef0df..39fe1f77 100644 +--- a/cmake/SociBackend.cmake ++++ b/cmake/SociBackend.cmake +@@ -171,7 +171,7 @@ macro(soci_backend NAME) + set_target_properties(${THIS_BACKEND_TARGET} + PROPERTIES + SOVERSION ${${PROJECT_NAME}_SOVERSION} +- INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) ++ ) + + if(APPLE) + set_target_properties(${THIS_BACKEND_TARGET} +diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt +index 3e7deeae..f9eae564 100644 +--- a/src/core/CMakeLists.txt ++++ b/src/core/CMakeLists.txt +@@ -59,7 +59,6 @@ if (SOCI_SHARED) + PROPERTIES + VERSION ${SOCI_VERSION} + SOVERSION ${SOCI_SOVERSION} +- INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib + CLEAN_DIRECT_OUTPUT 1) + endif() + +-- +2.25.1 + diff --git a/external/soci/patches/0002-Fix-soci_backend.patch b/external/soci/patches/0002-Fix-soci_backend.patch new file mode 100644 index 00000000000..eab3c3763c0 --- /dev/null +++ b/external/soci/patches/0002-Fix-soci_backend.patch @@ -0,0 +1,24 @@ +diff --git a/cmake/SociBackend.cmake b/cmake/SociBackend.cmake +index 0a664667..3fa2ed95 100644 +--- a/cmake/SociBackend.cmake ++++ b/cmake/SociBackend.cmake +@@ -31,14 +31,13 @@ macro(soci_backend_deps_found NAME DEPS SUCCESS) + if(NOT DEPEND_FOUND) + list(APPEND DEPS_NOT_FOUND ${dep}) + else() +- string(TOUPPER "${dep}" DEPU) +- if( ${DEPU}_INCLUDE_DIR ) +- list(APPEND DEPS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIR}) ++ if( ${dep}_INCLUDE_DIR ) ++ list(APPEND DEPS_INCLUDE_DIRS ${${dep}_INCLUDE_DIR}) + endif() +- if( ${DEPU}_INCLUDE_DIRS ) +- list(APPEND DEPS_INCLUDE_DIRS ${${DEPU}_INCLUDE_DIRS}) ++ if( ${dep}_INCLUDE_DIRS ) ++ list(APPEND DEPS_INCLUDE_DIRS ${${dep}_INCLUDE_DIRS}) + endif() +- list(APPEND DEPS_LIBRARIES ${${DEPU}_LIBRARIES}) ++ list(APPEND DEPS_LIBRARIES ${${dep}_LIBRARIES}) + endif() + endforeach() + diff --git a/src/ripple/basics/Archive.h b/include/xrpl/basics/Archive.h similarity index 98% rename from src/ripple/basics/Archive.h rename to include/xrpl/basics/Archive.h index 7eead5d7e3d..7ae6950f462 100644 --- a/src/ripple/basics/Archive.h +++ b/include/xrpl/basics/Archive.h @@ -36,6 +36,6 @@ extractTarLz4( boost::filesystem::path const& src, boost::filesystem::path const& dst); -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/basics/BasicConfig.h b/include/xrpl/basics/BasicConfig.h new file mode 100644 index 00000000000..2e3478644e2 --- /dev/null +++ b/include/xrpl/basics/BasicConfig.h @@ -0,0 +1,404 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_BASICCONFIG_H_INCLUDED +#define RIPPLE_BASICS_BASICCONFIG_H_INCLUDED + +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace ripple { + +using IniFileSections = + std::unordered_map>; + +//------------------------------------------------------------------------------ + +/** Holds a collection of configuration values. + A configuration file contains zero or more sections. +*/ +class Section +{ +private: + std::string name_; + std::unordered_map lookup_; + std::vector lines_; + std::vector values_; + bool had_trailing_comments_ = false; + + using const_iterator = decltype(lookup_)::const_iterator; + +public: + /** Create an empty section. */ + explicit Section(std::string const& name = ""); + + /** Returns the name of this section. */ + std::string const& + name() const + { + return name_; + } + + /** Returns all the lines in the section. + This includes everything. + */ + std::vector const& + lines() const + { + return lines_; + } + + /** Returns all the values in the section. + Values are non-empty lines which are not key/value pairs. + */ + std::vector const& + values() const + { + return values_; + } + + /** + * Set the legacy value for this section. + */ + void + legacy(std::string value) + { + if (lines_.empty()) + lines_.emplace_back(std::move(value)); + else + lines_[0] = std::move(value); + } + + /** + * Get the legacy value for this section. + * + * @return The retrieved value. A section with an empty legacy value returns + an empty string. + */ + std::string + legacy() const + { + if (lines_.empty()) + return ""; + if (lines_.size() > 1) + Throw( + "A legacy value must have exactly one line. Section: " + name_); + return lines_[0]; + } + + /** Set a key/value pair. + The previous value is discarded. + */ + void + set(std::string const& key, std::string const& value); + + /** Append a set of lines to this section. + Lines containing key/value pairs are added to the map, + else they are added to the values list. Everything is + added to the lines list. + */ + void + append(std::vector const& lines); + + /** Append a line to this section. */ + void + append(std::string const& line) + { + append(std::vector{line}); + } + + /** Returns `true` if a key with the given name exists. */ + bool + exists(std::string const& name) const; + + template + std::optional + get(std::string const& name) const + { + auto const iter = lookup_.find(name); + if (iter == lookup_.end()) + return std::nullopt; + return boost::lexical_cast(iter->second); + } + + /// Returns a value if present, else another value. + template + T + value_or(std::string const& name, T const& other) const + { + auto const v = get(name); + return v.has_value() ? *v : other; + } + + // indicates if trailing comments were seen + // during the appending of any lines/values + bool + had_trailing_comments() const + { + return had_trailing_comments_; + } + + friend std::ostream& + operator<<(std::ostream&, Section const& section); + + // Returns `true` if there are no key/value pairs. + bool + empty() const + { + return lookup_.empty(); + } + + // Returns the number of key/value pairs. + std::size_t + size() const + { + return lookup_.size(); + } + + // For iteration of key/value pairs. + const_iterator + begin() const + { + return lookup_.cbegin(); + } + + // For iteration of key/value pairs. + const_iterator + cbegin() const + { + return lookup_.cbegin(); + } + + // For iteration of key/value pairs. + const_iterator + end() const + { + return lookup_.cend(); + } + + // For iteration of key/value pairs. + const_iterator + cend() const + { + return lookup_.cend(); + } +}; + +//------------------------------------------------------------------------------ + +/** Holds unparsed configuration information. + The raw data sections are processed with intermediate parsers specific + to each module instead of being all parsed in a central location. +*/ +class BasicConfig +{ +private: + std::unordered_map map_; + +public: + /** Returns `true` if a section with the given name exists. */ + bool + exists(std::string const& name) const; + + /** Returns the section with the given name. + If the section does not exist, an empty section is returned. + */ + /** @{ */ + Section& + section(std::string const& name); + + Section const& + section(std::string const& name) const; + + Section const& + operator[](std::string const& name) const + { + return section(name); + } + + Section& + operator[](std::string const& name) + { + return section(name); + } + /** @} */ + + /** Overwrite a key/value pair with a command line argument + If the section does not exist it is created. + The previous value, if any, is overwritten. + */ + void + overwrite( + std::string const& section, + std::string const& key, + std::string const& value); + + /** Remove all the key/value pairs from the section. + */ + void + deprecatedClearSection(std::string const& section); + + /** + * Set a value that is not a key/value pair. + * + * The value is stored as the section's first value and may be retrieved + * through section::legacy. + * + * @param section Name of the section to modify. + * @param value Contents of the legacy value. + */ + void + legacy(std::string const& section, std::string value); + + /** + * Get the legacy value of a section. A section with a + * single-line value may be retrieved as a legacy value. + * + * @param sectionName Retrieve the contents of this section's + * legacy value. + * @return Contents of the legacy value. + */ + std::string + legacy(std::string const& sectionName) const; + + friend std::ostream& + operator<<(std::ostream& ss, BasicConfig const& c); + + // indicates if trailing comments were seen + // in any loaded Sections + bool + had_trailing_comments() const + { + return std::any_of(map_.cbegin(), map_.cend(), [](auto s) { + return s.second.had_trailing_comments(); + }); + } + +protected: + void + build(IniFileSections const& ifs); +}; + +//------------------------------------------------------------------------------ + +/** Set a value from a configuration Section + If the named value is not found or doesn't parse as a T, + the variable is unchanged. + @return `true` if value was set. +*/ +template +bool +set(T& target, std::string const& name, Section const& section) +{ + bool found_and_valid = false; + try + { + auto const val = section.get(name); + if ((found_and_valid = val.has_value())) + target = *val; + } + catch (boost::bad_lexical_cast&) + { + } + return found_and_valid; +} + +/** Set a value from a configuration Section + If the named value is not found or doesn't cast to T, + the variable is assigned the default. + @return `true` if the named value was found and is valid. +*/ +template +bool +set(T& target, + T const& defaultValue, + std::string const& name, + Section const& section) +{ + bool found_and_valid = set(target, name, section); + if (!found_and_valid) + target = defaultValue; + return found_and_valid; +} + +/** Retrieve a key/value pair from a section. + @return The value string converted to T if it exists + and can be parsed, or else defaultValue. +*/ +// NOTE This routine might be more clumsy than the previous two +template +T +get(Section const& section, + std::string const& name, + T const& defaultValue = T{}) +{ + try + { + return section.value_or(name, defaultValue); + } + catch (boost::bad_lexical_cast&) + { + } + return defaultValue; +} + +inline std::string +get(Section const& section, std::string const& name, const char* defaultValue) +{ + try + { + auto const val = section.get(name); + if (val.has_value()) + return *val; + } + catch (boost::bad_lexical_cast&) + { + } + return defaultValue; +} + +template +bool +get_if_exists(Section const& section, std::string const& name, T& v) +{ + return set(v, name, section); +} + +template <> +inline bool +get_if_exists(Section const& section, std::string const& name, bool& v) +{ + int intVal = 0; + auto stat = get_if_exists(section, name, intVal); + if (stat) + v = bool(intVal); + return stat; +} + +} // namespace ripple + +#endif diff --git a/src/ripple/basics/Blob.h b/include/xrpl/basics/Blob.h similarity index 95% rename from src/ripple/basics/Blob.h rename to include/xrpl/basics/Blob.h index 068fc2d677c..9949cbd0406 100644 --- a/src/ripple/basics/Blob.h +++ b/include/xrpl/basics/Blob.h @@ -27,8 +27,8 @@ namespace ripple { /** Storage for linear binary data. Blocks of binary data appear often in various idioms and structures. */ -using Blob = std::vector ; +using Blob = std::vector; -} +} // namespace ripple #endif diff --git a/src/ripple/basics/Buffer.h b/include/xrpl/basics/Buffer.h similarity index 77% rename from src/ripple/basics/Buffer.h rename to include/xrpl/basics/Buffer.h index d19afa661d7..b2f11634525 100644 --- a/src/ripple/basics/Buffer.h +++ b/include/xrpl/basics/Buffer.h @@ -20,12 +20,11 @@ #ifndef RIPPLE_BASICS_BUFFER_H_INCLUDED #define RIPPLE_BASICS_BUFFER_H_INCLUDED -#include -#include +#include +#include + #include #include -#include -#include namespace ripple { @@ -44,10 +43,8 @@ class Buffer Buffer() = default; /** Create an uninitialized buffer with the given size. */ - explicit - Buffer (std::size_t size) - : p_ (size ? new std::uint8_t[size] : nullptr) - , size_ (size) + explicit Buffer(std::size_t size) + : p_(size ? new std::uint8_t[size] : nullptr), size_(size) { } @@ -57,26 +54,25 @@ class Buffer size is non-zero, it must not be null. @param size size of the existing memory block. */ - Buffer (void const* data, std::size_t size) - : Buffer (size) + Buffer(void const* data, std::size_t size) : Buffer(size) { if (size) std::memcpy(p_.get(), data, size); } /** Copy-construct */ - Buffer (Buffer const& other) - : Buffer (other.p_.get(), other.size_) + Buffer(Buffer const& other) : Buffer(other.p_.get(), other.size_) { } /** Copy assign */ - Buffer& operator= (Buffer const& other) + Buffer& + operator=(Buffer const& other) { if (this != &other) { - if (auto p = alloc (other.size_)) - std::memcpy (p, other.p_.get(), size_); + if (auto p = alloc(other.size_)) + std::memcpy(p, other.p_.get(), size_); } return *this; } @@ -84,9 +80,8 @@ class Buffer /** Move-construct. The other buffer is reset. */ - Buffer (Buffer&& other) noexcept - : p_ (std::move(other.p_)) - , size_ (other.size_) + Buffer(Buffer&& other) noexcept + : p_(std::move(other.p_)), size_(other.size_) { other.size_ = 0; } @@ -94,7 +89,8 @@ class Buffer /** Move-assign. The other buffer is reset. */ - Buffer& operator= (Buffer&& other) noexcept + Buffer& + operator=(Buffer&& other) noexcept { if (this != &other) { @@ -106,22 +102,22 @@ class Buffer } /** Construct from a slice */ - explicit - Buffer (Slice s) - : Buffer (s.data(), s.size()) + explicit Buffer(Slice s) : Buffer(s.data(), s.size()) { } /** Assign from slice */ - Buffer& operator= (Slice s) + Buffer& + operator=(Slice s) { // Ensure the slice isn't a subset of the buffer. - assert (s.size() == 0 || size_ == 0 || - s.data() < p_.get() || - s.data() >= p_.get() + size_); + XRPL_ASSERT( + s.size() == 0 || size_ == 0 || s.data() < p_.get() || + s.data() >= p_.get() + size_, + "ripple::Buffer::operator=(Slice) : input not a subset"); - if (auto p = alloc (s.size())) - std::memcpy (p, s.data(), s.size()); + if (auto p = alloc(s.size())) + std::memcpy(p, s.data(), s.size()); return *this; } @@ -133,16 +129,16 @@ class Buffer } bool - empty () const noexcept + empty() const noexcept { return 0 == size_; } operator Slice() const noexcept { - if (! size_) + if (!size_) return Slice{}; - return Slice{ p_.get(), size_ }; + return Slice{p_.get(), size_}; } /** Return a pointer to beginning of the storage. @@ -177,7 +173,7 @@ class Buffer Existing data, if any, is discarded. */ std::uint8_t* - alloc (std::size_t n) + alloc(std::size_t n) { if (n != size_) { @@ -219,7 +215,8 @@ class Buffer } }; -inline bool operator==(Buffer const& lhs, Buffer const& rhs) noexcept +inline bool +operator==(Buffer const& lhs, Buffer const& rhs) noexcept { if (lhs.size() != rhs.size()) return false; @@ -230,11 +227,12 @@ inline bool operator==(Buffer const& lhs, Buffer const& rhs) noexcept return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; } -inline bool operator!=(Buffer const& lhs, Buffer const& rhs) noexcept +inline bool +operator!=(Buffer const& lhs, Buffer const& rhs) noexcept { return !(lhs == rhs); } -} // ripple +} // namespace ripple #endif diff --git a/src/ripple/basics/ByteUtilities.h b/include/xrpl/basics/ByteUtilities.h similarity index 75% rename from src/ripple/basics/ByteUtilities.h rename to include/xrpl/basics/ByteUtilities.h index 83d6e8e480a..8013398eba5 100644 --- a/src/ripple/basics/ByteUtilities.h +++ b/include/xrpl/basics/ByteUtilities.h @@ -22,20 +22,22 @@ namespace ripple { - template - constexpr auto kilobytes(T value) noexcept - { - return value * 1024; - } - - template - constexpr auto megabytes(T value) noexcept - { - return kilobytes(kilobytes(value)); - } - - static_assert(kilobytes(2) == 2048, "kilobytes(2) == 2048"); - static_assert(megabytes(3) == 3145728, "megabytes(3) == 3145728"); +template +constexpr auto +kilobytes(T value) noexcept +{ + return value * 1024; } +template +constexpr auto +megabytes(T value) noexcept +{ + return kilobytes(kilobytes(value)); +} + +static_assert(kilobytes(2) == 2048, "kilobytes(2) == 2048"); +static_assert(megabytes(3) == 3145728, "megabytes(3) == 3145728"); +} // namespace ripple + #endif diff --git a/include/xrpl/basics/CompressionAlgorithms.h b/include/xrpl/basics/CompressionAlgorithms.h new file mode 100644 index 00000000000..19db3568d6b --- /dev/null +++ b/include/xrpl/basics/CompressionAlgorithms.h @@ -0,0 +1,168 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2020 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED +#define RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED + +#include + +#include + +#include +#include +#include +#include + +namespace ripple { + +namespace compression_algorithms { + +/** LZ4 block compression. + * @tparam BufferFactory Callable object or lambda. + * Takes the requested buffer size and returns allocated buffer pointer. + * @param in Data to compress + * @param inSize Size of the data + * @param bf Compressed buffer allocator + * @return Size of compressed data, or zero if failed to compress + */ +template +std::size_t +lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf) +{ + if (inSize > UINT32_MAX) + Throw("lz4 compress: invalid size"); + + auto const outCapacity = LZ4_compressBound(inSize); + + // Request the caller to allocate and return the buffer to hold compressed + // data + auto compressed = bf(outCapacity); + + auto compressedSize = LZ4_compress_default( + reinterpret_cast(in), + reinterpret_cast(compressed), + inSize, + outCapacity); + if (compressedSize == 0) + Throw("lz4 compress: failed"); + + return compressedSize; +} + +/** + * @param in Compressed data + * @param inSizeUnchecked Size of compressed data + * @param decompressed Buffer to hold decompressed data + * @param decompressedSizeUnchecked Size of the decompressed buffer + * @return size of the decompressed data + */ +inline std::size_t +lz4Decompress( + std::uint8_t const* in, + std::size_t inSizeUnchecked, + std::uint8_t* decompressed, + std::size_t decompressedSizeUnchecked) +{ + int const inSize = static_cast(inSizeUnchecked); + int const decompressedSize = static_cast(decompressedSizeUnchecked); + + if (inSize <= 0) + Throw("lz4Decompress: integer overflow (input)"); + + if (decompressedSize <= 0) + Throw("lz4Decompress: integer overflow (output)"); + + if (LZ4_decompress_safe( + reinterpret_cast(in), + reinterpret_cast(decompressed), + inSize, + decompressedSize) != decompressedSize) + Throw("lz4Decompress: failed"); + + return decompressedSize; +} + +/** LZ4 block decompression. + * @tparam InputStream ZeroCopyInputStream + * @param in Input source stream + * @param inSize Size of compressed data + * @param decompressed Buffer to hold decompressed data + * @param decompressedSize Size of the decompressed buffer + * @return size of the decompressed data + */ +template +std::size_t +lz4Decompress( + InputStream& in, + std::size_t inSize, + std::uint8_t* decompressed, + std::size_t decompressedSize) +{ + std::vector compressed; + std::uint8_t const* chunk = nullptr; + int chunkSize = 0; + int copiedInSize = 0; + auto const currentBytes = in.ByteCount(); + + // Use the first chunk if it is >= inSize bytes of the compressed message. + // Otherwise copy inSize bytes of chunks into compressed buffer and + // use the buffer to decompress. + while (in.Next(reinterpret_cast(&chunk), &chunkSize)) + { + if (copiedInSize == 0) + { + if (chunkSize >= inSize) + { + copiedInSize = inSize; + break; + } + compressed.resize(inSize); + } + + chunkSize = chunkSize < (inSize - copiedInSize) + ? chunkSize + : (inSize - copiedInSize); + + std::copy(chunk, chunk + chunkSize, compressed.data() + copiedInSize); + + copiedInSize += chunkSize; + + if (copiedInSize == inSize) + { + chunk = compressed.data(); + break; + } + } + + // Put back unused bytes + if (in.ByteCount() > (currentBytes + copiedInSize)) + in.BackUp(in.ByteCount() - currentBytes - copiedInSize); + + if ((copiedInSize == 0 && chunkSize < inSize) || + (copiedInSize > 0 && copiedInSize != inSize)) + Throw("lz4 decompress: insufficient input size"); + + return lz4Decompress(chunk, inSize, decompressed, decompressedSize); +} + +} // namespace compression_algorithms + +} // namespace ripple + +#endif // RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED diff --git a/include/xrpl/basics/CountedObject.h b/include/xrpl/basics/CountedObject.h new file mode 100644 index 00000000000..ef4b6544d20 --- /dev/null +++ b/include/xrpl/basics/CountedObject.h @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED +#define RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED + +#include + +#include +#include +#include +#include + +namespace ripple { + +/** Manages all counted object types. */ +class CountedObjects +{ +public: + static CountedObjects& + getInstance() noexcept; + + using Entry = std::pair; + using List = std::vector; + + List + getCounts(int minimumThreshold) const; + +public: + /** Implementation for @ref CountedObject. + + @internal + */ + class Counter + { + public: + Counter(std::string name) noexcept : name_(std::move(name)), count_(0) + { + // Insert ourselves at the front of the lock-free linked list + CountedObjects& instance = CountedObjects::getInstance(); + Counter* head; + + do + { + head = instance.m_head.load(); + next_ = head; + } while (instance.m_head.exchange(this) != head); + + ++instance.m_count; + } + + ~Counter() noexcept = default; + + int + increment() noexcept + { + return ++count_; + } + + int + decrement() noexcept + { + return --count_; + } + + int + getCount() const noexcept + { + return count_.load(); + } + + Counter* + getNext() const noexcept + { + return next_; + } + + std::string const& + getName() const noexcept + { + return name_; + } + + private: + std::string const name_; + std::atomic count_; + Counter* next_; + }; + +private: + CountedObjects() noexcept; + ~CountedObjects() noexcept = default; + +private: + std::atomic m_count; + std::atomic m_head; +}; + +//------------------------------------------------------------------------------ + +/** Tracks the number of instances of an object. + + Derived classes have their instances counted automatically. This is used + for reporting purposes. + + @ingroup ripple_basics +*/ +template +class CountedObject +{ +private: + static auto& + getCounter() noexcept + { + static CountedObjects::Counter c{beast::type_name()}; + return c; + } + +public: + CountedObject() noexcept + { + getCounter().increment(); + } + + CountedObject(CountedObject const&) noexcept + { + getCounter().increment(); + } + + CountedObject& + operator=(CountedObject const&) noexcept = default; + + ~CountedObject() noexcept + { + getCounter().decrement(); + } +}; + +} // namespace ripple + +#endif diff --git a/src/ripple/basics/DecayingSample.h b/include/xrpl/basics/DecayingSample.h similarity index 80% rename from src/ripple/basics/DecayingSample.h rename to include/xrpl/basics/DecayingSample.h index a55b7e0a65a..20a02572dbb 100644 --- a/src/ripple/basics/DecayingSample.h +++ b/include/xrpl/basics/DecayingSample.h @@ -35,23 +35,22 @@ class DecayingSample using value_type = typename Clock::duration::rep; using time_point = typename Clock::time_point; - DecayingSample () = delete; + DecayingSample() = delete; /** @param now Start time of DecayingSample. */ - explicit DecayingSample (time_point now) - : m_value (value_type()) - , m_when (now) + explicit DecayingSample(time_point now) : m_value(value_type()), m_when(now) { } /** Add a new sample. The value is first aged according to the specified time. */ - value_type add (value_type value, time_point now) + value_type + add(value_type value, time_point now) { - decay (now); + decay(now); m_value += value; return m_value / Window; } @@ -59,23 +58,26 @@ class DecayingSample /** Retrieve the current value in normalized units. The samples are first aged according to the specified time. */ - value_type value (time_point now) + value_type + value(time_point now) { - decay (now); + decay(now); return m_value / Window; } private: // Apply exponential decay based on the specified time. - void decay (time_point now) + void + decay(time_point now) { if (now == m_when) return; if (m_value != value_type()) { - std::size_t elapsed = std::chrono::duration_cast< - std::chrono::seconds>(now - m_when).count(); + std::size_t elapsed = + std::chrono::duration_cast(now - m_when) + .count(); // A span larger than four times the window decays the // value to an insignificant amount so just reset it. @@ -112,40 +114,35 @@ class DecayWindow public: using time_point = typename Clock::time_point; - explicit - DecayWindow (time_point now) - : value_(0) - , when_(now) + explicit DecayWindow(time_point now) : value_(0), when_(now) { } void - add (double value, time_point now) + add(double value, time_point now) { decay(now); value_ += value; } double - value (time_point now) + value(time_point now) { decay(now); return value_ / HalfLife; } private: - static_assert(HalfLife > 0, - "half life must be positive"); + static_assert(HalfLife > 0, "half life must be positive"); void - decay (time_point now) + decay(time_point now) { if (now <= when_) return; using namespace std::chrono; - auto const elapsed = - duration(now - when_).count(); - value_ *= std::pow(2.0, - elapsed / HalfLife); + auto const elapsed = duration(now - when_).count(); + value_ *= std::pow(2.0, -elapsed / HalfLife); when_ = now; } @@ -153,6 +150,6 @@ class DecayWindow time_point when_; }; -} +} // namespace ripple #endif diff --git a/include/xrpl/basics/Expected.h b/include/xrpl/basics/Expected.h new file mode 100644 index 00000000000..9abc7c8432b --- /dev/null +++ b/include/xrpl/basics/Expected.h @@ -0,0 +1,256 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2021 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_EXPECTED_H_INCLUDED +#define RIPPLE_BASICS_EXPECTED_H_INCLUDED + +#include + +#include + +#include + +namespace ripple { + +/** Expected is an approximation of std::expected (hoped for in C++23) + + See: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html + + The implementation is entirely based on boost::outcome_v2::result. +*/ + +// Exception thrown by an invalid access to Expected. +struct bad_expected_access : public std::runtime_error +{ + bad_expected_access() : runtime_error("bad expected access") + { + } +}; + +namespace detail { + +// Custom policy for Expected. Always throw on an invalid access. +struct throw_policy : public boost::outcome_v2::policy::base +{ + template + static constexpr void + wide_value_check(Impl&& self) + { + if (!base::_has_value(std::forward(self))) + Throw(); + } + + template + static constexpr void + wide_error_check(Impl&& self) + { + if (!base::_has_error(std::forward(self))) + Throw(); + } + + template + static constexpr void + wide_exception_check(Impl&& self) + { + if (!base::_has_exception(std::forward(self))) + Throw(); + } +}; + +} // namespace detail + +// Definition of Unexpected, which is used to construct the unexpected +// return type of an Expected. +template +class Unexpected +{ +public: + static_assert(!std::is_same::value, "E must not be void"); + + Unexpected() = delete; + + constexpr explicit Unexpected(E const& e) : val_(e) + { + } + + constexpr explicit Unexpected(E&& e) : val_(std::move(e)) + { + } + + constexpr const E& + value() const& + { + return val_; + } + + constexpr E& + value() & + { + return val_; + } + + constexpr E&& + value() && + { + return std::move(val_); + } + + constexpr const E&& + value() const&& + { + return std::move(val_); + } + +private: + E val_; +}; + +// Unexpected deduction guide that converts array to const*. +template +Unexpected(E (&)[N]) -> Unexpected; + +// Definition of Expected. All of the machinery comes from boost::result. +template +class [[nodiscard]] Expected + : private boost::outcome_v2::result +{ + using Base = boost::outcome_v2::result; + +public: + template + requires std::convertible_to + constexpr Expected(U&& r) + : Base(boost::outcome_v2::in_place_type_t{}, std::forward(r)) + { + } + + template + requires std::convertible_to && (!std::is_reference_v) + constexpr Expected(Unexpected e) + : Base(boost::outcome_v2::in_place_type_t{}, std::move(e.value())) + { + } + + constexpr bool + has_value() const + { + return Base::has_value(); + } + + constexpr T const& + value() const + { + return Base::value(); + } + + constexpr T& + value() + { + return Base::value(); + } + + constexpr E const& + error() const + { + return Base::error(); + } + + constexpr E& + error() + { + return Base::error(); + } + + constexpr explicit + operator bool() const + { + return has_value(); + } + + // Add operator* and operator-> so the Expected API looks a bit more like + // what std::expected is likely to look like. See: + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html + [[nodiscard]] constexpr T& + operator*() + { + return this->value(); + } + + [[nodiscard]] constexpr T const& + operator*() const + { + return this->value(); + } + + [[nodiscard]] constexpr T* + operator->() + { + return &this->value(); + } + + [[nodiscard]] constexpr T const* + operator->() const + { + return &this->value(); + } +}; + +// Specialization of Expected. Allows returning either success +// (without a value) or the reason for the failure. +template +class [[nodiscard]] Expected + : private boost::outcome_v2::result +{ + using Base = boost::outcome_v2::result; + +public: + // The default constructor makes a successful Expected. + // This aligns with std::expected behavior proposed in P0323R10. + constexpr Expected() : Base(boost::outcome_v2::success()) + { + } + + template + requires std::convertible_to && (!std::is_reference_v) + constexpr Expected(Unexpected e) : Base(E(std::move(e.value()))) + { + } + + constexpr E const& + error() const + { + return Base::error(); + } + + constexpr E& + error() + { + return Base::error(); + } + + constexpr explicit + operator bool() const + { + return Base::has_value(); + } +}; + +} // namespace ripple + +#endif // RIPPLE_BASICS_EXPECTED_H_INCLUDED diff --git a/src/ripple/basics/FileUtilities.h b/include/xrpl/basics/FileUtilities.h similarity index 79% rename from src/ripple/basics/FileUtilities.h rename to include/xrpl/basics/FileUtilities.h index d38ffa396d6..49138c83c9e 100644 --- a/src/ripple/basics/FileUtilities.h +++ b/include/xrpl/basics/FileUtilities.h @@ -20,20 +20,25 @@ #ifndef RIPPLE_BASICS_FILEUTILITIES_H_INCLUDED #define RIPPLE_BASICS_FILEUTILITIES_H_INCLUDED -#include #include -#include +#include -namespace ripple -{ +#include -// TODO: Should this one function have its own file, or can it -// be absorbed somewhere else? +namespace ripple { -std::string getFileContents(boost::system::error_code& ec, +std::string +getFileContents( + boost::system::error_code& ec, boost::filesystem::path const& sourcePath, - boost::optional maxSize = boost::none); + std::optional maxSize = std::nullopt); + +void +writeFileContents( + boost::system::error_code& ec, + boost::filesystem::path const& destPath, + std::string const& contents); -} +} // namespace ripple #endif diff --git a/include/xrpl/basics/KeyCache.h b/include/xrpl/basics/KeyCache.h new file mode 100644 index 00000000000..1439a8b3344 --- /dev/null +++ b/include/xrpl/basics/KeyCache.h @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2021 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_KEYCACHE_H +#define RIPPLE_BASICS_KEYCACHE_H + +#include +#include + +namespace ripple { + +using KeyCache = TaggedCache; + +} // namespace ripple + +#endif // RIPPLE_BASICS_KEYCACHE_H diff --git a/src/ripple/basics/LocalValue.h b/include/xrpl/basics/LocalValue.h similarity index 79% rename from src/ripple/basics/LocalValue.h rename to include/xrpl/basics/LocalValue.h index 77c41d2d233..1f53fab2468 100644 --- a/src/ripple/basics/LocalValue.h +++ b/include/xrpl/basics/LocalValue.h @@ -21,6 +21,7 @@ #define RIPPLE_BASICS_LOCALVALUE_H_INCLUDED #include + #include #include @@ -37,7 +38,8 @@ struct LocalValues struct BasicValue { virtual ~BasicValue() = default; - virtual void* get() = 0; + virtual void* + get() = 0; }; template @@ -46,9 +48,12 @@ struct LocalValues T t_; Value() = default; - explicit Value(T const& t) : t_(t) {} + explicit Value(T const& t) : t_(t) + { + } - void* get() override + void* + get() override { return &t_; } @@ -57,42 +62,41 @@ struct LocalValues // Keys are the address of a LocalValue. std::unordered_map> values; - static - inline - void + static inline void cleanup(LocalValues* lvs) { - if (lvs && ! lvs->onCoro) + if (lvs && !lvs->onCoro) delete lvs; } }; -template +template boost::thread_specific_ptr& getLocalValues() { - static boost::thread_specific_ptr< - detail::LocalValues> tsp(&detail::LocalValues::cleanup); + static boost::thread_specific_ptr tsp( + &detail::LocalValues::cleanup); return tsp; } -} // detail +} // namespace detail template class LocalValue { public: template - LocalValue(Args&&... args) - : t_(std::forward(args)...) + LocalValue(Args&&... args) : t_(std::forward(args)...) { } /** Stores instance of T specific to the calling coroutine or thread. */ - T& operator*(); + T& + operator*(); /** Stores instance of T specific to the calling coroutine or thread. */ - T* operator->() + T* + operator->() { return &**this; } @@ -106,7 +110,7 @@ T& LocalValue::operator*() { auto lvs = detail::getLocalValues().get(); - if (! lvs) + if (!lvs) { lvs = new detail::LocalValues(); lvs->onCoro = false; @@ -119,10 +123,11 @@ LocalValue::operator*() return *reinterpret_cast(iter->second->get()); } - return *reinterpret_cast(lvs->values.emplace(this, - std::make_unique>(t_)). - first->second->get()); + return *reinterpret_cast( + lvs->values + .emplace(this, std::make_unique>(t_)) + .first->second->get()); } -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/basics/Log.h b/include/xrpl/basics/Log.h new file mode 100644 index 00000000000..2506b8ea8dd --- /dev/null +++ b/include/xrpl/basics/Log.h @@ -0,0 +1,294 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_LOG_H_INCLUDED +#define RIPPLE_BASICS_LOG_H_INCLUDED + +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace ripple { + +// DEPRECATED use beast::severities::Severity instead +enum LogSeverity { + lsINVALID = -1, // used to indicate an invalid severity + lsTRACE = 0, // Very low-level progress information, details inside + // an operation + lsDEBUG = 1, // Function-level progress information, operations + lsINFO = 2, // Server-level progress information, major operations + lsWARNING = 3, // Conditions that warrant human attention, may indicate + // a problem + lsERROR = 4, // A condition that indicates a problem + lsFATAL = 5 // A severe condition that indicates a server problem +}; + +/** Manages partitions for logging. */ +class Logs +{ +private: + class Sink : public beast::Journal::Sink + { + private: + Logs& logs_; + std::string partition_; + + public: + Sink( + std::string const& partition, + beast::severities::Severity thresh, + Logs& logs); + + Sink(Sink const&) = delete; + Sink& + operator=(Sink const&) = delete; + + void + write(beast::severities::Severity level, std::string const& text) + override; + + void + writeAlways(beast::severities::Severity level, std::string const& text) + override; + }; + + /** Manages a system file containing logged output. + The system file remains open during program execution. Interfaces + are provided for interoperating with standard log management + tools like logrotate(8): + http://linuxcommand.org/man_pages/logrotate8.html + @note None of the listed interfaces are thread-safe. + */ + class File + { + public: + /** Construct with no associated system file. + A system file may be associated later with @ref open. + @see open + */ + File(); + + /** Destroy the object. + If a system file is associated, it will be flushed and closed. + */ + ~File() = default; + + /** Determine if a system file is associated with the log. + @return `true` if a system file is associated and opened for + writing. + */ + bool + isOpen() const noexcept; + + /** Associate a system file with the log. + If the file does not exist an attempt is made to create it + and open it for writing. If the file already exists an attempt is + made to open it for appending. + If a system file is already associated with the log, it is closed + first. + @return `true` if the file was opened. + */ + bool + open(boost::filesystem::path const& path); + + /** Close and re-open the system file associated with the log + This assists in interoperating with external log management tools. + @return `true` if the file was opened. + */ + bool + closeAndReopen(); + + /** Close the system file if it is open. */ + void + close(); + + /** write to the log file. + Does nothing if there is no associated system file. + */ + void + write(char const* text); + + /** write to the log file and append an end of line marker. + Does nothing if there is no associated system file. + */ + void + writeln(char const* text); + + /** Write to the log file using std::string. */ + /** @{ */ + void + write(std::string const& str) + { + write(str.c_str()); + } + + void + writeln(std::string const& str) + { + writeln(str.c_str()); + } + /** @} */ + + private: + std::unique_ptr m_stream; + boost::filesystem::path m_path; + }; + + std::mutex mutable mutex_; + std::map< + std::string, + std::unique_ptr, + boost::beast::iless> + sinks_; + beast::severities::Severity thresh_; + File file_; + bool silent_ = false; + +public: + Logs(beast::severities::Severity level); + + Logs(Logs const&) = delete; + Logs& + operator=(Logs const&) = delete; + + virtual ~Logs() = default; + + bool + open(boost::filesystem::path const& pathToLogFile); + + beast::Journal::Sink& + get(std::string const& name); + + beast::Journal::Sink& + operator[](std::string const& name); + + beast::Journal + journal(std::string const& name); + + beast::severities::Severity + threshold() const; + + void + threshold(beast::severities::Severity thresh); + + std::vector> + partition_severities() const; + + void + write( + beast::severities::Severity level, + std::string const& partition, + std::string const& text, + bool console); + + std::string + rotate(); + + /** + * Set flag to write logs to stderr (false) or not (true). + * + * @param bSilent Set flag accordingly. + */ + void + silent(bool bSilent) + { + silent_ = bSilent; + } + + virtual std::unique_ptr + makeSink( + std::string const& partition, + beast::severities::Severity startingLevel); + +public: + static LogSeverity + fromSeverity(beast::severities::Severity level); + + static beast::severities::Severity + toSeverity(LogSeverity level); + + static std::string + toString(LogSeverity s); + + static LogSeverity + fromString(std::string const& s); + +private: + enum { + // Maximum line length for log messages. + // If the message exceeds this length it will be truncated with elipses. + maximumMessageCharacters = 12 * 1024 + }; + + static void + format( + std::string& output, + std::string const& message, + beast::severities::Severity severity, + std::string const& partition); +}; + +// Wraps a Journal::Stream to skip evaluation of +// expensive argument lists if the stream is not active. +#ifndef JLOG +#define JLOG(x) \ + if (!x) \ + { \ + } \ + else \ + x +#endif + +#ifndef CLOG +#define CLOG(ss) \ + if (!ss) \ + ; \ + else \ + *ss +#endif + +//------------------------------------------------------------------------------ +// Debug logging: + +/** Set the sink for the debug journal. + + @param sink unique_ptr to new debug Sink. + @return unique_ptr to the previous Sink. nullptr if there was no Sink. +*/ +std::unique_ptr +setDebugLogSink(std::unique_ptr sink); + +/** Returns a debug journal. + The journal may drain to a null sink, so its output + may never be seen. Never use it for critical + information. +*/ +beast::Journal +debugLog(); + +} // namespace ripple + +#endif diff --git a/include/xrpl/basics/MathUtilities.h b/include/xrpl/basics/MathUtilities.h new file mode 100644 index 00000000000..516c07f377f --- /dev/null +++ b/include/xrpl/basics/MathUtilities.h @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2020 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_MATHUTILITIES_H_INCLUDED +#define RIPPLE_BASICS_MATHUTILITIES_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +/** Calculate one number divided by another number in percentage. + * The result is rounded up to the next integer, and capped in the range [0,100] + * E.g. calculatePercent(1, 100) = 1 because 1/100 = 0.010000 + * calculatePercent(1, 99) = 2 because 1/99 = 0.010101 + * calculatePercent(0, 100) = 0 + * calculatePercent(100, 100) = 100 + * calculatePercent(200, 100) = 100 because the result is capped to 100 + * + * @param count dividend + * @param total divisor + * @return the percentage, in [0, 100] + * + * @note total cannot be zero. + * */ +constexpr std::size_t +calculatePercent(std::size_t count, std::size_t total) +{ + assert(total != 0); // NOTE No XRPL_ASSERT here, because constexpr + return ((std::min(count, total) * 100) + total - 1) / total; +} + +// unit tests +static_assert(calculatePercent(1, 2) == 50); +static_assert(calculatePercent(0, 100) == 0); +static_assert(calculatePercent(100, 100) == 100); +static_assert(calculatePercent(200, 100) == 100); +static_assert(calculatePercent(1, 100) == 1); +static_assert(calculatePercent(1, 99) == 2); +static_assert(calculatePercent(6, 14) == 43); +static_assert(calculatePercent(29, 33) == 88); +static_assert(calculatePercent(1, 64) == 2); +static_assert(calculatePercent(0, 100'000'000) == 0); +static_assert(calculatePercent(1, 100'000'000) == 1); +static_assert(calculatePercent(50'000'000, 100'000'000) == 50); +static_assert(calculatePercent(50'000'001, 100'000'000) == 51); +static_assert(calculatePercent(99'999'999, 100'000'000) == 100); + +} // namespace ripple + +#endif diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h new file mode 100644 index 00000000000..9ee05bfb450 --- /dev/null +++ b/include/xrpl/basics/Number.h @@ -0,0 +1,410 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2022 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_NUMBER_H_INCLUDED +#define RIPPLE_BASICS_NUMBER_H_INCLUDED + +#include +#include +#include +#include + +namespace ripple { + +class Number; + +std::string +to_string(Number const& amount); + +class Number +{ + using rep = std::int64_t; + rep mantissa_{0}; + int exponent_{std::numeric_limits::lowest()}; + +public: + // The range for the mantissa when normalized + constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL; + constexpr static std::int64_t maxMantissa = 9'999'999'999'999'999LL; + + // The range for the exponent when normalized + constexpr static int minExponent = -32768; + constexpr static int maxExponent = 32768; + + struct unchecked + { + explicit unchecked() = default; + }; + + explicit constexpr Number() = default; + + Number(rep mantissa); + explicit Number(rep mantissa, int exponent); + explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept; + + constexpr rep + mantissa() const noexcept; + constexpr int + exponent() const noexcept; + + constexpr Number + operator+() const noexcept; + constexpr Number + operator-() const noexcept; + Number& + operator++(); + Number + operator++(int); + Number& + operator--(); + Number + operator--(int); + + Number& + operator+=(Number const& x); + Number& + operator-=(Number const& x); + + Number& + operator*=(Number const& x); + Number& + operator/=(Number const& x); + + static constexpr Number + min() noexcept; + static constexpr Number + max() noexcept; + static constexpr Number + lowest() noexcept; + + /** Conversions to Number are implicit and conversions away from Number + * are explicit. This design encourages and facilitates the use of Number + * as the preferred type for floating point arithmetic as it makes + * "mixed mode" more convenient, e.g. MPTAmount + Number. + */ + explicit + operator rep() const; // round to nearest, even on tie + + friend constexpr bool + operator==(Number const& x, Number const& y) noexcept + { + return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_; + } + + friend constexpr bool + operator!=(Number const& x, Number const& y) noexcept + { + return !(x == y); + } + + friend constexpr bool + operator<(Number const& x, Number const& y) noexcept + { + // If the two amounts have different signs (zero is treated as positive) + // then the comparison is true iff the left is negative. + bool const lneg = x.mantissa_ < 0; + bool const rneg = y.mantissa_ < 0; + + if (lneg != rneg) + return lneg; + + // Both have same sign and the left is zero: the right must be + // greater than 0. + if (x.mantissa_ == 0) + return y.mantissa_ > 0; + + // Both have same sign, the right is zero and the left is non-zero. + if (y.mantissa_ == 0) + return false; + + // Both have the same sign, compare by exponents: + if (x.exponent_ > y.exponent_) + return lneg; + if (x.exponent_ < y.exponent_) + return !lneg; + + // If equal exponents, compare mantissas + return x.mantissa_ < y.mantissa_; + } + + /** Return the sign of the amount */ + constexpr int + signum() const noexcept + { + return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0); + } + + friend constexpr bool + operator>(Number const& x, Number const& y) noexcept + { + return y < x; + } + + friend constexpr bool + operator<=(Number const& x, Number const& y) noexcept + { + return !(y < x); + } + + friend constexpr bool + operator>=(Number const& x, Number const& y) noexcept + { + return !(x < y); + } + + friend std::ostream& + operator<<(std::ostream& os, Number const& x) + { + return os << to_string(x); + } + + // Thread local rounding control. Default is to_nearest + enum rounding_mode { to_nearest, towards_zero, downward, upward }; + static rounding_mode + getround(); + // Returns previously set mode + static rounding_mode + setround(rounding_mode mode); + +private: + static thread_local rounding_mode mode_; + + void + normalize(); + constexpr bool + isnormal() const noexcept; + + class Guard; +}; + +inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept + : mantissa_{mantissa}, exponent_{exponent} +{ +} + +inline Number::Number(rep mantissa, int exponent) + : mantissa_{mantissa}, exponent_{exponent} +{ + normalize(); +} + +inline Number::Number(rep mantissa) : Number{mantissa, 0} +{ +} + +inline constexpr Number::rep +Number::mantissa() const noexcept +{ + return mantissa_; +} + +inline constexpr int +Number::exponent() const noexcept +{ + return exponent_; +} + +inline constexpr Number +Number::operator+() const noexcept +{ + return *this; +} + +inline constexpr Number +Number::operator-() const noexcept +{ + auto x = *this; + x.mantissa_ = -x.mantissa_; + return x; +} + +inline Number& +Number::operator++() +{ + *this += Number{1000000000000000, -15, unchecked{}}; + return *this; +} + +inline Number +Number::operator++(int) +{ + auto x = *this; + ++(*this); + return x; +} + +inline Number& +Number::operator--() +{ + *this -= Number{1000000000000000, -15, unchecked{}}; + return *this; +} + +inline Number +Number::operator--(int) +{ + auto x = *this; + --(*this); + return x; +} + +inline Number& +Number::operator-=(Number const& x) +{ + return *this += -x; +} + +inline Number +operator+(Number const& x, Number const& y) +{ + auto z = x; + z += y; + return z; +} + +inline Number +operator-(Number const& x, Number const& y) +{ + auto z = x; + z -= y; + return z; +} + +inline Number +operator*(Number const& x, Number const& y) +{ + auto z = x; + z *= y; + return z; +} + +inline Number +operator/(Number const& x, Number const& y) +{ + auto z = x; + z /= y; + return z; +} + +inline constexpr Number +Number::min() noexcept +{ + return Number{minMantissa, minExponent, unchecked{}}; +} + +inline constexpr Number +Number::max() noexcept +{ + return Number{maxMantissa, maxExponent, unchecked{}}; +} + +inline constexpr Number +Number::lowest() noexcept +{ + return -Number{maxMantissa, maxExponent, unchecked{}}; +} + +inline constexpr bool +Number::isnormal() const noexcept +{ + auto const abs_m = mantissa_ < 0 ? -mantissa_ : mantissa_; + return minMantissa <= abs_m && abs_m <= maxMantissa && + minExponent <= exponent_ && exponent_ <= maxExponent; +} + +inline constexpr Number +abs(Number x) noexcept +{ + if (x < Number{}) + x = -x; + return x; +} + +// Returns f^n +// Uses a log_2(n) number of multiplications + +Number +power(Number const& f, unsigned n); + +// Returns f^(1/d) +// Uses Newton–Raphson iterations until the result stops changing +// to find the root of the polynomial g(x) = x^d - f + +Number +root(Number f, unsigned d); + +Number +root2(Number f); + +// Returns f^(n/d) + +Number +power(Number const& f, unsigned n, unsigned d); + +// Return 0 if abs(x) < limit, else returns x + +inline constexpr Number +squelch(Number const& x, Number const& limit) noexcept +{ + if (abs(x) < limit) + return Number{}; + return x; +} + +class saveNumberRoundMode +{ + Number::rounding_mode mode_; + +public: + ~saveNumberRoundMode() + { + Number::setround(mode_); + } + explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept + : mode_{mode} + { + } + saveNumberRoundMode(saveNumberRoundMode const&) = delete; + saveNumberRoundMode& + operator=(saveNumberRoundMode const&) = delete; +}; + +// saveNumberRoundMode doesn't do quite enough for us. What we want is a +// Number::RoundModeGuard that sets the new mode and restores the old mode +// when it leaves scope. Since Number doesn't have that facility, we'll +// build it here. +class NumberRoundModeGuard +{ + saveNumberRoundMode saved_; + +public: + explicit NumberRoundModeGuard(Number::rounding_mode mode) noexcept + : saved_{Number::setround(mode)} + { + } + + NumberRoundModeGuard(NumberRoundModeGuard const&) = delete; + + NumberRoundModeGuard& + operator=(NumberRoundModeGuard const&) = delete; +}; + +} // namespace ripple + +#endif // RIPPLE_BASICS_NUMBER_H_INCLUDED diff --git a/src/ripple/basics/README.md b/include/xrpl/basics/README.md similarity index 100% rename from src/ripple/basics/README.md rename to include/xrpl/basics/README.md diff --git a/include/xrpl/basics/RangeSet.h b/include/xrpl/basics/RangeSet.h new file mode 100644 index 00000000000..0ffed2db1e2 --- /dev/null +++ b/include/xrpl/basics/RangeSet.h @@ -0,0 +1,196 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_RANGESET_H_INCLUDED +#define RIPPLE_BASICS_RANGESET_H_INCLUDED + +#include + +#include +#include +#include + +#include +#include +#include + +namespace ripple { + +/** A closed interval over the domain T. + + For an instance ClosedInterval c, this represents the closed interval + (c.first(), c.last()). A single element interval has c.first() == c.last(). + + This is simply a type-alias for boost interval container library interval + set, so users should consult that documentation for available supporting + member and free functions. +*/ +template +using ClosedInterval = boost::icl::closed_interval; + +/** Create a closed range interval + + Helper function to create a closed range interval without having to qualify + the template argument. +*/ +template +ClosedInterval +range(T low, T high) +{ + return ClosedInterval(low, high); +} + +/** A set of closed intervals over the domain T. + + Represents a set of values of the domain T using the minimum number + of disjoint ClosedInterval. This is useful to represent ranges of + T where a few instances are missing, e.g. the set 1-5,8-9,11-14. + + This is simply a type-alias for boost interval container library interval + set, so users should consult that documentation for available supporting + member and free functions. +*/ +template +using RangeSet = boost::icl::interval_set>; + +/** Convert a ClosedInterval to a styled string + + The styled string is + "c.first()-c.last()" if c.first() != c.last() + "c.first()" if c.first() == c.last() + + @param ci The closed interval to convert + @return The style string +*/ +template +std::string +to_string(ClosedInterval const& ci) +{ + if (ci.first() == ci.last()) + return std::to_string(ci.first()); + return std::to_string(ci.first()) + "-" + std::to_string(ci.last()); +} + +/** Convert the given RangeSet to a styled string. + + The styled string representation is the set of disjoint intervals joined + by commas. The string "empty" is returned if the set is empty. + + @param rs The rangeset to convert + @return The styled string +*/ +template +std::string +to_string(RangeSet const& rs) +{ + if (rs.empty()) + return "empty"; + + std::string s; + for (auto const& interval : rs) + s += ripple::to_string(interval) + ","; + s.pop_back(); + + return s; +} + +/** Convert the given styled string to a RangeSet. + + The styled string representation is the set + of disjoint intervals joined by commas. + + @param rs The set to be populated + @param s The styled string to convert + @return True on successfully converting styled string +*/ +template +[[nodiscard]] bool +from_string(RangeSet& rs, std::string const& s) +{ + std::vector intervals; + std::vector tokens; + bool result{true}; + + rs.clear(); + boost::split(tokens, s, boost::algorithm::is_any_of(",")); + for (auto const& t : tokens) + { + boost::split(intervals, t, boost::algorithm::is_any_of("-")); + switch (intervals.size()) + { + case 1: { + T front; + if (!beast::lexicalCastChecked(front, intervals.front())) + result = false; + else + rs.insert(front); + break; + } + case 2: { + T front; + if (!beast::lexicalCastChecked(front, intervals.front())) + result = false; + else + { + T back; + if (!beast::lexicalCastChecked(back, intervals.back())) + result = false; + else + rs.insert(range(front, back)); + } + break; + } + default: + result = false; + } + + if (!result) + break; + intervals.clear(); + } + + if (!result) + rs.clear(); + return result; +} + +/** Find the largest value not in the set that is less than a given value. + + @param rs The set of interest + @param t The value that must be larger than the result + @param minVal (Default is 0) The smallest allowed value + @return The largest v such that minV <= v < t and !contains(rs, v) or + std::nullopt if no such v exists. +*/ +template +std::optional +prevMissing(RangeSet const& rs, T t, T minVal = 0) +{ + if (rs.empty() || t == minVal) + return std::nullopt; + RangeSet tgt{ClosedInterval{minVal, t - 1}}; + tgt -= rs; + if (tgt.empty()) + return std::nullopt; + return boost::icl::last(tgt); +} + +} // namespace ripple + +#endif diff --git a/src/ripple/basics/Resolver.h b/include/xrpl/basics/Resolver.h similarity index 76% rename from src/ripple/basics/Resolver.h rename to include/xrpl/basics/Resolver.h index 1bc0d7766d9..2ed32f39bd0 100644 --- a/src/ripple/basics/Resolver.h +++ b/include/xrpl/basics/Resolver.h @@ -20,29 +20,32 @@ #ifndef RIPPLE_BASICS_RESOLVER_H_INCLUDED #define RIPPLE_BASICS_RESOLVER_H_INCLUDED -#include -#include +#include -#include +#include +#include namespace ripple { class Resolver { public: - using HandlerType = std::function < - void (std::string, std::vector ) >; + using HandlerType = + std::function)>; - virtual ~Resolver () = 0; + virtual ~Resolver() = 0; /** Issue an asynchronous stop request. */ - virtual void stop_async () = 0; + virtual void + stop_async() = 0; /** Issue a synchronous stop request. */ - virtual void stop () = 0; + virtual void + stop() = 0; /** Issue a synchronous start request. */ - virtual void start () = 0; + virtual void + start() = 0; /** resolve all hostnames on the list @param names the names to be resolved @@ -50,17 +53,19 @@ class Resolver */ /** @{ */ template - void resolve (std::vector const& names, Handler handler) + void + resolve(std::vector const& names, Handler handler) { - resolve (names, HandlerType (handler)); + resolve(names, HandlerType(handler)); } - virtual void resolve ( - std::vector const& names, + virtual void + resolve( + std::vector const& names, HandlerType const& handler) = 0; /** @} */ }; -} +} // namespace ripple #endif diff --git a/src/ripple/basics/ResolverAsio.h b/include/xrpl/basics/ResolverAsio.h similarity index 87% rename from src/ripple/basics/ResolverAsio.h rename to include/xrpl/basics/ResolverAsio.h index 99ebee89e22..49700d2b243 100644 --- a/src/ripple/basics/ResolverAsio.h +++ b/include/xrpl/basics/ResolverAsio.h @@ -20,8 +20,9 @@ #ifndef RIPPLE_BASICS_RESOLVERASIO_H_INCLUDED #define RIPPLE_BASICS_RESOLVERASIO_H_INCLUDED -#include -#include +#include +#include + #include namespace ripple { @@ -31,11 +32,10 @@ class ResolverAsio : public Resolver public: explicit ResolverAsio() = default; - static - std::unique_ptr New ( - boost::asio::io_service&, beast::Journal); + static std::unique_ptr + New(boost::asio::io_service&, beast::Journal); }; -} +} // namespace ripple #endif diff --git a/include/xrpl/basics/SHAMapHash.h b/include/xrpl/basics/SHAMapHash.h new file mode 100644 index 00000000000..2d2dcdc3efa --- /dev/null +++ b/include/xrpl/basics/SHAMapHash.h @@ -0,0 +1,121 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2021 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED +#define RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED + +#include +#include + +#include + +namespace ripple { + +// A SHAMapHash is the hash of a node in a SHAMap, and also the +// type of the hash of the entire SHAMap. + +class SHAMapHash +{ + uint256 hash_; + +public: + SHAMapHash() = default; + explicit SHAMapHash(uint256 const& hash) : hash_(hash) + { + } + + uint256 const& + as_uint256() const + { + return hash_; + } + uint256& + as_uint256() + { + return hash_; + } + bool + isZero() const + { + return hash_.isZero(); + } + bool + isNonZero() const + { + return hash_.isNonZero(); + } + int + signum() const + { + return hash_.signum(); + } + void + zero() + { + hash_.zero(); + } + + friend bool + operator==(SHAMapHash const& x, SHAMapHash const& y) + { + return x.hash_ == y.hash_; + } + + friend bool + operator<(SHAMapHash const& x, SHAMapHash const& y) + { + return x.hash_ < y.hash_; + } + + friend std::ostream& + operator<<(std::ostream& os, SHAMapHash const& x) + { + return os << x.hash_; + } + + friend std::string + to_string(SHAMapHash const& x) + { + return to_string(x.hash_); + } + + template + friend void + hash_append(H& h, SHAMapHash const& x) + { + hash_append(h, x.hash_); + } +}; + +inline bool +operator!=(SHAMapHash const& x, SHAMapHash const& y) +{ + return !(x == y); +} + +template <> +inline std::size_t +extract(SHAMapHash const& key) +{ + return *reinterpret_cast(key.as_uint256().data()); +} + +} // namespace ripple + +#endif // RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED diff --git a/include/xrpl/basics/SlabAllocator.h b/include/xrpl/basics/SlabAllocator.h new file mode 100644 index 00000000000..5e3a2b5138e --- /dev/null +++ b/include/xrpl/basics/SlabAllocator.h @@ -0,0 +1,441 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright 2022, Nikolaos D. Bougalis + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED +#define RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if BOOST_OS_LINUX +#include +#endif + +namespace ripple { + +template +class SlabAllocator +{ + static_assert( + sizeof(Type) >= sizeof(std::uint8_t*), + "SlabAllocator: the requested object must be larger than a pointer."); + + static_assert(alignof(Type) == 8 || alignof(Type) == 4); + + /** A block of memory that is owned by a slab allocator */ + struct SlabBlock + { + // A mutex to protect the freelist for this block: + std::mutex m_; + + // A linked list of appropriately sized free buffers: + std::uint8_t* l_ = nullptr; + + // The next memory block + SlabBlock* next_; + + // The underlying memory block: + std::uint8_t const* const p_ = nullptr; + + // The extent of the underlying memory block: + std::size_t const size_; + + SlabBlock( + SlabBlock* next, + std::uint8_t* data, + std::size_t size, + std::size_t item) + : next_(next), p_(data), size_(size) + { + // We don't need to grab the mutex here, since we're the only + // ones with access at this moment. + + while (data + item <= p_ + size_) + { + // Use memcpy to avoid unaligned UB + // (will optimize to equivalent code) + std::memcpy(data, &l_, sizeof(std::uint8_t*)); + l_ = data; + data += item; + } + } + + ~SlabBlock() + { + // Calling this destructor will release the allocated memory but + // will not properly destroy any objects that are constructed in + // the block itself. + } + + SlabBlock(SlabBlock const& other) = delete; + SlabBlock& + operator=(SlabBlock const& other) = delete; + + SlabBlock(SlabBlock&& other) = delete; + SlabBlock& + operator=(SlabBlock&& other) = delete; + + /** Determines whether the given pointer belongs to this allocator */ + bool + own(std::uint8_t const* p) const noexcept + { + return (p >= p_) && (p < p_ + size_); + } + + std::uint8_t* + allocate() noexcept + { + std::uint8_t* ret; + + { + std::lock_guard l(m_); + + ret = l_; + + if (ret) + { + // Use memcpy to avoid unaligned UB + // (will optimize to equivalent code) + std::memcpy(&l_, ret, sizeof(std::uint8_t*)); + } + } + + return ret; + } + + /** Return an item to this allocator's freelist. + + @param ptr The pointer to the chunk of memory being deallocated. + + @note This is a dangerous, private interface; the item being + returned should belong to this allocator. Debug builds + will check and assert if this is not the case. Release + builds will not. + */ + void + deallocate(std::uint8_t* ptr) noexcept + { + XRPL_ASSERT( + own(ptr), + "ripple::SlabAllocator::SlabBlock::deallocate : own input"); + + std::lock_guard l(m_); + + // Use memcpy to avoid unaligned UB + // (will optimize to equivalent code) + std::memcpy(ptr, &l_, sizeof(std::uint8_t*)); + l_ = ptr; + } + }; + +private: + // A linked list of slabs + std::atomic slabs_ = nullptr; + + // The alignment requirements of the item we're allocating: + std::size_t const itemAlignment_; + + // The size of an item, including the extra bytes requested and + // any padding needed for alignment purposes: + std::size_t const itemSize_; + + // The size of each individual slab: + std::size_t const slabSize_; + +public: + /** Constructs a slab allocator able to allocate objects of a fixed size + + @param count the number of items the slab allocator can allocate; note + that a count of 0 is valid and means that the allocator + is, effectively, disabled. This can be very useful in some + contexts (e.g. when mimimal memory usage is needed) and + allows for graceful failure. + */ + constexpr explicit SlabAllocator( + std::size_t extra, + std::size_t alloc = 0, + std::size_t align = 0) + : itemAlignment_(align ? align : alignof(Type)) + , itemSize_( + boost::alignment::align_up(sizeof(Type) + extra, itemAlignment_)) + , slabSize_(alloc) + { + XRPL_ASSERT( + (itemAlignment_ & (itemAlignment_ - 1)) == 0, + "ripple::SlabAllocator::SlabAllocator : valid alignment"); + } + + SlabAllocator(SlabAllocator const& other) = delete; + SlabAllocator& + operator=(SlabAllocator const& other) = delete; + + SlabAllocator(SlabAllocator&& other) = delete; + SlabAllocator& + operator=(SlabAllocator&& other) = delete; + + ~SlabAllocator() + { + // FIXME: We can't destroy the memory blocks we've allocated, because + // we can't be sure that they are not being used. Cleaning the + // shutdown process up could make this possible. + } + + /** Returns the size of the memory block this allocator returns. */ + constexpr std::size_t + size() const noexcept + { + return itemSize_; + } + + /** Returns a suitably aligned pointer, if one is available. + + @return a pointer to a block of memory from the allocator, or + nullptr if the allocator can't satisfy this request. + */ + std::uint8_t* + allocate() noexcept + { + auto slab = slabs_.load(); + + while (slab != nullptr) + { + if (auto ret = slab->allocate()) + return ret; + + slab = slab->next_; + } + + // No slab can satisfy our request, so we attempt to allocate a new + // one here: + std::size_t size = slabSize_; + + // We want to allocate the memory at a 2 MiB boundary, to make it + // possible to use hugepage mappings on Linux: + auto buf = + boost::alignment::aligned_alloc(megabytes(std::size_t(2)), size); + + // clang-format off + if (!buf) [[unlikely]] + return nullptr; + // clang-format on + +#if BOOST_OS_LINUX + // When allocating large blocks, attempt to leverage Linux's + // transparent hugepage support. It is unclear and difficult + // to accurately determine if doing this impacts performance + // enough to justify using platform-specific tricks. + if (size >= megabytes(std::size_t(4))) + madvise(buf, size, MADV_HUGEPAGE); +#endif + + // We need to carve out a bit of memory for the slab header + // and then align the rest appropriately: + auto slabData = reinterpret_cast( + reinterpret_cast(buf) + sizeof(SlabBlock)); + auto slabSize = size - sizeof(SlabBlock); + + // This operation is essentially guaranteed not to fail but + // let's be careful anyways. + if (!boost::alignment::align( + itemAlignment_, itemSize_, slabData, slabSize)) + { + boost::alignment::aligned_free(buf); + return nullptr; + } + + slab = new (buf) SlabBlock( + slabs_.load(), + reinterpret_cast(slabData), + slabSize, + itemSize_); + + // Link the new slab + while (!slabs_.compare_exchange_weak( + slab->next_, + slab, + std::memory_order_release, + std::memory_order_relaxed)) + { + ; // Nothing to do + } + + return slab->allocate(); + } + + /** Returns the memory block to the allocator. + + @param ptr A pointer to a memory block. + @param size If non-zero, a hint as to the size of the block. + @return true if this memory block belonged to the allocator and has + been released; false otherwise. + */ + bool + deallocate(std::uint8_t* ptr) noexcept + { + XRPL_ASSERT( + ptr, + "ripple::SlabAllocator::SlabAllocator::deallocate : non-null " + "input"); + + for (auto slab = slabs_.load(); slab != nullptr; slab = slab->next_) + { + if (slab->own(ptr)) + { + slab->deallocate(ptr); + return true; + } + } + + return false; + } +}; + +/** A collection of slab allocators of various sizes for a given type. */ +template +class SlabAllocatorSet +{ +private: + // The list of allocators that belong to this set + boost::container::static_vector, 64> allocators_; + + std::size_t maxSize_ = 0; + +public: + class SlabConfig + { + friend class SlabAllocatorSet; + + private: + std::size_t extra; + std::size_t alloc; + std::size_t align; + + public: + constexpr SlabConfig( + std::size_t extra_, + std::size_t alloc_ = 0, + std::size_t align_ = alignof(Type)) + : extra(extra_), alloc(alloc_), align(align_) + { + } + }; + + constexpr SlabAllocatorSet(std::vector cfg) + { + // Ensure that the specified allocators are sorted from smallest to + // largest by size: + std::sort( + std::begin(cfg), + std::end(cfg), + [](SlabConfig const& a, SlabConfig const& b) { + return a.extra < b.extra; + }); + + // We should never have two slabs of the same size + if (std::adjacent_find( + std::begin(cfg), + std::end(cfg), + [](SlabConfig const& a, SlabConfig const& b) { + return a.extra == b.extra; + }) != cfg.end()) + { + throw std::runtime_error( + "SlabAllocatorSet<" + beast::type_name() + + ">: duplicate slab size"); + } + + for (auto const& c : cfg) + { + auto& a = allocators_.emplace_back(c.extra, c.alloc, c.align); + + if (a.size() > maxSize_) + maxSize_ = a.size(); + } + } + + SlabAllocatorSet(SlabAllocatorSet const& other) = delete; + SlabAllocatorSet& + operator=(SlabAllocatorSet const& other) = delete; + + SlabAllocatorSet(SlabAllocatorSet&& other) = delete; + SlabAllocatorSet& + operator=(SlabAllocatorSet&& other) = delete; + + ~SlabAllocatorSet() + { + } + + /** Returns a suitably aligned pointer, if one is available. + + @param extra The number of extra bytes, above and beyond the size of + the object, that should be returned by the allocator. + + @return a pointer to a block of memory, or nullptr if the allocator + can't satisfy this request. + */ + std::uint8_t* + allocate(std::size_t extra) noexcept + { + if (auto const size = sizeof(Type) + extra; size <= maxSize_) + { + for (auto& a : allocators_) + { + if (a.size() >= size) + return a.allocate(); + } + } + + return nullptr; + } + + /** Returns the memory block to the allocator. + + @param ptr A pointer to a memory block. + + @return true if this memory block belonged to one of the allocators + in this set and has been released; false otherwise. + */ + bool + deallocate(std::uint8_t* ptr) noexcept + { + for (auto& a : allocators_) + { + if (a.deallocate(ptr)) + return true; + } + + return false; + } +}; + +} // namespace ripple + +#endif // RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED diff --git a/include/xrpl/basics/Slice.h b/include/xrpl/basics/Slice.h new file mode 100644 index 00000000000..65d7acfd94e --- /dev/null +++ b/include/xrpl/basics/Slice.h @@ -0,0 +1,267 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_SLICE_H_INCLUDED +#define RIPPLE_BASICS_SLICE_H_INCLUDED + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +/** An immutable linear range of bytes. + + A fully constructed Slice is guaranteed to be in a valid state. + A Slice is lightweight and copyable, it retains no ownership + of the underlying memory. +*/ +class Slice +{ +private: + std::uint8_t const* data_ = nullptr; + std::size_t size_ = 0; + +public: + using value_type = std::uint8_t; + using const_iterator = value_type const*; + + /** Default constructed Slice has length 0. */ + Slice() noexcept = default; + + Slice(Slice const&) noexcept = default; + Slice& + operator=(Slice const&) noexcept = default; + + /** Create a slice pointing to existing memory. */ + Slice(void const* data, std::size_t size) noexcept + : data_(reinterpret_cast(data)), size_(size) + { + } + + /** Return `true` if the byte range is empty. */ + [[nodiscard]] bool + empty() const noexcept + { + return size_ == 0; + } + + /** Returns the number of bytes in the storage. + + This may be zero for an empty range. + */ + /** @{ */ + [[nodiscard]] std::size_t + size() const noexcept + { + return size_; + } + + [[nodiscard]] std::size_t + length() const noexcept + { + return size_; + } + /** @} */ + + /** Return a pointer to beginning of the storage. + @note The return type is guaranteed to be a pointer + to a single byte, to facilitate pointer arithmetic. + */ + std::uint8_t const* + data() const noexcept + { + return data_; + } + + /** Access raw bytes. */ + std::uint8_t + operator[](std::size_t i) const noexcept + { + XRPL_ASSERT( + i < size_, + "ripple::Slice::operator[](std::size_t) const : valid input"); + return data_[i]; + } + + /** Advance the buffer. */ + /** @{ */ + Slice& + operator+=(std::size_t n) + { + if (n > size_) + Throw("too small"); + data_ += n; + size_ -= n; + return *this; + } + + Slice + operator+(std::size_t n) const + { + Slice temp = *this; + return temp += n; + } + /** @} */ + + /** Shrinks the slice by moving its start forward by n characters. */ + void + remove_prefix(std::size_t n) + { + data_ += n; + size_ -= n; + } + + /** Shrinks the slice by moving its end backward by n characters. */ + void + remove_suffix(std::size_t n) + { + size_ -= n; + } + + const_iterator + begin() const noexcept + { + return data_; + } + + const_iterator + cbegin() const noexcept + { + return data_; + } + + const_iterator + end() const noexcept + { + return data_ + size_; + } + + const_iterator + cend() const noexcept + { + return data_ + size_; + } + + /** Return a "sub slice" of given length starting at the given position + + Note that the subslice encompasses the range [pos, pos + rcount), + where rcount is the smaller of count and size() - pos. + + @param pos position of the first character + @count requested length + + @returns The requested subslice, if the request is valid. + @throws std::out_of_range if pos > size() + */ + Slice + substr( + std::size_t pos, + std::size_t count = std::numeric_limits::max()) const + { + if (pos > size()) + throw std::out_of_range("Requested sub-slice is out of bounds"); + + return {data_ + pos, std::min(count, size() - pos)}; + } +}; + +//------------------------------------------------------------------------------ + +template +inline void +hash_append(Hasher& h, Slice const& v) +{ + h(v.data(), v.size()); +} + +inline bool +operator==(Slice const& lhs, Slice const& rhs) noexcept +{ + if (lhs.size() != rhs.size()) + return false; + + if (lhs.size() == 0) + return true; + + return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; +} + +inline bool +operator!=(Slice const& lhs, Slice const& rhs) noexcept +{ + return !(lhs == rhs); +} + +inline bool +operator<(Slice const& lhs, Slice const& rhs) noexcept +{ + return std::lexicographical_compare( + lhs.data(), + lhs.data() + lhs.size(), + rhs.data(), + rhs.data() + rhs.size()); +} + +template +Stream& +operator<<(Stream& s, Slice const& v) +{ + s << strHex(v); + return s; +} + +template +std::enable_if_t< + std::is_same::value || std::is_same::value, + Slice> +makeSlice(std::array const& a) +{ + return Slice(a.data(), a.size()); +} + +template +std::enable_if_t< + std::is_same::value || std::is_same::value, + Slice> +makeSlice(std::vector const& v) +{ + return Slice(v.data(), v.size()); +} + +template +Slice +makeSlice(std::basic_string const& s) +{ + return Slice(s.data(), s.size()); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/basics/StringUtilities.h b/include/xrpl/basics/StringUtilities.h new file mode 100644 index 00000000000..23d60e2db49 --- /dev/null +++ b/include/xrpl/basics/StringUtilities.h @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_STRINGUTILITIES_H_INCLUDED +#define RIPPLE_BASICS_STRINGUTILITIES_H_INCLUDED + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace ripple { + +/** Format arbitrary binary data as an SQLite "blob literal". + + In SQLite, blob literals must be encoded when used in a query. Per + https://sqlite.org/lang_expr.html#literal_values_constants_ they are + encoded as string literals containing hexadecimal data and preceded + by a single 'X' character. + + @param blob An arbitrary blob of binary data + @return The input, encoded as a blob literal. + */ +std::string +sqlBlobLiteral(Blob const& blob); + +template +std::optional +strUnHex(std::size_t strSize, Iterator begin, Iterator end) +{ + static constexpr std::array const unxtab = []() { + std::array t{}; + + for (auto& x : t) + x = -1; + + for (int i = 0; i < 10; ++i) + t['0' + i] = i; + + for (int i = 0; i < 6; ++i) + { + t['A' + i] = 10 + i; + t['a' + i] = 10 + i; + } + + return t; + }(); + + Blob out; + + out.reserve((strSize + 1) / 2); + + auto iter = begin; + + if (strSize & 1) + { + int c = unxtab[*iter++]; + + if (c < 0) + return {}; + + out.push_back(c); + } + + while (iter != end) + { + int cHigh = unxtab[*iter++]; + + if (cHigh < 0) + return {}; + + int cLow = unxtab[*iter++]; + + if (cLow < 0) + return {}; + + out.push_back(static_cast((cHigh << 4) | cLow)); + } + + return {std::move(out)}; +} + +inline std::optional +strUnHex(std::string const& strSrc) +{ + return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend()); +} + +inline std::optional +strViewUnHex(std::string_view strSrc) +{ + return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend()); +} + +struct parsedURL +{ + explicit parsedURL() = default; + + std::string scheme; + std::string username; + std::string password; + std::string domain; + std::optional port; + std::string path; + + bool + operator==(parsedURL const& other) const + { + return scheme == other.scheme && domain == other.domain && + port == other.port && path == other.path; + } +}; + +bool +parseUrl(parsedURL& pUrl, std::string const& strUrl); + +std::string +trim_whitespace(std::string str); + +std::optional +to_uint64(std::string const& s); + +/** Determines if the given string looks like a TOML-file hosting domain. + + Do not use this function to determine if a particular string is a valid + domain, as this function may reject domains that are otherwise valid and + doesn't check whether the TLD is valid. + */ +bool +isProperlyFormedTomlDomain(std::string_view domain); + +} // namespace ripple + +#endif diff --git a/include/xrpl/basics/TaggedCache.h b/include/xrpl/basics/TaggedCache.h new file mode 100644 index 00000000000..dcc7c0def96 --- /dev/null +++ b/include/xrpl/basics/TaggedCache.h @@ -0,0 +1,799 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED +#define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace ripple { + +/** Map/cache combination. + This class implements a cache and a map. The cache keeps objects alive + in the map. The map allows multiple code paths that reference objects + with the same tag to get the same actual object. + + So long as data is in the cache, it will stay in memory. + If it stays in memory even after it is ejected from the cache, + the map will track it. + + @note Callers must not modify data objects that are stored in the cache + unless they hold their own lock over all cache operations. +*/ +template < + class Key, + class T, + bool IsKeyCache = false, + class Hash = hardened_hash<>, + class KeyEqual = std::equal_to, + class Mutex = std::recursive_mutex> +class TaggedCache +{ +public: + using mutex_type = Mutex; + using key_type = Key; + using mapped_type = T; + using clock_type = beast::abstract_clock; + +public: + TaggedCache( + std::string const& name, + int size, + clock_type::duration expiration, + clock_type& clock, + beast::Journal journal, + beast::insight::Collector::ptr const& collector = + beast::insight::NullCollector::New()) + : m_journal(journal) + , m_clock(clock) + , m_stats( + name, + std::bind(&TaggedCache::collect_metrics, this), + collector) + , m_name(name) + , m_target_size(size) + , m_target_age(expiration) + , m_cache_count(0) + , m_hits(0) + , m_misses(0) + { + } + +public: + /** Return the clock associated with the cache. */ + clock_type& + clock() + { + return m_clock; + } + + /** Returns the number of items in the container. */ + std::size_t + size() const + { + std::lock_guard lock(m_mutex); + return m_cache.size(); + } + + void + setTargetSize(int s) + { + std::lock_guard lock(m_mutex); + m_target_size = s; + + if (s > 0) + { + for (auto& partition : m_cache.map()) + { + partition.rehash(static_cast( + (s + (s >> 2)) / + (partition.max_load_factor() * m_cache.partitions()) + + 1)); + } + } + + JLOG(m_journal.debug()) << m_name << " target size set to " << s; + } + + clock_type::duration + getTargetAge() const + { + std::lock_guard lock(m_mutex); + return m_target_age; + } + + void + setTargetAge(clock_type::duration s) + { + std::lock_guard lock(m_mutex); + m_target_age = s; + JLOG(m_journal.debug()) + << m_name << " target age set to " << m_target_age.count(); + } + + int + getCacheSize() const + { + std::lock_guard lock(m_mutex); + return m_cache_count; + } + + int + getTrackSize() const + { + std::lock_guard lock(m_mutex); + return m_cache.size(); + } + + float + getHitRate() + { + std::lock_guard lock(m_mutex); + auto const total = static_cast(m_hits + m_misses); + return m_hits * (100.0f / std::max(1.0f, total)); + } + + void + clear() + { + std::lock_guard lock(m_mutex); + m_cache.clear(); + m_cache_count = 0; + } + + void + reset() + { + std::lock_guard lock(m_mutex); + m_cache.clear(); + m_cache_count = 0; + m_hits = 0; + m_misses = 0; + } + + /** Refresh the last access time on a key if present. + @return `true` If the key was found. + */ + template + bool + touch_if_exists(KeyComparable const& key) + { + std::lock_guard lock(m_mutex); + auto const iter(m_cache.find(key)); + if (iter == m_cache.end()) + { + ++m_stats.misses; + return false; + } + iter->second.touch(m_clock.now()); + ++m_stats.hits; + return true; + } + + using SweptPointersVector = std::pair< + std::vector>, + std::vector>>; + + void + sweep() + { + // Keep references to all the stuff we sweep + // For performance, each worker thread should exit before the swept data + // is destroyed but still within the main cache lock. + std::vector allStuffToSweep(m_cache.partitions()); + + clock_type::time_point const now(m_clock.now()); + clock_type::time_point when_expire; + + auto const start = std::chrono::steady_clock::now(); + { + std::lock_guard lock(m_mutex); + + if (m_target_size == 0 || + (static_cast(m_cache.size()) <= m_target_size)) + { + when_expire = now - m_target_age; + } + else + { + when_expire = + now - m_target_age * m_target_size / m_cache.size(); + + clock_type::duration const minimumAge(std::chrono::seconds(1)); + if (when_expire > (now - minimumAge)) + when_expire = now - minimumAge; + + JLOG(m_journal.trace()) + << m_name << " is growing fast " << m_cache.size() << " of " + << m_target_size << " aging at " + << (now - when_expire).count() << " of " + << m_target_age.count(); + } + + std::vector workers; + workers.reserve(m_cache.partitions()); + std::atomic allRemovals = 0; + + for (std::size_t p = 0; p < m_cache.partitions(); ++p) + { + workers.push_back(sweepHelper( + when_expire, + now, + m_cache.map()[p], + allStuffToSweep[p], + allRemovals, + lock)); + } + for (std::thread& worker : workers) + worker.join(); + + m_cache_count -= allRemovals; + } + // At this point allStuffToSweep will go out of scope outside the lock + // and decrement the reference count on each strong pointer. + JLOG(m_journal.debug()) + << m_name << " TaggedCache sweep lock duration " + << std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count() + << "ms"; + } + + bool + del(const key_type& key, bool valid) + { + // Remove from cache, if !valid, remove from map too. Returns true if + // removed from cache + std::lock_guard lock(m_mutex); + + auto cit = m_cache.find(key); + + if (cit == m_cache.end()) + return false; + + Entry& entry = cit->second; + + bool ret = false; + + if (entry.isCached()) + { + --m_cache_count; + entry.ptr.reset(); + ret = true; + } + + if (!valid || entry.isExpired()) + m_cache.erase(cit); + + return ret; + } + + /** Replace aliased objects with originals. + + Due to concurrency it is possible for two separate objects with + the same content and referring to the same unique "thing" to exist. + This routine eliminates the duplicate and performs a replacement + on the callers shared pointer if needed. + + @param key The key corresponding to the object + @param data A shared pointer to the data corresponding to the object. + @param replace Function that decides if cache should be replaced + + @return `true` If the key already existed. + */ +public: + bool + canonicalize( + const key_type& key, + std::shared_ptr& data, + std::function const&)>&& replace) + { + // Return canonical value, store if needed, refresh in cache + // Return values: true=we had the data already + std::lock_guard lock(m_mutex); + + auto cit = m_cache.find(key); + + if (cit == m_cache.end()) + { + m_cache.emplace( + std::piecewise_construct, + std::forward_as_tuple(key), + std::forward_as_tuple(m_clock.now(), data)); + ++m_cache_count; + return false; + } + + Entry& entry = cit->second; + entry.touch(m_clock.now()); + + if (entry.isCached()) + { + if (replace(entry.ptr)) + { + entry.ptr = data; + entry.weak_ptr = data; + } + else + { + data = entry.ptr; + } + + return true; + } + + auto cachedData = entry.lock(); + + if (cachedData) + { + if (replace(entry.ptr)) + { + entry.ptr = data; + entry.weak_ptr = data; + } + else + { + entry.ptr = cachedData; + data = cachedData; + } + + ++m_cache_count; + return true; + } + + entry.ptr = data; + entry.weak_ptr = data; + ++m_cache_count; + + return false; + } + + bool + canonicalize_replace_cache( + const key_type& key, + std::shared_ptr const& data) + { + return canonicalize( + key, + const_cast&>(data), + [](std::shared_ptr const&) { return true; }); + } + + bool + canonicalize_replace_client(const key_type& key, std::shared_ptr& data) + { + return canonicalize( + key, data, [](std::shared_ptr const&) { return false; }); + } + + std::shared_ptr + fetch(const key_type& key) + { + std::lock_guard l(m_mutex); + auto ret = initialFetch(key, l); + if (!ret) + ++m_misses; + return ret; + } + + /** Insert the element into the container. + If the key already exists, nothing happens. + @return `true` If the element was inserted + */ + template + auto + insert(key_type const& key, T const& value) + -> std::enable_if_t + { + auto p = std::make_shared(std::cref(value)); + return canonicalize_replace_client(key, p); + } + + template + auto + insert(key_type const& key) -> std::enable_if_t + { + std::lock_guard lock(m_mutex); + clock_type::time_point const now(m_clock.now()); + auto [it, inserted] = m_cache.emplace( + std::piecewise_construct, + std::forward_as_tuple(key), + std::forward_as_tuple(now)); + if (!inserted) + it->second.last_access = now; + return inserted; + } + + // VFALCO NOTE It looks like this returns a copy of the data in + // the output parameter 'data'. This could be expensive. + // Perhaps it should work like standard containers, which + // simply return an iterator. + // + bool + retrieve(const key_type& key, T& data) + { + // retrieve the value of the stored data + auto entry = fetch(key); + + if (!entry) + return false; + + data = *entry; + return true; + } + + mutex_type& + peekMutex() + { + return m_mutex; + } + + std::vector + getKeys() const + { + std::vector v; + + { + std::lock_guard lock(m_mutex); + v.reserve(m_cache.size()); + for (auto const& _ : m_cache) + v.push_back(_.first); + } + + return v; + } + + // CachedSLEs functions. + /** Returns the fraction of cache hits. */ + double + rate() const + { + std::lock_guard lock(m_mutex); + auto const tot = m_hits + m_misses; + if (tot == 0) + return 0; + return double(m_hits) / tot; + } + + /** Fetch an item from the cache. + If the digest was not found, Handler + will be called with this signature: + std::shared_ptr(void) + */ + template + std::shared_ptr + fetch(key_type const& digest, Handler const& h) + { + { + std::lock_guard l(m_mutex); + if (auto ret = initialFetch(digest, l)) + return ret; + } + + auto sle = h(); + if (!sle) + return {}; + + std::lock_guard l(m_mutex); + ++m_misses; + auto const [it, inserted] = + m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle))); + if (!inserted) + it->second.touch(m_clock.now()); + return it->second.ptr; + } + // End CachedSLEs functions. + +private: + std::shared_ptr + initialFetch(key_type const& key, std::lock_guard const& l) + { + auto cit = m_cache.find(key); + if (cit == m_cache.end()) + return {}; + + Entry& entry = cit->second; + if (entry.isCached()) + { + ++m_hits; + entry.touch(m_clock.now()); + return entry.ptr; + } + entry.ptr = entry.lock(); + if (entry.isCached()) + { + // independent of cache size, so not counted as a hit + ++m_cache_count; + entry.touch(m_clock.now()); + return entry.ptr; + } + + m_cache.erase(cit); + return {}; + } + + void + collect_metrics() + { + m_stats.size.set(getCacheSize()); + + { + beast::insight::Gauge::value_type hit_rate(0); + { + std::lock_guard lock(m_mutex); + auto const total(m_hits + m_misses); + if (total != 0) + hit_rate = (m_hits * 100) / total; + } + m_stats.hit_rate.set(hit_rate); + } + } + +private: + struct Stats + { + template + Stats( + std::string const& prefix, + Handler const& handler, + beast::insight::Collector::ptr const& collector) + : hook(collector->make_hook(handler)) + , size(collector->make_gauge(prefix, "size")) + , hit_rate(collector->make_gauge(prefix, "hit_rate")) + , hits(0) + , misses(0) + { + } + + beast::insight::Hook hook; + beast::insight::Gauge size; + beast::insight::Gauge hit_rate; + + std::size_t hits; + std::size_t misses; + }; + + class KeyOnlyEntry + { + public: + clock_type::time_point last_access; + + explicit KeyOnlyEntry(clock_type::time_point const& last_access_) + : last_access(last_access_) + { + } + + void + touch(clock_type::time_point const& now) + { + last_access = now; + } + }; + + class ValueEntry + { + public: + std::shared_ptr ptr; + std::weak_ptr weak_ptr; + clock_type::time_point last_access; + + ValueEntry( + clock_type::time_point const& last_access_, + std::shared_ptr const& ptr_) + : ptr(ptr_), weak_ptr(ptr_), last_access(last_access_) + { + } + + bool + isWeak() const + { + return ptr == nullptr; + } + bool + isCached() const + { + return ptr != nullptr; + } + bool + isExpired() const + { + return weak_ptr.expired(); + } + std::shared_ptr + lock() + { + return weak_ptr.lock(); + } + void + touch(clock_type::time_point const& now) + { + last_access = now; + } + }; + + typedef + typename std::conditional::type + Entry; + + using KeyOnlyCacheType = + hardened_partitioned_hash_map; + + using KeyValueCacheType = + hardened_partitioned_hash_map; + + using cache_type = + hardened_partitioned_hash_map; + + [[nodiscard]] std::thread + sweepHelper( + clock_type::time_point const& when_expire, + [[maybe_unused]] clock_type::time_point const& now, + typename KeyValueCacheType::map_type& partition, + SweptPointersVector& stuffToSweep, + std::atomic& allRemovals, + std::lock_guard const&) + { + return std::thread([&, this]() { + int cacheRemovals = 0; + int mapRemovals = 0; + + // Keep references to all the stuff we sweep + // so that we can destroy them outside the lock. + stuffToSweep.first.reserve(partition.size()); + stuffToSweep.second.reserve(partition.size()); + { + auto cit = partition.begin(); + while (cit != partition.end()) + { + if (cit->second.isWeak()) + { + // weak + if (cit->second.isExpired()) + { + stuffToSweep.second.push_back( + std::move(cit->second.weak_ptr)); + ++mapRemovals; + cit = partition.erase(cit); + } + else + { + ++cit; + } + } + else if (cit->second.last_access <= when_expire) + { + // strong, expired + ++cacheRemovals; + if (cit->second.ptr.use_count() == 1) + { + stuffToSweep.first.push_back( + std::move(cit->second.ptr)); + ++mapRemovals; + cit = partition.erase(cit); + } + else + { + // remains weakly cached + cit->second.ptr.reset(); + ++cit; + } + } + else + { + // strong, not expired + ++cit; + } + } + } + + if (mapRemovals || cacheRemovals) + { + JLOG(m_journal.debug()) + << "TaggedCache partition sweep " << m_name + << ": cache = " << partition.size() << "-" << cacheRemovals + << ", map-=" << mapRemovals; + } + + allRemovals += cacheRemovals; + }); + } + + [[nodiscard]] std::thread + sweepHelper( + clock_type::time_point const& when_expire, + clock_type::time_point const& now, + typename KeyOnlyCacheType::map_type& partition, + SweptPointersVector&, + std::atomic& allRemovals, + std::lock_guard const&) + { + return std::thread([&, this]() { + int cacheRemovals = 0; + int mapRemovals = 0; + + // Keep references to all the stuff we sweep + // so that we can destroy them outside the lock. + { + auto cit = partition.begin(); + while (cit != partition.end()) + { + if (cit->second.last_access > now) + { + cit->second.last_access = now; + ++cit; + } + else if (cit->second.last_access <= when_expire) + { + cit = partition.erase(cit); + } + else + { + ++cit; + } + } + } + + if (mapRemovals || cacheRemovals) + { + JLOG(m_journal.debug()) + << "TaggedCache partition sweep " << m_name + << ": cache = " << partition.size() << "-" << cacheRemovals + << ", map-=" << mapRemovals; + } + + allRemovals += cacheRemovals; + }); + }; + + beast::Journal m_journal; + clock_type& m_clock; + Stats m_stats; + + mutex_type mutable m_mutex; + + // Used for logging + std::string m_name; + + // Desired number of cache entries (0 = ignore) + int m_target_size; + + // Desired maximum cache age + clock_type::duration m_target_age; + + // Number of items cached + int m_cache_count; + cache_type m_cache; // Hold strong reference to recent objects + std::uint64_t m_hits; + std::uint64_t m_misses; +}; + +} // namespace ripple + +#endif diff --git a/src/ripple/basics/ToString.h b/include/xrpl/basics/ToString.h similarity index 85% rename from src/ripple/basics/ToString.h rename to include/xrpl/basics/ToString.h index ae34d8ece46..93cb0ff335f 100644 --- a/src/ripple/basics/ToString.h +++ b/include/xrpl/basics/ToString.h @@ -32,33 +32,36 @@ namespace ripple { */ template -typename std::enable_if::value, - std::string>::type +typename std::enable_if::value, std::string>::type to_string(T t) { return std::to_string(t); } -inline std::string to_string(bool b) +inline std::string +to_string(bool b) { return b ? "true" : "false"; } -inline std::string to_string(char c) +inline std::string +to_string(char c) { return std::string(1, c); } -inline std::string to_string(std::string s) +inline std::string +to_string(std::string s) { return s; } -inline std::string to_string(char const* s) +inline std::string +to_string(char const* s) { return s; } -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/basics/UnorderedContainers.h b/include/xrpl/basics/UnorderedContainers.h new file mode 100644 index 00000000000..4f6e1093b13 --- /dev/null +++ b/include/xrpl/basics/UnorderedContainers.h @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_UNORDEREDCONTAINERS_H_INCLUDED +#define RIPPLE_BASICS_UNORDEREDCONTAINERS_H_INCLUDED + +#include +#include +#include +#include +#include + +#include +#include + +/** + * Use hash_* containers for keys that do not need a cryptographically secure + * hashing algorithm. + * + * Use hardened_hash_* containers for keys that do need a secure hashing + * algorithm. + * + * The cryptographic security of containers where a hash function is used as a + * template parameter depends entirely on that hash function and not at all on + * what container it is. + */ + +namespace ripple { + +// hash containers + +template < + class Key, + class Value, + class Hash = beast::uhash<>, + class Pred = std::equal_to, + class Allocator = std::allocator>> +using hash_map = std::unordered_map; + +template < + class Key, + class Value, + class Hash = beast::uhash<>, + class Pred = std::equal_to, + class Allocator = std::allocator>> +using hash_multimap = + std::unordered_multimap; + +template < + class Value, + class Hash = beast::uhash<>, + class Pred = std::equal_to, + class Allocator = std::allocator> +using hash_set = std::unordered_set; + +template < + class Value, + class Hash = beast::uhash<>, + class Pred = std::equal_to, + class Allocator = std::allocator> +using hash_multiset = std::unordered_multiset; + +// hardened_hash containers + +using strong_hash = beast::xxhasher; + +template < + class Key, + class Value, + class Hash = hardened_hash, + class Pred = std::equal_to, + class Allocator = std::allocator>> +using hardened_hash_map = std::unordered_map; + +template < + class Key, + class Value, + class Hash = hardened_hash, + class Pred = std::equal_to, + class Allocator = std::allocator>> +using hardened_partitioned_hash_map = + partitioned_unordered_map; + +template < + class Key, + class Value, + class Hash = hardened_hash, + class Pred = std::equal_to, + class Allocator = std::allocator>> +using hardened_hash_multimap = + std::unordered_multimap; + +template < + class Value, + class Hash = hardened_hash, + class Pred = std::equal_to, + class Allocator = std::allocator> +using hardened_hash_set = std::unordered_set; + +template < + class Value, + class Hash = hardened_hash, + class Pred = std::equal_to, + class Allocator = std::allocator> +using hardened_hash_multiset = + std::unordered_multiset; + +} // namespace ripple + +#endif diff --git a/src/ripple/basics/UptimeClock.h b/include/xrpl/basics/UptimeClock.h similarity index 84% rename from src/ripple/basics/UptimeClock.h rename to include/xrpl/basics/UptimeClock.h index 9fbc9c6cd61..7cafb94b53b 100644 --- a/src/ripple/basics/UptimeClock.h +++ b/include/xrpl/basics/UptimeClock.h @@ -37,22 +37,22 @@ namespace ripple { class UptimeClock { public: - using rep = int; - using period = std::ratio<1>; - using duration = std::chrono::duration; + using rep = int; + using period = std::ratio<1>; + using duration = std::chrono::duration; using time_point = std::chrono::time_point; static constexpr bool is_steady = std::chrono::system_clock::is_steady; explicit UptimeClock() = default; - static time_point now(); // seconds since rippled program start + static time_point + now(); // seconds since rippled program start private: - static std::atomic now_; + static std::atomic now_; static std::atomic stop_; - struct update_thread - : private std::thread + struct update_thread : private std::thread { ~update_thread(); update_thread(update_thread&&) = default; @@ -60,9 +60,10 @@ class UptimeClock using std::thread::thread; }; - static update_thread start_clock(); + static update_thread + start_clock(); }; -} // ripple +} // namespace ripple #endif diff --git a/src/ripple/basics/algorithm.h b/include/xrpl/basics/algorithm.h similarity index 77% rename from src/ripple/basics/algorithm.h rename to include/xrpl/basics/algorithm.h index cc9d4aaf386..ed6e8080d9a 100644 --- a/src/ripple/basics/algorithm.h +++ b/include/xrpl/basics/algorithm.h @@ -20,6 +20,7 @@ #ifndef RIPPLE_ALGORITHM_H_INCLUDED #define RIPPLE_ALGORITHM_H_INCLUDED +#include #include namespace ripple { @@ -33,23 +34,26 @@ namespace ripple { // Note: This algorithm is evolved from std::set_intersection. template void -generalized_set_intersection(InputIter1 first1, InputIter1 last1, - InputIter2 first2, InputIter2 last2, - Action action, Comp comp) +generalized_set_intersection( + InputIter1 first1, + InputIter1 last1, + InputIter2 first2, + InputIter2 last2, + Action action, + Comp comp) { while (first1 != last1 && first2 != last2) { - - if (comp(*first1, *first2)) // if *first1 < *first2 - ++first1; // then reduce first range + if (comp(*first1, *first2)) // if *first1 < *first2 + ++first1; // then reduce first range else { - if (!comp(*first2, *first1)) // if *first1 == *first2 - { // then this is an intersection - action(*first1, *first2); // do the action - ++first1; // reduce first range + if (!comp(*first2, *first1)) // if *first1 == *first2 + { // then this is an intersection + action(*first1, *first2); // do the action + ++first1; // reduce first range } - ++first2; // Reduce second range because *first2 <= *first1 + ++first2; // Reduce second range because *first2 <= *first1 } } } @@ -58,22 +62,28 @@ generalized_set_intersection(InputIter1 first1, InputIter1 last1, // comp. // Effects: Eliminates all the elements i in the range [first1, last1) which are -// equivalent to some value in [first2, last2) or for which pred(i) returns true. +// equivalent to some value in [first2, last2) or for which pred(i) returns +// true. // Returns: A FwdIter1 E such that [first1, E) is the range of elements not // removed by this algorithm. -// Note: This algorithm is evolved from std::remove_if and std::set_intersection. +// Note: This algorithm is evolved from std::remove_if and +// std::set_intersection. template FwdIter1 -remove_if_intersect_or_match(FwdIter1 first1, FwdIter1 last1, - InputIter2 first2, InputIter2 last2, - Pred pred, Comp comp) +remove_if_intersect_or_match( + FwdIter1 first1, + FwdIter1 last1, + InputIter2 first2, + InputIter2 last2, + Pred pred, + Comp comp) { // [original-first1, current-first1) is the set of elements to be preserved. // [current-first1, i) is the set of elements that have been removed. // [i, last1) is the set of elements not tested yet. - + // Test each *i in [first1, last1) against [first2, last2) and pred for (auto i = first1; i != last1;) { @@ -105,6 +115,6 @@ remove_if_intersect_or_match(FwdIter1 first1, FwdIter1 last1, return first1; } -} // ripple +} // namespace ripple #endif diff --git a/src/ripple/basics/base64.h b/include/xrpl/basics/base64.h similarity index 91% rename from src/ripple/basics/base64.h rename to include/xrpl/basics/base64.h index 516b588b33a..515a7584e56 100644 --- a/src/ripple/basics/base64.h +++ b/include/xrpl/basics/base64.h @@ -57,25 +57,24 @@ #ifndef RIPPLE_BASICS_BASE64_H_INCLUDED #define RIPPLE_BASICS_BASE64_H_INCLUDED +#include #include namespace ripple { std::string -base64_encode (std::uint8_t const* data, - std::size_t len); +base64_encode(std::uint8_t const* data, std::size_t len); -inline -std::string +inline std::string base64_encode(std::string const& s) { - return base64_encode (reinterpret_cast < - std::uint8_t const*> (s.data()), s.size()); + return base64_encode( + reinterpret_cast(s.data()), s.size()); } std::string -base64_decode(std::string const& data); +base64_decode(std::string_view data); -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/basics/base_uint.h b/include/xrpl/basics/base_uint.h new file mode 100644 index 00000000000..4b93330ef22 --- /dev/null +++ b/include/xrpl/basics/base_uint.h @@ -0,0 +1,673 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2011 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#ifndef RIPPLE_BASICS_BASE_UINT_H_INCLUDED +#define RIPPLE_BASICS_BASE_UINT_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace ripple { + +namespace detail { + +template > +struct is_contiguous_container : std::false_type +{ +}; + +template +struct is_contiguous_container< + Container, + std::void_t< + decltype(std::declval().size()), + decltype(std::declval().data()), + typename Container::value_type>> : std::true_type +{ +}; + +template <> +struct is_contiguous_container : std::true_type +{ +}; + +} // namespace detail + +/** Integers of any length that is a multiple of 32-bits + + @note This class stores its values internally in big-endian + form and that internal representation is part of the + binary protocol of the XRP Ledger and cannot be changed + arbitrarily without causing breakage. + + @tparam Bits The number of bits this integer should have; must + be at least 64 and a multiple of 32. + @tparam Tag An arbitrary type that functions as a tag and allows + the instantiation of "distinct" types that the same + number of bits. + */ +template +class base_uint +{ + static_assert( + (Bits % 32) == 0, + "The length of a base_uint in bits must be a multiple of 32."); + + static_assert( + Bits >= 64, + "The length of a base_uint in bits must be at least 64."); + + static constexpr std::size_t WIDTH = Bits / 32; + + // This is really big-endian in byte order. + // We sometimes use std::uint32_t for speed. + + std::array data_; + +public: + //-------------------------------------------------------------------------- + // + // STL Container Interface + // + + static std::size_t constexpr bytes = Bits / 8; + static_assert(sizeof(data_) == bytes, ""); + + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using value_type = unsigned char; + using pointer = value_type*; + using reference = value_type&; + using const_pointer = value_type const*; + using const_reference = value_type const&; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using tag_type = Tag; + + pointer + data() + { + return reinterpret_cast(data_.data()); + } + const_pointer + data() const + { + return reinterpret_cast(data_.data()); + } + + iterator + begin() + { + return data(); + } + iterator + end() + { + return data() + bytes; + } + const_iterator + begin() const + { + return data(); + } + const_iterator + end() const + { + return data() + bytes; + } + const_iterator + cbegin() const + { + return data(); + } + const_iterator + cend() const + { + return data() + bytes; + } + + /** Value hashing function. + The seed prevents crafted inputs from causing degenerate parent + containers. + */ + using hasher = hardened_hash<>; + + //-------------------------------------------------------------------------- + +private: + /** Construct from a raw pointer. + The buffer pointed to by `data` must be at least Bits/8 bytes. + + @note the structure is used to disambiguate this from the std::uint64_t + constructor: something like base_uint(0) is ambiguous. + */ + // NIKB TODO Remove the need for this constructor. + struct VoidHelper + { + explicit VoidHelper() = default; + }; + + explicit base_uint(void const* data, VoidHelper) + { + memcpy(data_.data(), data, bytes); + } + + // Helper function to initialize a base_uint from a std::string_view. + enum class ParseResult { + okay, + badLength, + badChar, + }; + + constexpr Expected + parseFromStringView(std::string_view sv) noexcept + { + // Local lambda that converts a single hex char to four bits and + // ORs those bits into a uint32_t. + auto hexCharToUInt = [](char c, + std::uint32_t shift, + std::uint32_t& accum) -> ParseResult { + std::uint32_t nibble = 0xFFu; + if (c < '0' || c > 'f') + return ParseResult::badChar; + + if (c >= 'a') + nibble = static_cast(c - 'a' + 0xA); + else if (c >= 'A') + nibble = static_cast(c - 'A' + 0xA); + else if (c <= '9') + nibble = static_cast(c - '0'); + + if (nibble > 0xFu) + return ParseResult::badChar; + + accum |= (nibble << shift); + + return ParseResult::okay; + }; + + decltype(data_) ret{}; + + if (sv == "0") + { + return ret; + } + + if (sv.size() != size() * 2) + return Unexpected(ParseResult::badLength); + + std::size_t i = 0u; + auto in = sv.begin(); + while (in != sv.end()) + { + std::uint32_t accum = {}; + for (std::uint32_t shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u}) + { + if (auto const result = hexCharToUInt(*in++, shift, accum); + result != ParseResult::okay) + return Unexpected(result); + } + ret[i++] = accum; + } + return ret; + } + + constexpr decltype(data_) + parseFromStringViewThrows(std::string_view sv) noexcept(false) + { + auto const result = parseFromStringView(sv); + if (!result) + { + if (result.error() == ParseResult::badLength) + Throw("invalid length for hex string"); + + Throw("invalid hex character"); + } + return *result; + } + +public: + constexpr base_uint() : data_{} + { + } + + constexpr base_uint(beast::Zero) : data_{} + { + } + + explicit base_uint(std::uint64_t b) + { + *this = b; + } + + // This constructor is intended to be used at compile time since it might + // throw at runtime. Consider declaring this constructor consteval once + // we get to C++23. + explicit constexpr base_uint(std::string_view sv) noexcept(false) + : data_(parseFromStringViewThrows(sv)) + { + } + + template < + class Container, + class = std::enable_if_t< + detail::is_contiguous_container::value && + std::is_trivially_copyable::value>> + explicit base_uint(Container const& c) + { + XRPL_ASSERT( + c.size() * sizeof(typename Container::value_type) == size(), + "ripple::base_uint::base_uint(Container auto) : input size match"); + std::memcpy(data_.data(), c.data(), size()); + } + + template + std::enable_if_t< + detail::is_contiguous_container::value && + std::is_trivially_copyable::value, + base_uint&> + operator=(Container const& c) + { + XRPL_ASSERT( + c.size() * sizeof(typename Container::value_type) == size(), + "ripple::base_uint::operator=(Container auto) : input size match"); + std::memcpy(data_.data(), c.data(), size()); + return *this; + } + + /* Construct from a raw pointer. + The buffer pointed to by `data` must be at least Bits/8 bytes. + */ + static base_uint + fromVoid(void const* data) + { + return base_uint(data, VoidHelper()); + } + + template + static std::optional + fromVoidChecked(T const& from) + { + if (from.size() != size()) + return {}; + return fromVoid(from.data()); + } + + constexpr int + signum() const + { + for (int i = 0; i < WIDTH; i++) + if (data_[i] != 0) + return 1; + + return 0; + } + + bool + operator!() const + { + return *this == beast::zero; + } + + constexpr base_uint + operator~() const + { + base_uint ret; + + for (int i = 0; i < WIDTH; i++) + ret.data_[i] = ~data_[i]; + + return ret; + } + + base_uint& + operator=(std::uint64_t uHost) + { + *this = beast::zero; + union + { + unsigned u[2]; + std::uint64_t ul; + }; + // Put in least significant bits. + ul = boost::endian::native_to_big(uHost); + data_[WIDTH - 2] = u[0]; + data_[WIDTH - 1] = u[1]; + return *this; + } + + base_uint& + operator^=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + data_[i] ^= b.data_[i]; + + return *this; + } + + base_uint& + operator&=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + data_[i] &= b.data_[i]; + + return *this; + } + + base_uint& + operator|=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + data_[i] |= b.data_[i]; + + return *this; + } + + base_uint& + operator++() + { + // prefix operator + for (int i = WIDTH - 1; i >= 0; --i) + { + data_[i] = boost::endian::native_to_big( + boost::endian::big_to_native(data_[i]) + 1); + if (data_[i] != 0) + break; + } + + return *this; + } + + const base_uint + operator++(int) + { + // postfix operator + const base_uint ret = *this; + ++(*this); + + return ret; + } + + base_uint& + operator--() + { + for (int i = WIDTH - 1; i >= 0; --i) + { + auto prev = data_[i]; + data_[i] = boost::endian::native_to_big( + boost::endian::big_to_native(data_[i]) - 1); + + if (prev != 0) + break; + } + + return *this; + } + + const base_uint + operator--(int) + { + // postfix operator + const base_uint ret = *this; + --(*this); + + return ret; + } + + base_uint + next() const + { + auto ret = *this; + return ++ret; + } + + base_uint + prev() const + { + auto ret = *this; + return --ret; + } + + base_uint& + operator+=(const base_uint& b) + { + std::uint64_t carry = 0; + + for (int i = WIDTH; i--;) + { + std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) + + boost::endian::big_to_native(b.data_[i]); + + data_[i] = + boost::endian::native_to_big(static_cast(n)); + carry = n >> 32; + } + + return *this; + } + + template + friend void + hash_append(Hasher& h, base_uint const& a) noexcept + { + // Do not allow any endian transformations on this memory + h(a.data_.data(), sizeof(a.data_)); + } + + /** Parse a hex string into a base_uint + + The input must be precisely `2 * bytes` hexadecimal characters + long, with one exception: the value '0'. + + @param sv A null-terminated string of hexadecimal characters + @return true if the input was parsed properly; false otherwise. + */ + [[nodiscard]] constexpr bool + parseHex(std::string_view sv) + { + auto const result = parseFromStringView(sv); + if (!result) + return false; + + data_ = *result; + return true; + } + + [[nodiscard]] constexpr bool + parseHex(const char* str) + { + return parseHex(std::string_view{str}); + } + + [[nodiscard]] bool + parseHex(std::string const& str) + { + return parseHex(std::string_view{str}); + } + + constexpr static std::size_t + size() + { + return bytes; + } + + base_uint& + operator=(beast::Zero) + { + data_.fill(0); + return *this; + } + + // Deprecated. + bool + isZero() const + { + return *this == beast::zero; + } + bool + isNonZero() const + { + return *this != beast::zero; + } + void + zero() + { + *this = beast::zero; + } +}; + +using uint128 = base_uint<128>; +using uint160 = base_uint<160>; +using uint256 = base_uint<256>; +using uint192 = base_uint<192>; + +template +[[nodiscard]] inline constexpr std::strong_ordering +operator<=>(base_uint const& lhs, base_uint const& rhs) +{ + // This comparison might seem wrong on a casual inspection because it + // compares data internally stored as std::uint32_t byte-by-byte. But + // note that the underlying data is stored in big endian, even if the + // plaform is little endian. This makes the comparison correct. + // + // FIXME: use std::lexicographical_compare_three_way once support is + // added to MacOS. + + auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + + // a == b + if (ret.first == lhs.cend()) + return std::strong_ordering::equivalent; + + return (*ret.first > *ret.second) ? std::strong_ordering::greater + : std::strong_ordering::less; +} + +template +[[nodiscard]] inline constexpr bool +operator==(base_uint const& lhs, base_uint const& rhs) +{ + return (lhs <=> rhs) == 0; +} + +//------------------------------------------------------------------------------ +template +inline constexpr bool +operator==(base_uint const& a, std::uint64_t b) +{ + return a == base_uint(b); +} + +//------------------------------------------------------------------------------ +template +inline constexpr base_uint +operator^(base_uint const& a, base_uint const& b) +{ + return base_uint(a) ^= b; +} + +template +inline constexpr base_uint +operator&(base_uint const& a, base_uint const& b) +{ + return base_uint(a) &= b; +} + +template +inline constexpr base_uint +operator|(base_uint const& a, base_uint const& b) +{ + return base_uint(a) |= b; +} + +template +inline constexpr base_uint +operator+(base_uint const& a, base_uint const& b) +{ + return base_uint(a) += b; +} + +//------------------------------------------------------------------------------ +template +inline std::string +to_string(base_uint const& a) +{ + return strHex(a.cbegin(), a.cend()); +} + +template +inline std::ostream& +operator<<(std::ostream& out, base_uint const& u) +{ + return out << to_string(u); +} + +template <> +inline std::size_t +extract(uint256 const& key) +{ + std::size_t result; + // Use memcpy to avoid unaligned UB + // (will optimize to equivalent code) + std::memcpy(&result, key.data(), sizeof(std::size_t)); + return result; +} + +#ifndef __INTELLISENSE__ +static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes"); +static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes"); +static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes"); +static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes"); +#endif + +} // namespace ripple + +namespace beast { + +template +struct is_uniquely_represented> + : public std::true_type +{ + explicit is_uniquely_represented() = default; +}; + +} // namespace beast + +#endif diff --git a/include/xrpl/basics/chrono.h b/include/xrpl/basics/chrono.h new file mode 100644 index 00000000000..2ed1a960470 --- /dev/null +++ b/include/xrpl/basics/chrono.h @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_CHRONO_H_INCLUDED +#define RIPPLE_BASICS_CHRONO_H_INCLUDED + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace ripple { + +// A few handy aliases + +using days = std::chrono::duration< + int, + std::ratio_multiply>>; + +using weeks = std::chrono:: + duration>>; + +/** Clock for measuring the network time. + + The epoch is January 1, 2000 + + epoch_offset + = date(2000-01-01) - date(1970-0-01) + = days(10957) + = seconds(946684800) +*/ + +constexpr static std::chrono::seconds epoch_offset = + date::sys_days{date::year{2000} / 1 / 1} - + date::sys_days{date::year{1970} / 1 / 1}; + +static_assert(epoch_offset.count() == 946684800); + +class NetClock +{ +public: + explicit NetClock() = default; + + using rep = std::uint32_t; + using period = std::ratio<1>; + using duration = std::chrono::duration; + using time_point = std::chrono::time_point; + + static bool const is_steady = false; +}; + +template +std::string +to_string(date::sys_time tp) +{ + return date::format("%Y-%b-%d %T %Z", tp); +} + +inline std::string +to_string(NetClock::time_point tp) +{ + // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC + using namespace std::chrono; + return to_string( + system_clock::time_point{tp.time_since_epoch() + epoch_offset}); +} + +template +std::string +to_string_iso(date::sys_time tp) +{ + using namespace std::chrono; + return date::format("%FT%TZ", tp); +} + +inline std::string +to_string_iso(NetClock::time_point tp) +{ + // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC + // Note, NetClock::duration is seconds, as checked by static_assert + static_assert(std::is_same_v>); + return to_string_iso(date::sys_time{ + tp.time_since_epoch() + epoch_offset}); +} + +/** A clock for measuring elapsed time. + + The epoch is unspecified. +*/ +using Stopwatch = beast::abstract_clock; + +/** A manual Stopwatch for unit tests. */ +using TestStopwatch = beast::manual_clock; + +/** Returns an instance of a wall clock. */ +inline Stopwatch& +stopwatch() +{ + using Clock = beast::basic_seconds_clock; + using Facade = Clock::Clock; + return beast::get_abstract_clock(); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/basics/comparators.h b/include/xrpl/basics/comparators.h new file mode 100644 index 00000000000..ce782dcd397 --- /dev/null +++ b/include/xrpl/basics/comparators.h @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_COMPARATORS_H_INCLUDED +#define RIPPLE_BASICS_COMPARATORS_H_INCLUDED + +#include + +namespace ripple { + +#ifdef _MSC_VER + +/* + * MSVC 2019 version 16.9.0 added [[nodiscard]] to the std comparison + * operator() functions. boost::bimap checks that the comparitor is a + * BinaryFunction, in part by calling the function and ignoring the value. + * These two things don't play well together. These wrapper classes simply + * strip [[nodiscard]] from operator() for use in boost::bimap. + * + * See also: + * https://www.boost.org/doc/libs/1_75_0/libs/bimap/doc/html/boost_bimap/the_tutorial/controlling_collection_types.html + */ + +template +struct less +{ + using result_type = bool; + + constexpr bool + operator()(const T& left, const T& right) const + { + return std::less()(left, right); + } +}; + +template +struct equal_to +{ + using result_type = bool; + + constexpr bool + operator()(const T& left, const T& right) const + { + return std::equal_to()(left, right); + } +}; + +#else + +template +using less = std::less; + +template +using equal_to = std::equal_to; + +#endif + +} // namespace ripple + +#endif diff --git a/src/ripple/basics/contract.h b/include/xrpl/basics/contract.h similarity index 78% rename from src/ripple/basics/contract.h rename to include/xrpl/basics/contract.h index b2f481fdb12..bf98964b9eb 100644 --- a/src/ripple/basics/contract.h +++ b/include/xrpl/basics/contract.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_BASICS_CONTRACT_H_INCLUDED #define RIPPLE_BASICS_CONTRACT_H_INCLUDED -#include +#include + #include #include -#include #include namespace ripple { @@ -36,7 +36,7 @@ namespace ripple { /** Generates and logs a call stack */ void -LogThrow (std::string const& title); +LogThrow(std::string const& title); /** Rethrow the exception currently being handled. @@ -44,36 +44,33 @@ LogThrow (std::string const& title); control to the next matching exception handler, if any. Otherwise, std::terminate will be called. */ -[[noreturn]] -inline -void -Rethrow () +[[noreturn]] inline void +Rethrow() { - LogThrow ("Re-throwing exception"); + LogThrow("Re-throwing exception"); throw; } template -[[noreturn]] -inline -void -Throw (Args&&... args) +[[noreturn]] inline void +Throw(Args&&... args) { - static_assert (std::is_convertible::value, + static_assert( + std::is_convertible::value, "Exception must derive from std::exception."); E e(std::forward(args)...); - LogThrow (std::string("Throwing exception of type " + - beast::type_name() +": ") + e.what()); + LogThrow( + std::string( + "Throwing exception of type " + beast::type_name() + ": ") + + e.what()); throw e; } /** Called when faulty logic causes a broken invariant. */ -[[noreturn]] -void -LogicError ( - std::string const& how) noexcept; +[[noreturn]] void +LogicError(std::string const& how) noexcept; -} // ripple +} // namespace ripple #endif diff --git a/src/ripple/basics/hardened_hash.h b/include/xrpl/basics/hardened_hash.h similarity index 90% rename from src/ripple/basics/hardened_hash.h rename to include/xrpl/basics/hardened_hash.h index abf0ac64642..0b77b0a07a8 100644 --- a/src/ripple/basics/hardened_hash.h +++ b/include/xrpl/basics/hardened_hash.h @@ -20,17 +20,17 @@ #ifndef RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED #define RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED -#include -#include +#include +#include #include #include #include -#include #include #include #include #include +#include namespace ripple { @@ -47,9 +47,11 @@ make_seed_pair() noexcept std::mutex mutex; std::random_device rng; std::mt19937_64 gen; - std::uniform_int_distribution dist; + std::uniform_int_distribution dist; - state_t() : gen(rng()) {} + state_t() : gen(rng()) + { + } // state_t(state_t const&) = delete; // state_t& operator=(state_t const&) = delete; }; @@ -58,7 +60,7 @@ make_seed_pair() noexcept return {state.dist(state.gen), state.dist(state.gen)}; } -} +} // namespace detail /** * Seed functor once per construction @@ -99,9 +101,9 @@ class hardened_hash public: using result_type = typename HashAlgorithm::result_type; - hardened_hash() - : m_seeds (detail::make_seed_pair<>()) - {} + hardened_hash() : m_seeds(detail::make_seed_pair<>()) + { + } template result_type @@ -113,6 +115,6 @@ class hardened_hash } }; -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/basics/join.h b/include/xrpl/basics/join.h new file mode 100644 index 00000000000..dde52bc9e69 --- /dev/null +++ b/include/xrpl/basics/join.h @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +/* +This file is part of rippled: https://github.com/ripple/rippled +Copyright (c) 2022 Ripple Labs Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef JOIN_H_INCLUDED +#define JOIN_H_INCLUDED + +#include + +namespace ripple { + +template +Stream& +join(Stream& s, Iter iter, Iter end, std::string const& delimiter) +{ + if (iter == end) + return s; + s << *iter; + for (++iter; iter != end; ++iter) + s << delimiter << *iter; + return s; +} + +template +class CollectionAndDelimiter +{ +public: + Collection const& collection; + std::string const delimiter; + + explicit CollectionAndDelimiter(Collection const& c, std::string delim) + : collection(c), delimiter(std::move(delim)) + { + } + + template + friend Stream& + operator<<(Stream& s, CollectionAndDelimiter const& cd) + { + return join( + s, + std::begin(cd.collection), + std::end(cd.collection), + cd.delimiter); + } +}; + +template +class CollectionAndDelimiter +{ +public: + Collection const* collection; + std::string const delimiter; + + explicit CollectionAndDelimiter(Collection const c[N], std::string delim) + : collection(c), delimiter(std::move(delim)) + { + } + + template + friend Stream& + operator<<(Stream& s, CollectionAndDelimiter const& cd) + { + return join(s, cd.collection, cd.collection + N, cd.delimiter); + } +}; + +// Specialization for const char* strings +template +class CollectionAndDelimiter +{ +public: + char const* collection; + std::string const delimiter; + + explicit CollectionAndDelimiter(char const c[N], std::string delim) + : collection(c), delimiter(std::move(delim)) + { + } + + template + friend Stream& + operator<<(Stream& s, CollectionAndDelimiter const& cd) + { + auto end = cd.collection + N; + if (N > 0 && *(end - 1) == '\0') + --end; + return join(s, cd.collection, end, cd.delimiter); + } +}; + +} // namespace ripple + +#endif diff --git a/src/ripple/basics/make_SSLContext.h b/include/xrpl/basics/make_SSLContext.h similarity index 94% rename from src/ripple/basics/make_SSLContext.h rename to include/xrpl/basics/make_SSLContext.h index db5127885b7..aba797ce31e 100644 --- a/src/ripple/basics/make_SSLContext.h +++ b/include/xrpl/basics/make_SSLContext.h @@ -21,24 +21,23 @@ #define RIPPLE_BASICS_MAKE_SSLCONTEXT_H_INCLUDED #include + #include namespace ripple { /** Create a self-signed SSL context that allows anonymous Diffie Hellman. */ std::shared_ptr -make_SSLContext( - std::string const& cipherList); +make_SSLContext(std::string const& cipherList); /** Create an authenticated SSL context using the specified files. */ std::shared_ptr -make_SSLContextAuthed ( +make_SSLContextAuthed( std::string const& keyFile, std::string const& certFile, std::string const& chainFile, std::string const& cipherList); - -} +} // namespace ripple #endif diff --git a/src/ripple/basics/mulDiv.h b/include/xrpl/basics/mulDiv.h similarity index 80% rename from src/ripple/basics/mulDiv.h rename to include/xrpl/basics/mulDiv.h index 1ee788387cd..e338f87c819 100644 --- a/src/ripple/basics/mulDiv.h +++ b/include/xrpl/basics/mulDiv.h @@ -21,10 +21,12 @@ #define RIPPLE_BASICS_MULDIV_H_INCLUDED #include +#include +#include #include -namespace ripple -{ +namespace ripple { +auto constexpr muldiv_max = std::numeric_limits::max(); /** Return value*mul/div accurately. Computes the result of the multiplication and division in @@ -32,16 +34,13 @@ namespace ripple Throws: None Returns: - `std::pair`: - `first` is `false` if the calculation overflows, - `true` if the calculation is safe. - `second` is the result of the calculation if - `first` is `false`, max value of `uint64_t` - if `true`. + `std::optional`: + `std::nullopt` if the calculation overflows. Otherwise, `value * mul + / div`. */ -std::pair +std::optional mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div); -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/basics/partitioned_unordered_map.h b/include/xrpl/basics/partitioned_unordered_map.h new file mode 100644 index 00000000000..a378011520f --- /dev/null +++ b/include/xrpl/basics/partitioned_unordered_map.h @@ -0,0 +1,425 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2021 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H +#define RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +template +static std::size_t +extract(Key const& key) +{ + return key; +} + +template <> +inline std::size_t +extract(std::string const& key) +{ + return ::beast::uhash<>{}(key); +} + +template < + typename Key, + typename Value, + typename Hash, + typename Pred = std::equal_to, + typename Alloc = std::allocator>> +class partitioned_unordered_map +{ + std::size_t partitions_; + +public: + using key_type = Key; + using mapped_type = Value; + using value_type = std::pair; + using size_type = std::size_t; + using difference_type = std::size_t; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Alloc; + using reference = value_type&; + using const_reference = value_type const&; + using pointer = value_type*; + using const_pointer = value_type const*; + using map_type = std:: + unordered_map; + using partition_map_type = std::vector; + + struct iterator + { + using iterator_category = std::forward_iterator_tag; + partition_map_type* map_{nullptr}; + typename partition_map_type::iterator ait_; + typename map_type::iterator mit_; + + iterator() = default; + + iterator(partition_map_type* map) : map_(map) + { + } + + reference + operator*() const + { + return *mit_; + } + + pointer + operator->() const + { + return &(*mit_); + } + + void + inc() + { + ++mit_; + while (mit_ == ait_->end()) + { + ++ait_; + if (ait_ == map_->end()) + return; + mit_ = ait_->begin(); + } + } + + // ++it + iterator& + operator++() + { + inc(); + return *this; + } + + // it++ + iterator + operator++(int) + { + iterator tmp(*this); + inc(); + return tmp; + } + + friend bool + operator==(iterator const& lhs, iterator const& rhs) + { + return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && + lhs.mit_ == rhs.mit_; + } + + friend bool + operator!=(iterator const& lhs, iterator const& rhs) + { + return !(lhs == rhs); + } + }; + + struct const_iterator + { + using iterator_category = std::forward_iterator_tag; + + partition_map_type* map_{nullptr}; + typename partition_map_type::iterator ait_; + typename map_type::iterator mit_; + + const_iterator() = default; + + const_iterator(partition_map_type* map) : map_(map) + { + } + + const_iterator(iterator const& orig) + { + map_ = orig.map_; + ait_ = orig.ait_; + mit_ = orig.mit_; + } + + const_reference + operator*() const + { + return *mit_; + } + + const_pointer + operator->() const + { + return &(*mit_); + } + + void + inc() + { + ++mit_; + while (mit_ == ait_->end()) + { + ++ait_; + if (ait_ == map_->end()) + return; + mit_ = ait_->begin(); + } + } + + // ++it + const_iterator& + operator++() + { + inc(); + return *this; + } + + // it++ + const_iterator + operator++(int) + { + const_iterator tmp(*this); + inc(); + return tmp; + } + + friend bool + operator==(const_iterator const& lhs, const_iterator const& rhs) + { + return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && + lhs.mit_ == rhs.mit_; + } + + friend bool + operator!=(const_iterator const& lhs, const_iterator const& rhs) + { + return !(lhs == rhs); + } + }; + +private: + std::size_t + partitioner(Key const& key) const + { + return extract(key) % partitions_; + } + + template + static void + end(T& it) + { + it.ait_ = it.map_->end(); + it.mit_ = it.map_->back().end(); + } + + template + static void + begin(T& it) + { + for (it.ait_ = it.map_->begin(); it.ait_ != it.map_->end(); ++it.ait_) + { + if (it.ait_->begin() == it.ait_->end()) + continue; + it.mit_ = it.ait_->begin(); + return; + } + end(it); + } + +public: + partitioned_unordered_map( + std::optional partitions = std::nullopt) + { + // Set partitions to the number of hardware threads if the parameter + // is either empty or set to 0. + partitions_ = partitions && *partitions + ? *partitions + : std::thread::hardware_concurrency(); + map_.resize(partitions_); + XRPL_ASSERT( + partitions_, + "ripple::partitioned_unordered_map::partitioned_unordered_map : " + "nonzero partitions"); + } + + std::size_t + partitions() const + { + return partitions_; + } + + partition_map_type& + map() + { + return map_; + } + + iterator + begin() + { + iterator it(&map_); + begin(it); + return it; + } + + const_iterator + cbegin() const + { + const_iterator it(&map_); + begin(it); + return it; + } + + const_iterator + begin() const + { + return cbegin(); + } + + iterator + end() + { + iterator it(&map_); + end(it); + return it; + } + + const_iterator + cend() const + { + const_iterator it(&map_); + end(it); + return it; + } + + const_iterator + end() const + { + return cend(); + } + +private: + template + void + find(key_type const& key, T& it) const + { + it.ait_ = it.map_->begin() + partitioner(key); + it.mit_ = it.ait_->find(key); + if (it.mit_ == it.ait_->end()) + end(it); + } + +public: + iterator + find(key_type const& key) + { + iterator it(&map_); + find(key, it); + return it; + } + + const_iterator + find(key_type const& key) const + { + const_iterator it(&map_); + find(key, it); + return it; + } + + template + std::pair + emplace(std::piecewise_construct_t const&, T&& keyTuple, U&& valueTuple) + { + auto const& key = std::get<0>(keyTuple); + iterator it(&map_); + it.ait_ = it.map_->begin() + partitioner(key); + auto [eit, inserted] = it.ait_->emplace( + std::piecewise_construct, + std::forward(keyTuple), + std::forward(valueTuple)); + it.mit_ = eit; + return {it, inserted}; + } + + template + std::pair + emplace(T&& key, U&& val) + { + iterator it(&map_); + it.ait_ = it.map_->begin() + partitioner(key); + auto [eit, inserted] = + it.ait_->emplace(std::forward(key), std::forward(val)); + it.mit_ = eit; + return {it, inserted}; + } + + void + clear() + { + for (auto& p : map_) + p.clear(); + } + + iterator + erase(const_iterator position) + { + iterator it(&map_); + it.ait_ = position.ait_; + it.mit_ = position.ait_->erase(position.mit_); + + while (it.mit_ == it.ait_->end()) + { + ++it.ait_; + if (it.ait_ == it.map_->end()) + break; + it.mit_ = it.ait_->begin(); + } + + return it; + } + + std::size_t + size() const + { + std::size_t ret = 0; + for (auto& p : map_) + ret += p.size(); + return ret; + } + + Value& + operator[](Key const& key) + { + return map_[partitioner(key)][key]; + } + +private: + mutable partition_map_type map_{}; +}; + +} // namespace ripple + +#endif // RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H diff --git a/include/xrpl/basics/random.h b/include/xrpl/basics/random.h new file mode 100644 index 00000000000..4b8bc81759b --- /dev/null +++ b/include/xrpl/basics/random.h @@ -0,0 +1,210 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_RANDOM_H_INCLUDED +#define RIPPLE_BASICS_RANDOM_H_INCLUDED + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace ripple { + +#ifndef __INTELLISENSE__ +static_assert( + std::is_integral::value && + std::is_unsigned::value, + "The Ripple default PRNG engine must return an unsigned integral type."); + +static_assert( + std::numeric_limits::max() >= + std::numeric_limits::max(), + "The Ripple default PRNG engine return must be at least 64 bits wide."); +#endif + +namespace detail { + +// Determines if a type can be called like an Engine +template +using is_engine = std::is_invocable_r; +} // namespace detail + +/** Return the default random engine. + + This engine is guaranteed to be deterministic, but by + default will be randomly seeded. It is NOT cryptographically + secure and MUST NOT be used to generate randomness that + will be used for keys, secure cookies, IVs, padding, etc. + + Each thread gets its own instance of the engine which + will be randomly seeded. +*/ +inline beast::xor_shift_engine& +default_prng() +{ + // This is used to seed the thread-specific PRNGs on demand + static beast::xor_shift_engine seeder = [] { + std::random_device rng; + std::uniform_int_distribution distribution{1}; + return beast::xor_shift_engine(distribution(rng)); + }(); + + // This protects the seeder + static std::mutex m; + + // The thread-specific PRNGs: + thread_local beast::xor_shift_engine engine = [] { + std::uint64_t seed; + { + std::lock_guard lk(m); + std::uniform_int_distribution distribution{1}; + seed = distribution(seeder); + } + return beast::xor_shift_engine{seed}; + }(); + + return engine; +} + +/** Return a uniformly distributed random integer. + + @param min The smallest value to return. If not specified + the value defaults to 0. + @param max The largest value to return. If not specified + the value defaults to the largest value that + can be represented. + + The randomness is generated by the specified engine (or + the default engine if one is not specified). The result + is cryptographically secure only when the engine passed + into the function is cryptographically secure. + + @note The range is always a closed interval, so calling + rand_int(-5, 15) can return any integer in the + closed interval [-5, 15]; similarly, calling + rand_int(7) can return any integer in the closed + interval [0, 7]. +*/ +/** @{ */ +template +std::enable_if_t< + std::is_integral::value && detail::is_engine::value, + Integral> +rand_int(Engine& engine, Integral min, Integral max) +{ + XRPL_ASSERT(max > min, "ripple::rand_int : max over min inputs"); + + // This should have no state and constructing it should + // be very cheap. If that turns out not to be the case + // it could be hand-optimized. + return std::uniform_int_distribution(min, max)(engine); +} + +template +std::enable_if_t::value, Integral> +rand_int(Integral min, Integral max) +{ + return rand_int(default_prng(), min, max); +} + +template +std::enable_if_t< + std::is_integral::value && detail::is_engine::value, + Integral> +rand_int(Engine& engine, Integral max) +{ + return rand_int(engine, Integral(0), max); +} + +template +std::enable_if_t::value, Integral> +rand_int(Integral max) +{ + return rand_int(default_prng(), max); +} + +template +std::enable_if_t< + std::is_integral::value && detail::is_engine::value, + Integral> +rand_int(Engine& engine) +{ + return rand_int(engine, std::numeric_limits::max()); +} + +template +std::enable_if_t::value, Integral> +rand_int() +{ + return rand_int(default_prng(), std::numeric_limits::max()); +} +/** @} */ + +/** Return a random byte */ +/** @{ */ +template +std::enable_if_t< + (std::is_same::value || + std::is_same::value) && + detail::is_engine::value, + Byte> +rand_byte(Engine& engine) +{ + return static_cast(rand_int( + engine, + std::numeric_limits::min(), + std::numeric_limits::max())); +} + +template +std::enable_if_t< + (std::is_same::value || + std::is_same::value), + Byte> +rand_byte() +{ + return rand_byte(default_prng()); +} +/** @} */ + +/** Return a random boolean value */ +/** @{ */ +template +inline bool +rand_bool(Engine& engine) +{ + return rand_int(engine, 1) == 1; +} + +inline bool +rand_bool() +{ + return rand_bool(default_prng()); +} +/** @} */ + +} // namespace ripple + +#endif // RIPPLE_BASICS_RANDOM_H_INCLUDED diff --git a/include/xrpl/basics/safe_cast.h b/include/xrpl/basics/safe_cast.h new file mode 100644 index 00000000000..f193f1793f2 --- /dev/null +++ b/include/xrpl/basics/safe_cast.h @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2018 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_SAFE_CAST_H_INCLUDED +#define RIPPLE_BASICS_SAFE_CAST_H_INCLUDED + +#include + +namespace ripple { + +// safe_cast adds compile-time checks to a static_cast to ensure that +// the destination can hold all values of the source. This is particularly +// handy when the source or destination is an enumeration type. + +template +static constexpr bool is_safetocasttovalue_v = + (std::is_integral_v && std::is_integral_v) && + (std::is_signed::value || std::is_unsigned::value) && + (std::is_signed::value != std::is_signed::value + ? sizeof(Dest) > sizeof(Src) + : sizeof(Dest) >= sizeof(Src)); + +template +inline constexpr std:: + enable_if_t && std::is_integral_v, Dest> + safe_cast(Src s) noexcept +{ + static_assert( + std::is_signed_v || std::is_unsigned_v, + "Cannot cast signed to unsigned"); + constexpr unsigned not_same = + std::is_signed_v != std::is_signed_v; + static_assert( + sizeof(Dest) >= sizeof(Src) + not_same, + "Destination is too small to hold all values of source"); + return static_cast(s); +} + +template +inline constexpr std:: + enable_if_t && std::is_integral_v, Dest> + safe_cast(Src s) noexcept +{ + return static_cast(safe_cast>(s)); +} + +template +inline constexpr std:: + enable_if_t && std::is_enum_v, Dest> + safe_cast(Src s) noexcept +{ + return safe_cast(static_cast>(s)); +} + +// unsafe_cast explicitly flags a static_cast as not necessarily able to hold +// all values of the source. It includes a compile-time check so that if +// underlying types become safe, it can be converted to a safe_cast. + +template +inline constexpr std:: + enable_if_t && std::is_integral_v, Dest> + unsafe_cast(Src s) noexcept +{ + static_assert( + !is_safetocasttovalue_v, + "Only unsafe if casting signed to unsigned or " + "destination is too small"); + return static_cast(s); +} + +template +inline constexpr std:: + enable_if_t && std::is_integral_v, Dest> + unsafe_cast(Src s) noexcept +{ + return static_cast(unsafe_cast>(s)); +} + +template +inline constexpr std:: + enable_if_t && std::is_enum_v, Dest> + unsafe_cast(Src s) noexcept +{ + return unsafe_cast(static_cast>(s)); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/basics/scope.h b/include/xrpl/basics/scope.h new file mode 100644 index 00000000000..954edcc2a16 --- /dev/null +++ b/include/xrpl/basics/scope.h @@ -0,0 +1,260 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2021 Ripple Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_SCOPE_H_INCLUDED +#define RIPPLE_BASICS_SCOPE_H_INCLUDED + +#include + +#include +#include +#include +#include + +namespace ripple { + +// RAII scope helpers. As specified in Library Fundamental, Version 3 +// Basic design of idea: https://www.youtube.com/watch?v=WjTrfoiB0MQ +// Specification: +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4873.html#scopeguard + +// This implementation deviates from the spec slightly: +// The scope_exit and scope_fail constructors taking a functor are not +// permitted to throw an exception. This was done because some compilers +// did not like the superfluous try/catch in the common instantiations +// where the construction was noexcept. Instead a static_assert is used +// to enforce this restriction. + +template +class scope_exit +{ + EF exit_function_; + bool execute_on_destruction_{true}; + +public: + ~scope_exit() + { + if (execute_on_destruction_) + exit_function_(); + } + + scope_exit(scope_exit&& rhs) noexcept( + std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + : exit_function_{std::forward(rhs.exit_function_)} + , execute_on_destruction_{rhs.execute_on_destruction_} + { + rhs.release(); + } + + scope_exit& + operator=(scope_exit&&) = delete; + + template + explicit scope_exit( + EFP&& f, + std::enable_if_t< + !std::is_same_v, scope_exit> && + std::is_constructible_v>* = 0) noexcept + : exit_function_{std::forward(f)} + { + static_assert( + std:: + is_nothrow_constructible_v(f))>); + } + + void + release() noexcept + { + execute_on_destruction_ = false; + } +}; + +template +scope_exit(EF) -> scope_exit; + +template +class scope_fail +{ + EF exit_function_; + bool execute_on_destruction_{true}; + int uncaught_on_creation_{std::uncaught_exceptions()}; + +public: + ~scope_fail() + { + if (execute_on_destruction_ && + std::uncaught_exceptions() > uncaught_on_creation_) + exit_function_(); + } + + scope_fail(scope_fail&& rhs) noexcept( + std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + : exit_function_{std::forward(rhs.exit_function_)} + , execute_on_destruction_{rhs.execute_on_destruction_} + , uncaught_on_creation_{rhs.uncaught_on_creation_} + { + rhs.release(); + } + + scope_fail& + operator=(scope_fail&&) = delete; + + template + explicit scope_fail( + EFP&& f, + std::enable_if_t< + !std::is_same_v, scope_fail> && + std::is_constructible_v>* = 0) noexcept + : exit_function_{std::forward(f)} + { + static_assert( + std:: + is_nothrow_constructible_v(f))>); + } + + void + release() noexcept + { + execute_on_destruction_ = false; + } +}; + +template +scope_fail(EF) -> scope_fail; + +template +class scope_success +{ + EF exit_function_; + bool execute_on_destruction_{true}; + int uncaught_on_creation_{std::uncaught_exceptions()}; + +public: + ~scope_success() noexcept(noexcept(exit_function_())) + { + if (execute_on_destruction_ && + std::uncaught_exceptions() <= uncaught_on_creation_) + exit_function_(); + } + + scope_success(scope_success&& rhs) noexcept( + std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + : exit_function_{std::forward(rhs.exit_function_)} + , execute_on_destruction_{rhs.execute_on_destruction_} + , uncaught_on_creation_{rhs.uncaught_on_creation_} + { + rhs.release(); + } + + scope_success& + operator=(scope_success&&) = delete; + + template + explicit scope_success( + EFP&& f, + std::enable_if_t< + !std::is_same_v, scope_success> && + std::is_constructible_v>* = + 0) noexcept(std::is_nothrow_constructible_v || std::is_nothrow_constructible_v) + : exit_function_{std::forward(f)} + { + } + + void + release() noexcept + { + execute_on_destruction_ = false; + } +}; + +template +scope_success(EF) -> scope_success; + +/** + Automatically unlocks and re-locks a unique_lock object. + + This is the reverse of a std::unique_lock object - instead of locking the + mutex for the lifetime of this object, it unlocks it. + + Make sure you don't try to unlock mutexes that aren't actually locked! + + This is essentially a less-versatile boost::reverse_lock. + + e.g. @code + + std::mutex mut; + + for (;;) + { + std::unique_lock myScopedLock{mut}; + // mut is now locked + + ... do some stuff with it locked .. + + while (xyz) + { + ... do some stuff with it locked .. + + scope_unlock unlocker{myScopedLock}; + + // mut is now unlocked for the remainder of this block, + // and re-locked at the end. + + ...do some stuff with it unlocked ... + } // mut gets locked here. + + } // mut gets unlocked here + @endcode +*/ + +template +class scope_unlock +{ + std::unique_lock* plock; + +public: + explicit scope_unlock(std::unique_lock& lock) noexcept(true) + : plock(&lock) + { + XRPL_ASSERT( + plock->owns_lock(), + "ripple::scope_unlock::scope_unlock : mutex must be locked"); + plock->unlock(); + } + + // Immovable type + scope_unlock(scope_unlock const&) = delete; + scope_unlock& + operator=(scope_unlock const&) = delete; + + ~scope_unlock() noexcept(true) + { + plock->lock(); + } +}; + +template +scope_unlock(std::unique_lock&) -> scope_unlock; + +} // namespace ripple + +#endif diff --git a/include/xrpl/basics/spinlock.h b/include/xrpl/basics/spinlock.h new file mode 100644 index 00000000000..5d5097bd2df --- /dev/null +++ b/include/xrpl/basics/spinlock.h @@ -0,0 +1,226 @@ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright 2022, Nikolaos D. Bougalis + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef RIPPLE_BASICS_SPINLOCK_H_INCLUDED +#define RIPPLE_BASICS_SPINLOCK_H_INCLUDED + +#include + +#include +#include +#include + +#ifndef __aarch64__ +#include +#endif + +namespace ripple { + +namespace detail { +/** Inform the processor that we are in a tight spin-wait loop. + + Spinlocks caught in tight loops can result in the processor's pipeline + filling up with comparison operations, resulting in a misprediction at + the time the lock is finally acquired, necessitating pipeline flushing + which is ridiculously expensive and results in very high latency. + + This function instructs the processor to "pause" for some architecture + specific amount of time, to prevent this. + */ +inline void +spin_pause() noexcept +{ +#ifdef __aarch64__ + asm volatile("yield"); +#else + _mm_pause(); +#endif +} + +} // namespace detail + +/** @{ */ +/** Classes to handle arrays of spinlocks packed into a single atomic integer: + + Packed spinlocks allow for tremendously space-efficient lock-sharding + but they come at a cost. + + First, the implementation is necessarily low-level and uses advanced + features like memory ordering and highly platform-specific tricks to + maximize performance. This imposes a significant and ongoing cost to + developers. + + Second, and perhaps most important, is that the packing of multiple + locks into a single integer which, albeit space-efficient, also has + performance implications stemming from data dependencies, increased + cache-coherency traffic between processors and heavier loads on the + processor's load/store units. + + To be sure, these locks can have advantages but they are definitely + not general purpose locks and should not be thought of or used that + way. The use cases for them are likely few and far between; without + a compelling reason to use them, backed by profiling data, it might + be best to use one of the standard locking primitives instead. Note + that in most common platforms, `std::mutex` is so heavily optimized + that it can, usually, outperform spinlocks. + + @tparam T An unsigned integral type (e.g. std::uint16_t) + */ + +/** A class that grabs a single packed spinlock from an atomic integer. + + This class meets the requirements of Lockable: + https://en.cppreference.com/w/cpp/named_req/Lockable + */ +template +class packed_spinlock +{ + // clang-format off + static_assert(std::is_unsigned_v); + static_assert(std::atomic::is_always_lock_free); + static_assert( + std::is_same_v&>().fetch_or(0)), T> && + std::is_same_v&>().fetch_and(0)), T>, + "std::atomic::fetch_and(T) and std::atomic::fetch_and(T) are required by packed_spinlock"); + // clang-format on + +private: + std::atomic& bits_; + T const mask_; + +public: + packed_spinlock(packed_spinlock const&) = delete; + packed_spinlock& + operator=(packed_spinlock const&) = delete; + + /** A single spinlock packed inside the specified atomic + + @param lock The atomic integer inside which the spinlock is packed. + @param index The index of the spinlock this object acquires. + + @note For performance reasons, you should strive to have `lock` be + on a cacheline by itself. + */ + packed_spinlock(std::atomic& lock, int index) + : bits_(lock), mask_(static_cast(1) << index) + { + XRPL_ASSERT( + index >= 0 && (mask_ != 0), + "ripple::packed_spinlock::packed_spinlock : valid index and mask"); + } + + [[nodiscard]] bool + try_lock() + { + return (bits_.fetch_or(mask_, std::memory_order_acquire) & mask_) == 0; + } + + void + lock() + { + while (!try_lock()) + { + // The use of relaxed memory ordering here is intentional and + // serves to help reduce cache coherency traffic during times + // of contention by avoiding writes that would definitely not + // result in the lock being acquired. + while ((bits_.load(std::memory_order_relaxed) & mask_) != 0) + detail::spin_pause(); + } + } + + void + unlock() + { + bits_.fetch_and(~mask_, std::memory_order_release); + } +}; + +/** A spinlock implemented on top of an atomic integer. + + @note Using `packed_spinlock` and `spinlock` against the same underlying + atomic integer can result in `spinlock` not being able to actually + acquire the lock during periods of high contention, because of how + the two locks operate: `spinlock` will spin trying to grab all the + bits at once, whereas any given `packed_spinlock` will only try to + grab one bit at a time. Caveat emptor. + + This class meets the requirements of Lockable: + https://en.cppreference.com/w/cpp/named_req/Lockable + */ +template +class spinlock +{ + static_assert(std::is_unsigned_v); + static_assert(std::atomic::is_always_lock_free); + +private: + std::atomic& lock_; + +public: + spinlock(spinlock const&) = delete; + spinlock& + operator=(spinlock const&) = delete; + + /** Grabs the + + @param lock The atomic integer to spin against. + + @note For performance reasons, you should strive to have `lock` be + on a cacheline by itself. + */ + spinlock(std::atomic& lock) : lock_(lock) + { + } + + [[nodiscard]] bool + try_lock() + { + T expected = 0; + + return lock_.compare_exchange_weak( + expected, + std::numeric_limits::max(), + std::memory_order_acquire, + std::memory_order_relaxed); + } + + void + lock() + { + while (!try_lock()) + { + // The use of relaxed memory ordering here is intentional and + // serves to help reduce cache coherency traffic during times + // of contention by avoiding writes that would definitely not + // result in the lock being acquired. + while (lock_.load(std::memory_order_relaxed) != 0) + detail::spin_pause(); + } + } + + void + unlock() + { + lock_.store(0, std::memory_order_release); + } +}; +/** @} */ + +} // namespace ripple + +#endif diff --git a/include/xrpl/basics/strHex.h b/include/xrpl/basics/strHex.h new file mode 100644 index 00000000000..257fb540b3c --- /dev/null +++ b/include/xrpl/basics/strHex.h @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_STRHEX_H_INCLUDED +#define RIPPLE_BASICS_STRHEX_H_INCLUDED + +#include +#include + +namespace ripple { + +template +std::string +strHex(FwdIt begin, FwdIt end) +{ + static_assert( + std::is_convertible< + typename std::iterator_traits::iterator_category, + std::forward_iterator_tag>::value, + "FwdIt must be a forward iterator"); + std::string result; + result.reserve(2 * std::distance(begin, end)); + boost::algorithm::hex(begin, end, std::back_inserter(result)); + return result; +} + +template ().begin())> +std::string +strHex(T const& from) +{ + return strHex(from.begin(), from.end()); +} + +} // namespace ripple + +#endif diff --git a/src/ripple/basics/tagged_integer.h b/include/xrpl/basics/tagged_integer.h similarity index 90% rename from src/ripple/basics/tagged_integer.h rename to include/xrpl/basics/tagged_integer.h index 5267fa9359b..b826b87db15 100644 --- a/src/ripple/basics/tagged_integer.h +++ b/include/xrpl/basics/tagged_integer.h @@ -20,8 +20,10 @@ #ifndef BEAST_UTILITY_TAGGED_INTEGER_H_INCLUDED #define BEAST_UTILITY_TAGGED_INTEGER_H_INCLUDED -#include +#include + #include + #include #include #include @@ -52,7 +54,6 @@ class tagged_integer tagged_integer, boost::shiftable>>>>> { - private: Int m_value; @@ -67,10 +68,7 @@ class tagged_integer class = typename std::enable_if< std::is_integral::value && sizeof(OtherInt) <= sizeof(Int)>::type> - explicit - /* constexpr */ - tagged_integer(OtherInt value) noexcept - : m_value(value) + explicit constexpr tagged_integer(OtherInt value) noexcept : m_value(value) { static_assert( sizeof(tagged_integer) == sizeof(Int), @@ -78,13 +76,13 @@ class tagged_integer } bool - operator<(const tagged_integer & rhs) const noexcept + operator<(const tagged_integer& rhs) const noexcept { return m_value < rhs.m_value; } bool - operator==(const tagged_integer & rhs) const noexcept + operator==(const tagged_integer& rhs) const noexcept { return m_value == rhs.m_value; } @@ -178,14 +176,14 @@ class tagged_integer } tagged_integer& - operator++ () noexcept + operator++() noexcept { ++m_value; return *this; } tagged_integer& - operator-- () noexcept + operator--() noexcept { --m_value; return *this; @@ -197,31 +195,28 @@ class tagged_integer return m_value; } - friend - std::ostream& - operator<< (std::ostream& s, tagged_integer const& t) + friend std::ostream& + operator<<(std::ostream& s, tagged_integer const& t) { s << t.m_value; return s; } - friend - std::istream& - operator>> (std::istream& s, tagged_integer& t) + friend std::istream& + operator>>(std::istream& s, tagged_integer& t) { s >> t.m_value; return s; } - friend - std::string + friend std::string to_string(tagged_integer const& t) { return std::to_string(t.m_value); } }; -} // ripple +} // namespace ripple namespace beast { template @@ -231,6 +226,5 @@ struct is_contiguously_hashable, HashAlgorithm> explicit is_contiguously_hashable() = default; }; -} // beast +} // namespace beast #endif - diff --git a/include/xrpl/beast/asio/io_latency_probe.h b/include/xrpl/beast/asio/io_latency_probe.h new file mode 100644 index 00000000000..966b4686aea --- /dev/null +++ b/include/xrpl/beast/asio/io_latency_probe.h @@ -0,0 +1,265 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED +#define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED + +#include + +#include +#include + +#include +#include +#include +#include + +namespace beast { + +/** Measures handler latency on an io_service queue. */ +template +class io_latency_probe +{ +private: + using duration = typename Clock::duration; + using time_point = typename Clock::time_point; + + std::recursive_mutex m_mutex; + std::condition_variable_any m_cond; + std::size_t m_count; + duration const m_period; + boost::asio::io_service& m_ios; + boost::asio::basic_waitable_timer m_timer; + bool m_cancel; + +public: + io_latency_probe(duration const& period, boost::asio::io_service& ios) + : m_count(1) + , m_period(period) + , m_ios(ios) + , m_timer(m_ios) + , m_cancel(false) + { + } + + ~io_latency_probe() + { + std::unique_lock lock(m_mutex); + cancel(lock, true); + } + + /** Return the io_service associated with the latency probe. */ + /** @{ */ + boost::asio::io_service& + get_io_service() + { + return m_ios; + } + + boost::asio::io_service const& + get_io_service() const + { + return m_ios; + } + /** @} */ + + /** Cancel all pending i/o. + Any handlers which have already been queued will still be called. + */ + /** @{ */ + void + cancel() + { + std::unique_lock lock(m_mutex); + cancel(lock, true); + } + + void + cancel_async() + { + std::unique_lock lock(m_mutex); + cancel(lock, false); + } + /** @} */ + + /** Measure one sample of i/o latency. + Handler will be called with this signature: + void Handler (Duration d); + */ + template + void + sample_one(Handler&& handler) + { + std::lock_guard lock(m_mutex); + if (m_cancel) + throw std::logic_error("io_latency_probe is canceled"); + m_ios.post(sample_op( + std::forward(handler), Clock::now(), false, this)); + } + + /** Initiate continuous i/o latency sampling. + Handler will be called with this signature: + void Handler (std::chrono::milliseconds); + */ + template + void + sample(Handler&& handler) + { + std::lock_guard lock(m_mutex); + if (m_cancel) + throw std::logic_error("io_latency_probe is canceled"); + m_ios.post(sample_op( + std::forward(handler), Clock::now(), true, this)); + } + +private: + void + cancel(std::unique_lock& lock, bool wait) + { + if (!m_cancel) + { + --m_count; + m_cancel = true; + } + + if (wait) + m_cond.wait(lock, [this] { return this->m_count == 0; }); + } + + void + addref() + { + std::lock_guard lock(m_mutex); + ++m_count; + } + + void + release() + { + std::lock_guard lock(m_mutex); + if (--m_count == 0) + m_cond.notify_all(); + } + + template + struct sample_op + { + Handler m_handler; + time_point m_start; + bool m_repeat; + io_latency_probe* m_probe; + + sample_op( + Handler const& handler, + time_point const& start, + bool repeat, + io_latency_probe* probe) + : m_handler(handler) + , m_start(start) + , m_repeat(repeat) + , m_probe(probe) + { + XRPL_ASSERT( + m_probe, + "beast::io_latency_probe::sample_op::sample_op : non-null " + "probe input"); + m_probe->addref(); + } + + sample_op(sample_op&& from) noexcept + : m_handler(std::move(from.m_handler)) + , m_start(from.m_start) + , m_repeat(from.m_repeat) + , m_probe(from.m_probe) + { + XRPL_ASSERT( + m_probe, + "beast::io_latency_probe::sample_op::sample_op(sample_op&&) : " + "non-null probe input"); + from.m_probe = nullptr; + } + + sample_op(sample_op const&) = delete; + sample_op + operator=(sample_op const&) = delete; + sample_op& + operator=(sample_op&&) = delete; + + ~sample_op() + { + if (m_probe) + m_probe->release(); + } + + void + operator()() const + { + if (!m_probe) + return; + typename Clock::time_point const now(Clock::now()); + typename Clock::duration const elapsed(now - m_start); + + m_handler(elapsed); + + { + std::lock_guard lock(m_probe->m_mutex); + if (m_probe->m_cancel) + return; + } + + if (m_repeat) + { + // Calculate when we want to sample again, and + // adjust for the expected latency. + // + typename Clock::time_point const when( + now + m_probe->m_period - 2 * elapsed); + + if (when <= now) + { + // The latency is too high to maintain the desired + // period so don't bother with a timer. + // + m_probe->m_ios.post( + sample_op(m_handler, now, m_repeat, m_probe)); + } + else + { + m_probe->m_timer.expires_from_now(when - now); + m_probe->m_timer.async_wait( + sample_op(m_handler, now, m_repeat, m_probe)); + } + } + } + + void + operator()(boost::system::error_code const& ec) + { + if (!m_probe) + return; + typename Clock::time_point const now(Clock::now()); + m_probe->m_ios.post( + sample_op(m_handler, now, m_repeat, m_probe)); + } + }; +}; + +} // namespace beast + +#endif diff --git a/src/ripple/beast/clock/abstract_clock.h b/include/xrpl/beast/clock/abstract_clock.h similarity index 93% rename from src/ripple/beast/clock/abstract_clock.h rename to include/xrpl/beast/clock/abstract_clock.h index 8f4c319107a..128ab82b4bd 100644 --- a/src/ripple/beast/clock/abstract_clock.h +++ b/include/xrpl/beast/clock/abstract_clock.h @@ -70,7 +70,8 @@ class abstract_clock abstract_clock(abstract_clock const&) = default; /** Returns the current time. */ - virtual time_point now() const = 0; + [[nodiscard]] virtual time_point + now() const = 0; }; //------------------------------------------------------------------------------ @@ -78,8 +79,7 @@ class abstract_clock namespace detail { template -struct abstract_clock_wrapper - : public abstract_clock +struct abstract_clock_wrapper : public abstract_clock { explicit abstract_clock_wrapper() = default; @@ -93,7 +93,7 @@ struct abstract_clock_wrapper } }; -} +} // namespace detail //------------------------------------------------------------------------------ @@ -102,7 +102,7 @@ struct abstract_clock_wrapper http://en.cppreference.com/w/cpp/concept/Clock @tparam Clock The actual concrete clock to use. */ -template +template abstract_clock& get_abstract_clock() { @@ -110,6 +110,6 @@ get_abstract_clock() return clock; } -} +} // namespace beast #endif diff --git a/include/xrpl/beast/clock/basic_seconds_clock.h b/include/xrpl/beast/clock/basic_seconds_clock.h new file mode 100644 index 00000000000..4e444fefeec --- /dev/null +++ b/include/xrpl/beast/clock/basic_seconds_clock.h @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CHRONO_BASIC_SECONDS_CLOCK_H_INCLUDED +#define BEAST_CHRONO_BASIC_SECONDS_CLOCK_H_INCLUDED + +#include + +namespace beast { + +/** A clock whose minimum resolution is one second. + + The purpose of this class is to optimize the performance of the now() + member function call. It uses a dedicated thread that wakes up at least + once per second to sample the requested trivial clock. + + @tparam Clock A type meeting these requirements: + http://en.cppreference.com/w/cpp/concept/Clock +*/ +class basic_seconds_clock +{ +public: + using Clock = std::chrono::steady_clock; + + explicit basic_seconds_clock() = default; + + using rep = typename Clock::rep; + using period = typename Clock::period; + using duration = typename Clock::duration; + using time_point = typename Clock::time_point; + + static bool const is_steady = Clock::is_steady; + + static time_point + now(); +}; + +} // namespace beast + +#endif diff --git a/src/ripple/beast/clock/manual_clock.h b/include/xrpl/beast/clock/manual_clock.h similarity index 78% rename from src/ripple/beast/clock/manual_clock.h rename to include/xrpl/beast/clock/manual_clock.h index 96baae4fcd8..32ff76bb073 100644 --- a/src/ripple/beast/clock/manual_clock.h +++ b/include/xrpl/beast/clock/manual_clock.h @@ -20,8 +20,8 @@ #ifndef BEAST_CHRONO_MANUAL_CLOCK_H_INCLUDED #define BEAST_CHRONO_MANUAL_CLOCK_H_INCLUDED -#include -#include +#include +#include namespace beast { @@ -35,8 +35,7 @@ namespace beast { http://en.cppreference.com/w/cpp/concept/Clock */ template -class manual_clock - : public abstract_clock +class manual_clock : public abstract_clock { public: using typename abstract_clock::rep; @@ -47,8 +46,7 @@ class manual_clock time_point now_; public: - explicit - manual_clock (time_point const& now = time_point(duration(0))) + explicit manual_clock(time_point const& now = time_point(duration(0))) : now_(now) { } @@ -61,9 +59,11 @@ class manual_clock /** Set the current time of the manual clock. */ void - set (time_point const& when) + set(time_point const& when) { - assert(! Clock::is_steady || when >= now_); + XRPL_ASSERT( + !Clock::is_steady || when >= now_, + "beast::manual_clock::set(time_point) : forward input"); now_ = when; } @@ -72,8 +72,7 @@ class manual_clock void set(Integer seconds_from_epoch) { - set(time_point(duration( - std::chrono::seconds(seconds_from_epoch)))); + set(time_point(duration(std::chrono::seconds(seconds_from_epoch)))); } /** Advance the clock by a duration. */ @@ -81,20 +80,21 @@ class manual_clock void advance(std::chrono::duration const& elapsed) { - assert(! Clock::is_steady || - (now_ + elapsed) >= now_); + XRPL_ASSERT( + !Clock::is_steady || (now_ + elapsed) >= now_, + "beast::manual_clock::advance(duration) : forward input"); now_ += elapsed; } /** Convenience for advancing the clock by one second. */ manual_clock& - operator++ () + operator++() { advance(std::chrono::seconds(1)); return *this; } }; -} +} // namespace beast #endif diff --git a/src/ripple/beast/container/aged_container.h b/include/xrpl/beast/container/aged_container.h similarity index 95% rename from src/ripple/beast/container/aged_container.h rename to include/xrpl/beast/container/aged_container.h index 484b59a845e..38a50b4e848 100644 --- a/src/ripple/beast/container/aged_container.h +++ b/include/xrpl/beast/container/aged_container.h @@ -25,12 +25,11 @@ namespace beast { template -struct is_aged_container - : std::false_type +struct is_aged_container : std::false_type { explicit is_aged_container() = default; }; -} +} // namespace beast #endif diff --git a/src/ripple/beast/container/aged_container_utility.h b/include/xrpl/beast/container/aged_container_utility.h similarity index 75% rename from src/ripple/beast/container/aged_container_utility.h rename to include/xrpl/beast/container/aged_container_utility.h index cbc609eea6d..b64cefbf5ad 100644 --- a/src/ripple/beast/container/aged_container_utility.h +++ b/include/xrpl/beast/container/aged_container_utility.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED #define BEAST_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED -#include +#include #include @@ -28,24 +28,21 @@ namespace beast { /** Expire aged container items past the specified age. */ template -typename std::enable_if < - is_aged_container ::value, - std::size_t ->::type -expire (AgedContainer& c, std::chrono::duration const& age) +typename std::enable_if::value, std::size_t>:: + type + expire(AgedContainer& c, std::chrono::duration const& age) { - std::size_t n (0); - auto const expired (c.clock().now() - age); - for (auto iter (c.chronological.cbegin()); - iter != c.chronological.cend() && - iter.when() <= expired;) + std::size_t n(0); + auto const expired(c.clock().now() - age); + for (auto iter(c.chronological.cbegin()); + iter != c.chronological.cend() && iter.when() <= expired;) { - iter = c.erase (iter); + iter = c.erase(iter); ++n; } return n; } -} +} // namespace beast #endif diff --git a/src/ripple/beast/container/aged_map.h b/include/xrpl/beast/container/aged_map.h similarity index 82% rename from src/ripple/beast/container/aged_map.h rename to include/xrpl/beast/container/aged_map.h index 051eed5c412..5b56cde9625 100644 --- a/src/ripple/beast/container/aged_map.h +++ b/include/xrpl/beast/container/aged_map.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_MAP_H_INCLUDED #define BEAST_CONTAINER_AGED_MAP_H_INCLUDED -#include +#include #include #include @@ -32,11 +32,10 @@ template < class Key, class T, class Clock = std::chrono::steady_clock, - class Compare = std::less , - class Allocator = std::allocator > -> -using aged_map = detail::aged_ordered_container < - false, true, Key, T, Clock, Compare, Allocator>; + class Compare = std::less, + class Allocator = std::allocator>> +using aged_map = detail:: + aged_ordered_container; } diff --git a/src/ripple/beast/container/aged_multimap.h b/include/xrpl/beast/container/aged_multimap.h similarity index 82% rename from src/ripple/beast/container/aged_multimap.h rename to include/xrpl/beast/container/aged_multimap.h index 8b475c1d8b5..aa6c01f5b32 100644 --- a/src/ripple/beast/container/aged_multimap.h +++ b/include/xrpl/beast/container/aged_multimap.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_MULTIMAP_H_INCLUDED #define BEAST_CONTAINER_AGED_MULTIMAP_H_INCLUDED -#include +#include #include #include @@ -32,11 +32,10 @@ template < class Key, class T, class Clock = std::chrono::steady_clock, - class Compare = std::less , - class Allocator = std::allocator > -> -using aged_multimap = detail::aged_ordered_container < - true, true, Key, T, Clock, Compare, Allocator>; + class Compare = std::less, + class Allocator = std::allocator>> +using aged_multimap = detail:: + aged_ordered_container; } diff --git a/src/ripple/beast/container/aged_multiset.h b/include/xrpl/beast/container/aged_multiset.h similarity index 83% rename from src/ripple/beast/container/aged_multiset.h rename to include/xrpl/beast/container/aged_multiset.h index 378380e2b35..d43cc8d5a70 100644 --- a/src/ripple/beast/container/aged_multiset.h +++ b/include/xrpl/beast/container/aged_multiset.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_MULTISET_H_INCLUDED #define BEAST_CONTAINER_AGED_MULTISET_H_INCLUDED -#include +#include #include #include @@ -31,11 +31,10 @@ namespace beast { template < class Key, class Clock = std::chrono::steady_clock, - class Compare = std::less , - class Allocator = std::allocator -> -using aged_multiset = detail::aged_ordered_container < - true, false, Key, void, Clock, Compare, Allocator>; + class Compare = std::less, + class Allocator = std::allocator> +using aged_multiset = detail:: + aged_ordered_container; } diff --git a/src/ripple/beast/container/aged_set.h b/include/xrpl/beast/container/aged_set.h similarity index 83% rename from src/ripple/beast/container/aged_set.h rename to include/xrpl/beast/container/aged_set.h index 1b07244b194..aa31a47af4a 100644 --- a/src/ripple/beast/container/aged_set.h +++ b/include/xrpl/beast/container/aged_set.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_SET_H_INCLUDED #define BEAST_CONTAINER_AGED_SET_H_INCLUDED -#include +#include #include #include @@ -31,11 +31,10 @@ namespace beast { template < class Key, class Clock = std::chrono::steady_clock, - class Compare = std::less , - class Allocator = std::allocator -> -using aged_set = detail::aged_ordered_container < - false, false, Key, void, Clock, Compare, Allocator>; + class Compare = std::less, + class Allocator = std::allocator> +using aged_set = detail:: + aged_ordered_container; } diff --git a/src/ripple/beast/container/aged_unordered_map.h b/include/xrpl/beast/container/aged_unordered_map.h similarity index 79% rename from src/ripple/beast/container/aged_unordered_map.h rename to include/xrpl/beast/container/aged_unordered_map.h index c78e2c9a235..b466c87b3ff 100644 --- a/src/ripple/beast/container/aged_unordered_map.h +++ b/include/xrpl/beast/container/aged_unordered_map.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED #define BEAST_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED -#include +#include #include #include @@ -32,12 +32,18 @@ template < class Key, class T, class Clock = std::chrono::steady_clock, - class Hash = std::hash , - class KeyEqual = std::equal_to , - class Allocator = std::allocator > -> -using aged_unordered_map = detail::aged_unordered_container < - false, true, Key, T, Clock, Hash, KeyEqual, Allocator>; + class Hash = std::hash, + class KeyEqual = std::equal_to, + class Allocator = std::allocator>> +using aged_unordered_map = detail::aged_unordered_container< + false, + true, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>; } diff --git a/src/ripple/beast/container/aged_unordered_multimap.h b/include/xrpl/beast/container/aged_unordered_multimap.h similarity index 83% rename from src/ripple/beast/container/aged_unordered_multimap.h rename to include/xrpl/beast/container/aged_unordered_multimap.h index ba708ae8a43..e64c8415c61 100644 --- a/src/ripple/beast/container/aged_unordered_multimap.h +++ b/include/xrpl/beast/container/aged_unordered_multimap.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED #define BEAST_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED -#include +#include #include #include @@ -32,12 +32,18 @@ template < class Key, class T, class Clock = std::chrono::steady_clock, - class Hash = std::hash , - class KeyEqual = std::equal_to , - class Allocator = std::allocator > -> -using aged_unordered_multimap = detail::aged_unordered_container < - true, true, Key, T, Clock, Hash, KeyEqual, Allocator>; + class Hash = std::hash, + class KeyEqual = std::equal_to, + class Allocator = std::allocator>> +using aged_unordered_multimap = detail::aged_unordered_container< + true, + true, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>; } diff --git a/src/ripple/beast/container/aged_unordered_multiset.h b/include/xrpl/beast/container/aged_unordered_multiset.h similarity index 83% rename from src/ripple/beast/container/aged_unordered_multiset.h rename to include/xrpl/beast/container/aged_unordered_multiset.h index c3806ef79f6..499dc7d6780 100644 --- a/src/ripple/beast/container/aged_unordered_multiset.h +++ b/include/xrpl/beast/container/aged_unordered_multiset.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED #define BEAST_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED -#include +#include #include #include @@ -31,12 +31,18 @@ namespace beast { template < class Key, class Clock = std::chrono::steady_clock, - class Hash = std::hash , - class KeyEqual = std::equal_to , - class Allocator = std::allocator -> -using aged_unordered_multiset = detail::aged_unordered_container < - true, false, Key, void, Clock, Hash, KeyEqual, Allocator>; + class Hash = std::hash, + class KeyEqual = std::equal_to, + class Allocator = std::allocator> +using aged_unordered_multiset = detail::aged_unordered_container< + true, + false, + Key, + void, + Clock, + Hash, + KeyEqual, + Allocator>; } diff --git a/src/ripple/beast/container/aged_unordered_set.h b/include/xrpl/beast/container/aged_unordered_set.h similarity index 79% rename from src/ripple/beast/container/aged_unordered_set.h rename to include/xrpl/beast/container/aged_unordered_set.h index 1ca61db3275..45fc6cd0ed8 100644 --- a/src/ripple/beast/container/aged_unordered_set.h +++ b/include/xrpl/beast/container/aged_unordered_set.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED #define BEAST_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED -#include +#include #include #include @@ -31,12 +31,18 @@ namespace beast { template < class Key, class Clock = std::chrono::steady_clock, - class Hash = std::hash , - class KeyEqual = std::equal_to , - class Allocator = std::allocator -> -using aged_unordered_set = detail::aged_unordered_container < - false, false, Key, void, Clock, Hash, KeyEqual, Allocator>; + class Hash = std::hash, + class KeyEqual = std::equal_to, + class Allocator = std::allocator> +using aged_unordered_set = detail::aged_unordered_container< + false, + false, + Key, + void, + Clock, + Hash, + KeyEqual, + Allocator>; } diff --git a/src/ripple/beast/container/detail/aged_associative_container.h b/include/xrpl/beast/container/detail/aged_associative_container.h similarity index 88% rename from src/ripple/beast/container/detail/aged_associative_container.h rename to include/xrpl/beast/container/detail/aged_associative_container.h index 42d04e1927c..5ff7901552f 100644 --- a/src/ripple/beast/container/detail/aged_associative_container.h +++ b/include/xrpl/beast/container/detail/aged_associative_container.h @@ -32,27 +32,27 @@ struct aged_associative_container_extract_t explicit aged_associative_container_extract_t() = default; template - decltype (Value::first) const& - operator() (Value const& value) const + decltype(Value::first) const& + operator()(Value const& value) const { return value.first; } }; template <> -struct aged_associative_container_extract_t +struct aged_associative_container_extract_t { explicit aged_associative_container_extract_t() = default; template Value const& - operator() (Value const& value) const + operator()(Value const& value) const { return value; } }; -} -} +} // namespace detail +} // namespace beast #endif diff --git a/include/xrpl/beast/container/detail/aged_container_iterator.h b/include/xrpl/beast/container/detail/aged_container_iterator.h new file mode 100644 index 00000000000..7467ad33c7d --- /dev/null +++ b/include/xrpl/beast/container/detail/aged_container_iterator.h @@ -0,0 +1,182 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_DETAIL_AGED_CONTAINER_ITERATOR_H_INCLUDED +#define BEAST_CONTAINER_DETAIL_AGED_CONTAINER_ITERATOR_H_INCLUDED + +#include +#include + +namespace beast { + +template +class aged_ordered_container; + +namespace detail { + +// If Iterator is SCARY then this iterator will be as well. +template +class aged_container_iterator +{ +public: + using iterator_category = + typename std::iterator_traits::iterator_category; + using value_type = typename std::conditional< + is_const, + typename Iterator::value_type::stashed::value_type const, + typename Iterator::value_type::stashed::value_type>::type; + using difference_type = + typename std::iterator_traits::difference_type; + using pointer = value_type*; + using reference = value_type&; + using time_point = typename Iterator::value_type::stashed::time_point; + + aged_container_iterator() = default; + + // Disable constructing a const_iterator from a non-const_iterator. + // Converting between reverse and non-reverse iterators should be explicit. + template < + bool other_is_const, + class OtherIterator, + class = typename std::enable_if< + (other_is_const == false || is_const == true) && + std::is_same::value == false>::type> + explicit aged_container_iterator( + aged_container_iterator const& other) + : m_iter(other.m_iter) + { + } + + // Disable constructing a const_iterator from a non-const_iterator. + template < + bool other_is_const, + class = typename std::enable_if< + other_is_const == false || is_const == true>::type> + aged_container_iterator( + aged_container_iterator const& other) + : m_iter(other.m_iter) + { + } + + // Disable assigning a const_iterator to a non-const iterator + template + auto + operator=( + aged_container_iterator const& other) -> + typename std::enable_if< + other_is_const == false || is_const == true, + aged_container_iterator&>::type + { + m_iter = other.m_iter; + return *this; + } + + template + bool + operator==(aged_container_iterator const& + other) const + { + return m_iter == other.m_iter; + } + + template + bool + operator!=(aged_container_iterator const& + other) const + { + return m_iter != other.m_iter; + } + + aged_container_iterator& + operator++() + { + ++m_iter; + return *this; + } + + aged_container_iterator + operator++(int) + { + aged_container_iterator const prev(*this); + ++m_iter; + return prev; + } + + aged_container_iterator& + operator--() + { + --m_iter; + return *this; + } + + aged_container_iterator + operator--(int) + { + aged_container_iterator const prev(*this); + --m_iter; + return prev; + } + + reference + operator*() const + { + return m_iter->value; + } + + pointer + operator->() const + { + return &m_iter->value; + } + + time_point const& + when() const + { + return m_iter->when; + } + +private: + template + friend class aged_ordered_container; + + template + friend class aged_unordered_container; + + template + friend class aged_container_iterator; + + template + aged_container_iterator(OtherIterator const& iter) : m_iter(iter) + { + } + + Iterator const& + iterator() const + { + return m_iter; + } + + Iterator m_iter; +}; + +} // namespace detail + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/container/detail/aged_ordered_container.h b/include/xrpl/beast/container/detail/aged_ordered_container.h new file mode 100644 index 00000000000..8c978d05173 --- /dev/null +++ b/include/xrpl/beast/container/detail/aged_ordered_container.h @@ -0,0 +1,2298 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_DETAIL_AGED_ORDERED_CONTAINER_H_INCLUDED +#define BEAST_CONTAINER_DETAIL_AGED_ORDERED_CONTAINER_H_INCLUDED + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace detail { + +// Traits templates used to discern reverse_iterators, which are disallowed +// for mutating operations. +template +struct is_boost_reverse_iterator : std::false_type +{ + explicit is_boost_reverse_iterator() = default; +}; + +template +struct is_boost_reverse_iterator> + : std::true_type +{ + explicit is_boost_reverse_iterator() = default; +}; + +/** Associative container where each element is also indexed by time. + + This container mirrors the interface of the standard library ordered + associative containers, with the addition that each element is associated + with a `when` `time_point` which is obtained from the value of the clock's + `now`. The function `touch` updates the time for an element to the current + time as reported by the clock. + + An extra set of iterator types and member functions are provided in the + `chronological` memberspace that allow traversal in temporal or reverse + temporal order. This container is useful as a building block for caches + whose items expire after a certain amount of time. The chronological + iterators allow for fully customizable expiration strategies. + + @see aged_set, aged_multiset, aged_map, aged_multimap +*/ +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock = std::chrono::steady_clock, + class Compare = std::less, + class Allocator = std::allocator< + typename std::conditional, Key>::type>> +class aged_ordered_container +{ +public: + using clock_type = abstract_clock; + using time_point = typename clock_type::time_point; + using duration = typename clock_type::duration; + using key_type = Key; + using mapped_type = T; + using value_type = + typename std::conditional, Key>::type; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + // Introspection (for unit tests) + using is_unordered = std::false_type; + using is_multi = std::integral_constant; + using is_map = std::integral_constant; + +private: + static Key const& + extract(value_type const& value) + { + return aged_associative_container_extract_t()(value); + } + + // VFALCO TODO hoist to remove template argument dependencies + struct element + : boost::intrusive::set_base_hook< + boost::intrusive::link_mode>, + boost::intrusive::list_base_hook< + boost::intrusive::link_mode> + { + // Stash types here so the iterator doesn't + // need to see the container declaration. + struct stashed + { + explicit stashed() = default; + + using value_type = typename aged_ordered_container::value_type; + using time_point = typename aged_ordered_container::time_point; + }; + + element(time_point const& when_, value_type const& value_) + : value(value_), when(when_) + { + } + + element(time_point const& when_, value_type&& value_) + : value(std::move(value_)), when(when_) + { + } + + template < + class... Args, + class = typename std::enable_if< + std::is_constructible::value>::type> + element(time_point const& when_, Args&&... args) + : value(std::forward(args)...), when(when_) + { + } + + value_type value; + time_point when; + }; + + // VFALCO TODO This should only be enabled for maps. + class pair_value_compare : public Compare + { + public: + using first_argument = value_type; + using second_argument = value_type; + using result_type = bool; + + bool + operator()(value_type const& lhs, value_type const& rhs) const + { + return Compare::operator()(lhs.first, rhs.first); + } + + pair_value_compare() + { + } + + pair_value_compare(pair_value_compare const& other) : Compare(other) + { + } + + private: + friend aged_ordered_container; + + pair_value_compare(Compare const& compare) : Compare(compare) + { + } + }; + + // Compares value_type against element, used in insert_check + // VFALCO TODO hoist to remove template argument dependencies + class KeyValueCompare : public Compare + { + public: + using first_argument = Key; + using second_argument = element; + using result_type = bool; + + KeyValueCompare() = default; + + KeyValueCompare(Compare const& compare) : Compare(compare) + { + } + + bool + operator()(Key const& k, element const& e) const + { + return Compare::operator()(k, extract(e.value)); + } + + bool + operator()(element const& e, Key const& k) const + { + return Compare::operator()(extract(e.value), k); + } + + bool + operator()(element const& x, element const& y) const + { + return Compare::operator()(extract(x.value), extract(y.value)); + } + + Compare& + compare() + { + return *this; + } + + Compare const& + compare() const + { + return *this; + } + }; + + using list_type = typename boost::intrusive:: + make_list>::type; + + using cont_type = typename std::conditional< + IsMulti, + typename boost::intrusive::make_multiset< + element, + boost::intrusive::constant_time_size, + boost::intrusive::compare>::type, + typename boost::intrusive::make_set< + element, + boost::intrusive::constant_time_size, + boost::intrusive::compare>::type>::type; + + using ElementAllocator = typename std::allocator_traits< + Allocator>::template rebind_alloc; + + using ElementAllocatorTraits = std::allocator_traits; + + class config_t + : private KeyValueCompare, + public beast::detail::empty_base_optimization + { + public: + explicit config_t(clock_type& clock_) : clock(clock_) + { + } + + config_t(clock_type& clock_, Compare const& comp) + : KeyValueCompare(comp), clock(clock_) + { + } + + config_t(clock_type& clock_, Allocator const& alloc_) + : beast::detail::empty_base_optimization(alloc_) + , clock(clock_) + { + } + + config_t( + clock_type& clock_, + Compare const& comp, + Allocator const& alloc_) + : KeyValueCompare(comp) + , beast::detail::empty_base_optimization(alloc_) + , clock(clock_) + { + } + + config_t(config_t const& other) + : KeyValueCompare(other.key_compare()) + , beast::detail::empty_base_optimization( + ElementAllocatorTraits::select_on_container_copy_construction( + other.alloc())) + , clock(other.clock) + { + } + + config_t(config_t const& other, Allocator const& alloc) + : KeyValueCompare(other.key_compare()) + , beast::detail::empty_base_optimization(alloc) + , clock(other.clock) + { + } + + config_t(config_t&& other) + : KeyValueCompare(std::move(other.key_compare())) + , beast::detail::empty_base_optimization( + std::move(other)) + , clock(other.clock) + { + } + + config_t(config_t&& other, Allocator const& alloc) + : KeyValueCompare(std::move(other.key_compare())) + , beast::detail::empty_base_optimization(alloc) + , clock(other.clock) + { + } + + config_t& + operator=(config_t const& other) + { + if (this != &other) + { + compare() = other.compare(); + alloc() = other.alloc(); + clock = other.clock; + } + return *this; + } + + config_t& + operator=(config_t&& other) + { + compare() = std::move(other.compare()); + alloc() = std::move(other.alloc()); + clock = other.clock; + return *this; + } + + Compare& + compare() + { + return KeyValueCompare::compare(); + } + + Compare const& + compare() const + { + return KeyValueCompare::compare(); + } + + KeyValueCompare& + key_compare() + { + return *this; + } + + KeyValueCompare const& + key_compare() const + { + return *this; + } + + ElementAllocator& + alloc() + { + return beast::detail::empty_base_optimization< + ElementAllocator>::member(); + } + + ElementAllocator const& + alloc() const + { + return beast::detail::empty_base_optimization< + ElementAllocator>::member(); + } + + std::reference_wrapper clock; + }; + + template + element* + new_element(Args&&... args) + { + struct Deleter + { + std::reference_wrapper a_; + Deleter(ElementAllocator& a) : a_(a) + { + } + + void + operator()(element* p) + { + ElementAllocatorTraits::deallocate(a_.get(), p, 1); + } + }; + + std::unique_ptr p( + ElementAllocatorTraits::allocate(m_config.alloc(), 1), + Deleter(m_config.alloc())); + ElementAllocatorTraits::construct( + m_config.alloc(), + p.get(), + clock().now(), + std::forward(args)...); + return p.release(); + } + + void + delete_element(element const* p) + { + ElementAllocatorTraits::destroy(m_config.alloc(), p); + ElementAllocatorTraits::deallocate( + m_config.alloc(), const_cast(p), 1); + } + + void + unlink_and_delete_element(element const* p) + { + chronological.list.erase(chronological.list.iterator_to(*p)); + m_cont.erase(m_cont.iterator_to(*p)); + delete_element(p); + } + +public: + using key_compare = Compare; + using value_compare = + typename std::conditional::type; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = value_type const&; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = + typename std::allocator_traits::const_pointer; + + // A set iterator (IsMap==false) is always const + // because the elements of a set are immutable. + using iterator = beast::detail:: + aged_container_iterator; + using const_iterator = beast::detail:: + aged_container_iterator; + using reverse_iterator = beast::detail:: + aged_container_iterator; + using const_reverse_iterator = beast::detail:: + aged_container_iterator; + + //-------------------------------------------------------------------------- + // + // Chronological ordered iterators + // + // "Memberspace" + // http://accu.org/index.php/journals/1527 + // + //-------------------------------------------------------------------------- + + class chronological_t + { + public: + // A set iterator (IsMap==false) is always const + // because the elements of a set are immutable. + using iterator = beast::detail:: + aged_container_iterator; + using const_iterator = beast::detail:: + aged_container_iterator; + using reverse_iterator = beast::detail::aged_container_iterator< + !IsMap, + typename list_type::reverse_iterator>; + using const_reverse_iterator = beast::detail:: + aged_container_iterator; + + iterator + begin() + { + return iterator(list.begin()); + } + + const_iterator + begin() const + { + return const_iterator(list.begin()); + } + + const_iterator + cbegin() const + { + return const_iterator(list.begin()); + } + + iterator + end() + { + return iterator(list.end()); + } + + const_iterator + end() const + { + return const_iterator(list.end()); + } + + const_iterator + cend() const + { + return const_iterator(list.end()); + } + + reverse_iterator + rbegin() + { + return reverse_iterator(list.rbegin()); + } + + const_reverse_iterator + rbegin() const + { + return const_reverse_iterator(list.rbegin()); + } + + const_reverse_iterator + crbegin() const + { + return const_reverse_iterator(list.rbegin()); + } + + reverse_iterator + rend() + { + return reverse_iterator(list.rend()); + } + + const_reverse_iterator + rend() const + { + return const_reverse_iterator(list.rend()); + } + + const_reverse_iterator + crend() const + { + return const_reverse_iterator(list.rend()); + } + + iterator + iterator_to(value_type& value) + { + static_assert( + std::is_standard_layout::value, + "must be standard layout"); + return list.iterator_to(*reinterpret_cast( + reinterpret_cast(&value) - + ((std::size_t)std::addressof(((element*)0)->member)))); + } + + const_iterator + iterator_to(value_type const& value) const + { + static_assert( + std::is_standard_layout::value, + "must be standard layout"); + return list.iterator_to(*reinterpret_cast( + reinterpret_cast(&value) - + ((std::size_t)std::addressof(((element*)0)->member)))); + } + + private: + chronological_t() + { + } + + chronological_t(chronological_t const&) = delete; + chronological_t(chronological_t&&) = delete; + + friend class aged_ordered_container; + list_type mutable list; + } chronological; + + //-------------------------------------------------------------------------- + // + // Construction + // + //-------------------------------------------------------------------------- + + aged_ordered_container() = delete; + + explicit aged_ordered_container(clock_type& clock); + + aged_ordered_container(clock_type& clock, Compare const& comp); + + aged_ordered_container(clock_type& clock, Allocator const& alloc); + + aged_ordered_container( + clock_type& clock, + Compare const& comp, + Allocator const& alloc); + + template + aged_ordered_container(InputIt first, InputIt last, clock_type& clock); + + template + aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Compare const& comp); + + template + aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Allocator const& alloc); + + template + aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Compare const& comp, + Allocator const& alloc); + + aged_ordered_container(aged_ordered_container const& other); + + aged_ordered_container( + aged_ordered_container const& other, + Allocator const& alloc); + + aged_ordered_container(aged_ordered_container&& other); + + aged_ordered_container( + aged_ordered_container&& other, + Allocator const& alloc); + + aged_ordered_container( + std::initializer_list init, + clock_type& clock); + + aged_ordered_container( + std::initializer_list init, + clock_type& clock, + Compare const& comp); + + aged_ordered_container( + std::initializer_list init, + clock_type& clock, + Allocator const& alloc); + + aged_ordered_container( + std::initializer_list init, + clock_type& clock, + Compare const& comp, + Allocator const& alloc); + + ~aged_ordered_container(); + + aged_ordered_container& + operator=(aged_ordered_container const& other); + + aged_ordered_container& + operator=(aged_ordered_container&& other); + + aged_ordered_container& + operator=(std::initializer_list init); + + allocator_type + get_allocator() const + { + return m_config.alloc(); + } + + clock_type& + clock() + { + return m_config.clock; + } + + clock_type const& + clock() const + { + return m_config.clock; + } + + //-------------------------------------------------------------------------- + // + // Element access (maps) + // + //-------------------------------------------------------------------------- + + template < + class K, + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if::type> + typename std::conditional::type& + at(K const& k); + + template < + class K, + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if::type> + typename std::conditional::type const& + at(K const& k) const; + + template < + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if::type> + typename std::conditional::type& + operator[](Key const& key); + + template < + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if::type> + typename std::conditional::type& + operator[](Key&& key); + + //-------------------------------------------------------------------------- + // + // Iterators + // + //-------------------------------------------------------------------------- + + iterator + begin() + { + return iterator(m_cont.begin()); + } + + const_iterator + begin() const + { + return const_iterator(m_cont.begin()); + } + + const_iterator + cbegin() const + { + return const_iterator(m_cont.begin()); + } + + iterator + end() + { + return iterator(m_cont.end()); + } + + const_iterator + end() const + { + return const_iterator(m_cont.end()); + } + + const_iterator + cend() const + { + return const_iterator(m_cont.end()); + } + + reverse_iterator + rbegin() + { + return reverse_iterator(m_cont.rbegin()); + } + + const_reverse_iterator + rbegin() const + { + return const_reverse_iterator(m_cont.rbegin()); + } + + const_reverse_iterator + crbegin() const + { + return const_reverse_iterator(m_cont.rbegin()); + } + + reverse_iterator + rend() + { + return reverse_iterator(m_cont.rend()); + } + + const_reverse_iterator + rend() const + { + return const_reverse_iterator(m_cont.rend()); + } + + const_reverse_iterator + crend() const + { + return const_reverse_iterator(m_cont.rend()); + } + + iterator + iterator_to(value_type& value) + { + static_assert( + std::is_standard_layout::value, "must be standard layout"); + return m_cont.iterator_to(*reinterpret_cast( + reinterpret_cast(&value) - + ((std::size_t)std::addressof(((element*)0)->member)))); + } + + const_iterator + iterator_to(value_type const& value) const + { + static_assert( + std::is_standard_layout::value, "must be standard layout"); + return m_cont.iterator_to(*reinterpret_cast( + reinterpret_cast(&value) - + ((std::size_t)std::addressof(((element*)0)->member)))); + } + + //-------------------------------------------------------------------------- + // + // Capacity + // + //-------------------------------------------------------------------------- + + bool + empty() const noexcept + { + return m_cont.empty(); + } + + size_type + size() const noexcept + { + return m_cont.size(); + } + + size_type + max_size() const noexcept + { + return m_config.max_size(); + } + + //-------------------------------------------------------------------------- + // + // Modifiers + // + //-------------------------------------------------------------------------- + + void + clear(); + + // map, set + template + auto + insert(value_type const& value) -> + typename std::enable_if>::type; + + // multimap, multiset + template + auto + insert(value_type const& value) -> + typename std::enable_if::type; + + // set + template + auto + insert(value_type&& value) -> typename std::enable_if< + !maybe_multi && !maybe_map, + std::pair>::type; + + // multiset + template + auto + insert(value_type&& value) -> + typename std::enable_if::type; + + //--- + + // map, set + template + auto + insert(const_iterator hint, value_type const& value) -> + typename std::enable_if::type; + + // multimap, multiset + template + typename std::enable_if::type + insert(const_iterator /*hint*/, value_type const& value) + { + // VFALCO TODO Figure out how to utilize 'hint' + return insert(value); + } + + // map, set + template + auto + insert(const_iterator hint, value_type&& value) -> + typename std::enable_if::type; + + // multimap, multiset + template + typename std::enable_if::type + insert(const_iterator /*hint*/, value_type&& value) + { + // VFALCO TODO Figure out how to utilize 'hint' + return insert(std::move(value)); + } + + // map, multimap + template + typename std::enable_if< + maybe_map && std::is_constructible::value, + typename std:: + conditional>::type>:: + type + insert(P&& value) + { + return emplace(std::forward

(value)); + } + + // map, multimap + template + typename std::enable_if< + maybe_map && std::is_constructible::value, + typename std:: + conditional>::type>:: + type + insert(const_iterator hint, P&& value) + { + return emplace_hint(hint, std::forward

(value)); + } + + template + void + insert(InputIt first, InputIt last) + { + for (; first != last; ++first) + insert(cend(), *first); + } + + void + insert(std::initializer_list init) + { + insert(init.begin(), init.end()); + } + + // map, set + template + auto + emplace(Args&&... args) -> + typename std::enable_if>::type; + + // multiset, multimap + template + auto + emplace(Args&&... args) -> + typename std::enable_if::type; + + // map, set + template + auto + emplace_hint(const_iterator hint, Args&&... args) -> + typename std::enable_if>::type; + + // multiset, multimap + template + typename std::enable_if::type + emplace_hint(const_iterator /*hint*/, Args&&... args) + { + // VFALCO TODO Figure out how to utilize 'hint' + return emplace(std::forward(args)...); + } + + // enable_if prevents erase (reverse_iterator pos) from compiling + template < + bool is_const, + class Iterator, + class = std::enable_if_t::value>> + beast::detail::aged_container_iterator + erase(beast::detail::aged_container_iterator pos); + + // enable_if prevents erase (reverse_iterator first, reverse_iterator last) + // from compiling + template < + bool is_const, + class Iterator, + class = std::enable_if_t::value>> + beast::detail::aged_container_iterator + erase( + beast::detail::aged_container_iterator first, + beast::detail::aged_container_iterator last); + + template + auto + erase(K const& k) -> size_type; + + void + swap(aged_ordered_container& other) noexcept; + + //-------------------------------------------------------------------------- + + // enable_if prevents touch (reverse_iterator pos) from compiling + template < + bool is_const, + class Iterator, + class = std::enable_if_t::value>> + void + touch(beast::detail::aged_container_iterator pos) + { + touch(pos, clock().now()); + } + + template + size_type + touch(K const& k); + + //-------------------------------------------------------------------------- + // + // Lookup + // + //-------------------------------------------------------------------------- + + // VFALCO TODO Respect is_transparent (c++14) + template + size_type + count(K const& k) const + { + return m_cont.count(k, std::cref(m_config.key_compare())); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + iterator + find(K const& k) + { + return iterator(m_cont.find(k, std::cref(m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + const_iterator + find(K const& k) const + { + return const_iterator( + m_cont.find(k, std::cref(m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + std::pair + equal_range(K const& k) + { + auto const r(m_cont.equal_range(k, std::cref(m_config.key_compare()))); + return std::make_pair(iterator(r.first), iterator(r.second)); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + std::pair + equal_range(K const& k) const + { + auto const r(m_cont.equal_range(k, std::cref(m_config.key_compare()))); + return std::make_pair( + const_iterator(r.first), const_iterator(r.second)); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + iterator + lower_bound(K const& k) + { + return iterator( + m_cont.lower_bound(k, std::cref(m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + const_iterator + lower_bound(K const& k) const + { + return const_iterator( + m_cont.lower_bound(k, std::cref(m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + iterator + upper_bound(K const& k) + { + return iterator( + m_cont.upper_bound(k, std::cref(m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + const_iterator + upper_bound(K const& k) const + { + return const_iterator( + m_cont.upper_bound(k, std::cref(m_config.key_compare()))); + } + + //-------------------------------------------------------------------------- + // + // Observers + // + //-------------------------------------------------------------------------- + + key_compare + key_comp() const + { + return m_config.compare(); + } + + // VFALCO TODO Should this return const reference for set? + value_compare + value_comp() const + { + return value_compare(m_config.compare()); + } + + //-------------------------------------------------------------------------- + // + // Comparison + // + //-------------------------------------------------------------------------- + + // This differs from the standard in that the comparison + // is only done on the key portion of the value type, ignoring + // the mapped type. + // + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator> + bool + operator==(aged_ordered_container< + OtherIsMulti, + OtherIsMap, + Key, + OtherT, + OtherDuration, + Compare, + OtherAllocator> const& other) const; + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator> + bool + operator!=(aged_ordered_container< + OtherIsMulti, + OtherIsMap, + Key, + OtherT, + OtherDuration, + Compare, + OtherAllocator> const& other) const + { + return !(this->operator==(other)); + } + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator> + bool + operator<(aged_ordered_container< + OtherIsMulti, + OtherIsMap, + Key, + OtherT, + OtherDuration, + Compare, + OtherAllocator> const& other) const + { + value_compare const comp(value_comp()); + return std::lexicographical_compare( + cbegin(), cend(), other.cbegin(), other.cend(), comp); + } + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator> + bool + operator<=(aged_ordered_container< + OtherIsMulti, + OtherIsMap, + Key, + OtherT, + OtherDuration, + Compare, + OtherAllocator> const& other) const + { + return !(other < *this); + } + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator> + bool + operator>(aged_ordered_container< + OtherIsMulti, + OtherIsMap, + Key, + OtherT, + OtherDuration, + Compare, + OtherAllocator> const& other) const + { + return other < *this; + } + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator> + bool + operator>=(aged_ordered_container< + OtherIsMulti, + OtherIsMap, + Key, + OtherT, + OtherDuration, + Compare, + OtherAllocator> const& other) const + { + return !(*this < other); + } + +private: + // enable_if prevents erase (reverse_iterator pos, now) from compiling + template < + bool is_const, + class Iterator, + class = std::enable_if_t::value>> + void + touch( + beast::detail::aged_container_iterator pos, + typename clock_type::time_point const& now); + + template < + bool maybe_propagate = std::allocator_traits< + Allocator>::propagate_on_container_swap::value> + typename std::enable_if::type + swap_data(aged_ordered_container& other) noexcept; + + template < + bool maybe_propagate = std::allocator_traits< + Allocator>::propagate_on_container_swap::value> + typename std::enable_if::type + swap_data(aged_ordered_container& other) noexcept; + +private: + config_t m_config; + cont_type mutable m_cont; +}; + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container(clock_type& clock) + : m_config(clock) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container(clock_type& clock, Compare const& comp) + : m_config(clock, comp), m_cont(comp) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container(clock_type& clock, Allocator const& alloc) + : m_config(clock, alloc) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container( + clock_type& clock, + Compare const& comp, + Allocator const& alloc) + : m_config(clock, comp, alloc), m_cont(comp) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +aged_ordered_container:: + aged_ordered_container(InputIt first, InputIt last, clock_type& clock) + : m_config(clock) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +aged_ordered_container:: + aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Compare const& comp) + : m_config(clock, comp), m_cont(comp) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +aged_ordered_container:: + aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Allocator const& alloc) + : m_config(clock, alloc) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +aged_ordered_container:: + aged_ordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Compare const& comp, + Allocator const& alloc) + : m_config(clock, comp, alloc), m_cont(comp) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container(aged_ordered_container const& other) + : m_config(other.m_config) +#if BOOST_VERSION >= 108000 + , m_cont(other.m_cont.get_comp()) +#else + , m_cont(other.m_cont.comp()) +#endif +{ + insert(other.cbegin(), other.cend()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container( + aged_ordered_container const& other, + Allocator const& alloc) + : m_config(other.m_config, alloc) +#if BOOST_VERSION >= 108000 + , m_cont(other.m_cont.get_comp()) +#else + , m_cont(other.m_cont.comp()) +#endif +{ + insert(other.cbegin(), other.cend()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container(aged_ordered_container&& other) + : m_config(std::move(other.m_config)), m_cont(std::move(other.m_cont)) +{ + chronological.list = std::move(other.chronological.list); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container( + aged_ordered_container&& other, + Allocator const& alloc) + : m_config(std::move(other.m_config), alloc) +#if BOOST_VERSION >= 108000 + , m_cont(std::move(other.m_cont.get_comp())) +#else + , m_cont(std::move(other.m_cont.comp())) +#endif + +{ + insert(other.cbegin(), other.cend()); + other.clear(); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container( + std::initializer_list init, + clock_type& clock) + : m_config(clock) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container( + std::initializer_list init, + clock_type& clock, + Compare const& comp) + : m_config(clock, comp), m_cont(comp) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container( + std::initializer_list init, + clock_type& clock, + Allocator const& alloc) + : m_config(clock, alloc) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + aged_ordered_container( + std::initializer_list init, + clock_type& clock, + Compare const& comp, + Allocator const& alloc) + : m_config(clock, comp, alloc), m_cont(comp) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +aged_ordered_container:: + ~aged_ordered_container() +{ + clear(); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +auto +aged_ordered_container:: +operator=(aged_ordered_container const& other) -> aged_ordered_container& +{ + if (this != &other) + { + clear(); + this->m_config = other.m_config; + insert(other.begin(), other.end()); + } + return *this; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +auto +aged_ordered_container:: +operator=(aged_ordered_container&& other) -> aged_ordered_container& +{ + clear(); + this->m_config = std::move(other.m_config); + insert(other.begin(), other.end()); + other.clear(); + return *this; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +auto +aged_ordered_container:: +operator=(std::initializer_list init) -> aged_ordered_container& +{ + clear(); + insert(init); + return *this; +} + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +typename std::conditional::type& +aged_ordered_container::at( + K const& k) +{ + auto const iter(m_cont.find(k, std::cref(m_config.key_compare()))); + if (iter == m_cont.end()) + throw std::out_of_range("key not found"); + return iter->value.second; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +typename std::conditional::type const& +aged_ordered_container::at( + K const& k) const +{ + auto const iter(m_cont.find(k, std::cref(m_config.key_compare()))); + if (iter == m_cont.end()) + throw std::out_of_range("key not found"); + return iter->value.second; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +typename std::conditional::type& +aged_ordered_container:: +operator[](Key const& key) +{ + typename cont_type::insert_commit_data d; + auto const result( + m_cont.insert_check(key, std::cref(m_config.key_compare()), d)); + if (result.second) + { + element* const p(new_element( + std::piecewise_construct, + std::forward_as_tuple(key), + std::forward_as_tuple())); + m_cont.insert_commit(*p, d); + chronological.list.push_back(*p); + return p->value.second; + } + return result.first->value.second; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +typename std::conditional::type& +aged_ordered_container:: +operator[](Key&& key) +{ + typename cont_type::insert_commit_data d; + auto const result( + m_cont.insert_check(key, std::cref(m_config.key_compare()), d)); + if (result.second) + { + element* const p(new_element( + std::piecewise_construct, + std::forward_as_tuple(std::move(key)), + std::forward_as_tuple())); + m_cont.insert_commit(*p, d); + chronological.list.push_back(*p); + return p->value.second; + } + return result.first->value.second; +} + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +void +aged_ordered_container:: + clear() +{ + for (auto iter(chronological.list.begin()); + iter != chronological.list.end();) + delete_element(&*iter++); + chronological.list.clear(); + m_cont.clear(); +} + +// map, set +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + insert(value_type const& value) -> + typename std::enable_if>::type +{ + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + extract(value), std::cref(m_config.key_compare()), d)); + if (result.second) + { + element* const p(new_element(value)); + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return std::make_pair(iterator(iter), true); + } + return std::make_pair(iterator(result.first), false); +} + +// multimap, multiset +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + insert(value_type const& value) -> + typename std::enable_if::type +{ + auto const before( + m_cont.upper_bound(extract(value), std::cref(m_config.key_compare()))); + element* const p(new_element(value)); + chronological.list.push_back(*p); + auto const iter(m_cont.insert_before(before, *p)); + return iterator(iter); +} + +// set +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + insert(value_type&& value) -> + typename std:: + enable_if>::type +{ + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + extract(value), std::cref(m_config.key_compare()), d)); + if (result.second) + { + element* const p(new_element(std::move(value))); + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return std::make_pair(iterator(iter), true); + } + return std::make_pair(iterator(result.first), false); +} + +// multiset +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + insert(value_type&& value) -> + typename std::enable_if::type +{ + auto const before( + m_cont.upper_bound(extract(value), std::cref(m_config.key_compare()))); + element* const p(new_element(std::move(value))); + chronological.list.push_back(*p); + auto const iter(m_cont.insert_before(before, *p)); + return iterator(iter); +} + +//--- + +// map, set +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + insert(const_iterator hint, value_type const& value) -> + typename std::enable_if::type +{ + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + hint.iterator(), extract(value), std::cref(m_config.key_compare()), d)); + if (result.second) + { + element* const p(new_element(value)); + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return iterator(iter); + } + return iterator(result.first); +} + +// map, set +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + insert(const_iterator hint, value_type&& value) -> + typename std::enable_if::type +{ + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + hint.iterator(), extract(value), std::cref(m_config.key_compare()), d)); + if (result.second) + { + element* const p(new_element(std::move(value))); + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return iterator(iter); + } + return iterator(result.first); +} + +// map, set +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + emplace(Args&&... args) -> + typename std::enable_if>::type +{ + // VFALCO NOTE Its unfortunate that we need to + // construct element here + element* const p(new_element(std::forward(args)...)); + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + extract(p->value), std::cref(m_config.key_compare()), d)); + if (result.second) + { + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return std::make_pair(iterator(iter), true); + } + delete_element(p); + return std::make_pair(iterator(result.first), false); +} + +// multiset, multimap +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + emplace(Args&&... args) -> + typename std::enable_if::type +{ + element* const p(new_element(std::forward(args)...)); + auto const before(m_cont.upper_bound( + extract(p->value), std::cref(m_config.key_compare()))); + chronological.list.push_back(*p); + auto const iter(m_cont.insert_before(before, *p)); + return iterator(iter); +} + +// map, set +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + emplace_hint(const_iterator hint, Args&&... args) -> + typename std::enable_if>::type +{ + // VFALCO NOTE Its unfortunate that we need to + // construct element here + element* const p(new_element(std::forward(args)...)); + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + hint.iterator(), + extract(p->value), + std::cref(m_config.key_compare()), + d)); + if (result.second) + { + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return std::make_pair(iterator(iter), true); + } + delete_element(p); + return std::make_pair(iterator(result.first), false); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +beast::detail::aged_container_iterator +aged_ordered_container:: + erase(beast::detail::aged_container_iterator pos) +{ + unlink_and_delete_element(&*((pos++).iterator())); + return beast::detail::aged_container_iterator( + pos.iterator()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +beast::detail::aged_container_iterator +aged_ordered_container:: + erase( + beast::detail::aged_container_iterator first, + beast::detail::aged_container_iterator last) +{ + for (; first != last;) + unlink_and_delete_element(&*((first++).iterator())); + + return beast::detail::aged_container_iterator( + first.iterator()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + erase(K const& k) -> size_type +{ + auto iter(m_cont.find(k, std::cref(m_config.key_compare()))); + if (iter == m_cont.end()) + return 0; + size_type n(0); + for (;;) + { + auto p(&*iter++); + bool const done(m_config(*p, extract(iter->value))); + unlink_and_delete_element(p); + ++n; + if (done) + break; + } + return n; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +void +aged_ordered_container::swap( + aged_ordered_container& other) noexcept +{ + swap_data(other); + std::swap(chronological, other.chronological); + std::swap(m_cont, other.m_cont); +} + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +auto +aged_ordered_container:: + touch(K const& k) -> size_type +{ + auto const now(clock().now()); + size_type n(0); + auto const range(equal_range(k)); + for (auto iter : range) + { + touch(iter, now); + ++n; + } + return n; +} + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator> +bool +aged_ordered_container:: +operator==(aged_ordered_container< + OtherIsMulti, + OtherIsMap, + Key, + OtherT, + OtherDuration, + Compare, + OtherAllocator> const& other) const +{ + using Other = aged_ordered_container< + OtherIsMulti, + OtherIsMap, + Key, + OtherT, + OtherDuration, + Compare, + OtherAllocator>; + if (size() != other.size()) + return false; + std::equal_to eq; + return std::equal( + cbegin(), + cend(), + other.cbegin(), + other.cend(), + [&eq, &other]( + value_type const& lhs, typename Other::value_type const& rhs) { + return eq(extract(lhs), other.extract(rhs)); + }); +} + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +void +aged_ordered_container:: + touch( + beast::detail::aged_container_iterator pos, + typename clock_type::time_point const& now) +{ + auto& e(*pos.iterator()); + e.when = now; + chronological.list.erase(chronological.list.iterator_to(e)); + chronological.list.push_back(e); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +typename std::enable_if::type +aged_ordered_container:: + swap_data(aged_ordered_container& other) noexcept +{ + std::swap(m_config.key_compare(), other.m_config.key_compare()); + std::swap(m_config.alloc(), other.m_config.alloc()); + std::swap(m_config.clock, other.m_config.clock); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +template +typename std::enable_if::type +aged_ordered_container:: + swap_data(aged_ordered_container& other) noexcept +{ + std::swap(m_config.key_compare(), other.m_config.key_compare()); + std::swap(m_config.clock, other.m_config.clock); +} + +} // namespace detail + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +struct is_aged_container> : std::true_type +{ + explicit is_aged_container() = default; +}; + +// Free functions + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator> +void +swap( + beast::detail::aged_ordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Compare, + Allocator>& lhs, + beast::detail::aged_ordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Compare, + Allocator>& rhs) noexcept +{ + lhs.swap(rhs); +} + +/** Expire aged container items past the specified age. */ +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Compare, + class Allocator, + class Rep, + class Period> +std::size_t +expire( + detail::aged_ordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Compare, + Allocator>& c, + std::chrono::duration const& age) +{ + std::size_t n(0); + auto const expired(c.clock().now() - age); + for (auto iter(c.chronological.cbegin()); + iter != c.chronological.cend() && iter.when() <= expired;) + { + iter = c.erase(iter); + ++n; + } + return n; +} + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/container/detail/aged_unordered_container.h b/include/xrpl/beast/container/detail/aged_unordered_container.h new file mode 100644 index 00000000000..3b9c83a0149 --- /dev/null +++ b/include/xrpl/beast/container/detail/aged_unordered_container.h @@ -0,0 +1,3451 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_DETAIL_AGED_UNORDERED_CONTAINER_H_INCLUDED +#define BEAST_CONTAINER_DETAIL_AGED_UNORDERED_CONTAINER_H_INCLUDED + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + +TODO + +- Add constructor variations that take a bucket count + +- Review for noexcept and exception guarantees + +- Call the safe version of is_permutation that takes 4 iterators + +*/ + +#ifndef BEAST_NO_CXX14_IS_PERMUTATION +#define BEAST_NO_CXX14_IS_PERMUTATION 1 +#endif + +namespace beast { +namespace detail { + +/** Associative container where each element is also indexed by time. + + This container mirrors the interface of the standard library unordered + associative containers, with the addition that each element is associated + with a `when` `time_point` which is obtained from the value of the clock's + `now`. The function `touch` updates the time for an element to the current + time as reported by the clock. + + An extra set of iterator types and member functions are provided in the + `chronological` memberspace that allow traversal in temporal or reverse + temporal order. This container is useful as a building block for caches + whose items expire after a certain amount of time. The chronological + iterators allow for fully customizable expiration strategies. + + @see aged_unordered_set, aged_unordered_multiset + @see aged_unordered_map, aged_unordered_multimap +*/ +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock = std::chrono::steady_clock, + class Hash = std::hash, + class KeyEqual = std::equal_to, + class Allocator = std::allocator< + typename std::conditional, Key>::type>> +class aged_unordered_container +{ +public: + using clock_type = abstract_clock; + using time_point = typename clock_type::time_point; + using duration = typename clock_type::duration; + using key_type = Key; + using mapped_type = T; + using value_type = + typename std::conditional, Key>::type; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + // Introspection (for unit tests) + using is_unordered = std::true_type; + using is_multi = std::integral_constant; + using is_map = std::integral_constant; + +private: + static Key const& + extract(value_type const& value) + { + return aged_associative_container_extract_t()(value); + } + + // VFALCO TODO hoist to remove template argument dependencies + struct element + : boost::intrusive::unordered_set_base_hook< + boost::intrusive::link_mode>, + boost::intrusive::list_base_hook< + boost::intrusive::link_mode> + { + // Stash types here so the iterator doesn't + // need to see the container declaration. + struct stashed + { + explicit stashed() = default; + + using value_type = typename aged_unordered_container::value_type; + using time_point = typename aged_unordered_container::time_point; + }; + + element(time_point const& when_, value_type const& value_) + : value(value_), when(when_) + { + } + + element(time_point const& when_, value_type&& value_) + : value(std::move(value_)), when(when_) + { + } + + template < + class... Args, + class = typename std::enable_if< + std::is_constructible::value>::type> + element(time_point const& when_, Args&&... args) + : value(std::forward(args)...), when(when_) + { + } + + value_type value; + time_point when; + }; + + // VFALCO TODO hoist to remove template argument dependencies + class ValueHash : public Hash + { + public: + using argument_type = element; + using result_type = size_t; + + ValueHash() + { + } + + ValueHash(Hash const& h) : Hash(h) + { + } + + std::size_t + operator()(element const& e) const + { + return Hash::operator()(extract(e.value)); + } + + Hash& + hash_function() + { + return *this; + } + + Hash const& + hash_function() const + { + return *this; + } + }; + + // Compares value_type against element, used in find/insert_check + // VFALCO TODO hoist to remove template argument dependencies + class KeyValueEqual : public KeyEqual + { + public: + using first_argument_type = Key; + using second_argument_type = element; + using result_type = bool; + + KeyValueEqual() + { + } + + KeyValueEqual(KeyEqual const& keyEqual) : KeyEqual(keyEqual) + { + } + + bool + operator()(Key const& k, element const& e) const + { + return KeyEqual::operator()(k, extract(e.value)); + } + + bool + operator()(element const& e, Key const& k) const + { + return KeyEqual::operator()(extract(e.value), k); + } + + bool + operator()(element const& lhs, element const& rhs) const + { + return KeyEqual::operator()(extract(lhs.value), extract(rhs.value)); + } + + KeyEqual& + key_eq() + { + return *this; + } + + KeyEqual const& + key_eq() const + { + return *this; + } + }; + + using list_type = typename boost::intrusive:: + make_list>::type; + + using cont_type = typename std::conditional< + IsMulti, + typename boost::intrusive::make_unordered_multiset< + element, + boost::intrusive::constant_time_size, + boost::intrusive::hash, + boost::intrusive::equal, + boost::intrusive::cache_begin>::type, + typename boost::intrusive::make_unordered_set< + element, + boost::intrusive::constant_time_size, + boost::intrusive::hash, + boost::intrusive::equal, + boost::intrusive::cache_begin>::type>::type; + + using bucket_type = typename cont_type::bucket_type; + using bucket_traits = typename cont_type::bucket_traits; + + using ElementAllocator = typename std::allocator_traits< + Allocator>::template rebind_alloc; + + using ElementAllocatorTraits = std::allocator_traits; + + using BucketAllocator = typename std::allocator_traits< + Allocator>::template rebind_alloc; + + using BucketAllocatorTraits = std::allocator_traits; + + class config_t + : private ValueHash, + private KeyValueEqual, + private beast::detail::empty_base_optimization + { + public: + explicit config_t(clock_type& clock_) : clock(clock_) + { + } + + config_t(clock_type& clock_, Hash const& hash) + : ValueHash(hash), clock(clock_) + { + } + + config_t(clock_type& clock_, KeyEqual const& keyEqual) + : KeyValueEqual(keyEqual), clock(clock_) + { + } + + config_t(clock_type& clock_, Allocator const& alloc_) + : beast::detail::empty_base_optimization(alloc_) + , clock(clock_) + { + } + + config_t(clock_type& clock_, Hash const& hash, KeyEqual const& keyEqual) + : ValueHash(hash), KeyValueEqual(keyEqual), clock(clock_) + { + } + + config_t(clock_type& clock_, Hash const& hash, Allocator const& alloc_) + : ValueHash(hash) + , beast::detail::empty_base_optimization(alloc_) + , clock(clock_) + { + } + + config_t( + clock_type& clock_, + KeyEqual const& keyEqual, + Allocator const& alloc_) + : KeyValueEqual(keyEqual) + , beast::detail::empty_base_optimization(alloc_) + , clock(clock_) + { + } + + config_t( + clock_type& clock_, + Hash const& hash, + KeyEqual const& keyEqual, + Allocator const& alloc_) + : ValueHash(hash) + , KeyValueEqual(keyEqual) + , beast::detail::empty_base_optimization(alloc_) + , clock(clock_) + { + } + + config_t(config_t const& other) + : ValueHash(other.hash_function()) + , KeyValueEqual(other.key_eq()) + , beast::detail::empty_base_optimization( + ElementAllocatorTraits::select_on_container_copy_construction( + other.alloc())) + , clock(other.clock) + { + } + + config_t(config_t const& other, Allocator const& alloc) + : ValueHash(other.hash_function()) + , KeyValueEqual(other.key_eq()) + , beast::detail::empty_base_optimization(alloc) + , clock(other.clock) + { + } + + config_t(config_t&& other) + : ValueHash(std::move(other.hash_function())) + , KeyValueEqual(std::move(other.key_eq())) + , beast::detail::empty_base_optimization( + std::move(other.alloc())) + , clock(other.clock) + { + } + + config_t(config_t&& other, Allocator const& alloc) + : ValueHash(std::move(other.hash_function())) + , KeyValueEqual(std::move(other.key_eq())) + , beast::detail::empty_base_optimization(alloc) + , clock(other.clock) + { + } + + config_t& + operator=(config_t const& other) + { + hash_function() = other.hash_function(); + key_eq() = other.key_eq(); + alloc() = other.alloc(); + clock = other.clock; + return *this; + } + + config_t& + operator=(config_t&& other) + { + hash_function() = std::move(other.hash_function()); + key_eq() = std::move(other.key_eq()); + alloc() = std::move(other.alloc()); + clock = other.clock; + return *this; + } + + ValueHash& + value_hash() + { + return *this; + } + + ValueHash const& + value_hash() const + { + return *this; + } + + Hash& + hash_function() + { + return ValueHash::hash_function(); + } + + Hash const& + hash_function() const + { + return ValueHash::hash_function(); + } + + KeyValueEqual& + key_value_equal() + { + return *this; + } + + KeyValueEqual const& + key_value_equal() const + { + return *this; + } + + KeyEqual& + key_eq() + { + return key_value_equal().key_eq(); + } + + KeyEqual const& + key_eq() const + { + return key_value_equal().key_eq(); + } + + ElementAllocator& + alloc() + { + return beast::detail::empty_base_optimization< + ElementAllocator>::member(); + } + + ElementAllocator const& + alloc() const + { + return beast::detail::empty_base_optimization< + ElementAllocator>::member(); + } + + std::reference_wrapper clock; + }; + + class Buckets + { + public: + using vec_type = std::vector< + bucket_type, + typename std::allocator_traits::template rebind_alloc< + bucket_type>>; + + Buckets() : m_max_load_factor(1.f), m_vec() + { + m_vec.resize(cont_type::suggested_upper_bucket_count(0)); + } + + Buckets(Allocator const& alloc) : m_max_load_factor(1.f), m_vec(alloc) + { + m_vec.resize(cont_type::suggested_upper_bucket_count(0)); + } + + operator bucket_traits() + { + return bucket_traits(&m_vec[0], m_vec.size()); + } + + void + clear() + { + m_vec.clear(); + } + + size_type + max_bucket_count() const + { + return m_vec.max_size(); + } + + float& + max_load_factor() + { + return m_max_load_factor; + } + + float const& + max_load_factor() const + { + return m_max_load_factor; + } + + // count is the number of buckets + template + void + rehash(size_type count, Container& c) + { + size_type const size(m_vec.size()); + if (count == size) + return; + if (count > m_vec.capacity()) + { + // Need two vectors otherwise we + // will destroy non-empty buckets. + vec_type vec(m_vec.get_allocator()); + std::swap(m_vec, vec); + m_vec.resize(count); + c.rehash(bucket_traits(&m_vec[0], m_vec.size())); + return; + } + // Rehash in place. + if (count > size) + { + // This should not reallocate since + // we checked capacity earlier. + m_vec.resize(count); + c.rehash(bucket_traits(&m_vec[0], count)); + return; + } + // Resize must happen after rehash otherwise + // we might destroy non-empty buckets. + c.rehash(bucket_traits(&m_vec[0], count)); + m_vec.resize(count); + } + + // Resize the buckets to accommodate at least n items. + template + void + resize(size_type n, Container& c) + { + size_type const suggested( + cont_type::suggested_upper_bucket_count(n)); + rehash(suggested, c); + } + + private: + float m_max_load_factor; + vec_type m_vec; + }; + + template + element* + new_element(Args&&... args) + { + struct Deleter + { + std::reference_wrapper a_; + Deleter(ElementAllocator& a) : a_(a) + { + } + + void + operator()(element* p) + { + ElementAllocatorTraits::deallocate(a_.get(), p, 1); + } + }; + + std::unique_ptr p( + ElementAllocatorTraits::allocate(m_config.alloc(), 1), + Deleter(m_config.alloc())); + ElementAllocatorTraits::construct( + m_config.alloc(), + p.get(), + clock().now(), + std::forward(args)...); + return p.release(); + } + + void + delete_element(element const* p) + { + ElementAllocatorTraits::destroy(m_config.alloc(), p); + ElementAllocatorTraits::deallocate( + m_config.alloc(), const_cast(p), 1); + } + + void + unlink_and_delete_element(element const* p) + { + chronological.list.erase(chronological.list.iterator_to(*p)); + m_cont.erase(m_cont.iterator_to(*p)); + delete_element(p); + } + +public: + using hasher = Hash; + using key_equal = KeyEqual; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = value_type const&; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = + typename std::allocator_traits::const_pointer; + + // A set iterator (IsMap==false) is always const + // because the elements of a set are immutable. + using iterator = beast::detail:: + aged_container_iterator; + using const_iterator = beast::detail:: + aged_container_iterator; + + using local_iterator = beast::detail:: + aged_container_iterator; + using const_local_iterator = beast::detail:: + aged_container_iterator; + + //-------------------------------------------------------------------------- + // + // Chronological ordered iterators + // + // "Memberspace" + // http://accu.org/index.php/journals/1527 + // + //-------------------------------------------------------------------------- + + class chronological_t + { + public: + // A set iterator (IsMap==false) is always const + // because the elements of a set are immutable. + using iterator = beast::detail:: + aged_container_iterator; + using const_iterator = beast::detail:: + aged_container_iterator; + using reverse_iterator = beast::detail::aged_container_iterator< + !IsMap, + typename list_type::reverse_iterator>; + using const_reverse_iterator = beast::detail:: + aged_container_iterator; + + iterator + begin() + { + return iterator(list.begin()); + } + + const_iterator + begin() const + { + return const_iterator(list.begin()); + } + + const_iterator + cbegin() const + { + return const_iterator(list.begin()); + } + + iterator + end() + { + return iterator(list.end()); + } + + const_iterator + end() const + { + return const_iterator(list.end()); + } + + const_iterator + cend() const + { + return const_iterator(list.end()); + } + + reverse_iterator + rbegin() + { + return reverse_iterator(list.rbegin()); + } + + const_reverse_iterator + rbegin() const + { + return const_reverse_iterator(list.rbegin()); + } + + const_reverse_iterator + crbegin() const + { + return const_reverse_iterator(list.rbegin()); + } + + reverse_iterator + rend() + { + return reverse_iterator(list.rend()); + } + + const_reverse_iterator + rend() const + { + return const_reverse_iterator(list.rend()); + } + + const_reverse_iterator + crend() const + { + return const_reverse_iterator(list.rend()); + } + + iterator + iterator_to(value_type& value) + { + static_assert( + std::is_standard_layout::value, + "must be standard layout"); + return list.iterator_to(*reinterpret_cast( + reinterpret_cast(&value) - + ((std::size_t)std::addressof(((element*)0)->member)))); + } + + const_iterator + iterator_to(value_type const& value) const + { + static_assert( + std::is_standard_layout::value, + "must be standard layout"); + return list.iterator_to(*reinterpret_cast( + reinterpret_cast(&value) - + ((std::size_t)std::addressof(((element*)0)->member)))); + } + + private: + chronological_t() + { + } + + chronological_t(chronological_t const&) = delete; + chronological_t(chronological_t&&) = delete; + + friend class aged_unordered_container; + list_type mutable list; + } chronological; + + //-------------------------------------------------------------------------- + // + // Construction + // + //-------------------------------------------------------------------------- + + aged_unordered_container() = delete; + + explicit aged_unordered_container(clock_type& clock); + + aged_unordered_container(clock_type& clock, Hash const& hash); + + aged_unordered_container(clock_type& clock, KeyEqual const& key_eq); + + aged_unordered_container(clock_type& clock, Allocator const& alloc); + + aged_unordered_container( + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq); + + aged_unordered_container( + clock_type& clock, + Hash const& hash, + Allocator const& alloc); + + aged_unordered_container( + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc); + + aged_unordered_container( + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc); + + template + aged_unordered_container(InputIt first, InputIt last, clock_type& clock); + + template + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash); + + template + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + KeyEqual const& key_eq); + + template + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Allocator const& alloc); + + template + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq); + + template + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash, + Allocator const& alloc); + + template + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc); + + template + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc); + + aged_unordered_container(aged_unordered_container const& other); + + aged_unordered_container( + aged_unordered_container const& other, + Allocator const& alloc); + + aged_unordered_container(aged_unordered_container&& other); + + aged_unordered_container( + aged_unordered_container&& other, + Allocator const& alloc); + + aged_unordered_container( + std::initializer_list init, + clock_type& clock); + + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash); + + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + KeyEqual const& key_eq); + + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Allocator const& alloc); + + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq); + + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash, + Allocator const& alloc); + + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc); + + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc); + + ~aged_unordered_container(); + + aged_unordered_container& + operator=(aged_unordered_container const& other); + + aged_unordered_container& + operator=(aged_unordered_container&& other); + + aged_unordered_container& + operator=(std::initializer_list init); + + allocator_type + get_allocator() const + { + return m_config.alloc(); + } + + clock_type& + clock() + { + return m_config.clock; + } + + clock_type const& + clock() const + { + return m_config.clock; + } + + //-------------------------------------------------------------------------- + // + // Element access (maps) + // + //-------------------------------------------------------------------------- + + template < + class K, + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if::type> + typename std::conditional::type& + at(K const& k); + + template < + class K, + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if::type> + typename std::conditional::type const& + at(K const& k) const; + + template < + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if::type> + typename std::conditional::type& + operator[](Key const& key); + + template < + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if::type> + typename std::conditional::type& + operator[](Key&& key); + + //-------------------------------------------------------------------------- + // + // Iterators + // + //-------------------------------------------------------------------------- + + iterator + begin() + { + return iterator(m_cont.begin()); + } + + const_iterator + begin() const + { + return const_iterator(m_cont.begin()); + } + + const_iterator + cbegin() const + { + return const_iterator(m_cont.begin()); + } + + iterator + end() + { + return iterator(m_cont.end()); + } + + const_iterator + end() const + { + return const_iterator(m_cont.end()); + } + + const_iterator + cend() const + { + return const_iterator(m_cont.end()); + } + + iterator + iterator_to(value_type& value) + { + static_assert( + std::is_standard_layout::value, "must be standard layout"); + return m_cont.iterator_to(*reinterpret_cast( + reinterpret_cast(&value) - + ((std::size_t)std::addressof(((element*)0)->member)))); + } + + const_iterator + iterator_to(value_type const& value) const + { + static_assert( + std::is_standard_layout::value, "must be standard layout"); + return m_cont.iterator_to(*reinterpret_cast( + reinterpret_cast(&value) - + ((std::size_t)std::addressof(((element*)0)->member)))); + } + + //-------------------------------------------------------------------------- + // + // Capacity + // + //-------------------------------------------------------------------------- + + bool + empty() const noexcept + { + return m_cont.empty(); + } + + size_type + size() const noexcept + { + return m_cont.size(); + } + + size_type + max_size() const noexcept + { + return m_config.max_size(); + } + + //-------------------------------------------------------------------------- + // + // Modifiers + // + //-------------------------------------------------------------------------- + + void + clear(); + + // map, set + template + auto + insert(value_type const& value) -> + typename std::enable_if>::type; + + // multimap, multiset + template + auto + insert(value_type const& value) -> + typename std::enable_if::type; + + // map, set + template + auto + insert(value_type&& value) -> typename std::enable_if< + !maybe_multi && !maybe_map, + std::pair>::type; + + // multimap, multiset + template + auto + insert(value_type&& value) -> + typename std::enable_if::type; + + // map, set + template + typename std::enable_if::type + insert(const_iterator /*hint*/, value_type const& value) + { + // Hint is ignored but we provide the interface so + // callers may use ordered and unordered interchangeably. + return insert(value).first; + } + + // multimap, multiset + template + typename std::enable_if::type + insert(const_iterator /*hint*/, value_type const& value) + { + // VFALCO TODO The hint could be used to let + // the client order equal ranges + return insert(value); + } + + // map, set + template + typename std::enable_if::type + insert(const_iterator /*hint*/, value_type&& value) + { + // Hint is ignored but we provide the interface so + // callers may use ordered and unordered interchangeably. + return insert(std::move(value)).first; + } + + // multimap, multiset + template + typename std::enable_if::type + insert(const_iterator /*hint*/, value_type&& value) + { + // VFALCO TODO The hint could be used to let + // the client order equal ranges + return insert(std::move(value)); + } + + // map, multimap + template + typename std::enable_if< + maybe_map && std::is_constructible::value, + typename std:: + conditional>::type>:: + type + insert(P&& value) + { + return emplace(std::forward

(value)); + } + + // map, multimap + template + typename std::enable_if< + maybe_map && std::is_constructible::value, + typename std:: + conditional>::type>:: + type + insert(const_iterator hint, P&& value) + { + return emplace_hint(hint, std::forward

(value)); + } + + template + void + insert(InputIt first, InputIt last) + { + insert( + first, + last, + typename std::iterator_traits::iterator_category()); + } + + void + insert(std::initializer_list init) + { + insert(init.begin(), init.end()); + } + + // set, map + template + auto + emplace(Args&&... args) -> + typename std::enable_if>::type; + + // multiset, multimap + template + auto + emplace(Args&&... args) -> + typename std::enable_if::type; + + // set, map + template + auto + emplace_hint(const_iterator /*hint*/, Args&&... args) -> + typename std::enable_if>::type; + + // multiset, multimap + template + typename std::enable_if::type + emplace_hint(const_iterator /*hint*/, Args&&... args) + { + // VFALCO TODO The hint could be used for multi, to let + // the client order equal ranges + return emplace(std::forward(args)...); + } + + template + beast::detail::aged_container_iterator + erase(beast::detail::aged_container_iterator pos); + + template + beast::detail::aged_container_iterator + erase( + beast::detail::aged_container_iterator first, + beast::detail::aged_container_iterator last); + + template + auto + erase(K const& k) -> size_type; + + void + swap(aged_unordered_container& other) noexcept; + + template + void + touch(beast::detail::aged_container_iterator pos) + { + touch(pos, clock().now()); + } + + template + auto + touch(K const& k) -> size_type; + + //-------------------------------------------------------------------------- + // + // Lookup + // + //-------------------------------------------------------------------------- + + // VFALCO TODO Respect is_transparent (c++14) + template + size_type + count(K const& k) const + { + return m_cont.count( + k, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal())); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + iterator + find(K const& k) + { + return iterator(m_cont.find( + k, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + const_iterator + find(K const& k) const + { + return const_iterator(m_cont.find( + k, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + std::pair + equal_range(K const& k) + { + auto const r(m_cont.equal_range( + k, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()))); + return std::make_pair(iterator(r.first), iterator(r.second)); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + std::pair + equal_range(K const& k) const + { + auto const r(m_cont.equal_range( + k, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()))); + return std::make_pair( + const_iterator(r.first), const_iterator(r.second)); + } + + //-------------------------------------------------------------------------- + // + // Bucket interface + // + //-------------------------------------------------------------------------- + + local_iterator + begin(size_type n) + { + return local_iterator(m_cont.begin(n)); + } + + const_local_iterator + begin(size_type n) const + { + return const_local_iterator(m_cont.begin(n)); + } + + const_local_iterator + cbegin(size_type n) const + { + return const_local_iterator(m_cont.begin(n)); + } + + local_iterator + end(size_type n) + { + return local_iterator(m_cont.end(n)); + } + + const_local_iterator + end(size_type n) const + { + return const_local_iterator(m_cont.end(n)); + } + + const_local_iterator + cend(size_type n) const + { + return const_local_iterator(m_cont.end(n)); + } + + size_type + bucket_count() const + { + return m_cont.bucket_count(); + } + + size_type + max_bucket_count() const + { + return m_buck.max_bucket_count(); + } + + size_type + bucket_size(size_type n) const + { + return m_cont.bucket_size(n); + } + + size_type + bucket(Key const& k) const + { + XRPL_ASSERT( + bucket_count() != 0, + "beast::detail::aged_unordered_container::bucket : nonzero bucket " + "count"); + return m_cont.bucket(k, std::cref(m_config.hash_function())); + } + + //-------------------------------------------------------------------------- + // + // Hash policy + // + //-------------------------------------------------------------------------- + + float + load_factor() const + { + return size() / static_cast(m_cont.bucket_count()); + } + + float + max_load_factor() const + { + return m_buck.max_load_factor(); + } + + void + max_load_factor(float ml) + { + m_buck.max_load_factor() = std::max(ml, m_buck.max_load_factor()); + } + + void + rehash(size_type count) + { + count = std::max(count, size_type(size() / max_load_factor())); + m_buck.rehash(count, m_cont); + } + + void + reserve(size_type count) + { + rehash(std::ceil(count / max_load_factor())); + } + + //-------------------------------------------------------------------------- + // + // Observers + // + //-------------------------------------------------------------------------- + + hasher const& + hash_function() const + { + return m_config.hash_function(); + } + + key_equal const& + key_eq() const + { + return m_config.key_eq(); + } + + //-------------------------------------------------------------------------- + // + // Comparison + // + //-------------------------------------------------------------------------- + + // This differs from the standard in that the comparison + // is only done on the key portion of the value type, ignoring + // the mapped type. + // + template < + bool OtherIsMap, + class OtherKey, + class OtherT, + class OtherDuration, + class OtherHash, + class OtherAllocator, + bool maybe_multi = IsMulti> + typename std::enable_if::type + operator==(aged_unordered_container< + false, + OtherIsMap, + OtherKey, + OtherT, + OtherDuration, + OtherHash, + KeyEqual, + OtherAllocator> const& other) const; + + template < + bool OtherIsMap, + class OtherKey, + class OtherT, + class OtherDuration, + class OtherHash, + class OtherAllocator, + bool maybe_multi = IsMulti> + typename std::enable_if::type + operator==(aged_unordered_container< + true, + OtherIsMap, + OtherKey, + OtherT, + OtherDuration, + OtherHash, + KeyEqual, + OtherAllocator> const& other) const; + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherKey, + class OtherT, + class OtherDuration, + class OtherHash, + class OtherAllocator> + bool + operator!=(aged_unordered_container< + OtherIsMulti, + OtherIsMap, + OtherKey, + OtherT, + OtherDuration, + OtherHash, + KeyEqual, + OtherAllocator> const& other) const + { + return !(this->operator==(other)); + } + +private: + bool + would_exceed(size_type additional) const + { + return size() + additional > bucket_count() * max_load_factor(); + } + + void + maybe_rehash(size_type additional) + { + if (would_exceed(additional)) + m_buck.resize(size() + additional, m_cont); + XRPL_ASSERT( + load_factor() <= max_load_factor(), + "beast::detail::aged_unordered_container::maybe_rehash : maximum " + "load factor"); + } + + // map, set + template + auto + insert_unchecked(value_type const& value) -> + typename std::enable_if>::type; + + // multimap, multiset + template + auto + insert_unchecked(value_type const& value) -> + typename std::enable_if::type; + + template + void + insert_unchecked(InputIt first, InputIt last) + { + for (; first != last; ++first) + insert_unchecked(*first); + } + + template + void + insert(InputIt first, InputIt last, std::input_iterator_tag) + { + for (; first != last; ++first) + insert(*first); + } + + template + void + insert(InputIt first, InputIt last, std::random_access_iterator_tag) + { + auto const n(std::distance(first, last)); + maybe_rehash(n); + insert_unchecked(first, last); + } + + template + void + touch( + beast::detail::aged_container_iterator pos, + typename clock_type::time_point const& now) + { + auto& e(*pos.iterator()); + e.when = now; + chronological.list.erase(chronological.list.iterator_to(e)); + chronological.list.push_back(e); + } + + template < + bool maybe_propagate = std::allocator_traits< + Allocator>::propagate_on_container_swap::value> + typename std::enable_if::type + swap_data(aged_unordered_container& other) noexcept + { + std::swap(m_config.key_compare(), other.m_config.key_compare()); + std::swap(m_config.alloc(), other.m_config.alloc()); + std::swap(m_config.clock, other.m_config.clock); + } + + template < + bool maybe_propagate = std::allocator_traits< + Allocator>::propagate_on_container_swap::value> + typename std::enable_if::type + swap_data(aged_unordered_container& other) noexcept + { + std::swap(m_config.key_compare(), other.m_config.key_compare()); + std::swap(m_config.clock, other.m_config.clock); + } + +private: + config_t m_config; + Buckets m_buck; + cont_type mutable m_cont; +}; + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::aged_unordered_container(clock_type& clock) + : m_config(clock) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::aged_unordered_container(clock_type& clock, Hash const& hash) + : m_config(clock, hash) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container(clock_type& clock, KeyEqual const& key_eq) + : m_config(clock, key_eq) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container(clock_type& clock, Allocator const& alloc) + : m_config(clock, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq) + : m_config(clock, hash, key_eq) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + clock_type& clock, + Hash const& hash, + Allocator const& alloc) + : m_config(clock, hash, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config(clock, key_eq, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config(clock, hash, key_eq, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container(InputIt first, InputIt last, clock_type& clock) + : m_config(clock) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash) + : m_config(clock, hash) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + KeyEqual const& key_eq) + : m_config(clock, key_eq) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Allocator const& alloc) + : m_config(clock, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq) + : m_config(clock, hash, key_eq) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash, + Allocator const& alloc) + : m_config(clock, hash, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config(clock, key_eq, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + InputIt first, + InputIt last, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config(clock, hash, key_eq, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(first, last); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::aged_unordered_container(aged_unordered_container const& other) + : m_config(other.m_config) + , m_buck(m_config.alloc()) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(other.cbegin(), other.cend()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + aged_unordered_container const& other, + Allocator const& alloc) + : m_config(other.m_config, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(other.cbegin(), other.cend()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::aged_unordered_container(aged_unordered_container&& other) + : m_config(std::move(other.m_config)) + , m_buck(std::move(other.m_buck)) + , m_cont(std::move(other.m_cont)) +{ + chronological.list = std::move(other.chronological.list); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + aged_unordered_container&& other, + Allocator const& alloc) + : m_config(std::move(other.m_config), alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(other.cbegin(), other.cend()); + other.clear(); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + std::initializer_list init, + clock_type& clock) + : m_config(clock) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash) + : m_config(clock, hash) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + KeyEqual const& key_eq) + : m_config(clock, key_eq) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Allocator const& alloc) + : m_config(clock, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq) + : m_config(clock, hash, key_eq) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash, + Allocator const& alloc) + : m_config(clock, hash, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config(clock, key_eq, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + aged_unordered_container( + std::initializer_list init, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config(clock, hash, key_eq, alloc) + , m_buck(alloc) + , m_cont( + m_buck, + std::cref(m_config.value_hash()), + std::cref(m_config.key_value_equal())) +{ + insert(init.begin(), init.end()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::~aged_unordered_container() +{ + clear(); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::operator=(aged_unordered_container const& other) + -> aged_unordered_container& +{ + if (this != &other) + { + size_type const n(other.size()); + clear(); + m_config = other.m_config; + m_buck = Buckets(m_config.alloc()); + maybe_rehash(n); + insert_unchecked(other.begin(), other.end()); + } + return *this; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::operator=(aged_unordered_container&& other) + -> aged_unordered_container& +{ + size_type const n(other.size()); + clear(); + m_config = std::move(other.m_config); + m_buck = Buckets(m_config.alloc()); + maybe_rehash(n); + insert_unchecked(other.begin(), other.end()); + other.clear(); + return *this; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::operator=(std::initializer_list init) + -> aged_unordered_container& +{ + clear(); + insert(init); + return *this; +} + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +typename std::conditional::type& +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::at(K const& k) +{ + auto const iter(m_cont.find( + k, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()))); + if (iter == m_cont.end()) + throw std::out_of_range("key not found"); + return iter->value.second; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +typename std::conditional::type const& +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::at(K const& k) const +{ + auto const iter(m_cont.find( + k, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()))); + if (iter == m_cont.end()) + throw std::out_of_range("key not found"); + return iter->value.second; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +typename std::conditional::type& +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::operator[](Key const& key) +{ + maybe_rehash(1); + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + key, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()), + d)); + if (result.second) + { + element* const p(new_element( + std::piecewise_construct, + std::forward_as_tuple(key), + std::forward_as_tuple())); + m_cont.insert_commit(*p, d); + chronological.list.push_back(*p); + return p->value.second; + } + return result.first->value.second; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +typename std::conditional::type& +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::operator[](Key&& key) +{ + maybe_rehash(1); + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + key, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()), + d)); + if (result.second) + { + element* const p(new_element( + std::piecewise_construct, + std::forward_as_tuple(std::move(key)), + std::forward_as_tuple())); + m_cont.insert_commit(*p, d); + chronological.list.push_back(*p); + return p->value.second; + } + return result.first->value.second; +} + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +void +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::clear() +{ + for (auto iter(chronological.list.begin()); + iter != chronological.list.end();) + unlink_and_delete_element(&*iter++); + chronological.list.clear(); + m_cont.clear(); + m_buck.clear(); +} + +// map, set +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::insert(value_type const& value) -> + typename std::enable_if>::type +{ + maybe_rehash(1); + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + extract(value), + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()), + d)); + if (result.second) + { + element* const p(new_element(value)); + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return std::make_pair(iterator(iter), true); + } + return std::make_pair(iterator(result.first), false); +} + +// multimap, multiset +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::insert(value_type const& value) -> + typename std::enable_if::type +{ + maybe_rehash(1); + element* const p(new_element(value)); + chronological.list.push_back(*p); + auto const iter(m_cont.insert(*p)); + return iterator(iter); +} + +// map, set +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::insert(value_type&& value) -> + typename std:: + enable_if>::type +{ + maybe_rehash(1); + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + extract(value), + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()), + d)); + if (result.second) + { + element* const p(new_element(std::move(value))); + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return std::make_pair(iterator(iter), true); + } + return std::make_pair(iterator(result.first), false); +} + +// multimap, multiset +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::insert(value_type&& value) -> + typename std::enable_if::type +{ + maybe_rehash(1); + element* const p(new_element(std::move(value))); + chronological.list.push_back(*p); + auto const iter(m_cont.insert(*p)); + return iterator(iter); +} + +#if 1 // Use insert() instead of insert_check() insert_commit() +// set, map +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::emplace(Args&&... args) -> + typename std::enable_if>::type +{ + maybe_rehash(1); + // VFALCO NOTE Its unfortunate that we need to + // construct element here + element* const p(new_element(std::forward(args)...)); + auto const result(m_cont.insert(*p)); + if (result.second) + { + chronological.list.push_back(*p); + return std::make_pair(iterator(result.first), true); + } + delete_element(p); + return std::make_pair(iterator(result.first), false); +} +#else // As original, use insert_check() / insert_commit () pair. +// set, map +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::emplace(Args&&... args) -> + typename std::enable_if>::type +{ + maybe_rehash(1); + // VFALCO NOTE Its unfortunate that we need to + // construct element here + element* const p(new_element(std::forward(args)...)); + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + extract(p->value), + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()), + d)); + if (result.second) + { + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return std::make_pair(iterator(iter), true); + } + delete_element(p); + return std::make_pair(iterator(result.first), false); +} +#endif // 0 + +// multiset, multimap +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::emplace(Args&&... args) -> + typename std::enable_if::type +{ + maybe_rehash(1); + element* const p(new_element(std::forward(args)...)); + chronological.list.push_back(*p); + auto const iter(m_cont.insert(*p)); + return iterator(iter); +} + +// set, map +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::emplace_hint(const_iterator /*hint*/, Args&&... args) -> + typename std::enable_if>::type +{ + maybe_rehash(1); + // VFALCO NOTE Its unfortunate that we need to + // construct element here + element* const p(new_element(std::forward(args)...)); + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + extract(p->value), + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()), + d)); + if (result.second) + { + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return std::make_pair(iterator(iter), true); + } + delete_element(p); + return std::make_pair(iterator(result.first), false); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +beast::detail::aged_container_iterator +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::erase(beast::detail::aged_container_iterator + pos) +{ + unlink_and_delete_element(&*((pos++).iterator())); + return beast::detail::aged_container_iterator( + pos.iterator()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +beast::detail::aged_container_iterator +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: + erase( + beast::detail::aged_container_iterator first, + beast::detail::aged_container_iterator last) +{ + for (; first != last;) + unlink_and_delete_element(&*((first++).iterator())); + + return beast::detail::aged_container_iterator( + first.iterator()); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::erase(K const& k) -> size_type +{ + auto iter(m_cont.find( + k, + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()))); + if (iter == m_cont.end()) + return 0; + size_type n(0); + for (;;) + { + auto p(&*iter++); + bool const done(m_config(*p, extract(iter->value))); + unlink_and_delete_element(p); + ++n; + if (done) + break; + } + return n; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +void +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::swap(aged_unordered_container& other) noexcept +{ + swap_data(other); + std::swap(chronological, other.chronological); + std::swap(m_cont, other.m_cont); +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::touch(K const& k) -> size_type +{ + auto const now(clock().now()); + size_type n(0); + auto const range(equal_range(k)); + for (auto iter : range) + { + touch(iter, now); + ++n; + } + return n; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template < + bool OtherIsMap, + class OtherKey, + class OtherT, + class OtherDuration, + class OtherHash, + class OtherAllocator, + bool maybe_multi> +typename std::enable_if::type +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: +operator==(aged_unordered_container< + false, + OtherIsMap, + OtherKey, + OtherT, + OtherDuration, + OtherHash, + KeyEqual, + OtherAllocator> const& other) const +{ + if (size() != other.size()) + return false; + for (auto iter(cbegin()), last(cend()), olast(other.cend()); iter != last; + ++iter) + { + auto oiter(other.find(extract(*iter))); + if (oiter == olast) + return false; + } + return true; +} + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template < + bool OtherIsMap, + class OtherKey, + class OtherT, + class OtherDuration, + class OtherHash, + class OtherAllocator, + bool maybe_multi> +typename std::enable_if::type +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>:: +operator==(aged_unordered_container< + true, + OtherIsMap, + OtherKey, + OtherT, + OtherDuration, + OtherHash, + KeyEqual, + OtherAllocator> const& other) const +{ + if (size() != other.size()) + return false; + using EqRng = std::pair; + for (auto iter(cbegin()), last(cend()); iter != last;) + { + auto const& k(extract(*iter)); + auto const eq(equal_range(k)); + auto const oeq(other.equal_range(k)); +#if BEAST_NO_CXX14_IS_PERMUTATION + if (std::distance(eq.first, eq.second) != + std::distance(oeq.first, oeq.second) || + !std::is_permutation(eq.first, eq.second, oeq.first)) + return false; +#else + if (!std::is_permutation(eq.first, eq.second, oeq.first, oeq.second)) + return false; +#endif + iter = eq.second; + } + return true; +} + +//------------------------------------------------------------------------------ + +// map, set +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::insert_unchecked(value_type const& value) -> + typename std::enable_if>::type +{ + typename cont_type::insert_commit_data d; + auto const result(m_cont.insert_check( + extract(value), + std::cref(m_config.hash_function()), + std::cref(m_config.key_value_equal()), + d)); + if (result.second) + { + element* const p(new_element(value)); + auto const iter(m_cont.insert_commit(*p, d)); + chronological.list.push_back(*p); + return std::make_pair(iterator(iter), true); + } + return std::make_pair(iterator(result.first), false); +} + +// multimap, multiset +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +template +auto +aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>::insert_unchecked(value_type const& value) -> + typename std::enable_if::type +{ + element* const p(new_element(value)); + chronological.list.push_back(*p); + auto const iter(m_cont.insert(*p)); + return iterator(iter); +} + +//------------------------------------------------------------------------------ + +} // namespace detail + +//------------------------------------------------------------------------------ + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +struct is_aged_container> : std::true_type +{ + explicit is_aged_container() = default; +}; + +// Free functions + +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator> +void +swap( + beast::detail::aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>& lhs, + beast::detail::aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>& rhs) noexcept +{ + lhs.swap(rhs); +} + +/** Expire aged container items past the specified age. */ +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Clock, + class Hash, + class KeyEqual, + class Allocator, + class Rep, + class Period> +std::size_t +expire( + beast::detail::aged_unordered_container< + IsMulti, + IsMap, + Key, + T, + Clock, + Hash, + KeyEqual, + Allocator>& c, + std::chrono::duration const& age) noexcept +{ + std::size_t n(0); + auto const expired(c.clock().now() - age); + for (auto iter(c.chronological.cbegin()); + iter != c.chronological.cend() && iter.when() <= expired;) + { + iter = c.erase(iter); + ++n; + } + return n; +} + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/container/detail/empty_base_optimization.h b/include/xrpl/beast/container/detail/empty_base_optimization.h new file mode 100644 index 00000000000..350046d5940 --- /dev/null +++ b/include/xrpl/beast/container/detail/empty_base_optimization.h @@ -0,0 +1,101 @@ +// +// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BEAST_CONTAINER_DETAIL_EMPTY_BASE_OPTIMIZATION_H_INCLUDED +#define BEAST_CONTAINER_DETAIL_EMPTY_BASE_OPTIMIZATION_H_INCLUDED + +#include + +#include +#include + +namespace beast { +namespace detail { + +template +struct is_empty_base_optimization_derived + : std::integral_constant< + bool, + std::is_empty::value && !boost::is_final::value> +{ +}; + +template < + class T, + int UniqueID = 0, + bool isDerived = is_empty_base_optimization_derived::value> +class empty_base_optimization : private T +{ +public: + empty_base_optimization() = default; + empty_base_optimization(empty_base_optimization&&) = default; + empty_base_optimization(empty_base_optimization const&) = default; + empty_base_optimization& + operator=(empty_base_optimization&&) = default; + empty_base_optimization& + operator=(empty_base_optimization const&) = default; + + template + explicit empty_base_optimization(Arg1&& arg1, ArgN&&... argn) + : T(std::forward(arg1), std::forward(argn)...) + { + } + + T& + member() noexcept + { + return *this; + } + + T const& + member() const noexcept + { + return *this; + } +}; + +//------------------------------------------------------------------------------ + +template +class empty_base_optimization +{ + T t_; + +public: + empty_base_optimization() = default; + empty_base_optimization(empty_base_optimization&&) = default; + empty_base_optimization(empty_base_optimization const&) = default; + empty_base_optimization& + operator=(empty_base_optimization&&) = default; + empty_base_optimization& + operator=(empty_base_optimization const&) = default; + + template + explicit empty_base_optimization(Arg1&& arg1, ArgN&&... argn) + : t_(std::forward(arg1), std::forward(argn)...) + { + } + + T& + member() noexcept + { + return t_; + } + + T const& + member() const noexcept + { + return t_; + } +}; + +} // namespace detail +} // namespace beast + +#endif diff --git a/src/ripple/beast/core/CurrentThreadName.h b/include/xrpl/beast/core/CurrentThreadName.h similarity index 93% rename from src/ripple/beast/core/CurrentThreadName.h rename to include/xrpl/beast/core/CurrentThreadName.h index be9bb692859..5adbb210880 100644 --- a/src/ripple/beast/core/CurrentThreadName.h +++ b/include/xrpl/beast/core/CurrentThreadName.h @@ -24,15 +24,16 @@ #ifndef BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED #define BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED -#include #include +#include namespace beast { /** Changes the name of the caller thread. Different OSes may place different length or content limits on this name. */ -void setCurrentThreadName (std::string_view newThreadName); +void +setCurrentThreadName(std::string_view newThreadName); /** Returns the name of the caller thread. @@ -42,8 +43,9 @@ void setCurrentThreadName (std::string_view newThreadName); If no name has ever been set, then the empty string is returned. */ -std::string getCurrentThreadName (); +std::string +getCurrentThreadName(); -} +} // namespace beast #endif diff --git a/include/xrpl/beast/core/LexicalCast.h b/include/xrpl/beast/core/LexicalCast.h new file mode 100644 index 00000000000..aa67bcad50f --- /dev/null +++ b/include/xrpl/beast/core/LexicalCast.h @@ -0,0 +1,240 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED +#define BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { + +namespace detail { + +// These specializatons get called by the non-member functions to do the work +template +struct LexicalCast; + +// conversion to std::string +template +struct LexicalCast +{ + explicit LexicalCast() = default; + + template + std::enable_if_t, bool> + operator()(std::string& out, Arithmetic in) + { + out = std::to_string(in); + return true; + } + + template + std::enable_if_t, bool> + operator()(std::string& out, Enumeration in) + { + out = std::to_string( + static_cast>(in)); + return true; + } +}; + +// Parse a std::string_view into a number +template +struct LexicalCast +{ + explicit LexicalCast() = default; + + static_assert( + std::is_integral_v, + "beast::LexicalCast can only be used with integral types"); + + template + std::enable_if_t< + std::is_integral_v && !std::is_same_v, + bool> + operator()(Integral& out, std::string_view in) const + { + auto first = in.data(); + auto last = in.data() + in.size(); + + if (first != last && *first == '+') + ++first; + + auto ret = std::from_chars(first, last, out); + + return ret.ec == std::errc() && ret.ptr == last; + } + + bool + operator()(bool& out, std::string_view in) const + { + std::string result; + + // Convert the input to lowercase + std::transform( + in.begin(), in.end(), std::back_inserter(result), [](auto c) { + return std::tolower(static_cast(c)); + }); + + if (result == "1" || result == "true") + { + out = true; + return true; + } + + if (result == "0" || result == "false") + { + out = false; + return true; + } + + return false; + } +}; +//------------------------------------------------------------------------------ + +// Parse boost library's string_view to number or boolean value +// Note: As of Jan 2024, Boost contains three different types of string_view +// (boost::core::basic_string_view, boost::string_ref and +// boost::string_view). The below template specialization is included because +// it is used in the handshake.cpp file +template +struct LexicalCast> +{ + explicit LexicalCast() = default; + + bool + operator()(Out& out, boost::core::basic_string_view in) const + { + return LexicalCast()(out, in); + } +}; + +// Parse std::string to number or boolean value +template +struct LexicalCast +{ + explicit LexicalCast() = default; + + bool + operator()(Out& out, std::string in) const + { + return LexicalCast()(out, in); + } +}; + +// Conversion from null terminated char const* +template +struct LexicalCast +{ + explicit LexicalCast() = default; + + bool + operator()(Out& out, char const* in) const + { + XRPL_ASSERT( + in, "beast::detail::LexicalCast(char const*) : non-null input"); + return LexicalCast()(out, in); + } +}; + +// Conversion from null terminated char* +// The string is not modified. +template +struct LexicalCast +{ + explicit LexicalCast() = default; + + bool + operator()(Out& out, char* in) const + { + XRPL_ASSERT(in, "beast::detail::LexicalCast(char*) : non-null input"); + return LexicalCast()(out, in); + } +}; + +} // namespace detail + +//------------------------------------------------------------------------------ + +/** Thrown when a conversion is not possible with LexicalCast. + Only used in the throw variants of lexicalCast. +*/ +struct BadLexicalCast : public std::bad_cast +{ + explicit BadLexicalCast() = default; +}; + +/** Intelligently convert from one type to another. + @return `false` if there was a parsing or range error +*/ +template +bool +lexicalCastChecked(Out& out, In in) +{ + return detail::LexicalCast()(out, in); +} + +/** Convert from one type to another, throw on error + + An exception of type BadLexicalCast is thrown if the conversion fails. + + @return The new type. +*/ +template +Out +lexicalCastThrow(In in) +{ + if (Out out; lexicalCastChecked(out, in)) + return out; + + throw BadLexicalCast(); +} + +/** Convert from one type to another. + + @param defaultValue The value returned if parsing fails + @return The new type. +*/ +template +Out +lexicalCast(In in, Out defaultValue = Out()) +{ + if (Out out; lexicalCastChecked(out, in)) + return out; + + return defaultValue; +} + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/core/List.h b/include/xrpl/beast/core/List.h new file mode 100644 index 00000000000..d95f92d1c8e --- /dev/null +++ b/include/xrpl/beast/core/List.h @@ -0,0 +1,598 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INTRUSIVE_LIST_H_INCLUDED +#define BEAST_INTRUSIVE_LIST_H_INCLUDED + +#include + +namespace beast { + +template +class List; + +namespace detail { + +/** Copy `const` attribute from T to U if present. */ +/** @{ */ +template +struct CopyConst +{ + explicit CopyConst() = default; + + using type = typename std::remove_const::type; +}; + +template +struct CopyConst +{ + explicit CopyConst() = default; + + using type = typename std::remove_const::type const; +}; +/** @} */ + +// This is the intrusive portion of the doubly linked list. +// One derivation per list that the object may appear on +// concurrently is required. +// +template +class ListNode +{ +private: + using value_type = T; + + friend class List; + + template + friend class ListIterator; + + ListNode* m_next; + ListNode* m_prev; +}; + +//------------------------------------------------------------------------------ + +template +class ListIterator +{ +public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = + typename beast::detail::CopyConst::type; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + using size_type = std::size_t; + + ListIterator(N* node = nullptr) noexcept : m_node(node) + { + } + + template + ListIterator(ListIterator const& other) noexcept : m_node(other.m_node) + { + } + + template + bool + operator==(ListIterator const& other) const noexcept + { + return m_node == other.m_node; + } + + template + bool + operator!=(ListIterator const& other) const noexcept + { + return !((*this) == other); + } + + reference + operator*() const noexcept + { + return dereference(); + } + + pointer + operator->() const noexcept + { + return &dereference(); + } + + ListIterator& + operator++() noexcept + { + increment(); + return *this; + } + + ListIterator + operator++(int) noexcept + { + ListIterator result(*this); + increment(); + return result; + } + + ListIterator& + operator--() noexcept + { + decrement(); + return *this; + } + + ListIterator + operator--(int) noexcept + { + ListIterator result(*this); + decrement(); + return result; + } + +private: + reference + dereference() const noexcept + { + return static_cast(*m_node); + } + + void + increment() noexcept + { + m_node = m_node->m_next; + } + + void + decrement() noexcept + { + m_node = m_node->m_prev; + } + + N* m_node; +}; + +} // namespace detail + +/** Intrusive doubly linked list. + + This intrusive List is a container similar in operation to std::list in the + Standard Template Library (STL). Like all @ref intrusive containers, List + requires you to first derive your class from List<>::Node: + + @code + + struct Object : List ::Node + { + explicit Object (int value) : m_value (value) + { + } + + int m_value; + }; + + @endcode + + Now we define the list, and add a couple of items. + + @code + + List list; + + list.push_back (* (new Object (1))); + list.push_back (* (new Object (2))); + + @endcode + + For compatibility with the standard containers, push_back() expects a + reference to the object. Unlike the standard container, however, push_back() + places the actual object in the list and not a copy-constructed duplicate. + + Iterating over the list follows the same idiom as the STL: + + @code + + for (List ::iterator iter = list.begin(); iter != list.end; ++iter) + std::cout << iter->m_value; + + @endcode + + You can even use BOOST_FOREACH, or range based for loops: + + @code + + BOOST_FOREACH (Object& object, list) // boost only + std::cout << object.m_value; + + for (Object& object : list) // C++11 only + std::cout << object.m_value; + + @endcode + + Because List is mostly STL compliant, it can be passed into STL algorithms: + e.g. `std::for_each()` or `std::find_first_of()`. + + In general, objects placed into a List should be dynamically allocated + although this cannot be enforced at compile time. Since the caller provides + the storage for the object, the caller is also responsible for deleting the + object. An object still exists after being removed from a List, until the + caller deletes it. This means an element can be moved from one List to + another with practically no overhead. + + Unlike the standard containers, an object may only exist in one list at a + time, unless special preparations are made. The Tag template parameter is + used to distinguish between different list types for the same object, + allowing the object to exist in more than one list simultaneously. + + For example, consider an actor system where a global list of actors is + maintained, so that they can each be periodically receive processing + time. We wish to also maintain a list of the subset of actors that require + a domain-dependent update. To achieve this, we declare two tags, the + associated list types, and the list element thusly: + + @code + + struct Actor; // Forward declaration required + + struct ProcessTag { }; + struct UpdateTag { }; + + using ProcessList = List ; + using UpdateList = List ; + + // Derive from both node types so we can be in each list at once. + // + struct Actor : ProcessList::Node, UpdateList::Node + { + bool process (); // returns true if we need an update + void update (); + }; + + @endcode + + @tparam T The base type of element which the list will store + pointers to. + + @tparam Tag An optional unique type name used to distinguish lists and + nodes, when the object can exist in multiple lists simultaneously. + + @ingroup beast_core intrusive +*/ +template +class List +{ +public: + using Node = typename detail::ListNode; + + using value_type = T; + using pointer = value_type*; + using reference = value_type&; + using const_pointer = value_type const*; + using const_reference = value_type const&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterator = detail::ListIterator; + using const_iterator = detail::ListIterator; + + /** Create an empty list. */ + List() + { + m_head.m_prev = nullptr; // identifies the head + m_tail.m_next = nullptr; // identifies the tail + clear(); + } + + List(List const&) = delete; + List& + operator=(List const&) = delete; + + /** Determine if the list is empty. + @return `true` if the list is empty. + */ + bool + empty() const noexcept + { + return size() == 0; + } + + /** Returns the number of elements in the list. */ + size_type + size() const noexcept + { + return m_size; + } + + /** Obtain a reference to the first element. + @invariant The list may not be empty. + @return A reference to the first element. + */ + reference + front() noexcept + { + return element_from(m_head.m_next); + } + + /** Obtain a const reference to the first element. + @invariant The list may not be empty. + @return A const reference to the first element. + */ + const_reference + front() const noexcept + { + return element_from(m_head.m_next); + } + + /** Obtain a reference to the last element. + @invariant The list may not be empty. + @return A reference to the last element. + */ + reference + back() noexcept + { + return element_from(m_tail.m_prev); + } + + /** Obtain a const reference to the last element. + @invariant The list may not be empty. + @return A const reference to the last element. + */ + const_reference + back() const noexcept + { + return element_from(m_tail.m_prev); + } + + /** Obtain an iterator to the beginning of the list. + @return An iterator pointing to the beginning of the list. + */ + iterator + begin() noexcept + { + return iterator(m_head.m_next); + } + + /** Obtain a const iterator to the beginning of the list. + @return A const iterator pointing to the beginning of the list. + */ + const_iterator + begin() const noexcept + { + return const_iterator(m_head.m_next); + } + + /** Obtain a const iterator to the beginning of the list. + @return A const iterator pointing to the beginning of the list. + */ + const_iterator + cbegin() const noexcept + { + return const_iterator(m_head.m_next); + } + + /** Obtain a iterator to the end of the list. + @return An iterator pointing to the end of the list. + */ + iterator + end() noexcept + { + return iterator(&m_tail); + } + + /** Obtain a const iterator to the end of the list. + @return A constiterator pointing to the end of the list. + */ + const_iterator + end() const noexcept + { + return const_iterator(&m_tail); + } + + /** Obtain a const iterator to the end of the list + @return A constiterator pointing to the end of the list. + */ + const_iterator + cend() const noexcept + { + return const_iterator(&m_tail); + } + + /** Clear the list. + @note This does not free the elements. + */ + void + clear() noexcept + { + m_head.m_next = &m_tail; + m_tail.m_prev = &m_head; + m_size = 0; + } + + /** Insert an element. + @invariant The element must not already be in the list. + @param pos The location to insert after. + @param element The element to insert. + @return An iterator pointing to the newly inserted element. + */ + iterator + insert(iterator pos, T& element) noexcept + { + Node* node = static_cast(&element); + node->m_next = &*pos; + node->m_prev = node->m_next->m_prev; + node->m_next->m_prev = node; + node->m_prev->m_next = node; + ++m_size; + return iterator(node); + } + + /** Insert another list into this one. + The other list is cleared. + @param pos The location to insert after. + @param other The list to insert. + */ + void + insert(iterator pos, List& other) noexcept + { + if (!other.empty()) + { + Node* before = &*pos; + other.m_head.m_next->m_prev = before->m_prev; + before->m_prev->m_next = other.m_head.m_next; + other.m_tail.m_prev->m_next = before; + before->m_prev = other.m_tail.m_prev; + m_size += other.m_size; + other.clear(); + } + } + + /** Remove an element. + @invariant The element must exist in the list. + @param pos An iterator pointing to the element to remove. + @return An iterator pointing to the next element after the one removed. + */ + iterator + erase(iterator pos) noexcept + { + Node* node = &*pos; + ++pos; + node->m_next->m_prev = node->m_prev; + node->m_prev->m_next = node->m_next; + --m_size; + return pos; + } + + /** Insert an element at the beginning of the list. + @invariant The element must not exist in the list. + @param element The element to insert. + */ + iterator + push_front(T& element) noexcept + { + return insert(begin(), element); + } + + /** Remove the element at the beginning of the list. + @invariant The list must not be empty. + @return A reference to the popped element. + */ + T& + pop_front() noexcept + { + T& element(front()); + erase(begin()); + return element; + } + + /** Append an element at the end of the list. + @invariant The element must not exist in the list. + @param element The element to append. + */ + iterator + push_back(T& element) noexcept + { + return insert(end(), element); + } + + /** Remove the element at the end of the list. + @invariant The list must not be empty. + @return A reference to the popped element. + */ + T& + pop_back() noexcept + { + T& element(back()); + erase(--end()); + return element; + } + + /** Swap contents with another list. */ + void + swap(List& other) noexcept + { + List temp; + temp.append(other); + other.append(*this); + append(temp); + } + + /** Insert another list at the beginning of this list. + The other list is cleared. + @param list The other list to insert. + */ + iterator + prepend(List& list) noexcept + { + return insert(begin(), list); + } + + /** Append another list at the end of this list. + The other list is cleared. + @param list the other list to append. + */ + iterator + append(List& list) noexcept + { + return insert(end(), list); + } + + /** Obtain an iterator from an element. + @invariant The element must exist in the list. + @param element The element to obtain an iterator for. + @return An iterator to the element. + */ + iterator + iterator_to(T& element) const noexcept + { + return iterator(static_cast(&element)); + } + + /** Obtain a const iterator from an element. + @invariant The element must exist in the list. + @param element The element to obtain an iterator for. + @return A const iterator to the element. + */ + const_iterator + const_iterator_to(T const& element) const noexcept + { + return const_iterator(static_cast(&element)); + } + +private: + reference + element_from(Node* node) noexcept + { + return *(static_cast(node)); + } + + const_reference + element_from(Node const* node) const noexcept + { + return *(static_cast(node)); + } + +private: + size_type m_size; + Node m_head; + Node m_tail; +}; + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/core/LockFreeStack.h b/include/xrpl/beast/core/LockFreeStack.h new file mode 100644 index 00000000000..107564415cd --- /dev/null +++ b/include/xrpl/beast/core/LockFreeStack.h @@ -0,0 +1,307 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INTRUSIVE_LOCKFREESTACK_H_INCLUDED +#define BEAST_INTRUSIVE_LOCKFREESTACK_H_INCLUDED + +#include +#include +#include + +namespace beast { + +//------------------------------------------------------------------------------ + +template +class LockFreeStackIterator +{ +protected: + using Node = typename Container::Node; + using NodePtr = + typename std::conditional::type; + +public: + using iterator_category = std::forward_iterator_tag; + using value_type = typename Container::value_type; + using difference_type = typename Container::difference_type; + using pointer = typename std::conditional< + IsConst, + typename Container::const_pointer, + typename Container::pointer>::type; + using reference = typename std::conditional< + IsConst, + typename Container::const_reference, + typename Container::reference>::type; + + LockFreeStackIterator() : m_node() + { + } + + LockFreeStackIterator(NodePtr node) : m_node(node) + { + } + + template + explicit LockFreeStackIterator( + LockFreeStackIterator const& other) + : m_node(other.m_node) + { + } + + LockFreeStackIterator& + operator=(NodePtr node) + { + m_node = node; + return static_cast(*this); + } + + LockFreeStackIterator& + operator++() + { + m_node = m_node->m_next.load(); + return static_cast(*this); + } + + LockFreeStackIterator + operator++(int) + { + LockFreeStackIterator result(*this); + m_node = m_node->m_next; + return result; + } + + NodePtr + node() const + { + return m_node; + } + + reference + operator*() const + { + return *this->operator->(); + } + + pointer + operator->() const + { + return static_cast(m_node); + } + +private: + NodePtr m_node; +}; + +//------------------------------------------------------------------------------ + +template +bool +operator==( + LockFreeStackIterator const& lhs, + LockFreeStackIterator const& rhs) +{ + return lhs.node() == rhs.node(); +} + +template +bool +operator!=( + LockFreeStackIterator const& lhs, + LockFreeStackIterator const& rhs) +{ + return lhs.node() != rhs.node(); +} + +//------------------------------------------------------------------------------ + +/** Multiple Producer, Multiple Consumer (MPMC) intrusive stack. + + This stack is implemented using the same intrusive interface as List. + All mutations are lock-free. + + The caller is responsible for preventing the "ABA" problem: + http://en.wikipedia.org/wiki/ABA_problem + + @param Tag A type name used to distinguish lists and nodes, for + putting objects in multiple lists. If this parameter is + omitted, the default tag is used. +*/ +template +class LockFreeStack +{ +public: + class Node + { + public: + Node() : m_next(nullptr) + { + } + + explicit Node(Node* next) : m_next(next) + { + } + + Node(Node const&) = delete; + Node& + operator=(Node const&) = delete; + + private: + friend class LockFreeStack; + + template + friend class LockFreeStackIterator; + + std::atomic m_next; + }; + +public: + using value_type = Element; + using pointer = Element*; + using reference = Element&; + using const_pointer = Element const*; + using const_reference = Element const&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using iterator = LockFreeStackIterator, false>; + using const_iterator = + LockFreeStackIterator, true>; + + LockFreeStack() : m_end(nullptr), m_head(&m_end) + { + } + + LockFreeStack(LockFreeStack const&) = delete; + LockFreeStack& + operator=(LockFreeStack const&) = delete; + + /** Returns true if the stack is empty. */ + bool + empty() const + { + return m_head.load() == &m_end; + } + + /** Push a node onto the stack. + The caller is responsible for preventing the ABA problem. + This operation is lock-free. + Thread safety: + Safe to call from any thread. + + @param node The node to push. + + @return `true` if the stack was previously empty. If multiple threads + are attempting to push, only one will receive `true`. + */ + // VFALCO NOTE Fix this, shouldn't it be a reference like intrusive list? + bool + push_front(Node* node) + { + bool first; + Node* old_head = m_head.load(std::memory_order_relaxed); + do + { + first = (old_head == &m_end); + node->m_next = old_head; + } while (!m_head.compare_exchange_strong( + old_head, + node, + std::memory_order_release, + std::memory_order_relaxed)); + return first; + } + + /** Pop an element off the stack. + The caller is responsible for preventing the ABA problem. + This operation is lock-free. + Thread safety: + Safe to call from any thread. + + @return The element that was popped, or `nullptr` if the stack + was empty. + */ + Element* + pop_front() + { + Node* node = m_head.load(); + Node* new_head; + do + { + if (node == &m_end) + return nullptr; + new_head = node->m_next.load(); + } while (!m_head.compare_exchange_strong( + node, + new_head, + std::memory_order_release, + std::memory_order_relaxed)); + return static_cast(node); + } + + /** Return a forward iterator to the beginning or end of the stack. + Undefined behavior results if push_front or pop_front is called + while an iteration is in progress. + Thread safety: + Caller is responsible for synchronization. + */ + /** @{ */ + iterator + begin() + { + return iterator(m_head.load()); + } + + iterator + end() + { + return iterator(&m_end); + } + + const_iterator + begin() const + { + return const_iterator(m_head.load()); + } + + const_iterator + end() const + { + return const_iterator(&m_end); + } + + const_iterator + cbegin() const + { + return const_iterator(m_head.load()); + } + + const_iterator + cend() const + { + return const_iterator(&m_end); + } + /** @} */ + +private: + Node m_end; + std::atomic m_head; +}; + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/core/SemanticVersion.h b/include/xrpl/beast/core/SemanticVersion.h new file mode 100644 index 00000000000..5fe216f1ab7 --- /dev/null +++ b/include/xrpl/beast/core/SemanticVersion.h @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_MODULE_CORE_DIAGNOSTIC_SEMANTICVERSION_H_INCLUDED +#define BEAST_MODULE_CORE_DIAGNOSTIC_SEMANTICVERSION_H_INCLUDED + +#include +#include + +namespace beast { + +/** A Semantic Version number. + + Identifies the build of a particular version of software using + the Semantic Versioning Specification described here: + + http://semver.org/ +*/ +class SemanticVersion +{ +public: + using identifier_list = std::vector; + + int majorVersion; + int minorVersion; + int patchVersion; + + identifier_list preReleaseIdentifiers; + identifier_list metaData; + + SemanticVersion(); + + SemanticVersion(std::string const& version); + + /** Parse a semantic version string. + The parsing is as strict as possible. + @return `true` if the string was parsed. + */ + bool + parse(std::string const& input); + + /** Produce a string from semantic version components. */ + std::string + print() const; + + inline bool + isRelease() const noexcept + { + return preReleaseIdentifiers.empty(); + } + inline bool + isPreRelease() const noexcept + { + return !isRelease(); + } +}; + +/** Compare two SemanticVersions against each other. + The comparison follows the rules as per the specification. +*/ +int +compare(SemanticVersion const& lhs, SemanticVersion const& rhs); + +inline bool +operator==(SemanticVersion const& lhs, SemanticVersion const& rhs) +{ + return compare(lhs, rhs) == 0; +} + +inline bool +operator!=(SemanticVersion const& lhs, SemanticVersion const& rhs) +{ + return compare(lhs, rhs) != 0; +} + +inline bool +operator>=(SemanticVersion const& lhs, SemanticVersion const& rhs) +{ + return compare(lhs, rhs) >= 0; +} + +inline bool +operator<=(SemanticVersion const& lhs, SemanticVersion const& rhs) +{ + return compare(lhs, rhs) <= 0; +} + +inline bool +operator>(SemanticVersion const& lhs, SemanticVersion const& rhs) +{ + return compare(lhs, rhs) > 0; +} + +inline bool +operator<(SemanticVersion const& lhs, SemanticVersion const& rhs) +{ + return compare(lhs, rhs) < 0; +} + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/hash/hash_append.h b/include/xrpl/beast/hash/hash_append.h new file mode 100644 index 00000000000..6b11fe1eb32 --- /dev/null +++ b/include/xrpl/beast/hash/hash_append.h @@ -0,0 +1,506 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2014, Howard Hinnant , + Vinnie Falco +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { + +namespace detail { + +template +/*constexpr*/ +inline void +reverse_bytes(T& t) +{ + unsigned char* bytes = static_cast( + std::memmove(std::addressof(t), std::addressof(t), sizeof(T))); + for (unsigned i = 0; i < sizeof(T) / 2; ++i) + std::swap(bytes[i], bytes[sizeof(T) - 1 - i]); +} + +template +/*constexpr*/ +inline void +maybe_reverse_bytes(T& t, std::false_type) +{ +} + +template +/*constexpr*/ +inline void +maybe_reverse_bytes(T& t, std::true_type) +{ + reverse_bytes(t); +} + +template +/*constexpr*/ +inline void +maybe_reverse_bytes(T& t, Hasher&) +{ + maybe_reverse_bytes( + t, + std::integral_constant< + bool, + Hasher::endian != boost::endian::order::native>{}); +} + +} // namespace detail + +// is_uniquely_represented + +// A type T is contiguously hashable if for all combinations of two values of +// a type, say x and y, if x == y, then it must also be true that +// memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y, +// then x and y have the same bit pattern representation. + +template +struct is_uniquely_represented + : public std::integral_constant< + bool, + std::is_integral::value || std::is_enum::value || + std::is_pointer::value> +{ + explicit is_uniquely_represented() = default; +}; + +template +struct is_uniquely_represented : public is_uniquely_represented +{ + explicit is_uniquely_represented() = default; +}; + +template +struct is_uniquely_represented : public is_uniquely_represented +{ + explicit is_uniquely_represented() = default; +}; + +template +struct is_uniquely_represented + : public is_uniquely_represented +{ + explicit is_uniquely_represented() = default; +}; + +// is_uniquely_represented> + +template +struct is_uniquely_represented> + : public std::integral_constant< + bool, + is_uniquely_represented::value && + is_uniquely_represented::value && + sizeof(T) + sizeof(U) == sizeof(std::pair)> +{ + explicit is_uniquely_represented() = default; +}; + +// is_uniquely_represented> + +template +struct is_uniquely_represented> + : public std::integral_constant< + bool, + std::conjunction_v...> && + sizeof(std::tuple) == (sizeof(T) + ...)> +{ + explicit is_uniquely_represented() = default; +}; + +// is_uniquely_represented + +template +struct is_uniquely_represented : public is_uniquely_represented +{ + explicit is_uniquely_represented() = default; +}; + +// is_uniquely_represented> + +template +struct is_uniquely_represented> + : public std::integral_constant< + bool, + is_uniquely_represented::value && + sizeof(T) * N == sizeof(std::array)> +{ + explicit is_uniquely_represented() = default; +}; + +/** Metafunction returning `true` if the type can be hashed in one call. + + For `is_contiguously_hashable::value` to be true, then for every + combination of possible values of `T` held in `x` and `y`, + if `x == y`, then it must be true that `memcmp(&x, &y, sizeof(T))` + return 0; i.e. that `x` and `y` are represented by the same bit pattern. + + For example: A two's complement `int` should be contiguously hashable. + Every bit pattern produces a unique value that does not compare equal to + any other bit pattern's value. A IEEE floating point should not be + contiguously hashable because -0. and 0. have different bit patterns, + though they compare equal. +*/ +/** @{ */ +template +struct is_contiguously_hashable + : public std::integral_constant< + bool, + is_uniquely_represented::value && + (sizeof(T) == 1 || + HashAlgorithm::endian == boost::endian::order::native)> +{ + explicit is_contiguously_hashable() = default; +}; + +template +struct is_contiguously_hashable + : public std::integral_constant< + bool, + is_uniquely_represented::value && + (sizeof(T) == 1 || + HashAlgorithm::endian == boost::endian::order::native)> +{ + explicit is_contiguously_hashable() = default; +}; +/** @} */ + +//------------------------------------------------------------------------------ + +/** Logically concatenate input data to a `Hasher`. + + Hasher requirements: + + `X` is the type `Hasher` + `h` is a value of type `x` + `p` is a value convertible to `void const*` + `n` is a value of type `std::size_t`, greater than zero + + Expression: + `h.append (p, n);` + Throws: + Never + Effect: + Adds the input data to the hasher state. + + Expression: + `static_cast(j)` + Throws: + Never + Effect: + Returns the reslting hash of all the input data. +*/ +/** @{ */ + +// scalars + +template +inline std::enable_if_t::value> +hash_append(Hasher& h, T const& t) noexcept +{ + h(std::addressof(t), sizeof(t)); +} + +template +inline std::enable_if_t< + !is_contiguously_hashable::value && + (std::is_integral::value || std::is_pointer::value || + std::is_enum::value)> +hash_append(Hasher& h, T t) noexcept +{ + detail::reverse_bytes(t); + h(std::addressof(t), sizeof(t)); +} + +template +inline std::enable_if_t::value> +hash_append(Hasher& h, T t) noexcept +{ + if (t == 0) + t = 0; + detail::maybe_reverse_bytes(t, h); + h(&t, sizeof(t)); +} + +template +inline void +hash_append(Hasher& h, std::nullptr_t) noexcept +{ + void const* p = nullptr; + detail::maybe_reverse_bytes(p, h); + h(&p, sizeof(p)); +} + +// Forward declarations for ADL purposes + +template +std::enable_if_t::value> +hash_append(Hasher& h, T (&a)[N]) noexcept; + +template +std::enable_if_t::value> +hash_append( + Hasher& h, + std::basic_string const& s) noexcept; + +template +std::enable_if_t::value> +hash_append( + Hasher& h, + std::basic_string const& s) noexcept; + +template +std::enable_if_t, Hasher>::value> +hash_append(Hasher& h, std::pair const& p) noexcept; + +template +std::enable_if_t::value> +hash_append(Hasher& h, std::vector const& v) noexcept; + +template +std::enable_if_t::value> +hash_append(Hasher& h, std::vector const& v) noexcept; + +template +std::enable_if_t, Hasher>::value> +hash_append(Hasher& h, std::array const& a) noexcept; + +template +std::enable_if_t, Hasher>::value> +hash_append(Hasher& h, std::tuple const& t) noexcept; + +template +void +hash_append(Hasher& h, std::unordered_map const& m); + +template +void +hash_append(Hasher& h, std::unordered_set const& s); + +template +std::enable_if_t::value> +hash_append( + Hasher& h, + boost::container::flat_set const& v) noexcept; +template +std::enable_if_t::value> +hash_append( + Hasher& h, + boost::container::flat_set const& v) noexcept; +template +void +hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept; + +// c-array + +template +std::enable_if_t::value> +hash_append(Hasher& h, T (&a)[N]) noexcept +{ + for (auto const& t : a) + hash_append(h, t); +} + +// basic_string + +template +inline std::enable_if_t::value> +hash_append( + Hasher& h, + std::basic_string const& s) noexcept +{ + for (auto c : s) + hash_append(h, c); + hash_append(h, s.size()); +} + +template +inline std::enable_if_t::value> +hash_append( + Hasher& h, + std::basic_string const& s) noexcept +{ + h(s.data(), s.size() * sizeof(CharT)); + hash_append(h, s.size()); +} + +// pair + +template +inline std::enable_if_t< + !is_contiguously_hashable, Hasher>::value> +hash_append(Hasher& h, std::pair const& p) noexcept +{ + hash_append(h, p.first, p.second); +} + +// vector + +template +inline std::enable_if_t::value> +hash_append(Hasher& h, std::vector const& v) noexcept +{ + for (auto const& t : v) + hash_append(h, t); + hash_append(h, v.size()); +} + +template +inline std::enable_if_t::value> +hash_append(Hasher& h, std::vector const& v) noexcept +{ + h(v.data(), v.size() * sizeof(T)); + hash_append(h, v.size()); +} + +// array + +template +std::enable_if_t, Hasher>::value> +hash_append(Hasher& h, std::array const& a) noexcept +{ + for (auto const& t : a) + hash_append(h, t); +} + +template +std::enable_if_t::value> +hash_append( + Hasher& h, + boost::container::flat_set const& v) noexcept +{ + for (auto const& t : v) + hash_append(h, t); +} +template +std::enable_if_t::value> +hash_append( + Hasher& h, + boost::container::flat_set const& v) noexcept +{ + h(&(v.begin()), v.size() * sizeof(Key)); +} +// tuple + +namespace detail { + +inline void +for_each_item(...) noexcept +{ +} + +template +inline int +hash_one(Hasher& h, T const& t) noexcept +{ + hash_append(h, t); + return 0; +} + +template +inline void +tuple_hash( + Hasher& h, + std::tuple const& t, + std::index_sequence) noexcept +{ + for_each_item(hash_one(h, std::get(t))...); +} + +} // namespace detail + +template +inline std::enable_if_t< + !is_contiguously_hashable, Hasher>::value> +hash_append(Hasher& h, std::tuple const& t) noexcept +{ + detail::tuple_hash(h, t, std::index_sequence_for{}); +} + +// shared_ptr + +template +inline void +hash_append(Hasher& h, std::shared_ptr const& p) noexcept +{ + hash_append(h, p.get()); +} + +// chrono + +template +inline void +hash_append(Hasher& h, std::chrono::duration const& d) noexcept +{ + hash_append(h, d.count()); +} + +template +inline void +hash_append( + Hasher& h, + std::chrono::time_point const& tp) noexcept +{ + hash_append(h, tp.time_since_epoch()); +} + +// variadic + +template +inline void +hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept +{ + hash_append(h, t0); + hash_append(h, t1, t...); +} + +// error_code + +template +inline void +hash_append(HashAlgorithm& h, std::error_code const& ec) +{ + hash_append(h, ec.value(), &ec.category()); +} + +} // namespace beast + +#endif diff --git a/src/ripple/beast/hash/uhash.h b/include/xrpl/beast/hash/uhash.h similarity index 92% rename from src/ripple/beast/hash/uhash.h rename to include/xrpl/beast/hash/uhash.h index 76aa6f15fe7..ab3eaad0392 100644 --- a/src/ripple/beast/hash/uhash.h +++ b/include/xrpl/beast/hash/uhash.h @@ -21,8 +21,8 @@ #ifndef BEAST_HASH_UHASH_H_INCLUDED #define BEAST_HASH_UHASH_H_INCLUDED -#include -#include +#include +#include namespace beast { @@ -39,11 +39,11 @@ struct uhash operator()(T const& t) const noexcept { Hasher h; - hash_append (h, t); + hash_append(h, t); return static_cast(h); } }; -} // beast +} // namespace beast #endif diff --git a/include/xrpl/beast/hash/xxhasher.h b/include/xrpl/beast/hash/xxhasher.h new file mode 100644 index 00000000000..381980902ac --- /dev/null +++ b/include/xrpl/beast/hash/xxhasher.h @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2014, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_HASH_XXHASHER_H_INCLUDED +#define BEAST_HASH_XXHASHER_H_INCLUDED + +#include + +#include + +#include +#include +#include + +namespace beast { + +class xxhasher +{ +private: + // requires 64-bit std::size_t + static_assert(sizeof(std::size_t) == 8, ""); + + XXH3_state_t* state_; + + static XXH3_state_t* + allocState() + { + auto ret = XXH3_createState(); + if (ret == nullptr) + throw std::bad_alloc(); + return ret; + } + +public: + using result_type = std::size_t; + + static constexpr auto const endian = boost::endian::order::native; + + xxhasher(xxhasher const&) = delete; + xxhasher& + operator=(xxhasher const&) = delete; + + xxhasher() + { + state_ = allocState(); + XXH3_64bits_reset(state_); + } + + ~xxhasher() noexcept + { + XXH3_freeState(state_); + } + + template < + class Seed, + std::enable_if_t::value>* = nullptr> + explicit xxhasher(Seed seed) + { + state_ = allocState(); + XXH3_64bits_reset_withSeed(state_, seed); + } + + template < + class Seed, + std::enable_if_t::value>* = nullptr> + xxhasher(Seed seed, Seed) + { + state_ = allocState(); + XXH3_64bits_reset_withSeed(state_, seed); + } + + void + operator()(void const* key, std::size_t len) noexcept + { + XXH3_64bits_update(state_, key, len); + } + + explicit + operator std::size_t() noexcept + { + return XXH3_64bits_digest(state_); + } +}; + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/insight/Collector.h b/include/xrpl/beast/insight/Collector.h new file mode 100644 index 00000000000..eab2bd7d70c --- /dev/null +++ b/include/xrpl/beast/insight/Collector.h @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_COLLECTOR_H_INCLUDED +#define BEAST_INSIGHT_COLLECTOR_H_INCLUDED + +#include +#include +#include +#include +#include + +#include + +namespace beast { +namespace insight { + +/** Interface for a manager that allows collection of metrics. + + To export metrics from a class, pass and save a shared_ptr to this + interface in the class constructor. Create the metric objects + as desired (counters, events, gauges, meters, and an optional hook) + using the interface. + + @see Counter, Event, Gauge, Hook, Meter + @see NullCollector, StatsDCollector +*/ +class Collector +{ +public: + using ptr = std::shared_ptr; + + virtual ~Collector() = 0; + + /** Create a hook. + + A hook is called at each collection interval, on an implementation + defined thread. This is a convenience facility for gathering metrics + in the polling style. The typical usage is to update all the metrics + of interest in the handler. + + Handler will be called with this signature: + void handler (void) + + @see Hook + */ + /** @{ */ + template + Hook + make_hook(Handler handler) + { + return make_hook(HookImpl::HandlerType(handler)); + } + + virtual Hook + make_hook(HookImpl::HandlerType const& handler) = 0; + /** @} */ + + /** Create a counter with the specified name. + @see Counter + */ + /** @{ */ + virtual Counter + make_counter(std::string const& name) = 0; + + Counter + make_counter(std::string const& prefix, std::string const& name) + { + if (prefix.empty()) + return make_counter(name); + return make_counter(prefix + "." + name); + } + /** @} */ + + /** Create an event with the specified name. + @see Event + */ + /** @{ */ + virtual Event + make_event(std::string const& name) = 0; + + Event + make_event(std::string const& prefix, std::string const& name) + { + if (prefix.empty()) + return make_event(name); + return make_event(prefix + "." + name); + } + /** @} */ + + /** Create a gauge with the specified name. + @see Gauge + */ + /** @{ */ + virtual Gauge + make_gauge(std::string const& name) = 0; + + Gauge + make_gauge(std::string const& prefix, std::string const& name) + { + if (prefix.empty()) + return make_gauge(name); + return make_gauge(prefix + "." + name); + } + /** @} */ + + /** Create a meter with the specified name. + @see Meter + */ + /** @{ */ + virtual Meter + make_meter(std::string const& name) = 0; + + Meter + make_meter(std::string const& prefix, std::string const& name) + { + if (prefix.empty()) + return make_meter(name); + return make_meter(prefix + "." + name); + } + /** @} */ +}; + +} // namespace insight +} // namespace beast + +#endif diff --git a/src/ripple/beast/insight/Counter.h b/include/xrpl/beast/insight/Counter.h similarity index 79% rename from src/ripple/beast/insight/Counter.h rename to include/xrpl/beast/insight/Counter.h index 8661a00306a..3f3a251de89 100644 --- a/src/ripple/beast/insight/Counter.h +++ b/include/xrpl/beast/insight/Counter.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_COUNTER_H_INCLUDED #define BEAST_INSIGHT_COUNTER_H_INCLUDED -#include +#include #include @@ -43,7 +43,7 @@ class Counter final /** Create a null metric. A null metric reports no information. */ - Counter () + Counter() { } @@ -52,67 +52,66 @@ class Counter final factory function in the Collector interface. @see Collector. */ - explicit Counter (std::shared_ptr const& impl) - : m_impl (impl) + explicit Counter(std::shared_ptr const& impl) : m_impl(impl) { } /** Increment the counter. */ /** @{ */ void - increment (value_type amount) const + increment(value_type amount) const { if (m_impl) - m_impl->increment (amount); + m_impl->increment(amount); } Counter const& - operator+= (value_type amount) const + operator+=(value_type amount) const { - increment (amount); + increment(amount); return *this; } Counter const& - operator-= (value_type amount) const + operator-=(value_type amount) const { - increment (-amount); + increment(-amount); return *this; } Counter const& - operator++ () const + operator++() const { - increment (1); + increment(1); return *this; } Counter const& - operator++ (int) const + operator++(int) const { - increment (1); + increment(1); return *this; } Counter const& - operator-- () const + operator--() const { - increment (-1); + increment(-1); return *this; } Counter const& - operator-- (int) const + operator--(int) const { - increment (-1); + increment(-1); return *this; } private: - std::shared_ptr m_impl; + std::shared_ptr m_impl; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/CounterImpl.h b/include/xrpl/beast/insight/CounterImpl.h similarity index 86% rename from src/ripple/beast/insight/CounterImpl.h rename to include/xrpl/beast/insight/CounterImpl.h index 383032fdad3..f369b32f776 100644 --- a/src/ripple/beast/insight/CounterImpl.h +++ b/include/xrpl/beast/insight/CounterImpl.h @@ -28,17 +28,17 @@ namespace insight { class Counter; -class CounterImpl - : public std::enable_shared_from_this +class CounterImpl : public std::enable_shared_from_this { public: using value_type = std::int64_t; - virtual ~CounterImpl () = 0; - virtual void increment (value_type amount) = 0; + virtual ~CounterImpl() = 0; + virtual void + increment(value_type amount) = 0; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/Event.h b/include/xrpl/beast/insight/Event.h similarity index 84% rename from src/ripple/beast/insight/Event.h rename to include/xrpl/beast/insight/Event.h index 200eadb7cb6..407dd233e95 100644 --- a/src/ripple/beast/insight/Event.h +++ b/include/xrpl/beast/insight/Event.h @@ -20,9 +20,7 @@ #ifndef BEAST_INSIGHT_EVENT_H_INCLUDED #define BEAST_INSIGHT_EVENT_H_INCLUDED -#include - -#include +#include #include #include @@ -47,38 +45,40 @@ class Event final /** Create a null metric. A null metric reports no information. */ - Event () - { } + Event() + { + } /** Create the metric reference the specified implementation. Normally this won't be called directly. Instead, call the appropriate factory function in the Collector interface. @see Collector. */ - explicit Event (std::shared_ptr const& impl) - : m_impl (impl) - { } + explicit Event(std::shared_ptr const& impl) : m_impl(impl) + { + } /** Push an event notification. */ template void - notify (std::chrono::duration const& value) const + notify(std::chrono::duration const& value) const { using namespace std::chrono; if (m_impl) - m_impl->notify (date::ceil (value)); + m_impl->notify(ceil(value)); } - std::shared_ptr const& impl () const + std::shared_ptr const& + impl() const { return m_impl; } private: - std::shared_ptr m_impl; + std::shared_ptr m_impl; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/EventImpl.h b/include/xrpl/beast/insight/EventImpl.h similarity index 86% rename from src/ripple/beast/insight/EventImpl.h rename to include/xrpl/beast/insight/EventImpl.h index 307615ba4d1..5104d05c468 100644 --- a/src/ripple/beast/insight/EventImpl.h +++ b/include/xrpl/beast/insight/EventImpl.h @@ -28,17 +28,17 @@ namespace insight { class Event; -class EventImpl - : public std::enable_shared_from_this +class EventImpl : public std::enable_shared_from_this { public: using value_type = std::chrono::milliseconds; - virtual ~EventImpl () = 0; - virtual void notify (value_type const& value) = 0; + virtual ~EventImpl() = 0; + virtual void + notify(value_type const& value) = 0; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/Gauge.h b/include/xrpl/beast/insight/Gauge.h similarity index 76% rename from src/ripple/beast/insight/Gauge.h rename to include/xrpl/beast/insight/Gauge.h index d77c932e289..b1e8bedfac2 100644 --- a/src/ripple/beast/insight/Gauge.h +++ b/include/xrpl/beast/insight/Gauge.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_GAUGE_H_INCLUDED #define BEAST_INSIGHT_GAUGE_H_INCLUDED -#include +#include #include @@ -45,7 +45,7 @@ class Gauge final /** Create a null metric. A null metric reports no information. */ - Gauge () + Gauge() { } @@ -54,8 +54,7 @@ class Gauge final factory function in the Collector interface. @see Collector. */ - explicit Gauge (std::shared_ptr const& impl) - : m_impl (impl) + explicit Gauge(std::shared_ptr const& impl) : m_impl(impl) { } @@ -65,78 +64,84 @@ class Gauge final collection interval. */ /** @{ */ - void set (value_type value) const + void + set(value_type value) const { if (m_impl) - m_impl->set (value); + m_impl->set(value); } - Gauge const& operator= (value_type value) const - { set (value); return *this; } + Gauge const& + operator=(value_type value) const + { + set(value); + return *this; + } /** @} */ /** Adjust the value of the gauge. */ /** @{ */ - void increment (difference_type amount) const + void + increment(difference_type amount) const { if (m_impl) - m_impl->increment (amount); + m_impl->increment(amount); } Gauge const& - operator+= (difference_type amount) const + operator+=(difference_type amount) const { - increment (amount); + increment(amount); return *this; } Gauge const& - operator-= (difference_type amount) const + operator-=(difference_type amount) const { - increment (-amount); + increment(-amount); return *this; } Gauge const& - operator++ () const + operator++() const { - increment (1); + increment(1); return *this; } Gauge const& - operator++ (int) const + operator++(int) const { - increment (1); + increment(1); return *this; } Gauge const& - operator-- () const + operator--() const { - increment (-1); + increment(-1); return *this; } Gauge const& - operator-- (int) const + operator--(int) const { - increment (-1); + increment(-1); return *this; } /** @} */ - std::shared_ptr const& - impl () const + std::shared_ptr const& + impl() const { return m_impl; } private: - std::shared_ptr m_impl; + std::shared_ptr m_impl; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/GaugeImpl.h b/include/xrpl/beast/insight/GaugeImpl.h similarity index 84% rename from src/ripple/beast/insight/GaugeImpl.h rename to include/xrpl/beast/insight/GaugeImpl.h index 07af0c9b540..78609fd4328 100644 --- a/src/ripple/beast/insight/GaugeImpl.h +++ b/include/xrpl/beast/insight/GaugeImpl.h @@ -28,19 +28,20 @@ namespace insight { class Gauge; -class GaugeImpl - : public std::enable_shared_from_this +class GaugeImpl : public std::enable_shared_from_this { public: using value_type = std::uint64_t; using difference_type = std::int64_t; - virtual ~GaugeImpl () = 0; - virtual void set (value_type value) = 0; - virtual void increment (difference_type amount) = 0; + virtual ~GaugeImpl() = 0; + virtual void + set(value_type value) = 0; + virtual void + increment(difference_type amount) = 0; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/Group.h b/include/xrpl/beast/insight/Group.h similarity index 88% rename from src/ripple/beast/insight/Group.h rename to include/xrpl/beast/insight/Group.h index ffd52ccec0d..f11b1397c8b 100644 --- a/src/ripple/beast/insight/Group.h +++ b/include/xrpl/beast/insight/Group.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_GROUP_H_INCLUDED #define BEAST_INSIGHT_GROUP_H_INCLUDED -#include +#include #include #include @@ -32,13 +32,14 @@ namespace insight { class Group : public Collector { public: - using ptr = std::shared_ptr ; + using ptr = std::shared_ptr; /** Returns the name of this group, for diagnostics. */ - virtual std::string const& name () const = 0; + virtual std::string const& + name() const = 0; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/Groups.h b/include/xrpl/beast/insight/Groups.h similarity index 82% rename from src/ripple/beast/insight/Groups.h rename to include/xrpl/beast/insight/Groups.h index 67dc55d9ec9..456deb79073 100644 --- a/src/ripple/beast/insight/Groups.h +++ b/include/xrpl/beast/insight/Groups.h @@ -20,8 +20,8 @@ #ifndef BEAST_INSIGHT_GROUPS_H_INCLUDED #define BEAST_INSIGHT_GROUPS_H_INCLUDED -#include -#include +#include +#include #include #include @@ -37,22 +37,22 @@ class Groups /** Find or create a new collector with a given name. */ /** @{ */ - virtual - Group::ptr const& - get (std::string const& name) = 0; + virtual Group::ptr const& + get(std::string const& name) = 0; Group::ptr const& - operator[] (std::string const& name) + operator[](std::string const& name) { - return get (name); + return get(name); } /** @} */ }; /** Create a group container that uses the specified collector. */ -std::unique_ptr make_Groups (Collector::ptr const& collector); +std::unique_ptr +make_Groups(Collector::ptr const& collector); -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/Hook.h b/include/xrpl/beast/insight/Hook.h similarity index 85% rename from src/ripple/beast/insight/Hook.h rename to include/xrpl/beast/insight/Hook.h index 55c4ebe37f9..affa42bb828 100644 --- a/src/ripple/beast/insight/Hook.h +++ b/include/xrpl/beast/insight/Hook.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_HOOK_H_INCLUDED #define BEAST_INSIGHT_HOOK_H_INCLUDED -#include +#include #include @@ -34,28 +34,30 @@ class Hook final /** Create a null hook. A null hook has no associated handler. */ - Hook () - { } + Hook() + { + } /** Create a hook referencing the specified implementation. Normally this won't be called directly. Instead, call the appropriate factory function in the Collector interface. @see Collector. */ - explicit Hook (std::shared_ptr const& impl) - : m_impl (impl) - { } + explicit Hook(std::shared_ptr const& impl) : m_impl(impl) + { + } - std::shared_ptr const& impl () const + std::shared_ptr const& + impl() const { return m_impl; } private: - std::shared_ptr m_impl; + std::shared_ptr m_impl; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/HookImpl.h b/include/xrpl/beast/insight/HookImpl.h similarity index 86% rename from src/ripple/beast/insight/HookImpl.h rename to include/xrpl/beast/insight/HookImpl.h index d3c021d8237..aca1f847fad 100644 --- a/src/ripple/beast/insight/HookImpl.h +++ b/include/xrpl/beast/insight/HookImpl.h @@ -26,16 +26,15 @@ namespace beast { namespace insight { -class HookImpl - : public std::enable_shared_from_this +class HookImpl : public std::enable_shared_from_this { public: - using HandlerType = std::function ; + using HandlerType = std::function; - virtual ~HookImpl () = 0; + virtual ~HookImpl() = 0; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/include/xrpl/beast/insight/Insight.h b/include/xrpl/beast/insight/Insight.h new file mode 100644 index 00000000000..1c2c1375a28 --- /dev/null +++ b/include/xrpl/beast/insight/Insight.h @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_H_INCLUDED +#define BEAST_INSIGHT_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/src/ripple/beast/insight/Meter.h b/include/xrpl/beast/insight/Meter.h similarity index 78% rename from src/ripple/beast/insight/Meter.h rename to include/xrpl/beast/insight/Meter.h index bdd65916058..7ef71988a13 100644 --- a/src/ripple/beast/insight/Meter.h +++ b/include/xrpl/beast/insight/Meter.h @@ -20,9 +20,9 @@ #ifndef BEAST_INSIGHT_METER_H_INCLUDED #define BEAST_INSIGHT_METER_H_INCLUDED -#include +#include -#include +#include namespace beast { namespace insight { @@ -42,55 +42,61 @@ class Meter final /** Create a null metric. A null metric reports no information. */ - Meter () - { } + Meter() + { + } /** Create the metric reference the specified implementation. Normally this won't be called directly. Instead, call the appropriate factory function in the Collector interface. @see Collector. */ - explicit Meter (std::shared_ptr const& impl) - : m_impl (impl) - { } + explicit Meter(std::shared_ptr const& impl) : m_impl(impl) + { + } /** Increment the meter. */ /** @{ */ - void increment (value_type amount) const + void + increment(value_type amount) const { if (m_impl) - m_impl->increment (amount); + m_impl->increment(amount); } - Meter const& operator+= (value_type amount) const + Meter const& + operator+=(value_type amount) const { - increment (amount); + increment(amount); return *this; } - Meter const& operator++ () const + Meter const& + operator++() const { - increment (1); + increment(1); return *this; } - Meter const& operator++ (int) const + Meter const& + operator++(int) const { - increment (1); + increment(1); return *this; } /** @} */ - std::shared_ptr const& impl () const + std::shared_ptr const& + impl() const { return m_impl; } private: - std::shared_ptr m_impl; + std::shared_ptr m_impl; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/MeterImpl.h b/include/xrpl/beast/insight/MeterImpl.h similarity index 86% rename from src/ripple/beast/insight/MeterImpl.h rename to include/xrpl/beast/insight/MeterImpl.h index b8812fb2383..846dbe19a89 100644 --- a/src/ripple/beast/insight/MeterImpl.h +++ b/include/xrpl/beast/insight/MeterImpl.h @@ -28,17 +28,17 @@ namespace insight { class Meter; -class MeterImpl - : public std::enable_shared_from_this +class MeterImpl : public std::enable_shared_from_this { public: using value_type = std::uint64_t; - virtual ~MeterImpl () = 0; - virtual void increment (value_type amount) = 0; + virtual ~MeterImpl() = 0; + virtual void + increment(value_type amount) = 0; }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/NullCollector.h b/include/xrpl/beast/insight/NullCollector.h similarity index 90% rename from src/ripple/beast/insight/NullCollector.h rename to include/xrpl/beast/insight/NullCollector.h index 36a78c17a7b..4379c3ceb98 100644 --- a/src/ripple/beast/insight/NullCollector.h +++ b/include/xrpl/beast/insight/NullCollector.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_NULLCOLLECTOR_H_INCLUDED #define BEAST_INSIGHT_NULLCOLLECTOR_H_INCLUDED -#include +#include namespace beast { namespace insight { @@ -31,10 +31,11 @@ class NullCollector : public Collector public: explicit NullCollector() = default; - static std::shared_ptr New (); + static std::shared_ptr + New(); }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/src/ripple/beast/insight/StatsDCollector.h b/include/xrpl/beast/insight/StatsDCollector.h similarity index 84% rename from src/ripple/beast/insight/StatsDCollector.h rename to include/xrpl/beast/insight/StatsDCollector.h index b96731af5ab..fb47eeb7fc3 100644 --- a/src/ripple/beast/insight/StatsDCollector.h +++ b/include/xrpl/beast/insight/StatsDCollector.h @@ -20,10 +20,9 @@ #ifndef BEAST_INSIGHT_STATSDCOLLECTOR_H_INCLUDED #define BEAST_INSIGHT_STATSDCOLLECTOR_H_INCLUDED -#include - -#include -#include +#include +#include +#include namespace beast { namespace insight { @@ -42,13 +41,13 @@ class StatsDCollector : public Collector @param prefix A string pre-pended before each metric name. @param journal Destination for logging output. */ - static - std::shared_ptr - New (IP::Endpoint const& address, - std::string const& prefix, Journal journal); + static std::shared_ptr + New(IP::Endpoint const& address, + std::string const& prefix, + Journal journal); }; -} -} +} // namespace insight +} // namespace beast #endif diff --git a/include/xrpl/beast/net/IPAddress.h b/include/xrpl/beast/net/IPAddress.h new file mode 100644 index 00000000000..62469cfda1b --- /dev/null +++ b/include/xrpl/beast/net/IPAddress.h @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_NET_IPADDRESS_H_INCLUDED +#define BEAST_NET_IPADDRESS_H_INCLUDED + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ + +namespace beast { +namespace IP { + +using Address = boost::asio::ip::address; + +/** Returns the address represented as a string. */ +inline std::string +to_string(Address const& addr) +{ + return addr.to_string(); +} + +/** Returns `true` if this is a loopback address. */ +inline bool +is_loopback(Address const& addr) +{ + return addr.is_loopback(); +} + +/** Returns `true` if the address is unspecified. */ +inline bool +is_unspecified(Address const& addr) +{ + return addr.is_unspecified(); +} + +/** Returns `true` if the address is a multicast address. */ +inline bool +is_multicast(Address const& addr) +{ + return addr.is_multicast(); +} + +/** Returns `true` if the address is a private unroutable address. */ +inline bool +is_private(Address const& addr) +{ + return (addr.is_v4()) ? is_private(addr.to_v4()) : is_private(addr.to_v6()); +} + +/** Returns `true` if the address is a public routable address. */ +inline bool +is_public(Address const& addr) +{ + return (addr.is_v4()) ? is_public(addr.to_v4()) : is_public(addr.to_v6()); +} + +} // namespace IP + +//------------------------------------------------------------------------------ + +template +void +hash_append(Hasher& h, beast::IP::Address const& addr) noexcept +{ + using beast::hash_append; + if (addr.is_v4()) + hash_append(h, addr.to_v4().to_bytes()); + else if (addr.is_v6()) + hash_append(h, addr.to_v6().to_bytes()); + else + UNREACHABLE("beast::hash_append : invalid address type"); +} +} // namespace beast + +namespace boost { +template <> +struct hash<::beast::IP::Address> +{ + explicit hash() = default; + + std::size_t + operator()(::beast::IP::Address const& addr) const + { + return ::beast::uhash<>{}(addr); + } +}; +} // namespace boost + +#endif diff --git a/include/xrpl/beast/net/IPAddressConversion.h b/include/xrpl/beast/net/IPAddressConversion.h new file mode 100644 index 00000000000..0dfbe3197d1 --- /dev/null +++ b/include/xrpl/beast/net/IPAddressConversion.h @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_NET_IPADDRESSCONVERSION_H_INCLUDED +#define BEAST_NET_IPADDRESSCONVERSION_H_INCLUDED + +#include + +#include + +namespace beast { +namespace IP { + +/** Convert to Endpoint. + The port is set to zero. +*/ +Endpoint +from_asio(boost::asio::ip::address const& address); + +/** Convert to Endpoint. */ +Endpoint +from_asio(boost::asio::ip::tcp::endpoint const& endpoint); + +/** Convert to asio::ip::address. + The port is ignored. +*/ +boost::asio::ip::address +to_asio_address(Endpoint const& endpoint); + +/** Convert to asio::ip::tcp::endpoint. */ +boost::asio::ip::tcp::endpoint +to_asio_endpoint(Endpoint const& endpoint); + +} // namespace IP +} // namespace beast + +namespace beast { + +// DEPRECATED +struct IPAddressConversion +{ + explicit IPAddressConversion() = default; + + static IP::Endpoint + from_asio(boost::asio::ip::address const& address) + { + return IP::from_asio(address); + } + static IP::Endpoint + from_asio(boost::asio::ip::tcp::endpoint const& endpoint) + { + return IP::from_asio(endpoint); + } + static boost::asio::ip::address + to_asio_address(IP::Endpoint const& address) + { + return IP::to_asio_address(address); + } + static boost::asio::ip::tcp::endpoint + to_asio_endpoint(IP::Endpoint const& address) + { + return IP::to_asio_endpoint(address); + } +}; + +} // namespace beast + +#endif diff --git a/src/ripple/beast/net/IPAddressV4.h b/include/xrpl/beast/net/IPAddressV4.h similarity index 88% rename from src/ripple/beast/net/IPAddressV4.h rename to include/xrpl/beast/net/IPAddressV4.h index 428d100369a..98a92dba207 100644 --- a/src/ripple/beast/net/IPAddressV4.h +++ b/include/xrpl/beast/net/IPAddressV4.h @@ -20,13 +20,15 @@ #ifndef BEAST_NET_IPADDRESSV4_H_INCLUDED #define BEAST_NET_IPADDRESSV4_H_INCLUDED -#include +#include + +#include + #include #include #include #include #include -#include namespace beast { namespace IP { @@ -34,17 +36,20 @@ namespace IP { using AddressV4 = boost::asio::ip::address_v4; /** Returns `true` if the address is a private unroutable address. */ -bool is_private (AddressV4 const& addr); +bool +is_private(AddressV4 const& addr); /** Returns `true` if the address is a public routable address. */ -bool is_public (AddressV4 const& addr); +bool +is_public(AddressV4 const& addr); /** Returns the address class for the given address. @note Class 'D' represents multicast addresses (224.*.*.*). */ -char get_class (AddressV4 const& address); +char +get_class(AddressV4 const& address); -} -} +} // namespace IP +} // namespace beast #endif diff --git a/src/ripple/beast/net/IPAddressV6.h b/include/xrpl/beast/net/IPAddressV6.h similarity index 89% rename from src/ripple/beast/net/IPAddressV6.h rename to include/xrpl/beast/net/IPAddressV6.h index 9e541a5000d..4a4ef73b86e 100644 --- a/src/ripple/beast/net/IPAddressV6.h +++ b/include/xrpl/beast/net/IPAddressV6.h @@ -20,13 +20,15 @@ #ifndef BEAST_NET_IPADDRESSV6_H_INCLUDED #define BEAST_NET_IPADDRESSV6_H_INCLUDED -#include +#include + +#include + #include #include #include #include #include -#include namespace beast { namespace IP { @@ -34,12 +36,14 @@ namespace IP { using AddressV6 = boost::asio::ip::address_v6; /** Returns `true` if the address is a private unroutable address. */ -bool is_private (AddressV6 const& addr); +bool +is_private(AddressV6 const& addr); /** Returns `true` if the address is a public routable address. */ -bool is_public (AddressV6 const& addr); +bool +is_public(AddressV6 const& addr); -} -} +} // namespace IP +} // namespace beast #endif diff --git a/include/xrpl/beast/net/IPEndpoint.h b/include/xrpl/beast/net/IPEndpoint.h new file mode 100644 index 00000000000..e66e7f4caae --- /dev/null +++ b/include/xrpl/beast/net/IPEndpoint.h @@ -0,0 +1,243 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_NET_IPENDPOINT_H_INCLUDED +#define BEAST_NET_IPENDPOINT_H_INCLUDED + +#include +#include +#include + +#include +#include +#include +#include + +namespace beast { +namespace IP { + +using Port = std::uint16_t; + +/** A version-independent IP address and port combination. */ +class Endpoint +{ +public: + /** Create an unspecified endpoint. */ + Endpoint(); + + /** Create an endpoint from the address and optional port. */ + explicit Endpoint(Address const& addr, Port port = 0); + + /** Create an Endpoint from a string. + If the port is omitted, the endpoint will have a zero port. + @return An optional endpoint; will be `std::nullopt` on failure + */ + static std::optional + from_string_checked(std::string const& s); + static Endpoint + from_string(std::string const& s); + + /** Returns a string representing the endpoint. */ + std::string + to_string() const; + + /** Returns the port number on the endpoint. */ + Port + port() const + { + return m_port; + } + + /** Returns a new Endpoint with a different port. */ + Endpoint + at_port(Port port) const + { + return Endpoint(m_addr, port); + } + + /** Returns the address portion of this endpoint. */ + Address const& + address() const + { + return m_addr; + } + + /** Convenience accessors for the address part. */ + /** @{ */ + bool + is_v4() const + { + return m_addr.is_v4(); + } + bool + is_v6() const + { + return m_addr.is_v6(); + } + AddressV4 const + to_v4() const + { + return m_addr.to_v4(); + } + AddressV6 const + to_v6() const + { + return m_addr.to_v6(); + } + /** @} */ + + /** Arithmetic comparison. */ + /** @{ */ + friend bool + operator==(Endpoint const& lhs, Endpoint const& rhs); + friend bool + operator<(Endpoint const& lhs, Endpoint const& rhs); + + friend bool + operator!=(Endpoint const& lhs, Endpoint const& rhs) + { + return !(lhs == rhs); + } + friend bool + operator>(Endpoint const& lhs, Endpoint const& rhs) + { + return rhs < lhs; + } + friend bool + operator<=(Endpoint const& lhs, Endpoint const& rhs) + { + return !(lhs > rhs); + } + friend bool + operator>=(Endpoint const& lhs, Endpoint const& rhs) + { + return !(rhs > lhs); + } + /** @} */ + + template + friend void + hash_append(Hasher& h, Endpoint const& endpoint) + { + using ::beast::hash_append; + hash_append(h, endpoint.m_addr, endpoint.m_port); + } + +private: + Address m_addr; + Port m_port; +}; + +//------------------------------------------------------------------------------ + +// Properties + +/** Returns `true` if the endpoint is a loopback address. */ +inline bool +is_loopback(Endpoint const& endpoint) +{ + return is_loopback(endpoint.address()); +} + +/** Returns `true` if the endpoint is unspecified. */ +inline bool +is_unspecified(Endpoint const& endpoint) +{ + return is_unspecified(endpoint.address()); +} + +/** Returns `true` if the endpoint is a multicast address. */ +inline bool +is_multicast(Endpoint const& endpoint) +{ + return is_multicast(endpoint.address()); +} + +/** Returns `true` if the endpoint is a private unroutable address. */ +inline bool +is_private(Endpoint const& endpoint) +{ + return is_private(endpoint.address()); +} + +/** Returns `true` if the endpoint is a public routable address. */ +inline bool +is_public(Endpoint const& endpoint) +{ + return is_public(endpoint.address()); +} + +//------------------------------------------------------------------------------ + +/** Returns the endpoint represented as a string. */ +inline std::string +to_string(Endpoint const& endpoint) +{ + return endpoint.to_string(); +} + +/** Output stream conversion. */ +template +OutputStream& +operator<<(OutputStream& os, Endpoint const& endpoint) +{ + os << to_string(endpoint); + return os; +} + +/** Input stream conversion. */ +std::istream& +operator>>(std::istream& is, Endpoint& endpoint); + +} // namespace IP +} // namespace beast + +//------------------------------------------------------------------------------ + +namespace std { +/** std::hash support. */ +template <> +struct hash<::beast::IP::Endpoint> +{ + explicit hash() = default; + + std::size_t + operator()(::beast::IP::Endpoint const& endpoint) const + { + return ::beast::uhash<>{}(endpoint); + } +}; +} // namespace std + +namespace boost { +/** boost::hash support. */ +template <> +struct hash<::beast::IP::Endpoint> +{ + explicit hash() = default; + + std::size_t + operator()(::beast::IP::Endpoint const& endpoint) const + { + return ::beast::uhash<>{}(endpoint); + } +}; +} // namespace boost + +#endif diff --git a/include/xrpl/beast/rfc2616.h b/include/xrpl/beast/rfc2616.h new file mode 100644 index 00000000000..648fbc22e2f --- /dev/null +++ b/include/xrpl/beast/rfc2616.h @@ -0,0 +1,402 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2014, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_RFC2616_HPP +#define BEAST_RFC2616_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace rfc2616 { + +namespace detail { + +struct ci_equal_pred +{ + explicit ci_equal_pred() = default; + + bool + operator()(char c1, char c2) + { + // VFALCO TODO Use a table lookup here + return std::tolower(static_cast(c1)) == + std::tolower(static_cast(c2)); + } +}; + +/** Returns `true` if `c` is linear white space. + + This excludes the CRLF sequence allowed for line continuations. +*/ +inline bool +is_lws(char c) +{ + return c == ' ' || c == '\t'; +} + +/** Returns `true` if `c` is any whitespace character. */ +inline bool +is_white(char c) +{ + switch (c) + { + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + return true; + }; + return false; +} + +template +FwdIter +trim_right(FwdIter first, FwdIter last) +{ + if (first == last) + return last; + do + { + --last; + if (!is_white(*last)) + return ++last; + } while (last != first); + return first; +} + +template +String +trim_right(String const& s) +{ + using std::begin; + using std::end; + auto first(begin(s)); + auto last(end(s)); + last = trim_right(first, last); + return {first, last}; +} + +} // namespace detail + +/** Parse a character sequence of values separated by commas. + Double quotes and escape sequences will be converted. Excess white + space, commas, double quotes, and empty elements are not copied. + Format: + #(token|quoted-string) + Reference: + http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2 +*/ +template < + class FwdIt, + class Result = std::vector< + std::basic_string::value_type>>, + class Char> +Result +split(FwdIt first, FwdIt last, Char delim) +{ + using namespace detail; + using string = typename Result::value_type; + + Result result; + + FwdIt iter = first; + string e; + while (iter != last) + { + if (*iter == '"') + { + // quoted-string + ++iter; + while (iter != last) + { + if (*iter == '"') + { + ++iter; + break; + } + + if (*iter == '\\') + { + // quoted-pair + ++iter; + if (iter != last) + e.append(1, *iter++); + } + else + { + // qdtext + e.append(1, *iter++); + } + } + if (!e.empty()) + { + result.emplace_back(std::move(e)); + e.clear(); + } + } + else if (*iter == delim) + { + e = trim_right(e); + if (!e.empty()) + { + result.emplace_back(std::move(e)); + e.clear(); + } + ++iter; + } + else if (is_lws(*iter)) + { + ++iter; + } + else + { + e.append(1, *iter++); + } + } + + if (!e.empty()) + { + e = trim_right(e); + if (!e.empty()) + result.emplace_back(std::move(e)); + } + return result; +} + +template < + class FwdIt, + class Result = std::vector< + std::basic_string::value_type>>> +Result +split_commas(FwdIt first, FwdIt last) +{ + return split(first, last, ','); +} + +template > +Result +split_commas(boost::beast::string_view const& s) +{ + return split_commas(s.begin(), s.end()); +} + +//------------------------------------------------------------------------------ + +/** Iterates through a comma separated list. + + Meets the requirements of ForwardIterator. + + List defined in rfc2616 2.1. + + @note Values returned may contain backslash escapes. +*/ +class list_iterator +{ + using iter_type = boost::string_ref::const_iterator; + + iter_type it_; + iter_type end_; + boost::string_ref value_; + +public: + using value_type = boost::string_ref; + using pointer = value_type const*; + using reference = value_type const&; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + list_iterator(iter_type begin, iter_type end) : it_(begin), end_(end) + { + if (it_ != end_) + increment(); + } + + bool + operator==(list_iterator const& other) const + { + return other.it_ == it_ && other.end_ == end_ && + other.value_.size() == value_.size(); + } + + bool + operator!=(list_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const + { + return value_; + } + + pointer + operator->() const + { + return &*(*this); + } + + list_iterator& + operator++() + { + increment(); + return *this; + } + + list_iterator + operator++(int) + { + auto temp = *this; + ++(*this); + return temp; + } + +private: + template + void + increment(); +}; + +template +void +list_iterator::increment() +{ + using namespace detail; + value_.clear(); + while (it_ != end_) + { + if (*it_ == '"') + { + // quoted-string + ++it_; + if (it_ == end_) + return; + if (*it_ != '"') + { + auto start = it_; + for (;;) + { + ++it_; + if (it_ == end_) + { + value_ = boost::string_ref( + &*start, std::distance(start, it_)); + return; + } + if (*it_ == '"') + { + value_ = boost::string_ref( + &*start, std::distance(start, it_)); + ++it_; + return; + } + } + } + ++it_; + } + else if (*it_ == ',') + { + it_++; + continue; + } + else if (is_lws(*it_)) + { + ++it_; + continue; + } + else + { + auto start = it_; + for (;;) + { + ++it_; + if (it_ == end_ || *it_ == ',' || is_lws(*it_)) + { + value_ = + boost::string_ref(&*start, std::distance(start, it_)); + return; + } + } + } + } +} +/** Returns true if two strings are equal. + + A case-insensitive comparison is used. +*/ +inline bool +ci_equal(boost::string_ref s1, boost::string_ref s2) +{ + return boost::range::equal(s1, s2, detail::ci_equal_pred{}); +} + +/** Returns a range representing the list. */ +inline boost::iterator_range +make_list(boost::string_ref const& field) +{ + return boost::iterator_range{ + list_iterator{field.begin(), field.end()}, + list_iterator{field.end(), field.end()}}; +} + +/** Returns true if the specified token exists in the list. + + A case-insensitive comparison is used. +*/ +template +bool +token_in_list(boost::string_ref const& value, boost::string_ref const& token) +{ + for (auto const& item : make_list(value)) + if (ci_equal(item, token)) + return true; + return false; +} + +template +bool +is_keep_alive(boost::beast::http::message const& m) +{ + if (m.version() <= 10) + return boost::beast::http::token_list{ + m[boost::beast::http::field::connection]} + .exists("keep-alive"); + return !boost::beast::http::token_list{ + m[boost::beast::http::field::connection]} + .exists("close"); +} + +} // namespace rfc2616 +} // namespace beast + +#endif diff --git a/include/xrpl/beast/test/yield_to.h b/include/xrpl/beast/test/yield_to.h new file mode 100644 index 00000000000..9e9f83b8974 --- /dev/null +++ b/include/xrpl/beast/test/yield_to.h @@ -0,0 +1,128 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_TEST_YIELD_TO_HPP +#define BEAST_TEST_YIELD_TO_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace beast { +namespace test { + +/** Mix-in to support tests using asio coroutines. + + Derive from this class and use yield_to to launch test + functions inside coroutines. This is handy for testing + asynchronous asio code. +*/ +class enable_yield_to +{ +protected: + boost::asio::io_service ios_; + +private: + boost::optional work_; + std::vector threads_; + std::mutex m_; + std::condition_variable cv_; + std::size_t running_ = 0; + +public: + /// The type of yield context passed to functions. + using yield_context = boost::asio::yield_context; + + explicit enable_yield_to(std::size_t concurrency = 1) : work_(ios_) + { + threads_.reserve(concurrency); + while (concurrency--) + threads_.emplace_back([&] { ios_.run(); }); + } + + ~enable_yield_to() + { + work_ = boost::none; + for (auto& t : threads_) + t.join(); + } + + /// Return the `io_service` associated with the object + boost::asio::io_service& + get_io_service() + { + return ios_; + } + + /** Run one or more functions, each in a coroutine. + + This call will block until all coroutines terminate. + + Each functions should have this signature: + @code + void f(yield_context); + @endcode + + @param fn... One or more functions to invoke. + */ +#if BEAST_DOXYGEN + template + void + yield_to(FN&&... fn); +#else + template + void + yield_to(F0&& f0, FN&&... fn); +#endif + +private: + void + spawn() + { + } + + template + void + spawn(F0&& f, FN&&... fn); +}; + +template +void +enable_yield_to::yield_to(F0&& f0, FN&&... fn) +{ + running_ = 1 + sizeof...(FN); + spawn(f0, fn...); + std::unique_lock lock{m_}; + cv_.wait(lock, [&] { return running_ == 0; }); +} + +template +inline void +enable_yield_to::spawn(F0&& f, FN&&... fn) +{ + boost::asio::spawn( + ios_, + [&](yield_context yield) { + f(yield); + std::lock_guard lock{m_}; + if (--running_ == 0) + cv_.notify_all(); + }, + boost::coroutines::attributes(2 * 1024 * 1024)); + spawn(fn...); +} + +} // namespace test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/type_name.h b/include/xrpl/beast/type_name.h new file mode 100644 index 00000000000..12281cdfe1d --- /dev/null +++ b/include/xrpl/beast/type_name.h @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2014, Howard Hinnant + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TYPE_NAME_H_INCLUDED +#define BEAST_TYPE_NAME_H_INCLUDED + +#include +#include +#include +#include + +#ifndef _MSC_VER +#include +#endif + +namespace beast { + +template +std::string +type_name() +{ + using TR = typename std::remove_reference::type; + + std::string name = typeid(TR).name(); + +#ifndef _MSC_VER + if (auto s = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, nullptr)) + { + name = s; + std::free(s); + } +#endif + + if (std::is_const::value) + name += " const"; + if (std::is_volatile::value) + name += " volatile"; + if (std::is_lvalue_reference::value) + name += "&"; + else if (std::is_rvalue_reference::value) + name += "&&"; + + return name; +} + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test.h b/include/xrpl/beast/unit_test.h new file mode 100644 index 00000000000..bf33b205e62 --- /dev/null +++ b/include/xrpl/beast/unit_test.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_UNIT_TEST_H_INCLUDED +#define BEAST_UNIT_TEST_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BEAST_EXPECT +#define BEAST_EXPECT_S1(x) #x +#define BEAST_EXPECT_S2(x) BEAST_EXPECT_S1(x) +// #define BEAST_EXPECT(cond) {expect(cond, __FILE__ ":" ## +//__LINE__);}while(false){} +#define BEAST_EXPECT(cond) expect(cond, __FILE__ ":" BEAST_EXPECT_S2(__LINE__)) +#endif + +#endif diff --git a/include/xrpl/beast/unit_test/amount.h b/include/xrpl/beast/unit_test/amount.h new file mode 100644 index 00000000000..6f2182f599d --- /dev/null +++ b/include/xrpl/beast/unit_test/amount.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_AMOUNT_HPP +#define BEAST_UNIT_TEST_AMOUNT_HPP + +#include +#include +#include + +namespace beast { +namespace unit_test { + +/** Utility for producing nicely composed output of amounts with units. */ +class amount +{ +private: + std::size_t n_; + std::string const& what_; + +public: + amount(amount const&) = default; + amount& + operator=(amount const&) = delete; + + template + amount(std::size_t n, std::string const& what); + + friend std::ostream& + operator<<(std::ostream& s, amount const& t); +}; + +template +amount::amount(std::size_t n, std::string const& what) : n_(n), what_(what) +{ +} + +inline std::ostream& +operator<<(std::ostream& s, amount const& t) +{ + s << t.n_ << " " << t.what_ << ((t.n_ != 1) ? "s" : ""); + return s; +} + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/detail/const_container.h b/include/xrpl/beast/unit_test/detail/const_container.h new file mode 100644 index 00000000000..b1f089feedf --- /dev/null +++ b/include/xrpl/beast/unit_test/detail/const_container.h @@ -0,0 +1,93 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_DETAIL_CONST_CONTAINER_HPP +#define BEAST_UNIT_TEST_DETAIL_CONST_CONTAINER_HPP + +namespace beast { +namespace unit_test { +namespace detail { + +/** Adapter to constrain a container interface. + The interface allows for limited read only operations. Derived classes + provide additional behavior. +*/ +template +class const_container +{ +private: + using cont_type = Container; + + cont_type m_cont; + +protected: + cont_type& + cont() + { + return m_cont; + } + + cont_type const& + cont() const + { + return m_cont; + } + +public: + using value_type = typename cont_type::value_type; + using size_type = typename cont_type::size_type; + using difference_type = typename cont_type::difference_type; + using iterator = typename cont_type::const_iterator; + using const_iterator = typename cont_type::const_iterator; + + /** Returns `true` if the container is empty. */ + bool + empty() const + { + return m_cont.empty(); + } + + /** Returns the number of items in the container. */ + size_type + size() const + { + return m_cont.size(); + } + + /** Returns forward iterators for traversal. */ + /** @{ */ + const_iterator + begin() const + { + return m_cont.cbegin(); + } + + const_iterator + cbegin() const + { + return m_cont.cbegin(); + } + + const_iterator + end() const + { + return m_cont.cend(); + } + + const_iterator + cend() const + { + return m_cont.cend(); + } + /** @} */ +}; + +} // namespace detail +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/global_suites.h b/include/xrpl/beast/unit_test/global_suites.h new file mode 100644 index 00000000000..64bbbc7a268 --- /dev/null +++ b/include/xrpl/beast/unit_test/global_suites.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_GLOBAL_SUITES_HPP +#define BEAST_UNIT_TEST_GLOBAL_SUITES_HPP + +#include + +namespace beast { +namespace unit_test { + +namespace detail { + +/// Holds test suites registered during static initialization. +inline suite_list& +global_suites() +{ + static suite_list s; + return s; +} + +template +struct insert_suite +{ + insert_suite( + char const* name, + char const* module, + char const* library, + bool manual, + int priority) + { + global_suites().insert(name, module, library, manual, priority); + } +}; + +} // namespace detail + +/// Holds test suites registered during static initialization. +inline suite_list const& +global_suites() +{ + return detail::global_suites(); +} + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/match.h b/include/xrpl/beast/unit_test/match.h new file mode 100644 index 00000000000..641787e8146 --- /dev/null +++ b/include/xrpl/beast/unit_test/match.h @@ -0,0 +1,174 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_MATCH_HPP +#define BEAST_UNIT_TEST_MATCH_HPP + +#include + +#include + +namespace beast { +namespace unit_test { + +// Predicate for implementing matches +class selector +{ +public: + enum mode_t { + // Run all tests except manual ones + all, + + // Run tests that match in any field + automatch, + + // Match on suite + suite, + + // Match on library + library, + + // Match on module (used internally) + module, + + // Match nothing (used internally) + none + }; + +private: + mode_t mode_; + std::string pat_; + std::string library_; + +public: + template + explicit selector(mode_t mode, std::string const& pattern = ""); + + template + bool + operator()(suite_info const& s); +}; + +//------------------------------------------------------------------------------ + +template +selector::selector(mode_t mode, std::string const& pattern) + : mode_(mode), pat_(pattern) +{ + if (mode_ == automatch && pattern.empty()) + mode_ = all; +} + +template +bool +selector::operator()(suite_info const& s) +{ + switch (mode_) + { + case automatch: + // suite or full name + if (s.name() == pat_ || s.full_name() == pat_) + { + mode_ = none; + return true; + } + + // check module + if (pat_ == s.module()) + { + mode_ = module; + library_ = s.library(); + return !s.manual(); + } + + // check library + if (pat_ == s.library()) + { + mode_ = library; + return !s.manual(); + } + + // check start of name + if (s.name().starts_with(pat_) || s.full_name().starts_with(pat_)) + { + // Don't change the mode so that the partial pattern can match + // more than once + return !s.manual(); + } + + return false; + + case suite: + return pat_ == s.name(); + + case module: + return pat_ == s.module() && !s.manual(); + + case library: + return pat_ == s.library() && !s.manual(); + + case none: + return false; + + case all: + default: + break; + }; + + return !s.manual(); +} + +//------------------------------------------------------------------------------ + +// Utility functions for producing predicates to select suites. + +/** Returns a predicate that implements a smart matching rule. + The predicate checks the suite, module, and library fields of the + suite_info in that order. When it finds a match, it changes modes + depending on what was found: + + If a suite is matched first, then only the suite is selected. The + suite may be marked manual. + + If a module is matched first, then only suites from that module + and library not marked manual are selected from then on. + + If a library is matched first, then only suites from that library + not marked manual are selected from then on. + +*/ +inline selector +match_auto(std::string const& name) +{ + return selector(selector::automatch, name); +} + +/** Return a predicate that matches all suites not marked manual. */ +inline selector +match_all() +{ + return selector(selector::all); +} + +/** Returns a predicate that matches a specific suite. */ +inline selector +match_suite(std::string const& name) +{ + return selector(selector::suite, name); +} + +/** Returns a predicate that matches all suites in a library. */ +inline selector +match_library(std::string const& name) +{ + return selector(selector::library, name); +} + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/recorder.h b/include/xrpl/beast/unit_test/recorder.h new file mode 100644 index 00000000000..fbe6ab6c10d --- /dev/null +++ b/include/xrpl/beast/unit_test/recorder.h @@ -0,0 +1,83 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_RECORDER_HPP +#define BEAST_UNIT_TEST_RECORDER_HPP + +#include +#include + +namespace beast { +namespace unit_test { + +/** A test runner that stores the results. */ +class recorder : public runner +{ +private: + results m_results; + suite_results m_suite; + case_results m_case; + +public: + recorder() = default; + + /** Returns a report with the results of all completed suites. */ + results const& + report() const + { + return m_results; + } + +private: + virtual void + on_suite_begin(suite_info const& info) override + { + m_suite = suite_results(info.full_name()); + } + + virtual void + on_suite_end() override + { + m_results.insert(std::move(m_suite)); + } + + virtual void + on_case_begin(std::string const& name) override + { + m_case = case_results(name); + } + + virtual void + on_case_end() override + { + if (m_case.tests.size() > 0) + m_suite.insert(std::move(m_case)); + } + + virtual void + on_pass() override + { + m_case.tests.pass(); + } + + virtual void + on_fail(std::string const& reason) override + { + m_case.tests.fail(reason); + } + + virtual void + on_log(std::string const& s) override + { + m_case.log.insert(s); + } +}; + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/reporter.h b/include/xrpl/beast/unit_test/reporter.h new file mode 100644 index 00000000000..e7a7d4b3adf --- /dev/null +++ b/include/xrpl/beast/unit_test/reporter.h @@ -0,0 +1,264 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_REPORTER_HPP +#define BEAST_UNIT_TEST_REPORTER_HPP + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace unit_test { + +namespace detail { + +/** A simple test runner that writes everything to a stream in real time. + The totals are output when the object is destroyed. +*/ +template +class reporter : public runner +{ +private: + using clock_type = std::chrono::steady_clock; + + struct case_results + { + std::string name; + std::size_t total = 0; + std::size_t failed = 0; + + explicit case_results(std::string name_ = "") : name(std::move(name_)) + { + } + }; + + struct suite_results + { + std::string name; + std::size_t cases = 0; + std::size_t total = 0; + std::size_t failed = 0; + typename clock_type::time_point start = clock_type::now(); + + explicit suite_results(std::string name_ = "") : name(std::move(name_)) + { + } + + void + add(case_results const& r); + }; + + struct results + { + using run_time = std::pair; + + enum { max_top = 10 }; + + std::size_t suites = 0; + std::size_t cases = 0; + std::size_t total = 0; + std::size_t failed = 0; + std::vector top; + typename clock_type::time_point start = clock_type::now(); + + void + add(suite_results const& r); + }; + + std::ostream& os_; + results results_; + suite_results suite_results_; + case_results case_results_; + +public: + reporter(reporter const&) = delete; + reporter& + operator=(reporter const&) = delete; + + ~reporter(); + + explicit reporter(std::ostream& os = std::cout); + +private: + static std::string + fmtdur(typename clock_type::duration const& d); + + virtual void + on_suite_begin(suite_info const& info) override; + + virtual void + on_suite_end() override; + + virtual void + on_case_begin(std::string const& name) override; + + virtual void + on_case_end() override; + + virtual void + on_pass() override; + + virtual void + on_fail(std::string const& reason) override; + + virtual void + on_log(std::string const& s) override; +}; + +//------------------------------------------------------------------------------ + +template +void +reporter<_>::suite_results::add(case_results const& r) +{ + ++cases; + total += r.total; + failed += r.failed; +} + +template +void +reporter<_>::results::add(suite_results const& r) +{ + ++suites; + total += r.total; + cases += r.cases; + failed += r.failed; + auto const elapsed = clock_type::now() - r.start; + if (elapsed >= std::chrono::seconds{1}) + { + auto const iter = std::lower_bound( + top.begin(), + top.end(), + elapsed, + [](run_time const& t1, typename clock_type::duration const& t2) { + return t1.second > t2; + }); + if (iter != top.end()) + { + if (top.size() == max_top) + top.resize(top.size() - 1); + top.emplace(iter, r.name, elapsed); + } + else if (top.size() < max_top) + { + top.emplace_back(r.name, elapsed); + } + } +} + +//------------------------------------------------------------------------------ + +template +reporter<_>::reporter(std::ostream& os) : os_(os) +{ +} + +template +reporter<_>::~reporter() +{ + if (results_.top.size() > 0) + { + os_ << "Longest suite times:\n"; + for (auto const& i : results_.top) + os_ << std::setw(8) << fmtdur(i.second) << " " << i.first << '\n'; + } + auto const elapsed = clock_type::now() - results_.start; + os_ << fmtdur(elapsed) << ", " << amount{results_.suites, "suite"} << ", " + << amount{results_.cases, "case"} << ", " + << amount{results_.total, "test"} << " total, " + << amount{results_.failed, "failure"} << std::endl; +} + +template +std::string +reporter<_>::fmtdur(typename clock_type::duration const& d) +{ + using namespace std::chrono; + auto const ms = duration_cast(d); + if (ms < seconds{1}) + return boost::lexical_cast(ms.count()) + "ms"; + std::stringstream ss; + ss << std::fixed << std::setprecision(1) << (ms.count() / 1000.) << "s"; + return ss.str(); +} + +template +void +reporter<_>::on_suite_begin(suite_info const& info) +{ + suite_results_ = suite_results{info.full_name()}; +} + +template +void +reporter<_>::on_suite_end() +{ + results_.add(suite_results_); +} + +template +void +reporter<_>::on_case_begin(std::string const& name) +{ + case_results_ = case_results(name); + os_ << suite_results_.name + << (case_results_.name.empty() ? "" : (" " + case_results_.name)) + << std::endl; +} + +template +void +reporter<_>::on_case_end() +{ + suite_results_.add(case_results_); +} + +template +void +reporter<_>::on_pass() +{ + ++case_results_.total; +} + +template +void +reporter<_>::on_fail(std::string const& reason) +{ + ++case_results_.failed; + ++case_results_.total; + os_ << "#" << case_results_.total << " failed" + << (reason.empty() ? "" : ": ") << reason << std::endl; +} + +template +void +reporter<_>::on_log(std::string const& s) +{ + os_ << s; +} + +} // namespace detail + +using reporter = detail::reporter<>; + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/results.h b/include/xrpl/beast/unit_test/results.h new file mode 100644 index 00000000000..96fedc9b75f --- /dev/null +++ b/include/xrpl/beast/unit_test/results.h @@ -0,0 +1,230 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_RESULTS_HPP +#define BEAST_UNIT_TEST_RESULTS_HPP + +#include + +#include +#include + +namespace beast { +namespace unit_test { + +/** Holds a set of test condition outcomes in a testcase. */ +class case_results +{ +public: + /** Holds the result of evaluating one test condition. */ + struct test + { + explicit test(bool pass_) : pass(pass_) + { + } + + test(bool pass_, std::string const& reason_) + : pass(pass_), reason(reason_) + { + } + + bool pass; + std::string reason; + }; + +private: + class tests_t : public detail::const_container> + { + private: + std::size_t failed_; + + public: + tests_t() : failed_(0) + { + } + + /** Returns the total number of test conditions. */ + std::size_t + total() const + { + return cont().size(); + } + + /** Returns the number of failed test conditions. */ + std::size_t + failed() const + { + return failed_; + } + + /** Register a successful test condition. */ + void + pass() + { + cont().emplace_back(true); + } + + /** Register a failed test condition. */ + void + fail(std::string const& reason = "") + { + ++failed_; + cont().emplace_back(false, reason); + } + }; + + class log_t : public detail::const_container> + { + public: + /** Insert a string into the log. */ + void + insert(std::string const& s) + { + cont().push_back(s); + } + }; + + std::string name_; + +public: + explicit case_results(std::string const& name = "") : name_(name) + { + } + + /** Returns the name of this testcase. */ + std::string const& + name() const + { + return name_; + } + + /** Memberspace for a container of test condition outcomes. */ + tests_t tests; + + /** Memberspace for a container of testcase log messages. */ + log_t log; +}; + +//-------------------------------------------------------------------------- + +/** Holds the set of testcase results in a suite. */ +class suite_results : public detail::const_container> +{ +private: + std::string name_; + std::size_t total_ = 0; + std::size_t failed_ = 0; + +public: + explicit suite_results(std::string const& name = "") : name_(name) + { + } + + /** Returns the name of this suite. */ + std::string const& + name() const + { + return name_; + } + + /** Returns the total number of test conditions. */ + std::size_t + total() const + { + return total_; + } + + /** Returns the number of failures. */ + std::size_t + failed() const + { + return failed_; + } + + /** Insert a set of testcase results. */ + /** @{ */ + void + insert(case_results&& r) + { + cont().emplace_back(std::move(r)); + total_ += r.tests.total(); + failed_ += r.tests.failed(); + } + + void + insert(case_results const& r) + { + cont().push_back(r); + total_ += r.tests.total(); + failed_ += r.tests.failed(); + } + /** @} */ +}; + +//------------------------------------------------------------------------------ + +// VFALCO TODO Make this a template class using scoped allocators +/** Holds the results of running a set of testsuites. */ +class results : public detail::const_container> +{ +private: + std::size_t m_cases; + std::size_t total_; + std::size_t failed_; + +public: + results() : m_cases(0), total_(0), failed_(0) + { + } + + /** Returns the total number of test cases. */ + std::size_t + cases() const + { + return m_cases; + } + + /** Returns the total number of test conditions. */ + std::size_t + total() const + { + return total_; + } + + /** Returns the number of failures. */ + std::size_t + failed() const + { + return failed_; + } + + /** Insert a set of suite results. */ + /** @{ */ + void + insert(suite_results&& r) + { + m_cases += r.size(); + total_ += r.total(); + failed_ += r.failed(); + cont().emplace_back(std::move(r)); + } + + void + insert(suite_results const& r) + { + m_cases += r.size(); + total_ += r.total(); + failed_ += r.failed(); + cont().push_back(r); + } + /** @} */ +}; + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/runner.h b/include/xrpl/beast/unit_test/runner.h new file mode 100644 index 00000000000..283f7c87238 --- /dev/null +++ b/include/xrpl/beast/unit_test/runner.h @@ -0,0 +1,284 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_RUNNER_H_INCLUDED +#define BEAST_UNIT_TEST_RUNNER_H_INCLUDED + +#include + +#include + +#include +#include +#include + +namespace beast { +namespace unit_test { + +/** Unit test runner interface. + + Derived classes can customize the reporting behavior. This interface is + injected into the unit_test class to receive the results of the tests. +*/ +class runner +{ + std::string arg_; + bool default_ = false; + bool failed_ = false; + bool cond_ = false; + std::recursive_mutex mutex_; + +public: + runner() = default; + virtual ~runner() = default; + runner(runner const&) = delete; + runner& + operator=(runner const&) = delete; + + /** Set the argument string. + + The argument string is available to suites and + allows for customization of the test. Each suite + defines its own syntax for the argumnet string. + The same argument is passed to all suites. + */ + void + arg(std::string const& s) + { + arg_ = s; + } + + /** Returns the argument string. */ + std::string const& + arg() const + { + return arg_; + } + + /** Run the specified suite. + @return `true` if any conditions failed. + */ + template + bool + run(suite_info const& s); + + /** Run a sequence of suites. + The expression + `FwdIter::value_type` + must be convertible to `suite_info`. + @return `true` if any conditions failed. + */ + template + bool + run(FwdIter first, FwdIter last); + + /** Conditionally run a sequence of suites. + pred will be called as: + @code + bool pred(suite_info const&); + @endcode + @return `true` if any conditions failed. + */ + template + bool + run_if(FwdIter first, FwdIter last, Pred pred = Pred{}); + + /** Run all suites in a container. + @return `true` if any conditions failed. + */ + template + bool + run_each(SequenceContainer const& c); + + /** Conditionally run suites in a container. + pred will be called as: + @code + bool pred(suite_info const&); + @endcode + @return `true` if any conditions failed. + */ + template + bool + run_each_if(SequenceContainer const& c, Pred pred = Pred{}); + +protected: + /// Called when a new suite starts. + virtual void + on_suite_begin(suite_info const&) + { + } + + /// Called when a suite ends. + virtual void + on_suite_end() + { + } + + /// Called when a new case starts. + virtual void + on_case_begin(std::string const&) + { + } + + /// Called when a new case ends. + virtual void + on_case_end() + { + } + + /// Called for each passing condition. + virtual void + on_pass() + { + } + + /// Called for each failing condition. + virtual void + on_fail(std::string const&) + { + } + + /// Called when a test logs output. + virtual void + on_log(std::string const&) + { + } + +private: + friend class suite; + + // Start a new testcase. + template + void + testcase(std::string const& name); + + template + void + pass(); + + template + void + fail(std::string const& reason); + + template + void + log(std::string const& s); +}; + +//------------------------------------------------------------------------------ + +template +bool +runner::run(suite_info const& s) +{ + // Enable 'default' testcase + default_ = true; + failed_ = false; + on_suite_begin(s); + s.run(*this); + // Forgot to call pass or fail. + BOOST_ASSERT(cond_); + on_case_end(); + on_suite_end(); + return failed_; +} + +template +bool +runner::run(FwdIter first, FwdIter last) +{ + bool failed(false); + for (; first != last; ++first) + failed = run(*first) || failed; + return failed; +} + +template +bool +runner::run_if(FwdIter first, FwdIter last, Pred pred) +{ + bool failed(false); + for (; first != last; ++first) + if (pred(*first)) + failed = run(*first) || failed; + return failed; +} + +template +bool +runner::run_each(SequenceContainer const& c) +{ + bool failed(false); + for (auto const& s : c) + failed = run(s) || failed; + return failed; +} + +template +bool +runner::run_each_if(SequenceContainer const& c, Pred pred) +{ + bool failed(false); + for (auto const& s : c) + if (pred(s)) + failed = run(s) || failed; + return failed; +} + +template +void +runner::testcase(std::string const& name) +{ + std::lock_guard lock(mutex_); + // Name may not be empty + BOOST_ASSERT(default_ || !name.empty()); + // Forgot to call pass or fail + BOOST_ASSERT(default_ || cond_); + if (!default_) + on_case_end(); + default_ = false; + cond_ = false; + on_case_begin(name); +} + +template +void +runner::pass() +{ + std::lock_guard lock(mutex_); + if (default_) + testcase(""); + on_pass(); + cond_ = true; +} + +template +void +runner::fail(std::string const& reason) +{ + std::lock_guard lock(mutex_); + if (default_) + testcase(""); + on_fail(reason); + failed_ = true; + cond_ = true; +} + +template +void +runner::log(std::string const& s) +{ + std::lock_guard lock(mutex_); + if (default_) + testcase(""); + on_log(s); +} + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/suite.h b/include/xrpl/beast/unit_test/suite.h new file mode 100644 index 00000000000..51cd3e17ea1 --- /dev/null +++ b/include/xrpl/beast/unit_test/suite.h @@ -0,0 +1,666 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_SUITE_HPP +#define BEAST_UNIT_TEST_SUITE_HPP + +#include + +#include +#include +#include + +#include +#include +#include + +namespace beast { +namespace unit_test { + +namespace detail { + +template +static std::string +make_reason(String const& reason, char const* file, int line) +{ + std::string s(reason); + if (!s.empty()) + s.append(": "); + namespace fs = boost::filesystem; + s.append(fs::path{file}.filename().string()); + s.append("("); + s.append(boost::lexical_cast(line)); + s.append(")"); + return s; +} + +} // namespace detail + +class thread; + +enum abort_t { no_abort_on_fail, abort_on_fail }; + +/** A testsuite class. + + Derived classes execute a series of testcases, where each testcase is + a series of pass/fail tests. To provide a unit test using this class, + derive from it and use the BEAST_DEFINE_UNIT_TEST macro in a + translation unit. +*/ +class suite +{ +private: + bool abort_ = false; + bool aborted_ = false; + runner* runner_ = nullptr; + + // This exception is thrown internally to stop the current suite + // in the event of a failure, if the option to stop is set. + struct abort_exception : public std::exception + { + char const* + what() const noexcept override + { + return "test suite aborted"; + } + }; + + template + class log_buf : public std::basic_stringbuf + { + suite& suite_; + + public: + explicit log_buf(suite& self) : suite_(self) + { + } + + ~log_buf() + { + sync(); + } + + int + sync() override + { + auto const& s = this->str(); + if (s.size() > 0) + suite_.runner_->log(s); + this->str(""); + return 0; + } + }; + + template < + class CharT, + class Traits = std::char_traits, + class Allocator = std::allocator> + class log_os : public std::basic_ostream + { + log_buf buf_; + + public: + explicit log_os(suite& self) + : std::basic_ostream(&buf_), buf_(self) + { + } + }; + + class scoped_testcase; + + class testcase_t + { + suite& suite_; + std::stringstream ss_; + + public: + explicit testcase_t(suite& self) : suite_(self) + { + } + + /** Open a new testcase. + + A testcase is a series of evaluated test conditions. A test + suite may have multiple test cases. A test is associated with + the last opened testcase. When the test first runs, a default + unnamed case is opened. Tests with only one case may omit the + call to testcase. + + @param abort Determines if suite continues running after a failure. + */ + void + operator()(std::string const& name, abort_t abort = no_abort_on_fail); + + scoped_testcase + operator()(abort_t abort); + + template + scoped_testcase + operator<<(T const& t); + }; + +public: + /** Logging output stream. + + Text sent to the log output stream will be forwarded to + the output stream associated with the runner. + */ + log_os log; + + /** Memberspace for declaring test cases. */ + testcase_t testcase; + + /** Returns the "current" running suite. + If no suite is running, nullptr is returned. + */ + static suite* + this_suite() + { + return *p_this_suite(); + } + + suite() : log(*this), testcase(*this) + { + } + + virtual ~suite() = default; + suite(suite const&) = delete; + suite& + operator=(suite const&) = delete; + + /** Invokes the test using the specified runner. + + Data members are set up here instead of the constructor as a + convenience to writing the derived class to avoid repetition of + forwarded constructor arguments to the base. + Normally this is called by the framework for you. + */ + template + void + operator()(runner& r); + + /** Record a successful test condition. */ + template + void + pass(); + + /** Record a failure. + + @param reason Optional text added to the output on a failure. + + @param file The source code file where the test failed. + + @param line The source code line number where the test failed. + */ + /** @{ */ + template + void + fail(String const& reason, char const* file, int line); + + template + void + fail(std::string const& reason = ""); + /** @} */ + + /** Evaluate a test condition. + + This function provides improved logging by incorporating the + file name and line number into the reported output on failure, + as well as additional text specified by the caller. + + @param shouldBeTrue The condition to test. The condition + is evaluated in a boolean context. + + @param reason Optional added text to output on a failure. + + @param file The source code file where the test failed. + + @param line The source code line number where the test failed. + + @return `true` if the test condition indicates success. + */ + /** @{ */ + template + bool + expect(Condition const& shouldBeTrue) + { + return expect(shouldBeTrue, ""); + } + + template + bool + expect(Condition const& shouldBeTrue, String const& reason); + + template + bool + expect(Condition const& shouldBeTrue, char const* file, int line) + { + return expect(shouldBeTrue, "", file, line); + } + + template + bool + expect( + Condition const& shouldBeTrue, + String const& reason, + char const* file, + int line); + /** @} */ + + // + // DEPRECATED + // + // Expect an exception from f() + template + bool + except(F&& f, String const& reason); + template + bool + except(F&& f) + { + return except(f, ""); + } + template + bool + except(F&& f, String const& reason); + template + bool + except(F&& f) + { + return except(f, ""); + } + template + bool + unexcept(F&& f, String const& reason); + template + bool + unexcept(F&& f) + { + return unexcept(f, ""); + } + + /** Return the argument associated with the runner. */ + std::string const& + arg() const + { + return runner_->arg(); + } + + // DEPRECATED + // @return `true` if the test condition indicates success(a false value) + template + bool + unexpected(Condition shouldBeFalse, String const& reason); + + template + bool + unexpected(Condition shouldBeFalse) + { + return unexpected(shouldBeFalse, ""); + } + +private: + friend class thread; + + static suite** + p_this_suite() + { + static suite* pts = nullptr; + return &pts; + } + + /** Runs the suite. */ + virtual void + run() = 0; + + void + propagate_abort(); + + template + void + run(runner& r); +}; + +//------------------------------------------------------------------------------ + +// Helper for streaming testcase names +class suite::scoped_testcase +{ +private: + suite& suite_; + std::stringstream& ss_; + +public: + scoped_testcase& + operator=(scoped_testcase const&) = delete; + + ~scoped_testcase() + { + auto const& name = ss_.str(); + if (!name.empty()) + suite_.runner_->testcase(name); + } + + scoped_testcase(suite& self, std::stringstream& ss) : suite_(self), ss_(ss) + { + ss_.clear(); + ss_.str({}); + } + + template + scoped_testcase(suite& self, std::stringstream& ss, T const& t) + : suite_(self), ss_(ss) + { + ss_.clear(); + ss_.str({}); + ss_ << t; + } + + template + scoped_testcase& + operator<<(T const& t) + { + ss_ << t; + return *this; + } +}; + +//------------------------------------------------------------------------------ + +inline void +suite::testcase_t::operator()(std::string const& name, abort_t abort) +{ + suite_.abort_ = abort == abort_on_fail; + suite_.runner_->testcase(name); +} + +inline suite::scoped_testcase +suite::testcase_t::operator()(abort_t abort) +{ + suite_.abort_ = abort == abort_on_fail; + return {suite_, ss_}; +} + +template +inline suite::scoped_testcase +suite::testcase_t::operator<<(T const& t) +{ + return {suite_, ss_, t}; +} + +//------------------------------------------------------------------------------ + +template +void +suite::operator()(runner& r) +{ + *p_this_suite() = this; + try + { + run(r); + *p_this_suite() = nullptr; + } + catch (...) + { + *p_this_suite() = nullptr; + throw; + } +} + +template +bool +suite::expect(Condition const& shouldBeTrue, String const& reason) +{ + if (shouldBeTrue) + { + pass(); + return true; + } + fail(reason); + return false; +} + +template +bool +suite::expect( + Condition const& shouldBeTrue, + String const& reason, + char const* file, + int line) +{ + if (shouldBeTrue) + { + pass(); + return true; + } + fail(detail::make_reason(reason, file, line)); + return false; +} + +// DEPRECATED + +template +bool +suite::except(F&& f, String const& reason) +{ + try + { + f(); + fail(reason); + return false; + } + catch (...) + { + pass(); + } + return true; +} + +template +bool +suite::except(F&& f, String const& reason) +{ + try + { + f(); + fail(reason); + return false; + } + catch (E const&) + { + pass(); + } + return true; +} + +template +bool +suite::unexcept(F&& f, String const& reason) +{ + try + { + f(); + pass(); + return true; + } + catch (...) + { + fail(reason); + } + return false; +} + +template +bool +suite::unexpected(Condition shouldBeFalse, String const& reason) +{ + bool const b = static_cast(shouldBeFalse); + if (!b) + pass(); + else + fail(reason); + return !b; +} + +template +void +suite::pass() +{ + propagate_abort(); + runner_->pass(); +} + +// ::fail +template +void +suite::fail(std::string const& reason) +{ + propagate_abort(); + runner_->fail(reason); + if (abort_) + { + aborted_ = true; + BOOST_THROW_EXCEPTION(abort_exception()); + } +} + +template +void +suite::fail(String const& reason, char const* file, int line) +{ + fail(detail::make_reason(reason, file, line)); +} + +inline void +suite::propagate_abort() +{ + if (abort_ && aborted_) + BOOST_THROW_EXCEPTION(abort_exception()); +} + +template +void +suite::run(runner& r) +{ + runner_ = &r; + + try + { + run(); + } + catch (abort_exception const&) + { + // ends the suite + } + catch (std::exception const& e) + { + runner_->fail("unhandled exception: " + std::string(e.what())); + } + catch (...) + { + runner_->fail("unhandled exception"); + } +} + +#ifndef BEAST_EXPECT +/** Check a precondition. + + If the condition is false, the file and line number are reported. +*/ +#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__) +#endif + +#ifndef BEAST_EXPECTS +/** Check a precondition. + + If the condition is false, the file and line number are reported. +*/ +#define BEAST_EXPECTS(cond, reason) \ + ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false)) +#endif + +} // namespace unit_test +} // namespace beast + +//------------------------------------------------------------------------------ + +// detail: +// This inserts the suite with the given manual flag +#define BEAST_DEFINE_TESTSUITE_INSERT( \ + Class, Module, Library, manual, priority) \ + static beast::unit_test::detail::insert_suite \ + Library##Module##Class##_test_instance( \ + #Class, #Module, #Library, manual, priority) + +//------------------------------------------------------------------------------ + +// Preprocessor directives for controlling unit test definitions. + +// If this is already defined, don't redefine it. This allows +// programs to provide custom behavior for testsuite definitions +// +#ifndef BEAST_DEFINE_TESTSUITE + +/** Enables insertion of test suites into the global container. + The default is to insert all test suite definitions into the global + container. If BEAST_DEFINE_TESTSUITE is user defined, this macro + has no effect. +*/ +#ifndef BEAST_NO_UNIT_TEST_INLINE +#define BEAST_NO_UNIT_TEST_INLINE 0 +#endif + +/** Define a unit test suite. + + Class The type representing the class being tested. + Module Identifies the module. + Library Identifies the library. + + The declaration for the class implementing the test should be the same + as Class ## _test. For example, if Class is aged_ordered_container, the + test class must be declared as: + + @code + + struct aged_ordered_container_test : beast::unit_test::suite + { + //... + }; + + @endcode + + The macro invocation must appear in the same namespace as the test class. + + Unit test priorities were introduced so parallel unit_test::suites would + execute faster. Suites with longer running times have higher priorities + than unit tests with shorter running times. Suites with no priorities + are assumed to run most quickly, so they run last. +*/ + +#if BEAST_NO_UNIT_TEST_INLINE +#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) +#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) +#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority) +#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority) + +#else +#include +#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \ + BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0) +#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \ + BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, 0) +#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority) \ + BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, Priority) +#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority) \ + BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, Priority) +#endif + +#endif + +//------------------------------------------------------------------------------ + +#endif diff --git a/include/xrpl/beast/unit_test/suite_info.h b/include/xrpl/beast/unit_test/suite_info.h new file mode 100644 index 00000000000..a7e63d606c8 --- /dev/null +++ b/include/xrpl/beast/unit_test/suite_info.h @@ -0,0 +1,125 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_SUITE_INFO_HPP +#define BEAST_UNIT_TEST_SUITE_INFO_HPP + +#include +#include +#include +#include + +namespace beast { +namespace unit_test { + +class runner; + +/** Associates a unit test type with metadata. */ +class suite_info +{ + using run_type = std::function; + + std::string name_; + std::string module_; + std::string library_; + bool manual_; + int priority_; + run_type run_; + +public: + suite_info( + std::string name, + std::string module, + std::string library, + bool manual, + int priority, + run_type run) + : name_(std::move(name)) + , module_(std::move(module)) + , library_(std::move(library)) + , manual_(manual) + , priority_(priority) + , run_(std::move(run)) + { + } + + std::string const& + name() const + { + return name_; + } + + std::string const& + module() const + { + return module_; + } + + std::string const& + library() const + { + return library_; + } + + /// Returns `true` if this suite only runs manually. + bool + manual() const + { + return manual_; + } + + /// Return the canonical suite name as a string. + std::string + full_name() const + { + return library_ + "." + module_ + "." + name_; + } + + /// Run a new instance of the associated test suite. + void + run(runner& r) const + { + run_(r); + } + + friend bool + operator<(suite_info const& lhs, suite_info const& rhs) + { + // we want higher priority suites sorted first, thus the negation + // of priority value here + return std::forward_as_tuple( + -lhs.priority_, lhs.library_, lhs.module_, lhs.name_) < + std::forward_as_tuple( + -rhs.priority_, rhs.library_, rhs.module_, rhs.name_); + } +}; + +//------------------------------------------------------------------------------ + +/// Convenience for producing suite_info for a given test type. +template +suite_info +make_suite_info( + std::string name, + std::string module, + std::string library, + bool manual, + int priority) +{ + return suite_info( + std::move(name), + std::move(module), + std::move(library), + manual, + priority, + [](runner& r) { Suite{}(r); }); +} + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/suite_list.h b/include/xrpl/beast/unit_test/suite_list.h new file mode 100644 index 00000000000..0095290eaca --- /dev/null +++ b/include/xrpl/beast/unit_test/suite_list.h @@ -0,0 +1,78 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_SUITE_LIST_HPP +#define BEAST_UNIT_TEST_SUITE_LIST_HPP + +#include +#include + +#include + +#include +#include +#include + +namespace beast { +namespace unit_test { + +/// A container of test suites. +class suite_list : public detail::const_container> +{ +private: +#ifndef NDEBUG + std::unordered_set names_; + std::unordered_set classes_; +#endif + +public: + /** Insert a suite into the set. + + The suite must not already exist. + */ + template + void + insert( + char const* name, + char const* module, + char const* library, + bool manual, + int priority); +}; + +//------------------------------------------------------------------------------ + +template +void +suite_list::insert( + char const* name, + char const* module, + char const* library, + bool manual, + int priority) +{ +#ifndef NDEBUG + { + std::string s; + s = std::string(library) + "." + module + "." + name; + auto const result(names_.insert(s)); + BOOST_ASSERT(result.second); // Duplicate name + } + + { + auto const result(classes_.insert(std::type_index(typeid(Suite)))); + BOOST_ASSERT(result.second); // Duplicate type + } +#endif + cont().emplace( + make_suite_info(name, module, library, manual, priority)); +} + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/unit_test/thread.h b/include/xrpl/beast/unit_test/thread.h new file mode 100644 index 00000000000..99572a549d9 --- /dev/null +++ b/include/xrpl/beast/unit_test/thread.h @@ -0,0 +1,119 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_UNIT_TEST_THREAD_HPP +#define BEAST_UNIT_TEST_THREAD_HPP + +#include + +#include +#include +#include + +namespace beast { +namespace unit_test { + +/** Replacement for std::thread that handles exceptions in unit tests. */ +class thread +{ +private: + suite* s_ = nullptr; + std::thread t_; + +public: + using id = std::thread::id; + using native_handle_type = std::thread::native_handle_type; + + thread() = default; + thread(thread const&) = delete; + thread& + operator=(thread const&) = delete; + + thread(thread&& other) : s_(other.s_), t_(std::move(other.t_)) + { + } + + thread& + operator=(thread&& other) + { + s_ = other.s_; + t_ = std::move(other.t_); + return *this; + } + + template + explicit thread(suite& s, F&& f, Args&&... args) : s_(&s) + { + std::function b = + std::bind(std::forward(f), std::forward(args)...); + t_ = std::thread(&thread::run, this, std::move(b)); + } + + bool + joinable() const + { + return t_.joinable(); + } + + std::thread::id + get_id() const + { + return t_.get_id(); + } + + static unsigned + hardware_concurrency() noexcept + { + return std::thread::hardware_concurrency(); + } + + void + join() + { + t_.join(); + s_->propagate_abort(); + } + + void + detach() + { + t_.detach(); + } + + void + swap(thread& other) + { + std::swap(s_, other.s_); + std::swap(t_, other.t_); + } + +private: + void + run(std::function f) + { + try + { + f(); + } + catch (suite::abort_exception const&) + { + } + catch (std::exception const& e) + { + s_->fail("unhandled exception: " + std::string(e.what())); + } + catch (...) + { + s_->fail("unhandled exception"); + } + } +}; + +} // namespace unit_test +} // namespace beast + +#endif diff --git a/include/xrpl/beast/utility/Journal.h b/include/xrpl/beast/utility/Journal.h new file mode 100644 index 00000000000..91ddf33d271 --- /dev/null +++ b/include/xrpl/beast/utility/Journal.h @@ -0,0 +1,463 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_UTILITY_JOURNAL_H_INCLUDED +#define BEAST_UTILITY_JOURNAL_H_INCLUDED + +#include + +#include + +namespace beast { + +/** A namespace for easy access to logging severity values. */ +namespace severities { +/** Severity level / threshold of a Journal message. */ +enum Severity { + kAll = 0, + + kTrace = kAll, + kDebug, + kInfo, + kWarning, + kError, + kFatal, + + kDisabled, + kNone = kDisabled +}; +} // namespace severities + +/** A generic endpoint for log messages. + + The Journal has a few simple goals: + + * To be light-weight and copied by value. + * To allow logging statements to be left in source code. + * The logging is controlled at run-time based on a logging threshold. + + It is advisable to check Journal::active(level) prior to formatting log + text. Doing so sidesteps expensive text formatting when the results + will not be sent to the log. +*/ +class Journal +{ +public: + class Sink; + +private: + // Severity level / threshold of a Journal message. + using Severity = severities::Severity; + + // Invariant: m_sink always points to a valid Sink + Sink* m_sink; + +public: + //-------------------------------------------------------------------------- + + /** Abstraction for the underlying message destination. */ + class Sink + { + protected: + Sink() = delete; + explicit Sink(Sink const& sink) = default; + Sink(Severity thresh, bool console); + Sink& + operator=(Sink const& lhs) = delete; + + public: + virtual ~Sink() = 0; + + /** Returns `true` if text at the passed severity produces output. */ + virtual bool + active(Severity level) const; + + /** Returns `true` if a message is also written to the Output Window + * (MSVC). */ + virtual bool + console() const; + + /** Set whether messages are also written to the Output Window (MSVC). + */ + virtual void + console(bool output); + + /** Returns the minimum severity level this sink will report. */ + virtual Severity + threshold() const; + + /** Set the minimum severity this sink will report. */ + virtual void + threshold(Severity thresh); + + /** Write text to the sink at the specified severity. + A conforming implementation will not write the text if the passed + level is below the current threshold(). + */ + virtual void + write(Severity level, std::string const& text) = 0; + + /** Bypass filter and write text to the sink at the specified severity. + * Always write the message, but maintain the same formatting as if + * it passed through a level filter. + * + * @param level Level to display in message. + * @param text Text to write to sink. + */ + virtual void + writeAlways(Severity level, std::string const& text) = 0; + + private: + Severity thresh_; + bool m_console; + }; + +#ifndef __INTELLISENSE__ + static_assert(std::is_default_constructible::value == false, ""); + static_assert(std::is_copy_constructible::value == false, ""); + static_assert(std::is_move_constructible::value == false, ""); + static_assert(std::is_copy_assignable::value == false, ""); + static_assert(std::is_move_assignable::value == false, ""); + static_assert(std::is_nothrow_destructible::value == true, ""); +#endif + + /** Returns a Sink which does nothing. */ + static Sink& + getNullSink(); + + //-------------------------------------------------------------------------- + + class Stream; + + /* Scoped ostream-based container for writing messages to a Journal. */ + class ScopedStream + { + public: + ScopedStream(ScopedStream const& other) + : ScopedStream(other.m_sink, other.m_level) + { + } + + ScopedStream(Sink& sink, Severity level); + + template + ScopedStream(Stream const& stream, T const& t); + + ScopedStream(Stream const& stream, std::ostream& manip(std::ostream&)); + + ScopedStream& + operator=(ScopedStream const&) = delete; + + ~ScopedStream(); + + std::ostringstream& + ostream() const + { + return m_ostream; + } + + std::ostream& + operator<<(std::ostream& manip(std::ostream&)) const; + + template + std::ostream& + operator<<(T const& t) const; + + private: + Sink& m_sink; + Severity const m_level; + std::ostringstream mutable m_ostream; + }; + +#ifndef __INTELLISENSE__ + static_assert( + std::is_default_constructible::value == false, + ""); + static_assert(std::is_copy_constructible::value == true, ""); + static_assert(std::is_move_constructible::value == true, ""); + static_assert(std::is_copy_assignable::value == false, ""); + static_assert(std::is_move_assignable::value == false, ""); + static_assert( + std::is_nothrow_destructible::value == true, + ""); +#endif + + //-------------------------------------------------------------------------- +public: + /** Provide a light-weight way to check active() before string formatting */ + class Stream + { + public: + /** Create a stream which produces no output. */ + explicit Stream() + : m_sink(getNullSink()), m_level(severities::kDisabled) + { + } + + /** Create a stream that writes at the given level. + + Constructor is inlined so checking active() very inexpensive. + */ + Stream(Sink& sink, Severity level) : m_sink(sink), m_level(level) + { + XRPL_ASSERT( + m_level < severities::kDisabled, + "beast::Journal::Stream::Stream : maximum level"); + } + + /** Construct or copy another Stream. */ + Stream(Stream const& other) : Stream(other.m_sink, other.m_level) + { + } + + Stream& + operator=(Stream const& other) = delete; + + /** Returns the Sink that this Stream writes to. */ + Sink& + sink() const + { + return m_sink; + } + + /** Returns the Severity level of messages this Stream reports. */ + Severity + level() const + { + return m_level; + } + + /** Returns `true` if sink logs anything at this stream's level. */ + /** @{ */ + bool + active() const + { + return m_sink.active(m_level); + } + + explicit + operator bool() const + { + return active(); + } + /** @} */ + + /** Output stream support. */ + /** @{ */ + ScopedStream + operator<<(std::ostream& manip(std::ostream&)) const; + + template + ScopedStream + operator<<(T const& t) const; + /** @} */ + + private: + Sink& m_sink; + Severity m_level; + }; + +#ifndef __INTELLISENSE__ + static_assert(std::is_default_constructible::value == true, ""); + static_assert(std::is_copy_constructible::value == true, ""); + static_assert(std::is_move_constructible::value == true, ""); + static_assert(std::is_copy_assignable::value == false, ""); + static_assert(std::is_move_assignable::value == false, ""); + static_assert(std::is_nothrow_destructible::value == true, ""); +#endif + + //-------------------------------------------------------------------------- + + /** Journal has no default constructor. */ + Journal() = delete; + + /** Create a journal that writes to the specified sink. */ + explicit Journal(Sink& sink) : m_sink(&sink) + { + } + + /** Returns the Sink associated with this Journal. */ + Sink& + sink() const + { + return *m_sink; + } + + /** Returns a stream for this sink, with the specified severity level. */ + Stream + stream(Severity level) const + { + return Stream(*m_sink, level); + } + + /** Returns `true` if any message would be logged at this severity level. + For a message to be logged, the severity must be at or above the + sink's severity threshold. + */ + bool + active(Severity level) const + { + return m_sink->active(level); + } + + /** Severity stream access functions. */ + /** @{ */ + Stream + trace() const + { + return {*m_sink, severities::kTrace}; + } + + Stream + debug() const + { + return {*m_sink, severities::kDebug}; + } + + Stream + info() const + { + return {*m_sink, severities::kInfo}; + } + + Stream + warn() const + { + return {*m_sink, severities::kWarning}; + } + + Stream + error() const + { + return {*m_sink, severities::kError}; + } + + Stream + fatal() const + { + return {*m_sink, severities::kFatal}; + } + /** @} */ +}; + +#ifndef __INTELLISENSE__ +static_assert(std::is_default_constructible::value == false, ""); +static_assert(std::is_copy_constructible::value == true, ""); +static_assert(std::is_move_constructible::value == true, ""); +static_assert(std::is_copy_assignable::value == true, ""); +static_assert(std::is_move_assignable::value == true, ""); +static_assert(std::is_nothrow_destructible::value == true, ""); +#endif + +//------------------------------------------------------------------------------ + +template +Journal::ScopedStream::ScopedStream(Journal::Stream const& stream, T const& t) + : ScopedStream(stream.sink(), stream.level()) +{ + m_ostream << t; +} + +template +std::ostream& +Journal::ScopedStream::operator<<(T const& t) const +{ + m_ostream << t; + return m_ostream; +} + +//------------------------------------------------------------------------------ + +template +Journal::ScopedStream +Journal::Stream::operator<<(T const& t) const +{ + return ScopedStream(*this, t); +} + +namespace detail { + +template > +class logstream_buf : public std::basic_stringbuf +{ + beast::Journal::Stream strm_; + + template + void + write(T const*) = delete; + + void + write(char const* s) + { + if (strm_) + strm_ << s; + } + + void + write(wchar_t const* s) + { + if (strm_) + strm_ << s; + } + +public: + explicit logstream_buf(beast::Journal::Stream const& strm) : strm_(strm) + { + } + + ~logstream_buf() + { + sync(); + } + + int + sync() override + { + write(this->str().c_str()); + this->str(""); + return 0; + } +}; + +} // namespace detail + +template > +class basic_logstream : public std::basic_ostream +{ + typedef CharT char_type; + typedef Traits traits_type; + typedef typename traits_type::int_type int_type; + typedef typename traits_type::pos_type pos_type; + typedef typename traits_type::off_type off_type; + + detail::logstream_buf buf_; + +public: + explicit basic_logstream(beast::Journal::Stream const& strm) + : std::basic_ostream(&buf_), buf_(strm) + { + } +}; + +using logstream = basic_logstream; +using logwstream = basic_logstream; + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/utility/PropertyStream.h b/include/xrpl/beast/utility/PropertyStream.h new file mode 100644 index 00000000000..18895e2410a --- /dev/null +++ b/include/xrpl/beast/utility/PropertyStream.h @@ -0,0 +1,431 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED +#define BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED + +#include + +#include +#include +#include + +namespace beast { + +//------------------------------------------------------------------------------ + +/** Abstract stream with RAII containers that produce a property tree. */ +class PropertyStream +{ +public: + class Map; + class Set; + class Source; + + PropertyStream() = default; + virtual ~PropertyStream() = default; + +protected: + virtual void + map_begin() = 0; + virtual void + map_begin(std::string const& key) = 0; + virtual void + map_end() = 0; + + virtual void + add(std::string const& key, std::string const& value) = 0; + + void + add(std::string const& key, char const* value) + { + add(key, std::string(value)); + } + + template + void + lexical_add(std::string const& key, Value value) + { + std::stringstream ss; + ss << value; + add(key, ss.str()); + } + + virtual void + add(std::string const& key, bool value); + virtual void + add(std::string const& key, char value); + virtual void + add(std::string const& key, signed char value); + virtual void + add(std::string const& key, unsigned char value); + virtual void + add(std::string const& key, short value); + virtual void + add(std::string const& key, unsigned short value); + virtual void + add(std::string const& key, int value); + virtual void + add(std::string const& key, unsigned int value); + virtual void + add(std::string const& key, long value); + virtual void + add(std::string const& key, unsigned long value); + virtual void + add(std::string const& key, long long value); + virtual void + add(std::string const& key, unsigned long long value); + virtual void + add(std::string const& key, float value); + virtual void + add(std::string const& key, double value); + virtual void + add(std::string const& key, long double value); + + virtual void + array_begin() = 0; + virtual void + array_begin(std::string const& key) = 0; + virtual void + array_end() = 0; + + virtual void + add(std::string const& value) = 0; + + void + add(char const* value) + { + add(std::string(value)); + } + + template + void + lexical_add(Value value) + { + std::stringstream ss; + ss << value; + add(ss.str()); + } + + virtual void + add(bool value); + virtual void + add(char value); + virtual void + add(signed char value); + virtual void + add(unsigned char value); + virtual void + add(short value); + virtual void + add(unsigned short value); + virtual void + add(int value); + virtual void + add(unsigned int value); + virtual void + add(long value); + virtual void + add(unsigned long value); + virtual void + add(long long value); + virtual void + add(unsigned long long value); + virtual void + add(float value); + virtual void + add(double value); + virtual void + add(long double value); + +private: + class Item; + class Proxy; +}; + +//------------------------------------------------------------------------------ +// +// Item +// +//------------------------------------------------------------------------------ + +class PropertyStream::Item : public List::Node +{ +public: + explicit Item(Source* source); + Source& + source() const; + Source* + operator->() const; + Source& + operator*() const; + +private: + Source* m_source; +}; + +//------------------------------------------------------------------------------ +// +// Proxy +// +//------------------------------------------------------------------------------ + +class PropertyStream::Proxy +{ +private: + Map const* m_map; + std::string m_key; + std::ostringstream mutable m_ostream; + +public: + Proxy(Map const& map, std::string const& key); + Proxy(Proxy const& other); + ~Proxy(); + + template + Proxy& + operator=(Value value); + + std::ostream& + operator<<(std::ostream& manip(std::ostream&)) const; + + template + std::ostream& + operator<<(T const& t) const + { + return m_ostream << t; + } +}; + +//------------------------------------------------------------------------------ +// +// Map +// +//------------------------------------------------------------------------------ + +class PropertyStream::Map +{ +private: + PropertyStream& m_stream; + +public: + explicit Map(PropertyStream& stream); + explicit Map(Set& parent); + Map(std::string const& key, Map& parent); + Map(std::string const& key, PropertyStream& stream); + ~Map(); + + Map(Map const&) = delete; + Map& + operator=(Map const&) = delete; + + PropertyStream& + stream(); + PropertyStream const& + stream() const; + + template + void + add(std::string const& key, Value value) const + { + m_stream.add(key, value); + } + + template + void + add(Key key, Value value) const + { + std::stringstream ss; + ss << key; + add(ss.str(), value); + } + + Proxy + operator[](std::string const& key); + + Proxy + operator[](char const* key) + { + return Proxy(*this, key); + } + + template + Proxy + operator[](Key key) const + { + std::stringstream ss; + ss << key; + return Proxy(*this, ss.str()); + } +}; + +//-------------------------------------------------------------------------- + +template +PropertyStream::Proxy& +PropertyStream::Proxy::operator=(Value value) +{ + m_map->add(m_key, value); + return *this; +} + +//-------------------------------------------------------------------------- +// +// Set +// +//------------------------------------------------------------------------------ + +class PropertyStream::Set +{ +private: + PropertyStream& m_stream; + +public: + Set(std::string const& key, Map& map); + Set(std::string const& key, PropertyStream& stream); + ~Set(); + + Set(Set const&) = delete; + Set& + operator=(Set const&) = delete; + + PropertyStream& + stream(); + PropertyStream const& + stream() const; + + template + void + add(Value value) const + { + m_stream.add(value); + } +}; + +//------------------------------------------------------------------------------ +// +// Source +// +//------------------------------------------------------------------------------ + +/** Subclasses can be called to write to a stream and have children. */ +class PropertyStream::Source +{ +private: + std::string const m_name; + std::recursive_mutex lock_; + Item item_; + Source* parent_; + List children_; + +public: + explicit Source(std::string const& name); + virtual ~Source(); + + Source(Source const&) = delete; + Source& + operator=(Source const&) = delete; + + /** Returns the name of this source. */ + std::string const& + name() const; + + /** Add a child source. */ + void + add(Source& source); + + /** Add a child source by pointer. + The source pointer is returned so it can be used in ctor-initializers. + */ + template + Derived* + add(Derived* child) + { + add(*static_cast(child)); + return child; + } + + /** Remove a child source from this Source. */ + void + remove(Source& child); + + /** Remove all child sources from this Source. */ + void + removeAll(); + + /** Write only this Source to the stream. */ + void + write_one(PropertyStream& stream); + + /** write this source and all its children recursively to the stream. */ + void + write(PropertyStream& stream); + + /** Parse the path and write the corresponding Source and optional children. + If the source is found, it is written. If the wildcard character '*' + exists as the last character in the path, then all the children are + written recursively. + */ + void + write(PropertyStream& stream, std::string const& path); + + /** Parse the dot-delimited Source path and return the result. + The first value will be a pointer to the Source object corresponding + to the given path. If no Source object exists, then the first value + will be nullptr and the second value will be undefined. + The second value is a boolean indicating whether or not the path string + specifies the wildcard character '*' as the last character. + + print statement examples + "parent.child" prints child and all of its children + "parent.child." start at the parent and print down to child + "parent.grandchild" prints nothing- grandchild not direct discendent + "parent.grandchild." starts at the parent and prints down to grandchild + "parent.grandchild.*" starts at parent, print through grandchild + children + */ + std::pair + find(std::string path); + + Source* + find_one_deep(std::string const& name); + PropertyStream::Source* + find_path(std::string path); + PropertyStream::Source* + find_one(std::string const& name); + + static bool + peel_leading_slash(std::string* path); + static bool + peel_trailing_slashstar(std::string* path); + static std::string + peel_name(std::string* path); + + //-------------------------------------------------------------------------- + + /** Subclass override. + The default version does nothing. + */ + virtual void + onWrite(Map&); +}; + +} // namespace beast + +#endif diff --git a/include/xrpl/beast/utility/WrappedSink.h b/include/xrpl/beast/utility/WrappedSink.h new file mode 100644 index 00000000000..72dcf4e8f59 --- /dev/null +++ b/include/xrpl/beast/utility/WrappedSink.h @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_UTILITY_WRAPPEDSINK_H_INCLUDED +#define BEAST_UTILITY_WRAPPEDSINK_H_INCLUDED + +#include + +namespace beast { + +/** Wraps a Journal::Sink to prefix its output with a string. */ + +// A WrappedSink both is a Sink and has a Sink: +// o It inherits from Sink so it has the correct interface. +// o It has a sink (reference) so it preserves the passed write() behavior. +// The data inherited from the base class is ignored. +class WrappedSink : public beast::Journal::Sink +{ +private: + beast::Journal::Sink& sink_; + std::string prefix_; + +public: + explicit WrappedSink( + beast::Journal::Sink& sink, + std::string const& prefix = "") + : Sink(sink), sink_(sink), prefix_(prefix) + { + } + + explicit WrappedSink( + beast::Journal const& journal, + std::string const& prefix = "") + : WrappedSink(journal.sink(), prefix) + { + } + + void + prefix(std::string const& s) + { + prefix_ = s; + } + + bool + active(beast::severities::Severity level) const override + { + return sink_.active(level); + } + + bool + console() const override + { + return sink_.console(); + } + + void + console(bool output) override + { + sink_.console(output); + } + + beast::severities::Severity + threshold() const override + { + return sink_.threshold(); + } + + void + threshold(beast::severities::Severity thresh) override + { + sink_.threshold(thresh); + } + + void + write(beast::severities::Severity level, std::string const& text) override + { + using beast::Journal; + sink_.write(level, prefix_ + text); + } + + void + writeAlways(severities::Severity level, std::string const& text) override + { + using beast::Journal; + sink_.writeAlways(level, prefix_ + text); + } +}; + +} // namespace beast + +#endif diff --git a/src/ripple/beast/utility/Zero.h b/include/xrpl/beast/utility/Zero.h similarity index 86% rename from src/ripple/beast/utility/Zero.h rename to include/xrpl/beast/utility/Zero.h index d2317474995..efd4d6d667f 100644 --- a/src/ripple/beast/utility/Zero.h +++ b/include/xrpl/beast/utility/Zero.h @@ -50,7 +50,8 @@ static constexpr Zero zero{}; /** Default implementation of signum calls the method on the class. */ template -auto signum(T const& t) +auto +signum(T const& t) { return t.signum(); } @@ -61,48 +62,55 @@ namespace zero_helper { // For argument dependent lookup to function properly, calls to signum must // be made from a namespace that does not include overloads of the function.. template -auto call_signum(T const& t) +auto +call_signum(T const& t) { return signum(t); } -} // zero_helper -} // detail +} // namespace zero_helper +} // namespace detail // Handle operators where T is on the left side using signum. template -bool operator==(T const& t, Zero) +bool +operator==(T const& t, Zero) { return detail::zero_helper::call_signum(t) == 0; } template -bool operator!=(T const& t, Zero) +bool +operator!=(T const& t, Zero) { return detail::zero_helper::call_signum(t) != 0; } template -bool operator<(T const& t, Zero) +bool +operator<(T const& t, Zero) { return detail::zero_helper::call_signum(t) < 0; } template -bool operator>(T const& t, Zero) +bool +operator>(T const& t, Zero) { return detail::zero_helper::call_signum(t) > 0; } template -bool operator>=(T const& t, Zero) +bool +operator>=(T const& t, Zero) { return detail::zero_helper::call_signum(t) >= 0; } template -bool operator<=(T const& t, Zero) +bool +operator<=(T const& t, Zero) { return detail::zero_helper::call_signum(t) <= 0; } @@ -111,41 +119,47 @@ bool operator<=(T const& t, Zero) // reversing the operation, so that T is on the left side. template -bool operator==(Zero, T const& t) +bool +operator==(Zero, T const& t) { return t == zero; } template -bool operator!=(Zero, T const& t) +bool +operator!=(Zero, T const& t) { return t != zero; } template -bool operator<(Zero, T const& t) +bool +operator<(Zero, T const& t) { return t > zero; } template -bool operator>(Zero, T const& t) +bool +operator>(Zero, T const& t) { return t < zero; } template -bool operator>=(Zero, T const& t) +bool +operator>=(Zero, T const& t) { return t <= zero; } template -bool operator<=(Zero, T const& t) +bool +operator<=(Zero, T const& t) { return t >= zero; } -} // beast +} // namespace beast #endif diff --git a/include/xrpl/beast/utility/instrumentation.h b/include/xrpl/beast/utility/instrumentation.h new file mode 100644 index 00000000000..72c48959a04 --- /dev/null +++ b/include/xrpl/beast/utility/instrumentation.h @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +/* +This file is part of rippled: https://github.com/ripple/rippled +Copyright (c) 2024 Ripple Labs Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_UTILITY_INSTRUMENTATION_H_INCLUDED +#define BEAST_UTILITY_INSTRUMENTATION_H_INCLUDED + +#include + +#ifdef ENABLE_VOIDSTAR +#ifdef NDEBUG +#error "Antithesis instrumentation requires Debug build" +#endif +#include +#else +// Macros below are copied from antithesis_sdk.h and slightly simplified +// The duplication is because Visual Studio 2019 cannot compile that header +// even with the option -Zc:__cplusplus added. +#define ALWAYS(cond, message, ...) assert((message) && (cond)) +#define ALWAYS_OR_UNREACHABLE(cond, message, ...) assert((message) && (cond)) +#define SOMETIMES(cond, message, ...) +#define REACHABLE(message, ...) +#define UNREACHABLE(message, ...) assert((message) && false) +#endif + +#define XRPL_ASSERT ALWAYS_OR_UNREACHABLE + +// How to use the instrumentation macros: +// +// * XRPL_ASSERT if cond must be true but the line might not be reached during +// fuzzing. Same like `assert` in normal use. +// * ALWAYS if cond must be true _and_ the line must be reached during fuzzing. +// Same like `assert` in normal use. +// * REACHABLE if the line must be reached during fuzzing +// * SOMETIMES a hint for the fuzzer to try to make the cond true +// * UNREACHABLE if the line must not be reached (in fuzzing or in normal use). +// Same like `assert(false)` in normal use. +// +// NOTE: XRPL_ASSERT has similar semantics as C `assert` macro, with only minor +// differences: +// * XRPL_ASSERT must have an unique name (naming convention in CONTRIBUTING.md) +// * during fuzzing, the program will continue execution past failed XRPL_ASSERT +// +// We continue to use regular C `assert` inside unit tests and inside constexpr +// functions. +// +// NOTE: UNREACHABLE does *not* have the same semantics as std::unreachable. +// The program will continue execution past an UNREACHABLE in a Release build +// and during fuzzing (similar to failed XRPL_ASSERT). +// Also, the naming convention in UNREACHABLE is subtly different from other +// instrumentation macros - its name describes the condition which was _not_ +// meant to happen, while name in other macros describes the condition that is +// meant to happen (e.g. as in "assert that this happens"). + +#endif diff --git a/src/ripple/beast/utility/maybe_const.h b/include/xrpl/beast/utility/maybe_const.h similarity index 85% rename from src/ripple/beast/utility/maybe_const.h rename to include/xrpl/beast/utility/maybe_const.h index 9cddbf41785..c1c01490c96 100644 --- a/src/ripple/beast/utility/maybe_const.h +++ b/include/xrpl/beast/utility/maybe_const.h @@ -29,15 +29,16 @@ template struct maybe_const { explicit maybe_const() = default; - using type = typename std::conditional ::type const, - typename std::remove_const ::type>::type; + using type = typename std::conditional< + IsConst, + typename std::remove_const::type const, + typename std::remove_const::type>::type; }; /** Alias for omitting `typename`. */ template -using maybe_const_t = typename maybe_const ::type; +using maybe_const_t = typename maybe_const::type; -} +} // namespace beast #endif diff --git a/include/xrpl/beast/utility/rngfill.h b/include/xrpl/beast/utility/rngfill.h new file mode 100644 index 00000000000..0188e5c5294 --- /dev/null +++ b/include/xrpl/beast/utility/rngfill.h @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2014, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_RANDOM_RNGFILL_H_INCLUDED +#define BEAST_RANDOM_RNGFILL_H_INCLUDED + +#include + +#include +#include +#include +#include + +namespace beast { + +template +void +rngfill(void* buffer, std::size_t bytes, Generator& g) +{ + using result_type = typename Generator::result_type; + + while (bytes >= sizeof(result_type)) + { + auto const v = g(); + std::memcpy(buffer, &v, sizeof(v)); + buffer = reinterpret_cast(buffer) + sizeof(v); + bytes -= sizeof(v); + } + + XRPL_ASSERT( + bytes < sizeof(result_type), "beast::rngfill(void*) : maximum bytes"); + +#ifdef __GNUC__ + // gcc 11.1 (falsely) warns about an array-bounds overflow in release mode. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif + + if (bytes > 0) + { + auto const v = g(); + std::memcpy(buffer, &v, bytes); + } + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +} + +template < + class Generator, + std::size_t N, + class = std::enable_if_t> +void +rngfill(std::array& a, Generator& g) +{ + using result_type = typename Generator::result_type; + auto i = N / sizeof(result_type); + result_type* p = reinterpret_cast(a.data()); + while (i--) + *p++ = g(); +} + +} // namespace beast + +#endif diff --git a/src/ripple/beast/utility/temp_dir.h b/include/xrpl/beast/utility/temp_dir.h similarity index 85% rename from src/ripple/beast/utility/temp_dir.h rename to include/xrpl/beast/utility/temp_dir.h index 63cb4e41547..bbb7afc7b43 100644 --- a/src/ripple/beast/utility/temp_dir.h +++ b/include/xrpl/beast/utility/temp_dir.h @@ -21,6 +21,7 @@ #define BEAST_UTILITY_TEMP_DIR_H_INCLUDED #include + #include namespace beast { @@ -35,23 +36,21 @@ class temp_dir boost::filesystem::path path_; public: -#if ! GENERATING_DOCS +#if !GENERATING_DOCS temp_dir(const temp_dir&) = delete; - temp_dir& operator=(const temp_dir&) = delete; + temp_dir& + operator=(const temp_dir&) = delete; #endif /// Construct a temporary directory. temp_dir() { - auto const dir = - boost::filesystem::temp_directory_path(); + auto const dir = boost::filesystem::temp_directory_path(); do { - path_ = - dir / boost::filesystem::unique_path(); - } - while(boost::filesystem::exists(path_)); - boost::filesystem::create_directory (path_); + path_ = dir / boost::filesystem::unique_path(); + } while (boost::filesystem::exists(path_)); + boost::filesystem::create_directory(path_); } /// Destroy a temporary directory. @@ -81,6 +80,6 @@ class temp_dir } }; -} // beast +} // namespace beast #endif diff --git a/src/ripple/beast/xor_shift_engine.h b/include/xrpl/beast/xor_shift_engine.h similarity index 78% rename from src/ripple/beast/xor_shift_engine.h rename to include/xrpl/beast/xor_shift_engine.h index 5b917c5feb5..77012980c8d 100644 --- a/src/ripple/beast/xor_shift_engine.h +++ b/include/xrpl/beast/xor_shift_engine.h @@ -35,27 +35,23 @@ class xor_shift_engine using result_type = std::uint64_t; xor_shift_engine(xor_shift_engine const&) = default; - xor_shift_engine& operator=(xor_shift_engine const&) = default; + xor_shift_engine& + operator=(xor_shift_engine const&) = default; - explicit - xor_shift_engine (result_type val = 1977u); + explicit xor_shift_engine(result_type val = 1977u); void - seed (result_type seed); + seed(result_type seed); result_type operator()(); - static - result_type constexpr - min() + static result_type constexpr min() { return std::numeric_limits::min(); } - static - result_type constexpr - max() + static result_type constexpr max() { return std::numeric_limits::max(); } @@ -63,32 +59,29 @@ class xor_shift_engine private: result_type s_[2]; - static - result_type - murmurhash3 (result_type x); + static result_type + murmurhash3(result_type x); }; template -xor_shift_engine<_>::xor_shift_engine ( - result_type val) +xor_shift_engine<_>::xor_shift_engine(result_type val) { - seed (val); + seed(val); } template void -xor_shift_engine<_>::seed (result_type seed) +xor_shift_engine<_>::seed(result_type seed) { if (seed == 0) throw std::domain_error("invalid seed"); - s_[0] = murmurhash3 (seed); - s_[1] = murmurhash3 (s_[0]); + s_[0] = murmurhash3(seed); + s_[1] = murmurhash3(s_[0]); } template auto -xor_shift_engine<_>::operator()() -> - result_type +xor_shift_engine<_>::operator()() -> result_type { result_type s1 = s_[0]; result_type const s0 = s_[1]; @@ -99,8 +92,7 @@ xor_shift_engine<_>::operator()() -> template auto -xor_shift_engine<_>::murmurhash3 (result_type x) - -> result_type +xor_shift_engine<_>::murmurhash3(result_type x) -> result_type { x ^= x >> 33; x *= 0xff51afd7ed558ccdULL; @@ -109,7 +101,7 @@ xor_shift_engine<_>::murmurhash3 (result_type x) return x ^= x >> 33; } -} // detail +} // namespace detail /** XOR-shift Generator. @@ -121,6 +113,6 @@ xor_shift_engine<_>::murmurhash3 (result_type x) */ using xor_shift_engine = detail::xor_shift_engine<>; -} +} // namespace beast #endif diff --git a/src/ripple/crypto/README.md b/include/xrpl/crypto/README.md similarity index 100% rename from src/ripple/crypto/README.md rename to include/xrpl/crypto/README.md diff --git a/include/xrpl/crypto/RFC1751.h b/include/xrpl/crypto/RFC1751.h new file mode 100644 index 00000000000..fa70830b798 --- /dev/null +++ b/include/xrpl/crypto/RFC1751.h @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_CRYPTO_RFC1751_H_INCLUDED +#define RIPPLE_CRYPTO_RFC1751_H_INCLUDED + +#include +#include + +namespace ripple { + +class RFC1751 +{ +public: + static int + getKeyFromEnglish(std::string& strKey, std::string const& strHuman); + + static void + getEnglishFromKey(std::string& strHuman, std::string const& strKey); + + /** Chooses a single dictionary word from the data. + + This is not particularly secure but it can be useful to provide + a unique name for something given a GUID or fixed data. We use + it to turn the pubkey_node into an easily remembered and identified + 4 character string. + */ + static std::string + getWordFromBlob(void const* blob, size_t bytes); + +private: + static unsigned long + extract(char const* s, int start, int length); + static void + btoe(std::string& strHuman, std::string const& strData); + static void + insert(char* s, int x, int start, int length); + static void + standard(std::string& strWord); + static int + wsrch(std::string const& strWord, int iMin, int iMax); + static int + etob(std::string& strData, std::vector vsHuman); + + static char const* s_dictionary[]; +}; + +} // namespace ripple + +#endif diff --git a/src/ripple/crypto/csprng.h b/include/xrpl/crypto/csprng.h similarity index 80% rename from src/ripple/crypto/csprng.h rename to include/xrpl/crypto/csprng.h index a06b8a2e7d3..9a4e933a2e7 100644 --- a/src/ripple/crypto/csprng.h +++ b/include/xrpl/crypto/csprng.h @@ -21,8 +21,6 @@ #define RIPPLE_CRYPTO_RANDOM_H_INCLUDED #include -#include -#include namespace ripple { @@ -39,27 +37,23 @@ class csprng_engine private: std::mutex mutex_; - void - mix ( - void* buffer, - std::size_t count, - double bitsPerByte); - public: using result_type = std::uint64_t; - csprng_engine(csprng_engine const&) = delete; - csprng_engine& operator=(csprng_engine const&) = delete; + csprng_engine(csprng_engine const&) = delete; + csprng_engine& + operator=(csprng_engine const&) = delete; csprng_engine(csprng_engine&&) = delete; - csprng_engine& operator=(csprng_engine&&) = delete; + csprng_engine& + operator=(csprng_engine&&) = delete; - csprng_engine (); - ~csprng_engine (); + csprng_engine(); + ~csprng_engine(); /** Mix entropy into the pool */ void - mix_entropy (void* buffer = nullptr, std::size_t count = 0); + mix_entropy(void* buffer = nullptr, std::size_t count = 0); /** Generate a random integer */ result_type @@ -67,19 +61,17 @@ class csprng_engine /** Fill a buffer with the requested amount of random data */ void - operator()(void *ptr, std::size_t count); + operator()(void* ptr, std::size_t count); /* The smallest possible value that can be returned */ - static constexpr - result_type + static constexpr result_type min() { return std::numeric_limits::min(); } /* The largest possible value that can be returned */ - static constexpr - result_type + static constexpr result_type max() { return std::numeric_limits::max(); @@ -94,8 +86,9 @@ class csprng_engine This meets the requirements of UniformRandomNumberEngine */ -csprng_engine& crypto_prng(); +csprng_engine& +crypto_prng(); -} +} // namespace ripple #endif diff --git a/include/xrpl/crypto/secure_erase.h b/include/xrpl/crypto/secure_erase.h new file mode 100644 index 00000000000..d7eceab87a8 --- /dev/null +++ b/include/xrpl/crypto/secure_erase.h @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2020 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_CRYPTO_SECURE_ERASE_H_INCLUDED +#define RIPPLE_CRYPTO_SECURE_ERASE_H_INCLUDED + +#include + +namespace ripple { + +/** Attempts to clear the given blob of memory. + + The underlying implementation of this function takes pains to + attempt to outsmart the compiler from optimizing the clearing + away. Please note that, despite that, remnants of content may + remain floating around in memory as well as registers, caches + and more. + + For a more in-depth discussion of the subject please see the + below posts by Colin Percival: + + http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html + http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html +*/ +void +secure_erase(void* dest, std::size_t bytes); + +} // namespace ripple + +#endif diff --git a/include/xrpl/json/JsonPropertyStream.h b/include/xrpl/json/JsonPropertyStream.h new file mode 100644 index 00000000000..fdc21971978 --- /dev/null +++ b/include/xrpl/json/JsonPropertyStream.h @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED +#define RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED + +#include +#include + +namespace ripple { + +/** A PropertyStream::Sink which produces a Json::Value of type objectValue. */ +class JsonPropertyStream : public beast::PropertyStream +{ +public: + Json::Value m_top; + std::vector m_stack; + +public: + JsonPropertyStream(); + Json::Value const& + top() const; + +protected: + void + map_begin() override; + void + map_begin(std::string const& key) override; + void + map_end() override; + void + add(std::string const& key, short value) override; + void + add(std::string const& key, unsigned short value) override; + void + add(std::string const& key, int value) override; + void + add(std::string const& key, unsigned int value) override; + void + add(std::string const& key, long value) override; + void + add(std::string const& key, float v) override; + void + add(std::string const& key, double v) override; + void + add(std::string const& key, std::string const& v) override; + void + array_begin() override; + void + array_begin(std::string const& key) override; + void + array_end() override; + + void + add(short value) override; + void + add(unsigned short value) override; + void + add(int value) override; + void + add(unsigned int value) override; + void + add(long value) override; + void + add(float v) override; + void + add(double v) override; + void + add(std::string const& v) override; +}; + +} // namespace ripple + +#endif diff --git a/src/ripple/json/Object.h b/include/xrpl/json/Object.h similarity index 76% rename from src/ripple/json/Object.h rename to include/xrpl/json/Object.h index f847940a85e..87ef8ea4f28 100644 --- a/src/ripple/json/Object.h +++ b/include/xrpl/json/Object.h @@ -20,7 +20,8 @@ #ifndef RIPPLE_JSON_OBJECT_H_INCLUDED #define RIPPLE_JSON_OBJECT_H_INCLUDED -#include +#include + #include namespace Json { @@ -39,8 +40,8 @@ namespace Json { 1. Only one collection can be open for change at any one time. - This condition is enforced automatically and a std::logic_error thrown if it - is violated. + This condition is enforced automatically and a std::logic_error thrown if + it is violated. 2. A tag may only be used once in an Object. @@ -151,8 +152,9 @@ namespace Json { class Collection { public: - Collection (Collection&& c) noexcept; - Collection& operator= (Collection&& c) noexcept; + Collection(Collection&& c) noexcept; + Collection& + operator=(Collection&& c) noexcept; Collection() = delete; ~Collection(); @@ -160,8 +162,9 @@ class Collection protected: // A null parent means "no parent at all". // Writers cannot be null. - Collection (Collection* parent, Writer*); - void checkWritable (std::string const& label); + Collection(Collection* parent, Writer*); + void + checkWritable(std::string const& label); Collection* parent_; Writer* writer_; @@ -193,40 +196,48 @@ class Object : protected Collection An operator[] is provided to allow writing `object["key"] = scalar;`. */ template - void set (std::string const& key, Scalar const&); + void + set(std::string const& key, Scalar const&); - void set (std::string const& key, Json::Value const&); + void + set(std::string const& key, Json::Value const&); // Detail class and method used to implement operator[]. class Proxy; - Proxy operator[] (std::string const& key); - Proxy operator[] (Json::StaticString const& key); + Proxy + operator[](std::string const& key); + Proxy + operator[](Json::StaticString const& key); /** Make a new Object at a key and return it. This Object is disabled until that sub-object is destroyed. Throws an exception if this Object was already disabled. */ - Object setObject (std::string const& key); + Object + setObject(std::string const& key); /** Make a new Array at a key and return it. This Object is disabled until that sub-array is destroyed. Throws an exception if this Object was already disabled. */ - Array setArray (std::string const& key); + Array + setArray(std::string const& key); protected: friend class Array; - Object (Collection* parent, Writer* w) : Collection (parent, w) {} + Object(Collection* parent, Writer* w) : Collection(parent, w) + { + } }; class Object::Root : public Object { - public: +public: /** Each Object::Root must be constructed with its own unique Writer. */ - Root (Writer&); + Root(Writer&); }; //------------------------------------------------------------------------------ @@ -241,31 +252,37 @@ class Array : private Collection its sub-collections is enabled). */ template - void append (Scalar const&); + void + append(Scalar const&); /** Appends a Json::Value to an array. Throws an exception if this Array was disabled. */ - void append (Json::Value const&); + void + append(Json::Value const&); /** Append a new Object and return it. This Array is disabled until that sub-object is destroyed. Throws an exception if this Array was disabled. */ - Object appendObject (); + Object + appendObject(); /** Append a new Array and return it. This Array is disabled until that sub-array is destroyed. Throws an exception if this Array was already disabled. */ - Array appendArray (); + Array + appendArray(); - protected: +protected: friend class Object; - Array (Collection* parent, Writer* w) : Collection (parent, w) {} + Array(Collection* parent, Writer* w) : Collection(parent, w) + { + } }; //------------------------------------------------------------------------------ @@ -274,68 +291,76 @@ class Array : private Collection // interoperate. /** Add a new subarray at a named key in a Json object. */ -Json::Value& setArray (Json::Value&, Json::StaticString const& key); +Json::Value& +setArray(Json::Value&, Json::StaticString const& key); /** Add a new subarray at a named key in a Json object. */ -Array setArray (Object&, Json::StaticString const& key); - +Array +setArray(Object&, Json::StaticString const& key); /** Add a new subobject at a named key in a Json object. */ -Json::Value& addObject (Json::Value&, Json::StaticString const& key); +Json::Value& +addObject(Json::Value&, Json::StaticString const& key); /** Add a new subobject at a named key in a Json object. */ -Object addObject (Object&, Json::StaticString const& key); - +Object +addObject(Object&, Json::StaticString const& key); /** Append a new subarray to a Json array. */ -Json::Value& appendArray (Json::Value&); +Json::Value& +appendArray(Json::Value&); /** Append a new subarray to a Json array. */ -Array appendArray (Array&); - +Array +appendArray(Array&); /** Append a new subobject to a Json object. */ -Json::Value& appendObject (Json::Value&); +Json::Value& +appendObject(Json::Value&); /** Append a new subobject to a Json object. */ -Object appendObject (Array&); - +Object +appendObject(Array&); /** Copy all the keys and values from one object into another. */ -void copyFrom (Json::Value& to, Json::Value const& from); +void +copyFrom(Json::Value& to, Json::Value const& from); /** Copy all the keys and values from one object into another. */ -void copyFrom (Object& to, Json::Value const& from); - +void +copyFrom(Object& to, Json::Value const& from); /** An Object that contains its own Writer. */ class WriterObject { public: - WriterObject (Output const& output) - : writer_ (std::make_unique (output)), - object_ (std::make_unique (*writer_)) + WriterObject(Output const& output) + : writer_(std::make_unique(output)) + , object_(std::make_unique(*writer_)) { } - WriterObject (WriterObject&& other) = default; + WriterObject(WriterObject&& other) = default; - Object* operator->() + Object* + operator->() { return object_.get(); } - Object& operator*() + Object& + operator*() { return *object_; } private: - std::unique_ptr writer_; + std::unique_ptr writer_; std::unique_ptr object_; }; -WriterObject stringWriterObject (std::string&); +WriterObject +stringWriterObject(std::string&); //------------------------------------------------------------------------------ // Implementation details. @@ -348,12 +373,13 @@ class Object::Proxy std::string const key_; public: - Proxy (Object& object, std::string const& key); + Proxy(Object& object, std::string const& key); template - void operator= (T const& t) + void + operator=(T const& t) { - object_.set (key_, t); + object_.set(key_, t); // Note: This function shouldn't return *this, because it's a trap. // // In Json::Value, foo[jss::key] returns a reference to a @@ -368,69 +394,71 @@ class Object::Proxy //------------------------------------------------------------------------------ template -void Array::append (Scalar const& value) +void +Array::append(Scalar const& value) { - checkWritable ("append"); + checkWritable("append"); if (writer_) - writer_->append (value); + writer_->append(value); } template -void Object::set (std::string const& key, Scalar const& value) +void +Object::set(std::string const& key, Scalar const& value) { - checkWritable ("set"); + checkWritable("set"); if (writer_) - writer_->set (key, value); + writer_->set(key, value); } -inline -Json::Value& setArray (Json::Value& json, Json::StaticString const& key) +inline Json::Value& +setArray(Json::Value& json, Json::StaticString const& key) { return (json[key] = Json::arrayValue); } -inline -Array setArray (Object& json, Json::StaticString const& key) +inline Array +setArray(Object& json, Json::StaticString const& key) { - return json.setArray (std::string (key)); + return json.setArray(std::string(key)); } -inline -Json::Value& addObject (Json::Value& json, Json::StaticString const& key) +inline Json::Value& +addObject(Json::Value& json, Json::StaticString const& key) { return (json[key] = Json::objectValue); } -inline -Object addObject (Object& object, Json::StaticString const& key) +inline Object +addObject(Object& object, Json::StaticString const& key) { - return object.setObject (std::string (key)); + return object.setObject(std::string(key)); } -inline -Json::Value& appendArray (Json::Value& json) +inline Json::Value& +appendArray(Json::Value& json) { - return json.append (Json::arrayValue); + return json.append(Json::arrayValue); } -inline -Array appendArray (Array& json) +inline Array +appendArray(Array& json) { - return json.appendArray (); + return json.appendArray(); } -inline -Json::Value& appendObject (Json::Value& json) +inline Json::Value& +appendObject(Json::Value& json) { - return json.append (Json::objectValue); + return json.append(Json::objectValue); } -inline -Object appendObject (Array& json) +inline Object +appendObject(Array& json) { - return json.appendObject (); + return json.appendObject(); } -} // Json +} // namespace Json #endif diff --git a/include/xrpl/json/Output.h b/include/xrpl/json/Output.h new file mode 100644 index 00000000000..ef5f68e5180 --- /dev/null +++ b/include/xrpl/json/Output.h @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_JSON_OUTPUT_H_INCLUDED +#define RIPPLE_JSON_OUTPUT_H_INCLUDED + +#include + +#include +#include + +namespace Json { + +class Value; + +using Output = std::function; + +inline Output +stringOutput(std::string& s) +{ + return [&](boost::beast::string_view const& b) { + s.append(b.data(), b.size()); + }; +} + +/** Writes a minimal representation of a Json value to an Output in O(n) time. + + Data is streamed right to the output, so only a marginal amount of memory is + used. This can be very important for a very large Json::Value. + */ +void +outputJson(Json::Value const&, Output const&); + +/** Return the minimal string representation of a Json::Value in O(n) time. + + This requires a memory allocation for the full size of the output. + If possible, use outputJson(). + */ +std::string +jsonAsString(Json::Value const&); + +} // namespace Json + +#endif diff --git a/src/ripple/json/README.md b/include/xrpl/json/README.md similarity index 100% rename from src/ripple/json/README.md rename to include/xrpl/json/README.md diff --git a/include/xrpl/json/Writer.h b/include/xrpl/json/Writer.h new file mode 100644 index 00000000000..f4c37c33162 --- /dev/null +++ b/include/xrpl/json/Writer.h @@ -0,0 +1,261 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_JSON_WRITER_H_INCLUDED +#define RIPPLE_JSON_WRITER_H_INCLUDED + +#include +#include +#include +#include + +#include + +namespace Json { + +/** + * Writer implements an O(1)-space, O(1)-granular output JSON writer. + * + * O(1)-space means that it uses a fixed amount of memory, and that there are + * no heap allocations at each step of the way. + * + * O(1)-granular output means the writer only outputs in small segments of a + * bounded size, using a bounded number of CPU cycles in doing so. This is + * very helpful in scheduling long jobs. + * + * The tradeoff is that you have to fill items in the JSON tree as you go, + * and you can never go backward. + * + * Writer can write single JSON tokens, but the typical use is to write out an + * entire JSON object. For example: + * + * { + * Writer w (out); + * + * w.startObject (); // Start the root object. + * w.set ("hello", "world"); + * w.set ("goodbye", 23); + * w.finishObject (); // Finish the root object. + * } + * + * which outputs the string + * + * {"hello":"world","goodbye":23} + * + * There can be an object inside an object: + * + * { + * Writer w (out); + * + * w.startObject (); // Start the root object. + * w.set ("hello", "world"); + * + * w.startObjectSet ("subobject"); // Start a sub-object. + * w.set ("goodbye", 23); // Add a key, value assignment. + * w.finishObject (); // Finish the sub-object. + * + * w.finishObject (); // Finish the root-object. + * } + * + * which outputs the string + * + * {"hello":"world","subobject":{"goodbye":23}}. + * + * Arrays work similarly + * + * { + * Writer w (out); + * w.startObject (); // Start the root object. + * + * w.startArraySet ("hello"); // Start an array. + * w.append (23) // Append some items. + * w.append ("skidoo") + * w.finishArray (); // Finish the array. + * + * w.finishObject (); // Finish the root object. + * } + * + * which outputs the string + * + * {"hello":[23,"skidoo"]}. + * + * + * If you've reached the end of a long object, you can just use finishAll() + * which finishes all arrays and objects that you have started. + * + * { + * Writer w (out); + * w.startObject (); // Start the root object. + * + * w.startArraySet ("hello"); // Start an array. + * w.append (23) // Append an item. + * + * w.startArrayAppend () // Start a sub-array. + * w.append ("one"); + * w.append ("two"); + * + * w.startObjectAppend (); // Append a sub-object. + * w.finishAll (); // Finish everything. + * } + * + * which outputs the string + * + * {"hello":[23,["one","two",{}]]}. + * + * For convenience, the destructor of Writer calls w.finishAll() which makes + * sure that all arrays and objects are closed. This means that you can throw + * an exception, or have a coroutine simply clean up the stack, and be sure + * that you do in fact generate a complete JSON object. + */ + +class Writer +{ +public: + enum CollectionType { array, object }; + + explicit Writer(Output const& output); + Writer(Writer&&) noexcept; + Writer& + operator=(Writer&&) noexcept; + + ~Writer(); + + /** Start a new collection at the root level. */ + void startRoot(CollectionType); + + /** Start a new collection inside an array. */ + void startAppend(CollectionType); + + /** Start a new collection inside an object. */ + void + startSet(CollectionType, std::string const& key); + + /** Finish the collection most recently started. */ + void + finish(); + + /** Finish all objects and arrays. After finishArray() has been called, no + * more operations can be performed. */ + void + finishAll(); + + /** Append a value to an array. + * + * Scalar must be a scalar - that is, a number, boolean, string, string + * literal, nullptr or Json::Value + */ + template + void + append(Scalar t) + { + rawAppend(); + output(t); + } + + /** Add a comma before this next item if not the first item in an array. + Useful if you are writing the actual array yourself. */ + void + rawAppend(); + + /** Add a key, value assignment to an object. + * + * Scalar must be a scalar - that is, a number, boolean, string, string + * literal, or nullptr. + * + * While the JSON spec doesn't explicitly disallow this, you should avoid + * calling this method twice with the same tag for the same object. + * + * If CHECK_JSON_WRITER is defined, this function throws an exception if if + * the tag you use has already been used in this object. + */ + template + void + set(std::string const& tag, Type t) + { + rawSet(tag); + output(t); + } + + /** Emit just "tag": as part of an object. Useful if you are writing the + actual value data yourself. */ + void + rawSet(std::string const& key); + + // You won't need to call anything below here until you are writing single + // items (numbers, strings, bools, null) to a JSON stream. + + /*** Output a string. */ + void + output(std::string const&); + + /*** Output a literal constant or C string. */ + void + output(char const*); + + /*** Output a Json::Value. */ + void + output(Json::Value const&); + + /** Output a null. */ + void output(std::nullptr_t); + + /** Output a float. */ + void + output(float); + + /** Output a double. */ + void + output(double); + + /** Output a bool. */ + void + output(bool); + + /** Output numbers or booleans. */ + template + void + output(Type t) + { + implOutput(std::to_string(t)); + } + + void + output(Json::StaticString const& t) + { + output(t.c_str()); + } + +private: + class Impl; + std::unique_ptr impl_; + + void + implOutput(std::string const&); +}; + +inline void +check(bool condition, std::string const& message) +{ + if (!condition) + ripple::Throw(message); +} + +} // namespace Json + +#endif diff --git a/src/ripple/json/impl/json_assert.h b/include/xrpl/json/detail/json_assert.h similarity index 79% rename from src/ripple/json/impl/json_assert.h rename to include/xrpl/json/detail/json_assert.h index fc8ab335aa4..5d680e6e34d 100644 --- a/src/ripple/json/impl/json_assert.h +++ b/include/xrpl/json/detail/json_assert.h @@ -20,10 +20,11 @@ #ifndef RIPPLE_JSON_JSON_ASSERT_H_INCLUDED #define RIPPLE_JSON_JSON_ASSERT_H_INCLUDED -#include "ripple/json/json_errors.h" +#include +#include -#define JSON_ASSERT_UNREACHABLE assert( false ) -#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw -#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) ripple::Throw ( message ); +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) \ + ripple::Throw(message); #endif diff --git a/src/ripple/json/json_errors.h b/include/xrpl/json/json_errors.h similarity index 94% rename from src/ripple/json/json_errors.h rename to include/xrpl/json/json_errors.h index 558d99e3a7f..4bed420409f 100644 --- a/src/ripple/json/json_errors.h +++ b/include/xrpl/json/json_errors.h @@ -22,15 +22,13 @@ #include -namespace Json -{ +namespace Json { struct error : std::runtime_error { using std::runtime_error::runtime_error; }; -} // namespace Json - +} // namespace Json -#endif // JSON_FORWARDS_H_INCLUDED +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/src/ripple/json/json_forwards.h b/include/xrpl/json/json_forwards.h similarity index 94% rename from src/ripple/json/json_forwards.h rename to include/xrpl/json/json_forwards.h index 6e8014ad8fb..e77ea581690 100644 --- a/src/ripple/json/json_forwards.h +++ b/include/xrpl/json/json_forwards.h @@ -20,8 +20,7 @@ #ifndef RIPPLE_JSON_JSON_FORWARDS_H_INCLUDED #define RIPPLE_JSON_JSON_FORWARDS_H_INCLUDED -namespace Json -{ +namespace Json { // value.h using Int = int; @@ -32,7 +31,6 @@ class ValueIteratorBase; class ValueIterator; class ValueConstIterator; -} // namespace Json +} // namespace Json - -#endif // JSON_FORWARDS_H_INCLUDED +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/include/xrpl/json/json_reader.h b/include/xrpl/json/json_reader.h new file mode 100644 index 00000000000..27d608f8504 --- /dev/null +++ b/include/xrpl/json/json_reader.h @@ -0,0 +1,253 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_JSON_JSON_READER_H_INCLUDED +#define RIPPLE_JSON_JSON_READER_H_INCLUDED + +#define CPPTL_JSON_READER_H_INCLUDED + +#include +#include + +#include + +#include + +namespace Json { + +/** \brief Unserialize a JSON document into a + * Value. + * + */ +class Reader +{ +public: + using Char = char; + using Location = const Char*; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader() = default; + + /** \brief Read a Value from a JSON + * document. \param document UTF-8 encoded string containing the document to + * read. \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool + parse(std::string const& document, Value& root); + + /** \brief Read a Value from a JSON + * document. \param document UTF-8 encoded string containing the document to + * read. \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool + parse(const char* beginDoc, const char* endDoc, Value& root); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool + parse(std::istream& is, Value& root); + + /** \brief Read a Value from a JSON buffer + * sequence. \param root [out] Contains the root value of the document if it + * was successfully parsed. \param UTF-8 encoded buffer sequence. \return \c + * true if the buffer was successfully parsed, \c false if an error + * occurred. + */ + template + bool + parse(Value& root, BufferSequence const& bs); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. \return Formatted error message with the list of errors with + * their location in the parsed document. An empty string is returned if no + * error occurred during parsing. + */ + std::string + getFormatedErrorMessages() const; + + static constexpr unsigned nest_limit{25}; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenInteger, + tokenDouble, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token + { + public: + explicit Token() = default; + + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo + { + public: + explicit ErrorInfo() = default; + + Token token_; + std::string message_; + Location extra_; + }; + + using Errors = std::deque; + + bool + expectToken(TokenType type, Token& token, const char* message); + bool + readToken(Token& token); + void + skipSpaces(); + bool + match(Location pattern, int patternLength); + bool + readComment(); + bool + readCStyleComment(); + bool + readCppStyleComment(); + bool + readString(); + Reader::TokenType + readNumber(); + bool + readValue(unsigned depth); + bool + readObject(Token& token, unsigned depth); + bool + readArray(Token& token, unsigned depth); + bool + decodeNumber(Token& token); + bool + decodeString(Token& token); + bool + decodeString(Token& token, std::string& decoded); + bool + decodeDouble(Token& token); + bool + decodeUnicodeCodePoint( + Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool + decodeUnicodeEscapeSequence( + Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool + addError(std::string const& message, Token& token, Location extra = 0); + bool + recoverFromError(TokenType skipUntilToken); + bool + addErrorAndRecover( + std::string const& message, + Token& token, + TokenType skipUntilToken); + void + skipUntilSpace(); + Value& + currentValue(); + Char + getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + std::string + getLocationLineAndColumn(Location location) const; + void + skipCommentTokens(Token& token); + + using Nodes = std::stack; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; +}; + +template +bool +Reader::parse(Value& root, BufferSequence const& bs) +{ + using namespace boost::asio; + std::string s; + s.reserve(buffer_size(bs)); + for (auto const& b : bs) + s.append(buffer_cast(b), buffer_size(b)); + return parse(s, root); +} + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { +"dir": { + "file": { + // The input stream JSON would be nested here. + } +} + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +std::istream& +operator>>(std::istream&, Value&); + +} // namespace Json + +#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/include/xrpl/json/json_value.h b/include/xrpl/json/json_value.h new file mode 100644 index 00000000000..91d29c28d68 --- /dev/null +++ b/include/xrpl/json/json_value.h @@ -0,0 +1,686 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_JSON_JSON_VALUE_H_INCLUDED +#define RIPPLE_JSON_JSON_VALUE_H_INCLUDED + +#include + +#include +#include +#include +#include + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignment takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class StaticString +{ +public: + constexpr explicit StaticString(const char* czstring) : str_(czstring) + { + } + + constexpr + operator const char*() const + { + return str_; + } + + constexpr const char* + c_str() const + { + return str_; + } + +private: + const char* str_; +}; + +inline bool +operator==(StaticString x, StaticString y) +{ + return strcmp(x.c_str(), y.c_str()) == 0; +} + +inline bool +operator!=(StaticString x, StaticString y) +{ + return !(x == y); +} + +inline bool +operator==(std::string const& x, StaticString y) +{ + return strcmp(x.c_str(), y.c_str()) == 0; +} + +inline bool +operator!=(std::string const& x, StaticString y) +{ + return !(x == y); +} + +inline bool +operator==(StaticString x, std::string const& y) +{ + return y == x; +} + +inline bool +operator!=(StaticString x, std::string const& y) +{ + return !(y == x); +} + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represent a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. Non const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resize and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain a default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + */ +class Value +{ + friend class ValueIteratorBase; + +public: + using Members = std::vector; + using iterator = ValueIterator; + using const_iterator = ValueConstIterator; + using UInt = Json::UInt; + using Int = Json::Int; + using ArrayIndex = UInt; + + static const Value null; + static const Int minInt; + static const Int maxInt; + static const UInt maxUInt; + +private: + class CZString + { + public: + enum DuplicationPolicy { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString(int index); + CZString(const char* cstr, DuplicationPolicy allocate); + CZString(const CZString& other); + ~CZString(); + CZString& + operator=(const CZString& other) = delete; + bool + operator<(const CZString& other) const; + bool + operator==(const CZString& other) const; + int + index() const; + const char* + c_str() const; + bool + isStaticString() const; + + private: + const char* cstr_; + int index_; + }; + +public: + using ObjectValues = std::map; + +public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. + This is useful since clear() and resize() will not alter types. + + Examples: + \code + Json::Value null_value; // null + Json::Value arr_value(Json::arrayValue); // [] + Json::Value obj_value(Json::objectValue); // {} + \endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); + Value(double value); + Value(const char* value); + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to + this + * constructor. + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * \endcode + */ + Value(const StaticString& value); + Value(std::string const& value); + Value(bool value); + Value(const Value& other); + ~Value(); + + Value& + operator=(Value const& other); + Value& + operator=(Value&& other); + + Value(Value&& other) noexcept; + + /// Swap values. + void + swap(Value& other) noexcept; + + ValueType + type() const; + + const char* + asCString() const; + /** Returns the unquoted string value. */ + std::string + asString() const; + Int + asInt() const; + UInt + asUInt() const; + double + asDouble() const; + bool + asBool() const; + + // TODO: What is the "empty()" method this docstring mentions? + /** isNull() tests to see if this field is null. Don't use this method to + test for emptiness: use empty(). */ + bool + isNull() const; + bool + isBool() const; + bool + isInt() const; + bool + isUInt() const; + bool + isIntegral() const; + bool + isDouble() const; + bool + isNumeric() const; + bool + isString() const; + bool + isArray() const; + bool + isArrayOrNull() const; + bool + isObject() const; + bool + isObjectOrNull() const; + + bool + isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + UInt + size() const; + + /** Returns false if this is an empty array, empty object, empty string, + or null. */ + explicit + operator bool() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void + clear(); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted in the array so that its size is index+1. (You may need to say + /// 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& + operator[](UInt index); + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& + operator[](UInt index) const; + /// If the array contains at least index+1 elements, returns the element + /// value, otherwise returns defaultValue. + Value + get(UInt index, const Value& defaultValue) const; + /// Return true if index < size(). + bool + isValidIndex(UInt index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& + append(const Value& value); + Value& + append(Value&& value); + + /// Access an object value by name, create a null member if it does not + /// exist. + Value& + operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& + operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not + /// exist. + Value& + operator[](std::string const& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& + operator[](std::string const& key) const; + /** \brief Access an object value by name, create a null member if it does + not exist. + + * If the object as no entry for that name, then the member name used to + store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& + operator[](const StaticString& key); + + /// Return the member named key if it exist, defaultValue otherwise. + Value + get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + Value + get(std::string const& key, const Value& defaultValue) const; + + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + Value + removeMember(const char* key); + /// Same as removeMember(const char*) + Value + removeMember(std::string const& key); + + /// Return true if the object has a member named key. + bool + isMember(const char* key) const; + /// Return true if the object has a member named key. + bool + isMember(std::string const& key) const; + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members + getMemberNames() const; + + std::string + toStyledString() const; + + const_iterator + begin() const; + const_iterator + end() const; + + iterator + begin(); + iterator + end(); + + friend bool + operator==(const Value&, const Value&); + friend bool + operator<(const Value&, const Value&); + +private: + Value& + resolveReference(const char* key, bool isStatic); + +private: + union ValueHolder + { + Int int_; + UInt uint_; + double real_; + bool bool_; + char* string_; + ObjectValues* map_{nullptr}; + } value_; + ValueType type_ : 8; + int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. +}; + +bool +operator==(const Value&, const Value&); + +inline bool +operator!=(const Value& x, const Value& y) +{ + return !(x == y); +} + +bool +operator<(const Value&, const Value&); + +inline bool +operator<=(const Value& x, const Value& y) +{ + return !(y < x); +} + +inline bool +operator>(const Value& x, const Value& y) +{ + return y < x; +} + +inline bool +operator>=(const Value& x, const Value& y) +{ + return !(x < y); +} + +/** \brief Experimental do not use: Allocator to customize member name and + * string value memory management done by Value. + * + * - makeMemberName() and releaseMemberName() are called to respectively + * duplicate and free an Json::objectValue member name. + * - duplicateStringValue() and releaseStringValue() are called similarly to + * duplicate and free a Json::stringValue value. + */ +class ValueAllocator +{ +public: + enum { unknown = (unsigned)-1 }; + + virtual ~ValueAllocator() = default; + + virtual char* + makeMemberName(const char* memberName) = 0; + virtual void + releaseMemberName(char* memberName) = 0; + virtual char* + duplicateStringValue(const char* value, unsigned int length = unknown) = 0; + virtual void + releaseStringValue(char* value) = 0; +}; + +/** \brief base class for Value iterators. + * + */ +class ValueIteratorBase +{ +public: + using size_t = unsigned int; + using difference_type = int; + using SelfType = ValueIteratorBase; + + ValueIteratorBase(); + + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); + + bool + operator==(const SelfType& other) const + { + return isEqual(other); + } + + bool + operator!=(const SelfType& other) const + { + return !isEqual(other); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value + key() const; + + /// Return the index of the referenced Value. -1 if it is not an arrayValue. + UInt + index() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + const char* + memberName() const; + +protected: + Value& + deref() const; + + void + increment(); + + void + decrement(); + + difference_type + computeDistance(const SelfType& other) const; + + bool + isEqual(const SelfType& other) const; + + void + copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; +}; + +/** \brief const iterator for object and array value. + * + */ +class ValueConstIterator : public ValueIteratorBase +{ + friend class Value; + +public: + using size_t = unsigned int; + using difference_type = int; + using reference = const Value&; + using pointer = const Value*; + using SelfType = ValueConstIterator; + + ValueConstIterator() = default; + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& + operator=(const ValueIteratorBase& other); + + SelfType + operator++(int) + { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType + operator--(int) + { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& + operator--() + { + decrement(); + return *this; + } + + SelfType& + operator++() + { + increment(); + return *this; + } + + reference + operator*() const + { + return deref(); + } +}; + +/** \brief Iterator for object and array value. + */ +class ValueIterator : public ValueIteratorBase +{ + friend class Value; + +public: + using size_t = unsigned int; + using difference_type = int; + using reference = Value&; + using pointer = Value*; + using SelfType = ValueIterator; + + ValueIterator() = default; + ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& + operator=(const SelfType& other); + + SelfType + operator++(int) + { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType + operator--(int) + { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& + operator--() + { + decrement(); + return *this; + } + + SelfType& + operator++() + { + increment(); + return *this; + } + + reference + operator*() const + { + return deref(); + } +}; + +} // namespace Json + +#endif // CPPTL_JSON_H_INCLUDED diff --git a/include/xrpl/json/json_writer.h b/include/xrpl/json/json_writer.h new file mode 100644 index 00000000000..1b4ff155083 --- /dev/null +++ b/include/xrpl/json/json_writer.h @@ -0,0 +1,348 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_JSON_JSON_WRITER_H_INCLUDED +#define RIPPLE_JSON_JSON_WRITER_H_INCLUDED + +#include +#include + +#include +#include + +namespace Json { + +class Value; + +/** \brief Abstract class for writers. + */ +class WriterBase +{ +public: + virtual ~WriterBase() + { + } + virtual std::string + write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + * without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + * consumption, but may be useful to support feature such as RPC where bandwith + * is limited. \sa Reader, Value + */ + +class FastWriter : public WriterBase +{ +public: + FastWriter() = default; + virtual ~FastWriter() + { + } + +public: // overridden from Writer + std::string + write(const Value& root) override; + +private: + void + writeValue(const Value& value); + + std::string document_; +}; + +/** \brief Writes a Value in JSON format in a + * human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + * line and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + * types, and all the values fit on one lines, then print the array on a single + * line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * \sa Reader, Value + */ +class StyledWriter : public WriterBase +{ +public: + StyledWriter(); + virtual ~StyledWriter() + { + } + +public: // overridden from Writer + /** \brief Serialize a Value in JSON + * format. \param root Value to serialize. \return String containing the + * JSON document that represents the root value. + */ + std::string + write(const Value& root) override; + +private: + void + writeValue(const Value& value); + void + writeArrayValue(const Value& value); + bool + isMultineArray(const Value& value); + void + pushValue(std::string const& value); + void + writeIndent(); + void + writeWithIndent(std::string const& value); + void + indent(); + void + unindent(); + + using ChildValues = std::vector; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in JSON format in a + human friendly way, to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value + */ +class StyledStreamWriter +{ +public: + StyledStreamWriter(std::string indentation = "\t"); + ~StyledStreamWriter() + { + } + +public: + /** \brief Serialize a Value in JSON + * format. \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void + write(std::ostream& out, const Value& root); + +private: + void + writeValue(const Value& value); + void + writeArrayValue(const Value& value); + bool + isMultineArray(const Value& value); + void + pushValue(std::string const& value); + void + writeIndent(); + void + writeWithIndent(std::string const& value); + void + indent(); + void + unindent(); + + using ChildValues = std::vector; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_; +}; + +std::string +valueToString(Int value); +std::string +valueToString(UInt value); +std::string +valueToString(double value); +std::string +valueToString(bool value); +std::string +valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +std::ostream& +operator<<(std::ostream&, const Value& root); + +//------------------------------------------------------------------------------ + +// Helpers for stream +namespace detail { + +template +void +write_string(Write const& write, std::string const& s) +{ + write(s.data(), s.size()); +} + +template +void +write_value(Write const& write, Value const& value) +{ + switch (value.type()) + { + case nullValue: + write("null", 4); + break; + + case intValue: + write_string(write, valueToString(value.asInt())); + break; + + case uintValue: + write_string(write, valueToString(value.asUInt())); + break; + + case realValue: + write_string(write, valueToString(value.asDouble())); + break; + + case stringValue: + write_string(write, valueToQuotedString(value.asCString())); + break; + + case booleanValue: + write_string(write, valueToString(value.asBool())); + break; + + case arrayValue: { + write("[", 1); + int const size = value.size(); + for (int index = 0; index < size; ++index) + { + if (index > 0) + write(",", 1); + write_value(write, value[index]); + } + write("]", 1); + break; + } + + case objectValue: { + Value::Members const members = value.getMemberNames(); + write("{", 1); + for (auto it = members.begin(); it != members.end(); ++it) + { + std::string const& name = *it; + if (it != members.begin()) + write(",", 1); + + write_string(write, valueToQuotedString(name.c_str())); + write(":", 1); + write_value(write, value[name]); + } + write("}", 1); + break; + } + } +} + +} // namespace detail + +/** Stream compact JSON to the specified function. + + @param jv The Json::Value to write + @param write Invocable with signature void(void const*, std::size_t) that + is called when output should be written to the stream. +*/ +template +void +stream(Json::Value const& jv, Write const& write) +{ + detail::write_value(write, jv); + write("\n", 1); +} + +/** Decorator for streaming out compact json + + Use + + Json::Value jv; + out << Json::Compact{jv} + + to write a single-line, compact version of `jv` to the stream, rather + than the styled format that comes from undecorated streaming. +*/ +class Compact +{ + Json::Value jv_; + +public: + /** Wrap a Json::Value for compact streaming + + @param jv The Json::Value to stream + + @note For now, we do not support wrapping lvalues to avoid + potentially costly copies. If we find a need, we can consider + adding support for compact lvalue streaming in the future. + */ + Compact(Json::Value&& jv) : jv_{std::move(jv)} + { + } + + friend std::ostream& + operator<<(std::ostream& o, Compact const& cJv) + { + detail::write_value( + [&o](void const* data, std::size_t n) { + o.write(static_cast(data), n); + }, + cJv.jv_); + return o; + } +}; + +} // namespace Json + +#endif // JSON_WRITER_H_INCLUDED diff --git a/src/ripple/json/to_string.h b/include/xrpl/json/to_string.h similarity index 87% rename from src/ripple/json/to_string.h rename to include/xrpl/json/to_string.h index cf093e2125c..5f692a415e0 100644 --- a/src/ripple/json/to_string.h +++ b/include/xrpl/json/to_string.h @@ -20,22 +20,25 @@ #ifndef RIPPLE_JSON_TO_STRING_H_INCLUDED #define RIPPLE_JSON_TO_STRING_H_INCLUDED -#include #include +#include namespace Json { class Value; /** Writes a Json::Value to an std::string. */ -std::string to_string (Value const&); +std::string +to_string(Value const&); /** Writes a Json::Value to an std::string. */ -std::string pretty (Value const&); +std::string +pretty(Value const&); /** Output using the StyledStreamWriter. @see Json::operator>>(). */ -std::ostream& operator<< (std::ostream&, const Value& root); +std::ostream& +operator<<(std::ostream&, const Value& root); -} // Json +} // namespace Json -#endif // JSON_TO_STRING_H_INCLUDED +#endif // JSON_TO_STRING_H_INCLUDED diff --git a/src/ripple/proto/README.md b/include/xrpl/proto/README.md similarity index 100% rename from src/ripple/proto/README.md rename to include/xrpl/proto/README.md diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/README.md b/include/xrpl/proto/org/xrpl/rpc/v1/README.md new file mode 100644 index 00000000000..9268439847d --- /dev/null +++ b/include/xrpl/proto/org/xrpl/rpc/v1/README.md @@ -0,0 +1,82 @@ +# Protocol buffer definitions for gRPC + +This folder contains the protocol buffer definitions used by the rippled gRPC API. +The gRPC API attempts to mimic the JSON/Websocket API as much as possible. +As of April 2020, the gRPC API supports a subset of the full rippled API: +tx, account_tx, account_info, fee and submit. + +### Making Changes + +#### Wire Format and Backwards Compatibility + +When making changes to the protocol buffer definitions in this folder, care must +be taken to ensure the changes do not break the wire format, which would break +backwards compatibility. At a high level, do not change any existing fields. +This includes the field's name, type and field number. Do not remove any +existing fields. It is always safe to add fields; just remember to give each of +the new fields a unique field number. The field numbers don't have to be in any +particular order and there can be gaps. More info about what changes break the +wire format can be found +[here](https://developers.google.com/protocol-buffers/docs/proto3#updating). + +#### Conventions + +For fields that are reused across different message types, we define the field as a unique +message type in common.proto. The name of the message type is the same as the +field name, with the exception that the field name itself is snake case, whereas +the message type is in Pascal case. The message type has one field, called +`value`. This pattern does not need to be strictly followed across the entire API, +but should be followed for transactions and ledger objects, since there is a high rate +of field reuse across different transactions and ledger objects. +The motivation for this pattern is two-fold. First, we ensure the field has the +same type everywhere that the field is used. Second, wrapping primitive types in +their own message type prevents default initialization of those primitive types. +For example, `uint32` is initialized to `0` if not explicitly set; +there is no way to tell if the client or server set the field to `0` (which may be +a valid value for the field) or the field was default initialized. + +#### Name Collisions + +Each message type must have a unique name. To resolve collisions, add a suffix +to one or more message types. For instance, ledger objects and transaction types +often have the same name (`DepositPreauth` for example). To resolve this, the +`DepositPreauth` ledger object is named `DepositPreauthObject`. + +#### To add a field or message type + +To add a field to a message, define the fields type, name and unique index. +To add a new message type, give the message type a unique name. +Then, add the appropriate C++ code in GRPCHelpers.cpp, or in the handler itself, +to serialize/deserialize the new field or message type. + +#### To add a new gRPC method + +To add a new gRPC method, add the gRPC method in xrp_ledger.proto. The method name +should begin with a verb. Define the request and response types in their own +file. The name of the request type should be the method name suffixed with `Request`, and +the response type name should be the method name suffixed with `Response`. For +example, the `GetAccountInfo` method has request type `GetAccountInfoRequest` and +response type `GetAccountInfoResponse`. + +After defining the protobuf messages for the new method, add an instantiation of the +templated `CallData` class in GRPCServerImpl::setupListeners(). The template +parameters should be the request type and the response type. + +Finally, define the handler itself in the appropriate file under the +src/ripple/rpc/handlers folder. If the method already has a JSON/Websocket +equivalent, write the gRPC handler in the same file, and abstract common logic +into helper functions (see Tx.cpp or AccountTx.cpp for an example). + +#### Testing + +When modifying an existing gRPC method, be sure to test that modification in the +corresponding, existing unit test. When creating a new gRPC method, implement a class that +derives from GRPCTestClientBase, and use the newly created class to call the new +method. See the class `GrpcTxClient` in the file Tx_test.cpp for an example. +The gRPC tests are paired with their JSON counterpart, and the tests should +mirror the JSON test as much as possible. + +Refer to the Protocol Buffers [language +guide](https://developers.google.com/protocol-buffers/docs/proto3) +for more detailed information about Protocol Buffers. + diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger.proto b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger.proto new file mode 100644 index 00000000000..0df9ca5ceb3 --- /dev/null +++ b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger.proto @@ -0,0 +1,94 @@ +syntax = "proto3"; + +package org.xrpl.rpc.v1; +option java_package = "org.xrpl.rpc.v1"; +option java_multiple_files = true; + +import "org/xrpl/rpc/v1/ledger.proto"; + +message GetLedgerRequest +{ + + LedgerSpecifier ledger = 1; + + // If true, include transactions contained in this ledger + bool transactions = 2; + + // If true and transactions, include full transactions and metadata + // If false and transactions, include only transaction hashes + bool expand = 3; + + // If true, include state map difference between this ledger and the + // previous ledger. This includes all added, modified or deleted ledger + // objects + bool get_objects = 4; + + // If the request needs to be forwarded from a reporting node to a p2p node, + // the reporting node will set this field. Clients should not set this + // field. + string client_ip = 5; + + // Identifying string. If user is set, client_ip is not set, and request is + // coming from a secure_gateway host, then the client is not subject to + // resource controls + string user = 6; + + // For every object in the diff, get the object's predecessor and successor + // in the state map. Only used if get_objects is also true. + bool get_object_neighbors = 7; +} + +message GetLedgerResponse +{ + bytes ledger_header = 1; + + oneof transactions + { + // Just the hashes + TransactionHashList hashes_list = 2; + + // Full transactions and metadata + TransactionAndMetadataList transactions_list = 3; + } + + // True if the ledger has been validated + bool validated = 4; + + // State map difference between this ledger and the previous ledger + RawLedgerObjects ledger_objects = 5; + + // True if the skiplist object is included in ledger_objects + bool skiplist_included = 6; + + // True if request was exempt from resource controls + bool is_unlimited = 7; + + // True if the response contains the state map diff + bool objects_included = 8; + + // True if the response contains key of objects adjacent to objects in state + // map diff + bool object_neighbors_included = 9; + + + // Successor information for book directories modified as part of this + // ledger + repeated BookSuccessor book_successors = 10; +} + +message TransactionHashList +{ + repeated bytes hashes = 1; +} + +message TransactionAndMetadata +{ + bytes transaction_blob = 1; + + bytes metadata_blob = 2; +} + +message TransactionAndMetadataList +{ + repeated TransactionAndMetadata transactions = 1; +} diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_data.proto b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_data.proto new file mode 100644 index 00000000000..c311994ac2f --- /dev/null +++ b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_data.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; + +package org.xrpl.rpc.v1; +option java_package = "org.xrpl.rpc.v1"; +option java_multiple_files = true; + +import "org/xrpl/rpc/v1/ledger.proto"; + +// Get ledger objects for a specific ledger. You can iterate through several +// calls to retrieve the entire contents of a single ledger version. +message GetLedgerDataRequest +{ + // If set, only objects with a key greater than marker are returned. + // This can be used to pick up where a previous call left off. + // Set marker to the value of marker in the previous response. + bytes marker = 1; + + LedgerSpecifier ledger = 2; + + // If set, only objects with a key less than end_marker are returned + bytes end_marker = 3; + + // If the request needs to be forwarded from a reporting node to a p2p node, + // the reporting node will set this field. Clients should not set this + // field. + string client_ip = 4; + + // Identifying string. If user is set, client_ip is not set, and request is + // coming from a secure_gateway host, then the client is not subject to + // resource controls + string user = 6; +} + +message GetLedgerDataResponse +{ + // Sequence of the ledger containing the returned ledger objects + uint32 ledger_index = 1; + + // Hash of the ledger containing the returned ledger objects + bytes ledger_hash = 2; + + // Ledger objects + RawLedgerObjects ledger_objects = 3; + + // Key to be passed into a subsequent call to continue iteration. If not + // set, there are no more objects left in the ledger, or no more objects + // with key less than end_marker (if end_marker was set in the request) + bytes marker = 4; + + // True if request was exempt from resource controls + bool is_unlimited = 7; +} + diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_diff.proto b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_diff.proto new file mode 100644 index 00000000000..218cbeb61fd --- /dev/null +++ b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_diff.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +package org.xrpl.rpc.v1; +option java_package = "org.xrpl.rpc.v1"; +option java_multiple_files = true; + +import "org/xrpl/rpc/v1/ledger.proto"; + + +// Get the state map difference between the two specified ledgers +message GetLedgerDiffRequest +{ + LedgerSpecifier base_ledger = 1; + + LedgerSpecifier desired_ledger = 2; + + // If true, include the full ledger object. If false, only keys are included. + bool include_blobs = 3; + + // If the request needs to be forwarded from a reporting node to a p2p node, + // the reporting node will set this field. Clients should not set this + // field. + string client_ip = 4; +} + +message GetLedgerDiffResponse +{ + // All ledger objects that were added, modified or deleted between + // base_ledger and desired_ledger + RawLedgerObjects ledger_objects = 1; +} + diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_entry.proto b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_entry.proto new file mode 100644 index 00000000000..a894c7729f5 --- /dev/null +++ b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_entry.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package org.xrpl.rpc.v1; +option java_package = "org.xrpl.rpc.v1"; +option java_multiple_files = true; + +import "org/xrpl/rpc/v1/ledger.proto"; + +// Get a single ledger object +message GetLedgerEntryRequest +{ + // Key of the desired object + bytes key = 1; + + // Ledger containing the object + LedgerSpecifier ledger = 2; + + // If the request needs to be forwarded from a reporting node to a p2p node, + // the reporting node will set this field. Clients should not set this + // field. + string client_ip = 3; +} + +message GetLedgerEntryResponse +{ + RawLedgerObject ledger_object = 1; + + // Ledger containing the object. Will match the value specified in the + // request. + LedgerSpecifier ledger = 2; +} diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/ledger.proto b/include/xrpl/proto/org/xrpl/rpc/v1/ledger.proto new file mode 100644 index 00000000000..3bb199de22f --- /dev/null +++ b/include/xrpl/proto/org/xrpl/rpc/v1/ledger.proto @@ -0,0 +1,75 @@ +syntax = "proto3"; + +package org.xrpl.rpc.v1; +option java_package = "org.xrpl.rpc.v1"; +option java_multiple_files = true; + +// Next field: 4 +message LedgerSpecifier +{ + // Next field: 4 + enum Shortcut + { + SHORTCUT_UNSPECIFIED = 0; + SHORTCUT_VALIDATED = 1; + SHORTCUT_CLOSED = 2; + SHORTCUT_CURRENT = 3; + } + + oneof ledger + { + Shortcut shortcut = 1; + uint32 sequence = 2; + // 32 bytes + bytes hash = 3; + } +} + + +// Next field: 3 +message RawLedgerObject +{ + // Raw data of the ledger object. In GetLedgerResponse and + // GetLedgerDiffResponse, data will be empty if the object was deleted. + bytes data = 1; + + // Key of the ledger object + bytes key = 2; + + enum ModificationType + { + UNSPECIFIED = 0; + CREATED = 1; + MODIFIED = 2; + DELETED = 3; + } + + // Whether the object was created, modified or deleted + ModificationType mod_type = 3; + + // Key of the object preceding this object in the desired ledger + bytes predecessor = 4; + + // Key of the object succeeding this object in the desired ledger + bytes successor = 5; +} + +message RawLedgerObjects +{ + repeated RawLedgerObject objects = 1; +} + +// Successor information for book directories. The book base is (usually) not +// an actual object, yet we need to be able to ask for the successor to the +// book base. +message BookSuccessor { + + // Base of the book in question + bytes book_base = 1; + + // First book directory in the book. An empty value here means the entire + // book is deleted + bytes first_book = 2; + +}; + diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto b/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto new file mode 100644 index 00000000000..01a23fbe375 --- /dev/null +++ b/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto @@ -0,0 +1,33 @@ +syntax = "proto3"; + +package org.xrpl.rpc.v1; +option java_package = "org.xrpl.rpc.v1"; +option java_multiple_files = true; + +import "org/xrpl/rpc/v1/get_ledger.proto"; +import "org/xrpl/rpc/v1/get_ledger_entry.proto"; +import "org/xrpl/rpc/v1/get_ledger_data.proto"; +import "org/xrpl/rpc/v1/get_ledger_diff.proto"; + + +// These methods are binary only methods for retrieiving arbitrary ledger state +// via gRPC. These methods are used by clio, but can also be +// used by any client that wants to extract ledger state in an efficient manner. +// They do not directly mimic the JSON equivalent methods. +service XRPLedgerAPIService { + + // Get a specific ledger, optionally including transactions and any modified, + // added or deleted ledger objects + rpc GetLedger(GetLedgerRequest) returns (GetLedgerResponse); + + // Get a specific ledger object from a specific ledger + rpc GetLedgerEntry(GetLedgerEntryRequest) returns (GetLedgerEntryResponse); + + // Iterate through all ledger objects in a specific ledger + rpc GetLedgerData(GetLedgerDataRequest) returns (GetLedgerDataResponse); + + // Get all ledger objects that are different between the two specified + // ledgers. Note, this method has no JSON equivalent. + rpc GetLedgerDiff(GetLedgerDiffRequest) returns (GetLedgerDiffResponse); + +} diff --git a/include/xrpl/proto/ripple.proto b/include/xrpl/proto/ripple.proto new file mode 100644 index 00000000000..a06bbd9a311 --- /dev/null +++ b/include/xrpl/proto/ripple.proto @@ -0,0 +1,387 @@ +syntax = "proto2"; +package protocol; + +// Unused numbers in the list below may have been used previously. Please don't +// reassign them for reuse unless you are 100% certain that there won't be a +// conflict. Even if you're sure, it's probably best to assign a new type. +enum MessageType +{ + mtMANIFESTS = 2; + mtPING = 3; + mtCLUSTER = 5; + mtENDPOINTS = 15; + mtTRANSACTION = 30; + mtGET_LEDGER = 31; + mtLEDGER_DATA = 32; + mtPROPOSE_LEDGER = 33; + mtSTATUS_CHANGE = 34; + mtHAVE_SET = 35; + mtVALIDATION = 41; + mtGET_OBJECTS = 42; + mtVALIDATORLIST = 54; + mtSQUELCH = 55; + mtVALIDATORLISTCOLLECTION = 56; + mtPROOF_PATH_REQ = 57; + mtPROOF_PATH_RESPONSE = 58; + mtREPLAY_DELTA_REQ = 59; + mtREPLAY_DELTA_RESPONSE = 60; + mtHAVE_TRANSACTIONS = 63; + mtTRANSACTIONS = 64; +} + +// token, iterations, target, challenge = issue demand for proof of work +// token, response = give solution to proof of work +// token, result = report result of pow + +//------------------------------------------------------------------------------ + +/* Provides the current ephemeral key for a validator. */ +message TMManifest +{ + // A Manifest object in the Ripple serialization format. + required bytes stobject = 1; +} + +message TMManifests +{ + repeated TMManifest list = 1; + + // The manifests sent when a peer first connects to another peer are `history`. + optional bool history = 2 [deprecated=true]; +} + +//------------------------------------------------------------------------------ + +// The status of a node in our cluster +message TMClusterNode +{ + required string publicKey = 1; + required uint32 reportTime = 2; + required uint32 nodeLoad = 3; + optional string nodeName = 4; + optional string address = 5; +} + +// Sources that are placing load on the server +message TMLoadSource +{ + required string name = 1; + required uint32 cost = 2; + optional uint32 count = 3; // number of connections +} + +// The status of all nodes in the cluster +message TMCluster +{ + repeated TMClusterNode clusterNodes = 1; + repeated TMLoadSource loadSources = 2; +} + +// Node public key +message TMLink +{ + required bytes nodePubKey = 1 [deprecated=true]; // node public key +} + +// Peer public key +message TMPublicKey +{ + required bytes publicKey = 1; +} + +// A transaction can have only one input and one output. +// If you want to send an amount that is greater than any single address of yours +// you must first combine coins from one address to another. + +enum TransactionStatus +{ + tsNEW = 1; // origin node did/could not validate + tsCURRENT = 2; // scheduled to go in this ledger + tsCOMMITED = 3; // in a closed ledger + tsREJECT_CONFLICT = 4; + tsREJECT_INVALID = 5; + tsREJECT_FUNDS = 6; + tsHELD_SEQ = 7; + tsHELD_LEDGER = 8; // held for future ledger +} + +message TMTransaction +{ + required bytes rawTransaction = 1; + required TransactionStatus status = 2; + optional uint64 receiveTimestamp = 3; + optional bool deferred = 4; // not applied to open ledger +} + +message TMTransactions +{ + repeated TMTransaction transactions = 1; +} + + +enum NodeStatus +{ + nsCONNECTING = 1; // acquiring connections + nsCONNECTED = 2; // convinced we are connected to the real network + nsMONITORING = 3; // we know what the previous ledger is + nsVALIDATING = 4; // we have the full ledger contents + nsSHUTTING = 5; // node is shutting down +} + +enum NodeEvent +{ + neCLOSING_LEDGER = 1; // closing a ledger because its close time has come + neACCEPTED_LEDGER = 2; // accepting a closed ledger, we have finished computing it + neSWITCHED_LEDGER = 3; // changing due to network consensus + neLOST_SYNC = 4; +} + +message TMStatusChange +{ + optional NodeStatus newStatus = 1; + optional NodeEvent newEvent = 2; + optional uint32 ledgerSeq = 3; + optional bytes ledgerHash = 4; + optional bytes ledgerHashPrevious = 5; + optional uint64 networkTime = 6; + optional uint32 firstSeq = 7; + optional uint32 lastSeq = 8; +} + + +// Announce to the network our position on a closing ledger +message TMProposeSet +{ + required uint32 proposeSeq = 1; + required bytes currentTxHash = 2; // the hash of the ledger we are proposing + required bytes nodePubKey = 3; + required uint32 closeTime = 4; + required bytes signature = 5; // signature of above fields + required bytes previousledger = 6; + repeated bytes addedTransactions = 10; // not required if number is large + repeated bytes removedTransactions = 11; // not required if number is large + + // node vouches signature is correct + optional bool checkedSignature = 7 [deprecated=true]; + + // Number of hops traveled + optional uint32 hops = 12 [deprecated=true]; +} + +enum TxSetStatus +{ + tsHAVE = 1; // We have this set locally + tsCAN_GET = 2; // We have a peer with this set + tsNEED = 3; // We need this set and can't get it +} + +message TMHaveTransactionSet +{ + required TxSetStatus status = 1; + required bytes hash = 2; +} + +// Validator list (UNL) +message TMValidatorList +{ + required bytes manifest = 1; + required bytes blob = 2; + required bytes signature = 3; + required uint32 version = 4; +} + +// Validator List v2 +message ValidatorBlobInfo +{ + optional bytes manifest = 1; + required bytes blob = 2; + required bytes signature = 3; +} + +// Collection of Validator List v2 (UNL) +message TMValidatorListCollection +{ + required uint32 version = 1; + required bytes manifest = 2; + repeated ValidatorBlobInfo blobs = 3; +} + +// Used to sign a final closed ledger after reprocessing +message TMValidation +{ + // The serialized validation + required bytes validation = 1; + + // node vouches signature is correct + optional bool checkedSignature = 2 [deprecated = true]; + + // Number of hops traveled + optional uint32 hops = 3 [deprecated = true]; +} + +// An array of Endpoint messages +message TMEndpoints +{ + // Previously used - don't reuse. + reserved 2; + + // This field is used to allow the TMEndpoints message format to be + // modified as necessary in the future. + required uint32 version = 1; + + // An update to the Endpoint type that uses a string + // to represent endpoints, thus allowing ipv6 or ipv4 addresses + message TMEndpointv2 + { + required string endpoint = 1; + required uint32 hops = 2; + } + repeated TMEndpointv2 endpoints_v2 = 3; +}; + +message TMIndexedObject +{ + optional bytes hash = 1; + optional bytes nodeID = 2; + optional bytes index = 3; + optional bytes data = 4; + optional uint32 ledgerSeq = 5; +} + +message TMGetObjectByHash +{ + enum ObjectType { + otUNKNOWN = 0; + otLEDGER = 1; + otTRANSACTION = 2; + otTRANSACTION_NODE = 3; + otSTATE_NODE = 4; + otCAS_OBJECT = 5; + otFETCH_PACK = 6; + otTRANSACTIONS = 7; + } + + required ObjectType type = 1; + required bool query = 2; // is this a query or a reply? + optional uint32 seq = 3; // used to match replies to queries + optional bytes ledgerHash = 4; // the hash of the ledger these queries are for + optional bool fat = 5; // return related nodes + repeated TMIndexedObject objects = 6; // the specific objects requested +} + + +message TMLedgerNode +{ + required bytes nodedata = 1; + optional bytes nodeid = 2; // missing for ledger base data +} + +enum TMLedgerInfoType +{ + liBASE = 0; // basic ledger info + liTX_NODE = 1; // transaction node + liAS_NODE = 2; // account state node + liTS_CANDIDATE = 3; // candidate transaction set +} + +enum TMLedgerType +{ + ltACCEPTED = 0; + ltCURRENT = 1; // no longer supported + ltCLOSED = 2; +} + +enum TMQueryType +{ + qtINDIRECT = 0; +} + +message TMGetLedger +{ + required TMLedgerInfoType itype = 1; + optional TMLedgerType ltype = 2; + optional bytes ledgerHash = 3; // Can also be the transaction set hash if liTS_CANDIDATE + optional uint32 ledgerSeq = 4; + repeated bytes nodeIDs = 5; + optional uint64 requestCookie = 6; + optional TMQueryType queryType = 7; + optional uint32 queryDepth = 8; // How deep to go, number of extra levels +} + +enum TMReplyError +{ + reNO_LEDGER = 1; // We don't have the ledger you are asking about + reNO_NODE = 2; // We don't have any of the nodes you are asking for + reBAD_REQUEST = 3; // The request is wrong, e.g. wrong format +} + +message TMLedgerData +{ + required bytes ledgerHash = 1; + required uint32 ledgerSeq = 2; + required TMLedgerInfoType type = 3; + repeated TMLedgerNode nodes = 4; + optional uint32 requestCookie = 5; + optional TMReplyError error = 6; +} + +message TMPing +{ + enum pingType { + ptPING = 0; // we want a reply + ptPONG = 1; // this is a reply + } + required pingType type = 1; + optional uint32 seq = 2; // detect stale replies, ensure other side is reading + optional uint64 pingTime = 3; // know when we think we sent the ping + optional uint64 netTime = 4; +} + +message TMSquelch +{ + required bool squelch = 1; // squelch if true, otherwise unsquelch + required bytes validatorPubKey = 2; // validator's public key + optional uint32 squelchDuration = 3; // squelch duration in seconds +} + +enum TMLedgerMapType +{ + lmTRANASCTION = 1; // transaction map + lmACCOUNT_STATE = 2; // account state map +} + +message TMProofPathRequest +{ + required bytes key = 1; + required bytes ledgerHash = 2; + required TMLedgerMapType type = 3; +} + +message TMProofPathResponse +{ + required bytes key = 1; + required bytes ledgerHash = 2; + required TMLedgerMapType type = 3; + optional bytes ledgerHeader = 4; + repeated bytes path = 5; + optional TMReplyError error = 6; +} + +message TMReplayDeltaRequest +{ + required bytes ledgerHash = 1; +} + +message TMReplayDeltaResponse +{ + required bytes ledgerHash = 1; + optional bytes ledgerHeader = 2; + repeated bytes transaction = 3; + optional TMReplyError error = 4; +} + +message TMHaveTransactions +{ + repeated bytes hashes = 1; +} + diff --git a/include/xrpl/protocol/AMMCore.h b/include/xrpl/protocol/AMMCore.h new file mode 100644 index 00000000000..32988af5fc7 --- /dev/null +++ b/include/xrpl/protocol/AMMCore.h @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_AMMCORE_H_INCLUDED +#define RIPPLE_PROTOCOL_AMMCORE_H_INCLUDED + +#include +#include +#include +#include +#include + +namespace ripple { + +std::uint16_t constexpr TRADING_FEE_THRESHOLD = 1000; // 1% + +// Auction slot +std::uint32_t constexpr TOTAL_TIME_SLOT_SECS = 24 * 3600; +std::uint16_t constexpr AUCTION_SLOT_TIME_INTERVALS = 20; +std::uint16_t constexpr AUCTION_SLOT_MAX_AUTH_ACCOUNTS = 4; +std::uint32_t constexpr AUCTION_SLOT_FEE_SCALE_FACTOR = 100000; +std::uint32_t constexpr AUCTION_SLOT_DISCOUNTED_FEE_FRACTION = 10; +std::uint32_t constexpr AUCTION_SLOT_MIN_FEE_FRACTION = 25; +std::uint32_t constexpr AUCTION_SLOT_INTERVAL_DURATION = + TOTAL_TIME_SLOT_SECS / AUCTION_SLOT_TIME_INTERVALS; + +// Votes +std::uint16_t constexpr VOTE_MAX_SLOTS = 8; +std::uint32_t constexpr VOTE_WEIGHT_SCALE_FACTOR = 100000; + +class STObject; +class STAmount; +class Rules; + +/** Calculate AMM account ID. + */ +AccountID +ammAccountID( + std::uint16_t prefix, + uint256 const& parentHash, + uint256 const& ammID); + +/** Calculate Liquidity Provider Token (LPT) Currency. + */ +Currency +ammLPTCurrency(Currency const& cur1, Currency const& cur2); + +/** Calculate LPT Issue from AMM asset pair. + */ +Issue +ammLPTIssue( + Currency const& cur1, + Currency const& cur2, + AccountID const& ammAccountID); + +/** Validate the amount. + * If validZero is false and amount is beast::zero then invalid amount. + * Return error code if invalid amount. + * If pair then validate amount's issue matches one of the pair's issue. + */ +NotTEC +invalidAMMAmount( + STAmount const& amount, + std::optional> const& pair = std::nullopt, + bool validZero = false); + +NotTEC +invalidAMMAsset( + Issue const& issue, + std::optional> const& pair = std::nullopt); + +NotTEC +invalidAMMAssetPair( + Issue const& issue1, + Issue const& issue2, + std::optional> const& pair = std::nullopt); + +/** Get time slot of the auction slot. + */ +std::optional +ammAuctionTimeSlot(std::uint64_t current, STObject const& auctionSlot); + +/** Return true if required AMM amendments are enabled + */ +bool +ammEnabled(Rules const&); + +/** Convert to the fee from the basis points + * @param tfee trading fee in {0, 1000} + * 1 = 1/10bps or 0.001%, 1000 = 1% + */ +inline Number +getFee(std::uint16_t tfee) +{ + return Number{tfee} / AUCTION_SLOT_FEE_SCALE_FACTOR; +} + +/** Get fee multiplier (1 - tfee) + * @tfee trading fee in basis points + */ +inline Number +feeMult(std::uint16_t tfee) +{ + return 1 - getFee(tfee); +} + +/** Get fee multiplier (1 - tfee / 2) + * @tfee trading fee in basis points + */ +inline Number +feeMultHalf(std::uint16_t tfee) +{ + return 1 - getFee(tfee) / 2; +} + +} // namespace ripple + +#endif // RIPPLE_PROTOCOL_AMMCORE_H_INCLUDED diff --git a/include/xrpl/protocol/AccountID.h b/include/xrpl/protocol/AccountID.h new file mode 100644 index 00000000000..2677dd76bce --- /dev/null +++ b/include/xrpl/protocol/AccountID.h @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2014 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED +#define RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED + +#include +// VFALCO Uncomment when the header issues are resolved +// #include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace ripple { + +namespace detail { + +class AccountIDTag +{ +public: + explicit AccountIDTag() = default; +}; + +} // namespace detail + +/** A 160-bit unsigned that uniquely identifies an account. */ +using AccountID = base_uint<160, detail::AccountIDTag>; + +/** Convert AccountID to base58 checked string */ +std::string +toBase58(AccountID const& v); + +/** Parse AccountID from checked, base58 string. + @return std::nullopt if a parse error occurs +*/ +template <> +std::optional +parseBase58(std::string const& s); + +/** Compute AccountID from public key. + + The account ID is computed as the 160-bit hash of the + public key data. This excludes the version byte and + guard bytes included in the base58 representation. + +*/ +// VFALCO In PublicKey.h for now +// AccountID +// calcAccountID (PublicKey const& pk); + +/** A special account that's used as the "issuer" for XRP. */ +AccountID const& +xrpAccount(); + +/** A placeholder for empty accounts. */ +AccountID const& +noAccount(); + +/** Convert hex or base58 string to AccountID. + + @return `true` if the parsing was successful. +*/ +// DEPRECATED +bool +to_issuer(AccountID&, std::string const&); + +// DEPRECATED Should be checking the currency or native flag +inline bool +isXRP(AccountID const& c) +{ + return c == beast::zero; +} + +// DEPRECATED +inline std::string +to_string(AccountID const& account) +{ + return toBase58(account); +} + +// DEPRECATED +inline std::ostream& +operator<<(std::ostream& os, AccountID const& x) +{ + os << to_string(x); + return os; +} + +/** Initialize the global cache used to map AccountID to base58 conversions. + + The cache is optional and need not be initialized. But because conversion + is expensive (it requires a SHA-256 operation) in most cases the overhead + of the cache is worth the benefit. + + @param count The number of entries the cache should accommodate. Zero will + disable the cache, releasing any memory associated with it. + + @note The function will only initialize the cache the first time it is + invoked. Subsequent invocations do nothing. + */ +void +initAccountIdCache(std::size_t count); + +} // namespace ripple + +//------------------------------------------------------------------------------ +namespace Json { +template <> +inline ripple::AccountID +getOrThrow(Json::Value const& v, ripple::SField const& field) +{ + using namespace ripple; + + std::string const b58 = getOrThrow(v, field); + if (auto const r = parseBase58(b58)) + return *r; + Throw(field.getJsonName(), "AccountID"); +} +} // namespace Json + +//------------------------------------------------------------------------------ + +namespace std { + +// DEPRECATED +// VFALCO Use beast::uhash or a hardened container +template <> +struct hash : ripple::AccountID::hasher +{ + explicit hash() = default; +}; + +} // namespace std + +#endif diff --git a/include/xrpl/protocol/AmountConversions.h b/include/xrpl/protocol/AmountConversions.h new file mode 100644 index 00000000000..a65f7fcad8b --- /dev/null +++ b/include/xrpl/protocol/AmountConversions.h @@ -0,0 +1,220 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_AMOUNTCONVERSION_H_INCLUDED +#define RIPPLE_PROTOCOL_AMOUNTCONVERSION_H_INCLUDED + +#include +#include +#include + +#include + +namespace ripple { + +inline STAmount +toSTAmount(IOUAmount const& iou, Issue const& iss) +{ + bool const isNeg = iou.signum() < 0; + std::uint64_t const umant = isNeg ? -iou.mantissa() : iou.mantissa(); + return STAmount(iss, umant, iou.exponent(), isNeg, STAmount::unchecked()); +} + +inline STAmount +toSTAmount(IOUAmount const& iou) +{ + return toSTAmount(iou, noIssue()); +} + +inline STAmount +toSTAmount(XRPAmount const& xrp) +{ + bool const isNeg = xrp.signum() < 0; + std::uint64_t const umant = isNeg ? -xrp.drops() : xrp.drops(); + return STAmount(umant, isNeg); +} + +inline STAmount +toSTAmount(XRPAmount const& xrp, Issue const& iss) +{ + XRPL_ASSERT( + isXRP(iss.account) && isXRP(iss.currency), + "ripple::toSTAmount : is XRP"); + return toSTAmount(xrp); +} + +template +T +toAmount(STAmount const& amt) = delete; + +template <> +inline STAmount +toAmount(STAmount const& amt) +{ + return amt; +} + +template <> +inline IOUAmount +toAmount(STAmount const& amt) +{ + XRPL_ASSERT( + amt.mantissa() < std::numeric_limits::max(), + "ripple::toAmount : maximum mantissa"); + bool const isNeg = amt.negative(); + std::int64_t const sMant = + isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); + + XRPL_ASSERT(!isXRP(amt), "ripple::toAmount : is not XRP"); + return IOUAmount(sMant, amt.exponent()); +} + +template <> +inline XRPAmount +toAmount(STAmount const& amt) +{ + XRPL_ASSERT( + amt.mantissa() < std::numeric_limits::max(), + "ripple::toAmount : maximum mantissa"); + bool const isNeg = amt.negative(); + std::int64_t const sMant = + isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); + + XRPL_ASSERT(isXRP(amt), "ripple::toAmount : is XRP"); + return XRPAmount(sMant); +} + +template +T +toAmount(IOUAmount const& amt) = delete; + +template <> +inline IOUAmount +toAmount(IOUAmount const& amt) +{ + return amt; +} + +template +T +toAmount(XRPAmount const& amt) = delete; + +template <> +inline XRPAmount +toAmount(XRPAmount const& amt) +{ + return amt; +} + +template +T +toAmount( + Issue const& issue, + Number const& n, + Number::rounding_mode mode = Number::getround()) +{ + saveNumberRoundMode rm(Number::getround()); + if (isXRP(issue)) + Number::setround(mode); + + if constexpr (std::is_same_v) + return IOUAmount(n); + else if constexpr (std::is_same_v) + return XRPAmount(static_cast(n)); + else if constexpr (std::is_same_v) + { + if (isXRP(issue)) + return STAmount(issue, static_cast(n)); + return STAmount(issue, n.mantissa(), n.exponent()); + } + else + { + constexpr bool alwaysFalse = !std::is_same_v; + static_assert(alwaysFalse, "Unsupported type for toAmount"); + } +} + +template +T +toMaxAmount(Issue const& issue) +{ + if constexpr (std::is_same_v) + return IOUAmount(STAmount::cMaxValue, STAmount::cMaxOffset); + else if constexpr (std::is_same_v) + return XRPAmount(static_cast(STAmount::cMaxNativeN)); + else if constexpr (std::is_same_v) + { + if (isXRP(issue)) + return STAmount( + issue, static_cast(STAmount::cMaxNativeN)); + return STAmount(issue, STAmount::cMaxValue, STAmount::cMaxOffset); + } + else + { + constexpr bool alwaysFalse = !std::is_same_v; + static_assert(alwaysFalse, "Unsupported type for toMaxAmount"); + } +} + +inline STAmount +toSTAmount( + Issue const& issue, + Number const& n, + Number::rounding_mode mode = Number::getround()) +{ + return toAmount(issue, n, mode); +} + +template +Issue +getIssue(T const& amt) +{ + if constexpr (std::is_same_v) + return noIssue(); + else if constexpr (std::is_same_v) + return xrpIssue(); + else if constexpr (std::is_same_v) + return amt.issue(); + else + { + constexpr bool alwaysFalse = !std::is_same_v; + static_assert(alwaysFalse, "Unsupported type for getIssue"); + } +} + +template +constexpr T +get(STAmount const& a) +{ + if constexpr (std::is_same_v) + return a.iou(); + else if constexpr (std::is_same_v) + return a.xrp(); + else if constexpr (std::is_same_v) + return a; + else + { + constexpr bool alwaysFalse = !std::is_same_v; + static_assert(alwaysFalse, "Unsupported type for get"); + } +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/ApiVersion.h b/include/xrpl/protocol/ApiVersion.h new file mode 100644 index 00000000000..dd09cf6bd1a --- /dev/null +++ b/include/xrpl/protocol/ApiVersion.h @@ -0,0 +1,116 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED +#define RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +/** + * API version numbers used in later API versions + * + * Requests with a version number in the range + * [apiMinimumSupportedVersion, apiMaximumSupportedVersion] + * are supported. + * + * If [beta_rpc_api] is enabled in config, the version numbers + * in the range [apiMinimumSupportedVersion, apiBetaVersion] + * are supported. + * + * Network Requests without explicit version numbers use + * apiVersionIfUnspecified. apiVersionIfUnspecified is 1, + * because all the RPC requests with a version >= 2 must + * explicitly specify the version in the requests. + * Note that apiVersionIfUnspecified will be lower than + * apiMinimumSupportedVersion when we stop supporting API + * version 1. + * + * Command line Requests use apiCommandLineVersion. + */ + +namespace RPC { + +template +constexpr static std::integral_constant apiVersion = {}; + +constexpr static auto apiInvalidVersion = apiVersion<0>; +constexpr static auto apiMinimumSupportedVersion = apiVersion<1>; +constexpr static auto apiMaximumSupportedVersion = apiVersion<2>; +constexpr static auto apiVersionIfUnspecified = apiVersion<1>; +constexpr static auto apiCommandLineVersion = + apiVersion<1>; // TODO Bump to 2 later +constexpr static auto apiBetaVersion = apiVersion<3>; +constexpr static auto apiMaximumValidVersion = apiBetaVersion; + +static_assert(apiInvalidVersion < apiMinimumSupportedVersion); +static_assert( + apiVersionIfUnspecified >= apiMinimumSupportedVersion && + apiVersionIfUnspecified <= apiMaximumSupportedVersion); +static_assert( + apiCommandLineVersion >= apiMinimumSupportedVersion && + apiCommandLineVersion <= apiMaximumSupportedVersion); +static_assert(apiMaximumSupportedVersion >= apiMinimumSupportedVersion); +static_assert(apiBetaVersion >= apiMaximumSupportedVersion); +static_assert(apiMaximumValidVersion >= apiMaximumSupportedVersion); + +} // namespace RPC + +template +void +forApiVersions(Fn const& fn, Args&&... args) + requires // + (maxVer >= minVer) && // + (minVer >= RPC::apiMinimumSupportedVersion) && // + (RPC::apiMaximumValidVersion >= maxVer) && requires { + fn(std::integral_constant{}, + std::forward(args)...); + fn(std::integral_constant{}, + std::forward(args)...); + } +{ + constexpr auto size = maxVer + 1 - minVer; + [&](std::index_sequence) { + (((void)fn( + std::integral_constant{}, + std::forward(args)...)), + ...); + }(std::make_index_sequence{}); +} + +template +void +forAllApiVersions(Fn const& fn, Args&&... args) + requires requires { + forApiVersions< + RPC::apiMinimumSupportedVersion, + RPC::apiMaximumValidVersion>(fn, std::forward(args)...); + } +{ + forApiVersions< + RPC::apiMinimumSupportedVersion, + RPC::apiMaximumValidVersion>(fn, std::forward(args)...); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/Asset.h b/include/xrpl/protocol/Asset.h new file mode 100644 index 00000000000..0d12cd40580 --- /dev/null +++ b/include/xrpl/protocol/Asset.h @@ -0,0 +1,227 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_ASSET_H_INCLUDED +#define RIPPLE_PROTOCOL_ASSET_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +class Asset; + +template +concept ValidIssueType = + std::is_same_v || std::is_same_v; + +template +concept AssetType = + std::is_convertible_v || std::is_convertible_v || + std::is_convertible_v || std::is_convertible_v; + +/* Asset is an abstraction of three different issue types: XRP, IOU, MPT. + * For historical reasons, two issue types XRP and IOU are wrapped in Issue + * type. Many functions and classes there were first written for Issue + * have been rewritten for Asset. + */ +class Asset +{ +public: + using value_type = std::variant; + +private: + value_type issue_; + +public: + Asset() = default; + + /** Conversions to Asset are implicit and conversions to specific issue + * type are explicit. This design facilitates the use of Asset. + */ + Asset(Issue const& issue) : issue_(issue) + { + } + + Asset(MPTIssue const& mptIssue) : issue_(mptIssue) + { + } + + Asset(MPTID const& issuanceID) : issue_(MPTIssue{issuanceID}) + { + } + + AccountID const& + getIssuer() const; + + template + constexpr TIss const& + get() const; + + template + TIss& + get(); + + template + constexpr bool + holds() const; + + std::string + getText() const; + + constexpr value_type const& + value() const; + + void + setJson(Json::Value& jv) const; + + bool + native() const + { + return holds() && get().native(); + } + + friend constexpr bool + operator==(Asset const& lhs, Asset const& rhs); + + friend constexpr std::weak_ordering + operator<=>(Asset const& lhs, Asset const& rhs); + + friend constexpr bool + operator==(Currency const& lhs, Asset const& rhs); + + /** Return true if both assets refer to the same currency (regardless of + * issuer) or MPT issuance. Otherwise return false. + */ + friend constexpr bool + equalTokens(Asset const& lhs, Asset const& rhs); +}; + +template +constexpr bool +Asset::holds() const +{ + return std::holds_alternative(issue_); +} + +template +constexpr TIss const& +Asset::get() const +{ + if (!std::holds_alternative(issue_)) + Throw("Asset is not a requested issue"); + return std::get(issue_); +} + +template +TIss& +Asset::get() +{ + if (!std::holds_alternative(issue_)) + Throw("Asset is not a requested issue"); + return std::get(issue_); +} + +constexpr Asset::value_type const& +Asset::value() const +{ + return issue_; +} + +constexpr bool +operator==(Asset const& lhs, Asset const& rhs) +{ + return std::visit( + [&]( + TLhs const& issLhs, TRhs const& issRhs) { + if constexpr (std::is_same_v) + return issLhs == issRhs; + else + return false; + }, + lhs.issue_, + rhs.issue_); +} + +constexpr std::weak_ordering +operator<=>(Asset const& lhs, Asset const& rhs) +{ + return std::visit( + []( + TLhs const& lhs_, TRhs const& rhs_) { + if constexpr (std::is_same_v) + return std::weak_ordering(lhs_ <=> rhs_); + else if constexpr ( + std::is_same_v && std::is_same_v) + return std::weak_ordering::greater; + else + return std::weak_ordering::less; + }, + lhs.issue_, + rhs.issue_); +} + +constexpr bool +operator==(Currency const& lhs, Asset const& rhs) +{ + return rhs.holds() && rhs.get().currency == lhs; +} + +constexpr bool +equalTokens(Asset const& lhs, Asset const& rhs) +{ + return std::visit( + [&]( + TLhs const& issLhs, TRhs const& issRhs) { + if constexpr ( + std::is_same_v && std::is_same_v) + return issLhs.currency == issRhs.currency; + else if constexpr ( + std::is_same_v && + std::is_same_v) + return issLhs.getMptID() == issRhs.getMptID(); + else + return false; + }, + lhs.issue_, + rhs.issue_); +} + +inline bool +isXRP(Asset const& asset) +{ + return asset.native(); +} + +std::string +to_string(Asset const& asset); + +bool +validJSONAsset(Json::Value const& jv); + +Asset +assetFromJson(Json::Value const& jv); + +Json::Value +to_json(Asset const& asset); + +} // namespace ripple + +#endif // RIPPLE_PROTOCOL_ASSET_H_INCLUDED diff --git a/include/xrpl/protocol/Book.h b/include/xrpl/protocol/Book.h new file mode 100644 index 00000000000..0a04deb2771 --- /dev/null +++ b/include/xrpl/protocol/Book.h @@ -0,0 +1,176 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_BOOK_H_INCLUDED +#define RIPPLE_PROTOCOL_BOOK_H_INCLUDED + +#include +#include + +#include + +namespace ripple { + +/** Specifies an order book. + The order book is a pair of Issues called in and out. + @see Issue. +*/ +class Book final : public CountedObject +{ +public: + Issue in; + Issue out; + + Book() + { + } + + Book(Issue const& in_, Issue const& out_) : in(in_), out(out_) + { + } +}; + +bool +isConsistent(Book const& book); + +std::string +to_string(Book const& book); + +std::ostream& +operator<<(std::ostream& os, Book const& x); + +template +void +hash_append(Hasher& h, Book const& b) +{ + using beast::hash_append; + hash_append(h, b.in, b.out); +} + +Book +reversed(Book const& book); + +/** Equality comparison. */ +/** @{ */ +[[nodiscard]] inline constexpr bool +operator==(Book const& lhs, Book const& rhs) +{ + return (lhs.in == rhs.in) && (lhs.out == rhs.out); +} +/** @} */ + +/** Strict weak ordering. */ +/** @{ */ +[[nodiscard]] inline constexpr std::weak_ordering +operator<=>(Book const& lhs, Book const& rhs) +{ + if (auto const c{lhs.in <=> rhs.in}; c != 0) + return c; + return lhs.out <=> rhs.out; +} +/** @} */ + +} // namespace ripple + +//------------------------------------------------------------------------------ + +namespace std { + +template <> +struct hash + : private boost::base_from_member, 0>, + private boost::base_from_member, 1> +{ +private: + using currency_hash_type = + boost::base_from_member, 0>; + using issuer_hash_type = + boost::base_from_member, 1>; + +public: + explicit hash() = default; + + using value_type = std::size_t; + using argument_type = ripple::Issue; + + value_type + operator()(argument_type const& value) const + { + value_type result(currency_hash_type::member(value.currency)); + if (!isXRP(value.currency)) + boost::hash_combine( + result, issuer_hash_type::member(value.account)); + return result; + } +}; + +//------------------------------------------------------------------------------ + +template <> +struct hash +{ +private: + using hasher = std::hash; + + hasher m_hasher; + +public: + explicit hash() = default; + + using value_type = std::size_t; + using argument_type = ripple::Book; + + value_type + operator()(argument_type const& value) const + { + value_type result(m_hasher(value.in)); + boost::hash_combine(result, m_hasher(value.out)); + return result; + } +}; + +} // namespace std + +//------------------------------------------------------------------------------ + +namespace boost { + +template <> +struct hash : std::hash +{ + explicit hash() = default; + + using Base = std::hash; + // VFALCO NOTE broken in vs2012 + // using Base::Base; // inherit ctors +}; + +template <> +struct hash : std::hash +{ + explicit hash() = default; + + using Base = std::hash; + // VFALCO NOTE broken in vs2012 + // using Base::Base; // inherit ctors +}; + +} // namespace boost + +#endif diff --git a/include/xrpl/protocol/BuildInfo.h b/include/xrpl/protocol/BuildInfo.h new file mode 100644 index 00000000000..cfe35d3383b --- /dev/null +++ b/include/xrpl/protocol/BuildInfo.h @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_BUILDINFO_H_INCLUDED +#define RIPPLE_PROTOCOL_BUILDINFO_H_INCLUDED + +#include +#include + +namespace ripple { + +/** Versioning information for this build. */ +// VFALCO The namespace is deprecated +namespace BuildInfo { + +/** Server version. + Follows the Semantic Versioning Specification: + http://semver.org/ +*/ +std::string const& +getVersionString(); + +/** Full server version string. + This includes the name of the server. It is used in the peer + protocol hello message and also the headers of some HTTP replies. +*/ +std::string const& +getFullVersionString(); + +/** Encode an arbitrary server software version in a 64-bit integer. + + The general format is: + + ........-........-........-........-........-........-........-........ + XXXXXXXX-XXXXXXXX-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY + + X: 16 bits identifying the particular implementation + Y: 48 bits of data specific to the implementation + + The rippled-specific format (implementation ID is: 0x18 0x3B) is: + + 00011000-00111011-MMMMMMMM-mmmmmmmm-pppppppp-TTNNNNNN-00000000-00000000 + + M: 8-bit major version (0-255) + m: 8-bit minor version (0-255) + p: 8-bit patch version (0-255) + T: 11 if neither an RC nor a beta + 10 if an RC + 01 if a beta + N: 6-bit rc/beta number (1-63) + + @param the version string + @return the encoded version in a 64-bit integer +*/ +std::uint64_t +encodeSoftwareVersion(char const* const versionStr); + +/** Returns this server's version packed in a 64-bit integer. */ +std::uint64_t +getEncodedVersion(); + +/** Check if the encoded software version is a rippled software version. + + @param version another node's encoded software version + @return true if the version is a rippled software version, false otherwise +*/ +bool +isRippledVersion(std::uint64_t version); + +/** Check if the version is newer than the local node's rippled software + version. + + @param version another node's encoded software version + @return true if the version is newer than the local node's rippled software + version, false otherwise. + + @note This function only understands version numbers that are generated by + rippled. Please see the encodeSoftwareVersion() function for detail. +*/ +bool +isNewerVersion(std::uint64_t version); + +} // namespace BuildInfo + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/ErrorCodes.h b/include/xrpl/protocol/ErrorCodes.h new file mode 100644 index 00000000000..2e7cb3b410f --- /dev/null +++ b/include/xrpl/protocol/ErrorCodes.h @@ -0,0 +1,374 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012 - 2019 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_ERRORCODES_H_INCLUDED +#define RIPPLE_PROTOCOL_ERRORCODES_H_INCLUDED + +#include +#include + +namespace ripple { + +// VFALCO NOTE These are outside the RPC namespace + +// NOTE: Although the precise numeric values of these codes were never +// intended to be stable, several API endpoints include the numeric values. +// Some users came to rely on the values, meaning that renumbering would be +// a breaking change for those users. +// +// We therefore treat the range of values as stable although they are not +// and are subject to change. +// +// Please only append to this table. Do not "fill-in" gaps and do not re-use +// or repurpose error code values. +enum error_code_i { + // -1 represents codes not listed in this enumeration + rpcUNKNOWN = -1, + + rpcSUCCESS = 0, + + rpcBAD_SYNTAX = 1, + rpcJSON_RPC = 2, + rpcFORBIDDEN = 3, + + rpcWRONG_NETWORK = 4, + // Misc failure + // unused 5, + rpcNO_PERMISSION = 6, + rpcNO_EVENTS = 7, + // unused 8, + rpcTOO_BUSY = 9, + rpcSLOW_DOWN = 10, + rpcHIGH_FEE = 11, + rpcNOT_ENABLED = 12, + rpcNOT_READY = 13, + rpcAMENDMENT_BLOCKED = 14, + + // Networking + rpcNO_CLOSED = 15, + rpcNO_CURRENT = 16, + rpcNO_NETWORK = 17, + rpcNOT_SYNCED = 18, + + // Ledger state + rpcACT_NOT_FOUND = 19, + // unused 20, + rpcLGR_NOT_FOUND = 21, + rpcLGR_NOT_VALIDATED = 22, + rpcMASTER_DISABLED = 23, + // unused 24, + // unused 25, + // unused 26, + // unused 27, + // unused 28, + rpcTXN_NOT_FOUND = 29, + rpcINVALID_HOTWALLET = 30, + + // Malformed command + rpcINVALID_PARAMS = 31, + rpcUNKNOWN_COMMAND = 32, + rpcNO_PF_REQUEST = 33, + + // Bad parameter + // NOT USED DO NOT USE AGAIN rpcACT_BITCOIN = 34, + rpcACT_MALFORMED = 35, + rpcALREADY_MULTISIG = 36, + rpcALREADY_SINGLE_SIG = 37, + // unused 38, + // unused 39, + rpcBAD_FEATURE = 40, + rpcBAD_ISSUER = 41, + rpcBAD_MARKET = 42, + rpcBAD_SECRET = 43, + rpcBAD_SEED = 44, + rpcCHANNEL_MALFORMED = 45, + rpcCHANNEL_AMT_MALFORMED = 46, + rpcCOMMAND_MISSING = 47, + rpcDST_ACT_MALFORMED = 48, + rpcDST_ACT_MISSING = 49, + rpcDST_ACT_NOT_FOUND = 50, + rpcDST_AMT_MALFORMED = 51, + rpcDST_AMT_MISSING = 52, + rpcDST_ISR_MALFORMED = 53, + // unused 54, + // unused 55, + // unused 56, + rpcLGR_IDXS_INVALID = 57, + rpcLGR_IDX_MALFORMED = 58, + // unused 59, + // unused 60, + // unused 61, + rpcPUBLIC_MALFORMED = 62, + rpcSIGNING_MALFORMED = 63, + rpcSENDMAX_MALFORMED = 64, + rpcSRC_ACT_MALFORMED = 65, + rpcSRC_ACT_MISSING = 66, + rpcSRC_ACT_NOT_FOUND = 67, + // unused 68, + rpcSRC_CUR_MALFORMED = 69, + rpcSRC_ISR_MALFORMED = 70, + rpcSTREAM_MALFORMED = 71, + rpcATX_DEPRECATED = 72, + + // Internal error (should never happen) + rpcINTERNAL = 73, // Generic internal error. + rpcNOT_IMPL = 74, + rpcNOT_SUPPORTED = 75, + rpcBAD_KEY_TYPE = 76, + rpcDB_DESERIALIZATION = 77, + rpcEXCESSIVE_LGR_RANGE = 78, + rpcINVALID_LGR_RANGE = 79, + rpcEXPIRED_VALIDATOR_LIST = 80, + + // unused = 90, + // DEPRECATED. New code must not use this value. + rpcREPORTING_UNSUPPORTED = 91, + + rpcOBJECT_NOT_FOUND = 92, + + // AMM + rpcISSUE_MALFORMED = 93, + + // Oracle + rpcORACLE_MALFORMED = 94, + + // deposit_authorized + credentials + rpcBAD_CREDENTIALS = 95, + + // Simulate + rpcTX_SIGNED = 96, + + rpcLAST = rpcTX_SIGNED // rpcLAST should always equal the last code. +}; + +/** Codes returned in the `warnings` array of certain RPC commands. + + These values need to remain stable. +*/ +enum warning_code_i { + warnRPC_UNSUPPORTED_MAJORITY = 1001, + warnRPC_AMENDMENT_BLOCKED = 1002, + warnRPC_EXPIRED_VALIDATOR_LIST = 1003, + // unused = 1004 +}; + +//------------------------------------------------------------------------------ + +// VFALCO NOTE these should probably not be in the RPC namespace. + +namespace RPC { + +/** Maps an rpc error code to its token, default message, and HTTP status. */ +struct ErrorInfo +{ + // Default ctor needed to produce an empty std::array during constexpr eval. + constexpr ErrorInfo() + : code(rpcUNKNOWN) + , token("unknown") + , message("An unknown error code.") + , http_status(200) + { + } + + constexpr ErrorInfo( + error_code_i code_, + char const* token_, + char const* message_) + : code(code_), token(token_), message(message_), http_status(200) + { + } + + constexpr ErrorInfo( + error_code_i code_, + char const* token_, + char const* message_, + int http_status_) + : code(code_) + , token(token_) + , message(message_) + , http_status(http_status_) + { + } + + error_code_i code; + Json::StaticString token; + Json::StaticString message; + int http_status; +}; + +/** Returns an ErrorInfo that reflects the error code. */ +ErrorInfo const& +get_error_info(error_code_i code); + +/** Add or update the json update to reflect the error code. */ +/** @{ */ +template +void +inject_error(error_code_i code, JsonValue& json) +{ + ErrorInfo const& info(get_error_info(code)); + json[jss::error] = info.token; + json[jss::error_code] = info.code; + json[jss::error_message] = info.message; +} + +template +void +inject_error(int code, JsonValue& json) +{ + inject_error(error_code_i(code), json); +} + +template +void +inject_error(error_code_i code, std::string const& message, JsonValue& json) +{ + ErrorInfo const& info(get_error_info(code)); + json[jss::error] = info.token; + json[jss::error_code] = info.code; + json[jss::error_message] = message; +} + +/** @} */ + +/** Returns a new json object that reflects the error code. */ +/** @{ */ +Json::Value +make_error(error_code_i code); +Json::Value +make_error(error_code_i code, std::string const& message); +/** @} */ + +/** Returns a new json object that indicates invalid parameters. */ +/** @{ */ +inline Json::Value +make_param_error(std::string const& message) +{ + return make_error(rpcINVALID_PARAMS, message); +} + +inline std::string +missing_field_message(std::string const& name) +{ + return "Missing field '" + name + "'."; +} + +inline Json::Value +missing_field_error(std::string const& name) +{ + return make_param_error(missing_field_message(name)); +} + +inline Json::Value +missing_field_error(Json::StaticString name) +{ + return missing_field_error(std::string(name)); +} + +inline std::string +object_field_message(std::string const& name) +{ + return "Invalid field '" + name + "', not object."; +} + +inline Json::Value +object_field_error(std::string const& name) +{ + return make_param_error(object_field_message(name)); +} + +inline Json::Value +object_field_error(Json::StaticString name) +{ + return object_field_error(std::string(name)); +} + +inline std::string +invalid_field_message(std::string const& name) +{ + return "Invalid field '" + name + "'."; +} + +inline std::string +invalid_field_message(Json::StaticString name) +{ + return invalid_field_message(std::string(name)); +} + +inline Json::Value +invalid_field_error(std::string const& name) +{ + return make_param_error(invalid_field_message(name)); +} + +inline Json::Value +invalid_field_error(Json::StaticString name) +{ + return invalid_field_error(std::string(name)); +} + +inline std::string +expected_field_message(std::string const& name, std::string const& type) +{ + return "Invalid field '" + name + "', not " + type + "."; +} + +inline std::string +expected_field_message(Json::StaticString name, std::string const& type) +{ + return expected_field_message(std::string(name), type); +} + +inline Json::Value +expected_field_error(std::string const& name, std::string const& type) +{ + return make_param_error(expected_field_message(name, type)); +} + +inline Json::Value +expected_field_error(Json::StaticString name, std::string const& type) +{ + return expected_field_error(std::string(name), type); +} + +inline Json::Value +not_validator_error() +{ + return make_param_error("not a validator"); +} + +/** @} */ + +/** Returns `true` if the json contains an rpc error specification. */ +bool +contains_error(Json::Value const& json); + +/** Returns http status that corresponds to the error code. */ +int +error_code_http_status(error_code_i code); + +} // namespace RPC + +/** Returns a single string with the contents of an RPC error. */ +std::string +rpcErrorString(Json::Value const& jv); + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h new file mode 100644 index 00000000000..a2eb7d8e50a --- /dev/null +++ b/include/xrpl/protocol/Feature.h @@ -0,0 +1,368 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_FEATURE_H_INCLUDED +#define RIPPLE_PROTOCOL_FEATURE_H_INCLUDED + +#include + +#include + +#include +#include +#include +#include +#include + +/** + * @page Feature How to add new features + * + * Steps required to add new features to the code: + * + * 1) Add the appropriate XRPL_FEATURE or XRPL_FIX macro definition for the + * feature to features.macro with the feature's name, `Supported::no`, and + * `VoteBehavior::DefaultNo`. + * + * 2) Use the generated variable name as the parameter to `view.rules.enabled()` + * to control flow into new code that this feature limits. (featureName or + * fixName) + * + * 3) If the feature development is COMPLETE, and the feature is ready to be + * SUPPORTED, change the macro parameter in features.macro to Supported::yes. + * + * 4) In general, any newly supported amendments (`Supported::yes`) should have + * a `VoteBehavior::DefaultNo` indefinitely so that external governance can + * make the decision on when to activate it. High priority bug fixes can be + * an exception to this rule. In such cases, ensure the fix has been + * clearly communicated to the community using appropriate channels, + * then change the macro parameter in features.macro to + * `VoteBehavior::DefaultYes`. The communication process is beyond + * the scope of these instructions. + * + * + * When a feature has been enabled for several years, the conditional code + * may be removed, and the feature "retired". To retire a feature: + * + * 1) MOVE the macro definition in features.macro to the "retired features" + * section at the end of the file, and change the macro to XRPL_RETIRE. + * + * The feature must remain registered and supported indefinitely because it + * may exist in the Amendments object on ledger. There is no need to vote + * for it because there's nothing to vote for. If the feature definition is + * removed completely from the code, any instances running that code will get + * amendment blocked. Removing the feature from the ledger is beyond the scope + * of these instructions. + * + */ + +namespace ripple { + +enum class VoteBehavior : int { Obsolete = -1, DefaultNo = 0, DefaultYes }; +enum class AmendmentSupport : int { Retired = -1, Supported = 0, Unsupported }; + +/** All amendments libxrpl knows about. */ +std::map const& +allAmendments(); + +namespace detail { + +#pragma push_macro("XRPL_FEATURE") +#undef XRPL_FEATURE +#pragma push_macro("XRPL_FIX") +#undef XRPL_FIX +#pragma push_macro("XRPL_RETIRE") +#undef XRPL_RETIRE + +#define XRPL_FEATURE(name, supported, vote) +1 +#define XRPL_FIX(name, supported, vote) +1 +#define XRPL_RETIRE(name) +1 + +// This value SHOULD be equal to the number of amendments registered in +// Feature.cpp. Because it's only used to reserve storage, and determine how +// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than +// the actual number of amendments. A LogicError on startup will verify this. +static constexpr std::size_t numFeatures = + (0 + +#include + ); + +#undef XRPL_RETIRE +#pragma pop_macro("XRPL_RETIRE") +#undef XRPL_FIX +#pragma pop_macro("XRPL_FIX") +#undef XRPL_FEATURE +#pragma pop_macro("XRPL_FEATURE") + +/** Amendments that this server supports and the default voting behavior. + Whether they are enabled depends on the Rules defined in the validated + ledger */ +std::map const& +supportedAmendments(); + +/** Amendments that this server won't vote for by default. + + This function is only used in unit tests. +*/ +std::size_t +numDownVotedAmendments(); + +/** Amendments that this server will vote for by default. + + This function is only used in unit tests. +*/ +std::size_t +numUpVotedAmendments(); + +} // namespace detail + +std::optional +getRegisteredFeature(std::string const& name); + +size_t +featureToBitsetIndex(uint256 const& f); + +uint256 +bitsetIndexToFeature(size_t i); + +std::string +featureToName(uint256 const& f); + +class FeatureBitset : private std::bitset +{ + using base = std::bitset; + + template + void + initFromFeatures(uint256 const& f, Fs&&... fs) + { + set(f); + if constexpr (sizeof...(fs) > 0) + initFromFeatures(std::forward(fs)...); + } + +public: + using base::bitset; + using base::operator==; + + using base::all; + using base::any; + using base::count; + using base::flip; + using base::none; + using base::reset; + using base::set; + using base::size; + using base::test; + using base::operator[]; + using base::to_string; + using base::to_ullong; + using base::to_ulong; + + FeatureBitset() = default; + + explicit FeatureBitset(base const& b) : base(b) + { + XRPL_ASSERT( + b.count() == count(), + "ripple::FeatureBitset::FeatureBitset(base) : count match"); + } + + template + explicit FeatureBitset(uint256 const& f, Fs&&... fs) + { + initFromFeatures(f, std::forward(fs)...); + XRPL_ASSERT( + count() == (sizeof...(fs) + 1), + "ripple::FeatureBitset::FeatureBitset(uint256) : count and " + "sizeof... do match"); + } + + template + explicit FeatureBitset(Col const& fs) + { + for (auto const& f : fs) + set(featureToBitsetIndex(f)); + XRPL_ASSERT( + fs.size() == count(), + "ripple::FeatureBitset::FeatureBitset(Container auto) : count and " + "size do match"); + } + + auto + operator[](uint256 const& f) + { + return base::operator[](featureToBitsetIndex(f)); + } + + auto + operator[](uint256 const& f) const + { + return base::operator[](featureToBitsetIndex(f)); + } + + FeatureBitset& + set(uint256 const& f, bool value = true) + { + base::set(featureToBitsetIndex(f), value); + return *this; + } + + FeatureBitset& + reset(uint256 const& f) + { + base::reset(featureToBitsetIndex(f)); + return *this; + } + + FeatureBitset& + flip(uint256 const& f) + { + base::flip(featureToBitsetIndex(f)); + return *this; + } + + FeatureBitset& + operator&=(FeatureBitset const& rhs) + { + base::operator&=(rhs); + return *this; + } + + FeatureBitset& + operator|=(FeatureBitset const& rhs) + { + base::operator|=(rhs); + return *this; + } + + FeatureBitset + operator~() const + { + return FeatureBitset{base::operator~()}; + } + + friend FeatureBitset + operator&(FeatureBitset const& lhs, FeatureBitset const& rhs) + { + return FeatureBitset{ + static_cast(lhs) & static_cast(rhs)}; + } + + friend FeatureBitset + operator&(FeatureBitset const& lhs, uint256 const& rhs) + { + return lhs & FeatureBitset{rhs}; + } + + friend FeatureBitset + operator&(uint256 const& lhs, FeatureBitset const& rhs) + { + return FeatureBitset{lhs} & rhs; + } + + friend FeatureBitset + operator|(FeatureBitset const& lhs, FeatureBitset const& rhs) + { + return FeatureBitset{ + static_cast(lhs) | static_cast(rhs)}; + } + + friend FeatureBitset + operator|(FeatureBitset const& lhs, uint256 const& rhs) + { + return lhs | FeatureBitset{rhs}; + } + + friend FeatureBitset + operator|(uint256 const& lhs, FeatureBitset const& rhs) + { + return FeatureBitset{lhs} | rhs; + } + + friend FeatureBitset + operator^(FeatureBitset const& lhs, FeatureBitset const& rhs) + { + return FeatureBitset{ + static_cast(lhs) ^ static_cast(rhs)}; + } + + friend FeatureBitset + operator^(FeatureBitset const& lhs, uint256 const& rhs) + { + return lhs ^ FeatureBitset { rhs }; + } + + friend FeatureBitset + operator^(uint256 const& lhs, FeatureBitset const& rhs) + { + return FeatureBitset{lhs} ^ rhs; + } + + // set difference + friend FeatureBitset + operator-(FeatureBitset const& lhs, FeatureBitset const& rhs) + { + return lhs & ~rhs; + } + + friend FeatureBitset + operator-(FeatureBitset const& lhs, uint256 const& rhs) + { + return lhs - FeatureBitset{rhs}; + } + + friend FeatureBitset + operator-(uint256 const& lhs, FeatureBitset const& rhs) + { + return FeatureBitset{lhs} - rhs; + } +}; + +template +void +foreachFeature(FeatureBitset bs, F&& f) +{ + for (size_t i = 0; i < bs.size(); ++i) + if (bs[i]) + f(bitsetIndexToFeature(i)); +} + +#pragma push_macro("XRPL_FEATURE") +#undef XRPL_FEATURE +#pragma push_macro("XRPL_FIX") +#undef XRPL_FIX +#pragma push_macro("XRPL_RETIRE") +#undef XRPL_RETIRE + +#define XRPL_FEATURE(name, supported, vote) extern uint256 const feature##name; +#define XRPL_FIX(name, supported, vote) extern uint256 const fix##name; +#define XRPL_RETIRE(name) + +#include + +#undef XRPL_RETIRE +#pragma pop_macro("XRPL_RETIRE") +#undef XRPL_FIX +#pragma pop_macro("XRPL_FIX") +#undef XRPL_FEATURE +#pragma pop_macro("XRPL_FEATURE") + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/FeeUnits.h b/include/xrpl/protocol/FeeUnits.h new file mode 100644 index 00000000000..0cbf1b608a2 --- /dev/null +++ b/include/xrpl/protocol/FeeUnits.h @@ -0,0 +1,570 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2019 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef BASICS_FEES_H_INCLUDED +#define BASICS_FEES_H_INCLUDED + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +namespace feeunit { + +/** "drops" are the smallest divisible amount of XRP. This is what most + of the code uses. */ +struct dropTag; +/** "fee units" calculations are a not-really-unitless value that is used + to express the cost of a given transaction vs. a reference transaction. + They are primarily used by the Transactor classes. */ +struct feeunitTag; +/** "fee levels" are used by the transaction queue to compare the relative + cost of transactions that require different levels of effort to process. + See also: src/ripple/app/misc/FeeEscalation.md#fee-level */ +struct feelevelTag; +/** unitless values are plain scalars wrapped in a TaggedFee. They are + used for calculations in this header. */ +struct unitlessTag; + +template +using enable_if_unit_t = typename std::enable_if_t< + std::is_class_v && std::is_object_v && + std::is_object_v>; + +/** `is_usable_unit_v` is checked to ensure that only values with + known valid type tags can be used (sometimes transparently) in + non-fee contexts. At the time of implementation, this includes + all known tags, but more may be added in the future, and they + should not be added automatically unless determined to be + appropriate. +*/ +template > +constexpr bool is_usable_unit_v = + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; + +template +class TaggedFee : private boost::totally_ordered>, + private boost::additive>, + private boost::equality_comparable, T>, + private boost::dividable, T>, + private boost::modable, T>, + private boost::unit_steppable> +{ +public: + using unit_type = UnitTag; + using value_type = T; + +private: + value_type fee_; + +protected: + template + static constexpr bool is_compatible_v = + std::is_arithmetic_v && std::is_arithmetic_v && + std::is_convertible_v; + + template > + static constexpr bool is_compatiblefee_v = + is_compatible_v && + std::is_same_v; + + template + using enable_if_compatible_t = + typename std::enable_if_t>; + + template + using enable_if_compatiblefee_t = + typename std::enable_if_t>; + +public: + TaggedFee() = default; + constexpr TaggedFee(TaggedFee const& other) = default; + constexpr TaggedFee& + operator=(TaggedFee const& other) = default; + + constexpr explicit TaggedFee(beast::Zero) : fee_(0) + { + } + + constexpr TaggedFee& + operator=(beast::Zero) + { + fee_ = 0; + return *this; + } + + constexpr explicit TaggedFee(value_type fee) : fee_(fee) + { + } + + TaggedFee& + operator=(value_type fee) + { + fee_ = fee; + return *this; + } + + /** Instances with the same unit, and a type that is + "safe" to convert to this one can be converted + implicitly */ + template < + class Other, + class = std::enable_if_t< + is_compatible_v && + is_safetocasttovalue_v>> + constexpr TaggedFee(TaggedFee const& fee) + : TaggedFee(safe_cast(fee.fee())) + { + } + + constexpr TaggedFee + operator*(value_type const& rhs) const + { + return TaggedFee{fee_ * rhs}; + } + + friend constexpr TaggedFee + operator*(value_type lhs, TaggedFee const& rhs) + { + // multiplication is commutative + return rhs * lhs; + } + + constexpr value_type + operator/(TaggedFee const& rhs) const + { + return fee_ / rhs.fee_; + } + + TaggedFee& + operator+=(TaggedFee const& other) + { + fee_ += other.fee(); + return *this; + } + + TaggedFee& + operator-=(TaggedFee const& other) + { + fee_ -= other.fee(); + return *this; + } + + TaggedFee& + operator++() + { + ++fee_; + return *this; + } + + TaggedFee& + operator--() + { + --fee_; + return *this; + } + + TaggedFee& + operator*=(value_type const& rhs) + { + fee_ *= rhs; + return *this; + } + + TaggedFee& + operator/=(value_type const& rhs) + { + fee_ /= rhs; + return *this; + } + + template + std::enable_if_t, TaggedFee&> + operator%=(value_type const& rhs) + { + fee_ %= rhs; + return *this; + } + + TaggedFee + operator-() const + { + static_assert( + std::is_signed_v, "- operator illegal on unsigned fee types"); + return TaggedFee{-fee_}; + } + + bool + operator==(TaggedFee const& other) const + { + return fee_ == other.fee_; + } + + template > + bool + operator==(TaggedFee const& other) const + { + return fee_ == other.fee(); + } + + bool + operator==(value_type other) const + { + return fee_ == other; + } + + template > + bool + operator!=(TaggedFee const& other) const + { + return !operator==(other); + } + + bool + operator<(TaggedFee const& other) const + { + return fee_ < other.fee_; + } + + /** Returns true if the amount is not zero */ + explicit constexpr + operator bool() const noexcept + { + return fee_ != 0; + } + + /** Return the sign of the amount */ + constexpr int + signum() const noexcept + { + return (fee_ < 0) ? -1 : (fee_ ? 1 : 0); + } + + /** Returns the number of drops */ + constexpr value_type + fee() const + { + return fee_; + } + + template + constexpr double + decimalFromReference(TaggedFee reference) const + { + return static_cast(fee_) / reference.fee(); + } + + // `is_usable_unit_v` is checked to ensure that only values with + // known valid type tags can be converted to JSON. At the time + // of implementation, that includes all known tags, but more may + // be added in the future. + std::enable_if_t, Json::Value> + jsonClipped() const + { + if constexpr (std::is_integral_v) + { + using jsontype = std::conditional_t< + std::is_signed_v, + Json::Int, + Json::UInt>; + + constexpr auto min = std::numeric_limits::min(); + constexpr auto max = std::numeric_limits::max(); + + if (fee_ < min) + return min; + if (fee_ > max) + return max; + return static_cast(fee_); + } + else + { + return fee_; + } + } + + /** Returns the underlying value. Code SHOULD NOT call this + function unless the type has been abstracted away, + e.g. in a templated function. + */ + constexpr value_type + value() const + { + return fee_; + } + + friend std::istream& + operator>>(std::istream& s, TaggedFee& val) + { + s >> val.fee_; + return s; + } +}; + +// Output Fees as just their numeric value. +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const TaggedFee& q) +{ + return os << q.value(); +} + +template +std::string +to_string(TaggedFee const& amount) +{ + return std::to_string(amount.fee()); +} + +template > +constexpr bool can_muldiv_source_v = + std::is_convertible_v; + +template > +constexpr bool can_muldiv_dest_v = + can_muldiv_source_v && // Dest is also a source + std::is_convertible_v && + sizeof(typename Dest::value_type) >= sizeof(std::uint64_t); + +template < + class Source1, + class Source2, + class = enable_if_unit_t, + class = enable_if_unit_t> +constexpr bool can_muldiv_sources_v = + can_muldiv_source_v && can_muldiv_source_v && + std::is_same_v; + +template < + class Source1, + class Source2, + class Dest, + class = enable_if_unit_t, + class = enable_if_unit_t, + class = enable_if_unit_t> +constexpr bool can_muldiv_v = + can_muldiv_sources_v && can_muldiv_dest_v; +// Source and Dest can be the same by default + +template < + class Source1, + class Source2, + class Dest, + class = enable_if_unit_t, + class = enable_if_unit_t, + class = enable_if_unit_t> +constexpr bool can_muldiv_commute_v = can_muldiv_v && + !std::is_same_v; + +template +using enable_muldiv_source_t = + typename std::enable_if_t>; + +template +using enable_muldiv_dest_t = typename std::enable_if_t>; + +template +using enable_muldiv_sources_t = + typename std::enable_if_t>; + +template +using enable_muldiv_t = + typename std::enable_if_t>; + +template +using enable_muldiv_commute_t = + typename std::enable_if_t>; + +template +TaggedFee +scalar(T value) +{ + return TaggedFee{value}; +} + +template < + class Source1, + class Source2, + class Dest, + class = enable_muldiv_t> +std::optional +mulDivU(Source1 value, Dest mul, Source2 div) +{ + // Fees can never be negative in any context. + if (value.value() < 0 || mul.value() < 0 || div.value() < 0) + { + // split the asserts so if one hits, the user can tell which + // without a debugger. + XRPL_ASSERT( + value.value() >= 0, + "ripple::feeunit::mulDivU : minimum value input"); + XRPL_ASSERT( + mul.value() >= 0, "ripple::feeunit::mulDivU : minimum mul input"); + XRPL_ASSERT( + div.value() >= 0, "ripple::feeunit::mulDivU : minimum div input"); + return std::nullopt; + } + + using desttype = typename Dest::value_type; + constexpr auto max = std::numeric_limits::max(); + + // Shortcuts, since these happen a lot in the real world + if (value == div) + return mul; + if (mul.value() == div.value()) + { + if (value.value() > max) + return std::nullopt; + return Dest{static_cast(value.value())}; + } + + using namespace boost::multiprecision; + + uint128_t product; + product = multiply( + product, + static_cast(value.value()), + static_cast(mul.value())); + + auto quotient = product / div.value(); + + if (quotient > max) + return std::nullopt; + + return Dest{static_cast(quotient)}; +} + +} // namespace feeunit + +template +using FeeLevel = feeunit::TaggedFee; +using FeeLevel64 = FeeLevel; +using FeeLevelDouble = FeeLevel; + +template < + class Source1, + class Source2, + class Dest, + class = feeunit::enable_muldiv_t> +std::optional +mulDiv(Source1 value, Dest mul, Source2 div) +{ + return feeunit::mulDivU(value, mul, div); +} + +template < + class Source1, + class Source2, + class Dest, + class = feeunit::enable_muldiv_commute_t> +std::optional +mulDiv(Dest value, Source1 mul, Source2 div) +{ + // Multiplication is commutative + return feeunit::mulDivU(mul, value, div); +} + +template > +std::optional +mulDiv(std::uint64_t value, Dest mul, std::uint64_t div) +{ + // Give the scalars a non-tag so the + // unit-handling version gets called. + return feeunit::mulDivU(feeunit::scalar(value), mul, feeunit::scalar(div)); +} + +template > +std::optional +mulDiv(Dest value, std::uint64_t mul, std::uint64_t div) +{ + // Multiplication is commutative + return mulDiv(mul, value, div); +} + +template < + class Source1, + class Source2, + class = feeunit::enable_muldiv_sources_t> +std::optional +mulDiv(Source1 value, std::uint64_t mul, Source2 div) +{ + // Give the scalars a dimensionless unit so the + // unit-handling version gets called. + auto unitresult = feeunit::mulDivU(value, feeunit::scalar(mul), div); + + if (!unitresult) + return std::nullopt; + + return unitresult->value(); +} + +template < + class Source1, + class Source2, + class = feeunit::enable_muldiv_sources_t> +std::optional +mulDiv(std::uint64_t value, Source1 mul, Source2 div) +{ + // Multiplication is commutative + return mulDiv(mul, value, div); +} + +template +constexpr std::enable_if_t< + std::is_same_v && + std::is_integral_v && + std::is_integral_v, + Dest> +safe_cast(Src s) noexcept +{ + // Dest may not have an explicit value constructor + return Dest{safe_cast(s.value())}; +} + +template +constexpr std::enable_if_t< + std::is_same_v && + std::is_integral_v && + std::is_integral_v, + Dest> +unsafe_cast(Src s) noexcept +{ + // Dest may not have an explicit value constructor + return Dest{unsafe_cast(s.value())}; +} + +} // namespace ripple + +#endif // BASICS_FEES_H_INCLUDED diff --git a/include/xrpl/protocol/Fees.h b/include/xrpl/protocol/Fees.h new file mode 100644 index 00000000000..4393f1a1d9c --- /dev/null +++ b/include/xrpl/protocol/Fees.h @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_FEES_H_INCLUDED +#define RIPPLE_PROTOCOL_FEES_H_INCLUDED + +#include + +namespace ripple { + +/** Reflects the fee settings for a particular ledger. + + The fees are always the same for any transactions applied + to a ledger. Changes to fees occur in between ledgers. +*/ +struct Fees +{ + XRPAmount base{0}; // Reference tx cost (drops) + XRPAmount reserve{0}; // Reserve base (drops) + XRPAmount increment{0}; // Reserve increment (drops) + + explicit Fees() = default; + Fees(Fees const&) = default; + Fees& + operator=(Fees const&) = default; + + /** Returns the account reserve given the owner count, in drops. + + The reserve is calculated as the reserve base plus + the reserve increment times the number of increments. + */ + XRPAmount + accountReserve(std::size_t ownerCount) const + { + return reserve + ownerCount * increment; + } +}; + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/HashPrefix.h b/include/xrpl/protocol/HashPrefix.h new file mode 100644 index 00000000000..ab825658e82 --- /dev/null +++ b/include/xrpl/protocol/HashPrefix.h @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_HASHPREFIX_H_INCLUDED +#define RIPPLE_PROTOCOL_HASHPREFIX_H_INCLUDED + +#include + +#include + +namespace ripple { + +namespace detail { + +constexpr std::uint32_t +make_hash_prefix(char a, char b, char c) +{ + return (static_cast(a) << 24) + + (static_cast(b) << 16) + + (static_cast(c) << 8); +} + +} // namespace detail + +/** Prefix for hashing functions. + + These prefixes are inserted before the source material used to generate + various hashes. This is done to put each hash in its own "space." This way, + two different types of objects with the same binary data will produce + different hashes. + + Each prefix is a 4-byte value with the last byte set to zero and the first + three bytes formed from the ASCII equivalent of some arbitrary string. For + example "TXN". + + @note Hash prefixes are part of the protocol; you cannot, arbitrarily, + change the type or the value of any of these without causing breakage. +*/ +enum class HashPrefix : std::uint32_t { + /** transaction plus signature to give transaction ID */ + transactionID = detail::make_hash_prefix('T', 'X', 'N'), + + /** transaction plus metadata */ + txNode = detail::make_hash_prefix('S', 'N', 'D'), + + /** account state */ + leafNode = detail::make_hash_prefix('M', 'L', 'N'), + + /** inner node in V1 tree */ + innerNode = detail::make_hash_prefix('M', 'I', 'N'), + + /** ledger master data for signing */ + ledgerMaster = detail::make_hash_prefix('L', 'W', 'R'), + + /** inner transaction to sign */ + txSign = detail::make_hash_prefix('S', 'T', 'X'), + + /** inner transaction to multi-sign */ + txMultiSign = detail::make_hash_prefix('S', 'M', 'T'), + + /** validation for signing */ + validation = detail::make_hash_prefix('V', 'A', 'L'), + + /** proposal for signing */ + proposal = detail::make_hash_prefix('P', 'R', 'P'), + + /** Manifest */ + manifest = detail::make_hash_prefix('M', 'A', 'N'), + + /** Payment Channel Claim */ + paymentChannelClaim = detail::make_hash_prefix('C', 'L', 'M'), + + /** Credentials signature */ + credential = detail::make_hash_prefix('C', 'R', 'D'), +}; + +template +void +hash_append(Hasher& h, HashPrefix const& hp) noexcept +{ + using beast::hash_append; + hash_append(h, static_cast(hp)); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/IOUAmount.h b/include/xrpl/protocol/IOUAmount.h new file mode 100644 index 00000000000..6895ed08aed --- /dev/null +++ b/include/xrpl/protocol/IOUAmount.h @@ -0,0 +1,227 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_IOUAMOUNT_H_INCLUDED +#define RIPPLE_BASICS_IOUAMOUNT_H_INCLUDED + +#include +#include +#include + +#include + +#include +#include +#include + +namespace ripple { + +/** Floating point representation of amounts with high dynamic range + + Amounts are stored as a normalized signed mantissa and an exponent. The + range of the normalized exponent is [-96,80] and the range of the absolute + value of the normalized mantissa is [1000000000000000, 9999999999999999]. + + Arithmetic operations can throw std::overflow_error during normalization + if the amount exceeds the largest representable amount, but underflows + will silently trunctate to zero. +*/ +class IOUAmount : private boost::totally_ordered, + private boost::additive +{ +private: + std::int64_t mantissa_; + int exponent_; + + /** Adjusts the mantissa and exponent to the proper range. + + This can throw if the amount cannot be normalized, or is larger than + the largest value that can be represented as an IOU amount. Amounts + that are too small to be represented normalize to 0. + */ + void + normalize(); + +public: + IOUAmount() = default; + explicit IOUAmount(Number const& other); + IOUAmount(beast::Zero); + IOUAmount(std::int64_t mantissa, int exponent); + + IOUAmount& operator=(beast::Zero); + + operator Number() const; + + IOUAmount& + operator+=(IOUAmount const& other); + + IOUAmount& + operator-=(IOUAmount const& other); + + IOUAmount + operator-() const; + + bool + operator==(IOUAmount const& other) const; + + bool + operator<(IOUAmount const& other) const; + + /** Returns true if the amount is not zero */ + explicit + operator bool() const noexcept; + + /** Return the sign of the amount */ + int + signum() const noexcept; + + int + exponent() const noexcept; + + std::int64_t + mantissa() const noexcept; + + static IOUAmount + minPositiveAmount(); +}; + +inline IOUAmount::IOUAmount(beast::Zero) +{ + *this = beast::zero; +} + +inline IOUAmount::IOUAmount(std::int64_t mantissa, int exponent) + : mantissa_(mantissa), exponent_(exponent) +{ + normalize(); +} + +inline IOUAmount& +IOUAmount::operator=(beast::Zero) +{ + // The -100 is used to allow 0 to sort less than small positive values + // which will have a large negative exponent. + mantissa_ = 0; + exponent_ = -100; + return *this; +} + +inline IOUAmount::operator Number() const +{ + return Number{mantissa_, exponent_}; +} + +inline IOUAmount& +IOUAmount::operator-=(IOUAmount const& other) +{ + *this += -other; + return *this; +} + +inline IOUAmount +IOUAmount::operator-() const +{ + return {-mantissa_, exponent_}; +} + +inline bool +IOUAmount::operator==(IOUAmount const& other) const +{ + return exponent_ == other.exponent_ && mantissa_ == other.mantissa_; +} + +inline bool +IOUAmount::operator<(IOUAmount const& other) const +{ + return Number{*this} < Number{other}; +} + +inline IOUAmount::operator bool() const noexcept +{ + return mantissa_ != 0; +} + +inline int +IOUAmount::signum() const noexcept +{ + return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0); +} + +inline int +IOUAmount::exponent() const noexcept +{ + return exponent_; +} + +inline std::int64_t +IOUAmount::mantissa() const noexcept +{ + return mantissa_; +} + +std::string +to_string(IOUAmount const& amount); + +/* Return num*amt/den + This function keeps more precision than computing + num*amt, storing the result in an IOUAmount, then + dividing by den. +*/ +IOUAmount +mulRatio( + IOUAmount const& amt, + std::uint32_t num, + std::uint32_t den, + bool roundUp); + +// Since many uses of the number class do not have access to a ledger, +// getSTNumberSwitchover needs to be globally accessible. + +bool +getSTNumberSwitchover(); + +void +setSTNumberSwitchover(bool v); + +/** RAII class to set and restore the Number switchover. + */ + +class NumberSO +{ + bool saved_; + +public: + ~NumberSO() + { + setSTNumberSwitchover(saved_); + } + + NumberSO(NumberSO const&) = delete; + NumberSO& + operator=(NumberSO const&) = delete; + + explicit NumberSO(bool v) : saved_(getSTNumberSwitchover()) + { + setSTNumberSwitchover(v); + } +}; + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h new file mode 100644 index 00000000000..bbed5395927 --- /dev/null +++ b/include/xrpl/protocol/Indexes.h @@ -0,0 +1,383 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_INDEXES_H_INCLUDED +#define RIPPLE_PROTOCOL_INDEXES_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace ripple { + +class SeqProxy; +/** Keylet computation funclets. + + Entries in the ledger are located using 256-bit locators. The locators are + calculated using a wide range of parameters specific to the entry whose + locator we are calculating (e.g. an account's locator is derived from the + account's address, whereas the locator for an offer is derived from the + account and the offer sequence.) + + To enhance type safety during lookup and make the code more robust, we use + keylets, which contain not only the locator of the object but also the type + of the object being referenced. + + These functions each return a type-specific keylet. +*/ +namespace keylet { + +/** AccountID root */ +Keylet +account(AccountID const& id) noexcept; + +/** The index of the amendment table */ +Keylet const& +amendments() noexcept; + +/** Any item that can be in an owner dir. */ +Keylet +child(uint256 const& key) noexcept; + +/** The index of the "short" skip list + + The "short" skip list is a node (at a fixed index) that holds the hashes + of ledgers since the last flag ledger. It will contain, at most, 256 hashes. +*/ +Keylet const& +skip() noexcept; + +/** The index of the long skip for a particular ledger range. + + The "long" skip list is a node that holds the hashes of (up to) 256 flag + ledgers. + + It can be used to efficiently skip back to any ledger using only two hops: + the first hop gets the "long" skip list for the ledger it wants to retrieve + and uses it to get the hash of the flag ledger whose short skip list will + contain the hash of the requested ledger. +*/ +Keylet +skip(LedgerIndex ledger) noexcept; + +/** The (fixed) index of the object containing the ledger fees. */ +Keylet const& +fees() noexcept; + +/** The (fixed) index of the object containing the ledger negativeUNL. */ +Keylet const& +negativeUNL() noexcept; + +/** The beginning of an order book */ +struct book_t +{ + explicit book_t() = default; + + Keylet + operator()(Book const& b) const; +}; +static book_t const book{}; + +/** The index of a trust line for a given currency + + Note that a trustline is *shared* between two accounts (commonly referred + to as the issuer and the holder); if Alice sets up a trust line to Bob for + BTC, and Bob trusts Alice for BTC, here is only a single BTC trust line + between them. +*/ +/** @{ */ +Keylet +line( + AccountID const& id0, + AccountID const& id1, + Currency const& currency) noexcept; + +inline Keylet +line(AccountID const& id, Issue const& issue) noexcept +{ + return line(id, issue.account, issue.currency); +} +/** @} */ + +/** An offer from an account */ +/** @{ */ +Keylet +offer(AccountID const& id, std::uint32_t seq) noexcept; + +inline Keylet +offer(uint256 const& key) noexcept +{ + return {ltOFFER, key}; +} +/** @} */ + +/** The initial directory page for a specific quality */ +Keylet +quality(Keylet const& k, std::uint64_t q) noexcept; + +/** The directory for the next lower quality */ +struct next_t +{ + explicit next_t() = default; + + Keylet + operator()(Keylet const& k) const; +}; +static next_t const next{}; + +/** A ticket belonging to an account */ +struct ticket_t +{ + explicit ticket_t() = default; + + Keylet + operator()(AccountID const& id, std::uint32_t ticketSeq) const; + + Keylet + operator()(AccountID const& id, SeqProxy ticketSeq) const; + + Keylet + operator()(uint256 const& key) const + { + return {ltTICKET, key}; + } +}; +static ticket_t const ticket{}; + +/** A SignerList */ +Keylet +signers(AccountID const& account) noexcept; + +/** A Check */ +/** @{ */ +Keylet +check(AccountID const& id, std::uint32_t seq) noexcept; + +inline Keylet +check(uint256 const& key) noexcept +{ + return {ltCHECK, key}; +} +/** @} */ + +/** A DepositPreauth */ +/** @{ */ +Keylet +depositPreauth(AccountID const& owner, AccountID const& preauthorized) noexcept; + +Keylet +depositPreauth( + AccountID const& owner, + std::set> const& authCreds) noexcept; + +inline Keylet +depositPreauth(uint256 const& key) noexcept +{ + return {ltDEPOSIT_PREAUTH, key}; +} +/** @} */ + +//------------------------------------------------------------------------------ + +/** Any ledger entry */ +Keylet +unchecked(uint256 const& key) noexcept; + +/** The root page of an account's directory */ +Keylet +ownerDir(AccountID const& id) noexcept; + +/** A page in a directory */ +/** @{ */ +Keylet +page(uint256 const& root, std::uint64_t index = 0) noexcept; + +inline Keylet +page(Keylet const& root, std::uint64_t index = 0) noexcept +{ + XRPL_ASSERT( + root.type == ltDIR_NODE, "ripple::keylet::page : valid root type"); + return page(root.key, index); +} +/** @} */ + +/** An escrow entry */ +Keylet +escrow(AccountID const& src, std::uint32_t seq) noexcept; + +/** A PaymentChannel */ +Keylet +payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept; + +/** NFT page keylets + + Unlike objects whose ledger identifiers are produced by hashing data, + NFT page identifiers are composite identifiers, consisting of the owner's + 160-bit AccountID, followed by a 96-bit value that determines which NFT + tokens are candidates for that page. + */ +/** @{ */ +/** A keylet for the owner's first possible NFT page. */ +Keylet +nftpage_min(AccountID const& owner); + +/** A keylet for the owner's last possible NFT page. */ +Keylet +nftpage_max(AccountID const& owner); + +Keylet +nftpage(Keylet const& k, uint256 const& token); +/** @} */ + +/** An offer from an account to buy or sell an NFT */ +Keylet +nftoffer(AccountID const& owner, std::uint32_t seq); + +inline Keylet +nftoffer(uint256 const& offer) +{ + return {ltNFTOKEN_OFFER, offer}; +} + +/** The directory of buy offers for the specified NFT */ +Keylet +nft_buys(uint256 const& id) noexcept; + +/** The directory of sell offers for the specified NFT */ +Keylet +nft_sells(uint256 const& id) noexcept; + +/** AMM entry */ +Keylet +amm(Asset const& issue1, Asset const& issue2) noexcept; + +Keylet +amm(uint256 const& amm) noexcept; + +Keylet +bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType); + +Keylet +xChainClaimID(STXChainBridge const& bridge, std::uint64_t seq); + +Keylet +xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq); + +Keylet +did(AccountID const& account) noexcept; + +Keylet +oracle(AccountID const& account, std::uint32_t const& documentID) noexcept; + +Keylet +credential( + AccountID const& subject, + AccountID const& issuer, + Slice const& credType) noexcept; + +inline Keylet +credential(uint256 const& key) noexcept +{ + return {ltCREDENTIAL, key}; +} + +Keylet +mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept; + +Keylet +mptIssuance(MPTID const& issuanceID) noexcept; + +inline Keylet +mptIssuance(uint256 const& issuanceKey) +{ + return {ltMPTOKEN_ISSUANCE, issuanceKey}; +} + +Keylet +mptoken(MPTID const& issuanceID, AccountID const& holder) noexcept; + +inline Keylet +mptoken(uint256 const& mptokenKey) +{ + return {ltMPTOKEN, mptokenKey}; +} + +Keylet +mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept; + +Keylet +permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept; + +Keylet +permissionedDomain(uint256 const& domainID) noexcept; +} // namespace keylet + +// Everything below is deprecated and should be removed in favor of keylets: + +uint256 +getBookBase(Book const& book); + +uint256 +getQualityNext(uint256 const& uBase); + +// VFALCO This name could be better +std::uint64_t +getQuality(uint256 const& uBase); + +uint256 +getTicketIndex(AccountID const& account, std::uint32_t uSequence); + +uint256 +getTicketIndex(AccountID const& account, SeqProxy ticketSeq); + +template +struct keyletDesc +{ + std::function function; + Json::StaticString expectedLEName; + bool includeInTests; +}; + +// This list should include all of the keylet functions that take a single +// AccountID parameter. +std::array, 6> const directAccountKeylets{ + {{&keylet::account, jss::AccountRoot, false}, + {&keylet::ownerDir, jss::DirectoryNode, true}, + {&keylet::signers, jss::SignerList, true}, + // It's normally impossible to create an item at nftpage_min, but + // test it anyway, since the invariant checks for it. + {&keylet::nftpage_min, jss::NFTokenPage, true}, + {&keylet::nftpage_max, jss::NFTokenPage, true}, + {&keylet::did, jss::DID, true}}}; + +MPTID +makeMptID(std::uint32_t sequence, AccountID const& account); + +} // namespace ripple + +#endif diff --git a/src/ripple/protocol/InnerObjectFormats.h b/include/xrpl/protocol/InnerObjectFormats.h similarity index 82% rename from src/ripple/protocol/InnerObjectFormats.h rename to include/xrpl/protocol/InnerObjectFormats.h index 29297563a51..06ca5af385c 100644 --- a/src/ripple/protocol/InnerObjectFormats.h +++ b/include/xrpl/protocol/InnerObjectFormats.h @@ -20,26 +20,28 @@ #ifndef RIPPLE_PROTOCOL_INNER_OBJECT_FORMATS_H_INCLUDED #define RIPPLE_PROTOCOL_INNER_OBJECT_FORMATS_H_INCLUDED -#include +#include namespace ripple { /** Manages the list of known inner object formats. -*/ -class InnerObjectFormats : public KnownFormats + */ +class InnerObjectFormats : public KnownFormats { private: /** Create the object. This will load the object with all the known inner object formats. */ - InnerObjectFormats (); + InnerObjectFormats(); public: - static InnerObjectFormats const& getInstance (); + static InnerObjectFormats const& + getInstance(); - SOTemplate const* findSOTemplateBySField (SField const& sField) const; + SOTemplate const* + findSOTemplateBySField(SField const& sField) const; }; -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/protocol/Issue.h b/include/xrpl/protocol/Issue.h new file mode 100644 index 00000000000..83ef337c357 --- /dev/null +++ b/include/xrpl/protocol/Issue.h @@ -0,0 +1,140 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_ISSUE_H_INCLUDED +#define RIPPLE_PROTOCOL_ISSUE_H_INCLUDED + +#include +#include +#include + +#include +#include + +namespace ripple { + +/** A currency issued by an account. + @see Currency, AccountID, Issue, Book +*/ +class Issue +{ +public: + Currency currency{}; + AccountID account{}; + + Issue() = default; + + Issue(Currency const& c, AccountID const& a) : currency(c), account(a) + { + } + + AccountID const& + getIssuer() const + { + return account; + } + + std::string + getText() const; + + void + setJson(Json::Value& jv) const; + + bool + native() const; + + friend constexpr std::weak_ordering + operator<=>(Issue const& lhs, Issue const& rhs); +}; + +bool +isConsistent(Issue const& ac); + +std::string +to_string(Issue const& ac); + +Json::Value +to_json(Issue const& is); + +Issue +issueFromJson(Json::Value const& v); + +std::ostream& +operator<<(std::ostream& os, Issue const& x); + +template +void +hash_append(Hasher& h, Issue const& r) +{ + using beast::hash_append; + hash_append(h, r.currency, r.account); +} + +/** Equality comparison. */ +/** @{ */ +[[nodiscard]] inline constexpr bool +operator==(Issue const& lhs, Issue const& rhs) +{ + return (lhs.currency == rhs.currency) && + (isXRP(lhs.currency) || lhs.account == rhs.account); +} +/** @} */ + +/** Strict weak ordering. */ +/** @{ */ +[[nodiscard]] constexpr std::weak_ordering +operator<=>(Issue const& lhs, Issue const& rhs) +{ + if (auto const c{lhs.currency <=> rhs.currency}; c != 0) + return c; + + if (isXRP(lhs.currency)) + return std::weak_ordering::equivalent; + + return (lhs.account <=> rhs.account); +} +/** @} */ + +//------------------------------------------------------------------------------ + +/** Returns an asset specifier that represents XRP. */ +inline Issue const& +xrpIssue() +{ + static Issue issue{xrpCurrency(), xrpAccount()}; + return issue; +} + +/** Returns an asset specifier that represents no account and currency. */ +inline Issue const& +noIssue() +{ + static Issue issue{noCurrency(), noAccount()}; + return issue; +} + +inline bool +isXRP(Issue const& issue) +{ + return issue.native(); +} + +} // namespace ripple + +#endif diff --git a/src/ripple/protocol/KeyType.h b/include/xrpl/protocol/KeyType.h similarity index 86% rename from src/ripple/protocol/KeyType.h rename to include/xrpl/protocol/KeyType.h index cb96f4a7a57..810e3e6fdf4 100644 --- a/src/ripple/protocol/KeyType.h +++ b/include/xrpl/protocol/KeyType.h @@ -20,20 +20,18 @@ #ifndef RIPPLE_PROTOCOL_KEYTYPE_H_INCLUDED #define RIPPLE_PROTOCOL_KEYTYPE_H_INCLUDED +#include #include -#include namespace ripple { -enum class KeyType -{ +enum class KeyType { secp256k1 = 0, - ed25519 = 1, + ed25519 = 1, }; -inline -boost::optional -keyTypeFromString (std::string const& s) +inline std::optional +keyTypeFromString(std::string const& s) { if (s == "secp256k1") return KeyType::secp256k1; @@ -44,9 +42,8 @@ keyTypeFromString (std::string const& s) return {}; } -inline -char const* -to_string (KeyType type) +inline char const* +to_string(KeyType type) { if (type == KeyType::secp256k1) return "secp256k1"; @@ -58,12 +55,12 @@ to_string (KeyType type) } template -inline -Stream& operator<<(Stream& s, KeyType type) +inline Stream& +operator<<(Stream& s, KeyType type) { return s << to_string(type); } -} +} // namespace ripple #endif diff --git a/src/ripple/protocol/Keylet.h b/include/xrpl/protocol/Keylet.h similarity index 87% rename from src/ripple/protocol/Keylet.h rename to include/xrpl/protocol/Keylet.h index 13e899441f4..d3bda103314 100644 --- a/src/ripple/protocol/Keylet.h +++ b/include/xrpl/protocol/Keylet.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_KEYLET_H_INCLUDED #define RIPPLE_PROTOCOL_KEYLET_H_INCLUDED -#include -#include +#include +#include namespace ripple { @@ -37,21 +37,18 @@ class STLedgerEntry; */ struct Keylet { - LedgerEntryType type; uint256 key; + LedgerEntryType type; - Keylet (LedgerEntryType type_, - uint256 const& key_) - : type(type_) - , key(key_) + Keylet(LedgerEntryType type_, uint256 const& key_) : key(key_), type(type_) { } /** Returns true if the SLE matches the type */ bool - check (STLedgerEntry const&) const; + check(STLedgerEntry const&) const; }; -} +} // namespace ripple #endif diff --git a/include/xrpl/protocol/KnownFormats.h b/include/xrpl/protocol/KnownFormats.h new file mode 100644 index 00000000000..db2042eadea --- /dev/null +++ b/include/xrpl/protocol/KnownFormats.h @@ -0,0 +1,207 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_KNOWNFORMATS_H_INCLUDED +#define RIPPLE_PROTOCOL_KNOWNFORMATS_H_INCLUDED + +#include +#include +#include + +#include + +#include +#include + +namespace ripple { + +/** Manages a list of known formats. + + Each format has a name, an associated KeyType (typically an enumeration), + and a predefined @ref SOElement. + + @tparam KeyType The type of key identifying the format. +*/ +template +class KnownFormats +{ +public: + /** A known format. + */ + class Item + { + public: + Item( + char const* name, + KeyType type, + std::initializer_list uniqueFields, + std::initializer_list commonFields) + : soTemplate_(uniqueFields, commonFields), name_(name), type_(type) + { + // Verify that KeyType is appropriate. + static_assert( + std::is_enum::value || + std::is_integral::value, + "KnownFormats KeyType must be integral or enum."); + } + + /** Retrieve the name of the format. + */ + std::string const& + getName() const + { + return name_; + } + + /** Retrieve the transaction type this format represents. + */ + KeyType + getType() const + { + return type_; + } + + SOTemplate const& + getSOTemplate() const + { + return soTemplate_; + } + + private: + SOTemplate soTemplate_; + std::string const name_; + KeyType const type_; + }; + + /** Create the known formats object. + + Derived classes will load the object with all the known formats. + */ + KnownFormats() : name_(beast::type_name()) + { + } + + /** Destroy the known formats object. + + The defined formats are deleted. + */ + virtual ~KnownFormats() = default; + KnownFormats(KnownFormats const&) = delete; + KnownFormats& + operator=(KnownFormats const&) = delete; + + /** Retrieve the type for a format specified by name. + + If the format name is unknown, an exception is thrown. + + @param name The name of the type. + @return The type. + */ + KeyType + findTypeByName(std::string const& name) const + { + if (auto const result = findByName(name)) + return result->getType(); + Throw( + name_ + ": Unknown format name '" + + name.substr(0, std::min(name.size(), std::size_t(32))) + "'"); + } + + /** Retrieve a format based on its type. + */ + Item const* + findByType(KeyType type) const + { + auto const itr = types_.find(type); + if (itr == types_.end()) + return nullptr; + return itr->second; + } + + // begin() and end() are provided for testing purposes. + typename std::forward_list::const_iterator + begin() const + { + return formats_.begin(); + } + + typename std::forward_list::const_iterator + end() const + { + return formats_.end(); + } + +protected: + /** Retrieve a format based on its name. + */ + Item const* + findByName(std::string const& name) const + { + auto const itr = names_.find(name); + if (itr == names_.end()) + return nullptr; + return itr->second; + } + + /** Add a new format. + + @param name The name of this format. + @param type The type of this format. + @param uniqueFields An std::initializer_list of unique fields + @param commonFields An std::initializer_list of common fields + + @return The created format. + */ + Item const& + add(char const* name, + KeyType type, + std::initializer_list uniqueFields, + std::initializer_list commonFields = {}) + { + if (auto const item = findByType(type)) + { + LogicError( + std::string("Duplicate key for item '") + name + + "': already maps to " + item->getName()); + } + + formats_.emplace_front(name, type, uniqueFields, commonFields); + Item const& item{formats_.front()}; + + names_[name] = &item; + types_[type] = &item; + + return item; + } + +private: + std::string name_; + + // One of the situations where a std::forward_list is useful. We want to + // store each Item in a place where its address won't change. So a node- + // based container is appropriate. But we don't need searchability. + std::forward_list formats_; + + boost::container::flat_map names_; + boost::container::flat_map types_; +}; + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h new file mode 100644 index 00000000000..5f3cca53ac8 --- /dev/null +++ b/include/xrpl/protocol/LedgerFormats.h @@ -0,0 +1,215 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_LEDGERFORMATS_H_INCLUDED +#define RIPPLE_PROTOCOL_LEDGERFORMATS_H_INCLUDED + +#include + +namespace ripple { + +/** Identifiers for on-ledger objects. + + Each ledger object requires a unique type identifier, which is stored + within the object itself; this makes it possible to iterate the entire + ledger and determine each object's type and verify that the object you + retrieved from a given hash matches the expected type. + + @warning Since these values are stored inside objects stored on the ledger + they are part of the protocol. **Changing them should be avoided + because without special handling, this will result in a hard + fork.** + + @note Values outside this range may be used internally by the code for + various purposes, but attempting to use such values to identify + on-ledger objects will results in an invariant failure. + + @note When retiring types, the specific values should not be removed but + should be marked as [[deprecated]]. This is to avoid accidental + reuse of identifiers. + + @todo The C++ language does not enable checking for duplicate values + here. If it becomes possible then we should do this. + + @ingroup protocol +*/ +// clang-format off +enum LedgerEntryType : std::uint16_t +{ + +#pragma push_macro("LEDGER_ENTRY") +#undef LEDGER_ENTRY + +#define LEDGER_ENTRY(tag, value, name, rpcName, fields) tag = value, + +#include + +#undef LEDGER_ENTRY +#pragma pop_macro("LEDGER_ENTRY") + + //--------------------------------------------------------------------------- + /** A special type, matching any ledger entry type. + + The value does not represent a concrete type, but rather is used in + contexts where the specific type of a ledger object is unimportant, + unknown or unavailable. + + Objects with this special type cannot be created or stored on the + ledger. + + \sa keylet::unchecked + */ + ltANY = 0, + + /** A special type, matching any ledger type except directory nodes. + + The value does not represent a concrete type, but rather is used in + contexts where the ledger object must not be a directory node but + its specific type is otherwise unimportant, unknown or unavailable. + + Objects with this special type cannot be created or stored on the + ledger. + + \sa keylet::child + */ + ltCHILD = 0x1CD2, + + //--------------------------------------------------------------------------- + /** A legacy, deprecated type. + + \deprecated **This object type is not supported and should not be used.** + Support for this type of object was never implemented. + No objects of this type were ever created. + */ + ltNICKNAME [[deprecated("This object type is not supported and should not be used.")]] = 0x006e, + + /** A legacy, deprecated type. + + \deprecated **This object type is not supported and should not be used.** + Support for this type of object was never implemented. + No objects of this type were ever created. + */ + ltCONTRACT [[deprecated("This object type is not supported and should not be used.")]] = 0x0063, + + /** A legacy, deprecated type. + + \deprecated **This object type is not supported and should not be used.** + Support for this type of object was never implemented. + No objects of this type were ever created. + */ + ltGENERATOR_MAP [[deprecated("This object type is not supported and should not be used.")]] = 0x0067, +}; +// clang-format off + +/** + @ingroup protocol +*/ +enum LedgerSpecificFlags { + // ltACCOUNT_ROOT + lsfPasswordSpent = 0x00010000, // True, if password set fee is spent. + lsfRequireDestTag = + 0x00020000, // True, to require a DestinationTag for payments. + lsfRequireAuth = + 0x00040000, // True, to require a authorization to hold IOUs. + lsfDisallowXRP = 0x00080000, // True, to disallow sending XRP. + lsfDisableMaster = 0x00100000, // True, force regular key + lsfNoFreeze = 0x00200000, // True, cannot freeze ripple states + lsfGlobalFreeze = 0x00400000, // True, all assets frozen + lsfDefaultRipple = + 0x00800000, // True, trust lines allow rippling by default + lsfDepositAuth = 0x01000000, // True, all deposits require authorization +/* // reserved for Hooks amendment + lsfTshCollect = 0x02000000, // True, allow TSH collect-calls to acc hooks +*/ + lsfDisallowIncomingNFTokenOffer = + 0x04000000, // True, reject new incoming NFT offers + lsfDisallowIncomingCheck = + 0x08000000, // True, reject new checks + lsfDisallowIncomingPayChan = + 0x10000000, // True, reject new paychans + lsfDisallowIncomingTrustline = + 0x20000000, // True, reject new trustlines (only if no issued assets) + // 0x40000000 is available + lsfAllowTrustLineClawback = + 0x80000000, // True, enable clawback + + // ltOFFER + lsfPassive = 0x00010000, + lsfSell = 0x00020000, // True, offer was placed as a sell. + + // ltRIPPLE_STATE + lsfLowReserve = 0x00010000, // True, if entry counts toward reserve. + lsfHighReserve = 0x00020000, + lsfLowAuth = 0x00040000, + lsfHighAuth = 0x00080000, + lsfLowNoRipple = 0x00100000, + lsfHighNoRipple = 0x00200000, + lsfLowFreeze = 0x00400000, // True, low side has set freeze flag + lsfHighFreeze = 0x00800000, // True, high side has set freeze flag + lsfLowDeepFreeze = 0x02000000, // True, low side has set deep freeze flag + lsfHighDeepFreeze = 0x04000000, // True, high side has set deep freeze flag + lsfAMMNode = 0x01000000, // True, trust line to AMM. Used by client + // apps to identify payments via AMM. + + // ltSIGNER_LIST + lsfOneOwnerCount = 0x00010000, // True, uses only one OwnerCount + + // ltDIR_NODE + lsfNFTokenBuyOffers = 0x00000001, + lsfNFTokenSellOffers = 0x00000002, + + // ltNFTOKEN_OFFER + lsfSellNFToken = 0x00000001, + + // ltMPTOKEN_ISSUANCE + lsfMPTLocked = 0x00000001, // Also used in ltMPTOKEN + lsfMPTCanLock = 0x00000002, + lsfMPTRequireAuth = 0x00000004, + lsfMPTCanEscrow = 0x00000008, + lsfMPTCanTrade = 0x00000010, + lsfMPTCanTransfer = 0x00000020, + lsfMPTCanClawback = 0x00000040, + + // ltMPTOKEN + lsfMPTAuthorized = 0x00000002, + + // ltCREDENTIAL + lsfAccepted = 0x00010000, +}; + +//------------------------------------------------------------------------------ + +/** Holds the list of known ledger entry formats. + */ +class LedgerFormats : public KnownFormats +{ +private: + /** Create the object. + This will load the object with all the known ledger formats. + */ + LedgerFormats(); + +public: + static LedgerFormats const& + getInstance(); +}; + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/LedgerHeader.h b/include/xrpl/protocol/LedgerHeader.h new file mode 100644 index 00000000000..0b35979971a --- /dev/null +++ b/include/xrpl/protocol/LedgerHeader.h @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_LEDGERHEADER_H_INCLUDED +#define RIPPLE_PROTOCOL_LEDGERHEADER_H_INCLUDED + +#include +#include +#include +#include +#include +#include + +namespace ripple { + +/** Information about the notional ledger backing the view. */ +struct LedgerHeader +{ + explicit LedgerHeader() = default; + + // + // For all ledgers + // + + LedgerIndex seq = 0; + NetClock::time_point parentCloseTime = {}; + + // + // For closed ledgers + // + + // Closed means "tx set already determined" + uint256 hash = beast::zero; + uint256 txHash = beast::zero; + uint256 accountHash = beast::zero; + uint256 parentHash = beast::zero; + + XRPAmount drops = beast::zero; + + // If validated is false, it means "not yet validated." + // Once validated is true, it will never be set false at a later time. + // VFALCO TODO Make this not mutable + bool mutable validated = false; + bool accepted = false; + + // flags indicating how this ledger close took place + int closeFlags = 0; + + // the resolution for this ledger close time (2-120 seconds) + NetClock::duration closeTimeResolution = {}; + + // For closed ledgers, the time the ledger + // closed. For open ledgers, the time the ledger + // will close if there's no transactions. + // + NetClock::time_point closeTime = {}; +}; + +// We call them "headers" in conversation +// but "info" in code. Unintuitive. +// This alias lets us give the "correct" name to the class +// without yet disturbing existing uses. +using LedgerInfo = LedgerHeader; + +// ledger close flags +static std::uint32_t const sLCF_NoConsensusTime = 0x01; + +inline bool +getCloseAgree(LedgerHeader const& info) +{ + return (info.closeFlags & sLCF_NoConsensusTime) == 0; +} + +void +addRaw(LedgerHeader const&, Serializer&, bool includeHash = false); + +/** Deserialize a ledger header from a byte array. */ +LedgerHeader +deserializeHeader(Slice data, bool hasHash = false); + +/** Deserialize a ledger header (prefixed with 4 bytes) from a byte array. */ +LedgerHeader +deserializePrefixedHeader(Slice data, bool hasHash = false); + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/MPTAmount.h b/include/xrpl/protocol/MPTAmount.h new file mode 100644 index 00000000000..244d6839156 --- /dev/null +++ b/include/xrpl/protocol/MPTAmount.h @@ -0,0 +1,177 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_MPTAMOUNT_H_INCLUDED +#define RIPPLE_PROTOCOL_MPTAMOUNT_H_INCLUDED + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace ripple { + +class MPTAmount : private boost::totally_ordered, + private boost::additive, + private boost::equality_comparable, + private boost::additive +{ +public: + using value_type = std::int64_t; + +protected: + value_type value_; + +public: + MPTAmount() = default; + constexpr MPTAmount(MPTAmount const& other) = default; + constexpr MPTAmount& + operator=(MPTAmount const& other) = default; + + // Round to nearest, even on tie. + explicit MPTAmount(Number const& x) : MPTAmount(static_cast(x)) + { + } + + constexpr explicit MPTAmount(value_type value); + + constexpr MPTAmount& operator=(beast::Zero); + + MPTAmount& + operator+=(MPTAmount const& other); + + MPTAmount& + operator-=(MPTAmount const& other); + + MPTAmount + operator-() const; + + bool + operator==(MPTAmount const& other) const; + + bool + operator==(value_type other) const; + + bool + operator<(MPTAmount const& other) const; + + /** Returns true if the amount is not zero */ + explicit constexpr + operator bool() const noexcept; + + operator Number() const noexcept + { + return value(); + } + + /** Return the sign of the amount */ + constexpr int + signum() const noexcept; + + /** Returns the underlying value. Code SHOULD NOT call this + function unless the type has been abstracted away, + e.g. in a templated function. + */ + constexpr value_type + value() const; + + static MPTAmount + minPositiveAmount(); +}; + +constexpr MPTAmount::MPTAmount(value_type value) : value_(value) +{ +} + +constexpr MPTAmount& +MPTAmount::operator=(beast::Zero) +{ + value_ = 0; + return *this; +} + +/** Returns true if the amount is not zero */ +constexpr MPTAmount::operator bool() const noexcept +{ + return value_ != 0; +} + +/** Return the sign of the amount */ +constexpr int +MPTAmount::signum() const noexcept +{ + return (value_ < 0) ? -1 : (value_ ? 1 : 0); +} + +/** Returns the underlying value. Code SHOULD NOT call this + function unless the type has been abstracted away, + e.g. in a templated function. +*/ +constexpr MPTAmount::value_type +MPTAmount::value() const +{ + return value_; +} + +inline std::string +to_string(MPTAmount const& amount) +{ + return std::to_string(amount.value()); +} + +inline MPTAmount +mulRatio( + MPTAmount const& amt, + std::uint32_t num, + std::uint32_t den, + bool roundUp) +{ + using namespace boost::multiprecision; + + if (!den) + Throw("division by zero"); + + int128_t const amt128(amt.value()); + auto const neg = amt.value() < 0; + auto const m = amt128 * num; + auto r = m / den; + if (m % den) + { + if (!neg && roundUp) + r += 1; + if (neg && !roundUp) + r -= 1; + } + if (r > std::numeric_limits::max()) + Throw("MPT mulRatio overflow"); + return MPTAmount(r.convert_to()); +} + +} // namespace ripple + +#endif // RIPPLE_BASICS_MPTAMOUNT_H_INCLUDED diff --git a/include/xrpl/protocol/MPTIssue.h b/include/xrpl/protocol/MPTIssue.h new file mode 100644 index 00000000000..028051ab1ae --- /dev/null +++ b/include/xrpl/protocol/MPTIssue.h @@ -0,0 +1,98 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_MPTISSUE_H_INCLUDED +#define RIPPLE_PROTOCOL_MPTISSUE_H_INCLUDED + +#include +#include + +namespace ripple { + +/* Adapt MPTID to provide the same interface as Issue. Enables using static + * polymorphism by Asset and other classes. MPTID is a 192-bit concatenation + * of a 32-bit account sequence and a 160-bit account id. + */ +class MPTIssue +{ +private: + MPTID mptID_; + +public: + MPTIssue() = default; + + explicit MPTIssue(MPTID const& issuanceID); + + AccountID const& + getIssuer() const; + + MPTID const& + getMptID() const; + + std::string + getText() const; + + void + setJson(Json::Value& jv) const; + + friend constexpr bool + operator==(MPTIssue const& lhs, MPTIssue const& rhs); + + friend constexpr std::weak_ordering + operator<=>(MPTIssue const& lhs, MPTIssue const& rhs); + + bool + native() const + { + return false; + } +}; + +constexpr bool +operator==(MPTIssue const& lhs, MPTIssue const& rhs) +{ + return lhs.mptID_ == rhs.mptID_; +} + +constexpr std::weak_ordering +operator<=>(MPTIssue const& lhs, MPTIssue const& rhs) +{ + return lhs.mptID_ <=> rhs.mptID_; +} + +/** MPT is a non-native token. + */ +inline bool +isXRP(MPTID const&) +{ + return false; +} + +Json::Value +to_json(MPTIssue const& mptIssue); + +std::string +to_string(MPTIssue const& mptIssue); + +MPTIssue +mptIssueFromJson(Json::Value const& jv); + +} // namespace ripple + +#endif // RIPPLE_PROTOCOL_MPTISSUE_H_INCLUDED diff --git a/include/xrpl/protocol/MultiApiJson.h b/include/xrpl/protocol/MultiApiJson.h new file mode 100644 index 00000000000..15743e856b6 --- /dev/null +++ b/include/xrpl/protocol/MultiApiJson.h @@ -0,0 +1,242 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_JSON_MULTIAPIJSON_H_INCLUDED +#define RIPPLE_JSON_MULTIAPIJSON_H_INCLUDED + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +namespace detail { +template +constexpr bool is_integral_constant = false; +template +constexpr bool is_integral_constant&> = true; +template +constexpr bool is_integral_constant const&> = true; + +template +concept some_integral_constant = detail::is_integral_constant; + +// This class is designed to wrap a collection of _almost_ identical Json::Value +// objects, indexed by version (i.e. there is some mapping of version to object +// index). It is used e.g. when we need to publish JSON data to users supporting +// different API versions. We allow manipulation and inspection of all objects +// at once with `isMember` and `set`, and also individual inspection and updates +// of an object selected by the user by version, using `visitor_t` nested type. +template +struct MultiApiJson +{ + static_assert(MinVer <= MaxVer); + + static constexpr auto + valid(unsigned int v) noexcept -> bool + { + return v >= MinVer && v <= MaxVer; + } + + static constexpr auto + index(unsigned int v) noexcept -> std::size_t + { + return (v < MinVer) ? 0 : static_cast(v - MinVer); + } + + constexpr static std::size_t size = MaxVer + 1 - MinVer; + std::array val = {}; + + explicit MultiApiJson(Json::Value const& init = {}) + { + if (init == Json::Value{}) + return; // All elements are already default-initialized + for (auto& v : val) + v = init; + } + + void + set(const char* key, auto const& v) + requires std::constructible_from + { + for (auto& a : this->val) + a[key] = v; + } + + // Intentionally not using class enum here, MultivarJson is scope enough + enum IsMemberResult : int { none = 0, some, all }; + + [[nodiscard]] IsMemberResult + isMember(const char* key) const + { + int count = 0; + for (auto& a : this->val) + if (a.isMember(key)) + count += 1; + + return (count == 0 ? none : (count < size ? some : all)); + } + + static constexpr struct visitor_t final + { + // integral_constant version, extra arguments + template < + typename Json, + unsigned int Version, + typename... Args, + typename Fn> + requires std::same_as, MultiApiJson> + auto + operator()( + Json& json, + std::integral_constant const version, + Fn fn, + Args&&... args) const + -> std::invoke_result_t< + Fn, + decltype(json.val[0]), + std::integral_constant, + Args&&...> + { + static_assert( + valid(Version) && index(Version) >= 0 && index(Version) < size); + return std::invoke( + fn, + json.val[index(Version)], + version, + std::forward(args)...); + } + + // integral_constant version, Json only + template + requires std::same_as, MultiApiJson> + auto + operator()( + Json& json, + std::integral_constant const, + Fn fn) const -> std::invoke_result_t + { + static_assert( + valid(Version) && index(Version) >= 0 && index(Version) < size); + return std::invoke(fn, json.val[index(Version)]); + } + + // unsigned int version, extra arguments + template < + typename Json, + typename Version, + typename... Args, + typename Fn> + requires(!some_integral_constant) && + std::convertible_to && + std::same_as, MultiApiJson> + auto + operator()(Json& json, Version version, Fn fn, Args&&... args) const + -> std:: + invoke_result_t + { + XRPL_ASSERT( + valid(version) && index(version) >= 0 && index(version) < size, + "ripple::detail::MultiApiJson::operator() : valid " + "version"); + return std::invoke( + fn, + json.val[index(version)], + version, + std::forward(args)...); + } + + // unsigned int version, Json only + template + requires(!some_integral_constant) && + std::convertible_to && + std::same_as, MultiApiJson> + auto + operator()(Json& json, Version version, Fn fn) const + -> std::invoke_result_t + { + XRPL_ASSERT( + valid(version) && index(version) >= 0 && index(version) < size, + "ripple::detail::MultiApiJson::operator() : valid version"); + return std::invoke(fn, json.val[index(version)]); + } + } visitor = {}; + + auto + visit() + { + return [self = this](auto... args) + requires requires { + visitor( + std::declval(), + std::declval()...); + } + { return visitor(*self, std::forward(args)...); }; + } + + auto + visit() const + { + return [self = this](auto... args) + requires requires { + visitor( + std::declval(), + std::declval()...); + } + { return visitor(*self, std::forward(args)...); }; + } + + template + auto + visit(Args... args) + -> std::invoke_result_t + requires(sizeof...(args) > 0) && + requires { visitor(*this, std::forward(args)...); } + { + return visitor(*this, std::forward(args)...); + } + + template + auto + visit(Args... args) const + -> std::invoke_result_t + requires(sizeof...(args) > 0) && + requires { visitor(*this, std::forward(args)...); } + { + return visitor(*this, std::forward(args)...); + } +}; + +} // namespace detail + +// Wrapper for Json for all supported API versions. +using MultiApiJson = detail:: + MultiApiJson; + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/NFTSyntheticSerializer.h b/include/xrpl/protocol/NFTSyntheticSerializer.h new file mode 100644 index 00000000000..e57b3ff71c9 --- /dev/null +++ b/include/xrpl/protocol/NFTSyntheticSerializer.h @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_NFTSYNTHETICSERIALIZER_H_INCLUDED +#define RIPPLE_PROTOCOL_NFTSYNTHETICSERIALIZER_H_INCLUDED + +#include +#include +#include + +#include + +namespace ripple { + +/** + Adds common synthetic fields to transaction-related JSON responses + + @{ + */ +void +insertNFTSyntheticInJson( + Json::Value&, + std::shared_ptr const&, + TxMeta const&); +/** @} */ + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/NFTokenID.h b/include/xrpl/protocol/NFTokenID.h new file mode 100644 index 00000000000..b9ea75d2036 --- /dev/null +++ b/include/xrpl/protocol/NFTokenID.h @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_NFTOKENID_H_INCLUDED +#define RIPPLE_PROTOCOL_NFTOKENID_H_INCLUDED + +#include +#include +#include +#include + +#include +#include +#include + +namespace ripple { + +/** + Add a `nftoken_ids` field to the `meta` output parameter. + The field is only added to successful NFTokenMint, NFTokenAcceptOffer, + and NFTokenCancelOffer transactions. + + Helper functions are not static because they can be used by Clio. + @{ + */ +bool +canHaveNFTokenID( + std::shared_ptr const& serializedTx, + TxMeta const& transactionMeta); + +std::optional +getNFTokenIDFromPage(TxMeta const& transactionMeta); + +std::vector +getNFTokenIDFromDeletedOffer(TxMeta const& transactionMeta); + +void +insertNFTokenID( + Json::Value& response, + std::shared_ptr const& transaction, + TxMeta const& transactionMeta); +/** @} */ + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/NFTokenOfferID.h b/include/xrpl/protocol/NFTokenOfferID.h new file mode 100644 index 00000000000..9645b0b34da --- /dev/null +++ b/include/xrpl/protocol/NFTokenOfferID.h @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_NFTOKENOFFERID_H_INCLUDED +#define RIPPLE_PROTOCOL_NFTOKENOFFERID_H_INCLUDED + +#include +#include +#include +#include + +#include +#include + +namespace ripple { + +/** + Add an `offer_id` field to the `meta` output parameter. + The field is only added to successful NFTokenCreateOffer transactions. + + Helper functions are not static because they can be used by Clio. + @{ + */ +bool +canHaveNFTokenOfferID( + std::shared_ptr const& serializedTx, + TxMeta const& transactionMeta); + +std::optional +getOfferIDFromCreatedOffer(TxMeta const& transactionMeta); + +void +insertNFTokenOfferID( + Json::Value& response, + std::shared_ptr const& transaction, + TxMeta const& transactionMeta); +/** @} */ + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/PayChan.h b/include/xrpl/protocol/PayChan.h new file mode 100644 index 00000000000..b552b591af2 --- /dev/null +++ b/include/xrpl/protocol/PayChan.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_PAYCHAN_H_INCLUDED +#define RIPPLE_PROTOCOL_PAYCHAN_H_INCLUDED + +#include +#include +#include +#include + +namespace ripple { + +inline void +serializePayChanAuthorization( + Serializer& msg, + uint256 const& key, + XRPAmount const& amt) +{ + msg.add32(HashPrefix::paymentChannelClaim); + msg.addBitString(key); + msg.add64(amt.drops()); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h new file mode 100644 index 00000000000..1e8c76dbd8b --- /dev/null +++ b/include/xrpl/protocol/Protocol.h @@ -0,0 +1,160 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_PROTOCOL_H_INCLUDED +#define RIPPLE_PROTOCOL_PROTOCOL_H_INCLUDED + +#include +#include +#include + +#include + +namespace ripple { + +/** Protocol specific constants. + + This information is, implicitly, part of the protocol. + + @note Changing these values without adding code to the + server to detect "pre-change" and "post-change" + will result in a hard fork. + + @ingroup protocol +*/ +/** Smallest legal byte size of a transaction. */ +std::size_t constexpr txMinSizeBytes = 32; + +/** Largest legal byte size of a transaction. */ +std::size_t constexpr txMaxSizeBytes = megabytes(1); + +/** The maximum number of unfunded offers to delete at once */ +std::size_t constexpr unfundedOfferRemoveLimit = 1000; + +/** The maximum number of expired offers to delete at once */ +std::size_t constexpr expiredOfferRemoveLimit = 256; + +/** The maximum number of metadata entries allowed in one transaction */ +std::size_t constexpr oversizeMetaDataCap = 5200; + +/** The maximum number of entries per directory page */ +std::size_t constexpr dirNodeMaxEntries = 32; + +/** The maximum number of pages allowed in a directory */ +std::uint64_t constexpr dirNodeMaxPages = 262144; + +/** The maximum number of items in an NFT page */ +std::size_t constexpr dirMaxTokensPerPage = 32; + +/** The maximum number of owner directory entries for account to be deletable */ +std::size_t constexpr maxDeletableDirEntries = 1000; + +/** The maximum number of token offers that can be canceled at once */ +std::size_t constexpr maxTokenOfferCancelCount = 500; + +/** The maximum number of offers in an offer directory for NFT to be burnable */ +std::size_t constexpr maxDeletableTokenOfferEntries = 500; + +/** The maximum token transfer fee allowed. + + Token transfer fees can range from 0% to 50% and are specified in tenths of + a basis point; that is a value of 1000 represents a transfer fee of 1% and + a value of 10000 represents a transfer fee of 10%. + + Note that for extremely low transfer fees values, it is possible that the + calculated fee will be 0. + */ +std::uint16_t constexpr maxTransferFee = 50000; + +/** The maximum length of a URI inside an NFT */ +std::size_t constexpr maxTokenURILength = 256; + +/** The maximum length of a Data element inside a DID */ +std::size_t constexpr maxDIDDocumentLength = 256; + +/** The maximum length of a URI inside a DID */ +std::size_t constexpr maxDIDURILength = 256; + +/** The maximum length of an Attestation inside a DID */ +std::size_t constexpr maxDIDAttestationLength = 256; + +/** The maximum length of a domain */ +std::size_t constexpr maxDomainLength = 256; + +/** The maximum length of a URI inside a Credential */ +std::size_t constexpr maxCredentialURILength = 256; + +/** The maximum length of a CredentialType inside a Credential */ +std::size_t constexpr maxCredentialTypeLength = 64; + +/** The maximum number of credentials can be passed in array */ +std::size_t constexpr maxCredentialsArraySize = 8; + +/** The maximum number of credentials can be passed in array for permissioned + * domain */ +std::size_t constexpr maxPermissionedDomainCredentialsArraySize = 10; + +/** The maximum length of MPTokenMetadata */ +std::size_t constexpr maxMPTokenMetadataLength = 1024; + +/** The maximum amount of MPTokenIssuance */ +std::uint64_t constexpr maxMPTokenAmount = 0x7FFF'FFFF'FFFF'FFFFull; + +/** A ledger index. */ +using LedgerIndex = std::uint32_t; + +/** A transaction identifier. + The value is computed as the hash of the + canonicalized, serialized transaction object. +*/ +using TxID = uint256; + +/** The maximum number of trustlines to delete as part of AMM account + * deletion cleanup. + */ +std::uint16_t constexpr maxDeletableAMMTrustLines = 512; + +/** The maximum length of a URI inside an Oracle */ +std::size_t constexpr maxOracleURI = 256; + +/** The maximum length of a Provider inside an Oracle */ +std::size_t constexpr maxOracleProvider = 256; + +/** The maximum size of a data series array inside an Oracle */ +std::size_t constexpr maxOracleDataSeries = 10; + +/** The maximum length of a SymbolClass inside an Oracle */ +std::size_t constexpr maxOracleSymbolClass = 16; + +/** The maximum allowed time difference between lastUpdateTime and the time + of the last closed ledger +*/ +std::size_t constexpr maxLastUpdateTimeDelta = 300; + +/** The maximum price scaling factor + */ +std::size_t constexpr maxPriceScale = 20; + +/** The maximum percentage of outliers to trim + */ +std::size_t constexpr maxTrim = 25; + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/PublicKey.h b/include/xrpl/protocol/PublicKey.h new file mode 100644 index 00000000000..c68656877c9 --- /dev/null +++ b/include/xrpl/protocol/PublicKey.h @@ -0,0 +1,293 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_PUBLICKEY_H_INCLUDED +#define RIPPLE_PROTOCOL_PUBLICKEY_H_INCLUDED + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace ripple { + +/** A public key. + + Public keys are used in the public-key cryptography + system used to verify signatures attached to messages. + + The format of the public key is Ripple specific, + information needed to determine the cryptosystem + parameters used is stored inside the key. + + As of this writing two systems are supported: + + secp256k1 + ed25519 + + secp256k1 public keys consist of a 33 byte + compressed public key, with the lead byte equal + to 0x02 or 0x03. + + The ed25519 public keys consist of a 1 byte + prefix constant 0xED, followed by 32 bytes of + public key data. +*/ +class PublicKey +{ +protected: + // All the constructed public keys are valid, non-empty and contain 33 + // bytes of data. + static constexpr std::size_t size_ = 33; + std::uint8_t buf_[size_]; // should be large enough + +public: + using const_iterator = std::uint8_t const*; + +public: + PublicKey() = delete; + + PublicKey(PublicKey const& other); + PublicKey& + operator=(PublicKey const& other); + + /** Create a public key. + + Preconditions: + publicKeyType(slice) != std::nullopt + */ + explicit PublicKey(Slice const& slice); + + std::uint8_t const* + data() const noexcept + { + return buf_; + } + + std::size_t + size() const noexcept + { + return size_; + } + + const_iterator + begin() const noexcept + { + return buf_; + } + + const_iterator + cbegin() const noexcept + { + return buf_; + } + + const_iterator + end() const noexcept + { + return buf_ + size_; + } + + const_iterator + cend() const noexcept + { + return buf_ + size_; + } + + Slice + slice() const noexcept + { + return {buf_, size_}; + } + + operator Slice() const noexcept + { + return slice(); + } +}; + +/** Print the public key to a stream. + */ +std::ostream& +operator<<(std::ostream& os, PublicKey const& pk); + +inline bool +operator==(PublicKey const& lhs, PublicKey const& rhs) +{ + return std::memcmp(lhs.data(), rhs.data(), rhs.size()) == 0; +} + +inline bool +operator<(PublicKey const& lhs, PublicKey const& rhs) +{ + return std::lexicographical_compare( + lhs.data(), + lhs.data() + lhs.size(), + rhs.data(), + rhs.data() + rhs.size()); +} + +template +void +hash_append(Hasher& h, PublicKey const& pk) +{ + h(pk.data(), pk.size()); +} + +template <> +struct STExchange +{ + explicit STExchange() = default; + + using value_type = PublicKey; + + static void + get(std::optional& t, STBlob const& u) + { + t.emplace(Slice(u.data(), u.size())); + } + + static std::unique_ptr + set(SField const& f, PublicKey const& t) + { + return std::make_unique(f, t.data(), t.size()); + } +}; + +//------------------------------------------------------------------------------ + +inline std::string +toBase58(TokenType type, PublicKey const& pk) +{ + return encodeBase58Token(type, pk.data(), pk.size()); +} + +template <> +std::optional +parseBase58(TokenType type, std::string const& s); + +enum class ECDSACanonicality { canonical, fullyCanonical }; + +/** Determines the canonicality of a signature. + + A canonical signature is in its most reduced form. + For example the R and S components do not contain + additional leading zeroes. However, even in + canonical form, (R,S) and (R,G-S) are both + valid signatures for message M. + + Therefore, to prevent malleability attacks we + define a fully canonical signature as one where: + + R < G - S + + where G is the curve order. + + This routine returns std::nullopt if the format + of the signature is invalid (for example, the + points are encoded incorrectly). + + @return std::nullopt if the signature fails + validity checks. + + @note Only the format of the signature is checked, + no verification cryptography is performed. +*/ +std::optional +ecdsaCanonicality(Slice const& sig); + +/** Returns the type of public key. + + @return std::nullopt If the public key does not + represent a known type. +*/ +/** @{ */ +[[nodiscard]] std::optional +publicKeyType(Slice const& slice); + +[[nodiscard]] inline std::optional +publicKeyType(PublicKey const& publicKey) +{ + return publicKeyType(publicKey.slice()); +} +/** @} */ + +/** Verify a secp256k1 signature on the digest of a message. */ +[[nodiscard]] bool +verifyDigest( + PublicKey const& publicKey, + uint256 const& digest, + Slice const& sig, + bool mustBeFullyCanonical = true) noexcept; + +/** Verify a signature on a message. + With secp256k1 signatures, the data is first hashed with + SHA512-Half, and the resulting digest is signed. +*/ +[[nodiscard]] bool +verify( + PublicKey const& publicKey, + Slice const& m, + Slice const& sig, + bool mustBeFullyCanonical = true) noexcept; + +/** Calculate the 160-bit node ID from a node public key. */ +NodeID +calcNodeID(PublicKey const&); + +// VFALCO This belongs in AccountID.h but +// is here because of header issues +AccountID +calcAccountID(PublicKey const& pk); + +} // namespace ripple + +//------------------------------------------------------------------------------ + +namespace Json { +template <> +inline ripple::PublicKey +getOrThrow(Json::Value const& v, ripple::SField const& field) +{ + using namespace ripple; + std::string const b58 = getOrThrow(v, field); + if (auto pubKeyBlob = strUnHex(b58); publicKeyType(makeSlice(*pubKeyBlob))) + { + return PublicKey{makeSlice(*pubKeyBlob)}; + } + for (auto const tokenType : + {TokenType::NodePublic, TokenType::AccountPublic}) + { + if (auto const pk = parseBase58(tokenType, b58)) + return *pk; + } + Throw(field.getJsonName(), "PublicKey"); +} +} // namespace Json + +#endif diff --git a/include/xrpl/protocol/Quality.h b/include/xrpl/protocol/Quality.h new file mode 100644 index 00000000000..6783fbf6dac --- /dev/null +++ b/include/xrpl/protocol/Quality.h @@ -0,0 +1,419 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_QUALITY_H_INCLUDED +#define RIPPLE_PROTOCOL_QUALITY_H_INCLUDED + +#include +#include +#include +#include + +#include +#include +#include + +namespace ripple { + +/** Represents a pair of input and output currencies. + + The input currency can be converted to the output + currency by multiplying by the rate, represented by + Quality. + + For offers, "in" is always TakerPays and "out" is + always TakerGets. +*/ +template +struct TAmounts +{ + TAmounts() = default; + + TAmounts(beast::Zero, beast::Zero) : in(beast::zero), out(beast::zero) + { + } + + TAmounts(In const& in_, Out const& out_) : in(in_), out(out_) + { + } + + /** Returns `true` if either quantity is not positive. */ + bool + empty() const noexcept + { + return in <= beast::zero || out <= beast::zero; + } + + TAmounts& + operator+=(TAmounts const& rhs) + { + in += rhs.in; + out += rhs.out; + return *this; + } + + TAmounts& + operator-=(TAmounts const& rhs) + { + in -= rhs.in; + out -= rhs.out; + return *this; + } + + In in; + Out out; +}; + +using Amounts = TAmounts; + +template +bool +operator==(TAmounts const& lhs, TAmounts const& rhs) noexcept +{ + return lhs.in == rhs.in && lhs.out == rhs.out; +} + +template +bool +operator!=(TAmounts const& lhs, TAmounts const& rhs) noexcept +{ + return !(lhs == rhs); +} + +//------------------------------------------------------------------------------ + +// Ripple specific constant used for parsing qualities and other things +#define QUALITY_ONE 1'000'000'000 + +/** Represents the logical ratio of output currency to input currency. + Internally this is stored using a custom floating point representation, + as the inverse of the ratio, so that quality will be descending in + a sequence of actual values that represent qualities. +*/ +class Quality +{ +public: + // Type of the internal representation. Higher qualities + // have lower unsigned integer representations. + using value_type = std::uint64_t; + + static const int minTickSize = 3; + static const int maxTickSize = 16; + +private: + // This has the same representation as STAmount, see the comment on the + // STAmount. However, this class does not always use the canonical + // representation. In particular, the increment and decrement operators may + // cause a non-canonical representation. + value_type m_value; + +public: + Quality() = default; + + /** Create a quality from the integer encoding of an STAmount */ + explicit Quality(std::uint64_t value); + + /** Create a quality from the ratio of two amounts. */ + explicit Quality(Amounts const& amount); + + /** Create a quality from the ratio of two amounts. */ + template + explicit Quality(TAmounts const& amount) + : Quality(Amounts(toSTAmount(amount.in), toSTAmount(amount.out))) + { + } + + /** Create a quality from the ratio of two amounts. */ + template + Quality(Out const& out, In const& in) + : Quality(Amounts(toSTAmount(in), toSTAmount(out))) + { + } + + /** Advances to the next higher quality level. */ + /** @{ */ + Quality& + operator++(); + + Quality + operator++(int); + /** @} */ + + /** Advances to the next lower quality level. */ + /** @{ */ + Quality& + operator--(); + + Quality + operator--(int); + /** @} */ + + /** Returns the quality as STAmount. */ + STAmount + rate() const + { + return amountFromQuality(m_value); + } + + /** Returns the quality rounded up to the specified number + of decimal digits. + */ + Quality + round(int tickSize) const; + + /** Returns the scaled amount with in capped. + Math is avoided if the result is exact. The output is clamped + to prevent money creation. + */ + [[nodiscard]] Amounts + ceil_in(Amounts const& amount, STAmount const& limit) const; + + template + [[nodiscard]] TAmounts + ceil_in(TAmounts const& amount, In const& limit) const; + + // Some of the underlying rounding functions called by ceil_in() ignored + // low order bits that could influence rounding decisions. This "strict" + // method uses underlying functions that pay attention to all the bits. + [[nodiscard]] Amounts + ceil_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp) + const; + + template + [[nodiscard]] TAmounts + ceil_in_strict( + TAmounts const& amount, + In const& limit, + bool roundUp) const; + + /** Returns the scaled amount with out capped. + Math is avoided if the result is exact. The input is clamped + to prevent money creation. + */ + [[nodiscard]] Amounts + ceil_out(Amounts const& amount, STAmount const& limit) const; + + template + [[nodiscard]] TAmounts + ceil_out(TAmounts const& amount, Out const& limit) const; + + // Some of the underlying rounding functions called by ceil_out() ignored + // low order bits that could influence rounding decisions. This "strict" + // method uses underlying functions that pay attention to all the bits. + [[nodiscard]] Amounts + ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp) + const; + + template + [[nodiscard]] TAmounts + ceil_out_strict( + TAmounts const& amount, + Out const& limit, + bool roundUp) const; + +private: + // The ceil_in and ceil_out methods that deal in TAmount all convert + // their arguments to STAoumout and convert the result back to TAmount. + // This helper function takes care of all the conversion operations. + template < + class In, + class Out, + class Lim, + typename FnPtr, + std::same_as... Round> + [[nodiscard]] TAmounts + ceil_TAmounts_helper( + TAmounts const& amount, + Lim const& limit, + Lim const& limit_cmp, + FnPtr ceil_function, + Round... round) const; + +public: + /** Returns `true` if lhs is lower quality than `rhs`. + Lower quality means the taker receives a worse deal. + Higher quality is better for the taker. + */ + friend bool + operator<(Quality const& lhs, Quality const& rhs) noexcept + { + return lhs.m_value > rhs.m_value; + } + + friend bool + operator>(Quality const& lhs, Quality const& rhs) noexcept + { + return lhs.m_value < rhs.m_value; + } + + friend bool + operator<=(Quality const& lhs, Quality const& rhs) noexcept + { + return !(lhs > rhs); + } + + friend bool + operator>=(Quality const& lhs, Quality const& rhs) noexcept + { + return !(lhs < rhs); + } + + friend bool + operator==(Quality const& lhs, Quality const& rhs) noexcept + { + return lhs.m_value == rhs.m_value; + } + + friend bool + operator!=(Quality const& lhs, Quality const& rhs) noexcept + { + return !(lhs == rhs); + } + + friend std::ostream& + operator<<(std::ostream& os, Quality const& quality) + { + os << quality.m_value; + return os; + } + + // return the relative distance (relative error) between two qualities. This + // is used for testing only. relative distance is abs(a-b)/min(a,b) + friend double + relativeDistance(Quality const& q1, Quality const& q2) + { + XRPL_ASSERT( + q1.m_value > 0 && q2.m_value > 0, + "ripple::Quality::relativeDistance : minimum inputs"); + + if (q1.m_value == q2.m_value) // make expected common case fast + return 0; + + auto const [minV, maxV] = std::minmax(q1.m_value, q2.m_value); + + auto mantissa = [](std::uint64_t rate) { + return rate & ~(255ull << (64 - 8)); + }; + auto exponent = [](std::uint64_t rate) { + return static_cast(rate >> (64 - 8)) - 100; + }; + + auto const minVMantissa = mantissa(minV); + auto const maxVMantissa = mantissa(maxV); + auto const expDiff = exponent(maxV) - exponent(minV); + + double const minVD = static_cast(minVMantissa); + double const maxVD = expDiff ? maxVMantissa * pow(10, expDiff) + : static_cast(maxVMantissa); + + // maxVD and minVD are scaled so they have the same exponents. Dividing + // cancels out the exponents, so we only need to deal with the (scaled) + // mantissas + return (maxVD - minVD) / minVD; + } +}; + +template < + class In, + class Out, + class Lim, + typename FnPtr, + std::same_as... Round> +TAmounts +Quality::ceil_TAmounts_helper( + TAmounts const& amount, + Lim const& limit, + Lim const& limit_cmp, + FnPtr ceil_function, + Round... roundUp) const +{ + if (limit_cmp <= limit) + return amount; + + // Use the existing STAmount implementation for now, but consider + // replacing with code specific to IOUAMount and XRPAmount + Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out)); + STAmount stLim(toSTAmount(limit)); + Amounts const stRes = ((*this).*ceil_function)(stAmt, stLim, roundUp...); + return TAmounts(toAmount(stRes.in), toAmount(stRes.out)); +} + +template +TAmounts +Quality::ceil_in(TAmounts const& amount, In const& limit) const +{ + // Construct a function pointer to the function we want to call. + static constexpr Amounts (Quality::*ceil_in_fn_ptr)( + Amounts const&, STAmount const&) const = &Quality::ceil_in; + + return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr); +} + +template +TAmounts +Quality::ceil_in_strict( + TAmounts const& amount, + In const& limit, + bool roundUp) const +{ + // Construct a function pointer to the function we want to call. + static constexpr Amounts (Quality::*ceil_in_fn_ptr)( + Amounts const&, STAmount const&, bool) const = &Quality::ceil_in_strict; + + return ceil_TAmounts_helper( + amount, limit, amount.in, ceil_in_fn_ptr, roundUp); +} + +template +TAmounts +Quality::ceil_out(TAmounts const& amount, Out const& limit) const +{ + // Construct a function pointer to the function we want to call. + static constexpr Amounts (Quality::*ceil_out_fn_ptr)( + Amounts const&, STAmount const&) const = &Quality::ceil_out; + + return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr); +} + +template +TAmounts +Quality::ceil_out_strict( + TAmounts const& amount, + Out const& limit, + bool roundUp) const +{ + // Construct a function pointer to the function we want to call. + static constexpr Amounts (Quality::*ceil_out_fn_ptr)( + Amounts const&, STAmount const&, bool) const = + &Quality::ceil_out_strict; + + return ceil_TAmounts_helper( + amount, limit, amount.out, ceil_out_fn_ptr, roundUp); +} + +/** Calculate the quality of a two-hop path given the two hops. + @param lhs The first leg of the path: input to intermediate. + @param rhs The second leg of the path: intermediate to output. +*/ +Quality +composed_quality(Quality const& lhs, Quality const& rhs); + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/QualityFunction.h b/include/xrpl/protocol/QualityFunction.h new file mode 100644 index 00000000000..f7184881489 --- /dev/null +++ b/include/xrpl/protocol/QualityFunction.h @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_QUALITYFUNCTION_H_INCLUDED +#define RIPPLE_PROTOCOL_QUALITYFUNCTION_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +/** Average quality of a path as a function of `out`: q(out) = m * out + b, + * where m = -1 / poolGets, b = poolPays / poolGets. If CLOB offer then + * `m` is equal to 0 `b` is equal to the offer's quality. The function + * is derived by substituting `in` in q = out / in with the swap out formula + * for `in`: + * in = [(poolGets * poolPays) / (poolGets - out) - poolPays] / (1 - tfee) + * and combining the function for multiple steps. The function is used + * to limit required output amount when quality limit is provided in one + * path optimization. + */ +class QualityFunction +{ +private: + // slope + Number m_; + // intercept + Number b_; + // seated if QF is for CLOB offer. + std::optional quality_; + +public: + struct AMMTag + { + }; + // AMMOffer for multi-path is like CLOB, i.e. the offer size + // changes proportionally to its quality. + struct CLOBLikeTag + { + }; + QualityFunction(Quality const& quality, CLOBLikeTag); + template + QualityFunction( + TAmounts const& amounts, + std::uint32_t tfee, + AMMTag); + + /** Combines QF with the next step QF + */ + void + combine(QualityFunction const& qf); + + /** Find output to produce the requested + * average quality. + * @param quality requested average quality (quality limit) + */ + std::optional + outFromAvgQ(Quality const& quality); + + /** Return true if the quality function is constant + */ + bool + isConst() const + { + return quality_.has_value(); + } + + std::optional const& + quality() const + { + return quality_; + } +}; + +template +QualityFunction::QualityFunction( + TAmounts const& amounts, + std::uint32_t tfee, + QualityFunction::AMMTag) +{ + if (amounts.in <= beast::zero || amounts.out <= beast::zero) + Throw("QualityFunction amounts are 0."); + Number const cfee = feeMult(tfee); + m_ = -cfee / amounts.in; + b_ = amounts.out * cfee / amounts.in; +} + +} // namespace ripple + +#endif // RIPPLE_PROTOCOL_QUALITYFUNCTION_H_INCLUDED diff --git a/include/xrpl/protocol/README.md b/include/xrpl/protocol/README.md new file mode 100644 index 00000000000..9864b700ef2 --- /dev/null +++ b/include/xrpl/protocol/README.md @@ -0,0 +1,44 @@ +# protocol + +Classes and functions for handling data and +values associated with the XRP Ledger protocol. + +## Serialized Objects + +Objects transmitted over the network must be +serialized into a canonical format. The prefix "ST" refers +to classes that deal with the serialized format. + +The term "Tx" or "tx" is an abbreviation for "Transaction", +a commonly occurring object type. + +### Optional Fields + +Our serialized fields have some "type magic" to make +optional fields easier to read: + +- The operation `x[sfFoo]` means "return the value of 'Foo' + if it exists, or the default value if it doesn't." +- The operation `x[~sfFoo]` means "return the value of 'Foo' + if it exists, or nothing if it doesn't." This usage of the + tilde/bitwise NOT operator is not standard outside of the + `rippled` codebase. + - As a consequence of this, `x[~sfFoo] = y[~sfFoo]` + assigns the value of Foo from y to x, including omitting + Foo from x if it doesn't exist in y. + +Typically, for things that are guaranteed to exist, you use +`x[sfFoo]` and avoid having to deal with a container that may +or may not hold a value. For things not guaranteed to exist, +you use `x[~sfFoo]` because you want such a container. It +avoids having to look something up twice, once just to see if +it exists and a second time to get/set its value. +([Real example](https://github.com/ripple/rippled/blob/35f4698aed5dce02f771b34cfbb690495cb5efcc/src/ripple/app/tx/impl/PayChan.cpp#L229-L236)) + +The source of this "type magic" is in +[SField.h](./SField.h#L296-L302). + +### Related Resources + +- [ripple-binary-codec SField enums](https://github.com/XRPLF/xrpl.js/tree/main/packages/ripple-binary-codec/src/enums) +- [SFCode Registry Tables](https://github.com/XRPLF/sFieldRegistry) diff --git a/src/ripple/net/RPCErr.h b/include/xrpl/protocol/RPCErr.h similarity index 85% rename from src/ripple/net/RPCErr.h rename to include/xrpl/protocol/RPCErr.h index 0841de2b085..cb106b2f0da 100644 --- a/src/ripple/net/RPCErr.h +++ b/include/xrpl/protocol/RPCErr.h @@ -20,15 +20,16 @@ #ifndef RIPPLE_NET_RPCERR_H_INCLUDED #define RIPPLE_NET_RPCERR_H_INCLUDED -#include +#include namespace ripple { // VFALCO NOTE these are deprecated -bool isRpcError (Json::Value jvResult); -Json::Value rpcError (int iError, - Json::Value jvResult = Json::Value (Json::objectValue)); +bool +isRpcError(Json::Value jvResult); +Json::Value +rpcError(int iError); -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/protocol/Rate.h b/include/xrpl/protocol/Rate.h new file mode 100644 index 00000000000..548a7af6f99 --- /dev/null +++ b/include/xrpl/protocol/Rate.h @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_RATE_H_INCLUDED +#define RIPPLE_PROTOCOL_RATE_H_INCLUDED + +#include +#include + +#include + +#include +#include + +namespace ripple { + +/** Represents a transfer rate + + Transfer rates are specified as fractions of 1 billion. + For example, a transfer rate of 1% is represented as + 1,010,000,000. +*/ +struct Rate : private boost::totally_ordered +{ + std::uint32_t value; + + Rate() = delete; + + explicit Rate(std::uint32_t rate) : value(rate) + { + } +}; + +inline bool +operator==(Rate const& lhs, Rate const& rhs) noexcept +{ + return lhs.value == rhs.value; +} + +inline bool +operator<(Rate const& lhs, Rate const& rhs) noexcept +{ + return lhs.value < rhs.value; +} + +inline std::ostream& +operator<<(std::ostream& os, Rate const& rate) +{ + os << rate.value; + return os; +} + +STAmount +multiply(STAmount const& amount, Rate const& rate); + +STAmount +multiplyRound(STAmount const& amount, Rate const& rate, bool roundUp); + +STAmount +multiplyRound( + STAmount const& amount, + Rate const& rate, + Asset const& asset, + bool roundUp); + +STAmount +divide(STAmount const& amount, Rate const& rate); + +STAmount +divideRound(STAmount const& amount, Rate const& rate, bool roundUp); + +STAmount +divideRound( + STAmount const& amount, + Rate const& rate, + Asset const& asset, + bool roundUp); + +namespace nft { +/** Given a transfer fee (in basis points) convert it to a transfer rate. */ +Rate +transferFeeAsRate(std::uint16_t fee); + +} // namespace nft + +/** A transfer rate signifying a 1:1 exchange */ +extern Rate const parityRate; + +} // namespace ripple + +#endif diff --git a/src/ripple/protocol/RippleLedgerHash.h b/include/xrpl/protocol/RippleLedgerHash.h similarity index 97% rename from src/ripple/protocol/RippleLedgerHash.h rename to include/xrpl/protocol/RippleLedgerHash.h index 2a7b5728342..19ba803b823 100644 --- a/src/ripple/protocol/RippleLedgerHash.h +++ b/include/xrpl/protocol/RippleLedgerHash.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_RIPPLELEDGERHASH_H_INCLUDED #define RIPPLE_PROTOCOL_RIPPLELEDGERHASH_H_INCLUDED -#include +#include namespace ripple { diff --git a/include/xrpl/protocol/Rules.h b/include/xrpl/protocol/Rules.h new file mode 100644 index 00000000000..6b22d01afe0 --- /dev/null +++ b/include/xrpl/protocol/Rules.h @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_LEDGER_RULES_H_INCLUDED +#define RIPPLE_LEDGER_RULES_H_INCLUDED + +#include +#include +#include + +#include + +namespace ripple { + +class DigestAwareReadView; + +/** Rules controlling protocol behavior. */ +class Rules +{ +private: + class Impl; + + // Carrying impl by shared_ptr makes Rules comparatively cheap to pass + // by value. + std::shared_ptr impl_; + +public: + Rules(Rules const&) = default; + + Rules(Rules&&) = default; + + Rules& + operator=(Rules const&) = default; + + Rules& + operator=(Rules&&) = default; + + Rules() = delete; + + /** Construct an empty rule set. + + These are the rules reflected by + the genesis ledger. + */ + explicit Rules(std::unordered_set> const& presets); + +private: + // Allow a friend function to construct Rules. + friend Rules + makeRulesGivenLedger( + DigestAwareReadView const& ledger, + Rules const& current); + + friend Rules + makeRulesGivenLedger( + DigestAwareReadView const& ledger, + std::unordered_set> const& presets); + + Rules( + std::unordered_set> const& presets, + std::optional const& digest, + STVector256 const& amendments); + + std::unordered_set> const& + presets() const; + +public: + /** Returns `true` if a feature is enabled. */ + bool + enabled(uint256 const& feature) const; + + /** Returns `true` if two rule sets are identical. + + @note This is for diagnostics. + */ + bool + operator==(Rules const&) const; + + bool + operator!=(Rules const& other) const; +}; + +std::optional const& +getCurrentTransactionRules(); + +void +setCurrentTransactionRules(std::optional r); + +/** RAII class to set and restore the current transaction rules + */ +class CurrentTransactionRulesGuard +{ +public: + explicit CurrentTransactionRulesGuard(Rules r) + : saved_(getCurrentTransactionRules()) + { + setCurrentTransactionRules(std::move(r)); + } + + ~CurrentTransactionRulesGuard() + { + setCurrentTransactionRules(saved_); + } + + CurrentTransactionRulesGuard() = delete; + CurrentTransactionRulesGuard(CurrentTransactionRulesGuard const&) = delete; + CurrentTransactionRulesGuard& + operator=(CurrentTransactionRulesGuard const&) = delete; + +private: + std::optional saved_; +}; + +} // namespace ripple +#endif diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h new file mode 100644 index 00000000000..01909b19862 --- /dev/null +++ b/include/xrpl/protocol/SField.h @@ -0,0 +1,390 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_SFIELD_H_INCLUDED +#define RIPPLE_PROTOCOL_SFIELD_H_INCLUDED + +#include +#include + +#include +#include +#include + +namespace ripple { + +/* + +Some fields have a different meaning for their + default value versus not present. + Example: + QualityIn on a TrustLine + +*/ + +//------------------------------------------------------------------------------ + +// Forwards +class STAccount; +class STAmount; +class STIssue; +class STBlob; +template +class STBitString; +template +class STInteger; +class STNumber; +class STXChainBridge; +class STVector256; +class STCurrency; + +#pragma push_macro("XMACRO") +#undef XMACRO + +#define XMACRO(STYPE) \ + /* special types */ \ + STYPE(STI_UNKNOWN, -2) \ + STYPE(STI_NOTPRESENT, 0) \ + STYPE(STI_UINT16, 1) \ + \ + /* types (common) */ \ + STYPE(STI_UINT32, 2) \ + STYPE(STI_UINT64, 3) \ + STYPE(STI_UINT128, 4) \ + STYPE(STI_UINT256, 5) \ + STYPE(STI_AMOUNT, 6) \ + STYPE(STI_VL, 7) \ + STYPE(STI_ACCOUNT, 8) \ + STYPE(STI_NUMBER, 9) \ + \ + /* 10-13 are reserved */ \ + STYPE(STI_OBJECT, 14) \ + STYPE(STI_ARRAY, 15) \ + \ + /* types (uncommon) */ \ + STYPE(STI_UINT8, 16) \ + STYPE(STI_UINT160, 17) \ + STYPE(STI_PATHSET, 18) \ + STYPE(STI_VECTOR256, 19) \ + STYPE(STI_UINT96, 20) \ + STYPE(STI_UINT192, 21) \ + STYPE(STI_UINT384, 22) \ + STYPE(STI_UINT512, 23) \ + STYPE(STI_ISSUE, 24) \ + STYPE(STI_XCHAIN_BRIDGE, 25) \ + STYPE(STI_CURRENCY, 26) \ + \ + /* high-level types */ \ + /* cannot be serialized inside other types */ \ + STYPE(STI_TRANSACTION, 10001) \ + STYPE(STI_LEDGERENTRY, 10002) \ + STYPE(STI_VALIDATION, 10003) \ + STYPE(STI_METADATA, 10004) + +#pragma push_macro("TO_ENUM") +#undef TO_ENUM +#pragma push_macro("TO_MAP") +#undef TO_MAP + +#define TO_ENUM(name, value) name = value, +#define TO_MAP(name, value) {#name, value}, + +enum SerializedTypeID { XMACRO(TO_ENUM) }; + +static std::map const sTypeMap = {XMACRO(TO_MAP)}; + +#undef XMACRO +#undef TO_ENUM + +#pragma pop_macro("XMACRO") +#pragma pop_macro("TO_ENUM") +#pragma pop_macro("TO_MAP") + +// constexpr +inline int +field_code(SerializedTypeID id, int index) +{ + return (safe_cast(id) << 16) | index; +} + +// constexpr +inline int +field_code(int id, int index) +{ + return (id << 16) | index; +} + +/** Identifies fields. + + Fields are necessary to tag data in signed transactions so that + the binary format of the transaction can be canonicalized. All + SFields are created at compile time. + + Each SField, once constructed, lives until program termination, and there + is only one instance per fieldType/fieldValue pair which serves the entire + application. +*/ +class SField +{ +public: + enum { + sMD_Never = 0x00, + sMD_ChangeOrig = 0x01, // original value when it changes + sMD_ChangeNew = 0x02, // new value when it changes + sMD_DeleteFinal = 0x04, // final value when it is deleted + sMD_Create = 0x08, // value when it's created + sMD_Always = 0x10, // value when node containing it is affected at all + sMD_BaseTen = 0x20, + sMD_Default = + sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create + }; + + enum class IsSigning : unsigned char { no, yes }; + static IsSigning const notSigning = IsSigning::no; + + int const fieldCode; // (type<<16)|index + SerializedTypeID const fieldType; // STI_* + int const fieldValue; // Code number for protocol + std::string const fieldName; + int const fieldMeta; + int const fieldNum; + IsSigning const signingField; + Json::StaticString const jsonName; + + SField(SField const&) = delete; + SField& + operator=(SField const&) = delete; + SField(SField&&) = delete; + SField& + operator=(SField&&) = delete; + +public: + struct private_access_tag_t; // public, but still an implementation detail + + // These constructors can only be called from SField.cpp + SField( + private_access_tag_t, + SerializedTypeID tid, + int fv, + const char* fn, + int meta = sMD_Default, + IsSigning signing = IsSigning::yes); + explicit SField(private_access_tag_t, int fc); + + static const SField& + getField(int fieldCode); + static const SField& + getField(std::string const& fieldName); + static const SField& + getField(int type, int value) + { + return getField(field_code(type, value)); + } + + static const SField& + getField(SerializedTypeID type, int value) + { + return getField(field_code(type, value)); + } + + std::string const& + getName() const + { + return fieldName; + } + + bool + hasName() const + { + return fieldCode > 0; + } + + Json::StaticString const& + getJsonName() const + { + return jsonName; + } + + operator Json::StaticString const&() const + { + return jsonName; + } + + bool + isInvalid() const + { + return fieldCode == -1; + } + + bool + isUseful() const + { + return fieldCode > 0; + } + + bool + isBinary() const + { + return fieldValue < 256; + } + + // A discardable field is one that cannot be serialized, and + // should be discarded during serialization,like 'hash'. + // You cannot serialize an object's hash inside that object, + // but you can have it in the JSON representation. + bool + isDiscardable() const + { + return fieldValue > 256; + } + + int + getCode() const + { + return fieldCode; + } + int + getNum() const + { + return fieldNum; + } + static int + getNumFields() + { + return num; + } + + bool + shouldMeta(int c) const + { + return (fieldMeta & c) != 0; + } + + bool + shouldInclude(bool withSigningField) const + { + return (fieldValue < 256) && + (withSigningField || (signingField == IsSigning::yes)); + } + + bool + operator==(const SField& f) const + { + return fieldCode == f.fieldCode; + } + + bool + operator!=(const SField& f) const + { + return fieldCode != f.fieldCode; + } + + static int + compare(const SField& f1, const SField& f2); + + static std::map const& + getKnownCodeToField() + { + return knownCodeToField; + } + +private: + static int num; + static std::map knownCodeToField; +}; + +/** A field with a type known at compile time. */ +template +struct TypedField : SField +{ + using type = T; + + template + explicit TypedField(private_access_tag_t pat, Args&&... args); +}; + +/** Indicate std::optional field semantics. */ +template +struct OptionaledField +{ + TypedField const* f; + + explicit OptionaledField(TypedField const& f_) : f(&f_) + { + } +}; + +template +inline OptionaledField +operator~(TypedField const& f) +{ + return OptionaledField(f); +} + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ + +using SF_UINT8 = TypedField>; +using SF_UINT16 = TypedField>; +using SF_UINT32 = TypedField>; +using SF_UINT64 = TypedField>; +using SF_UINT96 = TypedField>; +using SF_UINT128 = TypedField>; +using SF_UINT160 = TypedField>; +using SF_UINT192 = TypedField>; +using SF_UINT256 = TypedField>; +using SF_UINT384 = TypedField>; +using SF_UINT512 = TypedField>; + +using SF_ACCOUNT = TypedField; +using SF_AMOUNT = TypedField; +using SF_ISSUE = TypedField; +using SF_CURRENCY = TypedField; +using SF_NUMBER = TypedField; +using SF_VL = TypedField; +using SF_VECTOR256 = TypedField; +using SF_XCHAIN_BRIDGE = TypedField; + +//------------------------------------------------------------------------------ + +// Use macros for most SField construction to enforce naming conventions. +#pragma push_macro("UNTYPED_SFIELD") +#undef UNTYPED_SFIELD +#pragma push_macro("TYPED_SFIELD") +#undef TYPED_SFIELD + +#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ + extern SField const sfName; +#define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ + extern SF_##stiSuffix const sfName; + +extern SField const sfInvalid; +extern SField const sfGeneric; + +#include + +#undef TYPED_SFIELD +#pragma pop_macro("TYPED_SFIELD") +#undef UNTYPED_SFIELD +#pragma pop_macro("UNTYPED_SFIELD") + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h new file mode 100644 index 00000000000..9fd4cbf19d5 --- /dev/null +++ b/include/xrpl/protocol/SOTemplate.h @@ -0,0 +1,179 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_SOTEMPLATE_H_INCLUDED +#define RIPPLE_PROTOCOL_SOTEMPLATE_H_INCLUDED + +#include +#include + +#include +#include +#include +#include + +namespace ripple { + +/** Kind of element in each entry of an SOTemplate. */ +enum SOEStyle { + soeINVALID = -1, + soeREQUIRED = 0, // required + soeOPTIONAL = 1, // optional, may be present with default value + soeDEFAULT = 2, // optional, if present, must not have default value + // inner object with the default fields has to be + // constructed with STObject::makeInnerObject() +}; + +/** Amount fields that can support MPT */ +enum SOETxMPTIssue { soeMPTNone, soeMPTSupported, soeMPTNotSupported }; + +//------------------------------------------------------------------------------ + +/** An element in a SOTemplate. */ +class SOElement +{ + // Use std::reference_wrapper so SOElement can be stored in a std::vector. + std::reference_wrapper sField_; + SOEStyle style_; + SOETxMPTIssue supportMpt_ = soeMPTNone; + +private: + void + init(SField const& fieldName) const + { + if (!sField_.get().isUseful()) + { + auto nm = std::to_string(fieldName.getCode()); + if (fieldName.hasName()) + nm += ": '" + fieldName.getName() + "'"; + Throw( + "SField (" + nm + ") in SOElement must be useful."); + } + } + +public: + SOElement(SField const& fieldName, SOEStyle style) + : sField_(fieldName), style_(style) + { + init(fieldName); + } + + template + requires(std::is_same_v || std::is_same_v) + SOElement( + TypedField const& fieldName, + SOEStyle style, + SOETxMPTIssue supportMpt = soeMPTNotSupported) + : sField_(fieldName), style_(style), supportMpt_(supportMpt) + { + init(fieldName); + } + + SField const& + sField() const + { + return sField_.get(); + } + + SOEStyle + style() const + { + return style_; + } + + SOETxMPTIssue + supportMPT() const + { + return supportMpt_; + } +}; + +//------------------------------------------------------------------------------ + +/** Defines the fields and their attributes within a STObject. + Each subclass of SerializedObject will provide its own template + describing the available fields and their metadata attributes. +*/ +class SOTemplate +{ +public: + // Copying vectors is expensive. Make this a move-only type until + // there is motivation to change that. + SOTemplate(SOTemplate&& other) = default; + SOTemplate& + operator=(SOTemplate&& other) = default; + + /** Create a template populated with all fields. + After creating the template fields cannot be + added, modified, or removed. + */ + SOTemplate( + std::initializer_list uniqueFields, + std::initializer_list commonFields = {}); + + /* Provide for the enumeration of fields */ + std::vector::const_iterator + begin() const + { + return elements_.cbegin(); + } + + std::vector::const_iterator + cbegin() const + { + return begin(); + } + + std::vector::const_iterator + end() const + { + return elements_.cend(); + } + + std::vector::const_iterator + cend() const + { + return end(); + } + + /** The number of entries in this template */ + std::size_t + size() const + { + return elements_.size(); + } + + /** Retrieve the position of a named field. */ + int + getIndex(SField const&) const; + + SOEStyle + style(SField const& sf) const + { + return elements_[indices_[sf.getNum()]].style(); + } + +private: + std::vector elements_; + std::vector indices_; // field num -> index +}; + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STAccount.h b/include/xrpl/protocol/STAccount.h new file mode 100644 index 00000000000..537a336e5db --- /dev/null +++ b/include/xrpl/protocol/STAccount.h @@ -0,0 +1,136 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STACCOUNT_H_INCLUDED +#define RIPPLE_PROTOCOL_STACCOUNT_H_INCLUDED + +#include +#include +#include + +#include + +namespace ripple { + +class STAccount final : public STBase, public CountedObject +{ +private: + // The original implementation of STAccount kept the value in an STBlob. + // But an STAccount is always 160 bits, so we can store it with less + // overhead in a ripple::uint160. However, so the serialized format of the + // STAccount stays unchanged, we serialize and deserialize like an STBlob. + AccountID value_; + bool default_; + +public: + using value_type = AccountID; + + STAccount(); + + STAccount(SField const& n); + STAccount(SField const& n, Buffer&& v); + STAccount(SerialIter& sit, SField const& name); + STAccount(SField const& n, AccountID const& v); + + SerializedTypeID + getSType() const override; + + std::string + getText() const override; + + void + add(Serializer& s) const override; + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + + STAccount& + operator=(AccountID const& value); + + AccountID const& + value() const noexcept; + + void + setValue(AccountID const& v); + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +inline STAccount& +STAccount::operator=(AccountID const& value) +{ + setValue(value); + return *this; +} + +inline AccountID const& +STAccount::value() const noexcept +{ + return value_; +} + +inline void +STAccount::setValue(AccountID const& v) +{ + value_ = v; + default_ = false; +} + +inline bool +operator==(STAccount const& lhs, STAccount const& rhs) +{ + return lhs.value() == rhs.value(); +} + +inline auto +operator<(STAccount const& lhs, STAccount const& rhs) +{ + return lhs.value() < rhs.value(); +} + +inline bool +operator==(STAccount const& lhs, AccountID const& rhs) +{ + return lhs.value() == rhs; +} + +inline auto +operator<(STAccount const& lhs, AccountID const& rhs) +{ + return lhs.value() < rhs; +} + +inline auto +operator<(AccountID const& lhs, STAccount const& rhs) +{ + return lhs < rhs.value(); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STAmount.h b/include/xrpl/protocol/STAmount.h new file mode 100644 index 00000000000..23e4c5e5b59 --- /dev/null +++ b/include/xrpl/protocol/STAmount.h @@ -0,0 +1,734 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STAMOUNT_H_INCLUDED +#define RIPPLE_PROTOCOL_STAMOUNT_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +// Internal form: +// 1: If amount is zero, then value is zero and offset is -100 +// 2: Otherwise: +// legal offset range is -96 to +80 inclusive +// value range is 10^15 to (10^16 - 1) inclusive +// amount = value * [10 ^ offset] + +// Wire form: +// High 8 bits are (offset+142), legal range is, 80 to 22 inclusive +// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive +class STAmount final : public STBase, public CountedObject +{ +public: + using mantissa_type = std::uint64_t; + using exponent_type = int; + using rep = std::pair; + +private: + Asset mAsset; + mantissa_type mValue; + exponent_type mOffset; + bool mIsNegative; + +public: + using value_type = STAmount; + + static const int cMinOffset = -96; + static const int cMaxOffset = 80; + + // Maximum native value supported by the code + static const std::uint64_t cMinValue = 1000000000000000ull; + static const std::uint64_t cMaxValue = 9999999999999999ull; + static const std::uint64_t cMaxNative = 9000000000000000000ull; + + // Max native value on network. + static const std::uint64_t cMaxNativeN = 100000000000000000ull; + static const std::uint64_t cIssuedCurrency = 0x8000000000000000ull; + static const std::uint64_t cPositive = 0x4000000000000000ull; + static const std::uint64_t cMPToken = 0x2000000000000000ull; + static const std::uint64_t cValueMask = ~(cPositive | cMPToken); + + static std::uint64_t const uRateOne; + + //-------------------------------------------------------------------------- + STAmount(SerialIter& sit, SField const& name); + + struct unchecked + { + explicit unchecked() = default; + }; + + // Do not call canonicalize + template + STAmount( + SField const& name, + A const& asset, + mantissa_type mantissa, + exponent_type exponent, + bool negative, + unchecked); + + template + STAmount( + A const& asset, + mantissa_type mantissa, + exponent_type exponent, + bool negative, + unchecked); + + // Call canonicalize + template + STAmount( + SField const& name, + A const& asset, + mantissa_type mantissa = 0, + exponent_type exponent = 0, + bool negative = false); + + STAmount(SField const& name, std::int64_t mantissa); + + STAmount( + SField const& name, + std::uint64_t mantissa = 0, + bool negative = false); + + explicit STAmount(std::uint64_t mantissa = 0, bool negative = false); + + explicit STAmount(SField const& name, STAmount const& amt); + + template + STAmount( + A const& asset, + std::uint64_t mantissa = 0, + int exponent = 0, + bool negative = false) + : mAsset(asset) + , mValue(mantissa) + , mOffset(exponent) + , mIsNegative(negative) + { + canonicalize(); + } + + // VFALCO Is this needed when we have the previous signature? + template + STAmount( + A const& asset, + std::uint32_t mantissa, + int exponent = 0, + bool negative = false); + + template + STAmount(A const& asset, std::int64_t mantissa, int exponent = 0); + + template + STAmount(A const& asset, int mantissa, int exponent = 0); + + // Legacy support for new-style amounts + STAmount(IOUAmount const& amount, Issue const& issue); + STAmount(XRPAmount const& amount); + STAmount(MPTAmount const& amount, MPTIssue const& mptIssue); + operator Number() const; + + //-------------------------------------------------------------------------- + // + // Observers + // + //-------------------------------------------------------------------------- + + int + exponent() const noexcept; + + bool + native() const noexcept; + + template + constexpr bool + holds() const noexcept; + + bool + negative() const noexcept; + + std::uint64_t + mantissa() const noexcept; + + Asset const& + asset() const; + + template + constexpr TIss const& + get() const; + + Issue const& + issue() const; + + // These three are deprecated + Currency const& + getCurrency() const; + + AccountID const& + getIssuer() const; + + int + signum() const noexcept; + + /** Returns a zero value with the same issuer and currency. */ + STAmount + zeroed() const; + + void + setJson(Json::Value&) const; + + STAmount const& + value() const noexcept; + + //-------------------------------------------------------------------------- + // + // Operators + // + //-------------------------------------------------------------------------- + + explicit + operator bool() const noexcept; + + STAmount& + operator+=(STAmount const&); + STAmount& + operator-=(STAmount const&); + + STAmount& operator=(beast::Zero); + + STAmount& + operator=(XRPAmount const& amount); + + //-------------------------------------------------------------------------- + // + // Modification + // + //-------------------------------------------------------------------------- + + void + negate(); + + void + clear(); + + // Zero while copying currency and issuer. + void + clear(Asset const& asset); + + void + setIssuer(AccountID const& uIssuer); + + /** Set the Issue for this amount. */ + void + setIssue(Asset const& asset); + + //-------------------------------------------------------------------------- + // + // STBase + // + //-------------------------------------------------------------------------- + + SerializedTypeID + getSType() const override; + + std::string + getFullText() const override; + + std::string + getText() const override; + + Json::Value getJson(JsonOptions) const override; + + void + add(Serializer& s) const override; + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + + XRPAmount + xrp() const; + IOUAmount + iou() const; + MPTAmount + mpt() const; + +private: + static std::unique_ptr + construct(SerialIter&, SField const& name); + + void + set(std::int64_t v); + void + canonicalize(); + + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + STAmount& + operator=(IOUAmount const& iou); + + friend class detail::STVar; + + friend STAmount + operator+(STAmount const& v1, STAmount const& v2); +}; + +template +STAmount::STAmount( + SField const& name, + A const& asset, + mantissa_type mantissa, + exponent_type exponent, + bool negative, + unchecked) + : STBase(name) + , mAsset(asset) + , mValue(mantissa) + , mOffset(exponent) + , mIsNegative(negative) +{ +} + +template +STAmount::STAmount( + A const& asset, + mantissa_type mantissa, + exponent_type exponent, + bool negative, + unchecked) + : mAsset(asset), mValue(mantissa), mOffset(exponent), mIsNegative(negative) +{ +} + +template +STAmount::STAmount( + SField const& name, + A const& asset, + std::uint64_t mantissa, + int exponent, + bool negative) + : STBase(name) + , mAsset(asset) + , mValue(mantissa) + , mOffset(exponent) + , mIsNegative(negative) +{ + // mValue is uint64, but needs to fit in the range of int64 + XRPL_ASSERT( + mValue <= std::numeric_limits::max(), + "ripple::STAmount::STAmount(SField, A, std::uint64_t, int, bool) : " + "maximum mantissa input"); + canonicalize(); +} + +template +STAmount::STAmount(A const& asset, std::int64_t mantissa, int exponent) + : mAsset(asset), mOffset(exponent) +{ + set(mantissa); + canonicalize(); +} + +template +STAmount::STAmount( + A const& asset, + std::uint32_t mantissa, + int exponent, + bool negative) + : STAmount(asset, safe_cast(mantissa), exponent, negative) +{ +} + +template +STAmount::STAmount(A const& asset, int mantissa, int exponent) + : STAmount(asset, safe_cast(mantissa), exponent) +{ +} + +// Legacy support for new-style amounts +inline STAmount::STAmount(IOUAmount const& amount, Issue const& issue) + : mAsset(issue) + , mOffset(amount.exponent()) + , mIsNegative(amount < beast::zero) +{ + if (mIsNegative) + mValue = unsafe_cast(-amount.mantissa()); + else + mValue = unsafe_cast(amount.mantissa()); + + canonicalize(); +} + +inline STAmount::STAmount(MPTAmount const& amount, MPTIssue const& mptIssue) + : mAsset(mptIssue), mOffset(0), mIsNegative(amount < beast::zero) +{ + if (mIsNegative) + mValue = unsafe_cast(-amount.value()); + else + mValue = unsafe_cast(amount.value()); + + canonicalize(); +} + +//------------------------------------------------------------------------------ +// +// Creation +// +//------------------------------------------------------------------------------ + +// VFALCO TODO The parameter type should be Quality not uint64_t +STAmount +amountFromQuality(std::uint64_t rate); + +STAmount +amountFromString(Asset const& issue, std::string const& amount); + +STAmount +amountFromJson(SField const& name, Json::Value const& v); + +bool +amountFromJsonNoThrow(STAmount& result, Json::Value const& jvSource); + +// IOUAmount and XRPAmount define toSTAmount, defining this +// trivial conversion here makes writing generic code easier +inline STAmount const& +toSTAmount(STAmount const& a) +{ + return a; +} + +//------------------------------------------------------------------------------ +// +// Observers +// +//------------------------------------------------------------------------------ + +inline int +STAmount::exponent() const noexcept +{ + return mOffset; +} + +inline bool +STAmount::native() const noexcept +{ + return mAsset.native(); +} + +template +constexpr bool +STAmount::holds() const noexcept +{ + return mAsset.holds(); +} + +inline bool +STAmount::negative() const noexcept +{ + return mIsNegative; +} + +inline std::uint64_t +STAmount::mantissa() const noexcept +{ + return mValue; +} + +inline Asset const& +STAmount::asset() const +{ + return mAsset; +} + +template +constexpr TIss const& +STAmount::get() const +{ + return mAsset.get(); +} + +inline Issue const& +STAmount::issue() const +{ + return get(); +} + +inline Currency const& +STAmount::getCurrency() const +{ + return mAsset.get().currency; +} + +inline AccountID const& +STAmount::getIssuer() const +{ + return mAsset.getIssuer(); +} + +inline int +STAmount::signum() const noexcept +{ + return mValue ? (mIsNegative ? -1 : 1) : 0; +} + +inline STAmount +STAmount::zeroed() const +{ + return STAmount(mAsset); +} + +inline STAmount::operator bool() const noexcept +{ + return *this != beast::zero; +} + +inline STAmount::operator Number() const +{ + if (native()) + return xrp(); + if (mAsset.holds()) + return mpt(); + return iou(); +} + +inline STAmount& +STAmount::operator=(beast::Zero) +{ + clear(); + return *this; +} + +inline STAmount& +STAmount::operator=(XRPAmount const& amount) +{ + *this = STAmount(amount); + return *this; +} + +inline void +STAmount::negate() +{ + if (*this != beast::zero) + mIsNegative = !mIsNegative; +} + +inline void +STAmount::clear() +{ + // The -100 is used to allow 0 to sort less than a small positive values + // which have a negative exponent. + mOffset = native() ? 0 : -100; + mValue = 0; + mIsNegative = false; +} + +inline void +STAmount::clear(Asset const& asset) +{ + setIssue(asset); + clear(); +} + +inline void +STAmount::setIssuer(AccountID const& uIssuer) +{ + mAsset.get().account = uIssuer; +} + +inline STAmount const& +STAmount::value() const noexcept +{ + return *this; +} + +inline bool +isLegalNet(STAmount const& value) +{ + return !value.native() || (value.mantissa() <= STAmount::cMaxNativeN); +} + +//------------------------------------------------------------------------------ +// +// Operators +// +//------------------------------------------------------------------------------ + +bool +operator==(STAmount const& lhs, STAmount const& rhs); +bool +operator<(STAmount const& lhs, STAmount const& rhs); + +inline bool +operator!=(STAmount const& lhs, STAmount const& rhs) +{ + return !(lhs == rhs); +} + +inline bool +operator>(STAmount const& lhs, STAmount const& rhs) +{ + return rhs < lhs; +} + +inline bool +operator<=(STAmount const& lhs, STAmount const& rhs) +{ + return !(rhs < lhs); +} + +inline bool +operator>=(STAmount const& lhs, STAmount const& rhs) +{ + return !(lhs < rhs); +} + +STAmount +operator-(STAmount const& value); + +//------------------------------------------------------------------------------ +// +// Arithmetic +// +//------------------------------------------------------------------------------ + +STAmount +operator+(STAmount const& v1, STAmount const& v2); +STAmount +operator-(STAmount const& v1, STAmount const& v2); + +STAmount +divide(STAmount const& v1, STAmount const& v2, Asset const& asset); + +STAmount +multiply(STAmount const& v1, STAmount const& v2, Asset const& asset); + +// multiply rounding result in specified direction +STAmount +mulRound( + STAmount const& v1, + STAmount const& v2, + Asset const& asset, + bool roundUp); + +// multiply following the rounding directions more precisely. +STAmount +mulRoundStrict( + STAmount const& v1, + STAmount const& v2, + Asset const& asset, + bool roundUp); + +// divide rounding result in specified direction +STAmount +divRound( + STAmount const& v1, + STAmount const& v2, + Asset const& asset, + bool roundUp); + +// divide following the rounding directions more precisely. +STAmount +divRoundStrict( + STAmount const& v1, + STAmount const& v2, + Asset const& asset, + bool roundUp); + +// Someone is offering X for Y, what is the rate? +// Rate: smaller is better, the taker wants the most out: in/out +// VFALCO TODO Return a Quality object +std::uint64_t +getRate(STAmount const& offerOut, STAmount const& offerIn); + +//------------------------------------------------------------------------------ + +inline bool +isXRP(STAmount const& amount) +{ + return amount.native(); +} + +// Since `canonicalize` does not have access to a ledger, this is needed to put +// the low-level routine stAmountCanonicalize on an amendment switch. Only +// transactions need to use this switchover. Outside of a transaction it's safe +// to unconditionally use the new behavior. + +bool +getSTAmountCanonicalizeSwitchover(); + +void +setSTAmountCanonicalizeSwitchover(bool v); + +/** RAII class to set and restore the STAmount canonicalize switchover. + */ + +class STAmountSO +{ +public: + explicit STAmountSO(bool v) : saved_(getSTAmountCanonicalizeSwitchover()) + { + setSTAmountCanonicalizeSwitchover(v); + } + + ~STAmountSO() + { + setSTAmountCanonicalizeSwitchover(saved_); + } + +private: + bool saved_; +}; + +} // namespace ripple + +//------------------------------------------------------------------------------ +namespace Json { +template <> +inline ripple::STAmount +getOrThrow(Json::Value const& v, ripple::SField const& field) +{ + using namespace ripple; + Json::StaticString const& key = field.getJsonName(); + if (!v.isMember(key)) + Throw(key); + Json::Value const& inner = v[key]; + return amountFromJson(field, inner); +} +} // namespace Json +#endif diff --git a/include/xrpl/protocol/STArray.h b/include/xrpl/protocol/STArray.h new file mode 100644 index 00000000000..7fa2ecad834 --- /dev/null +++ b/include/xrpl/protocol/STArray.h @@ -0,0 +1,315 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STARRAY_H_INCLUDED +#define RIPPLE_PROTOCOL_STARRAY_H_INCLUDED + +#include +#include + +namespace ripple { + +class STArray final : public STBase, public CountedObject +{ +private: + using list_type = std::vector; + + list_type v_; + +public: + using value_type = STObject; + using size_type = list_type::size_type; + using iterator = list_type::iterator; + using const_iterator = list_type::const_iterator; + + STArray() = default; + STArray(STArray const&) = default; + + template < + class Iter, + class = std::enable_if_t::reference, + STObject>>> + explicit STArray(Iter first, Iter last); + + template < + class Iter, + class = std::enable_if_t::reference, + STObject>>> + STArray(SField const& f, Iter first, Iter last); + + STArray& + operator=(STArray const&) = default; + STArray(STArray&&); + STArray& + operator=(STArray&&); + + STArray(SField const& f, std::size_t n); + STArray(SerialIter& sit, SField const& f, int depth = 0); + explicit STArray(int n); + explicit STArray(SField const& f); + + STObject& + operator[](std::size_t j); + + STObject const& + operator[](std::size_t j) const; + + STObject& + back(); + + STObject const& + back() const; + + template + void + emplace_back(Args&&... args); + + void + push_back(STObject const& object); + + void + push_back(STObject&& object); + + iterator + begin(); + + iterator + end(); + + const_iterator + begin() const; + + const_iterator + end() const; + + size_type + size() const; + + bool + empty() const; + + void + clear(); + + void + reserve(std::size_t n); + + void + swap(STArray& a) noexcept; + + std::string + getFullText() const override; + + std::string + getText() const override; + + Json::Value + getJson(JsonOptions index) const override; + + void + add(Serializer& s) const override; + + void + sort(bool (*compare)(const STObject& o1, const STObject& o2)); + + bool + operator==(const STArray& s) const; + + bool + operator!=(const STArray& s) const; + + iterator + erase(iterator pos); + + iterator + erase(const_iterator pos); + + iterator + erase(iterator first, iterator last); + + iterator + erase(const_iterator first, const_iterator last); + + SerializedTypeID + getSType() const override; + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +template +STArray::STArray(Iter first, Iter last) : v_(first, last) +{ +} + +template +STArray::STArray(SField const& f, Iter first, Iter last) + : STBase(f), v_(first, last) +{ +} + +inline STObject& +STArray::operator[](std::size_t j) +{ + return v_[j]; +} + +inline STObject const& +STArray::operator[](std::size_t j) const +{ + return v_[j]; +} + +inline STObject& +STArray::back() +{ + return v_.back(); +} + +inline STObject const& +STArray::back() const +{ + return v_.back(); +} + +template +inline void +STArray::emplace_back(Args&&... args) +{ + v_.emplace_back(std::forward(args)...); +} + +inline void +STArray::push_back(STObject const& object) +{ + v_.push_back(object); +} + +inline void +STArray::push_back(STObject&& object) +{ + v_.push_back(std::move(object)); +} + +inline STArray::iterator +STArray::begin() +{ + return v_.begin(); +} + +inline STArray::iterator +STArray::end() +{ + return v_.end(); +} + +inline STArray::const_iterator +STArray::begin() const +{ + return v_.begin(); +} + +inline STArray::const_iterator +STArray::end() const +{ + return v_.end(); +} + +inline STArray::size_type +STArray::size() const +{ + return v_.size(); +} + +inline bool +STArray::empty() const +{ + return v_.empty(); +} + +inline void +STArray::clear() +{ + v_.clear(); +} + +inline void +STArray::reserve(std::size_t n) +{ + v_.reserve(n); +} + +inline void +STArray::swap(STArray& a) noexcept +{ + v_.swap(a.v_); +} + +inline bool +STArray::operator==(const STArray& s) const +{ + return v_ == s.v_; +} + +inline bool +STArray::operator!=(const STArray& s) const +{ + return v_ != s.v_; +} + +inline STArray::iterator +STArray::erase(iterator pos) +{ + return v_.erase(pos); +} + +inline STArray::iterator +STArray::erase(const_iterator pos) +{ + return v_.erase(pos); +} + +inline STArray::iterator +STArray::erase(iterator first, iterator last) +{ + return v_.erase(first, last); +} + +inline STArray::iterator +STArray::erase(const_iterator first, const_iterator last) +{ + return v_.erase(first, last); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STBase.h b/include/xrpl/protocol/STBase.h new file mode 100644 index 00000000000..e0f28e03dea --- /dev/null +++ b/include/xrpl/protocol/STBase.h @@ -0,0 +1,234 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STBASE_H_INCLUDED +#define RIPPLE_PROTOCOL_STBASE_H_INCLUDED + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace ripple { + +/// Note, should be treated as flags that can be | and & +struct JsonOptions +{ + using underlying_t = unsigned int; + underlying_t value; + + enum values : underlying_t { + // clang-format off + none = 0b0000'0000, + include_date = 0b0000'0001, + disable_API_prior_V2 = 0b0000'0010, + + // IMPORTANT `_all` must be union of all of the above; see also operator~ + _all = 0b0000'0011 + // clang-format on + }; + + constexpr JsonOptions(underlying_t v) noexcept : value(v) + { + } + + [[nodiscard]] constexpr explicit + operator underlying_t() const noexcept + { + return value; + } + [[nodiscard]] constexpr explicit + operator bool() const noexcept + { + return value != 0u; + } + [[nodiscard]] constexpr auto friend + operator==(JsonOptions lh, JsonOptions rh) noexcept -> bool = default; + [[nodiscard]] constexpr auto friend + operator!=(JsonOptions lh, JsonOptions rh) noexcept -> bool = default; + + /// Returns JsonOptions union of lh and rh + [[nodiscard]] constexpr JsonOptions friend + operator|(JsonOptions lh, JsonOptions rh) noexcept + { + return {lh.value | rh.value}; + } + + /// Returns JsonOptions intersection of lh and rh + [[nodiscard]] constexpr JsonOptions friend + operator&(JsonOptions lh, JsonOptions rh) noexcept + { + return {lh.value & rh.value}; + } + + /// Returns JsonOptions binary negation, can be used with & (above) for set + /// difference e.g. `(options & ~JsonOptions::include_date)` + [[nodiscard]] constexpr JsonOptions friend + operator~(JsonOptions v) noexcept + { + return {~v.value & static_cast(_all)}; + } +}; + +namespace detail { +class STVar; +} + +// VFALCO TODO fix this restriction on copy assignment. +// +// CAUTION: Do not create a vector (or similar container) of any object derived +// from STBase. Use Boost ptr_* containers. The copy assignment operator +// of STBase has semantics that will cause contained types to change +// their names when an object is deleted because copy assignment is used to +// "slide down" the remaining types and this will not copy the field +// name. Changing the copy assignment operator to copy the field name breaks the +// use of copy assignment just to copy values, which is used in the transaction +// engine code. + +//------------------------------------------------------------------------------ + +/** A type which can be exported to a well known binary format. + + A STBase: + - Always a field + - Can always go inside an eligible enclosing STBase + (such as STArray) + - Has a field name + + Like JSON, a SerializedObject is a basket which has rules + on what it can hold. + + @note "ST" stands for "Serialized Type." +*/ +class STBase +{ + SField const* fName; + +public: + virtual ~STBase() = default; + STBase(); + STBase(const STBase&) = default; + STBase& + operator=(const STBase& t); + + explicit STBase(SField const& n); + + bool + operator==(const STBase& t) const; + bool + operator!=(const STBase& t) const; + + template + D& + downcast(); + + template + D const& + downcast() const; + + virtual SerializedTypeID + getSType() const; + + virtual std::string + getFullText() const; + + virtual std::string + getText() const; + + virtual Json::Value getJson(JsonOptions /*options*/) const; + + virtual void + add(Serializer& s) const; + + virtual bool + isEquivalent(STBase const& t) const; + + virtual bool + isDefault() const; + + /** A STBase is a field. + This sets the name. + */ + void + setFName(SField const& n); + + SField const& + getFName() const; + + void + addFieldID(Serializer& s) const; + +protected: + template + static STBase* + emplace(std::size_t n, void* buf, T&& val); + +private: + virtual STBase* + copy(std::size_t n, void* buf) const; + virtual STBase* + move(std::size_t n, void* buf); + + friend class detail::STVar; +}; + +//------------------------------------------------------------------------------ + +std::ostream& +operator<<(std::ostream& out, const STBase& t); + +template +D& +STBase::downcast() +{ + D* ptr = dynamic_cast(this); + if (ptr == nullptr) + Throw(); + return *ptr; +} + +template +D const& +STBase::downcast() const +{ + D const* ptr = dynamic_cast(this); + if (ptr == nullptr) + Throw(); + return *ptr; +} + +template +STBase* +STBase::emplace(std::size_t n, void* buf, T&& val) +{ + using U = std::decay_t; + if (sizeof(U) > n) + return new U(std::forward(val)); + return new (buf) U(std::forward(val)); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STBitString.h b/include/xrpl/protocol/STBitString.h new file mode 100644 index 00000000000..bf4ce84a3f3 --- /dev/null +++ b/include/xrpl/protocol/STBitString.h @@ -0,0 +1,211 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STBITSTRING_H_INCLUDED +#define RIPPLE_PROTOCOL_STBITSTRING_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +// The template parameter could be an unsigned type, however there's a bug in +// gdb (last checked in gdb 12.1) that prevents gdb from finding the RTTI +// information of a template parameterized by an unsigned type. This RTTI +// information is needed to write gdb pretty printers. +template +class STBitString final : public STBase, public CountedObject> +{ + static_assert(Bits > 0, "Number of bits must be positive"); + +public: + using value_type = base_uint; + +private: + value_type value_; + +public: + STBitString() = default; + + STBitString(SField const& n); + STBitString(const value_type& v); + STBitString(SField const& n, const value_type& v); + STBitString(SerialIter& sit, SField const& name); + + SerializedTypeID + getSType() const override; + + std::string + getText() const override; + + bool + isEquivalent(const STBase& t) const override; + + void + add(Serializer& s) const override; + + bool + isDefault() const override; + + template + void + setValue(base_uint const& v); + + value_type const& + value() const; + + operator value_type() const; + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +using STUInt128 = STBitString<128>; +using STUInt160 = STBitString<160>; +using STUInt192 = STBitString<192>; +using STUInt256 = STBitString<256>; + +template +inline STBitString::STBitString(SField const& n) : STBase(n) +{ +} + +template +inline STBitString::STBitString(const value_type& v) : value_(v) +{ +} + +template +inline STBitString::STBitString(SField const& n, const value_type& v) + : STBase(n), value_(v) +{ +} + +template +inline STBitString::STBitString(SerialIter& sit, SField const& name) + : STBitString(name, sit.getBitString()) +{ +} + +template +STBase* +STBitString::copy(std::size_t n, void* buf) const +{ + return emplace(n, buf, *this); +} + +template +STBase* +STBitString::move(std::size_t n, void* buf) +{ + return emplace(n, buf, std::move(*this)); +} + +template <> +inline SerializedTypeID +STUInt128::getSType() const +{ + return STI_UINT128; +} + +template <> +inline SerializedTypeID +STUInt160::getSType() const +{ + return STI_UINT160; +} + +template <> +inline SerializedTypeID +STUInt192::getSType() const +{ + return STI_UINT192; +} + +template <> +inline SerializedTypeID +STUInt256::getSType() const +{ + return STI_UINT256; +} + +template +std::string +STBitString::getText() const +{ + return to_string(value_); +} + +template +bool +STBitString::isEquivalent(const STBase& t) const +{ + const STBitString* v = dynamic_cast(&t); + return v && (value_ == v->value_); +} + +template +void +STBitString::add(Serializer& s) const +{ + XRPL_ASSERT( + getFName().isBinary(), "ripple::STBitString::add : field is binary"); + XRPL_ASSERT( + getFName().fieldType == getSType(), + "ripple::STBitString::add : field type match"); + s.addBitString(value_); +} + +template +template +void +STBitString::setValue(base_uint const& v) +{ + value_ = v; +} + +template +typename STBitString::value_type const& +STBitString::value() const +{ + return value_; +} + +template +STBitString::operator value_type() const +{ + return value_; +} + +template +bool +STBitString::isDefault() const +{ + return value_ == beast::zero; +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STBlob.h b/include/xrpl/protocol/STBlob.h new file mode 100644 index 00000000000..cfe4ab5af58 --- /dev/null +++ b/include/xrpl/protocol/STBlob.h @@ -0,0 +1,151 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STBLOB_H_INCLUDED +#define RIPPLE_PROTOCOL_STBLOB_H_INCLUDED + +#include +#include +#include +#include +#include + +#include +#include + +namespace ripple { + +// variable length byte string +class STBlob : public STBase, public CountedObject +{ + Buffer value_; + +public: + using value_type = Slice; + + STBlob() = default; + STBlob(STBlob const& rhs); + + STBlob(SField const& f, void const* data, std::size_t size); + STBlob(SField const& f, Buffer&& b); + STBlob(SField const& n); + STBlob(SerialIter&, SField const& name = sfGeneric); + + std::size_t + size() const; + + std::uint8_t const* + data() const; + + SerializedTypeID + getSType() const override; + + std::string + getText() const override; + + void + add(Serializer& s) const override; + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + + STBlob& + operator=(Slice const& slice); + + value_type + value() const noexcept; + + STBlob& + operator=(Buffer&& buffer); + + void + setValue(Buffer&& b); + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +inline STBlob::STBlob(STBlob const& rhs) + : STBase(rhs), CountedObject(rhs), value_(rhs.data(), rhs.size()) +{ +} + +inline STBlob::STBlob(SField const& f, void const* data, std::size_t size) + : STBase(f), value_(data, size) +{ +} + +inline STBlob::STBlob(SField const& f, Buffer&& b) + : STBase(f), value_(std::move(b)) +{ +} + +inline STBlob::STBlob(SField const& n) : STBase(n) +{ +} + +inline std::size_t +STBlob::size() const +{ + return value_.size(); +} + +inline std::uint8_t const* +STBlob::data() const +{ + return reinterpret_cast(value_.data()); +} + +inline STBlob& +STBlob::operator=(Slice const& slice) +{ + value_ = Buffer(slice.data(), slice.size()); + return *this; +} + +inline STBlob::value_type +STBlob::value() const noexcept +{ + return value_; +} + +inline STBlob& +STBlob::operator=(Buffer&& buffer) +{ + value_ = std::move(buffer); + return *this; +} + +inline void +STBlob::setValue(Buffer&& b) +{ + value_ = std::move(b); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STCurrency.h b/include/xrpl/protocol/STCurrency.h new file mode 100644 index 00000000000..3383137fb3a --- /dev/null +++ b/include/xrpl/protocol/STCurrency.h @@ -0,0 +1,138 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STCURRENCY_H_INCLUDED +#define RIPPLE_PROTOCOL_STCURRENCY_H_INCLUDED + +#include +#include +#include +#include +#include + +namespace ripple { + +class STCurrency final : public STBase +{ +private: + Currency currency_{}; + +public: + using value_type = Currency; + + STCurrency() = default; + + explicit STCurrency(SerialIter& sit, SField const& name); + + explicit STCurrency(SField const& name, Currency const& currency); + + explicit STCurrency(SField const& name); + + Currency const& + currency() const; + + Currency const& + value() const noexcept; + + void + setCurrency(Currency const& currency); + + SerializedTypeID + getSType() const override; + + std::string + getText() const override; + + Json::Value getJson(JsonOptions) const override; + + void + add(Serializer& s) const override; + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + +private: + static std::unique_ptr + construct(SerialIter&, SField const& name); + + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +STCurrency +currencyFromJson(SField const& name, Json::Value const& v); + +inline Currency const& +STCurrency::currency() const +{ + return currency_; +} + +inline Currency const& +STCurrency::value() const noexcept +{ + return currency_; +} + +inline void +STCurrency::setCurrency(Currency const& currency) +{ + currency_ = currency; +} + +inline bool +operator==(STCurrency const& lhs, STCurrency const& rhs) +{ + return lhs.currency() == rhs.currency(); +} + +inline bool +operator!=(STCurrency const& lhs, STCurrency const& rhs) +{ + return !operator==(lhs, rhs); +} + +inline bool +operator<(STCurrency const& lhs, STCurrency const& rhs) +{ + return lhs.currency() < rhs.currency(); +} + +inline bool +operator==(STCurrency const& lhs, Currency const& rhs) +{ + return lhs.currency() == rhs; +} + +inline bool +operator<(STCurrency const& lhs, Currency const& rhs) +{ + return lhs.currency() < rhs; +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STExchange.h b/include/xrpl/protocol/STExchange.h new file mode 100644 index 00000000000..dd7c4834a6b --- /dev/null +++ b/include/xrpl/protocol/STExchange.h @@ -0,0 +1,179 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STEXCHANGE_H_INCLUDED +#define RIPPLE_PROTOCOL_STEXCHANGE_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace ripple { + +/** Convert between serialized type U and C++ type T. */ +template +struct STExchange; + +template +struct STExchange, T> +{ + explicit STExchange() = default; + + using value_type = U; + + static void + get(std::optional& t, STInteger const& u) + { + t = u.value(); + } + + static std::unique_ptr> + set(SField const& f, T const& t) + { + return std::make_unique>(f, t); + } +}; + +template <> +struct STExchange +{ + explicit STExchange() = default; + + using value_type = Slice; + + static void + get(std::optional& t, STBlob const& u) + { + t.emplace(u.data(), u.size()); + } + + static std::unique_ptr + set(TypedField const& f, Slice const& t) + { + return std::make_unique(f, t.data(), t.size()); + } +}; + +template <> +struct STExchange +{ + explicit STExchange() = default; + + using value_type = Buffer; + + static void + get(std::optional& t, STBlob const& u) + { + t.emplace(u.data(), u.size()); + } + + static std::unique_ptr + set(TypedField const& f, Buffer const& t) + { + return std::make_unique(f, t.data(), t.size()); + } + + static std::unique_ptr + set(TypedField const& f, Buffer&& t) + { + return std::make_unique(f, std::move(t)); + } +}; + +//------------------------------------------------------------------------------ + +/** Return the value of a field in an STObject as a given type. */ +/** @{ */ +template +std::optional +get(STObject const& st, TypedField const& f) +{ + std::optional t; + STBase const* const b = st.peekAtPField(f); + if (!b) + return t; + auto const id = b->getSType(); + if (id == STI_NOTPRESENT) + return t; + auto const u = dynamic_cast(b); + // This should never happen + if (!u) + Throw("Wrong field type"); + STExchange::get(t, *u); + return t; +} + +template +std::optional::value_type> +get(STObject const& st, TypedField const& f) +{ + return get(st, f); +} +/** @} */ + +/** Set a field value in an STObject. */ +template +void +set(STObject& st, TypedField const& f, T&& t) +{ + st.set(STExchange::type>::set( + f, std::forward(t))); +} + +/** Set a blob field using an init function. */ +template +void +set(STObject& st, TypedField const& f, std::size_t size, Init&& init) +{ + st.set(std::make_unique(f, size, init)); +} + +/** Set a blob field from data. */ +template +void +set(STObject& st, + TypedField const& f, + void const* data, + std::size_t size) +{ + st.set(std::make_unique(f, data, size)); +} + +/** Remove a field in an STObject. */ +template +void +erase(STObject& st, TypedField const& f) +{ + st.makeFieldAbsent(f); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STInteger.h b/include/xrpl/protocol/STInteger.h new file mode 100644 index 00000000000..68e25be1c9f --- /dev/null +++ b/include/xrpl/protocol/STInteger.h @@ -0,0 +1,166 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STINTEGER_H_INCLUDED +#define RIPPLE_PROTOCOL_STINTEGER_H_INCLUDED + +#include +#include + +namespace ripple { + +template +class STInteger : public STBase, public CountedObject> +{ +public: + using value_type = Integer; + +private: + Integer value_; + +public: + explicit STInteger(Integer v); + STInteger(SField const& n, Integer v = 0); + STInteger(SerialIter& sit, SField const& name); + + SerializedTypeID + getSType() const override; + + Json::Value getJson(JsonOptions) const override; + + std::string + getText() const override; + + void + add(Serializer& s) const override; + + bool + isDefault() const override; + + bool + isEquivalent(const STBase& t) const override; + + STInteger& + operator=(value_type const& v); + + value_type + value() const noexcept; + + void + setValue(Integer v); + + operator Integer() const; + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class ripple::detail::STVar; +}; + +using STUInt8 = STInteger; +using STUInt16 = STInteger; +using STUInt32 = STInteger; +using STUInt64 = STInteger; + +template +inline STInteger::STInteger(Integer v) : value_(v) +{ +} + +template +inline STInteger::STInteger(SField const& n, Integer v) + : STBase(n), value_(v) +{ +} + +template +inline STBase* +STInteger::copy(std::size_t n, void* buf) const +{ + return emplace(n, buf, *this); +} + +template +inline STBase* +STInteger::move(std::size_t n, void* buf) +{ + return emplace(n, buf, std::move(*this)); +} + +template +inline void +STInteger::add(Serializer& s) const +{ + XRPL_ASSERT( + getFName().isBinary(), "ripple::STInteger::add : field is binary"); + XRPL_ASSERT( + getFName().fieldType == getSType(), + "ripple::STInteger::add : field type match"); + s.addInteger(value_); +} + +template +inline bool +STInteger::isDefault() const +{ + return value_ == 0; +} + +template +inline bool +STInteger::isEquivalent(const STBase& t) const +{ + const STInteger* v = dynamic_cast(&t); + return v && (value_ == v->value_); +} + +template +inline STInteger& +STInteger::operator=(value_type const& v) +{ + value_ = v; + return *this; +} + +template +inline typename STInteger::value_type +STInteger::value() const noexcept +{ + return value_; +} + +template +inline void +STInteger::setValue(Integer v) +{ + value_ = v; +} + +template +inline STInteger::operator Integer() const +{ + return value_; +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STIssue.h b/include/xrpl/protocol/STIssue.h new file mode 100644 index 00000000000..08812c15aec --- /dev/null +++ b/include/xrpl/protocol/STIssue.h @@ -0,0 +1,170 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STISSUE_H_INCLUDED +#define RIPPLE_PROTOCOL_STISSUE_H_INCLUDED + +#include +#include +#include +#include +#include + +namespace ripple { + +class STIssue final : public STBase, CountedObject +{ +private: + Asset asset_{xrpIssue()}; + +public: + using value_type = Asset; + + STIssue() = default; + + explicit STIssue(SerialIter& sit, SField const& name); + + template + explicit STIssue(SField const& name, A const& issue); + + explicit STIssue(SField const& name); + + template + TIss const& + get() const; + + template + bool + holds() const; + + value_type const& + value() const noexcept; + + void + setIssue(Asset const& issue); + + SerializedTypeID + getSType() const override; + + std::string + getText() const override; + + Json::Value getJson(JsonOptions) const override; + + void + add(Serializer& s) const override; + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + + friend constexpr bool + operator==(STIssue const& lhs, STIssue const& rhs); + + friend constexpr std::weak_ordering + operator<=>(STIssue const& lhs, STIssue const& rhs); + + friend constexpr bool + operator==(STIssue const& lhs, Asset const& rhs); + + friend constexpr std::weak_ordering + operator<=>(STIssue const& lhs, Asset const& rhs); + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +template +STIssue::STIssue(SField const& name, A const& asset) + : STBase{name}, asset_{asset} +{ + if (holds() && !isConsistent(asset_.get())) + Throw( + "Invalid asset: currency and account native mismatch"); +} + +STIssue +issueFromJson(SField const& name, Json::Value const& v); + +template +bool +STIssue::holds() const +{ + return asset_.holds(); +} + +template +TIss const& +STIssue::get() const +{ + if (!holds(asset_)) + Throw("Asset doesn't hold the requested issue"); + return std::get(asset_); +} + +inline STIssue::value_type const& +STIssue::value() const noexcept +{ + return asset_; +} + +inline void +STIssue::setIssue(Asset const& asset) +{ + if (holds() && !isConsistent(asset_.get())) + Throw( + "Invalid asset: currency and account native mismatch"); + + asset_ = asset; +} + +constexpr bool +operator==(STIssue const& lhs, STIssue const& rhs) +{ + return lhs.asset_ == rhs.asset_; +} + +constexpr std::weak_ordering +operator<=>(STIssue const& lhs, STIssue const& rhs) +{ + return lhs.asset_ <=> rhs.asset_; +} + +constexpr bool +operator==(STIssue const& lhs, Asset const& rhs) +{ + return lhs.asset_ == rhs; +} + +constexpr std::weak_ordering +operator<=>(STIssue const& lhs, Asset const& rhs) +{ + return lhs.asset_ <=> rhs; +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STLedgerEntry.h b/include/xrpl/protocol/STLedgerEntry.h new file mode 100644 index 00000000000..96b37af0b9a --- /dev/null +++ b/include/xrpl/protocol/STLedgerEntry.h @@ -0,0 +1,127 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED +#define RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED + +#include +#include + +namespace ripple { + +class Rules; +class Invariants_test; + +class STLedgerEntry final : public STObject, public CountedObject +{ + uint256 key_; + LedgerEntryType type_; + +public: + using pointer = std::shared_ptr; + using ref = const std::shared_ptr&; + + /** Create an empty object with the given key and type. */ + explicit STLedgerEntry(Keylet const& k); + STLedgerEntry(LedgerEntryType type, uint256 const& key); + STLedgerEntry(SerialIter& sit, uint256 const& index); + STLedgerEntry(SerialIter&& sit, uint256 const& index); + STLedgerEntry(STObject const& object, uint256 const& index); + + SerializedTypeID + getSType() const override; + + std::string + getFullText() const override; + + std::string + getText() const override; + + Json::Value + getJson(JsonOptions options) const override; + + /** Returns the 'key' (or 'index') of this item. + The key identifies this entry's position in + the SHAMap associative container. + */ + uint256 const& + key() const; + + LedgerEntryType + getType() const; + + // is this a ledger entry that can be threaded + bool + isThreadedType(Rules const& rules) const; + + bool + thread( + uint256 const& txID, + std::uint32_t ledgerSeq, + uint256& prevTxID, + std::uint32_t& prevLedgerID); + +private: + /* Make STObject comply with the template for this SLE type + Can throw + */ + void + setSLEType(); + + friend Invariants_test; // this test wants access to the private type_ + + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +using SLE = STLedgerEntry; + +inline STLedgerEntry::STLedgerEntry(LedgerEntryType type, uint256 const& key) + : STLedgerEntry(Keylet(type, key)) +{ +} + +inline STLedgerEntry::STLedgerEntry(SerialIter&& sit, uint256 const& index) + : STLedgerEntry(sit, index) +{ +} + +/** Returns the 'key' (or 'index') of this item. + The key identifies this entry's position in + the SHAMap associative container. +*/ +inline uint256 const& +STLedgerEntry::key() const +{ + return key_; +} + +inline LedgerEntryType +STLedgerEntry::getType() const +{ + return type_; +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STNumber.h b/include/xrpl/protocol/STNumber.h new file mode 100644 index 00000000000..c0fce572c8c --- /dev/null +++ b/include/xrpl/protocol/STNumber.h @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef XRPL_PROTOCOL_STNUMBER_H_INCLUDED +#define XRPL_PROTOCOL_STNUMBER_H_INCLUDED + +#include +#include +#include + +#include + +namespace ripple { + +/** + * A serializable number. + * + * This type is-a `Number`, and can be used everywhere that is accepted. + * This type simply integrates `Number` with the serialization framework, + * letting it be used for fields in ledger entries and transactions. + * It is effectively an `STAmount` sans `Asset`: + * it can represent a value of any token type (XRP, IOU, or MPT) + * without paying the storage cost of duplicating asset information + * that may be deduced from the context. + */ +class STNumber : public STBase, public CountedObject +{ +private: + Number value_; + +public: + using value_type = Number; + + STNumber() = default; + explicit STNumber(SField const& field, Number const& value = Number()); + STNumber(SerialIter& sit, SField const& field); + + SerializedTypeID + getSType() const override; + std::string + getText() const override; + void + add(Serializer& s) const override; + + Number const& + value() const; + void + setValue(Number const& v); + + bool + isEquivalent(STBase const& t) const override; + bool + isDefault() const override; + + operator Number() const + { + return value_; + } + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; +}; + +std::ostream& +operator<<(std::ostream& out, STNumber const& rhs); + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h new file mode 100644 index 00000000000..b89a415ebe3 --- /dev/null +++ b/include/xrpl/protocol/STObject.h @@ -0,0 +1,1241 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STOBJECT_H_INCLUDED +#define RIPPLE_PROTOCOL_STOBJECT_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace ripple { + +class STArray; + +inline void +throwFieldNotFound(SField const& field) +{ + Throw("Field not found: " + field.getName()); +} + +class STObject : public STBase, public CountedObject +{ + // Proxy value for a STBase derived class + template + class Proxy; + template + class ValueProxy; + template + class OptionalProxy; + + struct Transform + { + explicit Transform() = default; + + using argument_type = detail::STVar; + using result_type = STBase; + + STBase const& + operator()(detail::STVar const& e) const; + }; + + using list_type = std::vector; + + list_type v_; + SOTemplate const* mType; + +public: + using iterator = boost:: + transform_iterator; + + virtual ~STObject() = default; + STObject(STObject const&) = default; + + template + STObject(SOTemplate const& type, SField const& name, F&& f) + : STObject(type, name) + { + f(*this); + } + + STObject& + operator=(STObject const&) = default; + STObject(STObject&&); + STObject& + operator=(STObject&& other); + + STObject(const SOTemplate& type, SField const& name); + STObject(const SOTemplate& type, SerialIter& sit, SField const& name); + STObject(SerialIter& sit, SField const& name, int depth = 0); + STObject(SerialIter&& sit, SField const& name); + explicit STObject(SField const& name); + + static STObject + makeInnerObject(SField const& name); + + iterator + begin() const; + + iterator + end() const; + + bool + empty() const; + + void + reserve(std::size_t n); + + void + applyTemplate(const SOTemplate& type); + + void + applyTemplateFromSField(SField const&); + + bool + isFree() const; + + void + set(const SOTemplate&); + + bool + set(SerialIter& u, int depth = 0); + + SerializedTypeID + getSType() const override; + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + + void + add(Serializer& s) const override; + + std::string + getFullText() const override; + + std::string + getText() const override; + + // TODO(tom): options should be an enum. + Json::Value + getJson(JsonOptions options) const override; + + void + addWithoutSigningFields(Serializer& s) const; + + Serializer + getSerializer() const; + + template + std::size_t + emplace_back(Args&&... args); + + int + getCount() const; + + bool setFlag(std::uint32_t); + bool clearFlag(std::uint32_t); + bool isFlag(std::uint32_t) const; + + std::uint32_t + getFlags() const; + + uint256 + getHash(HashPrefix prefix) const; + + uint256 + getSigningHash(HashPrefix prefix) const; + + const STBase& + peekAtIndex(int offset) const; + + STBase& + getIndex(int offset); + + const STBase* + peekAtPIndex(int offset) const; + + STBase* + getPIndex(int offset); + + int + getFieldIndex(SField const& field) const; + + SField const& + getFieldSType(int index) const; + + const STBase& + peekAtField(SField const& field) const; + + STBase& + getField(SField const& field); + + const STBase* + peekAtPField(SField const& field) const; + + STBase* + getPField(SField const& field, bool createOkay = false); + + // these throw if the field type doesn't match, or return default values + // if the field is optional but not present + unsigned char + getFieldU8(SField const& field) const; + std::uint16_t + getFieldU16(SField const& field) const; + std::uint32_t + getFieldU32(SField const& field) const; + std::uint64_t + getFieldU64(SField const& field) const; + uint128 + getFieldH128(SField const& field) const; + + uint160 + getFieldH160(SField const& field) const; + uint192 + getFieldH192(SField const& field) const; + uint256 + getFieldH256(SField const& field) const; + AccountID + getAccountID(SField const& field) const; + + Blob + getFieldVL(SField const& field) const; + STAmount const& + getFieldAmount(SField const& field) const; + STPathSet const& + getFieldPathSet(SField const& field) const; + const STVector256& + getFieldV256(SField const& field) const; + const STArray& + getFieldArray(SField const& field) const; + const STCurrency& + getFieldCurrency(SField const& field) const; + STNumber const& + getFieldNumber(SField const& field) const; + + /** Get the value of a field. + @param A TypedField built from an SField value representing the desired + object field. In typical use, the TypedField will be implicitly + constructed. + @return The value of the specified field. + @throws STObject::FieldErr if the field is not present. + */ + template + typename T::value_type + operator[](TypedField const& f) const; + + /** Get the value of a field as a std::optional + + @param An OptionaledField built from an SField value representing the + desired object field. In typical use, the OptionaledField will be + constructed by using the ~ operator on an SField. + @return std::nullopt if the field is not present, else the value of + the specified field. + */ + template + std::optional> + operator[](OptionaledField const& of) const; + + /** Get a modifiable field value. + @param A TypedField built from an SField value representing the desired + object field. In typical use, the TypedField will be implicitly + constructed. + @return A modifiable reference to the value of the specified field. + @throws STObject::FieldErr if the field is not present. + */ + template + ValueProxy + operator[](TypedField const& f); + + /** Return a modifiable field value as std::optional + + @param An OptionaledField built from an SField value representing the + desired object field. In typical use, the OptionaledField will be + constructed by using the ~ operator on an SField. + @return Transparent proxy object to an `optional` holding a modifiable + reference to the value of the specified field. Returns + std::nullopt if the field is not present. + */ + template + OptionalProxy + operator[](OptionaledField const& of); + + /** Get the value of a field. + @param A TypedField built from an SField value representing the desired + object field. In typical use, the TypedField will be implicitly + constructed. + @return The value of the specified field. + @throws STObject::FieldErr if the field is not present. + */ + template + typename T::value_type + at(TypedField const& f) const; + + /** Get the value of a field as std::optional + + @param An OptionaledField built from an SField value representing the + desired object field. In typical use, the OptionaledField will be + constructed by using the ~ operator on an SField. + @return std::nullopt if the field is not present, else the value of + the specified field. + */ + template + std::optional> + at(OptionaledField const& of) const; + + /** Get a modifiable field value. + @param A TypedField built from an SField value representing the desired + object field. In typical use, the TypedField will be implicitly + constructed. + @return A modifiable reference to the value of the specified field. + @throws STObject::FieldErr if the field is not present. + */ + template + ValueProxy + at(TypedField const& f); + + /** Return a modifiable field value as std::optional + + @param An OptionaledField built from an SField value representing the + desired object field. In typical use, the OptionaledField will be + constructed by using the ~ operator on an SField. + @return Transparent proxy object to an `optional` holding a modifiable + reference to the value of the specified field. Returns + std::nullopt if the field is not present. + */ + template + OptionalProxy + at(OptionaledField const& of); + + /** Set a field. + if the field already exists, it is replaced. + */ + void + set(std::unique_ptr v); + + void + set(STBase&& v); + + void + setFieldU8(SField const& field, unsigned char); + void + setFieldU16(SField const& field, std::uint16_t); + void + setFieldU32(SField const& field, std::uint32_t); + void + setFieldU64(SField const& field, std::uint64_t); + void + setFieldH128(SField const& field, uint128 const&); + void + setFieldH256(SField const& field, uint256 const&); + void + setFieldVL(SField const& field, Blob const&); + void + setFieldVL(SField const& field, Slice const&); + + void + setAccountID(SField const& field, AccountID const&); + + void + setFieldAmount(SField const& field, STAmount const&); + void + setFieldIssue(SField const& field, STIssue const&); + void + setFieldCurrency(SField const& field, STCurrency const&); + void + setFieldNumber(SField const& field, STNumber const&); + void + setFieldPathSet(SField const& field, STPathSet const&); + void + setFieldV256(SField const& field, STVector256 const& v); + void + setFieldArray(SField const& field, STArray const& v); + + template + void + setFieldH160(SField const& field, base_uint<160, Tag> const& v); + + STObject& + peekFieldObject(SField const& field); + STArray& + peekFieldArray(SField const& field); + + bool + isFieldPresent(SField const& field) const; + STBase* + makeFieldPresent(SField const& field); + void + makeFieldAbsent(SField const& field); + bool + delField(SField const& field); + void + delField(int index); + + bool + hasMatchingEntry(const STBase&); + + bool + operator==(const STObject& o) const; + bool + operator!=(const STObject& o) const; + + class FieldErr; + +private: + enum WhichFields : bool { + // These values are carefully chosen to do the right thing if passed + // to SField::shouldInclude (bool) + omitSigningFields = false, + withAllFields = true + }; + + void + add(Serializer& s, WhichFields whichFields) const; + + // Sort the entries in an STObject into the order that they will be + // serialized. Note: they are not sorted into pointer value order, they + // are sorted by SField::fieldCode. + static std::vector + getSortedFields(STObject const& objToSort, WhichFields whichFields); + + // Implementation for getting (most) fields that return by value. + // + // The remove_cv and remove_reference are necessitated by the STBitString + // types. Their value() returns by const ref. We return those types + // by value. + template < + typename T, + typename V = typename std::remove_cv().value())>::type>::type> + V + getFieldByValue(SField const& field) const; + + // Implementations for getting (most) fields that return by const reference. + // + // If an absent optional field is deserialized we don't have anything + // obvious to return. So we insist on having the call provide an + // 'empty' value we return in that circumstance. + template + V const& + getFieldByConstRef(SField const& field, V const& empty) const; + + // Implementation for setting most fields with a setValue() method. + template + void + setFieldUsingSetValue(SField const& field, V value); + + // Implementation for setting fields using assignment + template + void + setFieldUsingAssignment(SField const& field, T const& value); + + // Implementation for peeking STObjects and STArrays + template + T& + peekField(SField const& field); + + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +//------------------------------------------------------------------------------ + +template +class STObject::Proxy +{ +protected: + using value_type = typename T::value_type; + + STObject* st_; + SOEStyle style_; + TypedField const* f_; + + Proxy(Proxy const&) = default; + + Proxy(STObject* st, TypedField const* f); + + value_type + value() const; + + T const* + find() const; + + template + void + assign(U&& u); +}; + +// Constraint += and -= ValueProxy operators +// to value types that support arithmetic operations +template +concept IsArithmetic = std::is_arithmetic_v || std::is_same_v; + +template +class STObject::ValueProxy : private Proxy +{ +private: + using value_type = typename T::value_type; + +public: + ValueProxy(ValueProxy const&) = default; + ValueProxy& + operator=(ValueProxy const&) = delete; + + template + std::enable_if_t, ValueProxy&> + operator=(U&& u); + + // Convenience operators for value types supporting + // arithmetic operations + template + ValueProxy& + operator+=(U const& u); + + template + ValueProxy& + operator-=(U const& u); + + operator value_type() const; + +private: + friend class STObject; + + ValueProxy(STObject* st, TypedField const* f); +}; + +template +class STObject::OptionalProxy : private Proxy +{ +private: + using value_type = typename T::value_type; + + using optional_type = std::optional::type>; + +public: + OptionalProxy(OptionalProxy const&) = default; + OptionalProxy& + operator=(OptionalProxy const&) = delete; + + /** Returns `true` if the field is set. + + Fields with soeDEFAULT and set to the + default value will return `true` + */ + explicit + operator bool() const noexcept; + + /** Return the contained value + + Throws: + + STObject::FieldErr if !engaged() + */ + value_type + operator*() const; + + operator optional_type() const; + + /** Explicit conversion to std::optional */ + optional_type + operator~() const; + + friend bool + operator==(OptionalProxy const& lhs, std::nullopt_t) noexcept + { + return !lhs.engaged(); + } + + friend bool + operator==(std::nullopt_t, OptionalProxy const& rhs) noexcept + { + return rhs == std::nullopt; + } + + friend bool + operator==(OptionalProxy const& lhs, optional_type const& rhs) noexcept + { + if (!lhs.engaged()) + return !rhs; + if (!rhs) + return false; + return *lhs == *rhs; + } + + friend bool + operator==(optional_type const& lhs, OptionalProxy const& rhs) noexcept + { + return rhs == lhs; + } + + friend bool + operator==(OptionalProxy const& lhs, OptionalProxy const& rhs) noexcept + { + if (lhs.engaged() != rhs.engaged()) + return false; + return !lhs.engaged() || *lhs == *rhs; + } + + friend bool + operator!=(OptionalProxy const& lhs, std::nullopt_t) noexcept + { + return !(lhs == std::nullopt); + } + + friend bool + operator!=(std::nullopt_t, OptionalProxy const& rhs) noexcept + { + return !(rhs == std::nullopt); + } + + friend bool + operator!=(OptionalProxy const& lhs, optional_type const& rhs) noexcept + { + return !(lhs == rhs); + } + + friend bool + operator!=(optional_type const& lhs, OptionalProxy const& rhs) noexcept + { + return !(lhs == rhs); + } + + friend bool + operator!=(OptionalProxy const& lhs, OptionalProxy const& rhs) noexcept + { + return !(lhs == rhs); + } + + // Emulate std::optional::value_or + value_type + value_or(value_type val) const; + + OptionalProxy& + operator=(std::nullopt_t const&); + OptionalProxy& + operator=(optional_type&& v); + OptionalProxy& + operator=(optional_type const& v); + + template + std::enable_if_t, OptionalProxy&> + operator=(U&& u); + +private: + friend class STObject; + + OptionalProxy(STObject* st, TypedField const* f); + + bool + engaged() const noexcept; + + void + disengage(); + + optional_type + optional_value() const; +}; + +class STObject::FieldErr : public std::runtime_error +{ + using std::runtime_error::runtime_error; +}; + +template +STObject::Proxy::Proxy(STObject* st, TypedField const* f) : st_(st), f_(f) +{ + if (st_->mType) + { + // STObject has associated template + if (!st_->peekAtPField(*f_)) + Throw( + "Template field error '" + this->f_->getName() + "'"); + style_ = st_->mType->style(*f_); + } + else + { + style_ = soeINVALID; + } +} + +template +auto +STObject::Proxy::value() const -> value_type +{ + auto const t = find(); + if (t) + return t->value(); + if (style_ == soeINVALID) + { + Throw("Value requested from invalid STObject."); + } + if (style_ != soeDEFAULT) + { + Throw( + "Missing field '" + this->f_->getName() + "'"); + } + return value_type{}; +} + +template +inline T const* +STObject::Proxy::find() const +{ + return dynamic_cast(st_->peekAtPField(*f_)); +} + +template +template +void +STObject::Proxy::assign(U&& u) +{ + if (style_ == soeDEFAULT && u == value_type{}) + { + st_->makeFieldAbsent(*f_); + return; + } + T* t; + if (style_ == soeINVALID) + t = dynamic_cast(st_->getPField(*f_, true)); + else + t = dynamic_cast(st_->makeFieldPresent(*f_)); + XRPL_ASSERT(t, "ripple::STObject::Proxy::assign : type cast succeeded"); + *t = std::forward(u); +} + +//------------------------------------------------------------------------------ + +template +template +std::enable_if_t, STObject::ValueProxy&> +STObject::ValueProxy::operator=(U&& u) +{ + this->assign(std::forward(u)); + return *this; +} + +template +template +STObject::ValueProxy& +STObject::ValueProxy::operator+=(U const& u) +{ + this->assign(this->value() + u); + return *this; +} + +template +template +STObject::ValueProxy& +STObject::ValueProxy::operator-=(U const& u) +{ + this->assign(this->value() - u); + return *this; +} + +template +STObject::ValueProxy::operator value_type() const +{ + return this->value(); +} + +template +STObject::ValueProxy::ValueProxy(STObject* st, TypedField const* f) + : Proxy(st, f) +{ +} + +//------------------------------------------------------------------------------ + +template +STObject::OptionalProxy::operator bool() const noexcept +{ + return engaged(); +} + +template +auto +STObject::OptionalProxy::operator*() const -> value_type +{ + return this->value(); +} + +template +STObject::OptionalProxy::operator typename STObject::OptionalProxy< + T>::optional_type() const +{ + return optional_value(); +} + +template +typename STObject::OptionalProxy::optional_type +STObject::OptionalProxy::operator~() const +{ + return optional_value(); +} + +template +auto +STObject::OptionalProxy::operator=(std::nullopt_t const&) -> OptionalProxy& +{ + disengage(); + return *this; +} + +template +auto +STObject::OptionalProxy::operator=(optional_type&& v) -> OptionalProxy& +{ + if (v) + this->assign(std::move(*v)); + else + disengage(); + return *this; +} + +template +auto +STObject::OptionalProxy::operator=(optional_type const& v) -> OptionalProxy& +{ + if (v) + this->assign(*v); + else + disengage(); + return *this; +} + +template +template +std::enable_if_t, STObject::OptionalProxy&> +STObject::OptionalProxy::operator=(U&& u) +{ + this->assign(std::forward(u)); + return *this; +} + +template +STObject::OptionalProxy::OptionalProxy(STObject* st, TypedField const* f) + : Proxy(st, f) +{ +} + +template +bool +STObject::OptionalProxy::engaged() const noexcept +{ + return this->style_ == soeDEFAULT || this->find() != nullptr; +} + +template +void +STObject::OptionalProxy::disengage() +{ + if (this->style_ == soeREQUIRED || this->style_ == soeDEFAULT) + Throw( + "Template field error '" + this->f_->getName() + "'"); + if (this->style_ == soeINVALID) + this->st_->delField(*this->f_); + else + this->st_->makeFieldAbsent(*this->f_); +} + +template +auto +STObject::OptionalProxy::optional_value() const -> optional_type +{ + if (!engaged()) + return std::nullopt; + return this->value(); +} + +template +typename STObject::OptionalProxy::value_type +STObject::OptionalProxy::value_or(value_type val) const +{ + return engaged() ? this->value() : val; +} + +//------------------------------------------------------------------------------ + +inline STBase const& +STObject::Transform::operator()(detail::STVar const& e) const +{ + return e.get(); +} + +//------------------------------------------------------------------------------ + +inline STObject::STObject(SerialIter&& sit, SField const& name) + : STObject(sit, name) +{ +} + +inline STObject::iterator +STObject::begin() const +{ + return iterator(v_.begin()); +} + +inline STObject::iterator +STObject::end() const +{ + return iterator(v_.end()); +} + +inline bool +STObject::empty() const +{ + return v_.empty(); +} + +inline void +STObject::reserve(std::size_t n) +{ + v_.reserve(n); +} + +inline bool +STObject::isFree() const +{ + return mType == nullptr; +} + +inline void +STObject::addWithoutSigningFields(Serializer& s) const +{ + add(s, omitSigningFields); +} + +// VFALCO NOTE does this return an expensive copy of an object with a +// dynamic buffer? +// VFALCO TODO Remove this function and fix the few callers. +inline Serializer +STObject::getSerializer() const +{ + Serializer s; + add(s, withAllFields); + return s; +} + +template +inline std::size_t +STObject::emplace_back(Args&&... args) +{ + v_.emplace_back(std::forward(args)...); + return v_.size() - 1; +} + +inline int +STObject::getCount() const +{ + return v_.size(); +} + +inline const STBase& +STObject::peekAtIndex(int offset) const +{ + return v_[offset].get(); +} + +inline STBase& +STObject::getIndex(int offset) +{ + return v_[offset].get(); +} + +inline const STBase* +STObject::peekAtPIndex(int offset) const +{ + return &v_[offset].get(); +} + +inline STBase* +STObject::getPIndex(int offset) +{ + return &v_[offset].get(); +} + +template +typename T::value_type +STObject::operator[](TypedField const& f) const +{ + return at(f); +} + +template +std::optional> +STObject::operator[](OptionaledField const& of) const +{ + return at(of); +} + +template +inline auto +STObject::operator[](TypedField const& f) -> ValueProxy +{ + return at(f); +} + +template +inline auto +STObject::operator[](OptionaledField const& of) -> OptionalProxy +{ + return at(of); +} + +template +typename T::value_type +STObject::at(TypedField const& f) const +{ + auto const b = peekAtPField(f); + if (!b) + // This is a free object (no constraints) + // with no template + Throw("Missing field: " + f.getName()); + + if (auto const u = dynamic_cast(b)) + return u->value(); + + XRPL_ASSERT( + mType, + "ripple::STObject::at(TypedField auto) : field template non-null"); + XRPL_ASSERT( + b->getSType() == STI_NOTPRESENT, + "ripple::STObject::at(TypedField auto) : type not present"); + + if (mType->style(f) == soeOPTIONAL) + Throw("Missing optional field: " + f.getName()); + + XRPL_ASSERT( + mType->style(f) == soeDEFAULT, + "ripple::STObject::at(TypedField auto) : template style is default"); + + // Used to help handle the case where value_type is a const reference, + // otherwise we would return the address of a temporary. + static std::decay_t const dv{}; + return dv; +} + +template +std::optional> +STObject::at(OptionaledField const& of) const +{ + auto const b = peekAtPField(*of.f); + if (!b) + return std::nullopt; + auto const u = dynamic_cast(b); + if (!u) + { + XRPL_ASSERT( + mType, + "ripple::STObject::at(OptionaledField auto) : field template " + "non-null"); + XRPL_ASSERT( + b->getSType() == STI_NOTPRESENT, + "ripple::STObject::at(OptionaledField auto) : type not present"); + if (mType->style(*of.f) == soeOPTIONAL) + return std::nullopt; + XRPL_ASSERT( + mType->style(*of.f) == soeDEFAULT, + "ripple::STObject::at(OptionaledField auto) : template style is " + "default"); + return typename T::value_type{}; + } + return u->value(); +} + +template +inline auto +STObject::at(TypedField const& f) -> ValueProxy +{ + return ValueProxy(this, &f); +} + +template +inline auto +STObject::at(OptionaledField const& of) -> OptionalProxy +{ + return OptionalProxy(this, of.f); +} + +template +void +STObject::setFieldH160(SField const& field, base_uint<160, Tag> const& v) +{ + STBase* rf = getPField(field, true); + + if (!rf) + throwFieldNotFound(field); + + if (rf->getSType() == STI_NOTPRESENT) + rf = makeFieldPresent(field); + + using Bits = STBitString<160>; + if (auto cf = dynamic_cast(rf)) + cf->setValue(v); + else + Throw("Wrong field type"); +} + +inline bool +STObject::operator!=(const STObject& o) const +{ + return !(*this == o); +} + +template +V +STObject::getFieldByValue(SField const& field) const +{ + const STBase* rf = peekAtPField(field); + + if (!rf) + throwFieldNotFound(field); + + SerializedTypeID id = rf->getSType(); + + if (id == STI_NOTPRESENT) + return V(); // optional field not present + + const T* cf = dynamic_cast(rf); + + if (!cf) + Throw("Wrong field type"); + + return cf->value(); +} + +// Implementations for getting (most) fields that return by const reference. +// +// If an absent optional field is deserialized we don't have anything +// obvious to return. So we insist on having the call provide an +// 'empty' value we return in that circumstance. +template +V const& +STObject::getFieldByConstRef(SField const& field, V const& empty) const +{ + const STBase* rf = peekAtPField(field); + + if (!rf) + throwFieldNotFound(field); + + SerializedTypeID id = rf->getSType(); + + if (id == STI_NOTPRESENT) + return empty; // optional field not present + + const T* cf = dynamic_cast(rf); + + if (!cf) + Throw("Wrong field type"); + + return *cf; +} + +// Implementation for setting most fields with a setValue() method. +template +void +STObject::setFieldUsingSetValue(SField const& field, V value) +{ + static_assert(!std::is_lvalue_reference::value, ""); + + STBase* rf = getPField(field, true); + + if (!rf) + throwFieldNotFound(field); + + if (rf->getSType() == STI_NOTPRESENT) + rf = makeFieldPresent(field); + + T* cf = dynamic_cast(rf); + + if (!cf) + Throw("Wrong field type"); + + cf->setValue(std::move(value)); +} + +// Implementation for setting fields using assignment +template +void +STObject::setFieldUsingAssignment(SField const& field, T const& value) +{ + STBase* rf = getPField(field, true); + + if (!rf) + throwFieldNotFound(field); + + if (rf->getSType() == STI_NOTPRESENT) + rf = makeFieldPresent(field); + + T* cf = dynamic_cast(rf); + + if (!cf) + Throw("Wrong field type"); + + (*cf) = value; +} + +// Implementation for peeking STObjects and STArrays +template +T& +STObject::peekField(SField const& field) +{ + STBase* rf = getPField(field, true); + + if (!rf) + throwFieldNotFound(field); + + if (rf->getSType() == STI_NOTPRESENT) + rf = makeFieldPresent(field); + + T* cf = dynamic_cast(rf); + + if (!cf) + Throw("Wrong field type"); + + return *cf; +} + +} // namespace ripple + +#endif diff --git a/src/ripple/protocol/STParsedJSON.h b/include/xrpl/protocol/STParsedJSON.h similarity index 76% rename from src/ripple/protocol/STParsedJSON.h rename to include/xrpl/protocol/STParsedJSON.h index c4de5139972..d6559690302 100644 --- a/src/ripple/protocol/STParsedJSON.h +++ b/include/xrpl/protocol/STParsedJSON.h @@ -20,8 +20,9 @@ #ifndef RIPPLE_PROTOCOL_STPARSEDJSON_H_INCLUDED #define RIPPLE_PROTOCOL_STPARSEDJSON_H_INCLUDED -#include -#include +#include + +#include namespace ripple { @@ -38,15 +39,16 @@ class STParsedJSONObject @param name The name of the JSON field, used in diagnostics. @param json The JSON-RPC to parse. */ - STParsedJSONObject (std::string const& name, Json::Value const& json); + STParsedJSONObject(std::string const& name, Json::Value const& json); - STParsedJSONObject () = delete; - STParsedJSONObject (STParsedJSONObject const&) = delete; - STParsedJSONObject& operator= (STParsedJSONObject const&) = delete; - ~STParsedJSONObject () = default; + STParsedJSONObject() = delete; + STParsedJSONObject(STParsedJSONObject const&) = delete; + STParsedJSONObject& + operator=(STParsedJSONObject const&) = delete; + ~STParsedJSONObject() = default; /** The STObject if the parse was successful. */ - boost::optional object; + std::optional object; /** On failure, an appropriate set of error values. */ Json::Value error; @@ -65,22 +67,21 @@ class STParsedJSONArray @param name The name of the JSON field, used in diagnostics. @param json The JSON-RPC to parse. */ - STParsedJSONArray (std::string const& name, Json::Value const& json); + STParsedJSONArray(std::string const& name, Json::Value const& json); - STParsedJSONArray () = delete; - STParsedJSONArray (STParsedJSONArray const&) = delete; - STParsedJSONArray& operator= (STParsedJSONArray const&) = delete; - ~STParsedJSONArray () = default; + STParsedJSONArray() = delete; + STParsedJSONArray(STParsedJSONArray const&) = delete; + STParsedJSONArray& + operator=(STParsedJSONArray const&) = delete; + ~STParsedJSONArray() = default; /** The STArray if the parse was successful. */ - boost::optional array; + std::optional array; /** On failure, an appropriate set of error values. */ Json::Value error; }; - - -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/protocol/STPathSet.h b/include/xrpl/protocol/STPathSet.h new file mode 100644 index 00000000000..7605a2283c7 --- /dev/null +++ b/include/xrpl/protocol/STPathSet.h @@ -0,0 +1,528 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STPATHSET_H_INCLUDED +#define RIPPLE_PROTOCOL_STPATHSET_H_INCLUDED + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace ripple { + +class STPathElement final : public CountedObject +{ + unsigned int mType; + AccountID mAccountID; + Currency mCurrencyID; + AccountID mIssuerID; + + bool is_offer_; + std::size_t hash_value_; + +public: + enum Type { + typeNone = 0x00, + typeAccount = + 0x01, // Rippling through an account (vs taking an offer). + typeCurrency = 0x10, // Currency follows. + typeIssuer = 0x20, // Issuer follows. + typeBoundary = 0xFF, // Boundary between alternate paths. + typeAll = typeAccount | typeCurrency | typeIssuer, + // Combination of all types. + }; + + STPathElement(); + STPathElement(STPathElement const&) = default; + STPathElement& + operator=(STPathElement const&) = default; + + STPathElement( + std::optional const& account, + std::optional const& currency, + std::optional const& issuer); + + STPathElement( + AccountID const& account, + Currency const& currency, + AccountID const& issuer, + bool forceCurrency = false); + + STPathElement( + unsigned int uType, + AccountID const& account, + Currency const& currency, + AccountID const& issuer); + + auto + getNodeType() const; + + bool + isOffer() const; + + bool + isAccount() const; + + bool + hasIssuer() const; + + bool + hasCurrency() const; + + bool + isNone() const; + + // Nodes are either an account ID or a offer prefix. Offer prefixs denote a + // class of offers. + AccountID const& + getAccountID() const; + + Currency const& + getCurrency() const; + + AccountID const& + getIssuerID() const; + + bool + operator==(const STPathElement& t) const; + + bool + operator!=(const STPathElement& t) const; + +private: + static std::size_t + get_hash(STPathElement const& element); +}; + +class STPath final : public CountedObject +{ + std::vector mPath; + +public: + STPath() = default; + + STPath(std::vector p); + + std::vector::size_type + size() const; + + bool + empty() const; + + void + push_back(STPathElement const& e); + + template + void + emplace_back(Args&&... args); + + bool + hasSeen( + AccountID const& account, + Currency const& currency, + AccountID const& issuer) const; + + Json::Value getJson(JsonOptions) const; + + std::vector::const_iterator + begin() const; + + std::vector::const_iterator + end() const; + + bool + operator==(STPath const& t) const; + + std::vector::const_reference + back() const; + + std::vector::const_reference + front() const; + + STPathElement& + operator[](int i); + + const STPathElement& + operator[](int i) const; + + void + reserve(size_t s); +}; + +//------------------------------------------------------------------------------ + +// A set of zero or more payment paths +class STPathSet final : public STBase, public CountedObject +{ + std::vector value; + +public: + STPathSet() = default; + + STPathSet(SField const& n); + STPathSet(SerialIter& sit, SField const& name); + + void + add(Serializer& s) const override; + + Json::Value getJson(JsonOptions) const override; + + SerializedTypeID + getSType() const override; + + bool + assembleAdd(STPath const& base, STPathElement const& tail); + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + + // std::vector like interface: + std::vector::const_reference + operator[](std::vector::size_type n) const; + + std::vector::reference + operator[](std::vector::size_type n); + + std::vector::const_iterator + begin() const; + + std::vector::const_iterator + end() const; + + std::vector::size_type + size() const; + + bool + empty() const; + + void + push_back(STPath const& e); + + template + void + emplace_back(Args&&... args); + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +// ------------ STPathElement ------------ + +inline STPathElement::STPathElement() : mType(typeNone), is_offer_(true) +{ + hash_value_ = get_hash(*this); +} + +inline STPathElement::STPathElement( + std::optional const& account, + std::optional const& currency, + std::optional const& issuer) + : mType(typeNone) +{ + if (!account) + { + is_offer_ = true; + } + else + { + is_offer_ = false; + mAccountID = *account; + mType |= typeAccount; + XRPL_ASSERT( + mAccountID != noAccount(), + "ripple::STPathElement::STPathElement : account is set"); + } + + if (currency) + { + mCurrencyID = *currency; + mType |= typeCurrency; + } + + if (issuer) + { + mIssuerID = *issuer; + mType |= typeIssuer; + XRPL_ASSERT( + mIssuerID != noAccount(), + "ripple::STPathElement::STPathElement : issuer is set"); + } + + hash_value_ = get_hash(*this); +} + +inline STPathElement::STPathElement( + AccountID const& account, + Currency const& currency, + AccountID const& issuer, + bool forceCurrency) + : mType(typeNone) + , mAccountID(account) + , mCurrencyID(currency) + , mIssuerID(issuer) + , is_offer_(isXRP(mAccountID)) +{ + if (!is_offer_) + mType |= typeAccount; + + if (forceCurrency || !isXRP(currency)) + mType |= typeCurrency; + + if (!isXRP(issuer)) + mType |= typeIssuer; + + hash_value_ = get_hash(*this); +} + +inline STPathElement::STPathElement( + unsigned int uType, + AccountID const& account, + Currency const& currency, + AccountID const& issuer) + : mType(uType) + , mAccountID(account) + , mCurrencyID(currency) + , mIssuerID(issuer) + , is_offer_(isXRP(mAccountID)) +{ + hash_value_ = get_hash(*this); +} + +inline auto +STPathElement::getNodeType() const +{ + return mType; +} + +inline bool +STPathElement::isOffer() const +{ + return is_offer_; +} + +inline bool +STPathElement::isAccount() const +{ + return !isOffer(); +} + +inline bool +STPathElement::hasIssuer() const +{ + return getNodeType() & STPathElement::typeIssuer; +} + +inline bool +STPathElement::hasCurrency() const +{ + return getNodeType() & STPathElement::typeCurrency; +} + +inline bool +STPathElement::isNone() const +{ + return getNodeType() == STPathElement::typeNone; +} + +// Nodes are either an account ID or a offer prefix. Offer prefixs denote a +// class of offers. +inline AccountID const& +STPathElement::getAccountID() const +{ + return mAccountID; +} + +inline Currency const& +STPathElement::getCurrency() const +{ + return mCurrencyID; +} + +inline AccountID const& +STPathElement::getIssuerID() const +{ + return mIssuerID; +} + +inline bool +STPathElement::operator==(const STPathElement& t) const +{ + return (mType & typeAccount) == (t.mType & typeAccount) && + hash_value_ == t.hash_value_ && mAccountID == t.mAccountID && + mCurrencyID == t.mCurrencyID && mIssuerID == t.mIssuerID; +} + +inline bool +STPathElement::operator!=(const STPathElement& t) const +{ + return !operator==(t); +} + +// ------------ STPath ------------ + +inline STPath::STPath(std::vector p) : mPath(std::move(p)) +{ +} + +inline std::vector::size_type +STPath::size() const +{ + return mPath.size(); +} + +inline bool +STPath::empty() const +{ + return mPath.empty(); +} + +inline void +STPath::push_back(STPathElement const& e) +{ + mPath.push_back(e); +} + +template +inline void +STPath::emplace_back(Args&&... args) +{ + mPath.emplace_back(std::forward(args)...); +} + +inline std::vector::const_iterator +STPath::begin() const +{ + return mPath.begin(); +} + +inline std::vector::const_iterator +STPath::end() const +{ + return mPath.end(); +} + +inline bool +STPath::operator==(STPath const& t) const +{ + return mPath == t.mPath; +} + +inline std::vector::const_reference +STPath::back() const +{ + return mPath.back(); +} + +inline std::vector::const_reference +STPath::front() const +{ + return mPath.front(); +} + +inline STPathElement& +STPath::operator[](int i) +{ + return mPath[i]; +} + +inline const STPathElement& +STPath::operator[](int i) const +{ + return mPath[i]; +} + +inline void +STPath::reserve(size_t s) +{ + mPath.reserve(s); +} + +// ------------ STPathSet ------------ + +inline STPathSet::STPathSet(SField const& n) : STBase(n) +{ +} + +// std::vector like interface: +inline std::vector::const_reference +STPathSet::operator[](std::vector::size_type n) const +{ + return value[n]; +} + +inline std::vector::reference +STPathSet::operator[](std::vector::size_type n) +{ + return value[n]; +} + +inline std::vector::const_iterator +STPathSet::begin() const +{ + return value.begin(); +} + +inline std::vector::const_iterator +STPathSet::end() const +{ + return value.end(); +} + +inline std::vector::size_type +STPathSet::size() const +{ + return value.size(); +} + +inline bool +STPathSet::empty() const +{ + return value.empty(); +} + +inline void +STPathSet::push_back(STPath const& e) +{ + value.push_back(e); +} + +template +inline void +STPathSet::emplace_back(Args&&... args) +{ + value.emplace_back(std::forward(args)...); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STTx.h b/include/xrpl/protocol/STTx.h new file mode 100644 index 00000000000..8de2c8cc313 --- /dev/null +++ b/include/xrpl/protocol/STTx.h @@ -0,0 +1,201 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STTX_H_INCLUDED +#define RIPPLE_PROTOCOL_STTX_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace ripple { + +enum TxnSql : char { + txnSqlNew = 'N', + txnSqlConflict = 'C', + txnSqlHeld = 'H', + txnSqlValidated = 'V', + txnSqlIncluded = 'I', + txnSqlUnknown = 'U' +}; + +class STTx final : public STObject, public CountedObject +{ + uint256 tid_; + TxType tx_type_; + +public: + static std::size_t const minMultiSigners = 1; + + // if rules are not supplied then the largest possible value is returned + static std::size_t + maxMultiSigners(Rules const* rules = 0) + { + if (rules && !rules->enabled(featureExpandedSignerList)) + return 8; + + return 32; + } + + STTx() = delete; + STTx(STTx const& other) = default; + STTx& + operator=(STTx const& other) = delete; + + explicit STTx(SerialIter& sit); + explicit STTx(SerialIter&& sit); + explicit STTx(STObject&& object); + + /** Constructs a transaction. + + The returned transaction will have the specified type and + any fields that the callback function adds to the object + that's passed in. + */ + STTx(TxType type, std::function assembler); + + // STObject functions. + SerializedTypeID + getSType() const override; + + std::string + getFullText() const override; + + // Outer transaction functions / signature functions. + Blob + getSignature() const; + + uint256 + getSigningHash() const; + + TxType + getTxnType() const; + + Blob + getSigningPubKey() const; + + SeqProxy + getSeqProxy() const; + + boost::container::flat_set + getMentionedAccounts() const; + + uint256 + getTransactionID() const; + + Json::Value + getJson(JsonOptions options) const override; + + Json::Value + getJson(JsonOptions options, bool binary) const; + + void + sign(PublicKey const& publicKey, SecretKey const& secretKey); + + /** Check the signature. + @return `true` if valid signature. If invalid, the error message string. + */ + enum class RequireFullyCanonicalSig : bool { no, yes }; + Expected + checkSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const& rules) + const; + + // SQL Functions with metadata. + static std::string const& + getMetaSQLInsertReplaceHeader(); + + std::string + getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) + const; + + std::string + getMetaSQL( + Serializer rawTxn, + std::uint32_t inLedger, + char status, + std::string const& escapedMetaData) const; + +private: + Expected + checkSingleSign(RequireFullyCanonicalSig requireCanonicalSig) const; + + Expected + checkMultiSign( + RequireFullyCanonicalSig requireCanonicalSig, + Rules const& rules) const; + + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +bool +passesLocalChecks(STObject const& st, std::string&); + +/** Sterilize a transaction. + + The transaction is serialized and then deserialized, + ensuring that all equivalent transactions are in canonical + form. This also ensures that program metadata such as + the transaction's digest, are all computed. +*/ +std::shared_ptr +sterilize(STTx const& stx); + +/** Check whether a transaction is a pseudo-transaction */ +bool +isPseudoTx(STObject const& tx); + +inline STTx::STTx(SerialIter&& sit) : STTx(sit) +{ +} + +inline TxType +STTx::getTxnType() const +{ + return tx_type_; +} + +inline Blob +STTx::getSigningPubKey() const +{ + return getFieldVL(sfSigningPubKey); +} + +inline uint256 +STTx::getTransactionID() const +{ + return tid_; +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STValidation.h b/include/xrpl/protocol/STValidation.h new file mode 100644 index 00000000000..11ec733c01b --- /dev/null +++ b/include/xrpl/protocol/STValidation.h @@ -0,0 +1,293 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STVALIDATION_H_INCLUDED +#define RIPPLE_PROTOCOL_STVALIDATION_H_INCLUDED + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace ripple { + +// Validation flags + +// This is a full (as opposed to a partial) validation +constexpr std::uint32_t vfFullValidation = 0x00000001; + +// The signature is fully canonical +constexpr std::uint32_t vfFullyCanonicalSig = 0x80000000; + +class STValidation final : public STObject, public CountedObject +{ + bool mTrusted = false; + + // Determines the validity of the signature in this validation; unseated + // optional if we haven't yet checked it, a boolean otherwise. + mutable std::optional valid_; + + // The public key associated with the key used to sign this validation + PublicKey const signingPubKey_; + + // The ID of the validator that issued this validation. For validators + // that use manifests this will be derived from the master public key. + NodeID const nodeID_; + + NetClock::time_point seenTime_ = {}; + +public: + /** Construct a STValidation from a peer from serialized data. + + @param sit Iterator over serialized data + @param lookupNodeID Invocable with signature + NodeID(PublicKey const&) + used to find the Node ID based on the public key + that signed the validation. For manifest based + validators, this should be the NodeID of the master + public key. + @param checkSignature Whether to verify the data was signed properly + + @note Throws if the object is not valid + */ + template + STValidation( + SerialIter& sit, + LookupNodeID&& lookupNodeID, + bool checkSignature); + + /** Construct, sign and trust a new STValidation issued by this node. + + @param signTime When the validation is signed + @param publicKey The current signing public key + @param secretKey The current signing secret key + @param nodeID ID corresponding to node's public master key + @param f callback function to "fill" the validation with necessary data + */ + template + STValidation( + NetClock::time_point signTime, + PublicKey const& pk, + SecretKey const& sk, + NodeID const& nodeID, + F&& f); + + // Hash of the validated ledger + uint256 + getLedgerHash() const; + + // Hash of consensus transaction set used to generate ledger + uint256 + getConsensusHash() const; + + NetClock::time_point + getSignTime() const; + + NetClock::time_point + getSeenTime() const noexcept; + + PublicKey const& + getSignerPublic() const noexcept; + + NodeID const& + getNodeID() const noexcept; + + bool + isValid() const noexcept; + + bool + isFull() const noexcept; + + bool + isTrusted() const noexcept; + + uint256 + getSigningHash() const; + + void + setTrusted(); + + void + setUntrusted(); + + void + setSeen(NetClock::time_point s); + + Blob + getSerialized() const; + + Blob + getSignature() const; + + std::string + render() const + { + std::stringstream ss; + ss << "validation: " << " ledger_hash: " << getLedgerHash() + << " consensus_hash: " << getConsensusHash() + << " sign_time: " << to_string(getSignTime()) + << " seen_time: " << to_string(getSeenTime()) + << " signer_public_key: " << getSignerPublic() + << " node_id: " << getNodeID() << " is_valid: " << isValid() + << " is_full: " << isFull() << " is_trusted: " << isTrusted() + << " signing_hash: " << getSigningHash() + << " base58: " << toBase58(TokenType::NodePublic, getSignerPublic()); + return ss.str(); + } + +private: + static SOTemplate const& + validationFormat(); + + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +template +STValidation::STValidation( + SerialIter& sit, + LookupNodeID&& lookupNodeID, + bool checkSignature) + : STObject(validationFormat(), sit, sfValidation) + , signingPubKey_([this]() { + auto const spk = getFieldVL(sfSigningPubKey); + + if (publicKeyType(makeSlice(spk)) != KeyType::secp256k1) + Throw("Invalid public key in validation"); + + return PublicKey{makeSlice(spk)}; + }()) + , nodeID_(lookupNodeID(signingPubKey_)) +{ + if (checkSignature && !isValid()) + { + JLOG(debugLog().error()) << "Invalid signature in validation: " + << getJson(JsonOptions::none); + Throw("Invalid signature in validation"); + } + + XRPL_ASSERT( + nodeID_.isNonZero(), + "ripple::STValidation::STValidation(SerialIter) : nonzero node"); +} + +/** Construct, sign and trust a new STValidation issued by this node. + + @param signTime When the validation is signed + @param publicKey The current signing public key + @param secretKey The current signing secret key + @param nodeID ID corresponding to node's public master key + @param f callback function to "fill" the validation with necessary data +*/ +template +STValidation::STValidation( + NetClock::time_point signTime, + PublicKey const& pk, + SecretKey const& sk, + NodeID const& nodeID, + F&& f) + : STObject(validationFormat(), sfValidation) + , signingPubKey_(pk) + , nodeID_(nodeID) + , seenTime_(signTime) +{ + XRPL_ASSERT( + nodeID_.isNonZero(), + "ripple::STValidation::STValidation(PublicKey, SecretKey) : nonzero " + "node"); + + // First, set our own public key: + if (publicKeyType(pk) != KeyType::secp256k1) + LogicError("We can only use secp256k1 keys for signing validations"); + + setFieldVL(sfSigningPubKey, pk.slice()); + setFieldU32(sfSigningTime, signTime.time_since_epoch().count()); + + // Perform additional initialization + f(*this); + + // Finally, sign the validation and mark it as trusted: + setFlag(vfFullyCanonicalSig); + setFieldVL(sfSignature, signDigest(pk, sk, getSigningHash())); + setTrusted(); + + // Check to ensure that all required fields are present. + for (auto const& e : validationFormat()) + { + if (e.style() == soeREQUIRED && !isFieldPresent(e.sField())) + LogicError( + "Required field '" + e.sField().getName() + + "' missing from validation."); + } + + // We just signed this, so it should be valid. + valid_ = true; +} + +inline PublicKey const& +STValidation::getSignerPublic() const noexcept +{ + return signingPubKey_; +} + +inline NodeID const& +STValidation::getNodeID() const noexcept +{ + return nodeID_; +} + +inline bool +STValidation::isTrusted() const noexcept +{ + return mTrusted; +} + +inline void +STValidation::setTrusted() +{ + mTrusted = true; +} + +inline void +STValidation::setUntrusted() +{ + mTrusted = false; +} + +inline void +STValidation::setSeen(NetClock::time_point s) +{ + seenTime_ = s; +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STVector256.h b/include/xrpl/protocol/STVector256.h new file mode 100644 index 00000000000..d81ddf977ff --- /dev/null +++ b/include/xrpl/protocol/STVector256.h @@ -0,0 +1,261 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STVECTOR256_H_INCLUDED +#define RIPPLE_PROTOCOL_STVECTOR256_H_INCLUDED + +#include +#include +#include +#include + +namespace ripple { + +class STVector256 : public STBase, public CountedObject +{ + std::vector mValue; + +public: + using value_type = std::vector const&; + + STVector256() = default; + + explicit STVector256(SField const& n); + explicit STVector256(std::vector const& vector); + STVector256(SField const& n, std::vector const& vector); + STVector256(SerialIter& sit, SField const& name); + + SerializedTypeID + getSType() const override; + + void + add(Serializer& s) const override; + + Json::Value getJson(JsonOptions) const override; + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + + STVector256& + operator=(std::vector const& v); + + STVector256& + operator=(std::vector&& v); + + void + setValue(const STVector256& v); + + /** Retrieve a copy of the vector we contain */ + explicit + operator std::vector() const; + + std::size_t + size() const; + + void + resize(std::size_t n); + + bool + empty() const; + + std::vector::reference + operator[](std::vector::size_type n); + + std::vector::const_reference + operator[](std::vector::size_type n) const; + + std::vector const& + value() const; + + std::vector::iterator + insert(std::vector::const_iterator pos, uint256 const& value); + + std::vector::iterator + insert(std::vector::const_iterator pos, uint256&& value); + + void + push_back(uint256 const& v); + + std::vector::iterator + begin(); + + std::vector::const_iterator + begin() const; + + std::vector::iterator + end(); + + std::vector::const_iterator + end() const; + + std::vector::iterator + erase(std::vector::iterator position); + + void + clear() noexcept; + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend class detail::STVar; +}; + +inline STVector256::STVector256(SField const& n) : STBase(n) +{ +} + +inline STVector256::STVector256(std::vector const& vector) + : mValue(vector) +{ +} + +inline STVector256::STVector256( + SField const& n, + std::vector const& vector) + : STBase(n), mValue(vector) +{ +} + +inline STVector256& +STVector256::operator=(std::vector const& v) +{ + mValue = v; + return *this; +} + +inline STVector256& +STVector256::operator=(std::vector&& v) +{ + mValue = std::move(v); + return *this; +} + +inline void +STVector256::setValue(const STVector256& v) +{ + mValue = v.mValue; +} + +/** Retrieve a copy of the vector we contain */ +inline STVector256::operator std::vector() const +{ + return mValue; +} + +inline std::size_t +STVector256::size() const +{ + return mValue.size(); +} + +inline void +STVector256::resize(std::size_t n) +{ + return mValue.resize(n); +} + +inline bool +STVector256::empty() const +{ + return mValue.empty(); +} + +inline std::vector::reference +STVector256::operator[](std::vector::size_type n) +{ + return mValue[n]; +} + +inline std::vector::const_reference +STVector256::operator[](std::vector::size_type n) const +{ + return mValue[n]; +} + +inline std::vector const& +STVector256::value() const +{ + return mValue; +} + +inline std::vector::iterator +STVector256::insert( + std::vector::const_iterator pos, + uint256 const& value) +{ + return mValue.insert(pos, value); +} + +inline std::vector::iterator +STVector256::insert(std::vector::const_iterator pos, uint256&& value) +{ + return mValue.insert(pos, std::move(value)); +} + +inline void +STVector256::push_back(uint256 const& v) +{ + mValue.push_back(v); +} + +inline std::vector::iterator +STVector256::begin() +{ + return mValue.begin(); +} + +inline std::vector::const_iterator +STVector256::begin() const +{ + return mValue.begin(); +} + +inline std::vector::iterator +STVector256::end() +{ + return mValue.end(); +} + +inline std::vector::const_iterator +STVector256::end() const +{ + return mValue.end(); +} + +inline std::vector::iterator +STVector256::erase(std::vector::iterator position) +{ + return mValue.erase(position); +} + +inline void +STVector256::clear() noexcept +{ + return mValue.clear(); +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STXChainBridge.h b/include/xrpl/protocol/STXChainBridge.h new file mode 100644 index 00000000000..813bcc44437 --- /dev/null +++ b/include/xrpl/protocol/STXChainBridge.h @@ -0,0 +1,236 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2022 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STXCHAINBRIDGE_H_INCLUDED +#define RIPPLE_PROTOCOL_STXCHAINBRIDGE_H_INCLUDED + +#include +#include +#include +#include + +namespace ripple { + +class Serializer; +class STObject; + +class STXChainBridge final : public STBase, public CountedObject +{ + STAccount lockingChainDoor_{sfLockingChainDoor}; + STIssue lockingChainIssue_{sfLockingChainIssue}; + STAccount issuingChainDoor_{sfIssuingChainDoor}; + STIssue issuingChainIssue_{sfIssuingChainIssue}; + +public: + using value_type = STXChainBridge; + + enum class ChainType { locking, issuing }; + + static ChainType + otherChain(ChainType ct); + + static ChainType + srcChain(bool wasLockingChainSend); + + static ChainType + dstChain(bool wasLockingChainSend); + + STXChainBridge(); + + explicit STXChainBridge(SField const& name); + + STXChainBridge(STXChainBridge const& rhs) = default; + + STXChainBridge(STObject const& o); + + STXChainBridge( + AccountID const& srcChainDoor, + Issue const& srcChainIssue, + AccountID const& dstChainDoor, + Issue const& dstChainIssue); + + explicit STXChainBridge(Json::Value const& v); + + explicit STXChainBridge(SField const& name, Json::Value const& v); + + explicit STXChainBridge(SerialIter& sit, SField const& name); + + STXChainBridge& + operator=(STXChainBridge const& rhs) = default; + + std::string + getText() const override; + + STObject + toSTObject() const; + + AccountID const& + lockingChainDoor() const; + + Issue const& + lockingChainIssue() const; + + AccountID const& + issuingChainDoor() const; + + Issue const& + issuingChainIssue() const; + + AccountID const& + door(ChainType ct) const; + + Issue const& + issue(ChainType ct) const; + + SerializedTypeID + getSType() const override; + + Json::Value getJson(JsonOptions) const override; + + void + add(Serializer& s) const override; + + bool + isEquivalent(const STBase& t) const override; + + bool + isDefault() const override; + + value_type const& + value() const noexcept; + +private: + static std::unique_ptr + construct(SerialIter&, SField const& name); + + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; + + friend bool + operator==(STXChainBridge const& lhs, STXChainBridge const& rhs); + + friend bool + operator<(STXChainBridge const& lhs, STXChainBridge const& rhs); +}; + +inline bool +operator==(STXChainBridge const& lhs, STXChainBridge const& rhs) +{ + return std::tie( + lhs.lockingChainDoor_, + lhs.lockingChainIssue_, + lhs.issuingChainDoor_, + lhs.issuingChainIssue_) == + std::tie( + rhs.lockingChainDoor_, + rhs.lockingChainIssue_, + rhs.issuingChainDoor_, + rhs.issuingChainIssue_); +} + +inline bool +operator<(STXChainBridge const& lhs, STXChainBridge const& rhs) +{ + return std::tie( + lhs.lockingChainDoor_, + lhs.lockingChainIssue_, + lhs.issuingChainDoor_, + lhs.issuingChainIssue_) < + std::tie( + rhs.lockingChainDoor_, + rhs.lockingChainIssue_, + rhs.issuingChainDoor_, + rhs.issuingChainIssue_); +} + +inline AccountID const& +STXChainBridge::lockingChainDoor() const +{ + return lockingChainDoor_.value(); +}; + +inline Issue const& +STXChainBridge::lockingChainIssue() const +{ + return lockingChainIssue_.value().get(); +}; + +inline AccountID const& +STXChainBridge::issuingChainDoor() const +{ + return issuingChainDoor_.value(); +}; + +inline Issue const& +STXChainBridge::issuingChainIssue() const +{ + return issuingChainIssue_.value().get(); +}; + +inline STXChainBridge::value_type const& +STXChainBridge::value() const noexcept +{ + return *this; +} + +inline AccountID const& +STXChainBridge::door(ChainType ct) const +{ + if (ct == ChainType::locking) + return lockingChainDoor(); + return issuingChainDoor(); +} + +inline Issue const& +STXChainBridge::issue(ChainType ct) const +{ + if (ct == ChainType::locking) + return lockingChainIssue(); + return issuingChainIssue(); +} + +inline STXChainBridge::ChainType +STXChainBridge::otherChain(ChainType ct) +{ + if (ct == ChainType::locking) + return ChainType::issuing; + return ChainType::locking; +} + +inline STXChainBridge::ChainType +STXChainBridge::srcChain(bool wasLockingChainSend) +{ + if (wasLockingChainSend) + return ChainType::locking; + return ChainType::issuing; +} + +inline STXChainBridge::ChainType +STXChainBridge::dstChain(bool wasLockingChainSend) +{ + if (wasLockingChainSend) + return ChainType::issuing; + return ChainType::locking; +} + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/SecretKey.h b/include/xrpl/protocol/SecretKey.h new file mode 100644 index 00000000000..1a13cd17c98 --- /dev/null +++ b/include/xrpl/protocol/SecretKey.h @@ -0,0 +1,186 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_SECRETKEY_H_INCLUDED +#define RIPPLE_PROTOCOL_SECRETKEY_H_INCLUDED + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace ripple { + +/** A secret key. */ +class SecretKey +{ +private: + std::uint8_t buf_[32]; + +public: + using const_iterator = std::uint8_t const*; + + SecretKey() = delete; + SecretKey(SecretKey const&) = default; + SecretKey& + operator=(SecretKey const&) = default; + + ~SecretKey(); + + SecretKey(std::array const& data); + SecretKey(Slice const& slice); + + std::uint8_t const* + data() const + { + return buf_; + } + + std::size_t + size() const + { + return sizeof(buf_); + } + + /** Convert the secret key to a hexadecimal string. + + @note The operator<< function is deliberately omitted + to avoid accidental exposure of secret key material. + */ + std::string + to_string() const; + + const_iterator + begin() const noexcept + { + return buf_; + } + + const_iterator + cbegin() const noexcept + { + return buf_; + } + + const_iterator + end() const noexcept + { + return buf_ + sizeof(buf_); + } + + const_iterator + cend() const noexcept + { + return buf_ + sizeof(buf_); + } +}; + +inline bool +operator==(SecretKey const& lhs, SecretKey const& rhs) +{ + return lhs.size() == rhs.size() && + std::memcmp(lhs.data(), rhs.data(), rhs.size()) == 0; +} + +inline bool +operator!=(SecretKey const& lhs, SecretKey const& rhs) +{ + return !(lhs == rhs); +} + +//------------------------------------------------------------------------------ + +/** Parse a secret key */ +template <> +std::optional +parseBase58(TokenType type, std::string const& s); + +inline std::string +toBase58(TokenType type, SecretKey const& sk) +{ + return encodeBase58Token(type, sk.data(), sk.size()); +} + +/** Create a secret key using secure random numbers. */ +SecretKey +randomSecretKey(); + +/** Generate a new secret key deterministically. */ +SecretKey +generateSecretKey(KeyType type, Seed const& seed); + +/** Derive the public key from a secret key. */ +PublicKey +derivePublicKey(KeyType type, SecretKey const& sk); + +/** Generate a key pair deterministically. + + This algorithm is specific to Ripple: + + For secp256k1 key pairs, the seed is converted + to a Generator and used to compute the key pair + corresponding to ordinal 0 for the generator. +*/ +std::pair +generateKeyPair(KeyType type, Seed const& seed); + +/** Create a key pair using secure random numbers. */ +std::pair +randomKeyPair(KeyType type); + +/** Generate a signature for a message digest. + This can only be used with secp256k1 since Ed25519's + security properties come, in part, from how the message + is hashed. +*/ +/** @{ */ +Buffer +signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest); + +inline Buffer +signDigest(KeyType type, SecretKey const& sk, uint256 const& digest) +{ + return signDigest(derivePublicKey(type, sk), sk, digest); +} +/** @} */ + +/** Generate a signature for a message. + With secp256k1 signatures, the data is first hashed with + SHA512-Half, and the resulting digest is signed. +*/ +/** @{ */ +Buffer +sign(PublicKey const& pk, SecretKey const& sk, Slice const& message); + +inline Buffer +sign(KeyType type, SecretKey const& sk, Slice const& message) +{ + return sign(derivePublicKey(type, sk), sk, message); +} +/** @} */ + +} // namespace ripple + +#endif diff --git a/src/ripple/protocol/Seed.h b/include/xrpl/protocol/Seed.h similarity index 77% rename from src/ripple/protocol/Seed.h rename to include/xrpl/protocol/Seed.h index ebe346e0cb1..8a43d597a5c 100644 --- a/src/ripple/protocol/Seed.h +++ b/include/xrpl/protocol/Seed.h @@ -20,11 +20,12 @@ #ifndef RIPPLE_PROTOCOL_SEED_H_INCLUDED #define RIPPLE_PROTOCOL_SEED_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include + #include +#include namespace ripple { @@ -39,8 +40,9 @@ class Seed Seed() = delete; - Seed (Seed const&) = default; - Seed& operator= (Seed const&) = default; + Seed(Seed const&) = default; + Seed& + operator=(Seed const&) = default; /** Destroy the seed. The buffer will first be securely erased. @@ -49,8 +51,8 @@ class Seed /** Construct a seed */ /** @{ */ - explicit Seed (Slice const& slice); - explicit Seed (uint128 const& seed); + explicit Seed(Slice const& slice); + explicit Seed(uint128 const& seed); /** @} */ std::uint8_t const* @@ -108,29 +110,32 @@ randomSeed(); the string (e.g. hex or base58). */ Seed -generateSeed (std::string const& passPhrase); +generateSeed(std::string const& passPhrase); /** Parse a Base58 encoded string into a seed */ template <> -boost::optional -parseBase58 (std::string const& s); +std::optional +parseBase58(std::string const& s); + +/** Attempt to parse a string as a seed. -/** Attempt to parse a string as a seed */ -boost::optional -parseGenericSeed (std::string const& str); + @param str the string to parse + @param rfc1751 true if we should attempt RFC1751 style parsing (deprecated) + * */ +std::optional +parseGenericSeed(std::string const& str, bool rfc1751 = true); /** Encode a Seed in RFC1751 format */ std::string -seedAs1751 (Seed const& seed); +seedAs1751(Seed const& seed); /** Format a seed as a Base58 string */ -inline -std::string -toBase58 (Seed const& seed) +inline std::string +toBase58(Seed const& seed) { - return base58EncodeToken(TokenType::FamilySeed, seed.data(), seed.size()); + return encodeBase58Token(TokenType::FamilySeed, seed.data(), seed.size()); } -} +} // namespace ripple #endif diff --git a/include/xrpl/protocol/SeqProxy.h b/include/xrpl/protocol/SeqProxy.h new file mode 100644 index 00000000000..e7a89561c37 --- /dev/null +++ b/include/xrpl/protocol/SeqProxy.h @@ -0,0 +1,170 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2018 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_SEQ_PROXY_H_INCLUDED +#define RIPPLE_PROTOCOL_SEQ_PROXY_H_INCLUDED + +#include +#include + +namespace ripple { + +/** A type that represents either a sequence value or a ticket value. + + We use the value() of a SeqProxy in places where a sequence was used + before. An example of this is the sequence of an Offer stored in the + ledger. We do the same thing with the in-ledger identifier of a + Check, Payment Channel, and Escrow. + + Why is this safe? If we use the SeqProxy::value(), how do we know that + each ledger entry will be unique? + + There are two components that make this safe: + + 1. A "TicketCreate" transaction carefully avoids creating a ticket + that corresponds with an already used Sequence or Ticket value. + The transactor does this by referring to the account root's + sequence number. Creating the ticket advances the account root's + sequence number so the same ticket (or sequence) value cannot be + used again. + + 2. When a "TicketCreate" transaction creates a batch of tickets it advances + the account root sequence to one past the largest created ticket. + + Therefore all tickets in a batch other than the first may never have + the same value as a sequence on that same account. And since a ticket + may only be used once there will never be any duplicates within this + account. +*/ +class SeqProxy +{ +public: + enum Type : std::uint8_t { seq = 0, ticket }; + +private: + std::uint32_t value_; + Type type_; + +public: + constexpr explicit SeqProxy(Type t, std::uint32_t v) : value_{v}, type_{t} + { + } + + SeqProxy(SeqProxy const& other) = default; + + SeqProxy& + operator=(SeqProxy const& other) = default; + + /** Factory function to return a sequence-based SeqProxy */ + static constexpr SeqProxy + sequence(std::uint32_t v) + { + return SeqProxy{Type::seq, v}; + } + + constexpr std::uint32_t + value() const + { + return value_; + } + + constexpr bool + isSeq() const + { + return type_ == seq; + } + + constexpr bool + isTicket() const + { + return type_ == ticket; + } + + // Occasionally it is convenient to be able to increase the value_ + // of a SeqProxy. But it's unusual. So, rather than putting in an + // addition operator, you must invoke the method by name. That makes + // if more difficult to invoke accidentally. + SeqProxy& + advanceBy(std::uint32_t amount) + { + value_ += amount; + return *this; + } + + // Comparison + // + // The comparison is designed specifically so _all_ Sequence + // representations sort in front of Ticket representations. This + // is true even if the Ticket value() is less that the Sequence + // value(). + // + // This somewhat surprising sort order has benefits for transaction + // processing. It guarantees that transactions creating Tickets are + // sorted in from of transactions that consume Tickets. + friend constexpr bool + operator==(SeqProxy lhs, SeqProxy rhs) + { + if (lhs.type_ != rhs.type_) + return false; + return (lhs.value() == rhs.value()); + } + + friend constexpr bool + operator!=(SeqProxy lhs, SeqProxy rhs) + { + return !(lhs == rhs); + } + + friend constexpr bool + operator<(SeqProxy lhs, SeqProxy rhs) + { + if (lhs.type_ != rhs.type_) + return lhs.type_ < rhs.type_; + return lhs.value() < rhs.value(); + } + + friend constexpr bool + operator>(SeqProxy lhs, SeqProxy rhs) + { + return rhs < lhs; + } + + friend constexpr bool + operator>=(SeqProxy lhs, SeqProxy rhs) + { + return !(lhs < rhs); + } + + friend constexpr bool + operator<=(SeqProxy lhs, SeqProxy rhs) + { + return !(lhs > rhs); + } + + friend std::ostream& + operator<<(std::ostream& os, SeqProxy seqProx) + { + os << (seqProx.isSeq() ? "sequence " : "ticket "); + os << seqProx.value(); + return os; + } +}; +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h new file mode 100644 index 00000000000..5724a19f575 --- /dev/null +++ b/include/xrpl/protocol/Serializer.h @@ -0,0 +1,478 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_SERIALIZER_H_INCLUDED +#define RIPPLE_PROTOCOL_SERIALIZER_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace ripple { + +class Serializer +{ +private: + // DEPRECATED + Blob mData; + +public: + explicit Serializer(int n = 256) + { + mData.reserve(n); + } + + Serializer(void const* data, std::size_t size) + { + mData.resize(size); + + if (size) + { + XRPL_ASSERT( + data, + "ripple::Serializer::Serializer(void const*) : non-null input"); + std::memcpy(mData.data(), data, size); + } + } + + Slice + slice() const noexcept + { + return Slice(mData.data(), mData.size()); + } + + std::size_t + size() const noexcept + { + return mData.size(); + } + + void const* + data() const noexcept + { + return mData.data(); + } + + // assemble functions + int + add8(unsigned char i); + int + add16(std::uint16_t i); + + template + requires(std::is_same_v< + std::make_unsigned_t>, + std::uint32_t>) + int + add32(T i) + { + int ret = mData.size(); + mData.push_back(static_cast((i >> 24) & 0xff)); + mData.push_back(static_cast((i >> 16) & 0xff)); + mData.push_back(static_cast((i >> 8) & 0xff)); + mData.push_back(static_cast(i & 0xff)); + return ret; + } + + int + add32(HashPrefix p); + + template + requires(std::is_same_v< + std::make_unsigned_t>, + std::uint64_t>) + int + add64(T i) + { + int ret = mData.size(); + mData.push_back(static_cast((i >> 56) & 0xff)); + mData.push_back(static_cast((i >> 48) & 0xff)); + mData.push_back(static_cast((i >> 40) & 0xff)); + mData.push_back(static_cast((i >> 32) & 0xff)); + mData.push_back(static_cast((i >> 24) & 0xff)); + mData.push_back(static_cast((i >> 16) & 0xff)); + mData.push_back(static_cast((i >> 8) & 0xff)); + mData.push_back(static_cast(i & 0xff)); + return ret; + } + + template + int addInteger(Integer); + + template + int + addBitString(base_uint const& v) + { + return addRaw(v.data(), v.size()); + } + + int + addRaw(Blob const& vector); + int + addRaw(Slice slice); + int + addRaw(const void* ptr, int len); + int + addRaw(const Serializer& s); + + int + addVL(Blob const& vector); + int + addVL(Slice const& slice); + template + int + addVL(Iter begin, Iter end, int len); + int + addVL(const void* ptr, int len); + + // disassemble functions + bool + get8(int&, int offset) const; + + template + bool + getInteger(Integer& number, int offset) + { + static const auto bytes = sizeof(Integer); + if ((offset + bytes) > mData.size()) + return false; + number = 0; + + auto ptr = &mData[offset]; + for (auto i = 0; i < bytes; ++i) + { + if (i) + number <<= 8; + number |= *ptr++; + } + return true; + } + + template + bool + getBitString(base_uint& data, int offset) const + { + auto success = (offset + (Bits / 8)) <= mData.size(); + if (success) + memcpy(data.begin(), &(mData.front()) + offset, (Bits / 8)); + return success; + } + + int + addFieldID(int type, int name); + int + addFieldID(SerializedTypeID type, int name) + { + return addFieldID(safe_cast(type), name); + } + + // DEPRECATED + uint256 + getSHA512Half() const; + + // totality functions + Blob const& + peekData() const + { + return mData; + } + Blob + getData() const + { + return mData; + } + Blob& + modData() + { + return mData; + } + + int + getDataLength() const + { + return mData.size(); + } + const void* + getDataPtr() const + { + return mData.data(); + } + void* + getDataPtr() + { + return mData.data(); + } + int + getLength() const + { + return mData.size(); + } + std::string + getString() const + { + return std::string(static_cast(getDataPtr()), size()); + } + void + erase() + { + mData.clear(); + } + bool + chop(int num); + + // vector-like functions + Blob ::iterator + begin() + { + return mData.begin(); + } + Blob ::iterator + end() + { + return mData.end(); + } + Blob ::const_iterator + begin() const + { + return mData.begin(); + } + Blob ::const_iterator + end() const + { + return mData.end(); + } + void + reserve(size_t n) + { + mData.reserve(n); + } + void + resize(size_t n) + { + mData.resize(n); + } + size_t + capacity() const + { + return mData.capacity(); + } + + bool + operator==(Blob const& v) const + { + return v == mData; + } + bool + operator!=(Blob const& v) const + { + return v != mData; + } + bool + operator==(const Serializer& v) const + { + return v.mData == mData; + } + bool + operator!=(const Serializer& v) const + { + return v.mData != mData; + } + + static int + decodeLengthLength(int b1); + static int + decodeVLLength(int b1); + static int + decodeVLLength(int b1, int b2); + static int + decodeVLLength(int b1, int b2, int b3); + +private: + static int + encodeLengthLength(int length); // length to encode length + int + addEncoded(int length); +}; + +template +int +Serializer::addVL(Iter begin, Iter end, int len) +{ + int ret = addEncoded(len); + for (; begin != end; ++begin) + { + addRaw(begin->data(), begin->size()); +#ifndef NDEBUG + len -= begin->size(); +#endif + } + XRPL_ASSERT( + len == 0, "ripple::Serializer::addVL : length matches distance"); + return ret; +} + +//------------------------------------------------------------------------------ + +// DEPRECATED +// Transitional adapter to new serialization interfaces +class SerialIter +{ +private: + std::uint8_t const* p_; + std::size_t remain_; + std::size_t used_ = 0; + +public: + SerialIter(void const* data, std::size_t size) noexcept; + + SerialIter(Slice const& slice) : SerialIter(slice.data(), slice.size()) + { + } + + // Infer the size of the data based on the size of the passed array. + template + explicit SerialIter(std::uint8_t const (&data)[N]) : SerialIter(&data[0], N) + { + static_assert(N > 0, ""); + } + + std::size_t + empty() const noexcept + { + return remain_ == 0; + } + + void + reset() noexcept; + + int + getBytesLeft() const noexcept + { + return static_cast(remain_); + } + + // get functions throw on error + unsigned char + get8(); + + std::uint16_t + get16(); + + std::uint32_t + get32(); + std::int32_t + geti32(); + + std::uint64_t + get64(); + std::int64_t + geti64(); + + template + base_uint + getBitString(); + + uint128 + get128() + { + return getBitString<128>(); + } + + uint160 + get160() + { + return getBitString<160>(); + } + + uint192 + get192() + { + return getBitString<192>(); + } + + uint256 + get256() + { + return getBitString<256>(); + } + + void + getFieldID(int& type, int& name); + + // Returns the size of the VL if the + // next object is a VL. Advances the iterator + // to the beginning of the VL. + int + getVLDataLength(); + + Slice + getSlice(std::size_t bytes); + + // VFALCO DEPRECATED Returns a copy + Blob + getRaw(int size); + + // VFALCO DEPRECATED Returns a copy + Blob + getVL(); + + void + skip(int num); + + Buffer + getVLBuffer(); + + template + T + getRawHelper(int size); +}; + +template +base_uint +SerialIter::getBitString() +{ + auto const n = Bits / 8; + + if (remain_ < n) + Throw("invalid SerialIter getBitString"); + + auto const x = p_; + + p_ += n; + used_ += n; + remain_ -= n; + + return base_uint::fromVoid(x); +} + +} // namespace ripple + +#endif diff --git a/src/ripple/protocol/Sign.h b/include/xrpl/protocol/Sign.h similarity index 78% rename from src/ripple/protocol/Sign.h rename to include/xrpl/protocol/Sign.h index 86559958cee..7e1156ceda7 100644 --- a/src/ripple/protocol/Sign.h +++ b/include/xrpl/protocol/Sign.h @@ -20,10 +20,11 @@ #ifndef RIPPLE_PROTOCOL_SIGN_H_INCLUDED #define RIPPLE_PROTOCOL_SIGN_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include + #include namespace ripple { @@ -40,9 +41,12 @@ namespace ripple { @note If a signature already exists, it is overwritten. */ void -sign (STObject& st, HashPrefix const& prefix, - KeyType type, SecretKey const& sk, - SF_Blob const& sigField = sfSignature); +sign( + STObject& st, + HashPrefix const& prefix, + KeyType type, + SecretKey const& sk, + SF_VL const& sigField = sfSignature); /** Returns `true` if STObject contains valid signature @@ -53,13 +57,15 @@ sign (STObject& st, HashPrefix const& prefix, If not specified the value defaults to `sfSignature`. */ bool -verify (STObject const& st, HashPrefix const& prefix, +verify( + STObject const& st, + HashPrefix const& prefix, PublicKey const& pk, - SF_Blob const& sigField = sfSignature); + SF_VL const& sigField = sfSignature); /** Return a Serializer suitable for computing a multisigning TxnSignature. */ Serializer -buildMultiSigningData (STObject const& obj, AccountID const& signingID); +buildMultiSigningData(STObject const& obj, AccountID const& signingID); /** Break the multi-signing hash computation into 2 parts for optimization. @@ -70,18 +76,18 @@ buildMultiSigningData (STObject const& obj, AccountID const& signingID); The following methods support that optimization: 1. startMultiSigningData provides the large part which can be shared. - 2. finishMuiltiSigningData caps the passed in serializer with each + 2. finishMultiSigningData caps the passed in serializer with each signer's unique data. */ Serializer -startMultiSigningData (STObject const& obj); +startMultiSigningData(STObject const& obj); inline void -finishMultiSigningData (AccountID const& signingID, Serializer& s) +finishMultiSigningData(AccountID const& signingID, Serializer& s) { - s.add160 (signingID); + s.addBitString(signingID); } -} // ripple +} // namespace ripple #endif diff --git a/include/xrpl/protocol/SystemParameters.h b/include/xrpl/protocol/SystemParameters.h new file mode 100644 index 00000000000..121435dd92f --- /dev/null +++ b/include/xrpl/protocol/SystemParameters.h @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_SYSTEMPARAMETERS_H_INCLUDED +#define RIPPLE_PROTOCOL_SYSTEMPARAMETERS_H_INCLUDED + +#include +#include + +#include +#include + +namespace ripple { + +// Various protocol and system specific constant globals. + +/* The name of the system. */ +static inline std::string const& +systemName() +{ + static std::string const name = "ripple"; + return name; +} + +/** Configure the native currency. */ + +/** Number of drops in the genesis account. */ +constexpr XRPAmount INITIAL_XRP{100'000'000'000 * DROPS_PER_XRP}; + +/** Returns true if the amount does not exceed the initial XRP in existence. */ +inline bool +isLegalAmount(XRPAmount const& amount) +{ + return amount <= INITIAL_XRP; +} + +/** Returns true if the absolute value of the amount does not exceed the initial + * XRP in existence. */ +inline bool +isLegalAmountSigned(XRPAmount const& amount) +{ + return amount >= -INITIAL_XRP && amount <= INITIAL_XRP; +} + +/* The currency code for the native currency. */ +static inline std::string const& +systemCurrencyCode() +{ + static std::string const code = "XRP"; + return code; +} + +/** The XRP ledger network's earliest allowed sequence */ +static constexpr std::uint32_t XRP_LEDGER_EARLIEST_SEQ{32570u}; + +/** The XRP Ledger mainnet's earliest ledger with a FeeSettings object. Only + * used in asserts and tests. */ +static constexpr std::uint32_t XRP_LEDGER_EARLIEST_FEES{562177u}; + +/** The minimum amount of support an amendment should have. + + @note This value is used by legacy code and will become obsolete + once the fixAmendmentMajorityCalc amendment activates. +*/ +constexpr std::ratio<204, 256> preFixAmendmentMajorityCalcThreshold; + +constexpr std::ratio<80, 100> postFixAmendmentMajorityCalcThreshold; + +/** The minimum amount of time an amendment must hold a majority */ +constexpr std::chrono::seconds const defaultAmendmentMajorityTime = weeks{2}; + +} // namespace ripple + +/** Default peer port (IANA registered) */ +inline std::uint16_t constexpr DEFAULT_PEER_PORT{2459}; + +#endif diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h new file mode 100644 index 00000000000..da3788cd6ab --- /dev/null +++ b/include/xrpl/protocol/TER.h @@ -0,0 +1,686 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012 - 2019 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_TER_H_INCLUDED +#define RIPPLE_PROTOCOL_TER_H_INCLUDED + +#include +#include + +#include +#include +#include +#include + +namespace ripple { + +// See https://xrpl.org/transaction-results.html +// +// "Transaction Engine Result" +// or Transaction ERror. +// +using TERUnderlyingType = int; + +//------------------------------------------------------------------------------ + +enum TELcodes : TERUnderlyingType { + // Note: Range is stable. + // Exact numbers are used in ripple-binary-codec: + // https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json + // Use tokens. + + // -399 .. -300: L Local error (transaction fee inadequate, exceeds local + // limit) Only valid during non-consensus processing. Implications: + // - Not forwarded + // - No fee check + telLOCAL_ERROR = -399, + telBAD_DOMAIN, + telBAD_PATH_COUNT, + telBAD_PUBLIC_KEY, + telFAILED_PROCESSING, + telINSUF_FEE_P, + telNO_DST_PARTIAL, + telCAN_NOT_QUEUE, + telCAN_NOT_QUEUE_BALANCE, + telCAN_NOT_QUEUE_BLOCKS, + telCAN_NOT_QUEUE_BLOCKED, + telCAN_NOT_QUEUE_FEE, + telCAN_NOT_QUEUE_FULL, + telWRONG_NETWORK, + telREQUIRES_NETWORK_ID, + telNETWORK_ID_MAKES_TX_NON_CANONICAL, + telENV_RPC_FAILED +}; + +//------------------------------------------------------------------------------ + +enum TEMcodes : TERUnderlyingType { + // Note: Range is stable. + // Exact numbers are used in ripple-binary-codec: + // https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json + // Use tokens. + + // -299 .. -200: M Malformed (bad signature) + // Causes: + // - Transaction corrupt. + // Implications: + // - Not applied + // - Not forwarded + // - Reject + // - Cannot succeed in any imagined ledger. + temMALFORMED = -299, + + temBAD_AMOUNT, + temBAD_CURRENCY, + temBAD_EXPIRATION, + temBAD_FEE, + temBAD_ISSUER, + temBAD_LIMIT, + temBAD_OFFER, + temBAD_PATH, + temBAD_PATH_LOOP, + temBAD_REGKEY, + temBAD_SEND_XRP_LIMIT, + temBAD_SEND_XRP_MAX, + temBAD_SEND_XRP_NO_DIRECT, + temBAD_SEND_XRP_PARTIAL, + temBAD_SEND_XRP_PATHS, + temBAD_SEQUENCE, + temBAD_SIGNATURE, + temBAD_SRC_ACCOUNT, + temBAD_TRANSFER_RATE, + temDST_IS_SRC, + temDST_NEEDED, + temINVALID, + temINVALID_FLAG, + temREDUNDANT, + temRIPPLE_EMPTY, + temDISABLED, + temBAD_SIGNER, + temBAD_QUORUM, + temBAD_WEIGHT, + temBAD_TICK_SIZE, + temINVALID_ACCOUNT_ID, + temCANNOT_PREAUTH_SELF, + temINVALID_COUNT, + + temUNCERTAIN, // An internal intermediate result; should never be returned. + temUNKNOWN, // An internal intermediate result; should never be returned. + + temSEQ_AND_TICKET, + temBAD_NFTOKEN_TRANSFER_FEE, + + temBAD_AMM_TOKENS, + + temXCHAIN_EQUAL_DOOR_ACCOUNTS, + temXCHAIN_BAD_PROOF, + temXCHAIN_BRIDGE_BAD_ISSUES, + temXCHAIN_BRIDGE_NONDOOR_OWNER, + temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT, + temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT, + + temEMPTY_DID, + + temARRAY_EMPTY, + temARRAY_TOO_LARGE, + + temBAD_TRANSFER_FEE, +}; + +//------------------------------------------------------------------------------ + +enum TEFcodes : TERUnderlyingType { + // Note: Range is stable. + // Exact numbers are used in ripple-binary-codec: + // https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json + // Use tokens. + + // -199 .. -100: F + // Failure (sequence number previously used) + // + // Causes: + // - Transaction cannot succeed because of ledger state. + // - Unexpected ledger state. + // - C++ exception. + // + // Implications: + // - Not applied + // - Not forwarded + // - Could succeed in an imagined ledger. + tefFAILURE = -199, + tefALREADY, + tefBAD_ADD_AUTH, + tefBAD_AUTH, + tefBAD_LEDGER, + tefCREATED, + tefEXCEPTION, + tefINTERNAL, + tefNO_AUTH_REQUIRED, // Can't set auth if auth is not required. + tefPAST_SEQ, + tefWRONG_PRIOR, + tefMASTER_DISABLED, + tefMAX_LEDGER, + tefBAD_SIGNATURE, + tefBAD_QUORUM, + tefNOT_MULTI_SIGNING, + tefBAD_AUTH_MASTER, + tefINVARIANT_FAILED, + tefTOO_BIG, + tefNO_TICKET, + tefNFTOKEN_IS_NOT_TRANSFERABLE, + tefINVALID_LEDGER_FIX_TYPE, +}; + +//------------------------------------------------------------------------------ + +enum TERcodes : TERUnderlyingType { + // Note: Range is stable. + // Exact numbers are used in ripple-binary-codec: + // https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json + // Use tokens. + + // -99 .. -1: R Retry + // sequence too high, no funds for txn fee, originating -account + // non-existent + // + // Cause: + // Prior application of another, possibly non-existent, transaction could + // allow this transaction to succeed. + // + // Implications: + // - Not applied + // - May be forwarded + // - Results indicating the txn was forwarded: terQUEUED + // - All others are not forwarded. + // - Might succeed later + // - Hold + // - Makes hole in sequence which jams transactions. + terRETRY = -99, + terFUNDS_SPENT, // DEPRECATED. + terINSUF_FEE_B, // Can't pay fee, therefore don't burden network. + terNO_ACCOUNT, // Can't pay fee, therefore don't burden network. + terNO_AUTH, // Not authorized to hold IOUs. + terNO_LINE, // Internal flag. + terOWNERS, // Can't succeed with non-zero owner count. + terPRE_SEQ, // Can't pay fee, no point in forwarding, so don't + // burden network. + terLAST, // DEPRECATED. + terNO_RIPPLE, // Rippling not allowed + terQUEUED, // Transaction is being held in TxQ until fee drops + terPRE_TICKET, // Ticket is not yet in ledger but might be on its way + terNO_AMM, // AMM doesn't exist for the asset pair +}; + +//------------------------------------------------------------------------------ + +enum TEScodes : TERUnderlyingType { + // Note: Exact number must stay stable. This code is stored by value + // in metadata for historic transactions. + + // 0: S Success (success) + // Causes: + // - Success. + // Implications: + // - Applied + // - Forwarded + tesSUCCESS = 0 +}; + +//------------------------------------------------------------------------------ + +enum TECcodes : TERUnderlyingType { + // Note: Exact numbers must stay stable. These codes are stored by + // value in metadata for historic transactions. + + // 100 .. 255 C + // Claim fee only (ripple transaction with no good paths, pay to + // non-existent account, no path) + // + // Causes: + // - Success, but does not achieve optimal result. + // - Invalid transaction or no effect, but claim fee to use the sequence + // number. + // + // Implications: + // - Applied + // - Forwarded + // + // Only allowed as a return code of appliedTransaction when !tapRETRY. + // Otherwise, treated as terRETRY. + // + // DO NOT CHANGE THESE NUMBERS: They appear in ledger meta data. + tecCLAIM = 100, + tecPATH_PARTIAL = 101, + tecUNFUNDED_ADD = 102, // Unused legacy code + tecUNFUNDED_OFFER = 103, + tecUNFUNDED_PAYMENT = 104, + tecFAILED_PROCESSING = 105, + tecDIR_FULL = 121, + tecINSUF_RESERVE_LINE = 122, + tecINSUF_RESERVE_OFFER = 123, + tecNO_DST = 124, + tecNO_DST_INSUF_XRP = 125, + tecNO_LINE_INSUF_RESERVE = 126, + tecNO_LINE_REDUNDANT = 127, + tecPATH_DRY = 128, + tecUNFUNDED = 129, + tecNO_ALTERNATIVE_KEY = 130, + tecNO_REGULAR_KEY = 131, + tecOWNERS = 132, + tecNO_ISSUER = 133, + tecNO_AUTH = 134, + tecNO_LINE = 135, + tecINSUFF_FEE = 136, + tecFROZEN = 137, + tecNO_TARGET = 138, + tecNO_PERMISSION = 139, + tecNO_ENTRY = 140, + tecINSUFFICIENT_RESERVE = 141, + tecNEED_MASTER_KEY = 142, + tecDST_TAG_NEEDED = 143, + tecINTERNAL = 144, + tecOVERSIZE = 145, + tecCRYPTOCONDITION_ERROR = 146, + tecINVARIANT_FAILED = 147, + tecEXPIRED = 148, + tecDUPLICATE = 149, + tecKILLED = 150, + tecHAS_OBLIGATIONS = 151, + tecTOO_SOON = 152, + tecHOOK_REJECTED [[maybe_unused]] = 153, + tecMAX_SEQUENCE_REACHED = 154, + tecNO_SUITABLE_NFTOKEN_PAGE = 155, + tecNFTOKEN_BUY_SELL_MISMATCH = 156, + tecNFTOKEN_OFFER_TYPE_MISMATCH = 157, + tecCANT_ACCEPT_OWN_NFTOKEN_OFFER = 158, + tecINSUFFICIENT_FUNDS = 159, + tecOBJECT_NOT_FOUND = 160, + tecINSUFFICIENT_PAYMENT = 161, + tecUNFUNDED_AMM = 162, + tecAMM_BALANCE = 163, + tecAMM_FAILED = 164, + tecAMM_INVALID_TOKENS = 165, + tecAMM_EMPTY = 166, + tecAMM_NOT_EMPTY = 167, + tecAMM_ACCOUNT = 168, + tecINCOMPLETE = 169, + tecXCHAIN_BAD_TRANSFER_ISSUE = 170, + tecXCHAIN_NO_CLAIM_ID = 171, + tecXCHAIN_BAD_CLAIM_ID = 172, + tecXCHAIN_CLAIM_NO_QUORUM = 173, + tecXCHAIN_PROOF_UNKNOWN_KEY = 174, + tecXCHAIN_CREATE_ACCOUNT_NONXRP_ISSUE = 175, + tecXCHAIN_WRONG_CHAIN = 176, + tecXCHAIN_REWARD_MISMATCH = 177, + tecXCHAIN_NO_SIGNERS_LIST = 178, + tecXCHAIN_SENDING_ACCOUNT_MISMATCH = 179, + tecXCHAIN_INSUFF_CREATE_AMOUNT = 180, + tecXCHAIN_ACCOUNT_CREATE_PAST = 181, + tecXCHAIN_ACCOUNT_CREATE_TOO_MANY = 182, + tecXCHAIN_PAYMENT_FAILED = 183, + tecXCHAIN_SELF_COMMIT = 184, + tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR = 185, + tecXCHAIN_CREATE_ACCOUNT_DISABLED = 186, + tecEMPTY_DID = 187, + tecINVALID_UPDATE_TIME = 188, + tecTOKEN_PAIR_NOT_FOUND = 189, + tecARRAY_EMPTY = 190, + tecARRAY_TOO_LARGE = 191, + tecLOCKED = 192, + tecBAD_CREDENTIALS = 193, +}; + +//------------------------------------------------------------------------------ + +// For generic purposes, a free function that returns the value of a TE*codes. +constexpr TERUnderlyingType +TERtoInt(TELcodes v) +{ + return safe_cast(v); +} + +constexpr TERUnderlyingType +TERtoInt(TEMcodes v) +{ + return safe_cast(v); +} + +constexpr TERUnderlyingType +TERtoInt(TEFcodes v) +{ + return safe_cast(v); +} + +constexpr TERUnderlyingType +TERtoInt(TERcodes v) +{ + return safe_cast(v); +} + +constexpr TERUnderlyingType +TERtoInt(TEScodes v) +{ + return safe_cast(v); +} + +constexpr TERUnderlyingType +TERtoInt(TECcodes v) +{ + return safe_cast(v); +} + +//------------------------------------------------------------------------------ +// Template class that is specific to selected ranges of error codes. The +// Trait tells std::enable_if which ranges are allowed. +template